summaryrefslogtreecommitdiffstats
path: root/private/oleutest
diff options
context:
space:
mode:
Diffstat (limited to 'private/oleutest')
-rw-r--r--private/oleutest/act/acttest.h44
-rw-r--r--private/oleutest/act/client/client.cxx2122
-rw-r--r--private/oleutest/act/client/client.hxx43
-rw-r--r--private/oleutest/act/client/daytona/makefile1
-rw-r--r--private/oleutest/act/client/daytona/sources77
-rw-r--r--private/oleutest/act/client/dirs27
-rw-r--r--private/oleutest/act/client/pswrd.cxx58
-rw-r--r--private/oleutest/act/client/reg.cxx867
-rw-r--r--private/oleutest/act/common/clsid.c131
-rw-r--r--private/oleutest/act/common/daytona/makefile1
-rw-r--r--private/oleutest/act/common/daytona/sources69
-rw-r--r--private/oleutest/act/common/dirs27
-rw-r--r--private/oleutest/act/common/reg.c250
-rw-r--r--private/oleutest/act/dirs29
-rw-r--r--private/oleutest/act/dll/daytona/makefile1
-rw-r--r--private/oleutest/act/dll/daytona/sources77
-rw-r--r--private/oleutest/act/dll/dirs27
-rw-r--r--private/oleutest/act/dll/goober.def8
-rw-r--r--private/oleutest/act/dllsrv/actsrvd.def8
-rw-r--r--private/oleutest/act/dllsrv/daytona/makefile1
-rw-r--r--private/oleutest/act/dllsrv/daytona/sources79
-rw-r--r--private/oleutest/act/dllsrv/dirs27
-rw-r--r--private/oleutest/act/dllsrv/dllgco.cxx37
-rw-r--r--private/oleutest/act/dllsrv/goober.def8
-rw-r--r--private/oleutest/act/goober.idl17
-rw-r--r--private/oleutest/act/makefil021
-rw-r--r--private/oleutest/act/server/daytona/makefile1
-rw-r--r--private/oleutest/act/server/daytona/sources78
-rw-r--r--private/oleutest/act/server/dirs27
-rw-r--r--private/oleutest/act/server/pswrd.cxx66
-rw-r--r--private/oleutest/act/server/server.cxx1033
-rw-r--r--private/oleutest/act/server/server.hxx69
-rw-r--r--private/oleutest/act/srvcore/classes.cxx278
-rw-r--r--private/oleutest/act/srvcore/classes.hxx152
-rw-r--r--private/oleutest/act/srvcore/daytona/makefile1
-rw-r--r--private/oleutest/act/srvcore/daytona/sources69
-rw-r--r--private/oleutest/act/srvcore/dirs27
-rw-r--r--private/oleutest/act/srvcore/factory.cxx200
-rw-r--r--private/oleutest/act/srvcore/factory.hxx101
-rw-r--r--private/oleutest/act/tstsvc/client.cxx2231
-rw-r--r--private/oleutest/act/tstsvc/client.hxx38
-rw-r--r--private/oleutest/act/tstsvc/daytona/makefile1
-rw-r--r--private/oleutest/act/tstsvc/daytona/sources77
-rw-r--r--private/oleutest/act/tstsvc/dirs27
-rw-r--r--private/oleutest/act/tstsvc/pswrd.cxx56
-rw-r--r--private/oleutest/act/tstsvc/reg.cxx859
-rw-r--r--private/oleutest/act/tstsvc/service.cxx92
-rw-r--r--private/oleutest/assert/assert.cxx391
-rw-r--r--private/oleutest/assert/daytona/makefile10
-rw-r--r--private/oleutest/assert/daytona/sources80
-rw-r--r--private/oleutest/assert/dirs38
-rw-r--r--private/oleutest/assert/dprintf.c15
-rw-r--r--private/oleutest/assert/dprintf.h33
-rw-r--r--private/oleutest/assert/filelist.mk57
-rw-r--r--private/oleutest/assert/makefile25
-rw-r--r--private/oleutest/assert/output.c804
-rw-r--r--private/oleutest/assert/printf.c17
-rw-r--r--private/oleutest/assert/printf.h245
-rw-r--r--private/oleutest/assert/sprintf.c13
-rw-r--r--private/oleutest/assert/w4io.h49
-rw-r--r--private/oleutest/assert/wsprintf.c14
-rw-r--r--private/oleutest/balls/cairo.inc38
-rw-r--r--private/oleutest/balls/cballs.reg97
-rw-r--r--private/oleutest/balls/chicago.inc28
-rw-r--r--private/oleutest/balls/client/cfrace/cfrace.cxx118
-rw-r--r--private/oleutest/balls/client/cfrace/cfrace.h6
-rw-r--r--private/oleutest/balls/client/cfrace/daytona/makefile10
-rw-r--r--private/oleutest/balls/client/cfrace/daytona/sources57
-rw-r--r--private/oleutest/balls/client/cfrace/dirs38
-rw-r--r--private/oleutest/balls/client/cfrace/main.cxx28
-rw-r--r--private/oleutest/balls/client/daytona.inc41
-rw-r--r--private/oleutest/balls/client/dirs34
-rw-r--r--private/oleutest/balls/client/dllhost/daytona/makefile10
-rw-r--r--private/oleutest/balls/client/dllhost/daytona/sources57
-rw-r--r--private/oleutest/balls/client/dllhost/dirs38
-rw-r--r--private/oleutest/balls/client/dllhost/main.cxx28
-rw-r--r--private/oleutest/balls/client/dllhost/tdllhost.cxx600
-rw-r--r--private/oleutest/balls/client/dllhost/tdllhost.h6
-rw-r--r--private/oleutest/balls/client/prxytest/daytona/makefile10
-rw-r--r--private/oleutest/balls/client/prxytest/daytona/sources67
-rw-r--r--private/oleutest/balls/client/prxytest/dirs38
-rw-r--r--private/oleutest/balls/client/prxytest/prxytest.cxx152
-rw-r--r--private/oleutest/balls/client/smarshal/daytona/makefile10
-rw-r--r--private/oleutest/balls/client/smarshal/daytona/sources59
-rw-r--r--private/oleutest/balls/client/smarshal/dirs38
-rw-r--r--private/oleutest/balls/client/smarshal/smarshal.cxx862
-rw-r--r--private/oleutest/balls/client/smarshal/smarshal.hxx124
-rw-r--r--private/oleutest/balls/client/smarshal/stream.cxx315
-rw-r--r--private/oleutest/balls/client/smarshal/stream.hxx96
-rw-r--r--private/oleutest/balls/client/smarshal/testvars.cxx301
-rw-r--r--private/oleutest/balls/client/smarshal/tunk.cxx66
-rw-r--r--private/oleutest/balls/client/smarshal/tunk.h26
-rw-r--r--private/oleutest/balls/client/tmarshal/daytona/makefile10
-rw-r--r--private/oleutest/balls/client/tmarshal/daytona/sources60
-rw-r--r--private/oleutest/balls/client/tmarshal/dirs38
-rw-r--r--private/oleutest/balls/client/tmarshal/main.cxx29
-rw-r--r--private/oleutest/balls/client/tmarshal/objref.cxx270
-rw-r--r--private/oleutest/balls/client/tmarshal/stream.cxx315
-rw-r--r--private/oleutest/balls/client/tmarshal/stream.hxx96
-rw-r--r--private/oleutest/balls/client/tmarshal/tmarshal.cxx5634
-rw-r--r--private/oleutest/balls/client/tmarshal/tmarshal.h6
-rw-r--r--private/oleutest/balls/client/tmarshal/tmarshal.ini92
-rw-r--r--private/oleutest/balls/client/tmarshal/tunk.cxx482
-rw-r--r--private/oleutest/balls/client/tmarshal/tunk.h130
-rw-r--r--private/oleutest/balls/coffbase.txt456
-rw-r--r--private/oleutest/balls/common/actcf.cxx133
-rw-r--r--private/oleutest/balls/common/actcf.hxx73
-rw-r--r--private/oleutest/balls/common/advbnd.cxx442
-rw-r--r--private/oleutest/balls/common/advbnd.hxx111
-rw-r--r--private/oleutest/balls/common/ballscf.cxx151
-rw-r--r--private/oleutest/balls/common/ballscf.hxx63
-rw-r--r--private/oleutest/balls/common/bscbnd.cxx826
-rw-r--r--private/oleutest/balls/common/bscbnd.hxx208
-rw-r--r--private/oleutest/balls/common/cact.cxx547
-rw-r--r--private/oleutest/balls/common/cact.hxx94
-rw-r--r--private/oleutest/balls/common/cballs.cxx435
-rw-r--r--private/oleutest/balls/common/cballs.hxx107
-rw-r--r--private/oleutest/balls/common/ccubes.cxx314
-rw-r--r--private/oleutest/balls/common/ccubes.hxx77
-rw-r--r--private/oleutest/balls/common/cfballs.cxx127
-rw-r--r--private/oleutest/balls/common/cfballs.hxx38
-rw-r--r--private/oleutest/balls/common/cloop.cxx171
-rw-r--r--private/oleutest/balls/common/cloop.hxx57
-rw-r--r--private/oleutest/balls/common/common.h56
-rw-r--r--private/oleutest/balls/common/cqi.hxx59
-rw-r--r--private/oleutest/balls/common/cqisrv.cxx130
-rw-r--r--private/oleutest/balls/common/crpc.cxx347
-rw-r--r--private/oleutest/balls/common/crpc.hxx86
-rw-r--r--private/oleutest/balls/common/crpctyp.cxx393
-rw-r--r--private/oleutest/balls/common/crpctyp.hxx129
-rw-r--r--private/oleutest/balls/common/csrvapp.hxx79
-rw-r--r--private/oleutest/balls/common/ctballs.cxx532
-rw-r--r--private/oleutest/balls/common/ctballs.hxx92
-rw-r--r--private/oleutest/balls/common/ctext.cxx332
-rw-r--r--private/oleutest/balls/common/ctext.hxx75
-rw-r--r--private/oleutest/balls/common/cubescf.cxx142
-rw-r--r--private/oleutest/balls/common/cubescf.hxx61
-rw-r--r--private/oleutest/balls/common/dataobj.cxx310
-rw-r--r--private/oleutest/balls/common/dataobj.hxx75
-rw-r--r--private/oleutest/balls/common/daytona/makefile10
-rw-r--r--private/oleutest/balls/common/daytona/sources103
-rw-r--r--private/oleutest/balls/common/dirs38
-rw-r--r--private/oleutest/balls/common/embed.cxx401
-rw-r--r--private/oleutest/balls/common/embed.hxx103
-rw-r--r--private/oleutest/balls/common/loopscf.cxx141
-rw-r--r--private/oleutest/balls/common/loopscf.hxx61
-rw-r--r--private/oleutest/balls/common/memstm.cxx1004
-rw-r--r--private/oleutest/balls/common/memstm.h226
-rw-r--r--private/oleutest/balls/common/mixedcf.cxx152
-rw-r--r--private/oleutest/balls/common/mixedcf.hxx53
-rw-r--r--private/oleutest/balls/common/oleinit.hxx54
-rw-r--r--private/oleutest/balls/common/oleobj.cxx631
-rw-r--r--private/oleutest/balls/common/oleobj.hxx105
-rw-r--r--private/oleutest/balls/common/otrack.hxx85
-rw-r--r--private/oleutest/balls/common/pch.cxx22
-rw-r--r--private/oleutest/balls/common/persist.cxx252
-rw-r--r--private/oleutest/balls/common/persist.hxx65
-rw-r--r--private/oleutest/balls/common/qicf.cxx123
-rw-r--r--private/oleutest/balls/common/qicf.hxx55
-rw-r--r--private/oleutest/balls/common/regmain.cxx203
-rw-r--r--private/oleutest/balls/common/regmain.hxx18
-rw-r--r--private/oleutest/balls/common/rpccf.cxx140
-rw-r--r--private/oleutest/balls/common/rpccf.hxx61
-rw-r--r--private/oleutest/balls/common/rpctcf.cxx136
-rw-r--r--private/oleutest/balls/common/rpctcf.hxx61
-rw-r--r--private/oleutest/balls/common/smartp.hxx75
-rw-r--r--private/oleutest/balls/common/srvmain.cxx352
-rw-r--r--private/oleutest/balls/common/srvmain.hxx97
-rw-r--r--private/oleutest/balls/common/stream.cxx320
-rw-r--r--private/oleutest/balls/common/stream.hxx97
-rw-r--r--private/oleutest/balls/common/tstmain.cxx178
-rw-r--r--private/oleutest/balls/common/tstmain.hxx49
-rw-r--r--private/oleutest/balls/common/win4p.hxx3
-rw-r--r--private/oleutest/balls/common/wterm.c1027
-rw-r--r--private/oleutest/balls/common/wterm.h56
-rw-r--r--private/oleutest/balls/common/wterm2.cxx186
-rw-r--r--private/oleutest/balls/copyall.bat22
-rw-r--r--private/oleutest/balls/daytona.inc30
-rw-r--r--private/oleutest/balls/dirs41
-rw-r--r--private/oleutest/balls/dll/cairo.inc53
-rw-r--r--private/oleutest/balls/dll/chicago.inc64
-rw-r--r--private/oleutest/balls/dll/daytona.inc64
-rw-r--r--private/oleutest/balls/dll/dirs38
-rw-r--r--private/oleutest/balls/dll/dlltest/daytona/dlltest.src48
-rw-r--r--private/oleutest/balls/dll/dlltest/daytona/makefile10
-rw-r--r--private/oleutest/balls/dll/dlltest/daytona/makefile.inc1
-rw-r--r--private/oleutest/balls/dll/dlltest/daytona/sources59
-rw-r--r--private/oleutest/balls/dll/dlltest/dirs38
-rw-r--r--private/oleutest/balls/dll/dlltest/dlltest.cxx124
-rw-r--r--private/oleutest/balls/dll/dlltest/dlltest.def38
-rw-r--r--private/oleutest/balls/dll/oleimpl/daytona/makefile10
-rw-r--r--private/oleutest/balls/dll/oleimpl/daytona/makefile.inc1
-rw-r--r--private/oleutest/balls/dll/oleimpl/daytona/oleimpl.src48
-rw-r--r--private/oleutest/balls/dll/oleimpl/daytona/sources55
-rw-r--r--private/oleutest/balls/dll/oleimpl/dirs38
-rw-r--r--private/oleutest/balls/dll/oleimpl/oleimpl.cxx98
-rw-r--r--private/oleutest/balls/dll/oleimpl/oleimpl.def38
-rw-r--r--private/oleutest/balls/dll/qi/daytona/makefile10
-rw-r--r--private/oleutest/balls/dll/qi/daytona/makefile.inc1
-rw-r--r--private/oleutest/balls/dll/qi/daytona/qisrv.src48
-rw-r--r--private/oleutest/balls/dll/qi/daytona/sources55
-rw-r--r--private/oleutest/balls/dll/qi/dirs38
-rw-r--r--private/oleutest/balls/dll/qi/qisrv.cxx55
-rw-r--r--private/oleutest/balls/dll/qi/qisrv.def38
-rw-r--r--private/oleutest/balls/dll/rpctst/daytona/makefile10
-rw-r--r--private/oleutest/balls/dll/rpctst/daytona/makefile.inc1
-rw-r--r--private/oleutest/balls/dll/rpctst/daytona/rpcsrv.src48
-rw-r--r--private/oleutest/balls/dll/rpctst/daytona/sources68
-rw-r--r--private/oleutest/balls/dll/rpctst/dirs38
-rw-r--r--private/oleutest/balls/dll/rpctst/rpcsrv.cxx63
-rw-r--r--private/oleutest/balls/dll/rpctst/rpcsrv.def38
-rw-r--r--private/oleutest/balls/idl/iballs.idl47
-rw-r--r--private/oleutest/balls/idl/ibtest.idl32
-rw-r--r--private/oleutest/balls/idl/icube.idl46
-rw-r--r--private/oleutest/balls/idl/iloop.idl29
-rw-r--r--private/oleutest/balls/idl/makefile6
-rw-r--r--private/oleutest/balls/idl/pch.cxx24
-rw-r--r--private/oleutest/balls/idl/prxydll.def47
-rw-r--r--private/oleutest/balls/idl/rawrpc.idl59
-rw-r--r--private/oleutest/balls/idl/rpctst.idl66
-rw-r--r--private/oleutest/balls/idl/rpctyp.idl95
-rw-r--r--private/oleutest/balls/idl/sources30
-rw-r--r--private/oleutest/balls/idl/stdrpc.hxx240
-rw-r--r--private/oleutest/balls/idl/unknwn.idl33
-rw-r--r--private/oleutest/balls/idl/wtypes.idl741
-rw-r--r--private/oleutest/balls/licfiles.sed6
-rw-r--r--private/oleutest/balls/makefil016
-rw-r--r--private/oleutest/balls/makefile.inc2801
-rw-r--r--private/oleutest/balls/myproxy/daytona.inc64
-rw-r--r--private/oleutest/balls/myproxy/daytona/makefile10
-rw-r--r--private/oleutest/balls/myproxy/daytona/makefile.inc1
-rw-r--r--private/oleutest/balls/myproxy/daytona/myproxy.src48
-rw-r--r--private/oleutest/balls/myproxy/daytona/sources56
-rw-r--r--private/oleutest/balls/myproxy/dirs38
-rw-r--r--private/oleutest/balls/myproxy/myproxy.cxx1092
-rw-r--r--private/oleutest/balls/myproxy/myproxy.def38
-rw-r--r--private/oleutest/balls/oleprx32/dirs21
-rw-r--r--private/oleutest/balls/oleprx32/proxy/daytona/makefile6
-rw-r--r--private/oleutest/balls/oleprx32/proxy/daytona/sources59
-rw-r--r--private/oleutest/balls/oleprx32/proxy/dirs24
-rw-r--r--private/oleutest/balls/oleprx32/proxy/iballs.def38
-rw-r--r--private/oleutest/balls/oleprx32/proxy/stdrpc.hxx66
-rw-r--r--private/oleutest/balls/oleprx32/proxy/transmit.cxx3295
-rw-r--r--private/oleutest/balls/oleprx32/proxy/transmit.h145
-rw-r--r--private/oleutest/balls/oleprx32/uuid/daytona/makefile6
-rw-r--r--private/oleutest/balls/oleprx32/uuid/daytona/sources25
-rw-r--r--private/oleutest/balls/oleprx32/uuid/dirs24
-rw-r--r--private/oleutest/balls/public.sed13
-rw-r--r--private/oleutest/balls/rcfiles.sed36
-rw-r--r--private/oleutest/balls/srv/balls/ballsrv.cxx42
-rw-r--r--private/oleutest/balls/srv/balls/daytona/makefile10
-rw-r--r--private/oleutest/balls/srv/balls/daytona/sources54
-rw-r--r--private/oleutest/balls/srv/balls/dirs38
-rw-r--r--private/oleutest/balls/srv/cairo.inc38
-rw-r--r--private/oleutest/balls/srv/chicago.inc51
-rw-r--r--private/oleutest/balls/srv/cubes/cubesrv.cxx41
-rw-r--r--private/oleutest/balls/srv/cubes/daytona/makefile10
-rw-r--r--private/oleutest/balls/srv/cubes/daytona/sources54
-rw-r--r--private/oleutest/balls/srv/cubes/dirs38
-rw-r--r--private/oleutest/balls/srv/daytona.inc51
-rw-r--r--private/oleutest/balls/srv/dirs42
-rw-r--r--private/oleutest/balls/srv/distbind/daytona/makefile10
-rw-r--r--private/oleutest/balls/srv/distbind/daytona/sources53
-rw-r--r--private/oleutest/balls/srv/distbind/db.cxx42
-rw-r--r--private/oleutest/balls/srv/distbind/dirs38
-rw-r--r--private/oleutest/balls/srv/loops/daytona/makefile10
-rw-r--r--private/oleutest/balls/srv/loops/daytona/sources53
-rw-r--r--private/oleutest/balls/srv/loops/dirs38
-rw-r--r--private/oleutest/balls/srv/loops/loopsrv.cxx41
-rw-r--r--private/oleutest/balls/srv/mdi/daytona/makefile10
-rw-r--r--private/oleutest/balls/srv/mdi/daytona/sources53
-rw-r--r--private/oleutest/balls/srv/mdi/dirs38
-rw-r--r--private/oleutest/balls/srv/mdi/mdi.cxx41
-rw-r--r--private/oleutest/balls/srv/mixed/daytona/makefile10
-rw-r--r--private/oleutest/balls/srv/mixed/daytona/sources53
-rw-r--r--private/oleutest/balls/srv/mixed/dirs38
-rw-r--r--private/oleutest/balls/srv/mixed/mixedsrv.cxx305
-rw-r--r--private/oleutest/balls/srv/olesrv/daytona/makefile10
-rw-r--r--private/oleutest/balls/srv/olesrv/daytona/sources53
-rw-r--r--private/oleutest/balls/srv/olesrv/dirs38
-rw-r--r--private/oleutest/balls/srv/olesrv/olesrv.cxx41
-rw-r--r--private/oleutest/balls/srv/qi/daytona/makefile10
-rw-r--r--private/oleutest/balls/srv/qi/daytona/sources53
-rw-r--r--private/oleutest/balls/srv/qi/dirs38
-rw-r--r--private/oleutest/balls/srv/qi/qisrv.cxx107
-rw-r--r--private/oleutest/balls/srv/rpctst/daytona/makefile10
-rw-r--r--private/oleutest/balls/srv/rpctst/daytona/sources54
-rw-r--r--private/oleutest/balls/srv/rpctst/dirs38
-rw-r--r--private/oleutest/balls/srv/rpctst/rpcsrv.cxx103
-rw-r--r--private/oleutest/balls/srv/sdi/daytona/makefile10
-rw-r--r--private/oleutest/balls/srv/sdi/daytona/sources53
-rw-r--r--private/oleutest/balls/srv/sdi/dirs38
-rw-r--r--private/oleutest/balls/srv/sdi/sdi.cxx41
-rw-r--r--private/oleutest/balls/srv/testsrv/csrvapp.cxx289
-rw-r--r--private/oleutest/balls/srv/testsrv/daytona/makefile10
-rw-r--r--private/oleutest/balls/srv/testsrv/daytona/sources54
-rw-r--r--private/oleutest/balls/srv/testsrv/dirs38
-rw-r--r--private/oleutest/balls/srv/testsrv/testsrv.cxx204
-rw-r--r--private/oleutest/balls/srv/testsrv/testsrv.icobin0 -> 766 bytes
-rw-r--r--private/oleutest/balls/srv/testsrv/testsrv.rc3
-rw-r--r--private/oleutest/balls/stripspc.sed15
-rw-r--r--private/oleutest/balls/tmarshal.ini92
-rw-r--r--private/oleutest/balls/types.inc14
-rw-r--r--private/oleutest/balls/win.ini49
-rw-r--r--private/oleutest/cachetst/bmpfile.cxx1007
-rw-r--r--private/oleutest/cachetst/bmpfile.hxx112
-rw-r--r--private/oleutest/cachetst/ctest.hxx138
-rw-r--r--private/oleutest/cachetst/ctestapp.hxx129
-rw-r--r--private/oleutest/cachetst/davedbg.cpp473
-rw-r--r--private/oleutest/cachetst/davedbg.h74
-rw-r--r--private/oleutest/cachetst/daytona/sources83
-rw-r--r--private/oleutest/cachetst/dirs36
-rw-r--r--private/oleutest/cachetst/enum.cpp318
-rw-r--r--private/oleutest/cachetst/genenum.cpp722
-rw-r--r--private/oleutest/cachetst/genenum.h134
-rw-r--r--private/oleutest/cachetst/genforc.cpp276
-rw-r--r--private/oleutest/cachetst/genforc.hxx74
-rw-r--r--private/oleutest/cachetst/headers.hxx27
-rw-r--r--private/oleutest/cachetst/main.cpp1521
-rw-r--r--private/oleutest/cachetst/multi.cpp287
-rw-r--r--private/oleutest/cachetst/utils.cpp315
-rw-r--r--private/oleutest/cairo.inc26
-rw-r--r--private/oleutest/cfmex/cdir.cxx418
-rw-r--r--private/oleutest/cfmex/cdir.hxx161
-rw-r--r--private/oleutest/cfmex/cfmex.cxx449
-rw-r--r--private/oleutest/cfmex/cfmex.hxx31
-rw-r--r--private/oleutest/cfmex/cmoniker.cxx1684
-rw-r--r--private/oleutest/cfmex/cmoniker.hxx178
-rw-r--r--private/oleutest/cfmex/ctest.cxx1283
-rw-r--r--private/oleutest/cfmex/ctest.hxx118
-rw-r--r--private/oleutest/cfmex/makefile6
-rw-r--r--private/oleutest/cfmex/sources35
-rw-r--r--private/oleutest/channel/app/app.cxx9685
-rw-r--r--private/oleutest/channel/app/app_i.c28
-rw-r--r--private/oleutest/channel/app/makefile20
-rw-r--r--private/oleutest/channel/app/prxydll.def7
-rw-r--r--private/oleutest/channel/app/sources70
-rw-r--r--private/oleutest/channel/dirs38
-rw-r--r--private/oleutest/channel/idl/dog.acf9
-rw-r--r--private/oleutest/channel/idl/dog.idl45
-rw-r--r--private/oleutest/channel/idl/itest.acf4
-rw-r--r--private/oleutest/channel/idl/itest.idl192
-rw-r--r--private/oleutest/channel/idl/makefile9
-rw-r--r--private/oleutest/channel/idl/makefile.inc37
-rw-r--r--private/oleutest/channel/idl/pch.cxx18
-rw-r--r--private/oleutest/channel/idl/prxydll.def47
-rw-r--r--private/oleutest/channel/idl/sources66
-rw-r--r--private/oleutest/channel/idl/test.reg24
-rw-r--r--private/oleutest/channel/idl/test2.reg16
-rw-r--r--private/oleutest/channel/rel.cmd3
-rw-r--r--private/oleutest/chicago.inc23
-rw-r--r--private/oleutest/cmarshal/app/app.cxx764
-rw-r--r--private/oleutest/cmarshal/app/app.hxx108
-rw-r--r--private/oleutest/cmarshal/app/app_i.c26
-rw-r--r--private/oleutest/cmarshal/app/cmarshal.cxx317
-rw-r--r--private/oleutest/cmarshal/app/cmarshal.hxx131
-rw-r--r--private/oleutest/cmarshal/app/filelist.mk55
-rw-r--r--private/oleutest/cmarshal/app/makefile13
-rw-r--r--private/oleutest/cmarshal/cmarshal/cmarshal.def48
-rw-r--r--private/oleutest/cmarshal/cmarshal/filelist.mk52
-rw-r--r--private/oleutest/cmarshal/cmarshal/inproc.cxx77
-rw-r--r--private/oleutest/cmarshal/cmarshal/makefile13
-rw-r--r--private/oleutest/cmarshal/idl/filelist.mk81
-rw-r--r--private/oleutest/cmarshal/idl/itest.idl38
-rw-r--r--private/oleutest/cmarshal/idl/makefile17
-rw-r--r--private/oleutest/cmarshal/idl/pch.cxx18
-rw-r--r--private/oleutest/cmarshal/idl/prxydll.def47
-rw-r--r--private/oleutest/cmarshal/idl/test.reg26
-rw-r--r--private/oleutest/common/com.hxx18
-rw-r--r--private/oleutest/common/oleport.h50
-rw-r--r--private/oleutest/daytona.inc26
-rw-r--r--private/oleutest/dirs50
-rw-r--r--private/oleutest/dll/daytona/makefile10
-rw-r--r--private/oleutest/dll/daytona/makefile.inc1
-rw-r--r--private/oleutest/dll/daytona/oleimpl.src37
-rw-r--r--private/oleutest/dll/daytona/sources109
-rw-r--r--private/oleutest/dll/dirs38
-rw-r--r--private/oleutest/dll/iclisite.cxx108
-rw-r--r--private/oleutest/dll/oleimpl.cxx898
-rw-r--r--private/oleutest/dll/oleimpl.hxx242
-rw-r--r--private/oleutest/inc/testmess.h52
-rw-r--r--private/oleutest/inc/tstclsid.h25
-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
-rw-r--r--private/oleutest/makefil036
-rw-r--r--private/oleutest/memalloc/daytona/makefile20
-rw-r--r--private/oleutest/memalloc/daytona/makefile.inc31
-rw-r--r--private/oleutest/memalloc/daytona/sources88
-rw-r--r--private/oleutest/memalloc/dirs38
-rw-r--r--private/oleutest/memalloc/headers.cxx16
-rw-r--r--private/oleutest/memalloc/makefile16
-rw-r--r--private/oleutest/memalloc/memory.cxx138
-rw-r--r--private/oleutest/memalloc/memtask.cxx196
-rw-r--r--private/oleutest/memalloc/memtest.cxx436
-rw-r--r--private/oleutest/memalloc/memtest.hxx89
-rw-r--r--private/oleutest/memalloc/midl.cxx357
-rw-r--r--private/oleutest/memalloc/preinit.cxx121
-rw-r--r--private/oleutest/memalloc/signal.cxx89
-rw-r--r--private/oleutest/memalloc/signal.hxx39
-rw-r--r--private/oleutest/memalloc/test.acf7
-rw-r--r--private/oleutest/memalloc/test.idl29
-rw-r--r--private/oleutest/ole1/clidemo/clidemo37
-rw-r--r--private/oleutest/ole1/clidemo/clidemo.c1032
-rw-r--r--private/oleutest/ole1/clidemo/clidemo.def35
-rw-r--r--private/oleutest/ole1/clidemo/clidemo.h62
-rw-r--r--private/oleutest/ole1/clidemo/clidemo.icobin0 -> 766 bytes
-rw-r--r--private/oleutest/ole1/clidemo/clidemo.rc231
-rw-r--r--private/oleutest/ole1/clidemo/clidemo.rcv33
-rw-r--r--private/oleutest/ole1/clidemo/cliver.h9
-rw-r--r--private/oleutest/ole1/clidemo/daytona/makefile6
-rw-r--r--private/oleutest/ole1/clidemo/daytona/sources26
-rw-r--r--private/oleutest/ole1/clidemo/demorc.h180
-rw-r--r--private/oleutest/ole1/clidemo/dialog.c1150
-rw-r--r--private/oleutest/ole1/clidemo/dialog.h85
-rw-r--r--private/oleutest/ole1/clidemo/dirs4
-rw-r--r--private/oleutest/ole1/clidemo/global.h108
-rw-r--r--private/oleutest/ole1/clidemo/object.c1177
-rw-r--r--private/oleutest/ole1/clidemo/object.h40
-rw-r--r--private/oleutest/ole1/clidemo/register.c196
-rw-r--r--private/oleutest/ole1/clidemo/register.h17
-rw-r--r--private/oleutest/ole1/clidemo/stream.c348
-rw-r--r--private/oleutest/ole1/clidemo/stream.h35
-rw-r--r--private/oleutest/ole1/clidemo/utility.c612
-rw-r--r--private/oleutest/ole1/clidemo/utility.h34
-rw-r--r--private/oleutest/ole1/dirs38
-rw-r--r--private/oleutest/ole1/srvrdemo/daytona/makefile6
-rw-r--r--private/oleutest/ole1/srvrdemo/daytona/sources25
-rw-r--r--private/oleutest/ole1/srvrdemo/dirs4
-rw-r--r--private/oleutest/ole1/srvrdemo/doc.c594
-rw-r--r--private/oleutest/ole1/srvrdemo/file.c534
-rw-r--r--private/oleutest/ole1/srvrdemo/obj.c1187
-rw-r--r--private/oleutest/ole1/srvrdemo/server.c538
-rw-r--r--private/oleutest/ole1/srvrdemo/srvrdemo33
-rw-r--r--private/oleutest/ole1/srvrdemo/srvrdemo.c1335
-rw-r--r--private/oleutest/ole1/srvrdemo/srvrdemo.def56
-rw-r--r--private/oleutest/ole1/srvrdemo/srvrdemo.h333
-rw-r--r--private/oleutest/ole1/srvrdemo/srvrdemo.icobin0 -> 766 bytes
-rw-r--r--private/oleutest/ole1/srvrdemo/srvrdemo.rc74
-rw-r--r--private/oleutest/olebind/daytona/makefile10
-rw-r--r--private/oleutest/olebind/daytona/sources77
-rw-r--r--private/oleutest/olebind/dirs38
-rw-r--r--private/oleutest/olebind/olebind.cxx1154
-rw-r--r--private/oleutest/olebind/olebind.hxx90
-rw-r--r--private/oleutest/olebind/rot.cxx262
-rw-r--r--private/oleutest/olebind/tmalloc.cxx82
-rw-r--r--private/oleutest/olebind/tmoniker.cxx798
-rw-r--r--private/oleutest/olebind/tmoniker.h10
-rw-r--r--private/oleutest/olebind/widewrap.cxx1840
-rw-r--r--private/oleutest/olebind/widewrap.h764
-rw-r--r--private/oleutest/olebvt.bat13
-rw-r--r--private/oleutest/oledll2/daytona/makefile10
-rw-r--r--private/oleutest/oledll2/daytona/oledll2.src36
-rw-r--r--private/oleutest/oledll2/daytona/sources62
-rw-r--r--private/oleutest/oledll2/dirs38
-rw-r--r--private/oleutest/oledll2/oledll2.c79
-rw-r--r--private/oleutest/oledll2/oledll2.h27
-rw-r--r--private/oleutest/oledll2/readme12
-rw-r--r--private/oleutest/oleexts/daytona/makefile10
-rw-r--r--private/oleutest/oleexts/daytona/makefile.inc1
-rw-r--r--private/oleutest/oleexts/daytona/oledbg.src41
-rw-r--r--private/oleutest/oleexts/daytona/sources75
-rw-r--r--private/oleutest/oleexts/dirs35
-rw-r--r--private/oleutest/oleexts/oleexts.cpp4562
-rw-r--r--private/oleutest/oleexts/oleexts.h107
-rw-r--r--private/oleutest/oletest/app.cpp65
-rw-r--r--private/oleutest/oletest/app.h70
-rw-r--r--private/oleutest/oletest/appwin.h34
-rw-r--r--private/oleutest/oletest/assert.cpp177
-rw-r--r--private/oleutest/oletest/assert.h33
-rw-r--r--private/oleutest/oletest/attest.cpp1352
-rw-r--r--private/oleutest/oletest/attest.h123
-rw-r--r--private/oleutest/oletest/cliptest.cpp1481
-rw-r--r--private/oleutest/oletest/cotest.h25
-rw-r--r--private/oleutest/oletest/dataadv.cpp1432
-rw-r--r--private/oleutest/oletest/daytona/makefile10
-rw-r--r--private/oleutest/oletest/daytona/sources93
-rw-r--r--private/oleutest/oletest/dirs38
-rw-r--r--private/oleutest/oletest/gendata.cpp1930
-rw-r--r--private/oleutest/oletest/gendata.h181
-rw-r--r--private/oleutest/oletest/genenum.cpp335
-rw-r--r--private/oleutest/oletest/genenum.h105
-rw-r--r--private/oleutest/oletest/letest.h49
-rw-r--r--private/oleutest/oletest/letests.cpp155
-rw-r--r--private/oleutest/oletest/oleadv.cpp943
-rw-r--r--private/oleutest/oletest/oletest.cpp841
-rw-r--r--private/oleutest/oletest/oletest.h51
-rw-r--r--private/oleutest/oletest/oletest.rc45
-rw-r--r--private/oleutest/oletest/oletst16.def8
-rw-r--r--private/oleutest/oletest/oletst16.mak236
-rw-r--r--private/oleutest/oletest/output.cpp196
-rw-r--r--private/oleutest/oletest/output.h27
-rw-r--r--private/oleutest/oletest/stack.cpp413
-rw-r--r--private/oleutest/oletest/stack.h61
-rw-r--r--private/oleutest/oletest/task.cpp479
-rw-r--r--private/oleutest/oletest/task.h65
-rw-r--r--private/oleutest/oletest/uthread.cpp1131
-rw-r--r--private/oleutest/oletest/utils.cpp133
-rw-r--r--private/oleutest/oletest/utils.h24
-rw-r--r--private/oleutest/oleutest.bat405
-rw-r--r--private/oleutest/perf/dirs41
-rw-r--r--private/oleutest/perf/idl/iperf.idl32
-rw-r--r--private/oleutest/perf/idl/makefile9
-rw-r--r--private/oleutest/perf/idl/makefile.inc32
-rw-r--r--private/oleutest/perf/idl/perf.reg22
-rw-r--r--private/oleutest/perf/idl/sources66
-rw-r--r--private/oleutest/perf/perfcli/makefile20
-rw-r--r--private/oleutest/perf/perfcli/perfcli.cxx549
-rw-r--r--private/oleutest/perf/perfcli/sources62
-rw-r--r--private/oleutest/perf/perfsrv/makefile20
-rw-r--r--private/oleutest/perf/perfsrv/perfsrv.cxx475
-rw-r--r--private/oleutest/perf/perfsrv/perfsrv.hxx101
-rw-r--r--private/oleutest/perf/perfsrv/sources62
-rw-r--r--private/oleutest/perf/perfsrv/wterm.c1027
-rw-r--r--private/oleutest/perf/perfsrv/wterm.h40
-rw-r--r--private/oleutest/perf/perfuuid/makefile9
-rw-r--r--private/oleutest/perf/perfuuid/perfsrvi.c24
-rw-r--r--private/oleutest/perf/perfuuid/sources68
-rw-r--r--private/oleutest/perf/proxy/dllentry.c224
-rw-r--r--private/oleutest/perf/proxy/makefile9
-rw-r--r--private/oleutest/perf/proxy/prxydll.def9
-rw-r--r--private/oleutest/perf/proxy/sources105
-rw-r--r--private/oleutest/perf/rel.cmd4
-rw-r--r--private/oleutest/perf16/idata/bookpart.h48
-rw-r--r--private/oleutest/perf16/idata/classids.reg16
-rw-r--r--private/oleutest/perf16/idata/client/datausr.cpp1260
-rw-r--r--private/oleutest/perf16/idata/client/datausr.h226
-rw-r--r--private/oleutest/perf16/idata/client/datausr.icobin0 -> 766 bytes
-rw-r--r--private/oleutest/perf16/idata/client/idatausr.def9
-rw-r--r--private/oleutest/perf16/idata/client/idatausr.rc120
-rw-r--r--private/oleutest/perf16/idata/client/make16.inc331
-rw-r--r--private/oleutest/perf16/idata/client/make16.mak58
-rw-r--r--private/oleutest/perf16/idata/client/makefile10
-rw-r--r--private/oleutest/perf16/idata/client/perror.cpp76
-rw-r--r--private/oleutest/perf16/idata/client/perror.h36
-rw-r--r--private/oleutest/perf16/idata/client/sources85
-rw-r--r--private/oleutest/perf16/idata/client/stgmedif.cpp60
-rw-r--r--private/oleutest/perf16/idata/client/stpwatch.cpp145
-rw-r--r--private/oleutest/perf16/idata/client/stpwatch.h28
-rw-r--r--private/oleutest/perf16/idata/dirs36
-rw-r--r--private/oleutest/perf16/idata/makefil037
-rw-r--r--private/oleutest/perf16/idata/my3216.h10
-rw-r--r--private/oleutest/perf16/idata/readme13
-rw-r--r--private/oleutest/perf16/idata/server/dataobj.cpp146
-rw-r--r--private/oleutest/perf16/idata/server/dataobj.h196
-rw-r--r--private/oleutest/perf16/idata/server/edataobj.cpp445
-rw-r--r--private/oleutest/perf16/idata/server/edataobj.def5
-rw-r--r--private/oleutest/perf16/idata/server/edataobj.h63
-rw-r--r--private/oleutest/perf16/idata/server/idataobj.cpp261
-rw-r--r--private/oleutest/perf16/idata/server/ienumfe.cpp146
-rw-r--r--private/oleutest/perf16/idata/server/make16.inc331
-rw-r--r--private/oleutest/perf16/idata/server/make16.mak70
-rw-r--r--private/oleutest/perf16/idata/server/makefile10
-rw-r--r--private/oleutest/perf16/idata/server/render.cpp50
-rw-r--r--private/oleutest/perf16/idata/server/sources86
-rw-r--r--private/oleutest/perf16/idata/server/stgmedif.cpp56
-rw-r--r--private/oleutest/perf16/idata/syshead.h9
-rw-r--r--private/oleutest/perform/bmcopy.bat8
-rw-r--r--private/oleutest/perform/cairo.inc45
-rw-r--r--private/oleutest/perform/cairole/dirs39
-rw-r--r--private/oleutest/perform/cairole/dll/daytona/makefile10
-rw-r--r--private/oleutest/perform/cairole/dll/daytona/makefile.inc1
-rw-r--r--private/oleutest/perform/cairole/dll/daytona/oletest.src48
-rw-r--r--private/oleutest/perform/cairole/dll/daytona/sources81
-rw-r--r--private/oleutest/perform/cairole/dll/dirs38
-rw-r--r--private/oleutest/perform/cairole/dll/makefile25
-rw-r--r--private/oleutest/perform/cairole/dll/oletest.cxx130
-rw-r--r--private/oleutest/perform/cairole/dll/oletest.def38
-rw-r--r--private/oleutest/perform/cairole/dll/testdllx.cxx49
-rw-r--r--private/oleutest/perform/cairole/makefile25
-rw-r--r--private/oleutest/perform/cairole/svr/bmtstsvr.cxx52
-rw-r--r--private/oleutest/perform/cairole/svr/daytona/makefile10
-rw-r--r--private/oleutest/perform/cairole/svr/daytona/sources68
-rw-r--r--private/oleutest/perform/cairole/svr/dirs38
-rw-r--r--private/oleutest/perform/cairole/svr/makefile25
-rw-r--r--private/oleutest/perform/cairole/tests/bm_activ.cxx158
-rw-r--r--private/oleutest/perform/cairole/tests/bm_activ.hxx43
-rw-r--r--private/oleutest/perform/cairole/tests/bm_alloc.cxx187
-rw-r--r--private/oleutest/perform/cairole/tests/bm_alloc.hxx52
-rw-r--r--private/oleutest/perform/cairole/tests/bm_api.cxx351
-rw-r--r--private/oleutest/perform/cairole/tests/bm_api.hxx72
-rw-r--r--private/oleutest/perform/cairole/tests/bm_cgps.cxx89
-rw-r--r--private/oleutest/perform/cairole/tests/bm_cgps.hxx38
-rw-r--r--private/oleutest/perform/cairole/tests/bm_filio.cxx690
-rw-r--r--private/oleutest/perform/cairole/tests/bm_filio.hxx121
-rw-r--r--private/oleutest/perform/cairole/tests/bm_iid.cxx110
-rw-r--r--private/oleutest/perform/cairole/tests/bm_iid.hxx42
-rw-r--r--private/oleutest/perform/cairole/tests/bm_init.cxx201
-rw-r--r--private/oleutest/perform/cairole/tests/bm_init.hxx49
-rw-r--r--private/oleutest/perform/cairole/tests/bm_marsh.cxx296
-rw-r--r--private/oleutest/perform/cairole/tests/bm_marsh.hxx53
-rw-r--r--private/oleutest/perform/cairole/tests/bm_mrsh2.cxx417
-rw-r--r--private/oleutest/perform/cairole/tests/bm_mrsh2.hxx61
-rw-r--r--private/oleutest/perform/cairole/tests/bm_nest.cxx190
-rw-r--r--private/oleutest/perform/cairole/tests/bm_nest.hxx48
-rw-r--r--private/oleutest/perform/cairole/tests/bm_noise.cxx108
-rw-r--r--private/oleutest/perform/cairole/tests/bm_noise.hxx41
-rw-r--r--private/oleutest/perform/cairole/tests/bm_nstg.cxx564
-rw-r--r--private/oleutest/perform/cairole/tests/bm_nstg.hxx111
-rw-r--r--private/oleutest/perform/cairole/tests/bm_obind.cxx197
-rw-r--r--private/oleutest/perform/cairole/tests/bm_obind.hxx42
-rw-r--r--private/oleutest/perform/cairole/tests/bm_piact.cxx221
-rw-r--r--private/oleutest/perform/cairole/tests/bm_piact.hxx42
-rw-r--r--private/oleutest/perform/cairole/tests/bm_props.cxx125
-rw-r--r--private/oleutest/perform/cairole/tests/bm_props.hxx38
-rw-r--r--private/oleutest/perform/cairole/tests/bm_qi.cxx198
-rw-r--r--private/oleutest/perform/cairole/tests/bm_qi.hxx44
-rw-r--r--private/oleutest/perform/cairole/tests/bm_regis.cxx175
-rw-r--r--private/oleutest/perform/cairole/tests/bm_regis.hxx41
-rw-r--r--private/oleutest/perform/cairole/tests/bm_rot.cxx366
-rw-r--r--private/oleutest/perform/cairole/tests/bm_rot.hxx55
-rw-r--r--private/oleutest/perform/cairole/tests/bm_rpc.cxx427
-rw-r--r--private/oleutest/perform/cairole/tests/bm_rpc.hxx71
-rw-r--r--private/oleutest/perform/cairole/tests/bm_rpc2.cxx311
-rw-r--r--private/oleutest/perform/cairole/tests/bm_rpc2.hxx57
-rw-r--r--private/oleutest/perform/cairole/tests/bm_rrpc.cxx500
-rw-r--r--private/oleutest/perform/cairole/tests/bm_rrpc.hxx57
-rw-r--r--private/oleutest/perform/cairole/tests/bm_sbind.cxx222
-rw-r--r--private/oleutest/perform/cairole/tests/bm_sbind.hxx42
-rw-r--r--private/oleutest/perform/cairole/tests/bm_stg.cxx624
-rw-r--r--private/oleutest/perform/cairole/tests/bm_stg.hxx100
-rw-r--r--private/oleutest/perform/cairole/tests/bmguid.cxx44
-rw-r--r--private/oleutest/perform/cairole/tests/bmp_stg.cxx471
-rw-r--r--private/oleutest/perform/cairole/tests/bmp_stg.hxx215
-rw-r--r--private/oleutest/perform/cairole/tests/bmp_stg2.cxx1425
-rw-r--r--private/oleutest/perform/cairole/tests/bmp_test.cxx90
-rw-r--r--private/oleutest/perform/cairole/tests/bmp_test.hxx41
-rw-r--r--private/oleutest/perform/cairole/tests/daytona/makefile10
-rw-r--r--private/oleutest/perform/cairole/tests/daytona/sources81
-rw-r--r--private/oleutest/perform/cairole/tests/dirs38
-rw-r--r--private/oleutest/perform/cairole/tests/headers.cxx18
-rw-r--r--private/oleutest/perform/cairole/tests/makefile25
-rw-r--r--private/oleutest/perform/cairole/tests/oletest.hxx71
-rw-r--r--private/oleutest/perform/cairole/tests/rawrpc_c.c848
-rw-r--r--private/oleutest/perform/cairole/tests/rawrpc_x.c5
-rw-r--r--private/oleutest/perform/cairole/ui/bm_cache.cxx503
-rw-r--r--private/oleutest/perform/cairole/ui/bm_cache.hxx69
-rw-r--r--private/oleutest/perform/cairole/ui/bm_clip.cxx608
-rw-r--r--private/oleutest/perform/cairole/ui/bm_clip.hxx87
-rw-r--r--private/oleutest/perform/cairole/ui/bm_crt.cxx332
-rw-r--r--private/oleutest/perform/cairole/ui/bm_crt.hxx67
-rw-r--r--private/oleutest/perform/cairole/ui/bm_crtl.cxx355
-rw-r--r--private/oleutest/perform/cairole/ui/bm_crtl.hxx67
-rw-r--r--private/oleutest/perform/cairole/ui/bm_link.cxx629
-rw-r--r--private/oleutest/perform/cairole/ui/bm_link.hxx90
-rw-r--r--private/oleutest/perform/cairole/ui/bm_load.cxx557
-rw-r--r--private/oleutest/perform/cairole/ui/bm_load.hxx95
-rw-r--r--private/oleutest/perform/cairole/ui/daytona/makefile10
-rw-r--r--private/oleutest/perform/cairole/ui/daytona/sources64
-rw-r--r--private/oleutest/perform/cairole/ui/dirs38
-rw-r--r--private/oleutest/perform/cairole/ui/headers.cxx18
-rw-r--r--private/oleutest/perform/cairole/ui/hlp_app.cxx963
-rw-r--r--private/oleutest/perform/cairole/ui/hlp_app.hxx75
-rw-r--r--private/oleutest/perform/cairole/ui/hlp_doc.cxx508
-rw-r--r--private/oleutest/perform/cairole/ui/hlp_doc.hxx52
-rw-r--r--private/oleutest/perform/cairole/ui/hlp_ias.cxx318
-rw-r--r--private/oleutest/perform/cairole/ui/hlp_ias.hxx44
-rw-r--r--private/oleutest/perform/cairole/ui/hlp_iocs.cxx373
-rw-r--r--private/oleutest/perform/cairole/ui/hlp_iocs.hxx44
-rw-r--r--private/oleutest/perform/cairole/ui/hlp_iopf.cxx641
-rw-r--r--private/oleutest/perform/cairole/ui/hlp_iopf.hxx52
-rw-r--r--private/oleutest/perform/cairole/ui/hlp_iops.cxx609
-rw-r--r--private/oleutest/perform/cairole/ui/hlp_iops.hxx54
-rw-r--r--private/oleutest/perform/cairole/ui/hlp_site.cxx668
-rw-r--r--private/oleutest/perform/cairole/ui/hlp_site.hxx63
-rw-r--r--private/oleutest/perform/cairole/ui/hlp_util.hxx37
-rw-r--r--private/oleutest/perform/cairole/ui/makefile12
-rw-r--r--private/oleutest/perform/cairole/ui/readme13
-rw-r--r--private/oleutest/perform/common/benchmrk.hxx41
-rw-r--r--private/oleutest/perform/common/bm_base.cxx87
-rw-r--r--private/oleutest/perform/common/bm_base.hxx41
-rw-r--r--private/oleutest/perform/common/bm_parse.cxx347
-rw-r--r--private/oleutest/perform/common/bm_parse.hxx86
-rw-r--r--private/oleutest/perform/common/bmcomm.cxx47
-rw-r--r--private/oleutest/perform/common/bmcomm.hxx49
-rw-r--r--private/oleutest/perform/common/bmconfig.cxx96
-rw-r--r--private/oleutest/perform/common/bmdriver.hxx37
-rw-r--r--private/oleutest/perform/common/bminput.cxx267
-rw-r--r--private/oleutest/perform/common/bminput.hxx56
-rw-r--r--private/oleutest/perform/common/bmlog.cxx105
-rw-r--r--private/oleutest/perform/common/bmlog.hxx28
-rw-r--r--private/oleutest/perform/common/bmoutput.cxx474
-rw-r--r--private/oleutest/perform/common/bmoutput.hxx53
-rw-r--r--private/oleutest/perform/common/bmrpc.cxx74
-rw-r--r--private/oleutest/perform/common/cqisrv.cxx114
-rw-r--r--private/oleutest/perform/common/cqisrv.hxx48
-rw-r--r--private/oleutest/perform/common/daytona/makefile10
-rw-r--r--private/oleutest/perform/common/daytona/sources62
-rw-r--r--private/oleutest/perform/common/dirs38
-rw-r--r--private/oleutest/perform/common/rawrpc.h167
-rw-r--r--private/oleutest/perform/common/stopwtch.cxx101
-rw-r--r--private/oleutest/perform/common/stopwtch.hxx61
-rw-r--r--private/oleutest/perform/common/stream.cxx315
-rw-r--r--private/oleutest/perform/common/stream.hxx96
-rw-r--r--private/oleutest/perform/daytona.inc40
-rw-r--r--private/oleutest/perform/dirs40
-rw-r--r--private/oleutest/perform/driver/bm.ini301
-rw-r--r--private/oleutest/perform/driver/bm.reg36
-rw-r--r--private/oleutest/perform/driver/bmdriver.cxx512
-rw-r--r--private/oleutest/perform/driver/bmguid.cxx45
-rw-r--r--private/oleutest/perform/driver/daytona/makefile10
-rw-r--r--private/oleutest/perform/driver/daytona/sources71
-rw-r--r--private/oleutest/perform/driver/dirs38
-rw-r--r--private/oleutest/perform/driver/makefil013
-rw-r--r--private/oleutest/perform/driver/makefile25
-rw-r--r--private/oleutest/perform/le/create/makefile10
-rw-r--r--private/oleutest/perform/le/create/ocperf.cpp793
-rw-r--r--private/oleutest/perform/le/create/ocperf.reg20
-rw-r--r--private/oleutest/perform/le/create/sources62
-rw-r--r--private/oleutest/perform/makefile25
-rw-r--r--private/oleutest/perform/procswap/daytona/makefile10
-rw-r--r--private/oleutest/perform/procswap/daytona/sources70
-rw-r--r--private/oleutest/perform/procswap/dirs38
-rw-r--r--private/oleutest/perform/procswap/procswap.cxx1249
-rw-r--r--private/oleutest/perform/rawrpc/daytona/makefile10
-rw-r--r--private/oleutest/perform/rawrpc/daytona/sources72
-rw-r--r--private/oleutest/perform/rawrpc/dirs38
-rw-r--r--private/oleutest/perform/rawrpc/rawrpc.cxx292
-rw-r--r--private/oleutest/perform/rawrpc/rawrpc_s.c1001
-rw-r--r--private/oleutest/perform/rawrpc/rawrpc_y.c5
-rw-r--r--private/oleutest/rot/daytona/makefile10
-rw-r--r--private/oleutest/rot/daytona/sources81
-rw-r--r--private/oleutest/rot/dirs38
-rw-r--r--private/oleutest/rot/rotut.cxx618
-rw-r--r--private/oleutest/server1/csrvapp.cxx294
-rw-r--r--private/oleutest/server1/ctestcf.cxx176
-rw-r--r--private/oleutest/server1/ctestemb.cxx227
-rw-r--r--private/oleutest/server1/daytona/makefile10
-rw-r--r--private/oleutest/server1/daytona/sources80
-rw-r--r--private/oleutest/server1/dirs38
-rw-r--r--private/oleutest/server1/idataobj.cxx306
-rw-r--r--private/oleutest/server1/ioleobj.cxx629
-rw-r--r--private/oleutest/server1/ipersist.cxx251
-rw-r--r--private/oleutest/server1/testsrv.cxx204
-rw-r--r--private/oleutest/server1/testsrv.hxx386
-rw-r--r--private/oleutest/server1/testsrv.icobin0 -> 766 bytes
-rw-r--r--private/oleutest/server1/testsrv.rc3
-rw-r--r--private/oleutest/server2/daytona/makefile10
-rw-r--r--private/oleutest/server2/daytona/sources75
-rw-r--r--private/oleutest/server2/dirs38
-rw-r--r--private/oleutest/server2/headers.cxx18
-rw-r--r--private/oleutest/server2/headers.hxx26
-rw-r--r--private/oleutest/server2/olesrv.cxx1001
-rw-r--r--private/oleutest/server2/olesrv.hxx145
-rw-r--r--private/oleutest/server2/smartp.hxx74
-rw-r--r--private/oleutest/server2/wterm.c1029
-rw-r--r--private/oleutest/server2/wterm.h48
-rw-r--r--private/oleutest/server3/daytona/makefile10
-rw-r--r--private/oleutest/server3/daytona/sources74
-rw-r--r--private/oleutest/server3/dirs38
-rw-r--r--private/oleutest/server3/fail.cxx82
-rw-r--r--private/oleutest/simpcntr/app.cpp1060
-rw-r--r--private/oleutest/simpcntr/app.h76
-rw-r--r--private/oleutest/simpcntr/daytona/makefile6
-rw-r--r--private/oleutest/simpcntr/daytona/sources43
-rw-r--r--private/oleutest/simpcntr/dirs3
-rw-r--r--private/oleutest/simpcntr/doc.cpp628
-rw-r--r--private/oleutest/simpcntr/doc.h55
-rw-r--r--private/oleutest/simpcntr/ias.cpp304
-rw-r--r--private/oleutest/simpcntr/ias.h44
-rw-r--r--private/oleutest/simpcntr/iocs.cpp368
-rw-r--r--private/oleutest/simpcntr/iocs.h44
-rw-r--r--private/oleutest/simpcntr/ioipf.cpp641
-rw-r--r--private/oleutest/simpcntr/ioipf.h51
-rw-r--r--private/oleutest/simpcntr/ioips.cpp615
-rw-r--r--private/oleutest/simpcntr/ioips.h53
-rw-r--r--private/oleutest/simpcntr/pre.cpp9
-rw-r--r--private/oleutest/simpcntr/pre.h32
-rw-r--r--private/oleutest/simpcntr/readme.txt31
-rw-r--r--private/oleutest/simpcntr/resource.h32
-rw-r--r--private/oleutest/simpcntr/simpcntr.cpp523
-rw-r--r--private/oleutest/simpcntr/simpcntr.def26
-rw-r--r--private/oleutest/simpcntr/simpcntr.h40
-rw-r--r--private/oleutest/simpcntr/simpcntr.icobin0 -> 766 bytes
-rw-r--r--private/oleutest/simpcntr/simpcntr.rc114
-rw-r--r--private/oleutest/simpcntr/site.cpp637
-rw-r--r--private/oleutest/simpcntr/site.h53
-rw-r--r--private/oleutest/simpcntr/tests.cpp202
-rw-r--r--private/oleutest/simpcntr/tests.h8
-rw-r--r--private/oleutest/simpcntr/utaccel.h7
-rw-r--r--private/oleutest/simpdnd/app.cpp852
-rw-r--r--private/oleutest/simpdnd/app.h67
-rw-r--r--private/oleutest/simpdnd/bang.icobin0 -> 1846 bytes
-rw-r--r--private/oleutest/simpdnd/daytona/makefile6
-rw-r--r--private/oleutest/simpdnd/daytona/sources41
-rw-r--r--private/oleutest/simpdnd/default.icobin0 -> 766 bytes
-rw-r--r--private/oleutest/simpdnd/depend.mk227
-rw-r--r--private/oleutest/simpdnd/dirs3
-rw-r--r--private/oleutest/simpdnd/doc.cpp825
-rw-r--r--private/oleutest/simpdnd/doc.h75
-rw-r--r--private/oleutest/simpdnd/dxferobj.cpp739
-rw-r--r--private/oleutest/simpdnd/dxferobj.h57
-rw-r--r--private/oleutest/simpdnd/enumfetc.h13
-rw-r--r--private/oleutest/simpdnd/filelist.mk83
-rw-r--r--private/oleutest/simpdnd/ias.cpp302
-rw-r--r--private/oleutest/simpdnd/ias.h43
-rw-r--r--private/oleutest/simpdnd/ids.cpp384
-rw-r--r--private/oleutest/simpdnd/ids.h43
-rw-r--r--private/oleutest/simpdnd/idt.cpp851
-rw-r--r--private/oleutest/simpdnd/idt.h76
-rw-r--r--private/oleutest/simpdnd/iocs.cpp365
-rw-r--r--private/oleutest/simpdnd/iocs.h44
-rw-r--r--private/oleutest/simpdnd/pre.cpp9
-rw-r--r--private/oleutest/simpdnd/pre.h30
-rw-r--r--private/oleutest/simpdnd/readme.txt47
-rw-r--r--private/oleutest/simpdnd/resource.h39
-rw-r--r--private/oleutest/simpdnd/simpdnd.cpp502
-rw-r--r--private/oleutest/simpdnd/simpdnd.h45
-rw-r--r--private/oleutest/simpdnd/simpdnd.icobin0 -> 766 bytes
-rw-r--r--private/oleutest/simpdnd/simpdnd.rc114
-rw-r--r--private/oleutest/simpdnd/site.cpp632
-rw-r--r--private/oleutest/simpdnd/site.h47
-rw-r--r--private/oleutest/simpdnd/strings.rc124
-rw-r--r--private/oleutest/simpdnd/tests.cpp198
-rw-r--r--private/oleutest/simpdnd/tests.h27
-rw-r--r--private/oleutest/simpsvr/app.cpp987
-rw-r--r--private/oleutest/simpsvr/app.h87
-rw-r--r--private/oleutest/simpsvr/bang.icobin0 -> 1846 bytes
-rw-r--r--private/oleutest/simpsvr/daytona/makefile6
-rw-r--r--private/oleutest/simpsvr/daytona/sources42
-rw-r--r--private/oleutest/simpsvr/debug.log1
-rw-r--r--private/oleutest/simpsvr/default.icobin0 -> 766 bytes
-rw-r--r--private/oleutest/simpsvr/depend.mk271
-rw-r--r--private/oleutest/simpsvr/dirs3
-rw-r--r--private/oleutest/simpsvr/doc.cpp688
-rw-r--r--private/oleutest/simpsvr/doc.h70
-rw-r--r--private/oleutest/simpsvr/filelist.mk71
-rw-r--r--private/oleutest/simpsvr/icf.cpp228
-rw-r--r--private/oleutest/simpsvr/icf.h46
-rw-r--r--private/oleutest/simpsvr/ido.cpp529
-rw-r--r--private/oleutest/simpsvr/ido.h51
-rw-r--r--private/oleutest/simpsvr/iec.cpp197
-rw-r--r--private/oleutest/simpsvr/iec.h43
-rw-r--r--private/oleutest/simpsvr/ioipao.cpp404
-rw-r--r--private/oleutest/simpsvr/ioipao.h48
-rw-r--r--private/oleutest/simpsvr/ioipo.cpp400
-rw-r--r--private/oleutest/simpsvr/ioipo.h43
-rw-r--r--private/oleutest/simpsvr/ioo.cpp1085
-rw-r--r--private/oleutest/simpsvr/ioo.h71
-rw-r--r--private/oleutest/simpsvr/ips.cpp654
-rw-r--r--private/oleutest/simpsvr/ips.h50
-rw-r--r--private/oleutest/simpsvr/makefile12
-rw-r--r--private/oleutest/simpsvr/makefile.new198
-rw-r--r--private/oleutest/simpsvr/obj.cpp1151
-rw-r--r--private/oleutest/simpsvr/obj.h141
-rw-r--r--private/oleutest/simpsvr/pre.cpp9
-rw-r--r--private/oleutest/simpsvr/pre.h29
-rw-r--r--private/oleutest/simpsvr/readme.txt32
-rw-r--r--private/oleutest/simpsvr/resource.h32
-rw-r--r--private/oleutest/simpsvr/simpsvr.cpp454
-rw-r--r--private/oleutest/simpsvr/simpsvr.def26
-rw-r--r--private/oleutest/simpsvr/simpsvr.h49
-rw-r--r--private/oleutest/simpsvr/simpsvr.icobin0 -> 766 bytes
-rw-r--r--private/oleutest/simpsvr/simpsvr.mak439
-rw-r--r--private/oleutest/simpsvr/simpsvr.prjbin0 -> 9456 bytes
-rw-r--r--private/oleutest/simpsvr/simpsvr.rc111
-rw-r--r--private/oleutest/simpsvr/strings.rc124
-rw-r--r--private/oleutest/stgdrt/daytona/makefile1
-rw-r--r--private/oleutest/stgdrt/daytona/sources87
-rw-r--r--private/oleutest/stgdrt/dirs38
-rw-r--r--private/oleutest/stgdrt/drt.cxx305
-rw-r--r--private/oleutest/stgdrt/drt.hxx110
-rw-r--r--private/oleutest/stgdrt/drtguid.cxx26
-rw-r--r--private/oleutest/stgdrt/headers.cxx33
-rw-r--r--private/oleutest/stgdrt/ilb.cxx422
-rw-r--r--private/oleutest/stgdrt/ilb.hxx75
-rw-r--r--private/oleutest/stgdrt/illeg.cxx148
-rw-r--r--private/oleutest/stgdrt/illeg.hxx21
-rw-r--r--private/oleutest/stgdrt/strlist.cxx148
-rw-r--r--private/oleutest/stgdrt/strlist.hxx49
-rw-r--r--private/oleutest/stgdrt/tests.cxx812
-rw-r--r--private/oleutest/stgdrt/tests.hxx31
-rw-r--r--private/oleutest/stgdrt/util.cxx587
-rw-r--r--private/oleutest/stgdrt/util.hxx45
-rw-r--r--private/oleutest/stgdrt/wrap.cxx707
-rw-r--r--private/oleutest/stgdrt/wrap.hxx377
-rw-r--r--private/oleutest/trktest/bill.sr2bin0 -> 4608 bytes
-rw-r--r--private/oleutest/trktest/dirs10
-rw-r--r--private/oleutest/trktest/trk1.bat34
-rw-r--r--private/oleutest/trktest/trktest.cxx216
-rw-r--r--private/oleutest/utests16/makefile.inc330
-rw-r--r--private/oleutest/utests16/ole2ui/ole2ui.h918
-rw-r--r--private/oleutest/utests16/ole2ui/ole2ui.rc40
-rw-r--r--private/oleutest/utests16/ole2ui/res/localole.h1001
-rw-r--r--private/oleutest/utests16/ole2ui/res/ole2ui.rcv90
-rw-r--r--private/oleutest/utests16/ole2ui/res/usa/bang.icobin0 -> 1846 bytes
-rw-r--r--private/oleutest/utests16/ole2ui/res/usa/busy.dlg13
-rw-r--r--private/oleutest/utests16/ole2ui/res/usa/convert.dlg32
-rw-r--r--private/oleutest/utests16/ole2ui/res/usa/default.icobin0 -> 766 bytes
-rw-r--r--private/oleutest/utests16/ole2ui/res/usa/egares.bmpbin0 -> 6838 bytes
-rw-r--r--private/oleutest/utests16/ole2ui/res/usa/fileopen.dlg33
-rw-r--r--private/oleutest/utests16/ole2ui/res/usa/hivgares.bmpbin0 -> 20326 bytes
-rw-r--r--private/oleutest/utests16/ole2ui/res/usa/icon.dlg48
-rw-r--r--private/oleutest/utests16/ole2ui/res/usa/insobj.dlg52
-rw-r--r--private/oleutest/utests16/ole2ui/res/usa/links.dlg35
-rw-r--r--private/oleutest/utests16/ole2ui/res/usa/pastespl.dlg40
-rw-r--r--private/oleutest/utests16/ole2ui/res/usa/prompt.dlg80
-rw-r--r--private/oleutest/utests16/ole2ui/res/usa/strings.rc124
-rw-r--r--private/oleutest/utests16/ole2ui/res/usa/verlocal.h54
-rw-r--r--private/oleutest/utests16/ole2ui/res/usa/vgares.bmpbin0 -> 9078 bytes
-rw-r--r--private/oleutest/utests16/ole2ui/strings.rc124
-rw-r--r--private/oleutest/utests16/simpdnd/app.cpp710
-rw-r--r--private/oleutest/utests16/simpdnd/app.h63
-rw-r--r--private/oleutest/utests16/simpdnd/doc.cpp722
-rw-r--r--private/oleutest/utests16/simpdnd/doc.h70
-rw-r--r--private/oleutest/utests16/simpdnd/dxferobj.cpp574
-rw-r--r--private/oleutest/utests16/simpdnd/dxferobj.h57
-rw-r--r--private/oleutest/utests16/simpdnd/ias.cpp316
-rw-r--r--private/oleutest/utests16/simpdnd/ias.h44
-rw-r--r--private/oleutest/utests16/simpdnd/ids.cpp330
-rw-r--r--private/oleutest/utests16/simpdnd/ids.h43
-rw-r--r--private/oleutest/utests16/simpdnd/idt.cpp814
-rw-r--r--private/oleutest/utests16/simpdnd/idt.h77
-rw-r--r--private/oleutest/utests16/simpdnd/iocs.cpp365
-rw-r--r--private/oleutest/utests16/simpdnd/iocs.h44
-rw-r--r--private/oleutest/utests16/simpdnd/makefile94
-rw-r--r--private/oleutest/utests16/simpdnd/pre.cpp9
-rw-r--r--private/oleutest/utests16/simpdnd/pre.h23
-rw-r--r--private/oleutest/utests16/simpdnd/readme.txt5
-rw-r--r--private/oleutest/utests16/simpdnd/resource.h29
-rw-r--r--private/oleutest/utests16/simpdnd/simpdnd.cpp452
-rw-r--r--private/oleutest/utests16/simpdnd/simpdnd.h15
-rw-r--r--private/oleutest/utests16/simpdnd/simpdnd.icobin0 -> 766 bytes
-rw-r--r--private/oleutest/utests16/simpdnd/site.cpp627
-rw-r--r--private/oleutest/utests16/simpdnd/site.h47
-rw-r--r--private/oleutest/utests16/simpdnd/spdnd16.def22
-rw-r--r--private/oleutest/utests16/simpdnd/spdnd16.rc105
-rw-r--r--private/oleutest/utests16/simpdnd/tests.cpp202
-rw-r--r--private/oleutest/utests16/simpdnd/tests.h27
-rw-r--r--private/oleutest/utests16/simpsvr/app.cpp810
-rw-r--r--private/oleutest/utests16/simpsvr/app.h85
-rw-r--r--private/oleutest/utests16/simpsvr/doc.cpp693
-rw-r--r--private/oleutest/utests16/simpsvr/doc.h65
-rw-r--r--private/oleutest/utests16/simpsvr/icf.cpp235
-rw-r--r--private/oleutest/utests16/simpsvr/icf.h45
-rw-r--r--private/oleutest/utests16/simpsvr/ido.cpp544
-rw-r--r--private/oleutest/utests16/simpsvr/ido.h53
-rw-r--r--private/oleutest/utests16/simpsvr/iec.cpp212
-rw-r--r--private/oleutest/utests16/simpsvr/iec.h44
-rw-r--r--private/oleutest/utests16/simpsvr/ioipao.cpp400
-rw-r--r--private/oleutest/utests16/simpsvr/ioipao.h50
-rw-r--r--private/oleutest/utests16/simpsvr/ioipo.cpp413
-rw-r--r--private/oleutest/utests16/simpsvr/ioipo.h45
-rw-r--r--private/oleutest/utests16/simpsvr/ioo.cpp1082
-rw-r--r--private/oleutest/utests16/simpsvr/ioo.h73
-rw-r--r--private/oleutest/utests16/simpsvr/ips.cpp651
-rw-r--r--private/oleutest/utests16/simpsvr/ips.h53
-rw-r--r--private/oleutest/utests16/simpsvr/makefile98
-rw-r--r--private/oleutest/utests16/simpsvr/obj.cpp1057
-rw-r--r--private/oleutest/utests16/simpsvr/obj.h141
-rw-r--r--private/oleutest/utests16/simpsvr/pre.cpp9
-rw-r--r--private/oleutest/utests16/simpsvr/pre.h22
-rw-r--r--private/oleutest/utests16/simpsvr/readme.txt7
-rw-r--r--private/oleutest/utests16/simpsvr/resource.h32
-rw-r--r--private/oleutest/utests16/simpsvr/simpsvr.cpp357
-rw-r--r--private/oleutest/utests16/simpsvr/simpsvr.h16
-rw-r--r--private/oleutest/utests16/simpsvr/simpsvr.icobin0 -> 766 bytes
-rw-r--r--private/oleutest/utests16/simpsvr/simpsvr.reg21
-rw-r--r--private/oleutest/utests16/simpsvr/spsvr16.def22
-rw-r--r--private/oleutest/utests16/simpsvr/spsvr16.rc107
-rw-r--r--private/oleutest/uthread/at/makefile10
-rw-r--r--private/oleutest/uthread/at/makefile.inc1
-rw-r--r--private/oleutest/uthread/at/oleat.cpp26
-rw-r--r--private/oleutest/uthread/at/oleat.src48
-rw-r--r--private/oleutest/uthread/at/sources96
-rw-r--r--private/oleutest/uthread/bt/makefile10
-rw-r--r--private/oleutest/uthread/bt/makefile.inc1
-rw-r--r--private/oleutest/uthread/bt/olebt.cpp474
-rw-r--r--private/oleutest/uthread/bt/olebt.src48
-rw-r--r--private/oleutest/uthread/bt/sources89
-rw-r--r--private/oleutest/uthread/comclass.h17
-rw-r--r--private/oleutest/uthread/common/classdef.cpp25
-rw-r--r--private/oleutest/uthread/common/comclass.cpp436
-rw-r--r--private/oleutest/uthread/common/makefile10
-rw-r--r--private/oleutest/uthread/common/sources77
-rw-r--r--private/oleutest/uthread/common/sources.inc2
-rw-r--r--private/oleutest/uthread/dirs7
-rw-r--r--private/oleutest/uthread/st/makefile10
-rw-r--r--private/oleutest/uthread/st/makefile.inc1
-rw-r--r--private/oleutest/uthread/st/olest.cpp26
-rw-r--r--private/oleutest/uthread/st/olest.src47
-rw-r--r--private/oleutest/uthread/st/sources89
-rw-r--r--private/oleutest/uthread/uthread.h24
1208 files changed, 277347 insertions, 0 deletions
diff --git a/private/oleutest/act/acttest.h b/private/oleutest/act/acttest.h
new file mode 100644
index 000000000..8ac135237
--- /dev/null
+++ b/private/oleutest/act/acttest.h
@@ -0,0 +1,44 @@
+/*
+ * acttest.h
+ */
+
+#ifndef _CLSID_
+#define _CLSID_
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+
+extern CLSID CLSID_ActLocal;
+extern CLSID CLSID_ActRemote;
+extern CLSID CLSID_ActAtStorage;
+extern CLSID CLSID_ActInproc;
+extern CLSID CLSID_ActPreConfig;
+extern CLSID CLSID_ActRunAsLoggedOn;
+extern CLSID CLSID_ActService;
+extern CLSID CLSID_ActServerOnly;
+
+extern TCHAR * ClsidGoober32String;
+extern TCHAR * ClsidActLocalString;
+extern TCHAR * ClsidActRemoteString;
+extern TCHAR * ClsidActAtStorageString;
+extern TCHAR * ClsidActInprocString;
+extern TCHAR * ClsidActPreConfigString;
+extern TCHAR * ClsidActRunAsLoggedOnString;
+extern TCHAR * ClsidActServiceString;
+extern TCHAR * ClsidActServerOnlyString;
+
+void DeleteClsidKey( TCHAR * pwszClsid );
+
+long SetAppIDSecurity( TCHAR * pszAppID );
+
+
+int AddBatchPrivilege(const TCHAR *szUser);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/private/oleutest/act/client/client.cxx b/private/oleutest/act/client/client.cxx
new file mode 100644
index 000000000..cd13f1b7d
--- /dev/null
+++ b/private/oleutest/act/client/client.cxx
@@ -0,0 +1,2122 @@
+/*
+ * client.cxx
+ */
+
+#include "client.hxx"
+
+#define MIN_TEST_NUMBER 1
+#define MAX_TEST_NUMBER 27
+
+BOOL UnimplementedTest();
+BOOL UnsupportedTest();
+BOOL GenericCITest(REFCLSID clsid, REFIID iid, WCHAR * wszServerName, int n, DWORD ctxt);
+
+BOOL CGCOLocalEXE();
+BOOL CGCOExplicitActivator();
+BOOL CILocalDLL();
+BOOL CILocalEXE();
+BOOL CIExplicitActivator();
+BOOL CI3LocalEXE();
+BOOL CI3ExplicitActivator();
+BOOL CGIFFLocalEXE();
+BOOL CGIFFExplicitActivator();
+BOOL CGIFFRegistryActivator();
+BOOL CGIFFAtStorageActivator();
+BOOL IMBLocalEXE();
+BOOL IMBLocalService();
+BOOL IMBAtStorageActivator();
+BOOL IMBAtStorageService();
+BOOL IMBAtStoragePreCon();
+BOOL IMBAtStorageUser();
+BOOL CIFromStgLocalEXE();
+BOOL CIFromStgActivator();
+BOOL CICustomLocalDLL();
+BOOL CICustomLocalEXE();
+BOOL CILocalPreCon();
+BOOL CIExplicitPreCon();
+BOOL CILocalUser();
+BOOL CIExplicitUser();
+BOOL CILocalPreConACL();
+BOOL CIExplicitPreConACL();
+BOOL CILocalService();
+BOOL CIExplicitService();
+
+#ifdef NO_DCOM
+LPTESTFUNC rgTest[] =
+ {
+ NULL,
+ CGCOLocalEXE,
+ UnsupportedTest,
+ CILocalDLL,
+ CILocalEXE,
+ UnsupportedTest,
+ UnsupportedTest,
+ UnsupportedTest,
+ UnsupportedTest,
+ UnsupportedTest,
+ UnsupportedTest,
+ UnsupportedTest
+/* New tests
+ UnsupportedTest,
+ UnsupportedTest,
+end new tests */
+ CI3LocalEXE,
+ UnsupportedTest,
+ UnsupportedTest,
+ UnsupportedTest,
+ UnsupportedTest,
+ UnsupportedTest,
+ UnsupportedTest,
+ UnsupportedTest,
+ IMBLocalEXE,
+ UnsupportedTest,
+ UnsupportedTest,
+ UnsupportedTest,
+ UnsupportedTest,
+ UnsupportedTest,
+ UnsupportedTest,
+ UnsupportedTest,
+ NULL
+ };
+#else
+#ifdef CHICO
+LPTESTFUNC rgTest[] =
+ {
+ NULL,
+ CGCOLocalEXE,
+ CGCOExplicitActivator,
+ CILocalDLL,
+ CILocalEXE,
+ CIExplicitActivator,
+ CILocalPreCon,
+ CIExplicitPreCon,
+ CILocalUser,
+ CIExplicitUser,
+ UnsupportedTest,
+ CIExplicitService,
+/* new tests
+ CILocalPreConACL,
+ CIExplicitPreConACL,
+end new tests */
+ CI3LocalEXE,
+ CI3ExplicitActivator,
+ CICustomLocalDLL,
+ CICustomLocalEXE,
+ CGIFFLocalEXE,
+ CGIFFExplicitActivator,
+ CGIFFRegistryActivator,
+ CGIFFAtStorageActivator,
+ IMBLocalEXE,
+ UnsupportedTest,
+ IMBAtStorageActivator,
+ IMBAtStorageService,
+ IMBAtStoragePreCon,
+ IMBAtStorageUser,
+ CIFromStgLocalEXE,
+ CIFromStgActivator,
+ NULL
+ };
+#else
+LPTESTFUNC rgTest[] =
+ {
+ NULL,
+ CGCOLocalEXE,
+ CGCOExplicitActivator,
+ CILocalDLL,
+ CILocalEXE,
+ CIExplicitActivator,
+ CILocalPreCon,
+ CIExplicitPreCon,
+ CILocalUser,
+ CIExplicitUser,
+ CILocalService,
+ CIExplicitService,
+/* new tests
+ CILocalPreConACL,
+ CIExplicitPreConACL,
+end new tests */
+ CI3LocalEXE,
+ CI3ExplicitActivator,
+ CICustomLocalDLL,
+ CICustomLocalEXE,
+ CGIFFLocalEXE,
+ CGIFFExplicitActivator,
+ CGIFFRegistryActivator,
+ CGIFFAtStorageActivator,
+ IMBLocalEXE,
+ IMBLocalService,
+ IMBAtStorageActivator,
+ IMBAtStorageService,
+ IMBAtStoragePreCon,
+ IMBAtStorageUser,
+ CIFromStgLocalEXE,
+ CIFromStgActivator,
+ NULL
+ };
+#endif // CHICO
+#endif // NO_DCOM
+
+char * TestName[] =
+ {
+ NULL,
+ "CoGetClassObject local EXE",
+ "CoGetClassObject explicit activator",
+ "CoCreateInstance local DLL",
+ "CoCreateInstance local EXE",
+ "CoCreateInstance explicit activator",
+ "CoCreateInstance local pre-configured",
+ "CoCreateInstance explicit pre-configured",
+ "CoCreateInstance local user",
+ "CoCreateInstance explicit user",
+ "CoCreateInstance local service",
+ "CoCreateInstance explicit service",
+/* new tests
+ "CoCreateInstance local pre-configured ACL",
+ "CoCreateInstance explicit pre-configured ACL",
+end new tests */
+ "CoCreateInstance (3 IIDs) local EXE",
+ "CoCreateInstance (3 IIDs) explicit activator",
+ "CoCreateInstance from custom itf. local DLL",
+ "CoCreateInstance from custom itf. local EXE",
+ "CoGetInstanceFromFile local EXE",
+ "CoGetInstanceFromFile explicit activator",
+ "CoGetInstanceFromFile registry activator",
+ "CoGetInstanceFromFile AtStorage activator",
+ "IMoniker::BindToObject local EXE",
+ "IMoniker::BindToObject local service",
+ "IMoniker::BindToObject AtStorage activator",
+ "IMoniker::BindToObject AtStorage service",
+ "IMoniker::BindToObject AtStorage pre-configured",
+ "IMoniker::BindToObject AtStorage user",
+ "CoGetInstanceFromIStorage local EXE",
+ "CoGetInstanceFromIStorage explicit activator",
+ NULL
+ };
+
+char RunTest[] =
+ {
+ -1,
+ // CoGetClassObject
+ YES,
+ YES,
+ // CoCreateInstance
+ YES,
+ YES,
+ YES,
+ YES,
+ YES,
+ YES,
+ YES,
+ YES,
+ YES,
+/* new tests
+ YES,
+ YES,
+end new tests */
+ // CoCreateInstance (3 IIDs)
+ YES,
+ YES,
+ // CoGetInstanceFromFile
+ YES,
+ YES,
+ YES,
+ YES,
+ // IMoniker:Bind
+ YES,
+ YES,
+ YES,
+ YES,
+ YES,
+ YES,
+ YES,
+ YES,
+ YES,
+ YES,
+ -1
+ };
+
+char RunLocalTest[] =
+ {
+ -1,
+ // CoGetClassObject
+ YES,
+ NO,
+ // CreateInstance
+ YES,
+ YES,
+ NO,
+ YES,
+ NO,
+ YES,
+ NO,
+ YES,
+ NO,
+/* new tests
+ YES,
+ NO,
+end new tests */
+ // CreateInstance (3 IIDs)
+ YES,
+ NO,
+ // CreateInstance from custom Itf.
+ YES,
+ YES,
+ // CoGetInstanceFromFile
+ YES,
+ NO,
+ NO,
+ NO,
+ // IMoniker:Bind
+ YES,
+ YES,
+ NO,
+ NO,
+ NO,
+ NO,
+ // CoGetInstanceFromIStorage
+ YES,
+ NO,
+ -1
+ };
+
+WCHAR ServerName[32];
+WCHAR RemoteFileName[256];
+WCHAR * LocalFileName = L"c:\\acttest.dat";
+WCHAR * StorageName = L"c:\\acttest.stg";
+#ifndef UNICODE
+char szRemoteFileName[256];
+char * szLocalFileName = "c:\\acttest.dat";
+char * szStorageName = "c:\\acttest.stg";
+#endif
+
+LARGE_INTEGER liPerfFreq;
+LARGE_INTEGER liStart;
+LARGE_INTEGER liStop;
+LARGE_INTEGER liElapsedTime;
+
+#define RESET_CLOCK liElapsedTime.LowPart = liElapsedTime.HighPart = 0
+#define START_CLOCK QueryPerformanceCounter(&liStart)
+#define STOP_CLOCK QueryPerformanceCounter(&liStop); \
+ liElapsedTime.QuadPart += liStop.QuadPart - liStart.QuadPart
+#define DUMP_CLOCK DisplayElapsedTime()
+#define START_LOOP for (unsigned sl_n = uIterations+1; sl_n--;){
+#define STOP_LOOP if (uIterations == sl_n ) RESET_CLOCK;}
+#define SLEEP_IF_LOOPING if (sl_n && !gfHoldServer) Sleep(1000)
+
+unsigned uIterations = 0;
+
+BOOL gfRegister = TRUE;
+BOOL gfHoldServer = FALSE;
+BOOL gfLocal = FALSE;
+BOOL gfNolocal = FALSE;
+BOOL gfSpecificTest = FALSE;
+
+void DisplayElapsedTime(void)
+{
+ LONGLONG MicroPerIter;
+
+ liElapsedTime.QuadPart /= uIterations;
+
+ MicroPerIter = liElapsedTime.QuadPart * 1000000;
+ MicroPerIter /= liPerfFreq.QuadPart;
+
+ printf( "Time: %d microseconds per iteration", (DWORD) MicroPerIter );
+}
+
+BOOL AllLocal()
+{
+ for (int x = MIN_TEST_NUMBER; x<= MAX_TEST_NUMBER; x++)
+ {
+ if (RunTest[x] && !RunLocalTest[x])
+ return(FALSE);
+ }
+ return(TRUE);
+}
+
+void _cdecl main( int argc, char ** argv )
+{
+ HRESULT HResult;
+ HANDLE hFile;
+ int n;
+
+#ifndef NO_DCOM
+ if ( argc == 1 )
+ PrintUsageAndExit( FALSE );
+#endif // NO_DCOM
+
+ if ( argc > 1 && strcmp(argv[1],"-?") == 0 )
+ PrintUsageAndExit( TRUE );
+
+ n = 1;
+
+ while ( (n < argc) && (*argv[n] == '-') )
+ {
+ if ( (n < argc) && strcmp(argv[n],"-local") == 0 )
+ {
+ if (gfLocal | gfNolocal)
+ {
+ PrintUsageAndExit( FALSE );
+ }
+ gfLocal = TRUE;
+ memcpy(RunTest, RunLocalTest, MAX_TEST_NUMBER + MIN_TEST_NUMBER);
+ n++;
+ }
+
+ if ( (n < argc) && strcmp(argv[n],"-nolocal") == 0 )
+ {
+ if (gfLocal | gfNolocal)
+ {
+ PrintUsageAndExit( FALSE );
+ }
+ gfNolocal = TRUE;
+ for (int x = MIN_TEST_NUMBER; x<= MAX_TEST_NUMBER; x++)
+ {
+ RunTest[x] = !RunLocalTest[x];
+ }
+ n++;
+ }
+
+ if ( (n < argc) && strcmp(argv[n],"-noreg") == 0 )
+ {
+ gfRegister = FALSE;
+ n++;
+ continue;
+ }
+
+ if ( (n < argc) && strcmp(argv[n],"-hold") == 0 )
+ {
+ gfHoldServer = TRUE;
+ n++;
+ continue;
+ }
+
+ if ( (n < argc) && strcmp(argv[n],"-n") == 0 )
+ {
+ if ( ++n >= argc )
+ PrintUsageAndExit(FALSE);
+
+ uIterations = atoi(argv[n++]);
+ }
+
+ if ( (n < argc) && strcmp(argv[n],"-t") == 0 )
+ {
+ long TestNum1, TestNum2;
+
+ if ( ++n >= argc )
+ PrintUsageAndExit(FALSE);
+
+ TestNum1 = atoi(argv[n++]);
+
+ if ( (n < argc) && ((TestNum2 = atoi(argv[n])) != 0) )
+ n++;
+ else
+ TestNum2 = TestNum1;
+
+ if ( (TestNum1 < MIN_TEST_NUMBER) || (TestNum2 > MAX_TEST_NUMBER) )
+ {
+ printf( "Test number(s) must be between %d and %d.\n",
+ MIN_TEST_NUMBER,
+ MAX_TEST_NUMBER );
+ return;
+ }
+
+ if ( TestNum1 > TestNum2 )
+ {
+ printf( "Second test number must be greater than the first.\n" );
+ return;
+ }
+
+ if (!gfSpecificTest)
+ {
+ gfSpecificTest = TRUE;
+ // only do this the first time -t is found on the command line
+ memset(RunTest,NO,sizeof(RunTest));
+ }
+ memset(&RunTest[TestNum1],YES,sizeof(char)*(TestNum2-TestNum1+1));
+ }
+ }
+
+#ifndef NO_DCOM
+ if ( n != argc - 1 && !AllLocal())
+ {
+ printf("ERROR - Selected tests require a server name.\n");
+ ExitThread(0);
+ }
+
+ if ( n < argc )
+ {
+ MultiByteToWideChar( CP_ACP,
+ 0,
+ argv[n],
+ -1,
+ ServerName,
+ sizeof(ServerName) / sizeof(WCHAR) );
+ }
+ else
+ {
+ ServerName[0] = 0;
+ }
+#endif // NO_DCOM
+
+ hFile = CreateFile(
+#ifdef UNICODE
+ LocalFileName,
+#else
+ szLocalFileName,
+#endif
+ GENERIC_WRITE,
+ FILE_SHARE_READ,
+ 0,
+ OPEN_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ 0 );
+
+ if ( hFile == INVALID_HANDLE_VALUE )
+ {
+ printf("CreateFile failed while creating local file: %d\n", GetLastError());
+ return;
+ }
+
+ CloseHandle( hFile );
+
+#ifndef NO_DCOM
+ if ( ServerName[0] != 0 )
+ {
+ RemoteFileName[0] = 0;
+
+ if ( ServerName[0] != L'\\' )
+ wcscat( RemoteFileName, L"\\\\" );
+
+ wcscat( RemoteFileName, ServerName );
+ wcscat( RemoteFileName, L"\\c$\\acttest.dat" );
+
+#ifndef UNICODE
+ WideCharToMultiByte(
+ CP_ACP,
+ 0,
+ RemoteFileName,
+ -1,
+ szRemoteFileName,
+ sizeof(szRemoteFileName),
+ NULL,
+ NULL );
+#endif
+
+ hFile = CreateFile(
+#ifdef UNICODE
+ RemoteFileName,
+#else
+ szRemoteFileName,
+#endif
+ GENERIC_WRITE,
+ FILE_SHARE_READ,
+ 0,
+ OPEN_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ 0 );
+
+ if ( hFile == INVALID_HANDLE_VALUE )
+ {
+ printf("CreateFile failed while creating remote file: %d\n", GetLastError());
+ return;
+ }
+
+ CloseHandle( hFile );
+ }
+#endif // NO_DCOM
+
+ HResult = CoInitialize(NULL);
+
+ if( FAILED(HResult) )
+ {
+ printf( "Client CoInitialize failed Ox%x!\n", HResult );
+ return;
+ }
+
+ if ((!QueryPerformanceFrequency(&liPerfFreq)) && uIterations > 0)
+ {
+ printf("No high performance counter.\nTests cannot be timed.\nAborting.\n");
+ }
+ else
+ {
+ if ( ! Tests() )
+ printf("\nTests FAILED\n");
+ else
+ printf("\nTests SUCCEEDED\n");
+ }
+
+ CoUninitialize();
+#ifdef UNICODE
+ DeleteFile( LocalFileName );
+#ifndef NO_DCOM
+ DeleteFile( RemoteFileName );
+#endif // NO_DCOM
+#else
+ DeleteFile( szLocalFileName );
+#ifndef NO_DCOM
+ DeleteFile( szRemoteFileName );
+#endif // NO_DCOM
+#endif
+}
+
+BOOL Tests()
+{
+ HRESULT HResult;
+ long RegStatus;
+
+ if (gfRegister)
+ {
+ DeleteClsidKey( ClsidGoober32String );
+ DeleteClsidKey( ClsidActLocalString );
+ DeleteClsidKey( ClsidActRemoteString );
+ DeleteClsidKey( ClsidActAtStorageString );
+ DeleteClsidKey( ClsidActInprocString );
+ DeleteClsidKey( ClsidActPreConfigString );
+ DeleteClsidKey( ClsidActRunAsLoggedOnString );
+ DeleteClsidKey( ClsidActServiceString );
+ DeleteClsidKey( ClsidActServerOnlyString );
+
+ if ( (RegStatus = InitializeRegistryForInproc()) != ERROR_SUCCESS )
+ {
+ printf("InitializeRegistryForInproc failed %d.\n", RegStatus);
+ return FALSE;
+ }
+
+ if ( (RegStatus = InitializeRegistryForLocal()) != ERROR_SUCCESS )
+ {
+ printf("InitializeRegistryForLocal failed %d.\n", RegStatus);
+ return FALSE;
+ }
+
+ if ( (RegStatus = InitializeRegistryForCustom()) != ERROR_SUCCESS )
+ {
+ printf("InitializeRegistryForCustom failed %d.\n", RegStatus);
+ return FALSE;
+ }
+ #ifndef NO_DCOM
+ if ( (RegStatus = InitializeRegistryForRemote()) != ERROR_SUCCESS )
+ {
+ printf("InitializeRegistryForRemote failed %d.\n", RegStatus);
+ return FALSE;
+ }
+
+ if ( (RegStatus = InitializeRegistryForService()) != ERROR_SUCCESS )
+ {
+ printf("InitializeRegistryForService failed %d.\n", RegStatus);
+ return FALSE;
+ }
+ #endif // NO_DCOM
+ }
+ BOOL fAllTests = TRUE;
+
+ for (int x = MIN_TEST_NUMBER; x <= MAX_TEST_NUMBER; x++)
+ {
+ if (RunTest[x])
+ {
+ printf("\nTest %2d: %s\n",x, TestName[x]);
+ // prime the system once to ensure the test is fully cached
+ if (rgTest[x]())
+ {
+ printf("PASSED");
+ if (uIterations)
+ {
+ printf(" - ");
+ DUMP_CLOCK;
+ }
+ printf("\n");
+ }
+ else
+ {
+ printf("FAILED\n");
+ fAllTests = FALSE;
+ }
+
+ }
+ }
+
+ return(fAllTests);
+}
+
+void PrintUsageAndExit( BOOL bListTests )
+{
+#ifdef NO_DCOM
+ printf("Usage : %s [-hold] [-noreg] [-n #] [-t # [#]]\n", "actclt");
+ printf("\t-n # : Run specific number of timed iterations (default is 0).\n");
+ printf("\t-noreg : Don't update registry\n");
+ printf("\t-t # : Run specific test number or a range of tests.\n");
+ printf("\t-? : Print usage plus test descriptions.\n");
+#else
+ printf("Usage : %s [-hold] [-noreg] [[-local] | [-nolocal]] [-n #] [-t # [#]] [server_name]\n", "actclt");
+ printf("\t-hold : Hold the server up during all iterations.\n");
+ printf("\t-local : Run only local activation tests.\n");
+ printf("\t-n # : Run specific number of timed iterations (default is 0).\n");
+ printf("\t-nolocal : Run only remote activation tests.\n");
+ printf("\t-noreg : Don't update registry\n");
+ printf("\t-t # : Run specific test number or a range of tests.\n");
+ printf("\t-? : Print usage plus test descriptions.\n");
+#endif // NO_DCOM
+
+ if ( bListTests )
+ {
+ long n;
+
+ printf("\nTests :\n");
+ printf("\t # Method Location Security\n");
+ printf("\t-- ----------------------------------- ----------- --------------\n");
+
+ for ( n = MIN_TEST_NUMBER; n <= MAX_TEST_NUMBER; n++ )
+ {
+ printf("\t%2d %s\n", n, TestName[n]);
+ }
+ }
+
+ ExitThread(0);
+}
+
+void * __RPC_API
+MIDL_user_allocate(size_t len)
+{
+ return malloc(len);
+}
+
+void __RPC_API
+MIDL_user_free(void * vp)
+{
+ free(vp);
+}
+
+BOOL StampFileWithCLSID(WCHAR * szFilename, CLSID & clsid)
+{
+ HRESULT hr;
+ IStorage * pStg;
+
+ hr = StgCreateDocfile(
+ szFilename,
+ STGM_READWRITE | STGM_DIRECT | STGM_SHARE_EXCLUSIVE | STGM_CREATE,
+ 0,
+ &pStg);
+
+ if (FAILED (hr))
+ {
+ printf("StgCreateDocfile returned 0x%x\n", hr);
+ return(FALSE);
+ }
+
+ hr = WriteClassStg(pStg, clsid);
+
+ pStg->Release();
+
+ if (FAILED (hr))
+ {
+ printf("WriteClassStg returned 0x%x\n", hr);
+ return(FALSE);
+ }
+
+ return(TRUE);
+}
+
+//
+// Test Procedures:
+//
+
+BOOL UnimplementedTest()
+{
+ printf("Not implemented at this time.\n");
+ return(TRUE);
+}
+
+BOOL UnsupportedTest()
+{
+ printf("Not supported by this version.\n");
+ return(TRUE);
+}
+
+BOOL GenericCITest(REFCLSID clsid, REFIID iid, WCHAR * wszServerName, int n, DWORD ctxt)
+{
+ COSERVERINFO ServerInfo;
+ COSERVERINFO *pServerInfo;
+ IUnknown * punkHeld = NULL;
+
+ if (wszServerName)
+ {
+ memset( &ServerInfo, 0, sizeof(COSERVERINFO) );
+ ServerInfo.pwszName = wszServerName;
+ pServerInfo = &ServerInfo;
+ }
+ else
+ {
+ pServerInfo = NULL;
+ }
+
+ MULTI_QI QIStruct[10];
+ int x;
+ HRESULT hr;
+ BOOL fReturn = TRUE;
+
+ START_LOOP;
+
+ for (x = n; x--;)
+ {
+ QIStruct[x].pItf = NULL;
+ QIStruct[x].pIID = (IID *) &iid;
+ }
+
+
+ START_CLOCK;
+ hr = CoCreateInstanceEx(
+ clsid,
+ NULL,
+ ctxt,
+ pServerInfo,
+ n,
+ QIStruct);
+ STOP_CLOCK;
+
+ if ( FAILED(hr) )
+ {
+ printf("CoCreateInstanceEx returned 0x%x\n", hr);
+ if (punkHeld)
+ punkHeld->Release();
+ return FALSE;
+ }
+
+ if (gfHoldServer && NULL == punkHeld && SUCCEEDED(QIStruct[0].hr))
+ {
+ punkHeld = QIStruct[0].pItf;
+ punkHeld->AddRef();
+ }
+
+ for (x = 0; x < n; x++)
+ {
+ if (FAILED(QIStruct[x].hr))
+ {
+ printf("CoCreateInstanceEx returned 0x%x for interface %d\n",
+ QIStruct[x].hr, x);
+ fReturn = FALSE;
+ }
+ else
+ QIStruct[x].pItf->Release();
+ }
+ if (!fReturn)
+ {
+ if (punkHeld)
+ punkHeld->Release();
+ return(fReturn);
+ }
+
+ STOP_LOOP;
+
+ if (punkHeld)
+ punkHeld->Release();
+
+ return fReturn;
+}
+
+BOOL CGCOLocalEXE()
+{
+ IClassFactory * pClassFactory;
+ IUnknown * pUnknown;
+ IUnknown * punkHeld = NULL;
+ HRESULT hr;
+
+ START_LOOP;
+
+ START_CLOCK;
+ hr = CoGetClassObject(
+ CLSID_ActLocal,
+ CLSCTX_LOCAL_SERVER,
+ NULL,
+ IID_IClassFactory,
+ (void **) &pClassFactory );
+ STOP_CLOCK;
+
+ if ( FAILED(hr) )
+ {
+ printf("CoGetClassObject returned 0x%x\n", hr);
+ if (punkHeld)
+ punkHeld->Release();
+ return FALSE;
+ }
+
+ hr = pClassFactory->CreateInstance( NULL,
+ IID_IUnknown,
+ (void **) &pUnknown );
+
+ pClassFactory->Release();
+
+ if ( FAILED(hr) )
+ {
+ printf("CreateInstance returned 0x%x\n", hr);
+ if (punkHeld)
+ punkHeld->Release();
+ return FALSE;
+ }
+
+ if (gfHoldServer && NULL == punkHeld)
+ {
+ punkHeld = pUnknown;
+ punkHeld->AddRef();
+ }
+
+ pUnknown->Release();
+
+ STOP_LOOP;
+
+ if (punkHeld)
+ punkHeld->Release();
+
+ return TRUE;
+}
+
+#ifndef NO_DCOM
+BOOL CGCOExplicitActivator()
+{
+ COSERVERINFO ServerInfo;
+ IClassFactory * pClassFactory;
+ IUnknown * pUnknown;
+ IUnknown * punkHeld = NULL;
+ HRESULT hr;
+
+ memset( &ServerInfo, 0, sizeof(COSERVERINFO) );
+ ServerInfo.pwszName = ServerName;
+
+ START_LOOP;
+
+ START_CLOCK;
+ hr = CoGetClassObject(
+ CLSID_ActLocal,
+ CLSCTX_REMOTE_SERVER,
+ &ServerInfo,
+ IID_IClassFactory,
+ (void **) &pClassFactory );
+ STOP_CLOCK;
+
+ if ( FAILED(hr) )
+ {
+ printf("CoGetClassObject returned 0x%x\n", hr);
+ if (punkHeld)
+ punkHeld->Release();
+ return FALSE;
+ }
+
+ hr = pClassFactory->CreateInstance( NULL,
+ IID_IUnknown,
+ (void **) &pUnknown );
+
+ pClassFactory->Release();
+
+ if ( FAILED(hr) )
+ {
+ printf("CreateInstance returned 0x%x\n", hr);
+ if (punkHeld)
+ punkHeld->Release();
+ return FALSE;
+ }
+
+ if (gfHoldServer && NULL == punkHeld)
+ {
+ punkHeld = pUnknown;
+ punkHeld->AddRef();
+ }
+
+ pUnknown->Release();
+
+ STOP_LOOP;
+
+ if (punkHeld)
+ punkHeld->Release();
+ return TRUE;
+}
+#endif // NO_DCOM
+
+#ifdef NO_DCOM
+BOOL CILocalDLL()
+{
+ IUnknown * pUnknown;
+ IUnknown * punkHeld = NULL;
+ HRESULT hr;
+
+ START_LOOP;
+
+ START_CLOCK;
+ hr = CoCreateInstance(
+ CLSID_ActInproc,
+ NULL,
+ CLSCTX_INPROC_SERVER,
+ IID_IUnknown,
+ (void **) &pUnknown );
+ STOP_CLOCK;
+
+ if ( FAILED(hr) )
+ {
+ printf("CoCreateInstance returned 0x%x\n", hr);
+ if (punkHeld)
+ punkHeld->Release();
+ return FALSE;
+ }
+
+ if (gfHoldServer && NULL == punkHeld)
+ {
+ punkHeld = pUnknown;
+ punkHeld->AddRef();
+ }
+
+ pUnknown->Release();
+
+ STOP_LOOP;
+
+ if (punkHeld)
+ punkHeld->Release();
+ return TRUE;
+}
+
+BOOL CILocalEXE()
+{
+ IUnknown * pUnknown;
+ IUnknown * punkHeld = NULL;
+ HRESULT hr;
+
+ START_LOOP;
+
+ START_CLOCK;
+ hr = CoCreateInstance(
+ CLSID_ActLocal,
+ NULL,
+ CLSCTX_LOCAL_SERVER,
+ IID_IUnknown,
+ (void **) &pUnknown );
+ STOP_CLOCK;
+
+ if ( FAILED(hr) )
+ {
+ printf("CoCreateInstance returned 0x%x\n", hr);
+ if (punkHeld)
+ punkHeld->Release();
+ return FALSE;
+ }
+
+ if (gfHoldServer && NULL == punkHeld)
+ {
+ punkHeld = pUnknown;
+ punkHeld->AddRef();
+ }
+
+ pUnknown->Release();
+
+ STOP_LOOP;
+
+ if (punkHeld)
+ punkHeld->Release();
+
+ return TRUE;
+}
+#else
+BOOL CILocalDLL()
+{
+ return GenericCITest(CLSID_ActInproc, IID_IUnknown, NULL, 1, CLSCTX_INPROC_SERVER);
+}
+
+BOOL CILocalEXE()
+{
+ return GenericCITest(CLSID_ActLocal, IID_IUnknown, NULL, 1, CLSCTX_LOCAL_SERVER);
+}
+
+BOOL CIExplicitActivator()
+{
+#ifdef UNICODE
+ return GenericCITest(CLSID_ActLocal, IID_IUnknown, ServerName, 1, CLSCTX_REMOTE_SERVER);
+#else
+ return GenericCITest(CLSID_ActLocal, IID_IUnknown, wszServerName, 1, CLSCTX_REMOTE_SERVER);
+#endif
+}
+#endif // NO_DCOM
+
+#ifdef NO_DCOM
+// Pre-DCOM version of CI3LocalEXE which calls CoCreateInstance
+// once followed by 2 calls to QueryInterface
+// instead of calling CoCreateInstanceEx.
+BOOL CI3LocalEXE()
+{
+ IUnknown * pUnknown;
+ IUnknwon * punkHeld = NULL;
+ IPersist * pPersist;
+ IPersistFile * pPersistFile;
+
+ HRESULT hr;
+
+ START_LOOP;
+
+ START_CLOCK;
+ hr = CoCreateInstance(
+ CLSID_ActLocal,
+ NULL,
+ CLSCTX_LOCAL_SERVER,
+ IID_IUnknown,
+ (void **) &pUnknown );
+
+ if ( FAILED(hr) )
+ {
+ printf("CoCreateInstance returned 0x%x\n", hr);
+ if (punkHeld)
+ punkHeld->Release();
+ return FALSE;
+ }
+
+ if (gfHoldServer && NULL == punkHeld)
+ {
+ punkHeld = pUnknown;
+ punkHeld->AddRef();
+ }
+
+ pUnknown->QueryInterface( IID_IPersist, (void **)&pPersist );
+ pUnknown->QueryInterface( IID_IPersist, (void **)&pPersistFile );
+ STOP_CLOCK;
+
+ pUnknown->Release();
+ pPersist->Release();
+ pPersistFile->Release();
+
+ STOP_LOOP;
+
+ if (punkHeld)
+ punkHeld->Release();
+
+ return TRUE;
+}
+#else // NO_DCOM
+
+BOOL CI3LocalEXE()
+{
+ return GenericCITest(CLSID_ActLocal, IID_IPersist, NULL, 3, CLSCTX_LOCAL_SERVER);
+ /*
+ MULTI_QI QIStruct[3];
+ QIStruct[0].pIID = (IID *)&IID_IUnknown;
+ QIStruct[1].pIID = (IID *)&IID_IPersist;
+ QIStruct[2].pIID = (IID *)&IID_IPersistFile;
+ QIStruct[0].pItf = NULL;
+ QIStruct[1].pItf = NULL;
+ QIStruct[2].pItf = NULL;
+ */
+}
+
+BOOL CI3ExplicitActivator()
+{
+#ifdef UNICODE
+ return GenericCITest(CLSID_ActLocal, IID_IPersist, ServerName, 3, CLSCTX_REMOTE_SERVER);
+#else
+ return GenericCITest(CLSID_ActLocal, IID_IPersist, wszServerName, 3, CLSCTX_REMOTE_SERVER);
+#endif
+ /*
+ MULTI_QI QIStruct[3];
+ QIStruct[0].pIID = (IID *)&IID_IUnknown;
+ QIStruct[1].pIID = (IID *)&IID_IPersist;
+ QIStruct[2].pIID = (IID *)&IID_IPersistFile;
+ QIStruct[0].pItf = NULL;
+ QIStruct[1].pItf = NULL;
+ QIStruct[2].pItf = NULL;
+ */
+}
+
+BOOL CGIFFLocalEXE()
+{
+ MULTI_QI QIStruct[1];
+ IUnknown * punkHeld = NULL;
+
+ START_LOOP;
+
+ QIStruct[0].pIID = (IID *)&IID_IUnknown;
+ QIStruct[0].pItf = NULL;
+
+ START_CLOCK;
+ HRESULT HResult = CoGetInstanceFromFile(
+ NULL,
+ &CLSID_ActLocal,
+ NULL,
+ CLSCTX_LOCAL_SERVER,
+ STGM_READWRITE,
+ LocalFileName,
+ 1,
+ QIStruct );
+ STOP_CLOCK;
+
+ if ( FAILED(HResult) )
+ {
+ printf("CoGetInstanceFromFile returned 0x%x\n", HResult);
+ if (punkHeld)
+ punkHeld->Release();
+ return FALSE;
+ }
+
+ if (gfHoldServer && NULL == punkHeld)
+ {
+ punkHeld = QIStruct[0].pItf;
+ punkHeld->AddRef();
+ }
+
+ QIStruct[0].pItf->Release();
+
+ STOP_LOOP;
+
+ if (punkHeld)
+ punkHeld->Release();
+ return(TRUE);
+}
+
+BOOL CGIFFExplicitActivator()
+{
+ COSERVERINFO ServerInfo;
+ IUnknown * punkHeld = NULL;
+
+ memset( &ServerInfo, 0, sizeof(COSERVERINFO) );
+ ServerInfo.pwszName = ServerName;
+
+ MULTI_QI QIStruct[1];
+
+ START_LOOP;
+
+ QIStruct[0].pIID = (IID *)&IID_IUnknown;
+ QIStruct[0].pItf = NULL;
+
+ START_CLOCK;
+ HRESULT HResult = CoGetInstanceFromFile(
+ &ServerInfo,
+ &CLSID_ActLocal,
+ NULL,
+ CLSCTX_REMOTE_SERVER,
+ STGM_READWRITE,
+ RemoteFileName,
+ 1,
+ QIStruct );
+ STOP_CLOCK;
+
+ if ( FAILED(HResult) )
+ {
+ printf("CoGetInstanceFromFile returned 0x%x\n", HResult);
+ if (punkHeld)
+ punkHeld->Release();
+ return FALSE;
+ }
+
+ if (gfHoldServer && NULL == punkHeld)
+ {
+ punkHeld = QIStruct[0].pItf;
+ punkHeld->AddRef();
+ }
+
+ QIStruct[0].pItf->Release();
+
+ STOP_LOOP;
+
+ if (punkHeld)
+ punkHeld->Release();
+ return(TRUE);
+}
+
+BOOL CGIFFRegistryActivator()
+{
+ MULTI_QI QIStruct[1];
+ IUnknown * punkHeld = NULL;
+
+ START_LOOP;
+
+ QIStruct[0].pIID = (IID *)&IID_IUnknown;
+ QIStruct[0].pItf = NULL;
+ START_CLOCK;
+ HRESULT HResult = CoGetInstanceFromFile(
+ NULL,
+ &CLSID_ActRemote,
+ NULL,
+ CLSCTX_REMOTE_SERVER,
+ STGM_READWRITE,
+ RemoteFileName,
+ 1,
+ QIStruct );
+ STOP_CLOCK;
+
+ if ( FAILED(HResult) )
+ {
+ printf("CoGetInstanceFromFile returned 0x%x\n", HResult);
+ if (punkHeld)
+ punkHeld->Release();
+ return FALSE;
+ }
+
+ if (gfHoldServer && NULL == punkHeld)
+ {
+ punkHeld = QIStruct[0].pItf;
+ punkHeld->AddRef();
+ }
+
+ QIStruct[0].pItf->Release();
+
+ STOP_LOOP;
+
+ if (punkHeld)
+ punkHeld->Release();
+ return(TRUE);
+}
+
+BOOL CGIFFAtStorageActivator()
+{
+ MULTI_QI QIStruct[1];
+ IUnknown * punkHeld = NULL;
+
+ START_LOOP;
+
+ QIStruct[0].pIID = (IID *)&IID_IUnknown;
+ QIStruct[0].pItf = NULL;
+ START_CLOCK;
+ HRESULT HResult = CoGetInstanceFromFile(
+ NULL,
+ &CLSID_ActAtStorage,
+ NULL,
+ CLSCTX_REMOTE_SERVER,
+ STGM_READWRITE,
+ RemoteFileName,
+ 1,
+ QIStruct );
+ STOP_CLOCK;
+
+ if ( FAILED(HResult) )
+ {
+ printf("CoGetInstanceFromFile returned 0x%x\n", HResult);
+ if (punkHeld)
+ punkHeld->Release();
+ return FALSE;
+ }
+
+ if (gfHoldServer && NULL == punkHeld)
+ {
+ punkHeld = QIStruct[0].pItf;
+ punkHeld->AddRef();
+ }
+
+ QIStruct[0].pItf->Release();
+
+ STOP_LOOP;
+
+ if (punkHeld)
+ punkHeld->Release();
+ return(TRUE);
+}
+#endif // NO_DCOM
+
+BOOL IMBLocalEXE()
+{
+ IBindCtx * pBc;
+ IUnknown * pUnk;
+ IUnknown * punkHeld = NULL;
+ HRESULT hr;
+ IMoniker *pMon;
+
+ if (!StampFileWithCLSID(LocalFileName, CLSID_ActLocal))
+ {
+ return(FALSE);
+ }
+
+ hr = CreateFileMoniker(LocalFileName, &pMon);
+
+ if (FAILED(hr))
+ {
+ printf("CreateFileMoniker returned 0x%x\n", hr);
+ }
+
+ hr = CreateBindCtx(0, &pBc);
+
+ if (FAILED(hr))
+ {
+ printf("CreateBindCtx returned 0x%x\n", hr);
+ pMon->Release();
+ return(FALSE);
+ }
+
+ START_LOOP;
+
+ START_CLOCK;
+ hr = pMon->BindToObject(
+ pBc,
+ NULL,
+ IID_IUnknown,
+ (void **) &pUnk);
+ STOP_CLOCK;
+
+ if (FAILED(hr))
+ {
+ printf("IMoniker::BindToObject returned 0x%x\n", hr);
+ if (punkHeld)
+ punkHeld->Release();
+ return(FALSE);
+ }
+
+ if (gfHoldServer && NULL == punkHeld)
+ {
+ punkHeld = pUnk;
+ punkHeld->AddRef();
+ }
+
+ pUnk->Release();
+
+ STOP_LOOP
+
+ pMon->Release();
+ pBc->Release();
+
+ if (punkHeld)
+ punkHeld->Release();
+ return(TRUE);
+}
+
+#ifndef NO_DCOM
+BOOL IMBLocalService()
+{
+ IBindCtx * pBc;
+ IUnknown * pUnk;
+ IUnknown * punkHeld = NULL;
+ HRESULT hr;
+ IMoniker *pMon;
+
+ if (!StampFileWithCLSID(LocalFileName, CLSID_ActService))
+ {
+ return(FALSE);
+ }
+
+ hr = CreateFileMoniker(LocalFileName, &pMon);
+
+ if (FAILED(hr))
+ {
+ printf("CreateFileMoniker returned 0x%x\n", hr);
+ }
+
+ hr = CreateBindCtx(0, &pBc);
+
+ if (FAILED(hr))
+ {
+ printf("CreateBindCtx returned 0x%x\n", hr);
+ pMon->Release();
+ return(FALSE);
+ }
+
+ START_LOOP;
+
+ START_CLOCK;
+ hr = pMon->BindToObject(
+ pBc,
+ NULL,
+ IID_IUnknown,
+ (void **) &pUnk);
+ STOP_CLOCK;
+ if (FAILED(hr))
+ {
+ printf("IMoniker::BindToObject returned 0x%x\n", hr);
+ if (punkHeld)
+ punkHeld->Release();
+ return(FALSE);
+ }
+
+ if (gfHoldServer && NULL == punkHeld)
+ {
+ punkHeld = pUnk;
+ punkHeld->AddRef();
+ }
+ pUnk->Release();
+
+ SLEEP_IF_LOOPING;
+
+ STOP_LOOP;
+
+ pMon->Release();
+ pBc->Release();
+
+ if (punkHeld)
+ punkHeld->Release();
+ return(TRUE);
+}
+
+BOOL IMBAtStorageActivator()
+{
+ IBindCtx * pBc;
+ IUnknown * pUnk;
+ IUnknown * punkHeld = NULL;
+ HRESULT hr;
+ IMoniker *pMon;
+
+ if (!StampFileWithCLSID(RemoteFileName, CLSID_ActAtStorage))
+ {
+ return(FALSE);
+ }
+
+ hr = CreateFileMoniker(RemoteFileName, &pMon);
+
+ if (FAILED(hr))
+ {
+ printf("CreateFileMoniker returned 0x%x\n", hr);
+ }
+
+ hr = CreateBindCtx(0, &pBc);
+
+ if (FAILED(hr))
+ {
+ printf("CreateBindCtx returned 0x%x\n", hr);
+ pMon->Release();
+ return(FALSE);
+ }
+
+ START_LOOP;
+
+ START_CLOCK;
+ hr = pMon->BindToObject(
+ pBc,
+ NULL,
+ IID_IUnknown,
+ (void **) &pUnk);
+ STOP_CLOCK;
+
+ if (FAILED(hr))
+ {
+ printf("IMoniker::BindToObject returned 0x%x\n", hr);
+ if (punkHeld)
+ punkHeld->Release();
+ return(FALSE);
+ }
+
+ if (gfHoldServer && NULL == punkHeld)
+ {
+ punkHeld = pUnk;
+ punkHeld->AddRef();
+ }
+
+ pUnk->Release();
+
+ STOP_LOOP;
+
+ pMon->Release();
+ pBc->Release();
+
+ if (punkHeld)
+ punkHeld->Release();
+ return(TRUE);
+}
+
+BOOL IMBAtStorageService()
+{
+ IBindCtx * pBc;
+ IUnknown * pUnk;
+ IUnknown * punkHeld = NULL;
+ HRESULT hr;
+ IMoniker *pMon;
+
+ if (!StampFileWithCLSID(RemoteFileName, CLSID_ActService))
+ {
+ return(FALSE);
+ }
+
+ hr = CreateFileMoniker(RemoteFileName, &pMon);
+
+ if (FAILED(hr))
+ {
+ printf("CreateFileMoniker returned 0x%x\n", hr);
+ }
+
+ hr = CreateBindCtx(0, &pBc);
+
+ if (FAILED(hr))
+ {
+ printf("CreateBindCtx returned 0x%x\n", hr);
+ pMon->Release();
+ return(FALSE);
+ }
+
+ START_LOOP;
+
+ START_CLOCK;
+ hr = pMon->BindToObject(
+ pBc,
+ NULL,
+ IID_IUnknown,
+ (void **) &pUnk);
+ STOP_CLOCK;
+
+ if (FAILED(hr))
+ {
+ printf("IMoniker::BindToObject returned 0x%x\n", hr);
+ if (punkHeld)
+ punkHeld->Release();
+ return(FALSE);
+ }
+
+ if (gfHoldServer && NULL == punkHeld)
+ {
+ punkHeld = pUnk;
+ punkHeld->AddRef();
+ }
+
+ pUnk->Release();
+
+ SLEEP_IF_LOOPING;
+
+ STOP_LOOP;
+
+ pMon->Release();
+ pBc->Release();
+
+ if (punkHeld)
+ punkHeld->Release();
+ return(TRUE);
+}
+
+BOOL IMBAtStoragePreCon()
+{
+ IBindCtx * pBc;
+ IUnknown * pUnk;
+ IUnknown * punkHeld = NULL;
+ HRESULT hr;
+ IMoniker *pMon;
+
+ if (!StampFileWithCLSID(RemoteFileName, CLSID_ActPreConfig))
+ {
+ return(FALSE);
+ }
+
+ hr = CreateFileMoniker(RemoteFileName, &pMon);
+
+ if (FAILED(hr))
+ {
+ printf("CreateFileMoniker returned 0x%x\n", hr);
+ }
+
+ hr = CreateBindCtx(0, &pBc);
+
+ if (FAILED(hr))
+ {
+ printf("CreateBindCtx returned 0x%x\n", hr);
+ pMon->Release();
+ return(FALSE);
+ }
+
+ START_LOOP;
+
+ START_CLOCK;
+ hr = pMon->BindToObject(
+ pBc,
+ NULL,
+ IID_IUnknown,
+ (void **) &pUnk);
+ STOP_CLOCK;
+
+ if (FAILED(hr))
+ {
+ printf("IMoniker::BindToObject returned 0x%x\n", hr);
+ if (punkHeld)
+ punkHeld->Release();
+ return(FALSE);
+ }
+
+ if (gfHoldServer && NULL == punkHeld)
+ {
+ punkHeld = pUnk;
+ punkHeld->AddRef();
+ }
+
+ pUnk->Release();
+
+ STOP_LOOP;
+
+ pMon->Release();
+ pBc->Release();
+
+ if (punkHeld)
+ punkHeld->Release();
+ return(TRUE);
+}
+
+BOOL IMBAtStorageUser()
+{
+ IBindCtx * pBc;
+ IUnknown * pUnk;
+ IUnknown * punkHeld = NULL;
+ HRESULT hr;
+ IMoniker *pMon;
+
+ if (!StampFileWithCLSID(RemoteFileName, CLSID_ActRunAsLoggedOn))
+ {
+ return(FALSE);
+ }
+
+ hr = CreateFileMoniker(RemoteFileName, &pMon);
+
+ if (FAILED(hr))
+ {
+ printf("CreateFileMoniker returned 0x%x\n", hr);
+ }
+
+ hr = CreateBindCtx(0, &pBc);
+
+ if (FAILED(hr))
+ {
+ printf("CreateBindCtx returned 0x%x\n", hr);
+ pMon->Release();
+ return(FALSE);
+ }
+
+ START_LOOP;
+
+ START_CLOCK;
+ hr = pMon->BindToObject(
+ pBc,
+ NULL,
+ IID_IUnknown,
+ (void **) &pUnk);
+ STOP_CLOCK;
+
+ if (FAILED(hr))
+ {
+ printf("IMoniker::BindToObject returned 0x%x\n", hr);
+ if (punkHeld)
+ punkHeld->Release();
+ return(FALSE);
+ }
+
+ if (gfHoldServer && NULL == punkHeld)
+ {
+ punkHeld = pUnk;
+ punkHeld->AddRef();
+ }
+
+ pUnk->Release();
+
+ STOP_LOOP;
+
+ pMon->Release();
+ pBc->Release();
+
+ if (punkHeld)
+ punkHeld->Release();
+ return(TRUE);
+}
+
+BOOL CIFromStgLocalEXE()
+{
+ IStorage * pStorage;
+ MULTI_QI QIStruct[10];
+ IUnknown * punkHeld = NULL;
+
+ pStorage = 0;
+
+#ifdef UNICODE
+ DeleteFile( StorageName );
+#else
+ DeleteFile( szStorageName );
+#endif
+
+ HRESULT HResult = StgCreateDocfile(
+ StorageName,
+ STGM_READWRITE | STGM_DIRECT | STGM_SHARE_EXCLUSIVE | STGM_CREATE,
+ 0,
+ &pStorage );
+
+ if ( FAILED(HResult) )
+ {
+ printf("StgCreateDocfile returned 0x%x\n", HResult);
+ return FALSE;
+ }
+
+ START_LOOP;
+
+ QIStruct[0].pIID = (IID *)&IID_IUnknown;
+ QIStruct[0].pItf = NULL;
+
+ START_CLOCK;
+ HResult = CoGetInstanceFromIStorage(
+ NULL,
+ &CLSID_ActLocal,
+ NULL,
+ CLSCTX_SERVER,
+ pStorage,
+ 1,
+ QIStruct );
+ STOP_CLOCK;
+
+ if ( FAILED(HResult) )
+ {
+ printf("CoGetInstanceFromIStorage returned 0x%x\n", HResult);
+ if (punkHeld)
+ punkHeld->Release();
+ return FALSE;
+ }
+
+ if (gfHoldServer && NULL == punkHeld)
+ {
+ punkHeld = QIStruct[0].pItf;
+ punkHeld->AddRef();
+ }
+
+ QIStruct[0].pItf->Release();
+ QIStruct[0].pItf = 0;
+
+ STOP_LOOP;
+
+ pStorage->Release();
+
+ if (punkHeld)
+ punkHeld->Release();
+ return(TRUE);
+}
+
+BOOL CIFromStgActivator()
+{
+ IStorage * pStorage;
+ MULTI_QI QIStruct[10];
+ COSERVERINFO ServerInfo;
+ IUnknown * punkHeld = NULL;
+
+ memset( &ServerInfo, 0, sizeof(COSERVERINFO) );
+ ServerInfo.pwszName = ServerName;
+
+ pStorage = 0;
+
+#ifdef UNICODE
+ DeleteFile( StorageName );
+#else
+ DeleteFile( szStorageName );
+#endif
+
+ HRESULT HResult = StgCreateDocfile(
+ StorageName,
+ STGM_READWRITE | STGM_DIRECT | STGM_SHARE_EXCLUSIVE | STGM_CREATE,
+ 0,
+ &pStorage );
+
+ if ( FAILED(HResult) )
+ {
+ printf("StgCreateDocfile returned 0x%x\n", HResult);
+ return FALSE;
+ }
+
+ START_LOOP;
+
+ QIStruct[0].pIID = (IID *)&IID_IUnknown;
+ QIStruct[0].pItf = NULL;
+
+ START_CLOCK;
+ HResult = CoGetInstanceFromIStorage(
+ &ServerInfo,
+ &CLSID_ActRemote,
+ NULL,
+ CLSCTX_REMOTE_SERVER,
+ pStorage,
+ 1,
+ QIStruct );
+ STOP_CLOCK;
+
+ if ( FAILED(HResult) )
+ {
+ printf("CoGetInstanceFromIStorage returned 0x%x\n", HResult);
+ if (punkHeld)
+ punkHeld->Release();
+ return FALSE;
+ }
+
+ if (gfHoldServer && NULL == punkHeld)
+ {
+ punkHeld = QIStruct[0].pItf;
+ punkHeld->AddRef();
+ }
+
+ QIStruct[0].pItf->Release();
+ QIStruct[0].pItf = 0;
+
+ STOP_LOOP;
+
+ pStorage->Release();
+
+ if (punkHeld)
+ punkHeld->Release();
+ return(TRUE);
+}
+
+BOOL CICustomLocalDLL()
+{
+ IGoober * pGoober;
+ MULTI_QI QIStruct[10];
+ HRESULT hr;
+ IUnknown * punkHeld = NULL;
+
+ START_LOOP;
+
+ QIStruct[0].pItf = NULL;
+ QIStruct[0].pIID = (IID *) &IID_IGoober;
+
+ START_CLOCK;
+ hr = CoCreateInstanceEx(
+ CLSID_ActInproc,
+ NULL,
+ CLSCTX_INPROC_SERVER,
+ NULL,
+ 1,
+ QIStruct );
+ STOP_CLOCK;
+
+ pGoober = (IGoober *)QIStruct[0].pItf;
+
+ if ( FAILED(hr) )
+ {
+ printf("CoCreateInstanceEx returned 0x%x\n", hr);
+ if (punkHeld)
+ punkHeld->Release();
+ return FALSE;
+ }
+
+ if (gfHoldServer && NULL == punkHeld)
+ {
+ punkHeld = QIStruct[0].pItf;
+ punkHeld->AddRef();
+ }
+
+ START_CLOCK;
+ hr = pGoober->Ping();
+ STOP_CLOCK;
+
+ if ( hr != S_OK )
+ {
+ printf("IGoober::Ping returned %d\n", hr);
+ pGoober->Release();
+ if (punkHeld)
+ punkHeld->Release();
+ return FALSE;
+ }
+
+ pGoober->Release();
+
+ STOP_LOOP;
+
+ if (punkHeld)
+ punkHeld->Release();
+ return(TRUE);
+}
+
+BOOL CICustomLocalEXE()
+{
+ IGoober * pGoober;
+ MULTI_QI QIStruct[10];
+ HRESULT hr;
+ IUnknown * punkHeld = NULL;
+
+ START_LOOP;
+
+ QIStruct[0].pItf = NULL;
+ QIStruct[0].pIID = (IID *) &IID_IGoober;
+
+ START_CLOCK;
+ hr = CoCreateInstanceEx(
+ CLSID_ActLocal,
+ NULL,
+ CLSCTX_LOCAL_SERVER,
+ NULL,
+ 1,
+ QIStruct );
+ STOP_CLOCK;
+
+ pGoober = (IGoober *)QIStruct[0].pItf;
+
+ if ( FAILED(hr) )
+ {
+ printf("CoCreateInstanceEx returned 0x%x\n", hr);
+ if (punkHeld)
+ punkHeld->Release();
+ return FALSE;
+ }
+
+ if (gfHoldServer && NULL == punkHeld)
+ {
+ punkHeld = QIStruct[0].pItf;
+ punkHeld->AddRef();
+ }
+
+ START_CLOCK;
+ hr = pGoober->Ping();
+ STOP_CLOCK;
+
+ if ( hr != S_OK )
+ {
+ printf("IGoober::Ping returned %d\n", hr);
+ pGoober->Release();
+ if (punkHeld)
+ punkHeld->Release();
+ return FALSE;
+ }
+
+ pGoober->Release();
+
+ STOP_LOOP;
+
+ if (punkHeld)
+ punkHeld->Release();
+ return(TRUE);
+}
+
+BOOL CILocalPreCon()
+{
+ return GenericCITest(CLSID_ActPreConfig, IID_IUnknown, NULL, 1, CLSCTX_LOCAL_SERVER);
+}
+
+BOOL CIExplicitPreCon()
+{
+#ifdef UNICODE
+ return GenericCITest(CLSID_ActPreConfig, IID_IUnknown, ServerName, 1, CLSCTX_REMOTE_SERVER);
+#else
+ return GenericCITest(CLSID_ActPreConfig, IID_IUnknown, wszServerName, 1, CLSCTX_REMOTE_SERVER);
+#endif
+}
+
+BOOL CILocalUser()
+{
+ return GenericCITest(CLSID_ActRunAsLoggedOn, IID_IUnknown, NULL, 1, CLSCTX_LOCAL_SERVER);
+}
+
+BOOL CIExplicitUser()
+{
+#ifdef UNICODE
+ return GenericCITest(CLSID_ActRunAsLoggedOn, IID_IUnknown, ServerName, 1, CLSCTX_REMOTE_SERVER);
+#else
+ return GenericCITest(CLSID_ActRunAsLoggedOn, IID_IUnknown, wszServerName, 1, CLSCTX_REMOTE_SERVER);
+#endif
+}
+
+BOOL CILocalService()
+{
+ COSERVERINFO ServerInfo;
+ COSERVERINFO *pServerInfo;
+ IUnknown * punkHeld = NULL;
+
+ MULTI_QI QIStruct[1];
+ HRESULT hr;
+ BOOL fReturn = TRUE;
+
+ START_LOOP;
+
+ QIStruct[0].pItf = NULL;
+ QIStruct[0].pIID = (IID *) &IID_IUnknown;
+
+ START_CLOCK;
+ hr = CoCreateInstanceEx(
+ CLSID_ActService,
+ NULL,
+ CLSCTX_LOCAL_SERVER,
+ NULL,
+ 1,
+ QIStruct);
+ STOP_CLOCK;
+
+ if ( FAILED(hr) )
+ {
+ printf("CoCreateInstanceEx returned 0x%x\n", hr);
+ if (punkHeld)
+ punkHeld->Release();
+ return FALSE;
+ }
+
+ if (gfHoldServer && NULL == punkHeld && SUCCEEDED(QIStruct[0].hr))
+ {
+ punkHeld = QIStruct[0].pItf;
+ punkHeld->AddRef();
+ }
+
+ if (FAILED(QIStruct[0].hr))
+ {
+ printf("CoCreateInstanceEx returned 0x%x\n",
+ QIStruct[0].hr);
+ fReturn = FALSE;
+ }
+ else
+ QIStruct[0].pItf->Release();
+
+ if (!fReturn)
+ {
+ if (punkHeld)
+ punkHeld->Release();
+ return(fReturn);
+ }
+
+ SLEEP_IF_LOOPING;
+
+ STOP_LOOP;
+
+ if (punkHeld)
+ punkHeld->Release();
+
+ return fReturn;
+}
+
+BOOL CIExplicitService()
+{
+ COSERVERINFO ServerInfo;
+ COSERVERINFO *pServerInfo;
+ IUnknown * punkHeld = NULL;
+
+ memset( &ServerInfo, 0, sizeof(COSERVERINFO) );
+ ServerInfo.pwszName = ServerName;
+ pServerInfo = &ServerInfo;
+
+ MULTI_QI QIStruct[1];
+ HRESULT hr;
+ BOOL fReturn = TRUE;
+
+ START_LOOP;
+
+ QIStruct[0].pItf = NULL;
+ QIStruct[0].pIID = (IID *) &IID_IUnknown;
+
+ START_CLOCK;
+ hr = CoCreateInstanceEx(
+ CLSID_ActService,
+ NULL,
+ CLSCTX_REMOTE_SERVER,
+ pServerInfo,
+ 1,
+ QIStruct);
+ STOP_CLOCK;
+
+ if ( FAILED(hr) )
+ {
+ printf("CoCreateInstanceEx returned 0x%x\n", hr);
+ if (punkHeld)
+ punkHeld->Release();
+ return FALSE;
+ }
+
+ if (gfHoldServer && NULL == punkHeld && SUCCEEDED(QIStruct[0].hr))
+ {
+ punkHeld = QIStruct[0].pItf;
+ punkHeld->AddRef();
+ }
+
+ if (FAILED(QIStruct[0].hr))
+ {
+ printf("CoCreateInstanceEx returned 0x%x\n",
+ QIStruct[0].hr);
+ fReturn = FALSE;
+ }
+ else
+ QIStruct[0].pItf->Release();
+
+ if (!fReturn)
+ {
+ if (punkHeld)
+ punkHeld->Release();
+ return(fReturn);
+ }
+
+ SLEEP_IF_LOOPING;
+
+ STOP_LOOP;
+
+ if (punkHeld)
+ punkHeld->Release();
+
+ return fReturn;
+}
+
+BOOL CILocalPreConACL();
+BOOL CIExplicitPreConACL();
+
+#endif // NO_DCOM
diff --git a/private/oleutest/act/client/client.hxx b/private/oleutest/act/client/client.hxx
new file mode 100644
index 000000000..b5c9a412f
--- /dev/null
+++ b/private/oleutest/act/client/client.hxx
@@ -0,0 +1,43 @@
+/*
+ * client.hxx
+ */
+
+#ifdef UNICODE
+#define _UNICODE 1
+#endif
+
+#include <windows.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <tchar.h>
+#include <ole2.h>
+#include <oleext.h>
+#include "..\acttest.h"
+#include "..\dll\goober.h"
+#include <rpc.h>
+
+// To build performance tests for pre-DCOM systems
+// uncomment the following line.
+//#define NO_DCOM
+
+typedef unsigned long ulong;
+typedef unsigned char uchar;
+#define NO 0
+#define YES 1
+
+typedef BOOL (* LPTESTFUNC) (void);
+
+DWORD InstallService(TCHAR * Path);
+
+extern TCHAR ServerName[32];
+
+void PrintUsageAndExit( BOOL bListTests );
+long InitializeRegistryForLocal();
+long InitializeRegistryForInproc();
+long InitializeRegistryForCustom();
+long InitializeRegistryForRemote();
+long InitializeRegistryForService();
+
+BOOL Tests();
+
+
diff --git a/private/oleutest/act/client/daytona/makefile b/private/oleutest/act/client/daytona/makefile
new file mode 100644
index 000000000..5acbbd24c
--- /dev/null
+++ b/private/oleutest/act/client/daytona/makefile
@@ -0,0 +1 @@
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/oleutest/act/client/daytona/sources b/private/oleutest/act/client/daytona/sources
new file mode 100644
index 000000000..94b616c6a
--- /dev/null
+++ b/private/oleutest/act/client/daytona/sources
@@ -0,0 +1,77 @@
+!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:
+
+ Steve Wood (stevewo) 12-Apr-1989
+
+
+Revision History:
+ Modified by Steve Blanding 15-Jan 1996 for DCOM performance tests
+
+!ENDIF
+
+#
+# The TARGETNAME variable is defined by the developer. It is the name of
+# the target (component) that is being built by this makefile. It
+# should NOT include any path or file extension information.
+#
+
+TARGETNAME=actclt
+
+#
+# The TARGETPATH and TARGETTYPE varialbes are defined by the developer.
+# The first specifies where the target is to be build. The second specifies
+# the type of target (either PROGRAM, DYNLINK or LIBRARY)
+#
+
+TARGETPATH=.
+TARGETTYPE=PROGRAM
+
+#
+# The INCLUDES variable specifies any include paths that are specific to
+# this source directory. Separate multiple directory paths with single
+# semicolons. Relative path specifications are okay.
+#
+
+INCLUDES=.
+
+#
+# The SOURCES variable is defined by the developer. It is a list of all the
+# source files for this component. Each source file should be on a separate
+# line using the line continuation character. This will minimize merge
+# conflicts if two developers adding source files to the same component.
+#
+
+SOURCES=\
+ ..\client.cxx \
+ ..\pswrd.cxx \
+ ..\reg.cxx
+
+C_DEFINES=-DUNICODE
+
+LINKLIBS=\
+ $(BASEDIR)\public\sdk\lib\*\kernel32.lib \
+ $(BASEDIR)\public\sdk\lib\*\user32.lib \
+ $(BASEDIR)\public\sdk\lib\*\advapi32.lib \
+ $(BASEDIR)\public\sdk\lib\*\ntdll.lib \
+ $(BASEDIR)\public\sdk\lib\*\ole32.lib \
+ $(BASEDIR)\public\sdk\lib\*\rpcrt4.lib \
+ $(BASEDIR)\public\sdk\lib\*\uuid.lib \
+ $(BASEDIR)\public\sdk\lib\*\mpr.lib \
+ ..\..\common\daytona\*\common.lib
+
+UMTYPE=console
diff --git a/private/oleutest/act/client/dirs b/private/oleutest/act/client/dirs
new file mode 100644
index 000000000..35b6c7372
--- /dev/null
+++ b/private/oleutest/act/client/dirs
@@ -0,0 +1,27 @@
+!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:
+
+ Steve Wood (stevewo) 17-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\dirs.tpl
+
+!ENDIF
+
+DIRS=
+
+OPTIONAL_DIRS=\
+ daytona \
+
diff --git a/private/oleutest/act/client/pswrd.cxx b/private/oleutest/act/client/pswrd.cxx
new file mode 100644
index 000000000..3dd7f6545
--- /dev/null
+++ b/private/oleutest/act/client/pswrd.cxx
@@ -0,0 +1,58 @@
+extern "C"
+{
+#include <nt.h>
+#include <ntrtl.h>
+#include <nturtl.h>
+#include <ntlsa.h>
+}
+#include <stdarg.h>
+#include <windef.h>
+#include <winbase.h>
+#include <winnls.h>
+#include <stdio.h>
+
+BOOL SetPassword(TCHAR * szCID, TCHAR * pszPw)
+{
+#ifndef CHICO
+ WCHAR * szPw = pszPw;
+ LSA_OBJECT_ATTRIBUTES sObjAttributes;
+ LSA_HANDLE hPolicy;
+ LSA_UNICODE_STRING sKey;
+ LSA_UNICODE_STRING sPassword;
+ WCHAR szKey[256];
+ swprintf(szKey, L"SCM:%s", szCID);
+ sKey.Length = (wcslen(szKey) + 1) * sizeof(WCHAR);
+ sKey.MaximumLength = (wcslen(szKey) + 1) * sizeof(WCHAR);
+ sKey.Buffer = szKey;
+ sPassword.Length = (wcslen(szPw) + 1) * sizeof(WCHAR);
+ sPassword.MaximumLength = 80 * sizeof(WCHAR);
+ sPassword.Buffer = szPw;
+
+ InitializeObjectAttributes(&sObjAttributes, NULL, 0L, NULL, NULL);
+
+ // open the local security policy
+ if (!NT_SUCCESS(
+ LsaOpenPolicy(
+ NULL,
+ &sObjAttributes,
+ POLICY_CREATE_SECRET,
+ &hPolicy)))
+ {
+ printf("LsaOpenPolicy failed with %d\n",GetLastError());
+ return(FALSE);
+ }
+
+ // store private data
+ if (!NT_SUCCESS(
+ LsaStorePrivateData(hPolicy, &sKey, &sPassword)))
+ {
+ printf("LsaStorePrivateData failed with %d\n",GetLastError());
+ return(FALSE);
+ }
+
+ LsaClose(hPolicy);
+#endif
+ return(TRUE);
+}
+
+
diff --git a/private/oleutest/act/client/reg.cxx b/private/oleutest/act/client/reg.cxx
new file mode 100644
index 000000000..2b1639304
--- /dev/null
+++ b/private/oleutest/act/client/reg.cxx
@@ -0,0 +1,867 @@
+//
+// reg.cxx
+//
+
+#include "client.hxx"
+
+BOOL SetPassword(TCHAR * szCID, TCHAR * szPw);
+
+TCHAR * ServiceName = TEXT("ActTestService");
+TCHAR * ServiceDisplayName = TEXT("ActTestService");
+TCHAR * UserName = TEXT("redmond\\oleuser");
+TCHAR * Password = TEXT("stocksplit");
+
+long InitializeRegistryForLocal()
+{
+ SYSTEM_INFO SystemInfo;
+ long RegStatus;
+ ulong Disposition;
+ HKEY hInterface;
+ HKEY hClsidKey;
+ HKEY hActKey;
+ HKEY hActValueKey;
+ TCHAR Path[256];
+
+ //
+ // Get CLASSES_ROOT.
+ //
+ RegStatus = RegOpenKeyEx( HKEY_CLASSES_ROOT,
+ TEXT("CLSID"),
+ 0,
+ KEY_ALL_ACCESS,
+ &hClsidKey );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ //
+ // Local CLSID entries.
+ //
+
+ RegStatus = RegCreateKeyEx(
+ hClsidKey,
+ ClsidActLocalString,
+ 0,
+ TEXT("REG_SZ"),
+ REG_OPTION_NON_VOLATILE,
+ KEY_ALL_ACCESS,
+ NULL,
+ &hActKey,
+ &Disposition );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ RegStatus = RegCreateKeyEx(
+ hActKey,
+ TEXT("LocalServer32"),
+ 0,
+ TEXT("REG_SZ"),
+ REG_OPTION_NON_VOLATILE,
+ KEY_ALL_ACCESS,
+ NULL,
+ &hActValueKey,
+ &Disposition );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ if ( ! GetModuleFileName( 0, Path, sizeof(Path) ) )
+ return RegStatus;
+
+ _tcslwr( Path );
+ _tcscpy( _tcsstr( Path, TEXT("actclt") ), TEXT("actsrv.exe 2") );
+
+ RegStatus = RegSetValueEx(
+ hActValueKey,
+ TEXT(""),
+ 0,
+ REG_SZ,
+ (const BYTE *)Path,
+ (_tcslen(Path) + 1) * sizeof(TCHAR) );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ RegStatus = RegSetValueEx(
+ hClsidKey,
+ TEXT("AppID"),
+ 0,
+ REG_SZ,
+ (const BYTE *) ClsidActLocalString,
+ (_tcslen(ClsidActLocalString)+1)*sizeof(TCHAR));
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ RegStatus = SetAppIDSecurity( ClsidActLocalString );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ return ERROR_SUCCESS;
+}
+
+long InitializeRegistryForInproc()
+{
+ SYSTEM_INFO SystemInfo;
+ long RegStatus;
+ ulong Disposition;
+ HKEY hInterface;
+ HKEY hClsidKey;
+ HKEY hActKey;
+ HKEY hActValueKey;
+ TCHAR Path[256];
+
+ //
+ // Get CLASSES_ROOT.
+ //
+ RegStatus = RegOpenKeyEx( HKEY_CLASSES_ROOT,
+ TEXT("CLSID"),
+ 0,
+ KEY_ALL_ACCESS,
+ &hClsidKey );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ //
+ // Local CLSID entries.
+ //
+
+ RegStatus = RegCreateKeyEx(
+ hClsidKey,
+ ClsidActInprocString,
+ 0,
+ TEXT("REG_SZ"),
+ REG_OPTION_NON_VOLATILE,
+ KEY_ALL_ACCESS,
+ NULL,
+ &hActKey,
+ &Disposition );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ // if ( Disposition == REG_OPENED_EXISTING_KEY )
+ // return TRUE;
+
+ RegStatus = RegCreateKeyEx(
+ hActKey,
+ TEXT("InprocServer32"),
+ 0,
+ TEXT("REG_SZ"),
+ REG_OPTION_NON_VOLATILE,
+ KEY_ALL_ACCESS,
+ NULL,
+ &hActValueKey,
+ &Disposition );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ if ( ! GetModuleFileName( 0, Path, sizeof(Path) ) )
+ return RegStatus;
+
+ _tcslwr( Path );
+ _tcscpy( _tcsstr( Path, TEXT("actclt") ), TEXT("actsrvd.dll") );
+
+ RegStatus = RegSetValueEx(
+ hActValueKey,
+ TEXT(""),
+ 0,
+ REG_SZ,
+ (const BYTE *)Path,
+ (_tcslen(Path) + 1) * sizeof(TCHAR) );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ RegStatus = RegSetValueEx(
+ hActValueKey,
+ TEXT("ThreadingModel"),
+ 0,
+ REG_SZ,
+ (const BYTE *)TEXT("Both"),
+ (_tcslen(TEXT("Both")) + 1) * sizeof(TCHAR) );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ return ERROR_SUCCESS;
+}
+
+TCHAR * StringIidIGoober = TEXT("{ffffffff-0000-0000-0000-000000000000}");
+
+long InitializeRegistryForCustom()
+{
+ SYSTEM_INFO SystemInfo;
+ long RegStatus;
+ ulong Disposition;
+ HKEY hInterface;
+ HKEY hClsidKey;
+ HKEY hActKey;
+ HKEY hActValueKey;
+ TCHAR Path[256];
+
+ RegStatus = RegOpenKeyEx( HKEY_CLASSES_ROOT,
+ TEXT("Interface"),
+ 0,
+ KEY_ALL_ACCESS,
+ &hInterface );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ RegStatus = RegCreateKeyEx(
+ hInterface,
+ StringIidIGoober,
+ 0,
+ TEXT("REG_SZ"),
+ REG_OPTION_NON_VOLATILE,
+ KEY_ALL_ACCESS,
+ NULL,
+ &hInterface,
+ &Disposition );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ RegStatus = RegSetValueEx(
+ hInterface,
+ TEXT(""),
+ 0,
+ REG_SZ,
+ (const BYTE *)TEXT("IGoober"),
+ (_tcslen(TEXT("IGoober")) + 1) * sizeof(TCHAR) );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ RegStatus = RegCreateKeyEx(
+ hInterface,
+ TEXT("ProxyStubClsid32"),
+ 0,
+ TEXT("REG_SZ"),
+ REG_OPTION_NON_VOLATILE,
+ KEY_ALL_ACCESS,
+ NULL,
+ &hInterface,
+ &Disposition );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ RegStatus = RegSetValueEx(
+ hInterface,
+ TEXT(""),
+ 0,
+ REG_SZ,
+ (const BYTE *)ClsidGoober32String,
+ (_tcslen(ClsidGoober32String) + 1) * sizeof(TCHAR) );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ RegStatus = RegOpenKeyEx( HKEY_CLASSES_ROOT,
+ TEXT("CLSID"),
+ 0,
+ KEY_ALL_ACCESS,
+ &hClsidKey );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ RegStatus = RegCreateKeyEx(
+ hClsidKey,
+ ClsidGoober32String,
+ 0,
+ TEXT("REG_SZ"),
+ REG_OPTION_NON_VOLATILE,
+ KEY_ALL_ACCESS,
+ NULL,
+ &hActKey,
+ &Disposition );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ // if ( Disposition == REG_OPENED_EXISTING_KEY )
+ // return TRUE;
+
+ RegStatus = RegCreateKeyEx(
+ hActKey,
+ TEXT("InProcServer32"),
+ 0,
+ TEXT("REG_SZ"),
+ REG_OPTION_NON_VOLATILE,
+ KEY_ALL_ACCESS,
+ NULL,
+ &hActValueKey,
+ &Disposition );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ if ( ! GetModuleFileName( 0, Path, sizeof(Path) ) )
+ return RegStatus;
+
+ _tcslwr( Path );
+ _tcscpy( _tcsstr( Path, TEXT("actclt") ), TEXT("goober.dll") );
+
+ RegStatus = RegSetValueEx(
+ hActValueKey,
+ TEXT(""),
+ 0,
+ REG_SZ,
+ (const BYTE *)Path,
+ (_tcslen(Path) + 1) * sizeof(TCHAR) );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ return ERROR_SUCCESS;
+}
+
+long InitializeRegistryForRemote()
+{
+ long RegStatus;
+ ulong Disposition;
+ HKEY hClsidKey;
+ HKEY hAppIDKey;
+ HKEY hThisClsidKey;
+ HKEY hActKey;
+ HKEY hActValueKey;
+ TCHAR Path[256];
+
+ RegStatus = RegOpenKeyEx( HKEY_CLASSES_ROOT,
+ TEXT("CLSID"),
+ 0,
+ KEY_ALL_ACCESS,
+ &hClsidKey );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ //
+ // CLSID_ActRemote
+ //
+
+ RegStatus = RegCreateKeyEx(
+ hClsidKey,
+ ClsidActRemoteString,
+ 0,
+ TEXT("REG_SZ"),
+ REG_OPTION_NON_VOLATILE,
+ KEY_ALL_ACCESS,
+ NULL,
+ &hThisClsidKey,
+ &Disposition );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ RegStatus = RegSetValueEx(
+ hThisClsidKey,
+ TEXT("AppID"),
+ 0,
+ REG_SZ,
+ (const BYTE *) ClsidActRemoteString,
+ (_tcslen(ClsidActRemoteString)+1)*sizeof(TCHAR));
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ RegStatus = SetAppIDSecurity( ClsidActRemoteString );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ RegStatus = RegCreateKeyEx(
+ HKEY_CLASSES_ROOT,
+ TEXT("AppID"),
+ 0,
+ TEXT("REG_SZ"),
+ REG_OPTION_NON_VOLATILE,
+ KEY_ALL_ACCESS,
+ NULL,
+ &hAppIDKey,
+ &Disposition );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ RegStatus = RegCreateKeyEx(
+ hAppIDKey,
+ ClsidActRemoteString,
+ 0,
+ TEXT("REG_SZ"),
+ REG_OPTION_NON_VOLATILE,
+ KEY_ALL_ACCESS,
+ NULL,
+ &hActKey,
+ &Disposition );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ if ( *ServerName )
+ RegStatus = RegSetValueEx(
+ hActKey,
+ TEXT("RemoteServerName"),
+ 0,
+ REG_SZ,
+ (const BYTE *)ServerName,
+ (_tcslen(ServerName) + 1) * sizeof(TCHAR) );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ //
+ // CLSID_ActAtStorage
+ //
+
+ RegStatus = RegCreateKeyEx(
+ hClsidKey,
+ ClsidActAtStorageString,
+ 0,
+ TEXT("REG_SZ"),
+ REG_OPTION_NON_VOLATILE,
+ KEY_ALL_ACCESS,
+ NULL,
+ &hThisClsidKey,
+ &Disposition );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ RegStatus = RegSetValueEx(
+ hThisClsidKey,
+ TEXT("AppID"),
+ 0,
+ REG_SZ,
+ (const BYTE *) ClsidActAtStorageString,
+ (_tcslen(ClsidActAtStorageString)+1)*sizeof(TCHAR));
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ RegStatus = SetAppIDSecurity( ClsidActAtStorageString );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ RegStatus = RegCreateKeyEx(
+ hAppIDKey,
+ ClsidActAtStorageString,
+ 0,
+ TEXT("REG_SZ"),
+ REG_OPTION_NON_VOLATILE,
+ KEY_ALL_ACCESS,
+ NULL,
+ &hActKey,
+ &Disposition );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ RegStatus = RegSetValueEx(
+ hActKey,
+ TEXT("ActivateAtStorage"),
+ 0,
+ REG_SZ,
+ (const BYTE *)TEXT("Y"),
+ (_tcslen(TEXT("Y")) + 1) * sizeof(TCHAR) );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ //
+ // CLSID_ActRunAsLoggedOnUser
+ //
+
+ RegStatus = RegCreateKeyEx(
+ hClsidKey,
+ ClsidActRunAsLoggedOnString,
+ 0,
+ TEXT("REG_SZ"),
+ REG_OPTION_NON_VOLATILE,
+ KEY_ALL_ACCESS,
+ NULL,
+ &hThisClsidKey,
+ &Disposition );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ RegStatus = SetAppIDSecurity( ClsidActRunAsLoggedOnString );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ RegStatus = RegSetValueEx(
+ hThisClsidKey,
+ TEXT("AppID"),
+ 0,
+ REG_SZ,
+ (const BYTE *) ClsidActRunAsLoggedOnString,
+ (_tcslen(ClsidActRunAsLoggedOnString)+1)*sizeof(TCHAR));
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ RegStatus = RegCreateKeyEx(
+ hAppIDKey,
+ ClsidActRunAsLoggedOnString,
+ 0,
+ TEXT("REG_SZ"),
+ REG_OPTION_NON_VOLATILE,
+ KEY_ALL_ACCESS,
+ NULL,
+ &hActKey,
+ &Disposition );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ if ( *ServerName )
+ RegStatus = RegSetValueEx(
+ hActKey,
+ TEXT("RemoteServerName"),
+ 0,
+ REG_SZ,
+ (const BYTE *)ServerName,
+ (_tcslen(ServerName) + 1) * sizeof(TCHAR) );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ RegStatus = RegCreateKeyEx(
+ hThisClsidKey,
+ TEXT("LocalServer32"),
+ 0,
+ TEXT("REG_SZ"),
+ REG_OPTION_NON_VOLATILE,
+ KEY_ALL_ACCESS,
+ NULL,
+ &hActValueKey,
+ &Disposition );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ if ( ! GetModuleFileName( 0, Path, sizeof(Path) ) )
+ return RegStatus;
+
+ _tcslwr( Path );
+ _tcscpy( _tcsstr( Path, TEXT("actclt") ), TEXT("actsrv.exe 7") );
+
+ RegStatus = RegSetValueEx(
+ hActValueKey,
+ TEXT(""),
+ 0,
+ REG_SZ,
+ (const BYTE *)Path,
+ (_tcslen(Path) + 1) * sizeof(TCHAR) );
+
+ RegStatus = RegSetValueEx(
+ hActKey,
+ TEXT("RunAs"),
+ 0,
+ REG_SZ,
+ (const BYTE *)TEXT("Interactive User"),
+ (_tcslen(TEXT("Interactive User")) + 1) * sizeof(TCHAR) );
+
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ //
+ // RunAs CLSID entries.
+ //
+
+ RegStatus = RegCreateKeyEx(
+ hClsidKey,
+ ClsidActPreConfigString,
+ 0,
+ TEXT("REG_SZ"),
+ REG_OPTION_NON_VOLATILE,
+ KEY_ALL_ACCESS,
+ NULL,
+ &hThisClsidKey,
+ &Disposition );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ RegStatus = RegSetValueEx(
+ hThisClsidKey,
+ TEXT("AppID"),
+ 0,
+ REG_SZ,
+ (const BYTE *) ClsidActPreConfigString,
+ (_tcslen(ClsidActPreConfigString)+1)*sizeof(TCHAR));
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ RegStatus = SetAppIDSecurity( ClsidActPreConfigString );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ RegStatus = RegCreateKeyEx(
+ hAppIDKey,
+ ClsidActPreConfigString,
+ 0,
+ TEXT("REG_SZ"),
+ REG_OPTION_NON_VOLATILE,
+ KEY_ALL_ACCESS,
+ NULL,
+ &hActKey,
+ &Disposition );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ if ( *ServerName )
+ RegStatus = RegSetValueEx(
+ hActKey,
+ TEXT("RemoteServerName"),
+ 0,
+ REG_SZ,
+ (const BYTE *)ServerName,
+ (_tcslen(ServerName) + 1) * sizeof(TCHAR) );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ RegStatus = RegCreateKeyEx(
+ hThisClsidKey,
+ TEXT("LocalServer32"),
+ 0,
+ TEXT("REG_SZ"),
+ REG_OPTION_NON_VOLATILE,
+ KEY_ALL_ACCESS,
+ NULL,
+ &hActValueKey,
+ &Disposition );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ if ( ! GetModuleFileName( 0, Path, sizeof(Path) ) )
+ return RegStatus;
+
+ _tcslwr( Path );
+ _tcscpy( _tcsstr( Path, TEXT("actclt") ), TEXT("actsrv.exe 6") );
+
+ RegStatus = RegSetValueEx(
+ hActValueKey,
+ TEXT(""),
+ 0,
+ REG_SZ,
+ (const BYTE *)Path,
+ (_tcslen(Path) + 1) * sizeof(TCHAR) );
+
+ RegStatus = RegSetValueEx(
+ hActKey,
+ TEXT("RunAs"),
+ 0,
+ REG_SZ,
+ (const BYTE *)UserName,
+ (_tcslen(UserName) + 1) * sizeof(TCHAR) );
+
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ if (!SetPassword(ClsidActPreConfigString, Password))
+ return(FALSE);
+
+ if (AddBatchPrivilege( UserName ) )
+ return(FALSE);
+
+ return ERROR_SUCCESS;
+}
+
+long InitializeRegistryForService()
+{
+ long RegStatus;
+ ulong Disposition;
+ HKEY hClsidKey;
+ HKEY hAppIDKey;
+ HKEY hThisClsidKey;
+ HKEY hActKey;
+ HKEY hActValueKey;
+ HKEY hServices;
+ TCHAR Path[256];
+
+ //
+ // Get CLASSES_ROOT.
+ //
+ RegStatus = RegOpenKeyEx( HKEY_CLASSES_ROOT,
+ TEXT("CLSID"),
+ 0,
+ KEY_ALL_ACCESS,
+ &hClsidKey );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ RegStatus = RegCreateKeyEx(
+ HKEY_CLASSES_ROOT,
+ TEXT("AppID"),
+ 0,
+ TEXT("REG_SZ"),
+ REG_OPTION_NON_VOLATILE,
+ KEY_ALL_ACCESS,
+ NULL,
+ &hAppIDKey,
+ &Disposition );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ //
+ // Local CLSID entries.
+ //
+
+ RegStatus = RegCreateKeyEx(
+ hClsidKey,
+ ClsidActServiceString,
+ 0,
+ TEXT("REG_SZ"),
+ REG_OPTION_NON_VOLATILE,
+ KEY_ALL_ACCESS,
+ NULL,
+ &hThisClsidKey,
+ &Disposition );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ RegStatus = SetAppIDSecurity( ClsidActServiceString );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ RegStatus = RegSetValueEx(
+ hThisClsidKey,
+ TEXT("AppID"),
+ 0,
+ REG_SZ,
+ (const BYTE *) ClsidActServiceString,
+ (_tcslen(ClsidActServiceString)+1)*sizeof(TCHAR));
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ // if ( Disposition == REG_OPENED_EXISTING_KEY )
+ // return TRUE;
+
+ RegStatus = RegCreateKeyEx(
+ hAppIDKey,
+ ClsidActServiceString,
+ 0,
+ TEXT("REG_SZ"),
+ REG_OPTION_NON_VOLATILE,
+ KEY_ALL_ACCESS,
+ NULL,
+ &hActKey,
+ &Disposition );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ if ( ! GetModuleFileName( 0, Path, sizeof(Path) ) )
+ return RegStatus;
+
+ _tcslwr( Path );
+ _tcscpy( _tcsstr( Path, TEXT("actclt") ), TEXT("actsrv.exe 8") );
+
+ RegStatus = RegSetValueEx(
+ hActKey,
+ TEXT("LocalService"),
+ 0,
+ REG_SZ,
+ (const BYTE *)ServiceName,
+ (_tcslen(ServiceName) + 1) * sizeof(TCHAR) );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ RegStatus = RegSetValueEx(
+ hActKey,
+ TEXT("ActivateAtStorage"),
+ 0,
+ REG_SZ,
+ (const BYTE *)TEXT("Y"),
+ (_tcslen(TEXT("Y")) + 1) * sizeof(TCHAR) );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ RegStatus = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
+ TEXT("SYSTEM\\CurrentControlSet\\Services"),
+ 0,
+ KEY_READ,
+ &hServices );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ return InstallService(Path);
+}
+
+DWORD InstallService( TCHAR * Path )
+{
+#ifndef CHICO
+ SC_HANDLE hManager;
+ SC_HANDLE hService;
+
+ hManager = OpenSCManager( NULL,
+ NULL,
+ SC_MANAGER_ALL_ACCESS );
+
+ if ( ! hManager )
+ {
+ printf( "OpenSCManager returned %d\n", GetLastError() );
+ return GetLastError();
+ }
+
+ hService = OpenService( hManager,
+ ServiceName,
+ SERVICE_ALL_ACCESS );
+
+ if ( ! hService )
+ {
+ hService = CreateService(
+ hManager,
+ ServiceName,
+ ServiceDisplayName,
+ SERVICE_ALL_ACCESS,
+ SERVICE_WIN32_OWN_PROCESS,
+ SERVICE_DEMAND_START,
+ SERVICE_ERROR_NORMAL,
+ Path,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+ }
+
+ if ( ! hService )
+ {
+ printf( "CreateService returned %d\n", GetLastError() );
+ CloseServiceHandle(hManager);
+ return GetLastError();
+ }
+
+ CloseServiceHandle(hService);
+ CloseServiceHandle(hManager);
+#endif
+ return ERROR_SUCCESS;
+}
+
diff --git a/private/oleutest/act/common/clsid.c b/private/oleutest/act/common/clsid.c
new file mode 100644
index 000000000..e55978a5f
--- /dev/null
+++ b/private/oleutest/act/common/clsid.c
@@ -0,0 +1,131 @@
+/*
+ * clsid.cxx
+ *
+ * IMPORTANT: Please DO NOT change these CLSIDs. If you need to add
+ * to this list, add new CLSIDs at the END of the list.
+ *
+ * The BVTs depend on these CLSIDs being defined as they are.
+ */
+#ifdef UNICODE
+#define _UNICODE 1
+#endif
+
+#include "windows.h"
+#include "tchar.h"
+
+typedef struct
+ {
+ unsigned long Data1;
+ unsigned short Data2;
+ unsigned short Data3;
+ unsigned char Data4[8];
+ } CLSID;
+
+//
+// This is the CLSID for the custom interface proxy, just to be different.
+//
+CLSID CLSID_GooberProxy = { /* 00000000-0000-0000-0000-000000000001 */
+ 0x00000000,
+ 0x0000,
+ 0x0000,
+ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1}
+ };
+
+//
+// This one gets registered as LocalServer32.
+//
+CLSID CLSID_ActLocal = { /* 00000000-0000-0000-0000-000000000002 */
+ 0x00000000,
+ 0x0000,
+ 0x0000,
+ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2}
+ };
+
+//
+// This one gets registered as LocalServer32 and has a Remote key on the
+// client side.
+//
+CLSID CLSID_ActRemote = { /* 00000000-0000-0000-0000-000000000003 */
+ 0x00000000,
+ 0x0000,
+ 0x0000,
+ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3}
+ };
+
+//
+// This one gets registered as LocalServer32 and has an AtStorage key on the
+// client side.
+//
+CLSID CLSID_ActAtStorage = { /* 00000000-0000-0000-0000-000000000004 */
+ 0x00000000,
+ 0x0000,
+ 0x0000,
+ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4}
+ };
+
+//
+// This one gets registered as InprocServer32.
+//
+CLSID CLSID_ActInproc = { /* 00000000-0000-0000-0000-000000000005 */
+ 0x00000000,
+ 0x0000,
+ 0x0000,
+ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5}
+ };
+
+//
+// This one gets registered as InprocServer32.
+// It has an AtStorage key on the client side.
+// It is configured to run in Pre-Configured user mode on the server side.
+//
+CLSID CLSID_ActPreConfig = { /* 00000000-0000-0000-0000-000000000006 */
+ 0x00000000,
+ 0x0000,
+ 0x0000,
+ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6}
+ };
+
+//
+// Configured with RemoteServerName on client and as
+// RunAs Logged On User on the server.
+//
+CLSID CLSID_ActRunAsLoggedOn = { /* 00000000-0000-0000-0000-000000000007 */
+ 0x00000000,
+ 0x0000,
+ 0x0000,
+ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7}
+ };
+
+//
+// This one gets registered as an AtStorage service.
+//
+CLSID CLSID_ActService = { /* 00000000-0000-0000-0000-000000000008 */
+ 0x00000000,
+ 0x0000,
+ 0x0000,
+ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8}
+ };
+
+//
+// This CLSID is registered only in the server's registry. Tests default
+// ActivateAtStorage on the client.
+//
+CLSID CLSID_ActServerOnly = { /* 00000000-0000-0000-0000-000000000009 */
+ 0x00000000,
+ 0x0000,
+ 0x0000,
+ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9}
+ };
+
+typedef unsigned short wchar_t;
+
+TCHAR * ClsidGoober32String = TEXT("{00000000-0000-0000-0000-000000000001}");
+TCHAR * ClsidActLocalString = TEXT("{00000000-0000-0000-0000-000000000002}");
+TCHAR * ClsidActRemoteString = TEXT("{00000000-0000-0000-0000-000000000003}");
+TCHAR * ClsidActAtStorageString = TEXT("{00000000-0000-0000-0000-000000000004}");
+TCHAR * ClsidActInprocString = TEXT("{00000000-0000-0000-0000-000000000005}");
+TCHAR * ClsidActPreConfigString = TEXT("{00000000-0000-0000-0000-000000000006}");
+TCHAR * ClsidActRunAsLoggedOnString = TEXT("{00000000-0000-0000-0000-000000000007}");
+TCHAR * ClsidActServiceString = TEXT("{00000000-0000-0000-0000-000000000008}");
+TCHAR * ClsidActServerOnlyString = TEXT("{00000000-0000-0000-0000-000000000009}");
+
diff --git a/private/oleutest/act/common/daytona/makefile b/private/oleutest/act/common/daytona/makefile
new file mode 100644
index 000000000..5acbbd24c
--- /dev/null
+++ b/private/oleutest/act/common/daytona/makefile
@@ -0,0 +1 @@
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/oleutest/act/common/daytona/sources b/private/oleutest/act/common/daytona/sources
new file mode 100644
index 000000000..df5024241
--- /dev/null
+++ b/private/oleutest/act/common/daytona/sources
@@ -0,0 +1,69 @@
+!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:
+
+ Steve Wood (stevewo) 12-Apr-1989
+
+
+Revision History:
+
+!ENDIF
+
+#
+# The TARGETNAME variable is defined by the developer. It is the name of
+# the target (component) that is being built by this makefile. It
+# should NOT include any path or file extension information.
+#
+
+TARGETNAME=common
+
+#
+# The TARGETPATH and TARGETTYPE varialbes are defined by the developer.
+# The first specifies where the target is to be build. The second specifies
+# the type of target (either PROGRAM, DYNLINK or LIBRARY)
+#
+
+TARGETPATH=.
+TARGETTYPE=LIBRARY
+
+#
+# The INCLUDES variable specifies any include paths that are specific to
+# this source directory. Separate multiple directory paths with single
+# semicolons. Relative path specifications are okay.
+#
+
+INCLUDES=.;..;..\..
+
+SYNCHRONIZE_BLOCK=1
+
+#
+# The SOURCES variable is defined by the developer. It is a list of all the
+# source files for this component. Each source file should be on a separate
+# line using the line continuation character. This will minimize merge
+# conflicts if two developers adding source files to the same component.
+#
+
+SOURCES=\
+ ..\clsid.c \
+ ..\reg.c \
+ ..\goober_i.c
+
+C_DEFINES=-DUNICODE
+
+LINKLIBS=
+
+UMTYPE=console
diff --git a/private/oleutest/act/common/dirs b/private/oleutest/act/common/dirs
new file mode 100644
index 000000000..35b6c7372
--- /dev/null
+++ b/private/oleutest/act/common/dirs
@@ -0,0 +1,27 @@
+!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:
+
+ Steve Wood (stevewo) 17-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\dirs.tpl
+
+!ENDIF
+
+DIRS=
+
+OPTIONAL_DIRS=\
+ daytona \
+
diff --git a/private/oleutest/act/common/reg.c b/private/oleutest/act/common/reg.c
new file mode 100644
index 000000000..1c3ce233d
--- /dev/null
+++ b/private/oleutest/act/common/reg.c
@@ -0,0 +1,250 @@
+//
+// reg.c
+//
+// Common registry manipulation routines.
+//
+
+#ifdef UNICODE
+#define _UNICODE 1
+#endif
+
+#include <windows.h>
+#include <ole2.h>
+#include "acttest.h"
+#include "tchar.h"
+#ifndef CHICO
+#include <subauth.h>
+#include <ntlsa.h>
+#endif
+
+void DeleteSubTree( TCHAR * pszClsid, TCHAR * SubTree )
+{
+ HKEY hClsidRoot;
+ HKEY hClsid;
+ long RegStatus;
+ TCHAR szKeyName[256];
+ DWORD KeyNameSize;
+ FILETIME FileTime;
+ int SubKey;
+
+ RegStatus = RegOpenKeyEx( HKEY_CLASSES_ROOT,
+ SubTree,
+ 0,
+ KEY_ALL_ACCESS,
+ &hClsidRoot );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return;
+
+ RegStatus = RegOpenKeyEx( hClsidRoot,
+ pszClsid,
+ 0,
+ KEY_ALL_ACCESS,
+ &hClsid );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return;
+
+ for ( SubKey = 0; ; SubKey++ )
+ {
+ KeyNameSize = sizeof(szKeyName);
+
+ RegStatus = RegEnumKeyEx(
+ hClsid,
+ SubKey,
+ szKeyName,
+ &KeyNameSize,
+ 0,
+ NULL,
+ NULL,
+ &FileTime );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ break;
+
+ RegStatus = RegDeleteKey( hClsid, szKeyName );
+ }
+
+ RegCloseKey( hClsid );
+ RegDeleteKey( hClsidRoot, pszClsid );
+ RegCloseKey( hClsidRoot );
+}
+
+
+void DeleteClsidKey( TCHAR * pwszClsid )
+{
+
+ // Note that we also delete the corresponding AppID entries
+
+ DeleteSubTree( pwszClsid, TEXT("CLSID"));
+ DeleteSubTree( pwszClsid, TEXT("AppID"));
+}
+
+long SetAppIDSecurity( TCHAR * pszAppID )
+{
+ HKEY hActKey;
+ HKEY hAppIDKey;
+ BYTE SecurityDescriptor[2000];
+ LONG RegStatus;
+ SECURITY_INFORMATION SI;
+ DWORD dwSize = sizeof( SecurityDescriptor );
+ DWORD Disposition;
+
+ RegStatus = RegOpenKeyEx( HKEY_CLASSES_ROOT,
+ TEXT("AppID"),
+ 0,
+ KEY_ALL_ACCESS,
+ &hAppIDKey );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ RegStatus = RegCreateKeyEx(
+ hAppIDKey,
+ pszAppID,
+ 0,
+ TEXT("REG_SZ"),
+ REG_OPTION_NON_VOLATILE,
+ KEY_ALL_ACCESS,
+ NULL,
+ &hActKey,
+ &Disposition );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+#ifndef CHICO
+ RegStatus = RegGetKeySecurity( hActKey,
+ OWNER_SECURITY_INFORMATION
+ | GROUP_SECURITY_INFORMATION
+ | DACL_SECURITY_INFORMATION,
+ &SecurityDescriptor,
+ &dwSize );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+#endif
+ RegStatus = RegSetValueEx(
+ hActKey,
+ TEXT("LaunchPermission"),
+ 0,
+ REG_BINARY,
+ SecurityDescriptor,
+ dwSize );
+
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ RegStatus = RegSetValueEx(
+ hActKey,
+ TEXT("AccessPermission"),
+ 0,
+ REG_BINARY,
+ SecurityDescriptor,
+ dwSize );
+
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ RegCloseKey(hActKey);
+
+ // make the key for the exe
+ RegStatus = RegCreateKeyEx(
+ hAppIDKey,
+ TEXT("ActSrv.Exe"),
+ 0,
+ TEXT("REG_SZ"),
+ REG_OPTION_NON_VOLATILE,
+ KEY_ALL_ACCESS,
+ NULL,
+ &hActKey,
+ &Disposition );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ RegStatus = RegSetValueEx(
+ hActKey,
+ TEXT("AppID"),
+ 0,
+ REG_SZ,
+ (BYTE*) pszAppID,
+ (_tcslen(pszAppID) + 1) * sizeof(TCHAR) );
+
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ RegCloseKey(hActKey);
+ RegCloseKey(hAppIDKey);
+
+ return ERROR_SUCCESS;
+}
+
+
+
+int SetAccountRights(const TCHAR *szUser, TCHAR *szPrivilege)
+{
+#ifndef CHICO
+ int err;
+ LSA_HANDLE hPolicy;
+ LSA_OBJECT_ATTRIBUTES objAtt;
+ DWORD cbSid = 1;
+ TCHAR szDomain[128];
+ DWORD cbDomain = 128;
+ PSID pSid = NULL;
+ SID_NAME_USE snu;
+ LSA_UNICODE_STRING privStr;
+
+ // Get a policy handle
+ memset(&objAtt, 0, sizeof(LSA_OBJECT_ATTRIBUTES));
+ if (!NT_SUCCESS(LsaOpenPolicy(NULL,
+ &objAtt,
+ POLICY_CREATE_ACCOUNT | POLICY_LOOKUP_NAMES,
+ &hPolicy)))
+ {
+ return GetLastError();
+ }
+
+ // Fetch the SID for the specified user
+ LookupAccountName(NULL, szUser, pSid, &cbSid, szDomain, &cbDomain, &snu);
+ if ((err = GetLastError()) != ERROR_INSUFFICIENT_BUFFER)
+ {
+ return err;
+ }
+ pSid = (PSID*) malloc(cbSid);
+ if (pSid == NULL)
+ {
+ return ERROR_OUTOFMEMORY;
+ }
+ if (!LookupAccountName(NULL, szUser, pSid, &cbSid,
+ szDomain, &cbDomain, &snu))
+ {
+ return GetLastError();
+ }
+
+ // Set the specified privilege on this account
+ privStr.Length = _tcslen(szPrivilege) * sizeof(WCHAR);
+ privStr.MaximumLength = privStr.Length + sizeof(WCHAR);
+ privStr.Buffer = szPrivilege;
+ if (!NT_SUCCESS(LsaAddAccountRights(hPolicy, pSid, &privStr, 1)))
+ {
+ return GetLastError();
+ }
+
+ // We're done
+ free( pSid );
+ LsaClose(hPolicy);
+#endif
+ return ERROR_SUCCESS;
+}
+
+int AddBatchPrivilege(const TCHAR *szUser)
+{
+#ifndef CHICO
+ return !SetAccountRights( szUser, SE_BATCH_LOGON_NAME );
+#else
+ return(TRUE);
+#endif
+}
diff --git a/private/oleutest/act/dirs b/private/oleutest/act/dirs
new file mode 100644
index 000000000..06124c36d
--- /dev/null
+++ b/private/oleutest/act/dirs
@@ -0,0 +1,29 @@
+!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:
+
+ Steve Wood (stevewo) 17-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\dirs.tpl
+
+!ENDIF
+
+DIRS=\
+ common \
+ srvcore \
+ dllsrv \
+ client \
+ dll \
+ server
diff --git a/private/oleutest/act/dll/daytona/makefile b/private/oleutest/act/dll/daytona/makefile
new file mode 100644
index 000000000..5acbbd24c
--- /dev/null
+++ b/private/oleutest/act/dll/daytona/makefile
@@ -0,0 +1 @@
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/oleutest/act/dll/daytona/sources b/private/oleutest/act/dll/daytona/sources
new file mode 100644
index 000000000..88a3cdb33
--- /dev/null
+++ b/private/oleutest/act/dll/daytona/sources
@@ -0,0 +1,77 @@
+!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:
+
+ Steve Wood (stevewo) 12-Apr-1989
+
+
+Revision History:
+
+!ENDIF
+
+#
+# The TARGETNAME variable is defined by the developer. It is the name of
+# the target (component) that is being built by this makefile. It
+# should NOT include any path or file extension information.
+#
+
+TARGETNAME=goober
+
+#
+# The TARGETPATH and TARGETTYPE varialbes are defined by the developer.
+# The first specifies where the target is to be build. The second specifies
+# the type of target (either PROGRAM, DYNLINK or LIBRARY)
+#
+
+TARGETPATH=.
+TARGETTYPE=DYNLINK
+
+#
+# The INCLUDES variable specifies any include paths that are specific to
+# this source directory. Separate multiple directory paths with single
+# semicolons. Relative path specifications are okay.
+#
+
+INCLUDES=.;..
+
+#
+# The SOURCES variable is defined by the developer. It is a list of all the
+# source files for this component. Each source file should be on a separate
+# line using the line continuation character. This will minimize merge
+# conflicts if two developers adding source files to the same component.
+#
+
+SOURCES=\
+ ..\dlldata.c \
+ ..\goober_p.c
+
+C_DEFINES=-DUNICODE -DPROXY_CLSID=CLSID_GooberProxy
+
+DLLDEF=..\goober.def
+
+LINKLIBS=\
+ $(BASEDIR)\public\sdk\lib\*\kernel32.lib \
+ $(BASEDIR)\public\sdk\lib\*\user32.lib \
+ $(BASEDIR)\public\sdk\lib\*\advapi32.lib \
+ $(BASEDIR)\public\sdk\lib\*\ntdll.lib \
+ $(BASEDIR)\public\sdk\lib\*\ole32.lib \
+ $(BASEDIR)\public\sdk\lib\*\rpcrt4.lib \
+ $(BASEDIR)\public\sdk\lib\*\uuid.lib \
+ ..\..\common\daytona\*\common.lib
+
+UMTYPE=console
+DLLBASE=@$(BASEDIR)\PUBLIC\SDK\LIB\coffbase.txt,usermode
diff --git a/private/oleutest/act/dll/dirs b/private/oleutest/act/dll/dirs
new file mode 100644
index 000000000..35b6c7372
--- /dev/null
+++ b/private/oleutest/act/dll/dirs
@@ -0,0 +1,27 @@
+!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:
+
+ Steve Wood (stevewo) 17-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\dirs.tpl
+
+!ENDIF
+
+DIRS=
+
+OPTIONAL_DIRS=\
+ daytona \
+
diff --git a/private/oleutest/act/dll/goober.def b/private/oleutest/act/dll/goober.def
new file mode 100644
index 000000000..82ae45878
--- /dev/null
+++ b/private/oleutest/act/dll/goober.def
@@ -0,0 +1,8 @@
+
+LIBRARY GOOBER
+
+DESCRIPTION 'Microsoft (R) Example Proxy/Stub DLL 1.00'
+
+EXPORTS
+ DllGetClassObject
+ DllCanUnloadNow
diff --git a/private/oleutest/act/dllsrv/actsrvd.def b/private/oleutest/act/dllsrv/actsrvd.def
new file mode 100644
index 000000000..91bb46d64
--- /dev/null
+++ b/private/oleutest/act/dllsrv/actsrvd.def
@@ -0,0 +1,8 @@
+
+LIBRARY ActsrvD
+
+DESCRIPTION 'Microsoft (R) Example Proxy/Stub DLL 1.00'
+
+EXPORTS
+ DllGetClassObject
+ DllCanUnloadNow
diff --git a/private/oleutest/act/dllsrv/daytona/makefile b/private/oleutest/act/dllsrv/daytona/makefile
new file mode 100644
index 000000000..5acbbd24c
--- /dev/null
+++ b/private/oleutest/act/dllsrv/daytona/makefile
@@ -0,0 +1 @@
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/oleutest/act/dllsrv/daytona/sources b/private/oleutest/act/dllsrv/daytona/sources
new file mode 100644
index 000000000..b1e1259c7
--- /dev/null
+++ b/private/oleutest/act/dllsrv/daytona/sources
@@ -0,0 +1,79 @@
+!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:
+
+ Steve Wood (stevewo) 12-Apr-1989
+
+
+Revision History:
+
+!ENDIF
+
+#
+# The TARGETNAME variable is defined by the developer. It is the name of
+# the target (component) that is being built by this makefile. It
+# should NOT include any path or file extension information.
+#
+
+TARGETNAME=ActSrvD
+
+#
+# The TARGETPATH and TARGETTYPE varialbes are defined by the developer.
+# The first specifies where the target is to be build. The second specifies
+# the type of target (either PROGRAM, DYNLINK or LIBRARY)
+#
+
+TARGETPATH=.
+TARGETTYPE=DYNLINK
+USE_CRTDLL=1
+
+#
+# The INCLUDES variable specifies any include paths that are specific to
+# this source directory. Separate multiple directory paths with single
+# semicolons. Relative path specifications are okay.
+#
+
+INCLUDES=.;..;..\..\srvcore;..\..\server
+
+#
+# The SOURCES variable is defined by the developer. It is a list of all the
+# source files for this component. Each source file should be on a separate
+# line using the line continuation character. This will minimize merge
+# conflicts if two developers adding source files to the same component.
+#
+
+C_DEFINES=-DUNICODE
+
+SOURCES=\
+ ..\DllGCO.cxx
+
+
+DLLDEF=..\ActSrvD.def
+
+LINKLIBS=\
+ ..\..\srvcore\daytona\obj\*\srvcore.lib \
+ $(BASEDIR)\public\sdk\lib\*\kernel32.lib \
+ $(BASEDIR)\public\sdk\lib\*\user32.lib \
+ $(BASEDIR)\public\sdk\lib\*\advapi32.lib \
+ $(BASEDIR)\public\sdk\lib\*\ntdll.lib \
+ $(BASEDIR)\public\sdk\lib\*\ole32.lib \
+ $(BASEDIR)\public\sdk\lib\*\rpcrt4.lib \
+ $(BASEDIR)\public\sdk\lib\*\uuid.lib \
+ ..\..\common\daytona\*\common.lib
+
+UMTYPE = windows
+DLLBASE=@$(BASEDIR)\PUBLIC\SDK\LIB\coffbase.txt,usermode
diff --git a/private/oleutest/act/dllsrv/dirs b/private/oleutest/act/dllsrv/dirs
new file mode 100644
index 000000000..35b6c7372
--- /dev/null
+++ b/private/oleutest/act/dllsrv/dirs
@@ -0,0 +1,27 @@
+!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:
+
+ Steve Wood (stevewo) 17-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\dirs.tpl
+
+!ENDIF
+
+DIRS=
+
+OPTIONAL_DIRS=\
+ daytona \
+
diff --git a/private/oleutest/act/dllsrv/dllgco.cxx b/private/oleutest/act/dllsrv/dllgco.cxx
new file mode 100644
index 000000000..2ccf23160
--- /dev/null
+++ b/private/oleutest/act/dllsrv/dllgco.cxx
@@ -0,0 +1,37 @@
+/*
+ * DllGCO.cxx
+ * - DllGetClassObject implementation for inproc DLL
+ */
+
+
+#include "server.hxx"
+#include "factory.hxx"
+
+HANDLE hStopServiceEvent;
+BOOL fStartedAsService = FALSE;
+
+long ObjectCount = 0;
+
+STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID FAR* ppv)
+{
+ HRESULT hr = E_NOINTERFACE;
+
+ *ppv = NULL;
+
+ MyFactory * pClass = new FactoryInproc();
+
+ hr = pClass->QueryInterface( riid, ppv );
+
+ return hr;
+}
+
+
+STDAPI DllCanUnloadNow(void)
+{
+return S_FALSE;
+}
+
+void ShutDown()
+{
+}
+
diff --git a/private/oleutest/act/dllsrv/goober.def b/private/oleutest/act/dllsrv/goober.def
new file mode 100644
index 000000000..82ae45878
--- /dev/null
+++ b/private/oleutest/act/dllsrv/goober.def
@@ -0,0 +1,8 @@
+
+LIBRARY GOOBER
+
+DESCRIPTION 'Microsoft (R) Example Proxy/Stub DLL 1.00'
+
+EXPORTS
+ DllGetClassObject
+ DllCanUnloadNow
diff --git a/private/oleutest/act/goober.idl b/private/oleutest/act/goober.idl
new file mode 100644
index 000000000..d273b1180
--- /dev/null
+++ b/private/oleutest/act/goober.idl
@@ -0,0 +1,17 @@
+//
+// goober.idl
+//
+
+[
+ uuid(ffffffff-0000-0000-0000-000000000000),
+ version(0.0),
+ pointer_default(unique),
+ object
+]
+interface IGoober : IUnknown
+{
+ import "unknwn.idl";
+
+ HRESULT Ping();
+}
+ \ No newline at end of file
diff --git a/private/oleutest/act/makefil0 b/private/oleutest/act/makefil0
new file mode 100644
index 000000000..48e5b10ab
--- /dev/null
+++ b/private/oleutest/act/makefil0
@@ -0,0 +1,21 @@
+#
+#
+#
+
+MIDL_FLAGS=-Oi -oldnames -I\nt\public\sdk\inc
+
+all: dll\goober.h
+
+dll\goober.h: goober.idl
+ midl $(MIDL_FLAGS) \
+ -proxy dll/goober_p.c \
+ -dlldata dll/dlldata.c \
+ -header dll/goober.h \
+ -iid common/goober_i.c \
+ goober.idl
+
+clean: sweep all
+
+sweep:
+ del dll\goober.h
+
diff --git a/private/oleutest/act/server/daytona/makefile b/private/oleutest/act/server/daytona/makefile
new file mode 100644
index 000000000..5acbbd24c
--- /dev/null
+++ b/private/oleutest/act/server/daytona/makefile
@@ -0,0 +1 @@
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/oleutest/act/server/daytona/sources b/private/oleutest/act/server/daytona/sources
new file mode 100644
index 000000000..05467a74c
--- /dev/null
+++ b/private/oleutest/act/server/daytona/sources
@@ -0,0 +1,78 @@
+!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:
+
+ Steve Wood (stevewo) 12-Apr-1989
+
+
+Revision History:
+
+!ENDIF
+
+#
+# The TARGETNAME variable is defined by the developer. It is the name of
+# the target (component) that is being built by this makefile. It
+# should NOT include any path or file extension information.
+#
+
+TARGETNAME=actsrv
+
+#
+# The TARGETPATH and TARGETTYPE varialbes are defined by the developer.
+# The first specifies where the target is to be build. The second specifies
+# the type of target (either PROGRAM, DYNLINK or LIBRARY)
+#
+
+TARGETPATH=.
+TARGETTYPE=PROGRAM
+
+USE_CRTDLL=1
+
+#
+# The INCLUDES variable specifies any include paths that are specific to
+# this source directory. Separate multiple directory paths with single
+# semicolons. Relative path specifications are okay.
+#
+
+INCLUDES=.;..\..\srvcore
+
+#
+# The SOURCES variable is defined by the developer. It is a list of all the
+# source files for this component. Each source file should be on a separate
+# line using the line continuation character. This will minimize merge
+# conflicts if two developers adding source files to the same component.
+#
+
+SOURCES=\
+ ..\server.cxx \
+ ..\pswrd.cxx
+
+
+C_DEFINES=-DUNICODE
+
+LINKLIBS=\
+ ..\..\srvcore\daytona\obj\*\srvcore.lib \
+ $(BASEDIR)\public\sdk\lib\*\kernel32.lib \
+ $(BASEDIR)\public\sdk\lib\*\user32.lib \
+ $(BASEDIR)\public\sdk\lib\*\advapi32.lib \
+ $(BASEDIR)\public\sdk\lib\*\ntdll.lib \
+ $(BASEDIR)\public\sdk\lib\*\ole32.lib \
+ $(BASEDIR)\public\sdk\lib\*\rpcrt4.lib \
+ $(BASEDIR)\public\sdk\lib\*\uuid.lib \
+ ..\..\common\daytona\*\common.lib
+
+UMTYPE=console
diff --git a/private/oleutest/act/server/dirs b/private/oleutest/act/server/dirs
new file mode 100644
index 000000000..35b6c7372
--- /dev/null
+++ b/private/oleutest/act/server/dirs
@@ -0,0 +1,27 @@
+!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:
+
+ Steve Wood (stevewo) 17-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\dirs.tpl
+
+!ENDIF
+
+DIRS=
+
+OPTIONAL_DIRS=\
+ daytona \
+
diff --git a/private/oleutest/act/server/pswrd.cxx b/private/oleutest/act/server/pswrd.cxx
new file mode 100644
index 000000000..3b9d3cc79
--- /dev/null
+++ b/private/oleutest/act/server/pswrd.cxx
@@ -0,0 +1,66 @@
+extern "C"
+{
+#include <nt.h>
+#include <ntrtl.h>
+#include <nturtl.h>
+#include <ntlsa.h>
+}
+#include <stdarg.h>
+#include <windef.h>
+#include <winbase.h>
+#include <winnls.h>
+#include <stdio.h>
+
+BOOL SetPassword(TCHAR * szCID, TCHAR * pszPw)
+{
+#ifndef CHICO
+ WCHAR * szPw = pszPw;
+ LSA_OBJECT_ATTRIBUTES sObjAttributes;
+ LSA_HANDLE hPolicy;
+ LSA_UNICODE_STRING sKey;
+ LSA_UNICODE_STRING sPassword;
+ WCHAR szKey[256];
+ swprintf(szKey, L"SCM:%s", szCID);
+ sKey.Length = (wcslen(szKey) + 1) * sizeof(WCHAR);
+ sKey.MaximumLength = (wcslen(szKey) + 1) * sizeof(WCHAR);
+ sKey.Buffer = szKey;
+ sPassword.Length = (wcslen(szPw) + 1) * sizeof(WCHAR);
+ sPassword.MaximumLength = 80 * sizeof(WCHAR);
+ sPassword.Buffer = szPw;
+
+ InitializeObjectAttributes(&sObjAttributes, NULL, 0L, NULL, NULL);
+
+ // open the local security policy
+ if (!NT_SUCCESS(
+ LsaOpenPolicy(
+ NULL,
+ &sObjAttributes,
+ POLICY_CREATE_SECRET,
+ &hPolicy)))
+ {
+ printf("LsaOpenPolicy failed with %d\n",GetLastError());
+ return(FALSE);
+ }
+
+ // store private data
+ if (!NT_SUCCESS(
+ LsaStorePrivateData(hPolicy, &sKey, &sPassword)))
+ {
+ printf("LsaStorePrivateData failed with %d\n",GetLastError());
+ return(FALSE);
+ }
+
+ LsaClose(hPolicy);
+#else
+ WCHAR szPw[256];
+ MultiByteToWideChar( CP_ACP,
+ 0,
+ pszPw,
+ -1,
+ szPw,
+ sizeof(szPw) / sizeof(WCHAR) );
+#endif
+ return(TRUE);
+}
+
+
diff --git a/private/oleutest/act/server/server.cxx b/private/oleutest/act/server/server.cxx
new file mode 100644
index 000000000..7b400bc7d
--- /dev/null
+++ b/private/oleutest/act/server/server.cxx
@@ -0,0 +1,1033 @@
+/*
+ * server.cxx
+ */
+
+#ifdef UNICODE
+#define _UNICODE 1
+#endif
+
+#include "server.hxx"
+#include "factory.hxx"
+#include "tchar.h"
+
+long ObjectCount = 0;
+
+TCHAR * AtStorageFileName = TEXT("c:\\tmp\\atbits.dat");
+
+TCHAR * UserName = TEXT("redmond\\oleuser");
+TCHAR * Password = TEXT("stocksplit");
+TCHAR * ServiceName = TEXT("ActTestService");
+TCHAR * ServiceDisplayName = TEXT("ActTestService");
+BOOL fStartedAsService = FALSE;
+HANDLE hStopServiceEvent;
+SERVICE_STATUS SStatus;
+SERVICE_STATUS_HANDLE hService;
+BOOL InstallService(TCHAR * );
+
+HKEY ghClsidRootKey = 0;
+HKEY ghAppIDRootKey = 0;
+
+DWORD RegHandleLocal;
+DWORD RegHandleRemote;
+DWORD RegHandleAtStorage;
+DWORD RegHandlePreConfig;
+DWORD RegHandleRunAsLoggedOn;
+DWORD RegHandleService;
+DWORD RegHandleServerOnly;
+unsigned uClassIndex = 0;
+
+//+---------------------------------------------------------------------------
+//
+// Function: main
+//
+// Synopsis: main entry point for SCM
+//
+// History: 1-18-96 stevebl Created
+//
+//----------------------------------------------------------------------------
+void _cdecl RealMain( int argc, char ** argv )
+{
+ HRESULT hr;
+ MSG msg;
+
+ if ( (argc > 1) &&
+ ((strcmp(argv[1],"-?") == 0) || (strcmp(argv[1],"/?") == 0)) )
+ PrintUsageAndExit();
+
+ if ( (argc > 1) && (strcmp(argv[1],"-r") == 0) )
+ {
+ DebuggerType eDebug = same_debugger;
+ int n;
+
+ n = 2;
+
+ if ( n < argc )
+ {
+ if (strcmp(argv[n],"-d") == 0)
+ eDebug = windbg_debugger;
+ else if (strcmp(argv[n],"-n") == 0 )
+ eDebug = ntsd_debugger;
+ else if (strcmp(argv[n],"-x") == 0 )
+ eDebug = clear_debugger;
+ }
+
+ if ( hr = InitializeRegistry( eDebug ) )
+ printf("InitializeRegistry failed with %08x\n", hr);
+ else
+ printf("Registry updated successfully.\n");
+
+ return;
+ }
+
+ // Started manually. Don't go away.
+ if ( (argc == 1) && ! fStartedAsService )
+ ObjectCount = 1;
+
+ if ( ! fStartedAsService )
+ {
+ if ( (argc >= 3 && strcmp(argv[2], "-Embedding") == 0) )
+ uClassIndex = argv[1][0] - '0';
+ else
+ uClassIndex = 0;
+ }
+
+ if ( fStartedAsService )
+ {
+ uClassIndex = 8;
+
+#ifdef NT351
+ hr = E_FAIL;
+#else
+ hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
+#endif
+ }
+ else
+ {
+ hr = CoInitialize(NULL);
+ }
+
+ if ( FAILED(hr) )
+ {
+ printf( "Server: CoInitialize failed(%x)\n", hr );
+ return;
+ }
+
+ if (0 == uClassIndex || 2 == uClassIndex)
+ {
+ hr = CoRegisterClassObject( CLSID_ActLocal,
+ (IUnknown *)new FactoryLocal(),
+ CLSCTX_LOCAL_SERVER,
+ REGCLS_MULTIPLEUSE,
+ &RegHandleLocal );
+
+ if ( FAILED(hr) )
+ {
+ printf("Server: CoRegisterClassObject failed %x\n", hr);
+ CoUninitialize();
+ return;
+ }
+ }
+
+ if (0 == uClassIndex || 3 == uClassIndex)
+ {
+ hr = CoRegisterClassObject( CLSID_ActRemote,
+ (IUnknown *)new FactoryRemote(),
+ CLSCTX_LOCAL_SERVER,
+ REGCLS_MULTIPLEUSE,
+ &RegHandleRemote );
+
+ if ( FAILED(hr) )
+ {
+ printf("Server: CoRegisterClassObject failed %x\n", hr);
+ if (0 == uClassIndex)
+ {
+ CoRevokeClassObject( RegHandleLocal );
+ }
+ CoUninitialize();
+ return;
+ }
+ }
+
+ if (0 == uClassIndex || 4 == uClassIndex)
+ {
+ hr = CoRegisterClassObject( CLSID_ActAtStorage,
+ (IUnknown *)new FactoryAtStorage(),
+ CLSCTX_LOCAL_SERVER,
+ REGCLS_MULTIPLEUSE,
+ &RegHandleAtStorage );
+
+ if ( FAILED(hr) )
+ {
+ printf("Server: CoRegisterClassObject failed %x\n", hr);
+ if (0 == uClassIndex)
+ {
+ CoRevokeClassObject( RegHandleLocal );
+ CoRevokeClassObject( RegHandleRemote );
+ }
+ CoUninitialize();
+ return;
+ }
+ }
+
+ if (0 == uClassIndex || 6 == uClassIndex)
+ {
+ hr = CoRegisterClassObject( CLSID_ActPreConfig,
+ (IUnknown *)new FactoryAtStorage(),
+ CLSCTX_LOCAL_SERVER,
+ REGCLS_MULTIPLEUSE,
+ &RegHandlePreConfig );
+
+ if ( FAILED(hr) )
+ {
+ printf("Server: CoRegisterClassObject failed %x\n", hr);
+ if (0 == uClassIndex)
+ {
+ CoRevokeClassObject( RegHandleLocal );
+ CoRevokeClassObject( RegHandleRemote );
+ CoRevokeClassObject( RegHandleAtStorage );
+ }
+ CoUninitialize();
+ return;
+ }
+ }
+
+ if (0 == uClassIndex || 7 == uClassIndex)
+ {
+ hr = CoRegisterClassObject( CLSID_ActRunAsLoggedOn,
+ (IUnknown *)new FactoryAtStorage(),
+ CLSCTX_LOCAL_SERVER,
+ REGCLS_MULTIPLEUSE,
+ &RegHandleRunAsLoggedOn );
+
+ if ( FAILED(hr) )
+ {
+ printf("Server: CoRegisterClassObject failed %x\n", hr);
+ if (0 == uClassIndex)
+ {
+ CoRevokeClassObject( RegHandleLocal );
+ CoRevokeClassObject( RegHandleRemote );
+ CoRevokeClassObject( RegHandleAtStorage );
+ CoRevokeClassObject( RegHandlePreConfig );
+ }
+ CoUninitialize();
+ return;
+ }
+ }
+
+ if (0 == uClassIndex || 9 == uClassIndex)
+ {
+ hr = CoRegisterClassObject( CLSID_ActServerOnly,
+ (IUnknown *)new FactoryAtStorage(),
+ CLSCTX_LOCAL_SERVER,
+ REGCLS_MULTIPLEUSE,
+ &RegHandleServerOnly );
+
+ if ( FAILED(hr) )
+ {
+ printf("Server: CoRegisterClassObject failed %x\n", hr);
+ if (0 == uClassIndex)
+ {
+ CoRevokeClassObject( RegHandleLocal );
+ CoRevokeClassObject( RegHandleRemote );
+ CoRevokeClassObject( RegHandleAtStorage );
+ CoRevokeClassObject( RegHandlePreConfig );
+ CoRevokeClassObject( RegHandleRunAsLoggedOn );
+ }
+ CoUninitialize();
+ return;
+ }
+ }
+
+ if (fStartedAsService)
+ {
+ hr = CoRegisterClassObject( CLSID_ActService,
+ (IUnknown *)new FactoryAtStorage(),
+ CLSCTX_LOCAL_SERVER,
+ REGCLS_MULTIPLEUSE,
+ &RegHandleService );
+
+ if ( FAILED(hr) )
+ {
+ CoUninitialize();
+ return;
+ }
+
+ WaitForSingleObject(hStopServiceEvent, INFINITE);
+ }
+ else
+ {
+ // only do message loop if not a service
+ while (GetMessage(&msg, NULL, 0, 0))
+ {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ }
+
+ CoUninitialize();
+
+ return;
+}
+
+int gargc;
+char * gargv[100];
+
+BOOL UpdateStatus(DWORD dwState)
+{
+ if (SERVICE_RUNNING == SStatus.dwCurrentState &&
+ SERVICE_START_PENDING == dwState)
+ {
+ return(TRUE);
+ }
+
+ SStatus.dwCurrentState = dwState;
+ if (SERVICE_START_PENDING == dwState ||
+ SERVICE_STOP_PENDING == dwState)
+ {
+ SStatus.dwCheckPoint++;
+ SStatus.dwWaitHint = 1;
+ }
+ else
+ {
+ SStatus.dwCheckPoint = 0;
+ SStatus.dwWaitHint = 0;
+ }
+
+ return(SetServiceStatus(hService, &SStatus));
+}
+
+DWORD StartMyMain(void * pArg)
+{
+ // reconstruct the command line args and call the real main
+ RealMain(gargc, gargv);
+ UpdateStatus(SERVICE_STOPPED);
+ return(0);
+}
+
+void Handler(DWORD fdwControl)
+{
+ switch (fdwControl)
+ {
+ case SERVICE_CONTROL_STOP:
+ UpdateStatus(SERVICE_STOP_PENDING);
+ SetEvent(hStopServiceEvent);
+ break;
+ case SERVICE_CONTROL_INTERROGATE:
+ UpdateStatus(SERVICE_RUNNING);
+ break;
+ default:
+ break;
+ }
+}
+
+//+---------------------------------------------------------------------------
+//
+// Function: ServiceMain
+//
+// Synopsis: main entry point for service
+//
+// History: 1-18-96 stevebl Created
+//
+//----------------------------------------------------------------------------
+
+void ServiceMain(DWORD argc, LPTSTR * argv)
+{
+ fStartedAsService = TRUE;
+
+ // register the service handler
+ hService = RegisterServiceCtrlHandler(ServiceName, Handler);
+
+ if (!hService)
+ return;
+
+ SStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS |
+ SERVICE_INTERACTIVE_PROCESS,
+ SStatus.dwControlsAccepted = SERVICE_CONTROL_STOP |
+ SERVICE_CONTROL_INTERROGATE;
+ SStatus.dwWin32ExitCode = NO_ERROR;
+ SStatus.dwServiceSpecificExitCode = 0;
+ SStatus.dwCheckPoint = 0;
+ SStatus.dwWaitHint = 0;
+
+ if (!UpdateStatus(SERVICE_START_PENDING))
+ return;
+
+ // create an event to signal when the service is to stop
+ hStopServiceEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+ if (!hStopServiceEvent)
+ {
+ return;
+ }
+
+ UpdateStatus(SERVICE_RUNNING);
+
+ StartMyMain( NULL );
+}
+
+void _cdecl main( int argc, char ** argv)
+{
+ if (argc > 1 && strcmp(argv[1], "8") == 0)
+ {
+ gargc = argc;
+
+ // save the command line arguments
+ gargc = (int) argc;
+ if (gargc > 100)
+ {
+ gargc = 100;
+ }
+ for (int k = 1; k <= gargc; k++)
+ {
+ gargv[k-1] = (char *) malloc(strlen(argv[k-1]) + 1);
+ strcpy(gargv[k-1], argv[k-1]);
+ }
+
+ // Start as a service
+ SERVICE_TABLE_ENTRY ServiceStart[2];
+ ServiceStart[0].lpServiceName = ServiceName;
+ ServiceStart[0].lpServiceProc = ServiceMain;
+ ServiceStart[1].lpServiceName = NULL;
+ ServiceStart[1].lpServiceProc = NULL;
+
+ if (!StartServiceCtrlDispatcher (ServiceStart))
+ {
+ ExitProcess(GetLastError());
+ }
+ ExitProcess(0);
+ }
+ else
+ {
+ // start as a regular app
+ RealMain(argc, argv);
+ }
+}
+
+
+long InitializeRegistry( DebuggerType eDebugServer )
+{
+ long RegStatus;
+ ulong Disposition;
+ HKEY hActKey;
+ HKEY hDebugKey;
+ HANDLE hFile;
+ TCHAR Path[256];
+ TCHAR * pwszServerExe;
+ TCHAR * pwszDebuggerName;
+ DWORD DebugFlags;
+
+ if ( ! GetModuleFileName( 0, Path, sizeof(Path) ) )
+ return ERROR_BAD_PATHNAME;
+
+ hFile = CreateFile( AtStorageFileName,
+ GENERIC_WRITE,
+ 0,
+ NULL,
+ CREATE_ALWAYS,
+ 0,
+ 0 );
+
+ if ( hFile == INVALID_HANDLE_VALUE )
+ {
+ printf("Couldn't create file %ws\n", AtStorageFileName );
+ return GetLastError();
+ }
+
+ CloseHandle( hFile );
+
+ RegStatus = RegOpenKeyEx( HKEY_CLASSES_ROOT,
+ TEXT("CLSID"),
+ 0,
+ KEY_ALL_ACCESS,
+ &ghClsidRootKey );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ RegStatus = RegOpenKeyEx( HKEY_CLASSES_ROOT,
+ TEXT("APPID"),
+ 0,
+ KEY_ALL_ACCESS,
+ &ghAppIDRootKey );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ DeleteClsidKey( ClsidGoober32String );
+ DeleteClsidKey( ClsidActLocalString );
+ DeleteClsidKey( ClsidActRemoteString );
+ DeleteClsidKey( ClsidActAtStorageString );
+ DeleteClsidKey( ClsidActInprocString );
+ DeleteClsidKey( ClsidActPreConfigString );
+ DeleteClsidKey( ClsidActRunAsLoggedOnString );
+ DeleteClsidKey( ClsidActServiceString );
+ DeleteClsidKey( ClsidActServerOnlyString );
+
+ //
+ // Local CLSID entries.
+ //
+
+ _tcscat(Path, TEXT(" 2"));
+
+ RegStatus = SetClsidRegKeyAndStringValue(
+ ClsidActLocalString,
+ TEXT("LocalServer32"),
+ Path,
+ NULL,
+ NULL );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ RegStatus = SetAppIDSecurity( ClsidActLocalString );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ //
+ // Remote CLSID entries.
+ //
+
+ Path[_tcslen(Path)-1] = TEXT('3');
+
+ RegStatus = SetClsidRegKeyAndStringValue(
+ ClsidActRemoteString,
+ TEXT("LocalServer32"),
+ Path,
+ NULL,
+ NULL );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ RegStatus = SetAppIDSecurity( ClsidActRemoteString );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ //
+ // AtStorage CLSID entries.
+ //
+
+ Path[_tcslen(Path)-1] = TEXT('4');
+
+ RegStatus = SetClsidRegKeyAndStringValue(
+ ClsidActAtStorageString,
+ TEXT("LocalServer32"),
+ Path,
+ NULL,
+ NULL );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ RegStatus = SetAppIDSecurity( ClsidActAtStorageString );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ //
+ // RunAs CLSID entries.'
+ //
+
+ Path[_tcslen(Path)-1] = TEXT('6');
+
+ RegStatus = SetClsidRegKeyAndStringValue(
+ ClsidActPreConfigString,
+ TEXT("LocalServer32"),
+ Path,
+ NULL,
+ NULL );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ RegStatus = SetAppIDRegKeyAndNamedValue(
+ ClsidActPreConfigString,
+ TEXT("RunAs"),
+ UserName,
+ NULL );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+
+ RegStatus = SetAppIDSecurity( ClsidActPreConfigString );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ if (!SetPassword(ClsidActPreConfigString, Password))
+ return(FALSE);
+
+ if (!AddBatchPrivilege( UserName ) )
+ return(FALSE);
+
+ //
+ // RunAs logged on user CLSID entries.
+ //
+
+ Path[_tcslen(Path)-1] = TEXT('7');
+
+ RegStatus = SetClsidRegKeyAndStringValue(
+ ClsidActRunAsLoggedOnString,
+ TEXT("LocalServer32"),
+ Path,
+ NULL,
+ NULL );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ RegStatus = SetAppIDRegKeyAndNamedValue(
+ ClsidActRunAsLoggedOnString,
+ TEXT("RunAs"),
+ TEXT("Interactive User"),
+ NULL );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ RegStatus = SetAppIDSecurity( ClsidActRunAsLoggedOnString );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ //
+ // Service CLSID entries.
+ //
+
+ RegStatus = SetAppIDRegKeyAndNamedValue(
+ ClsidActServiceString,
+ TEXT("LocalService"),
+ ServiceName,
+ NULL );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ RegStatus = SetAppIDSecurity( ClsidActServiceString );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ // Get the services key
+ HKEY hServices;
+ RegStatus = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
+ TEXT("SYSTEM\\CurrentControlSet\\Services"),
+ 0,
+ KEY_READ | KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS,
+ &hServices );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ Path[_tcslen(Path)-1] = TEXT('8');
+
+
+ if (!InstallService(Path))
+ return TRUE;
+
+ //
+ // Server only CLSID entry.
+ //
+
+ Path[_tcslen(Path)-1] = TEXT('9');
+
+ RegStatus = SetClsidRegKeyAndStringValue(
+ ClsidActServerOnlyString,
+ TEXT("LocalServer32"),
+ Path,
+ NULL,
+ NULL );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ RegStatus = SetAppIDSecurity( ClsidActServerOnlyString );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+
+ //
+ // Add entries to launch server in debugger.
+ //
+
+ if ( eDebugServer == same_debugger )
+ return ERROR_SUCCESS;
+
+ Path[_tcslen(Path)-2] = 0;
+ pwszServerExe = Path + _tcslen(Path);
+ while ( (pwszServerExe > Path) && (pwszServerExe[-1] != TEXT('\\')) )
+ pwszServerExe--;
+
+ RegStatus = RegOpenKeyEx(
+ HKEY_LOCAL_MACHINE,
+ TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion"),
+ 0,
+ KEY_ALL_ACCESS,
+ &hDebugKey );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ RegStatus = RegCreateKeyEx(
+ hDebugKey,
+ TEXT("Image File Execution Options"),
+ 0,
+ TEXT("REG_SZ"),
+ REG_OPTION_NON_VOLATILE,
+ KEY_ALL_ACCESS,
+ NULL,
+ &hDebugKey,
+ &Disposition );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ if ( eDebugServer == clear_debugger )
+ {
+ RegDeleteKey( hDebugKey, pwszServerExe );
+ return ERROR_SUCCESS;
+ }
+
+ RegStatus = RegCreateKeyEx(
+ hDebugKey,
+ pwszServerExe,
+ 0,
+ TEXT("REG_SZ"),
+ REG_OPTION_NON_VOLATILE,
+ KEY_ALL_ACCESS,
+ NULL,
+ &hDebugKey,
+ &Disposition );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ if ( eDebugServer == ntsd_debugger )
+ {
+ pwszDebuggerName = TEXT("ntsd.exe -d");
+ }
+ else
+ {
+ pwszDebuggerName = TEXT("windbg.exe");
+ }
+
+ DebugFlags = 0x10f0;
+
+ RegStatus = RegSetValueEx(
+ hDebugKey,
+ TEXT("Debugger"),
+ 0,
+ REG_SZ,
+ (const BYTE *)pwszDebuggerName,
+ (_tcslen(pwszDebuggerName) + 1) * sizeof(TCHAR) );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ RegStatus = RegSetValueEx(
+ hDebugKey,
+ TEXT("GlobalFlag"),
+ 0,
+ REG_DWORD,
+ (const BYTE *)&DebugFlags,
+ sizeof(DWORD) );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ return ERROR_SUCCESS;
+}
+
+long SetClsidRegKeyAndStringValue(
+ TCHAR * pwszClsid,
+ TCHAR * pwszKey,
+ TCHAR * pwszValue,
+ HKEY * phClsidKey,
+ HKEY * phNewKey )
+{
+ long RegStatus;
+ DWORD Disposition;
+ HKEY hClsidKey;
+
+ if ( phClsidKey )
+ *phClsidKey = 0;
+
+ if ( phNewKey )
+ *phNewKey = 0;
+
+ RegStatus = RegCreateKeyEx(
+ ghClsidRootKey,
+ pwszClsid,
+ 0,
+ TEXT("REG_SZ"),
+ REG_OPTION_NON_VOLATILE,
+ KEY_ALL_ACCESS,
+ NULL,
+ &hClsidKey,
+ &Disposition );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ if ( phClsidKey )
+ *phClsidKey = hClsidKey;
+
+ return SetRegKeyAndStringValue(
+ hClsidKey,
+ pwszKey,
+ pwszValue,
+ phNewKey );
+}
+
+long SetAppIDRegKeyAndNamedValue(
+ TCHAR * pwszAppID,
+ TCHAR * pwszKey,
+ TCHAR * pwszValue,
+ HKEY * phClsidKey )
+{
+ long RegStatus;
+ DWORD Disposition;
+ HKEY hClsidKey;
+
+ if ( phClsidKey )
+ *phClsidKey = 0;
+
+ // first, make sure the clsid has appid={appid}
+ RegStatus = RegCreateKeyEx(
+ ghClsidRootKey,
+ pwszAppID,
+ 0,
+ TEXT("REG_SZ"),
+ REG_OPTION_NON_VOLATILE,
+ KEY_ALL_ACCESS,
+ NULL,
+ &hClsidKey,
+ &Disposition );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ RegStatus = SetNamedStringValue(
+ hClsidKey,
+ TEXT("AppID"),
+ pwszAppID );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ RegStatus = RegCreateKeyEx(
+ ghAppIDRootKey,
+ pwszAppID,
+ 0,
+ TEXT("REG_SZ"),
+ REG_OPTION_NON_VOLATILE,
+ KEY_ALL_ACCESS,
+ NULL,
+ &hClsidKey,
+ &Disposition );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ if ( phClsidKey )
+ *phClsidKey = hClsidKey;
+
+ return SetNamedStringValue(
+ hClsidKey,
+ pwszKey,
+ pwszValue );
+}
+
+long SetNamedStringValue(
+ HKEY hKey,
+ TCHAR * pwszKey,
+ TCHAR * pwszValue )
+{
+ long RegStatus;
+ DWORD Disposition;
+
+ RegStatus = RegSetValueEx(
+ hKey,
+ pwszKey,
+ 0,
+ REG_SZ,
+ (const BYTE *)pwszValue,
+ (_tcslen(pwszValue) + 1) * sizeof(TCHAR) );
+
+ return RegStatus;
+}
+
+long SetRegKeyAndStringValue(
+ HKEY hKey,
+ TCHAR * pwszKey,
+ TCHAR * pwszValue,
+ HKEY * phNewKey )
+{
+ long RegStatus;
+ DWORD Disposition;
+ HKEY hNewKey;
+
+ if ( phNewKey )
+ *phNewKey = 0;
+
+ RegStatus = RegCreateKeyEx(
+ hKey,
+ pwszKey,
+ 0,
+ TEXT("REG_SZ"),
+ REG_OPTION_NON_VOLATILE,
+ KEY_ALL_ACCESS,
+ NULL,
+ &hNewKey,
+ &Disposition );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ RegStatus = RegSetValueEx(
+ hNewKey,
+ TEXT(""),
+ 0,
+ REG_SZ,
+ (const BYTE *)pwszValue,
+ (_tcslen(pwszValue) + 1) * sizeof(TCHAR) );
+
+ if ( phNewKey )
+ *phNewKey = hNewKey;
+
+ return RegStatus;
+}
+
+BOOL InstallService(TCHAR * Path)
+{
+#ifndef CHICO
+ SC_HANDLE hManager = OpenSCManager(
+ NULL,
+ NULL,
+ SC_MANAGER_ALL_ACCESS);
+ if (NULL == hManager)
+ {
+ printf("OpenSCManager returned %d\n",GetLastError());
+ return(FALSE);
+ }
+
+ SC_HANDLE hService = OpenService(
+ hManager,
+ ServiceName,
+ SERVICE_ALL_ACCESS);
+
+ if (NULL != hService)
+ {
+ if (!ChangeServiceConfig(
+ hService,
+ SERVICE_WIN32_OWN_PROCESS |
+ SERVICE_INTERACTIVE_PROCESS,
+ SERVICE_DEMAND_START,
+ SERVICE_ERROR_NORMAL,
+ Path,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ ServiceDisplayName
+ )
+ )
+ {
+ printf("ChangeService returned %d\n",GetLastError());
+ CloseServiceHandle(hService);
+ CloseServiceHandle(hManager);
+ return(FALSE);
+ }
+ return(TRUE);
+ }
+
+ hService = CreateService(
+ hManager,
+ ServiceName,
+ ServiceDisplayName,
+ SERVICE_ALL_ACCESS,
+ SERVICE_WIN32_OWN_PROCESS |
+ SERVICE_INTERACTIVE_PROCESS,
+ SERVICE_DEMAND_START,
+ SERVICE_ERROR_NORMAL,
+ Path,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+ if (NULL == hService)
+ {
+ printf("CreateService returned %d\n",GetLastError());
+ CloseServiceHandle(hManager);
+ return(FALSE);
+ }
+
+ CloseServiceHandle(hService);
+ CloseServiceHandle(hManager);
+#endif
+ return(TRUE);
+}
+
+void PrintUsageAndExit()
+{
+ printf("Usage : actsrv [-r [-d | -n | -x]]\n");
+ printf("\t-r : Make necessary registry changes.\n");
+ printf("\t-d : Register server to start in windbg.\n");
+ printf("\t-n : Register server to start with ntsd -d.\n");
+ printf("\t-x : Register server and clear debugger.\n");
+
+ ExitProcess(0);
+}
+
+void ShutDown()
+{
+ // The last object has been destroyed.
+ if (fStartedAsService)
+ {
+ CoRevokeClassObject( RegHandleService );
+ }
+
+ switch( uClassIndex )
+ {
+ case 0 :
+ CoRevokeClassObject( RegHandleLocal );
+ CoRevokeClassObject( RegHandleRemote );
+ CoRevokeClassObject( RegHandleAtStorage );
+ CoRevokeClassObject( RegHandlePreConfig );
+ CoRevokeClassObject( RegHandleRunAsLoggedOn );
+ CoRevokeClassObject( RegHandleServerOnly );
+ break;
+ case 2:
+ CoRevokeClassObject( RegHandleLocal );
+ break;
+ case 3:
+ CoRevokeClassObject( RegHandleRemote );
+ break;
+ case 4:
+ CoRevokeClassObject( RegHandleAtStorage );
+ break;
+ case 6:
+ CoRevokeClassObject( RegHandlePreConfig );
+ break;
+ case 7 :
+ CoRevokeClassObject( RegHandleRunAsLoggedOn );
+ break;
+ case 9 :
+ CoRevokeClassObject( RegHandleServerOnly );
+ break;
+ }
+
+ if (fStartedAsService)
+ {
+ SetEvent(hStopServiceEvent);
+ }
+ else
+ {
+ PostQuitMessage(0);
+ }
+}
diff --git a/private/oleutest/act/server/server.hxx b/private/oleutest/act/server/server.hxx
new file mode 100644
index 000000000..1761ce041
--- /dev/null
+++ b/private/oleutest/act/server/server.hxx
@@ -0,0 +1,69 @@
+/*
+ * server.hxx
+ */
+
+#ifndef _SERVER_
+#define _SERVER_
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <windows.h>
+#include <rpc.h>
+#include <ole2.h>
+#include "..\acttest.h"
+#include "..\dll\goober.h"
+
+typedef unsigned long ulong;
+typedef unsigned char uchar;
+
+#define LOCAL 1
+#define REMOTE 2
+#define ATBITS 3
+#define INPROC 4
+
+typedef enum _debugger_type {
+ same_debugger,
+ clear_debugger,
+ ntsd_debugger,
+ windbg_debugger
+ } DebuggerType;
+
+void PrintUsageAndExit();
+
+BOOL SetPassword(
+ TCHAR * szCID,
+ TCHAR * szPw );
+
+long InitializeRegistry(
+ DebuggerType eDebug );
+
+long SetClsidRegKeyAndStringValue(
+ TCHAR * pwszClsid,
+ TCHAR * pwszKey,
+ TCHAR * pwszValue,
+ HKEY * phClsidKey,
+ HKEY * phNewKey );
+
+long SetRegKeyAndStringValue(
+ HKEY hKey,
+ TCHAR * pwszKey,
+ TCHAR * pwszValue,
+ HKEY * phNewKey );
+
+long SetAppIDRegKeyAndNamedValue(
+ TCHAR * pwszAppID,
+ TCHAR * pwszKey,
+ TCHAR * pwszValue,
+ HKEY * phClsidKey );
+
+long SetNamedStringValue(
+ HKEY hKey,
+ TCHAR * pwszKey,
+ TCHAR * pwszValue );
+
+extern BOOL fStartedAsService;
+extern HANDLE hStopServiceEvent;
+extern long ObjectCount;
+void ShutDown();
+
+#endif
diff --git a/private/oleutest/act/srvcore/classes.cxx b/private/oleutest/act/srvcore/classes.cxx
new file mode 100644
index 000000000..45bd0bac0
--- /dev/null
+++ b/private/oleutest/act/srvcore/classes.cxx
@@ -0,0 +1,278 @@
+/*
+ * classes.cxx
+ */
+
+#include "server.hxx"
+#include "classes.hxx"
+
+//
+// MyObject implementation.
+//
+
+MyObject::MyObject( int ActType ) :
+ Refs(0),
+ ActivationType(ActType),
+ PersistFileObj(this),
+ PersistStorageObj(this),
+ GooberObj(this)
+{
+}
+
+MyObject::~MyObject()
+{
+}
+
+//
+// MyObject IUnknown.
+//
+
+HRESULT STDMETHODCALLTYPE
+MyObject::QueryInterface (
+ REFIID iid,
+ void ** ppv )
+{
+ HRESULT hr = E_NOINTERFACE;
+
+ *ppv = 0;
+
+ if ( memcmp(&iid, &IID_IUnknown, sizeof(IID)) == 0 )
+ *ppv = this;
+ else if ( (memcmp(&iid, &IID_IPersist, sizeof(IID)) == 0) ||
+ (memcmp(&iid, &IID_IPersistFile, sizeof(IID)) == 0) )
+ *ppv = &PersistFileObj;
+ else if ( memcmp(&iid, &IID_IPersistStorage, sizeof(IID)) == 0 )
+ *ppv = &PersistStorageObj;
+ else if ( memcmp(&iid, &IID_IGoober, sizeof(IID)) == 0 )
+ *ppv = &GooberObj;
+ else
+ return E_NOINTERFACE;
+
+ ((IUnknown *)(*ppv))->AddRef();
+ return S_OK;
+}
+
+ULONG STDMETHODCALLTYPE
+MyObject::AddRef()
+{
+ Refs++;
+ return Refs;
+}
+
+ULONG STDMETHODCALLTYPE
+MyObject::Release()
+{
+ unsigned long Count;
+
+ Count = --Refs;
+
+ if ( Count == 0 )
+ {
+ delete this;
+
+ // Decrement the object count.
+ if ( --ObjectCount == 0 )
+ ShutDown();
+ }
+
+ return Count;
+}
+
+//
+// PersistFile implementation.
+//
+
+PersistFile::PersistFile( MyObject * pObj ) :
+ pObject(pObj)
+{
+}
+
+//
+// PersistFile IUnknown.
+//
+IUnknownMETHODS( PersistFile )
+
+//
+// PersistFile IPersist.
+//
+
+HRESULT STDMETHODCALLTYPE
+PersistFile::GetClassID(
+ CLSID * pClassID )
+{
+ if ( pObject->GetActivationType() == LOCAL )
+ memcpy( pClassID, &CLSID_ActLocal, sizeof(IID) );
+ else if ( pObject->GetActivationType() == REMOTE )
+ memcpy( pClassID, &CLSID_ActRemote, sizeof(IID) );
+ else if (pObject->GetActivationType() == ATBITS )
+ memcpy( pClassID, &CLSID_ActAtStorage, sizeof(IID) );
+ else if (pObject->GetActivationType() == INPROC )
+ memcpy( pClassID, &CLSID_ActInproc, sizeof(IID) );
+ return S_OK;
+}
+
+//
+// PersistFile IPersistFile
+//
+
+HRESULT STDMETHODCALLTYPE
+PersistFile::IsDirty()
+{
+ return S_FALSE;
+}
+
+HRESULT STDMETHODCALLTYPE
+PersistFile::Load(
+ LPCOLESTR pszFileName,
+ DWORD dwMode )
+{
+ /** Doesn't work until we have security stuff...
+
+ HANDLE hFile;
+
+ //
+ // Verify that we can open the file.
+ //
+
+ hFile = CreateFile(
+ pszFileName,
+ dwMode,
+ 0,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL );
+
+ if ( hFile == INVALID_HANDLE_VALUE )
+ return HRESULT_FROM_WIN32( GetLastError() );
+
+ CloseHandle( hFile );
+
+ **/
+
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE
+PersistFile::Save(
+ LPCOLESTR pszFileName,
+ BOOL fRemember )
+{
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE
+PersistFile::SaveCompleted(
+ LPCOLESTR pszFileName )
+{
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE
+PersistFile::GetCurFile(
+ LPOLESTR * ppszFileName )
+{
+ *ppszFileName = 0;
+ return S_OK;
+}
+
+//
+// PersistStorage implementation.
+//
+
+PersistStorage::PersistStorage( MyObject * pObj ) :
+ pObject(pObj)
+{
+}
+
+//
+// PersistStorage IUnknown.
+//
+IUnknownMETHODS( PersistStorage )
+
+//
+// PersistStorage IPersist.
+//
+
+HRESULT STDMETHODCALLTYPE
+PersistStorage::GetClassID(
+ CLSID * pClassID )
+{
+ if ( pObject->GetActivationType() == LOCAL )
+ memcpy( pClassID, &CLSID_ActLocal, sizeof(IID) );
+ else if ( pObject->GetActivationType() == REMOTE )
+ memcpy( pClassID, &CLSID_ActRemote, sizeof(IID) );
+ else if (pObject->GetActivationType() == ATBITS )
+ memcpy( pClassID, &CLSID_ActAtStorage, sizeof(IID) );
+ else if (pObject->GetActivationType() == INPROC )
+ memcpy( pClassID, &CLSID_ActInproc, sizeof(IID) );
+ return S_OK;
+}
+
+//
+// PersistStorage IPersistStorage
+//
+
+HRESULT STDMETHODCALLTYPE
+PersistStorage::IsDirty()
+{
+ return S_FALSE;
+}
+
+HRESULT STDMETHODCALLTYPE
+PersistStorage::InitNew(
+ IStorage * pStg )
+{
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE
+PersistStorage::Load(
+ IStorage * pStg )
+{
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE
+PersistStorage::Save(
+ IStorage * pStgSave,
+ BOOL fSameAsLoad )
+{
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE
+PersistStorage::SaveCompleted(
+ IStorage * pStgNew )
+{
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE
+PersistStorage::HandsOffStorage()
+{
+ return S_OK;
+}
+
+//
+// Goober implementation
+//
+Goober::Goober( MyObject * pObj ) :
+ pObject(pObj)
+{
+}
+
+//
+// Goober IUnknown.
+//
+IUnknownMETHODS( Goober )
+
+//
+// Goober IGoober.
+//
+HRESULT STDMETHODCALLTYPE
+Goober::Ping()
+{
+ return S_OK;
+}
+
+
diff --git a/private/oleutest/act/srvcore/classes.hxx b/private/oleutest/act/srvcore/classes.hxx
new file mode 100644
index 000000000..37aab7051
--- /dev/null
+++ b/private/oleutest/act/srvcore/classes.hxx
@@ -0,0 +1,152 @@
+/*
+ * classes.hxx
+ */
+
+#ifndef _CLASSES_
+#define _CLASSES_
+
+#define IUnknownMETHODS( ClassName ) \
+ HRESULT STDMETHODCALLTYPE \
+ ClassName::QueryInterface ( \
+ REFIID iid, \
+ void ** ppv ) \
+ { \
+ return pObject->QueryInterface( iid, ppv ); \
+ } \
+ \
+ ULONG STDMETHODCALLTYPE \
+ ClassName::AddRef() \
+ { \
+ return pObject->AddRef(); \
+ } \
+ \
+ ULONG STDMETHODCALLTYPE \
+ ClassName::Release() \
+ { \
+ return pObject->Release(); \
+ }
+
+class MyObject;
+
+//
+// PersistFile class.
+//
+class PersistFile : public IPersistFile
+{
+private:
+ MyObject * pObject;
+
+public:
+ PersistFile( MyObject * pObj );
+
+ // IUnknown
+ HRESULT __stdcall QueryInterface(
+ REFIID iid,
+ void ** ppv );
+ ULONG __stdcall AddRef();
+ ULONG __stdcall Release();
+
+ // IPersist
+ HRESULT __stdcall GetClassID(
+ CLSID * pClassID );
+
+ // IPersistFile
+ HRESULT __stdcall IsDirty();
+ HRESULT __stdcall Load(
+ LPCOLESTR pszFileName,
+ DWORD dwMode );
+ HRESULT __stdcall Save(
+ LPCOLESTR pszFileName,
+ BOOL fRemember );
+ HRESULT __stdcall SaveCompleted(
+ LPCOLESTR pszFileName );
+ HRESULT __stdcall GetCurFile(
+ LPOLESTR * ppszFileName );
+};
+
+//
+// PersistStorage class.
+//
+class PersistStorage : public IPersistStorage
+{
+private:
+ MyObject * pObject;
+
+public:
+ PersistStorage( MyObject * pObj );
+
+ // IUnknown
+ HRESULT __stdcall QueryInterface(
+ REFIID iid,
+ void ** ppv );
+ ULONG __stdcall AddRef();
+ ULONG __stdcall Release();
+
+ // IPersist
+ HRESULT __stdcall GetClassID(
+ CLSID *pClassID );
+
+ // IPersistStorage
+ HRESULT __stdcall IsDirty();
+ HRESULT __stdcall InitNew(
+ IStorage *pStg );
+ HRESULT __stdcall Load(
+ IStorage *pStg );
+ HRESULT __stdcall Save(
+ IStorage *pStgSave,
+ BOOL fSameAsLoad );
+ HRESULT __stdcall SaveCompleted(
+ IStorage *pStgNew );
+ HRESULT __stdcall HandsOffStorage();
+};
+
+//
+// Goober class.
+//
+class Goober : IGoober
+{
+private:
+ MyObject * pObject;
+
+public:
+ Goober( MyObject * pObj );
+
+ // IUnknown
+ HRESULT __stdcall QueryInterface(
+ REFIID iid,
+ void ** ppv );
+ ULONG __stdcall AddRef();
+ ULONG __stdcall Release();
+
+ // IGoober
+ HRESULT __stdcall Ping();
+};
+
+//
+// MyObject class.
+//
+class MyObject : public IUnknown
+{
+private:
+ ulong Refs;
+ int ActivationType;
+
+ PersistFile PersistFileObj;
+ PersistStorage PersistStorageObj;
+ Goober GooberObj;
+
+public:
+ MyObject( int ActType );
+ ~MyObject();
+
+ // IUnknown
+ HRESULT __stdcall QueryInterface(
+ REFIID iid,
+ void ** ppv );
+ ULONG __stdcall AddRef();
+ ULONG __stdcall Release();
+
+ inline int GetActivationType() { return ActivationType; }
+};
+
+#endif
diff --git a/private/oleutest/act/srvcore/daytona/makefile b/private/oleutest/act/srvcore/daytona/makefile
new file mode 100644
index 000000000..5acbbd24c
--- /dev/null
+++ b/private/oleutest/act/srvcore/daytona/makefile
@@ -0,0 +1 @@
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/oleutest/act/srvcore/daytona/sources b/private/oleutest/act/srvcore/daytona/sources
new file mode 100644
index 000000000..6654da0b3
--- /dev/null
+++ b/private/oleutest/act/srvcore/daytona/sources
@@ -0,0 +1,69 @@
+!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:
+
+ Steve Wood (stevewo) 12-Apr-1989
+
+
+Revision History:
+
+!ENDIF
+
+#
+# The TARGETNAME variable is defined by the developer. It is the name of
+# the target (component) that is being built by this makefile. It
+# should NOT include any path or file extension information.
+#
+
+TARGETNAME=srvcore
+
+#
+# The TARGETPATH and TARGETTYPE varialbes are defined by the developer.
+# The first specifies where the target is to be build. The second specifies
+# the type of target (either PROGRAM, DYNLINK or LIBRARY)
+#
+
+TARGETPATH=obj
+TARGETTYPE=LIBRARY
+
+USE_CRTDLL=1
+
+#
+# The INCLUDES variable specifies any include paths that are specific to
+# this source directory. Separate multiple directory paths with single
+# semicolons. Relative path specifications are okay.
+#
+
+INCLUDES=..;..\..\server
+
+SYNCHRONIZE_BLOCK=1
+
+#
+# The SOURCES variable is defined by the developer. It is a list of all the
+# source files for this component. Each source file should be on a separate
+# line using the line continuation character. This will minimize merge
+# conflicts if two developers adding source files to the same component.
+#
+
+C_DEFINES=-DUNICODE
+
+SOURCES=\
+ ..\factory.cxx \
+ ..\classes.cxx
+
+
+UMTYPE=windows
diff --git a/private/oleutest/act/srvcore/dirs b/private/oleutest/act/srvcore/dirs
new file mode 100644
index 000000000..35b6c7372
--- /dev/null
+++ b/private/oleutest/act/srvcore/dirs
@@ -0,0 +1,27 @@
+!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:
+
+ Steve Wood (stevewo) 17-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\dirs.tpl
+
+!ENDIF
+
+DIRS=
+
+OPTIONAL_DIRS=\
+ daytona \
+
diff --git a/private/oleutest/act/srvcore/factory.cxx b/private/oleutest/act/srvcore/factory.cxx
new file mode 100644
index 000000000..11bd291c1
--- /dev/null
+++ b/private/oleutest/act/srvcore/factory.cxx
@@ -0,0 +1,200 @@
+/*
+ * factory.cxx
+ */
+
+#include "server.hxx"
+#include "factory.hxx"
+#include "classes.hxx"
+
+//
+// MyFactory methods.
+//
+MyFactory::MyFactory()
+{
+ Refs = 0;
+}
+
+MyFactory::~MyFactory()
+{
+}
+
+HRESULT STDMETHODCALLTYPE
+MyFactory::QueryInterface (
+ REFIID iid,
+ void ** ppv )
+{
+ HRESULT hr = E_NOINTERFACE;
+
+ *ppv = 0;
+
+ if ((memcmp(&iid, &IID_IUnknown, sizeof(IID)) == 0) ||
+ (memcmp(&iid, &IID_IClassFactory, sizeof(IID)) == 0))
+ {
+ *ppv = this;
+ AddRef();
+ hr = S_OK;
+ }
+
+ return hr;
+}
+
+ULONG STDMETHODCALLTYPE
+MyFactory::AddRef()
+{
+ Refs++;
+ return Refs;
+}
+
+ULONG STDMETHODCALLTYPE
+MyFactory::Release()
+{
+ unsigned long Count;
+
+ Count = --Refs;
+
+ if ( Count == 0 )
+ {
+ delete this;
+ }
+
+ return Count;
+}
+
+HRESULT STDMETHODCALLTYPE
+MyFactory::CreateInstance(
+ IUnknown * punkOuter,
+ REFIID riid,
+ void ** ppv )
+{
+ // Should never be called.
+ *ppv = 0;
+ return E_FAIL;
+}
+
+HRESULT STDMETHODCALLTYPE
+MyFactory::LockServer(
+ BOOL fLock )
+{
+ return S_OK;
+}
+
+//
+// FactoryLocal methods.
+//
+HRESULT STDMETHODCALLTYPE
+FactoryLocal::CreateInstance(
+ IUnknown * punkOuter,
+ REFIID riid,
+ void ** ppv )
+{
+ HRESULT hr = E_OUTOFMEMORY;
+ MyObject * pObject;
+
+ *ppv = 0;
+
+ pObject = new MyObject( LOCAL );
+
+ if ( ! pObject )
+ return hr;
+
+ //
+ // Increment the object count.
+ // The object count will keep this process alive until all objects are released.
+ //
+
+ ObjectCount++;
+ hr = pObject->QueryInterface(riid, ppv);
+
+ return hr;
+}
+
+//
+// FactoryRemote methods.
+//
+HRESULT STDMETHODCALLTYPE
+FactoryRemote::CreateInstance(
+ IUnknown * punkOuter,
+ REFIID riid,
+ void ** ppv )
+{
+ HRESULT hr = E_OUTOFMEMORY;
+ MyObject * pObject;
+
+ *ppv = 0;
+
+ pObject = new MyObject( REMOTE );
+
+ if ( ! pObject )
+ return hr;
+
+ //
+ // Increment the object count.
+ // The object count will keep this process alive until all objects are released.
+ //
+
+ ObjectCount++;
+ hr = pObject->QueryInterface(riid, ppv);
+
+ return hr;
+}
+
+//
+// FactoryRemote methods.
+//
+HRESULT STDMETHODCALLTYPE
+FactoryAtStorage::CreateInstance(
+ IUnknown * punkOuter,
+ REFIID riid,
+ void ** ppv )
+{
+ HRESULT hr = E_OUTOFMEMORY;
+ MyObject * pObject;
+
+ *ppv = 0;
+
+ pObject = new MyObject( ATBITS );
+
+ if ( ! pObject )
+ return hr;
+
+ //
+ // Increment the object count.
+ // The object count will keep this process alive until all objects are released.
+ //
+
+ ObjectCount++;
+ hr = pObject->QueryInterface(riid, ppv);
+
+ return hr;
+}
+
+//
+// FactoryInproc methods.
+//
+HRESULT STDMETHODCALLTYPE
+FactoryInproc::CreateInstance(
+ IUnknown * punkOuter,
+ REFIID riid,
+ void ** ppv )
+{
+ HRESULT hr = E_OUTOFMEMORY;
+ MyObject * pObject;
+
+ *ppv = 0;
+
+ pObject = new MyObject( INPROC );
+
+ if ( ! pObject )
+ return hr;
+
+ //
+ // Increment the object count.
+ // The object count will keep this process alive until all objects are released.
+ //
+
+ ObjectCount++;
+ hr = pObject->QueryInterface(riid, ppv);
+
+ return hr;
+}
+
diff --git a/private/oleutest/act/srvcore/factory.hxx b/private/oleutest/act/srvcore/factory.hxx
new file mode 100644
index 000000000..c0e27b2eb
--- /dev/null
+++ b/private/oleutest/act/srvcore/factory.hxx
@@ -0,0 +1,101 @@
+/*
+ * factory.hxx
+ */
+
+#ifndef _FACTORY_
+#define _FACTORY_
+
+//
+// MyFactory base class.
+//
+class MyFactory : public IClassFactory
+{
+protected :
+ unsigned long Refs;
+
+public:
+ MyFactory();
+ ~MyFactory();
+
+ // IUnknown
+ virtual
+ HRESULT __stdcall QueryInterface(
+ REFIID iid,
+ void ** ppv );
+ virtual
+ ULONG __stdcall AddRef();
+ virtual
+ ULONG __stdcall Release();
+
+ // IClassFactory
+ virtual
+ HRESULT __stdcall CreateInstance(
+ IUnknown * pUnkOuter,
+ REFIID riid,
+ void ** ppv );
+ virtual
+ HRESULT __stdcall LockServer(
+ BOOL fLock );
+};
+
+//
+// FactoryLocal class.
+//
+class FactoryLocal : public MyFactory
+{
+public:
+ FactoryLocal() {}
+ ~FactoryLocal() {}
+
+ HRESULT __stdcall CreateInstance(
+ IUnknown * pUnkOuter,
+ REFIID riid,
+ void ** ppv );
+};
+
+//
+// FactoryRemote class.
+//
+class FactoryRemote : public MyFactory
+{
+public:
+ FactoryRemote() {}
+ ~FactoryRemote() {}
+
+ HRESULT __stdcall CreateInstance(
+ IUnknown * pUnkOuter,
+ REFIID riid,
+ void ** ppv );
+};
+
+//
+// FactoryAtStorage class.
+//
+class FactoryAtStorage : public MyFactory
+{
+public:
+ FactoryAtStorage() {}
+ ~FactoryAtStorage() {}
+
+ HRESULT __stdcall CreateInstance(
+ IUnknown * pUnkOuter,
+ REFIID riid,
+ void ** ppv );
+};
+
+//
+// FactoryInproc class.
+//
+class FactoryInproc : public MyFactory
+{
+public:
+ FactoryInproc() {}
+ ~FactoryInproc() {}
+
+ HRESULT __stdcall CreateInstance(
+ IUnknown * pUnkOuter,
+ REFIID riid,
+ void ** ppv );
+};
+
+#endif
diff --git a/private/oleutest/act/tstsvc/client.cxx b/private/oleutest/act/tstsvc/client.cxx
new file mode 100644
index 000000000..b21fb4c36
--- /dev/null
+++ b/private/oleutest/act/tstsvc/client.cxx
@@ -0,0 +1,2231 @@
+/*
+ * client.cxx
+ */
+
+#include "client.hxx"
+
+#define MIN_TEST_NUMBER 1
+#define MAX_TEST_NUMBER 27
+
+BOOL UnimplementedTest();
+BOOL UnsupportedTest();
+BOOL GenericCITest(REFCLSID clsid, REFIID iid, WCHAR * szServerName, int n, DWORD ctxt);
+
+BOOL CGCOLocalEXE();
+BOOL CGCOExplicitActivator();
+BOOL CILocalDLL();
+BOOL CILocalEXE();
+BOOL CIExplicitActivator();
+BOOL CI3LocalEXE();
+BOOL CI3ExplicitActivator();
+BOOL CGIFFLocalEXE();
+BOOL CGIFFExplicitActivator();
+BOOL CGIFFRegistryActivator();
+BOOL CGIFFAtStorageActivator();
+BOOL IMBLocalEXE();
+BOOL IMBLocalService();
+BOOL IMBAtStorageActivator();
+BOOL IMBAtStorageService();
+BOOL IMBAtStoragePreCon();
+BOOL IMBAtStorageUser();
+BOOL CIFromStgLocalEXE();
+BOOL CIFromStgActivator();
+BOOL CICustomLocalDLL();
+BOOL CICustomLocalEXE();
+BOOL CILocalPreCon();
+BOOL CIExplicitPreCon();
+BOOL CILocalUser();
+BOOL CIExplicitUser();
+BOOL CILocalPreConACL();
+BOOL CIExplicitPreConACL();
+BOOL CILocalService();
+BOOL CIExplicitService();
+
+BOOL MyStartService(WCHAR * wszServiceName, WCHAR *pwszRegServiceArgs);
+BOOL MyStopService(WCHAR * wszServiceName);
+
+#ifdef NO_DCOM
+LPTESTFUNC rgTest[] =
+ {
+ NULL,
+ CGCOLocalEXE,
+ UnsupportedTest,
+ CILocalDLL,
+ CILocalEXE,
+ UnsupportedTest,
+ UnsupportedTest,
+ UnsupportedTest,
+ UnsupportedTest,
+ UnsupportedTest,
+ UnsupportedTest,
+ UnsupportedTest
+/* New tests
+ UnsupportedTest,
+ UnsupportedTest,
+end new tests */
+ CI3LocalEXE,
+ UnsupportedTest,
+ UnsupportedTest,
+ UnsupportedTest,
+ UnsupportedTest,
+ UnsupportedTest,
+ UnsupportedTest,
+ UnsupportedTest,
+ IMBLocalEXE,
+ UnsupportedTest,
+ UnsupportedTest,
+ UnsupportedTest,
+ UnsupportedTest,
+ UnsupportedTest,
+ UnsupportedTest,
+ UnsupportedTest,
+ NULL
+ };
+#else
+LPTESTFUNC rgTest[] =
+ {
+ NULL,
+ CGCOLocalEXE,
+ CGCOExplicitActivator,
+ CILocalDLL,
+ CILocalEXE,
+ CIExplicitActivator,
+ CILocalPreCon,
+ CIExplicitPreCon,
+ CILocalUser,
+ CIExplicitUser,
+ CILocalService,
+ CIExplicitService,
+/* new tests
+ CILocalPreConACL,
+ CIExplicitPreConACL,
+end new tests */
+ CI3LocalEXE,
+ CI3ExplicitActivator,
+ CICustomLocalDLL,
+ CICustomLocalEXE,
+ CGIFFLocalEXE,
+ CGIFFExplicitActivator,
+ CGIFFRegistryActivator,
+ CGIFFAtStorageActivator,
+ IMBLocalEXE,
+ IMBLocalService,
+ IMBAtStorageActivator,
+ IMBAtStorageService,
+ IMBAtStoragePreCon,
+ IMBAtStorageUser,
+ CIFromStgLocalEXE,
+ CIFromStgActivator,
+ NULL
+ };
+#endif // NO_DCOM
+
+char * TestName[] =
+ {
+ NULL,
+ "CoGetClassObject local EXE",
+ "CoGetClassObject explicit activator",
+ "CoCreateInstance local DLL",
+ "CoCreateInstance local EXE",
+ "CoCreateInstance explicit activator",
+ "CoCreateInstance local pre-configured",
+ "CoCreateInstance explicit pre-configured",
+ "CoCreateInstance local user",
+ "CoCreateInstance explicit user",
+ "CoCreateInstance local service",
+ "CoCreateInstance explicit service",
+/* new tests
+ "CoCreateInstance local pre-configured ACL",
+ "CoCreateInstance explicit pre-configured ACL",
+end new tests */
+ "CoCreateInstance (3 IIDs) local EXE",
+ "CoCreateInstance (3 IIDs) explicit activator",
+ "CoCreateInstance from custom itf. local DLL",
+ "CoCreateInstance from custom itf. local EXE",
+ "CoGetInstanceFromFile local EXE",
+ "CoGetInstanceFromFile explicit activator",
+ "CoGetInstanceFromFile registry activator",
+ "CoGetInstanceFromFile AtStorage activator",
+ "IMoniker::BindToObject local EXE",
+ "IMoniker::BindToObject local service",
+ "IMoniker::BindToObject AtStorage activator",
+ "IMoniker::BindToObject AtStorage service",
+ "IMoniker::BindToObject AtStorage pre-configured",
+ "IMoniker::BindToObject AtStorage user",
+ "CoGetInstanceFromIStorage local EXE",
+ "CoGetInstanceFromIStorage explicit activator",
+ NULL
+ };
+
+char RunTest[] =
+ {
+ -1,
+ // CoGetClassObject
+ YES,
+ YES,
+ // CoCreateInstance
+ YES,
+ YES,
+ YES,
+ YES,
+ YES,
+ YES,
+ YES,
+ YES,
+ YES,
+/* new tests
+ YES,
+ YES,
+end new tests */
+ // CoCreateInstance (3 IIDs)
+ YES,
+ YES,
+ // CoGetInstanceFromFile
+ YES,
+ YES,
+ YES,
+ YES,
+ // IMoniker:Bind
+ YES,
+ YES,
+ YES,
+ YES,
+ YES,
+ YES,
+ YES,
+ YES,
+ YES,
+ YES,
+ -1
+ };
+
+char RunLocalTest[] =
+ {
+ -1,
+ // CoGetClassObject
+ YES,
+ NO,
+ // CreateInstance
+ YES,
+ YES,
+ NO,
+ YES,
+ NO,
+ YES,
+ NO,
+ YES,
+ NO,
+/* new tests
+ YES,
+ NO,
+end new tests */
+ // CreateInstance (3 IIDs)
+ YES,
+ NO,
+ // CreateInstance from custom Itf.
+ YES,
+ YES,
+ // CoGetInstanceFromFile
+ YES,
+ NO,
+ NO,
+ NO,
+ // IMoniker:Bind
+ YES,
+ YES,
+ NO,
+ NO,
+ NO,
+ NO,
+ // CoGetInstanceFromIStorage
+ YES,
+ NO,
+ -1
+ };
+
+WCHAR ServerName[32];
+
+WCHAR RemoteFileName[256];
+WCHAR * LocalFileName = L"c:\\acttest.dat";
+WCHAR * StorageName = L"c:\\acttest.stg";
+
+LARGE_INTEGER liPerfFreq;
+LARGE_INTEGER liStart;
+LARGE_INTEGER liStop;
+LARGE_INTEGER liElapsedTime;
+
+#define RESET_CLOCK liElapsedTime.LowPart = liElapsedTime.HighPart = 0
+#define START_CLOCK QueryPerformanceCounter(&liStart)
+#define STOP_CLOCK QueryPerformanceCounter(&liStop); \
+ liElapsedTime.QuadPart += liStop.QuadPart - liStart.QuadPart
+#define DUMP_CLOCK DisplayElapsedTime()
+#define START_LOOP for (unsigned sl_n = uIterations+1; sl_n--;){
+#define STOP_LOOP if (uIterations == sl_n ) RESET_CLOCK;}
+#define SLEEP_IF_LOOPING if (sl_n && !gfHoldServer) Sleep(1000)
+
+unsigned uIterations = 0;
+
+BOOL gfRegister = TRUE;
+BOOL gfHoldServer = FALSE;
+BOOL gfLocal = FALSE;
+BOOL gfNolocal = FALSE;
+BOOL gfSpecificTest = FALSE;
+
+DWORD dwWaitHint = 0;
+
+void DisplayElapsedTime(void)
+{
+ LONGLONG MicroPerIter;
+
+ liElapsedTime.QuadPart /= uIterations;
+
+ MicroPerIter = liElapsedTime.QuadPart * 1000000;
+ MicroPerIter /= liPerfFreq.QuadPart;
+
+ printf( "Time: %d microseconds per iteration", (DWORD) MicroPerIter );
+}
+
+BOOL AllLocal()
+{
+ for (int x = MIN_TEST_NUMBER; x<= MAX_TEST_NUMBER; x++)
+ {
+ if (RunTest[x] && !RunLocalTest[x])
+ return(FALSE);
+ }
+ return(TRUE);
+}
+
+extern WCHAR ServiceName[];
+
+void _cdecl main( int argc, char ** argv )
+{
+ HRESULT HResult;
+ HANDLE hFile;
+ int n;
+ BOOL f;
+
+ if (argc > 1)
+ {
+ if (argc == 3 && (!strcmp(argv[1], "-t")))
+ {
+ dwWaitHint = atoi(argv[2]);
+ }
+ else
+ {
+ printf("usage: %s [-t #]\n # number of milliseconds between QueryServiceStatus calls\n", argv[0]);
+ return;
+ }
+ }
+ if ((!QueryPerformanceFrequency(&liPerfFreq)) && uIterations > 0)
+ {
+ printf("No high performance counter.\nTests cannot be timed.\nAborting.\n");
+ return;
+ }
+
+ uIterations = 1;
+
+ printf("Starting service...\n");
+ RESET_CLOCK;
+ START_CLOCK;
+ f = MyStartService(L"ActTestService", L"");
+ STOP_CLOCK;
+ if (f)
+ printf("succeeded - ");
+ else
+ printf("failed - ");
+ DUMP_CLOCK;
+ printf("\n");
+
+ printf("Stopping service...\n");
+ RESET_CLOCK;
+ START_CLOCK;
+ f = MyStopService(L"ActTestService");
+ STOP_CLOCK;
+ if (f)
+ printf("succeeded - ");
+ else
+ printf("failed - ");
+ DUMP_CLOCK;
+ printf("\n");
+
+ return;
+#ifndef NO_DCOM
+ if ( argc == 1 )
+ PrintUsageAndExit( FALSE );
+#endif // NO_DCOM
+
+ if ( argc > 1 && strcmp(argv[1],"-?") == 0 )
+ PrintUsageAndExit( TRUE );
+
+ n = 1;
+
+ while ( (n < argc) && (*argv[n] == '-') )
+ {
+ if ( (n < argc) && strcmp(argv[n],"-local") == 0 )
+ {
+ if (gfLocal | gfNolocal)
+ {
+ PrintUsageAndExit( FALSE );
+ }
+ gfLocal = TRUE;
+ memcpy(RunTest, RunLocalTest, MAX_TEST_NUMBER + MIN_TEST_NUMBER);
+ n++;
+ }
+
+ if ( (n < argc) && strcmp(argv[n],"-nolocal") == 0 )
+ {
+ if (gfLocal | gfNolocal)
+ {
+ PrintUsageAndExit( FALSE );
+ }
+ gfNolocal = TRUE;
+ for (int x = MIN_TEST_NUMBER; x<= MAX_TEST_NUMBER; x++)
+ {
+ RunTest[x] = !RunLocalTest[x];
+ }
+ n++;
+ }
+
+ if ( (n < argc) && strcmp(argv[n],"-noreg") == 0 )
+ {
+ gfRegister = FALSE;
+ n++;
+ continue;
+ }
+
+ if ( (n < argc) && strcmp(argv[n],"-hold") == 0 )
+ {
+ gfHoldServer = TRUE;
+ n++;
+ continue;
+ }
+
+ if ( (n < argc) && strcmp(argv[n],"-n") == 0 )
+ {
+ if ( ++n >= argc )
+ PrintUsageAndExit(FALSE);
+
+ uIterations = atoi(argv[n++]);
+ }
+
+ if ( (n < argc) && strcmp(argv[n],"-t") == 0 )
+ {
+ long TestNum1, TestNum2;
+
+ if ( ++n >= argc )
+ PrintUsageAndExit(FALSE);
+
+ TestNum1 = atoi(argv[n++]);
+
+ if ( (n < argc) && ((TestNum2 = atoi(argv[n])) != 0) )
+ n++;
+ else
+ TestNum2 = TestNum1;
+
+ if ( (TestNum1 < MIN_TEST_NUMBER) || (TestNum2 > MAX_TEST_NUMBER) )
+ {
+ printf( "Test number(s) must be between %d and %d.\n",
+ MIN_TEST_NUMBER,
+ MAX_TEST_NUMBER );
+ return;
+ }
+
+ if ( TestNum1 > TestNum2 )
+ {
+ printf( "Second test number must be greater than the first.\n" );
+ return;
+ }
+
+ if (!gfSpecificTest)
+ {
+ gfSpecificTest = TRUE;
+ // only do this the first time -t is found on the command line
+ memset(RunTest,NO,sizeof(RunTest));
+ }
+ memset(&RunTest[TestNum1],YES,sizeof(char)*(TestNum2-TestNum1+1));
+ }
+ }
+
+#ifndef NO_DCOM
+ if ( n != argc - 1 && !AllLocal())
+ {
+ printf("ERROR - Selected tests require a server name.\n");
+ ExitThread(0);
+ }
+
+ if ( n < argc )
+ {
+ MultiByteToWideChar( CP_ACP,
+ 0,
+ argv[n],
+ -1,
+ ServerName,
+ sizeof(ServerName) / sizeof(WCHAR) );
+ }
+ else
+ ServerName[0] = 0;
+#endif // NO_DCOM
+
+ hFile = CreateFile(
+ LocalFileName,
+ GENERIC_WRITE,
+ FILE_SHARE_READ,
+ 0,
+ OPEN_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ 0 );
+
+ if ( hFile == INVALID_HANDLE_VALUE )
+ {
+ printf("CreateFile failed while creating local file: %d\n", GetLastError());
+ return;
+ }
+
+ CloseHandle( hFile );
+
+#ifndef NO_DCOM
+ if ( ServerName[0] != 0 )
+ {
+ RemoteFileName[0] = 0;
+
+ if ( ServerName[0] != L'\\' )
+ wcscat( RemoteFileName, L"\\\\" );
+
+ wcscat( RemoteFileName, ServerName );
+ wcscat( RemoteFileName, L"\\c$\\acttest.dat" );
+
+ hFile = CreateFile(
+ RemoteFileName,
+ GENERIC_WRITE,
+ FILE_SHARE_READ,
+ 0,
+ OPEN_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ 0 );
+
+ if ( hFile == INVALID_HANDLE_VALUE )
+ {
+ printf("CreateFile failed while creating remote file: %d\n", GetLastError());
+ return;
+ }
+
+ CloseHandle( hFile );
+ }
+#endif // NO_DCOM
+
+ HResult = CoInitialize(NULL);
+
+ if( FAILED(HResult) )
+ {
+ printf( "Client CoInitialize failed Ox%x!\n", HResult );
+ return;
+ }
+
+ if ((!QueryPerformanceFrequency(&liPerfFreq)) && uIterations > 0)
+ {
+ printf("No high performance counter.\nTests cannot be timed.\nAborting.\n");
+ }
+ else
+ {
+ if ( ! Tests() )
+ printf("\nTests FAILED\n");
+ else
+ printf("\nTests SUCCEEDED\n");
+ }
+
+ CoUninitialize();
+
+ DeleteFile( LocalFileName );
+#ifndef NO_DCOM
+ DeleteFile( RemoteFileName );
+#endif // NO_DCOM
+}
+
+BOOL Tests()
+{
+ HRESULT HResult;
+ long RegStatus;
+
+ if (gfRegister)
+ {
+ DeleteClsidKey( ClsidGoober32String );
+ DeleteClsidKey( ClsidActLocalString );
+ DeleteClsidKey( ClsidActRemoteString );
+ DeleteClsidKey( ClsidActAtStorageString );
+ DeleteClsidKey( ClsidActInprocString );
+ DeleteClsidKey( ClsidActPreConfigString );
+ DeleteClsidKey( ClsidActRunAsLoggedOnString );
+ DeleteClsidKey( ClsidActServiceString );
+ DeleteClsidKey( ClsidActServerOnlyString );
+
+ if ( (RegStatus = InitializeRegistryForInproc()) != ERROR_SUCCESS )
+ {
+ printf("InitializeRegistryForInproc failed %d.\n", RegStatus);
+ return FALSE;
+ }
+
+ if ( (RegStatus = InitializeRegistryForLocal()) != ERROR_SUCCESS )
+ {
+ printf("InitializeRegistryForLocal failed %d.\n", RegStatus);
+ return FALSE;
+ }
+
+ if ( (RegStatus = InitializeRegistryForCustom()) != ERROR_SUCCESS )
+ {
+ printf("InitializeRegistryForCustom failed %d.\n", RegStatus);
+ return FALSE;
+ }
+ #ifndef NO_DCOM
+ if ( (RegStatus = InitializeRegistryForRemote()) != ERROR_SUCCESS )
+ {
+ printf("InitializeRegistryForRemote failed %d.\n", RegStatus);
+ return FALSE;
+ }
+
+ if ( (RegStatus = InitializeRegistryForService()) != ERROR_SUCCESS )
+ {
+ printf("InitializeRegistryForService failed %d.\n", RegStatus);
+ return FALSE;
+ }
+ #endif // NO_DCOM
+ }
+ BOOL fAllTests = TRUE;
+
+ for (int x = MIN_TEST_NUMBER; x <= MAX_TEST_NUMBER; x++)
+ {
+ if (RunTest[x])
+ {
+ printf("\nTest %2d: %s\n",x, TestName[x]);
+ // prime the system once to ensure the test is fully cached
+ if (rgTest[x]())
+ {
+ printf("PASSED");
+ if (uIterations)
+ {
+ printf(" - ");
+ DUMP_CLOCK;
+ }
+ printf("\n");
+ }
+ else
+ {
+ printf("FAILED\n");
+ fAllTests = FALSE;
+ }
+
+ }
+ }
+
+ return(fAllTests);
+}
+
+void PrintUsageAndExit( BOOL bListTests )
+{
+#ifdef NO_DCOM
+ printf("Usage : %s [-hold] [-noreg] [-n #] [-t # [#]]\n", "actclt");
+ printf("\t-n # : Run specific number of timed iterations (default is 0).\n");
+ printf("\t-noreg : Don't update registry\n");
+ printf("\t-t # : Run specific test number or a range of tests.\n");
+ printf("\t-? : Print usage plus test descriptions.\n");
+#else
+ printf("Usage : %s [-hold] [-noreg] [[-local] | [-nolocal]] [-n #] [-t # [#]] [server_name]\n", "actclt");
+ printf("\t-hold : Hold the server up during all iterations.\n");
+ printf("\t-local : Run only local activation tests.\n");
+ printf("\t-n # : Run specific number of timed iterations (default is 0).\n");
+ printf("\t-nolocal : Run only remote activation tests.\n");
+ printf("\t-noreg : Don't update registry\n");
+ printf("\t-t # : Run specific test number or a range of tests.\n");
+ printf("\t-? : Print usage plus test descriptions.\n");
+#endif // NO_DCOM
+
+ if ( bListTests )
+ {
+ long n;
+
+ printf("\nTests :\n");
+ printf("\t # Method Location Security\n");
+ printf("\t-- ----------------------------------- ----------- --------------\n");
+
+ for ( n = MIN_TEST_NUMBER; n <= MAX_TEST_NUMBER; n++ )
+ {
+ printf("\t%2d %s\n", n, TestName[n]);
+ }
+ }
+
+ ExitThread(0);
+}
+
+void * __RPC_API
+MIDL_user_allocate(size_t len)
+{
+ return malloc(len);
+}
+
+void __RPC_API
+MIDL_user_free(void * vp)
+{
+ free(vp);
+}
+
+BOOL StampFileWithCLSID(WCHAR * szFilename, CLSID & clsid)
+{
+ HRESULT hr;
+ IStorage * pStg;
+
+ hr = StgCreateDocfile(
+ szFilename,
+ STGM_READWRITE | STGM_DIRECT | STGM_SHARE_EXCLUSIVE | STGM_CREATE,
+ 0,
+ &pStg);
+
+ if (FAILED (hr))
+ {
+ printf("StgCreateDocfile returned 0x%x\n", hr);
+ return(FALSE);
+ }
+
+ hr = WriteClassStg(pStg, clsid);
+
+ pStg->Release();
+
+ if (FAILED (hr))
+ {
+ printf("WriteClassStg returned 0x%x\n", hr);
+ return(FALSE);
+ }
+
+ return(TRUE);
+}
+
+//
+// Test Procedures:
+//
+
+BOOL UnimplementedTest()
+{
+ printf("Not implemented at this time.\n");
+ return(TRUE);
+}
+
+BOOL UnsupportedTest()
+{
+ printf("Not supported by this version.\n");
+ return(TRUE);
+}
+
+BOOL GenericCITest(REFCLSID clsid, REFIID iid, WCHAR * szServerName, int n, DWORD ctxt)
+{
+ COSERVERINFO ServerInfo;
+ COSERVERINFO *pServerInfo;
+ IUnknown * punkHeld = NULL;
+
+ if (szServerName)
+ {
+ memset( &ServerInfo, 0, sizeof(COSERVERINFO) );
+ ServerInfo.pwszName = szServerName;
+ pServerInfo = &ServerInfo;
+ }
+ else
+ {
+ pServerInfo = NULL;
+ }
+
+ MULTI_QI QIStruct[10];
+ int x;
+ HRESULT hr;
+ BOOL fReturn = TRUE;
+
+ START_LOOP;
+
+ for (x = n; x--;)
+ {
+ QIStruct[x].pItf = NULL;
+ QIStruct[x].pIID = (IID *) &iid;
+ }
+
+
+ START_CLOCK;
+ hr = CoCreateInstanceEx(
+ clsid,
+ NULL,
+ ctxt,
+ pServerInfo,
+ n,
+ QIStruct);
+ STOP_CLOCK;
+
+ if ( FAILED(hr) )
+ {
+ printf("CoCreateInstanceEx returned 0x%x\n", hr);
+ if (punkHeld)
+ punkHeld->Release();
+ return FALSE;
+ }
+
+ if (gfHoldServer && NULL == punkHeld && SUCCEEDED(QIStruct[0].hr))
+ {
+ punkHeld = QIStruct[0].pItf;
+ punkHeld->AddRef();
+ }
+
+ for (x = 0; x < n; x++)
+ {
+ if (FAILED(QIStruct[x].hr))
+ {
+ printf("CoCreateInstanceEx returned 0x%x for interface %d\n",
+ QIStruct[x].hr, x);
+ fReturn = FALSE;
+ }
+ else
+ QIStruct[x].pItf->Release();
+ }
+ if (!fReturn)
+ {
+ if (punkHeld)
+ punkHeld->Release();
+ return(fReturn);
+ }
+
+ STOP_LOOP;
+
+ if (punkHeld)
+ punkHeld->Release();
+
+ return fReturn;
+}
+
+BOOL CGCOLocalEXE()
+{
+ IClassFactory * pClassFactory;
+ IUnknown * pUnknown;
+ IUnknown * punkHeld = NULL;
+ HRESULT hr;
+
+ START_LOOP;
+
+ START_CLOCK;
+ hr = CoGetClassObject(
+ CLSID_ActLocal,
+ CLSCTX_LOCAL_SERVER,
+ NULL,
+ IID_IClassFactory,
+ (void **) &pClassFactory );
+ STOP_CLOCK;
+
+ if ( FAILED(hr) )
+ {
+ printf("CoGetClassObject returned 0x%x\n", hr);
+ if (punkHeld)
+ punkHeld->Release();
+ return FALSE;
+ }
+
+ hr = pClassFactory->CreateInstance( NULL,
+ IID_IUnknown,
+ (void **) &pUnknown );
+
+ pClassFactory->Release();
+
+ if ( FAILED(hr) )
+ {
+ printf("CreateInstance returned 0x%x\n", hr);
+ if (punkHeld)
+ punkHeld->Release();
+ return FALSE;
+ }
+
+ if (gfHoldServer && NULL == punkHeld)
+ {
+ punkHeld = pUnknown;
+ punkHeld->AddRef();
+ }
+
+ pUnknown->Release();
+
+ STOP_LOOP;
+
+ if (punkHeld)
+ punkHeld->Release();
+
+ return TRUE;
+}
+
+#ifndef NO_DCOM
+BOOL CGCOExplicitActivator()
+{
+ COSERVERINFO ServerInfo;
+
+ memset( &ServerInfo, 0, sizeof(COSERVERINFO) );
+ ServerInfo.pwszName = ServerName;
+
+ IClassFactory * pClassFactory;
+ IUnknown * pUnknown;
+ IUnknown * punkHeld = NULL;
+ HRESULT hr;
+
+ START_LOOP;
+
+ START_CLOCK;
+ hr = CoGetClassObject(
+ CLSID_ActLocal,
+ CLSCTX_REMOTE_SERVER,
+ &ServerInfo,
+ IID_IClassFactory,
+ (void **) &pClassFactory );
+ STOP_CLOCK;
+
+ if ( FAILED(hr) )
+ {
+ printf("CoGetClassObject returned 0x%x\n", hr);
+ if (punkHeld)
+ punkHeld->Release();
+ return FALSE;
+ }
+
+ hr = pClassFactory->CreateInstance( NULL,
+ IID_IUnknown,
+ (void **) &pUnknown );
+
+ pClassFactory->Release();
+
+ if ( FAILED(hr) )
+ {
+ printf("CreateInstance returned 0x%x\n", hr);
+ if (punkHeld)
+ punkHeld->Release();
+ return FALSE;
+ }
+
+ if (gfHoldServer && NULL == punkHeld)
+ {
+ punkHeld = pUnknown;
+ punkHeld->AddRef();
+ }
+
+ pUnknown->Release();
+
+ STOP_LOOP;
+
+ if (punkHeld)
+ punkHeld->Release();
+ return TRUE;
+}
+#endif // NO_DCOM
+
+#ifdef NO_DCOM
+BOOL CILocalDLL()
+{
+ IUnknown * pUnknown;
+ IUnknown * punkHeld = NULL;
+ HRESULT hr;
+
+ START_LOOP;
+
+ START_CLOCK;
+ hr = CoCreateInstance(
+ CLSID_ActInproc,
+ NULL,
+ CLSCTX_INPROC_SERVER,
+ IID_IUnknown,
+ (void **) &pUnknown );
+ STOP_CLOCK;
+
+ if ( FAILED(hr) )
+ {
+ printf("CoCreateInstance returned 0x%x\n", hr);
+ if (punkHeld)
+ punkHeld->Release();
+ return FALSE;
+ }
+
+ if (gfHoldServer && NULL == punkHeld)
+ {
+ punkHeld = pUnknown;
+ punkHeld->AddRef();
+ }
+
+ pUnknown->Release();
+
+ STOP_LOOP;
+
+ if (punkHeld)
+ punkHeld->Release();
+ return TRUE;
+}
+
+BOOL CILocalEXE()
+{
+ IUnknown * pUnknown;
+ IUnknown * punkHeld = NULL;
+ HRESULT hr;
+
+ START_LOOP;
+
+ START_CLOCK;
+ hr = CoCreateInstance(
+ CLSID_ActLocal,
+ NULL,
+ CLSCTX_LOCAL_SERVER,
+ IID_IUnknown,
+ (void **) &pUnknown );
+ STOP_CLOCK;
+
+ if ( FAILED(hr) )
+ {
+ printf("CoCreateInstance returned 0x%x\n", hr);
+ if (punkHeld)
+ punkHeld->Release();
+ return FALSE;
+ }
+
+ if (gfHoldServer && NULL == punkHeld)
+ {
+ punkHeld = pUnknown;
+ punkHeld->AddRef();
+ }
+
+ pUnknown->Release();
+
+ STOP_LOOP;
+
+ if (punkHeld)
+ punkHeld->Release();
+
+ return TRUE;
+}
+#else
+BOOL CILocalDLL()
+{
+ return GenericCITest(CLSID_ActInproc, IID_IUnknown, NULL, 1, CLSCTX_INPROC_SERVER);
+}
+
+BOOL CILocalEXE()
+{
+ return GenericCITest(CLSID_ActLocal, IID_IUnknown, NULL, 1, CLSCTX_LOCAL_SERVER);
+}
+
+BOOL CIExplicitActivator()
+{
+ return GenericCITest(CLSID_ActLocal, IID_IUnknown, ServerName, 1, CLSCTX_REMOTE_SERVER);
+}
+#endif // NO_DCOM
+
+#ifdef NO_DCOM
+// Pre-DCOM version of CI3LocalEXE which calls CoCreateInstance
+// once followed by 2 calls to QueryInterface
+// instead of calling CoCreateInstanceEx.
+BOOL CI3LocalEXE()
+{
+ IUnknown * pUnknown;
+ IUnknwon * punkHeld = NULL;
+ IPersist * pPersist;
+ IPersistFile * pPersistFile;
+
+ HRESULT hr;
+
+ START_LOOP;
+
+ START_CLOCK;
+ hr = CoCreateInstance(
+ CLSID_ActLocal,
+ NULL,
+ CLSCTX_LOCAL_SERVER,
+ IID_IUnknown,
+ (void **) &pUnknown );
+
+ if ( FAILED(hr) )
+ {
+ printf("CoCreateInstance returned 0x%x\n", hr);
+ if (punkHeld)
+ punkHeld->Release();
+ return FALSE;
+ }
+
+ if (gfHoldServer && NULL == punkHeld)
+ {
+ punkHeld = pUnknown;
+ punkHeld->AddRef();
+ }
+
+ pUnknown->QueryInterface( IID_IPersist, (void **)&pPersist );
+ pUnknown->QueryInterface( IID_IPersist, (void **)&pPersistFile );
+ STOP_CLOCK;
+
+ pUnknown->Release();
+ pPersist->Release();
+ pPersistFile->Release();
+
+ STOP_LOOP;
+
+ if (punkHeld)
+ punkHeld->Release();
+
+ return TRUE;
+}
+#else // NO_DCOM
+
+BOOL CI3LocalEXE()
+{
+ return GenericCITest(CLSID_ActLocal, IID_IPersist, NULL, 3, CLSCTX_LOCAL_SERVER);
+ /*
+ MULTI_QI QIStruct[3];
+ QIStruct[0].pIID = (IID *)&IID_IUnknown;
+ QIStruct[1].pIID = (IID *)&IID_IPersist;
+ QIStruct[2].pIID = (IID *)&IID_IPersistFile;
+ QIStruct[0].pItf = NULL;
+ QIStruct[1].pItf = NULL;
+ QIStruct[2].pItf = NULL;
+ */
+}
+
+BOOL CI3ExplicitActivator()
+{
+ return GenericCITest(CLSID_ActLocal, IID_IPersist, ServerName, 3, CLSCTX_REMOTE_SERVER);
+ /*
+ MULTI_QI QIStruct[3];
+ QIStruct[0].pIID = (IID *)&IID_IUnknown;
+ QIStruct[1].pIID = (IID *)&IID_IPersist;
+ QIStruct[2].pIID = (IID *)&IID_IPersistFile;
+ QIStruct[0].pItf = NULL;
+ QIStruct[1].pItf = NULL;
+ QIStruct[2].pItf = NULL;
+ */
+}
+
+BOOL CGIFFLocalEXE()
+{
+ MULTI_QI QIStruct[1];
+ IUnknown * punkHeld = NULL;
+
+ START_LOOP;
+
+ QIStruct[0].pIID = (IID *)&IID_IUnknown;
+ QIStruct[0].pItf = NULL;
+
+ START_CLOCK;
+ HRESULT HResult = CoGetInstanceFromFile(
+ NULL,
+ &CLSID_ActLocal,
+ NULL,
+ CLSCTX_LOCAL_SERVER,
+ STGM_READWRITE,
+ LocalFileName,
+ 1,
+ QIStruct );
+ STOP_CLOCK;
+
+ if ( FAILED(HResult) )
+ {
+ printf("CoGetInstanceFromFile returned 0x%x\n", HResult);
+ if (punkHeld)
+ punkHeld->Release();
+ return FALSE;
+ }
+
+ if (gfHoldServer && NULL == punkHeld)
+ {
+ punkHeld = QIStruct[0].pItf;
+ punkHeld->AddRef();
+ }
+
+ QIStruct[0].pItf->Release();
+
+ STOP_LOOP;
+
+ if (punkHeld)
+ punkHeld->Release();
+ return(TRUE);
+}
+
+BOOL CGIFFExplicitActivator()
+{
+ COSERVERINFO ServerInfo;
+ IUnknown * punkHeld = NULL;
+
+ memset( &ServerInfo, 0, sizeof(COSERVERINFO) );
+ ServerInfo.pwszName = ServerName;
+
+ MULTI_QI QIStruct[1];
+
+ START_LOOP;
+
+ QIStruct[0].pIID = (IID *)&IID_IUnknown;
+ QIStruct[0].pItf = NULL;
+
+ START_CLOCK;
+ HRESULT HResult = CoGetInstanceFromFile(
+ &ServerInfo,
+ &CLSID_ActLocal,
+ NULL,
+ CLSCTX_REMOTE_SERVER,
+ STGM_READWRITE,
+ RemoteFileName,
+ 1,
+ QIStruct );
+ STOP_CLOCK;
+
+ if ( FAILED(HResult) )
+ {
+ printf("CoGetInstanceFromFile returned 0x%x\n", HResult);
+ if (punkHeld)
+ punkHeld->Release();
+ return FALSE;
+ }
+
+ if (gfHoldServer && NULL == punkHeld)
+ {
+ punkHeld = QIStruct[0].pItf;
+ punkHeld->AddRef();
+ }
+
+ QIStruct[0].pItf->Release();
+
+ STOP_LOOP;
+
+ if (punkHeld)
+ punkHeld->Release();
+ return(TRUE);
+}
+
+BOOL CGIFFRegistryActivator()
+{
+ MULTI_QI QIStruct[1];
+ IUnknown * punkHeld = NULL;
+
+ START_LOOP;
+
+ QIStruct[0].pIID = (IID *)&IID_IUnknown;
+ QIStruct[0].pItf = NULL;
+ START_CLOCK;
+ HRESULT HResult = CoGetInstanceFromFile(
+ NULL,
+ &CLSID_ActRemote,
+ NULL,
+ CLSCTX_REMOTE_SERVER,
+ STGM_READWRITE,
+ RemoteFileName,
+ 1,
+ QIStruct );
+ STOP_CLOCK;
+
+ if ( FAILED(HResult) )
+ {
+ printf("CoGetInstanceFromFile returned 0x%x\n", HResult);
+ if (punkHeld)
+ punkHeld->Release();
+ return FALSE;
+ }
+
+ if (gfHoldServer && NULL == punkHeld)
+ {
+ punkHeld = QIStruct[0].pItf;
+ punkHeld->AddRef();
+ }
+
+ QIStruct[0].pItf->Release();
+
+ STOP_LOOP;
+
+ if (punkHeld)
+ punkHeld->Release();
+ return(TRUE);
+}
+
+BOOL CGIFFAtStorageActivator()
+{
+ MULTI_QI QIStruct[1];
+ IUnknown * punkHeld = NULL;
+
+ START_LOOP;
+
+ QIStruct[0].pIID = (IID *)&IID_IUnknown;
+ QIStruct[0].pItf = NULL;
+ START_CLOCK;
+ HRESULT HResult = CoGetInstanceFromFile(
+ NULL,
+ &CLSID_ActAtStorage,
+ NULL,
+ CLSCTX_REMOTE_SERVER,
+ STGM_READWRITE,
+ RemoteFileName,
+ 1,
+ QIStruct );
+ STOP_CLOCK;
+
+ if ( FAILED(HResult) )
+ {
+ printf("CoGetInstanceFromFile returned 0x%x\n", HResult);
+ if (punkHeld)
+ punkHeld->Release();
+ return FALSE;
+ }
+
+ if (gfHoldServer && NULL == punkHeld)
+ {
+ punkHeld = QIStruct[0].pItf;
+ punkHeld->AddRef();
+ }
+
+ QIStruct[0].pItf->Release();
+
+ STOP_LOOP;
+
+ if (punkHeld)
+ punkHeld->Release();
+ return(TRUE);
+}
+#endif // NO_DCOM
+
+BOOL IMBLocalEXE()
+{
+ IBindCtx * pBc;
+ IUnknown * pUnk;
+ IUnknown * punkHeld = NULL;
+ HRESULT hr;
+ IMoniker *pMon;
+
+ if (!StampFileWithCLSID(LocalFileName, CLSID_ActLocal))
+ {
+ return(FALSE);
+ }
+
+ hr = CreateFileMoniker(LocalFileName, &pMon);
+
+ if (FAILED(hr))
+ {
+ printf("CreateFileMoniker returned 0x%x\n", hr);
+ }
+
+ hr = CreateBindCtx(0, &pBc);
+
+ if (FAILED(hr))
+ {
+ printf("CreateBindCtx returned 0x%x\n", hr);
+ pMon->Release();
+ return(FALSE);
+ }
+
+ START_LOOP;
+
+ START_CLOCK;
+ hr = pMon->BindToObject(
+ pBc,
+ NULL,
+ IID_IUnknown,
+ (void **) &pUnk);
+ STOP_CLOCK;
+
+ if (FAILED(hr))
+ {
+ printf("IMoniker::BindToObject returned 0x%x\n", hr);
+ if (punkHeld)
+ punkHeld->Release();
+ return(FALSE);
+ }
+
+ if (gfHoldServer && NULL == punkHeld)
+ {
+ punkHeld = pUnk;
+ punkHeld->AddRef();
+ }
+
+ pUnk->Release();
+
+ STOP_LOOP
+
+ pMon->Release();
+ pBc->Release();
+
+ if (punkHeld)
+ punkHeld->Release();
+ return(TRUE);
+}
+
+#ifndef NO_DCOM
+BOOL IMBLocalService()
+{
+ IBindCtx * pBc;
+ IUnknown * pUnk;
+ IUnknown * punkHeld = NULL;
+ HRESULT hr;
+ IMoniker *pMon;
+
+ if (!StampFileWithCLSID(LocalFileName, CLSID_ActService))
+ {
+ return(FALSE);
+ }
+
+ hr = CreateFileMoniker(LocalFileName, &pMon);
+
+ if (FAILED(hr))
+ {
+ printf("CreateFileMoniker returned 0x%x\n", hr);
+ }
+
+ hr = CreateBindCtx(0, &pBc);
+
+ if (FAILED(hr))
+ {
+ printf("CreateBindCtx returned 0x%x\n", hr);
+ pMon->Release();
+ return(FALSE);
+ }
+
+ START_LOOP;
+
+ START_CLOCK;
+ hr = pMon->BindToObject(
+ pBc,
+ NULL,
+ IID_IUnknown,
+ (void **) &pUnk);
+ STOP_CLOCK;
+ if (FAILED(hr))
+ {
+ printf("IMoniker::BindToObject returned 0x%x\n", hr);
+ if (punkHeld)
+ punkHeld->Release();
+ return(FALSE);
+ }
+
+ if (gfHoldServer && NULL == punkHeld)
+ {
+ punkHeld = pUnk;
+ punkHeld->AddRef();
+ }
+ pUnk->Release();
+
+ SLEEP_IF_LOOPING;
+
+ STOP_LOOP;
+
+ pMon->Release();
+ pBc->Release();
+
+ if (punkHeld)
+ punkHeld->Release();
+ return(TRUE);
+}
+
+BOOL IMBAtStorageActivator()
+{
+ IBindCtx * pBc;
+ IUnknown * pUnk;
+ IUnknown * punkHeld = NULL;
+ HRESULT hr;
+ IMoniker *pMon;
+
+ if (!StampFileWithCLSID(RemoteFileName, CLSID_ActAtStorage))
+ {
+ return(FALSE);
+ }
+
+ hr = CreateFileMoniker(RemoteFileName, &pMon);
+
+ if (FAILED(hr))
+ {
+ printf("CreateFileMoniker returned 0x%x\n", hr);
+ }
+
+ hr = CreateBindCtx(0, &pBc);
+
+ if (FAILED(hr))
+ {
+ printf("CreateBindCtx returned 0x%x\n", hr);
+ pMon->Release();
+ return(FALSE);
+ }
+
+ START_LOOP;
+
+ START_CLOCK;
+ hr = pMon->BindToObject(
+ pBc,
+ NULL,
+ IID_IUnknown,
+ (void **) &pUnk);
+ STOP_CLOCK;
+
+ if (FAILED(hr))
+ {
+ printf("IMoniker::BindToObject returned 0x%x\n", hr);
+ if (punkHeld)
+ punkHeld->Release();
+ return(FALSE);
+ }
+
+ if (gfHoldServer && NULL == punkHeld)
+ {
+ punkHeld = pUnk;
+ punkHeld->AddRef();
+ }
+
+ pUnk->Release();
+
+ STOP_LOOP;
+
+ pMon->Release();
+ pBc->Release();
+
+ if (punkHeld)
+ punkHeld->Release();
+ return(TRUE);
+}
+
+BOOL IMBAtStorageService()
+{
+ IBindCtx * pBc;
+ IUnknown * pUnk;
+ IUnknown * punkHeld = NULL;
+ HRESULT hr;
+ IMoniker *pMon;
+
+ if (!StampFileWithCLSID(RemoteFileName, CLSID_ActService))
+ {
+ return(FALSE);
+ }
+
+ hr = CreateFileMoniker(RemoteFileName, &pMon);
+
+ if (FAILED(hr))
+ {
+ printf("CreateFileMoniker returned 0x%x\n", hr);
+ }
+
+ hr = CreateBindCtx(0, &pBc);
+
+ if (FAILED(hr))
+ {
+ printf("CreateBindCtx returned 0x%x\n", hr);
+ pMon->Release();
+ return(FALSE);
+ }
+
+ START_LOOP;
+
+ START_CLOCK;
+ hr = pMon->BindToObject(
+ pBc,
+ NULL,
+ IID_IUnknown,
+ (void **) &pUnk);
+ STOP_CLOCK;
+
+ if (FAILED(hr))
+ {
+ printf("IMoniker::BindToObject returned 0x%x\n", hr);
+ if (punkHeld)
+ punkHeld->Release();
+ return(FALSE);
+ }
+
+ if (gfHoldServer && NULL == punkHeld)
+ {
+ punkHeld = pUnk;
+ punkHeld->AddRef();
+ }
+
+ pUnk->Release();
+
+ SLEEP_IF_LOOPING;
+
+ STOP_LOOP;
+
+ pMon->Release();
+ pBc->Release();
+
+ if (punkHeld)
+ punkHeld->Release();
+ return(TRUE);
+}
+
+BOOL IMBAtStoragePreCon()
+{
+ IBindCtx * pBc;
+ IUnknown * pUnk;
+ IUnknown * punkHeld = NULL;
+ HRESULT hr;
+ IMoniker *pMon;
+
+ if (!StampFileWithCLSID(RemoteFileName, CLSID_ActPreConfig))
+ {
+ return(FALSE);
+ }
+
+ hr = CreateFileMoniker(RemoteFileName, &pMon);
+
+ if (FAILED(hr))
+ {
+ printf("CreateFileMoniker returned 0x%x\n", hr);
+ }
+
+ hr = CreateBindCtx(0, &pBc);
+
+ if (FAILED(hr))
+ {
+ printf("CreateBindCtx returned 0x%x\n", hr);
+ pMon->Release();
+ return(FALSE);
+ }
+
+ START_LOOP;
+
+ START_CLOCK;
+ hr = pMon->BindToObject(
+ pBc,
+ NULL,
+ IID_IUnknown,
+ (void **) &pUnk);
+ STOP_CLOCK;
+
+ if (FAILED(hr))
+ {
+ printf("IMoniker::BindToObject returned 0x%x\n", hr);
+ if (punkHeld)
+ punkHeld->Release();
+ return(FALSE);
+ }
+
+ if (gfHoldServer && NULL == punkHeld)
+ {
+ punkHeld = pUnk;
+ punkHeld->AddRef();
+ }
+
+ pUnk->Release();
+
+ STOP_LOOP;
+
+ pMon->Release();
+ pBc->Release();
+
+ if (punkHeld)
+ punkHeld->Release();
+ return(TRUE);
+}
+
+BOOL IMBAtStorageUser()
+{
+ IBindCtx * pBc;
+ IUnknown * pUnk;
+ IUnknown * punkHeld = NULL;
+ HRESULT hr;
+ IMoniker *pMon;
+
+ if (!StampFileWithCLSID(RemoteFileName, CLSID_ActRunAsLoggedOn))
+ {
+ return(FALSE);
+ }
+
+ hr = CreateFileMoniker(RemoteFileName, &pMon);
+
+ if (FAILED(hr))
+ {
+ printf("CreateFileMoniker returned 0x%x\n", hr);
+ }
+
+ hr = CreateBindCtx(0, &pBc);
+
+ if (FAILED(hr))
+ {
+ printf("CreateBindCtx returned 0x%x\n", hr);
+ pMon->Release();
+ return(FALSE);
+ }
+
+ START_LOOP;
+
+ START_CLOCK;
+ hr = pMon->BindToObject(
+ pBc,
+ NULL,
+ IID_IUnknown,
+ (void **) &pUnk);
+ STOP_CLOCK;
+
+ if (FAILED(hr))
+ {
+ printf("IMoniker::BindToObject returned 0x%x\n", hr);
+ if (punkHeld)
+ punkHeld->Release();
+ return(FALSE);
+ }
+
+ if (gfHoldServer && NULL == punkHeld)
+ {
+ punkHeld = pUnk;
+ punkHeld->AddRef();
+ }
+
+ pUnk->Release();
+
+ STOP_LOOP;
+
+ pMon->Release();
+ pBc->Release();
+
+ if (punkHeld)
+ punkHeld->Release();
+ return(TRUE);
+}
+
+BOOL CIFromStgLocalEXE()
+{
+ IStorage * pStorage;
+ MULTI_QI QIStruct[10];
+ IUnknown * punkHeld = NULL;
+
+ pStorage = 0;
+
+ DeleteFile( StorageName );
+
+ HRESULT HResult = StgCreateDocfile(
+ StorageName,
+ STGM_READWRITE | STGM_DIRECT | STGM_SHARE_EXCLUSIVE | STGM_CREATE,
+ 0,
+ &pStorage );
+
+ if ( FAILED(HResult) )
+ {
+ printf("StgCreateDocfile returned 0x%x\n", HResult);
+ return FALSE;
+ }
+
+ START_LOOP;
+
+ QIStruct[0].pIID = (IID *)&IID_IUnknown;
+ QIStruct[0].pItf = NULL;
+
+ START_CLOCK;
+ HResult = CoGetInstanceFromIStorage(
+ NULL,
+ &CLSID_ActLocal,
+ NULL,
+ CLSCTX_SERVER,
+ pStorage,
+ 1,
+ QIStruct );
+ STOP_CLOCK;
+
+ if ( FAILED(HResult) )
+ {
+ printf("CoGetInstanceFromIStorage returned 0x%x\n", HResult);
+ if (punkHeld)
+ punkHeld->Release();
+ return FALSE;
+ }
+
+ if (gfHoldServer && NULL == punkHeld)
+ {
+ punkHeld = QIStruct[0].pItf;
+ punkHeld->AddRef();
+ }
+
+ QIStruct[0].pItf->Release();
+ QIStruct[0].pItf = 0;
+
+ STOP_LOOP;
+
+ pStorage->Release();
+
+ if (punkHeld)
+ punkHeld->Release();
+ return(TRUE);
+}
+
+BOOL CIFromStgActivator()
+{
+ IStorage * pStorage;
+ MULTI_QI QIStruct[10];
+ COSERVERINFO ServerInfo;
+ IUnknown * punkHeld = NULL;
+
+ memset( &ServerInfo, 0, sizeof(COSERVERINFO) );
+ ServerInfo.pwszName = ServerName;
+
+ pStorage = 0;
+
+ DeleteFile( StorageName );
+
+ HRESULT HResult = StgCreateDocfile(
+ StorageName,
+ STGM_READWRITE | STGM_DIRECT | STGM_SHARE_EXCLUSIVE | STGM_CREATE,
+ 0,
+ &pStorage );
+
+ if ( FAILED(HResult) )
+ {
+ printf("StgCreateDocfile returned 0x%x\n", HResult);
+ return FALSE;
+ }
+
+ START_LOOP;
+
+ QIStruct[0].pIID = (IID *)&IID_IUnknown;
+ QIStruct[0].pItf = NULL;
+
+ START_CLOCK;
+ HResult = CoGetInstanceFromIStorage(
+ &ServerInfo,
+ &CLSID_ActRemote,
+ NULL,
+ CLSCTX_REMOTE_SERVER,
+ pStorage,
+ 1,
+ QIStruct );
+ STOP_CLOCK;
+
+ if ( FAILED(HResult) )
+ {
+ printf("CoGetInstanceFromIStorage returned 0x%x\n", HResult);
+ if (punkHeld)
+ punkHeld->Release();
+ return FALSE;
+ }
+
+ if (gfHoldServer && NULL == punkHeld)
+ {
+ punkHeld = QIStruct[0].pItf;
+ punkHeld->AddRef();
+ }
+
+ QIStruct[0].pItf->Release();
+ QIStruct[0].pItf = 0;
+
+ STOP_LOOP;
+
+ pStorage->Release();
+
+ if (punkHeld)
+ punkHeld->Release();
+ return(TRUE);
+}
+
+BOOL CICustomLocalDLL()
+{
+ IGoober * pGoober;
+ MULTI_QI QIStruct[10];
+ HRESULT hr;
+ IUnknown * punkHeld = NULL;
+
+ START_LOOP;
+
+ QIStruct[0].pItf = NULL;
+ QIStruct[0].pIID = (IID *) &IID_IGoober;
+
+ START_CLOCK;
+ hr = CoCreateInstanceEx(
+ CLSID_ActInproc,
+ NULL,
+ CLSCTX_INPROC_SERVER,
+ NULL,
+ 1,
+ QIStruct );
+ STOP_CLOCK;
+
+ pGoober = (IGoober *)QIStruct[0].pItf;
+
+ if ( FAILED(hr) )
+ {
+ printf("CoCreateInstanceEx returned 0x%x\n", hr);
+ if (punkHeld)
+ punkHeld->Release();
+ return FALSE;
+ }
+
+ if (gfHoldServer && NULL == punkHeld)
+ {
+ punkHeld = QIStruct[0].pItf;
+ punkHeld->AddRef();
+ }
+
+ START_CLOCK;
+ hr = pGoober->Ping();
+ STOP_CLOCK;
+
+ if ( hr != S_OK )
+ {
+ printf("IGoober::Ping returned %d\n", hr);
+ pGoober->Release();
+ if (punkHeld)
+ punkHeld->Release();
+ return FALSE;
+ }
+
+ pGoober->Release();
+
+ STOP_LOOP;
+
+ if (punkHeld)
+ punkHeld->Release();
+ return(TRUE);
+}
+
+BOOL CICustomLocalEXE()
+{
+ IGoober * pGoober;
+ MULTI_QI QIStruct[10];
+ HRESULT hr;
+ IUnknown * punkHeld = NULL;
+
+ START_LOOP;
+
+ QIStruct[0].pItf = NULL;
+ QIStruct[0].pIID = (IID *) &IID_IGoober;
+
+ START_CLOCK;
+ hr = CoCreateInstanceEx(
+ CLSID_ActLocal,
+ NULL,
+ CLSCTX_LOCAL_SERVER,
+ NULL,
+ 1,
+ QIStruct );
+ STOP_CLOCK;
+
+ pGoober = (IGoober *)QIStruct[0].pItf;
+
+ if ( FAILED(hr) )
+ {
+ printf("CoCreateInstanceEx returned 0x%x\n", hr);
+ if (punkHeld)
+ punkHeld->Release();
+ return FALSE;
+ }
+
+ if (gfHoldServer && NULL == punkHeld)
+ {
+ punkHeld = QIStruct[0].pItf;
+ punkHeld->AddRef();
+ }
+
+ START_CLOCK;
+ hr = pGoober->Ping();
+ STOP_CLOCK;
+
+ if ( hr != S_OK )
+ {
+ printf("IGoober::Ping returned %d\n", hr);
+ pGoober->Release();
+ if (punkHeld)
+ punkHeld->Release();
+ return FALSE;
+ }
+
+ pGoober->Release();
+
+ STOP_LOOP;
+
+ if (punkHeld)
+ punkHeld->Release();
+ return(TRUE);
+}
+
+BOOL CILocalPreCon()
+{
+ return GenericCITest(CLSID_ActPreConfig, IID_IUnknown, NULL, 1, CLSCTX_LOCAL_SERVER);
+}
+
+BOOL CIExplicitPreCon()
+{
+ return GenericCITest(CLSID_ActPreConfig, IID_IUnknown, ServerName, 1, CLSCTX_REMOTE_SERVER);
+}
+
+BOOL CILocalUser()
+{
+ return GenericCITest(CLSID_ActRunAsLoggedOn, IID_IUnknown, NULL, 1, CLSCTX_LOCAL_SERVER);
+}
+
+BOOL CIExplicitUser()
+{
+ return GenericCITest(CLSID_ActRunAsLoggedOn, IID_IUnknown, ServerName, 1, CLSCTX_REMOTE_SERVER);
+}
+
+BOOL CILocalService()
+{
+ COSERVERINFO ServerInfo;
+ COSERVERINFO *pServerInfo;
+ IUnknown * punkHeld = NULL;
+
+ MULTI_QI QIStruct[1];
+ HRESULT hr;
+ BOOL fReturn = TRUE;
+
+ START_LOOP;
+
+ QIStruct[0].pItf = NULL;
+ QIStruct[0].pIID = (IID *) &IID_IUnknown;
+
+ START_CLOCK;
+ hr = CoCreateInstanceEx(
+ CLSID_ActService,
+ NULL,
+ CLSCTX_LOCAL_SERVER,
+ NULL,
+ 1,
+ QIStruct);
+ STOP_CLOCK;
+
+ if ( FAILED(hr) )
+ {
+ printf("CoCreateInstanceEx returned 0x%x\n", hr);
+ if (punkHeld)
+ punkHeld->Release();
+ return FALSE;
+ }
+
+ if (gfHoldServer && NULL == punkHeld && SUCCEEDED(QIStruct[0].hr))
+ {
+ punkHeld = QIStruct[0].pItf;
+ punkHeld->AddRef();
+ }
+
+ if (FAILED(QIStruct[0].hr))
+ {
+ printf("CoCreateInstanceEx returned 0x%x\n",
+ QIStruct[0].hr);
+ fReturn = FALSE;
+ }
+ else
+ QIStruct[0].pItf->Release();
+
+ if (!fReturn)
+ {
+ if (punkHeld)
+ punkHeld->Release();
+ return(fReturn);
+ }
+
+ SLEEP_IF_LOOPING;
+
+ STOP_LOOP;
+
+ if (punkHeld)
+ punkHeld->Release();
+
+ return fReturn;
+}
+
+BOOL CIExplicitService()
+{
+ COSERVERINFO ServerInfo;
+ COSERVERINFO *pServerInfo;
+ IUnknown * punkHeld = NULL;
+
+ memset( &ServerInfo, 0, sizeof(COSERVERINFO) );
+ ServerInfo.pwszName = ServerName;
+ pServerInfo = &ServerInfo;
+
+ MULTI_QI QIStruct[1];
+ HRESULT hr;
+ BOOL fReturn = TRUE;
+
+ START_LOOP;
+
+ QIStruct[0].pItf = NULL;
+ QIStruct[0].pIID = (IID *) &IID_IUnknown;
+
+ START_CLOCK;
+ hr = CoCreateInstanceEx(
+ CLSID_ActService,
+ NULL,
+ CLSCTX_REMOTE_SERVER,
+ pServerInfo,
+ 1,
+ QIStruct);
+ STOP_CLOCK;
+
+ if ( FAILED(hr) )
+ {
+ printf("CoCreateInstanceEx returned 0x%x\n", hr);
+ if (punkHeld)
+ punkHeld->Release();
+ return FALSE;
+ }
+
+ if (gfHoldServer && NULL == punkHeld && SUCCEEDED(QIStruct[0].hr))
+ {
+ punkHeld = QIStruct[0].pItf;
+ punkHeld->AddRef();
+ }
+
+ if (FAILED(QIStruct[0].hr))
+ {
+ printf("CoCreateInstanceEx returned 0x%x\n",
+ QIStruct[0].hr);
+ fReturn = FALSE;
+ }
+ else
+ QIStruct[0].pItf->Release();
+
+ if (!fReturn)
+ {
+ if (punkHeld)
+ punkHeld->Release();
+ return(fReturn);
+ }
+
+ SLEEP_IF_LOOPING;
+
+ STOP_LOOP;
+
+ if (punkHeld)
+ punkHeld->Release();
+
+ return fReturn;
+}
+
+BOOL CILocalPreConACL();
+BOOL CIExplicitPreConACL();
+
+#define MAX_SERVICE_ARGS 10
+
+BOOL MyStartService(WCHAR * wszServiceName, WCHAR *pwszRegServiceArgs)
+{
+ SC_HANDLE hSCManager;
+ SC_HANDLE hService;
+ WCHAR *pwszServiceArgs = NULL;
+ ULONG cArgs = 0;
+ WCHAR *apwszArgs[MAX_SERVICE_ARGS];
+
+ // Get a handle to the Service Control Manager
+ if (hSCManager = OpenSCManager(NULL, NULL, GENERIC_EXECUTE | SERVICE_QUERY_STATUS ))
+ {
+ // Open a handle to the requested service
+ if (hService = OpenService(hSCManager, wszServiceName, GENERIC_EXECUTE | SERVICE_QUERY_STATUS ))
+ {
+ // Close the service manager's database
+ CloseServiceHandle(hSCManager);
+
+ // Formulate the arguments (if any)
+ if (pwszRegServiceArgs)
+ {
+ UINT k = 0;
+
+ // Make a copy of the service arguments
+ pwszServiceArgs = new WCHAR[(lstrlenW(pwszRegServiceArgs) + 1)];
+ if (pwszServiceArgs == NULL)
+ {
+ CloseServiceHandle(hService);
+ return FALSE;
+ }
+ lstrcpyW(pwszServiceArgs, pwszRegServiceArgs);
+
+ // Scan the arguments
+ do
+ {
+ // Scan to the next non-whitespace character
+ while(pwszServiceArgs[k] &&
+ (pwszServiceArgs[k] == L' ' ||
+ pwszServiceArgs[k] == L'\t'))
+ {
+ k++;
+ }
+
+ // Store the next argument
+ if (pwszServiceArgs[k])
+ {
+ apwszArgs[cArgs++] = &pwszServiceArgs[k];
+ }
+
+ // Scan to the next whitespace char
+ while(pwszServiceArgs[k] &&
+ pwszServiceArgs[k] != L' ' &&
+ pwszServiceArgs[k] != L'\t')
+ {
+ k++;
+ }
+
+ // Null terminate the previous argument
+ if (pwszServiceArgs[k])
+ {
+ pwszServiceArgs[k++] = L'\0';
+ }
+ } while(pwszServiceArgs[k]);
+ }
+
+ // Start the service
+ if (StartService(hService, cArgs,
+ cArgs > 0 ? (LPCTSTR *) apwszArgs : NULL))
+ {
+ SERVICE_STATUS ss;
+ do
+ {
+ QueryServiceStatus(hService, &ss);
+ if (dwWaitHint)
+ {
+ Sleep(dwWaitHint);
+ }
+ else
+ Sleep(ss.dwWaitHint);
+ } while (ss.dwCurrentState == SERVICE_START_PENDING);
+
+ CloseServiceHandle(hService);
+ delete [] pwszServiceArgs;
+ return TRUE;
+ }
+ else
+ {
+ CloseServiceHandle(hService);
+ delete [] pwszServiceArgs;
+ }
+ }
+ else
+ {
+ CloseServiceHandle(hSCManager);
+ }
+ }
+
+ DWORD err = GetLastError();
+ return FALSE;
+}
+
+BOOL MyStopService(WCHAR * wszServiceName)
+{
+ SC_HANDLE hSCManager;
+ SC_HANDLE hService;
+ SERVICE_STATUS ss;
+
+ // Get a handle to the Service Control Manager
+ if (hSCManager = OpenSCManager(NULL, NULL, GENERIC_EXECUTE | SERVICE_QUERY_STATUS ))
+ {
+ // Open a handle to the requested service
+ if (hService = OpenService(hSCManager, wszServiceName, GENERIC_EXECUTE | SERVICE_QUERY_STATUS ))
+ {
+ // Close the service manager's database
+ CloseServiceHandle(hSCManager);
+
+ // Stop the service
+ if (ControlService(hService, SERVICE_CONTROL_STOP, &ss))
+ {
+
+ while (ss.dwCurrentState == SERVICE_STOP_PENDING)
+ {
+ if (dwWaitHint)
+ {
+ Sleep(dwWaitHint);
+ }
+ else
+ Sleep(ss.dwWaitHint);
+ QueryServiceStatus(hService, &ss);
+ };
+
+ CloseServiceHandle(hService);
+ return TRUE;
+ }
+ else
+ {
+ CloseServiceHandle(hService);
+ }
+ }
+ else
+ {
+ CloseServiceHandle(hSCManager);
+ }
+ }
+
+ DWORD err = GetLastError();
+ return FALSE;
+}
+
+#endif // NO_DCOM
diff --git a/private/oleutest/act/tstsvc/client.hxx b/private/oleutest/act/tstsvc/client.hxx
new file mode 100644
index 000000000..6ce43a62a
--- /dev/null
+++ b/private/oleutest/act/tstsvc/client.hxx
@@ -0,0 +1,38 @@
+/*
+ * client.hxx
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <windows.h>
+#include <rpc.h>
+#include <ole2.h>
+#include <oleext.h>
+#include "..\acttest.h"
+#include "..\dll\goober.h"
+
+// To build performance tests for pre-DCOM systems
+// uncomment the following line.
+//#define NO_DCOM
+
+typedef unsigned long ulong;
+typedef unsigned char uchar;
+#define NO 0
+#define YES 1
+
+typedef BOOL (* LPTESTFUNC) (void);
+
+DWORD InstallService(WCHAR * Path);
+
+extern WCHAR ServerName[32];
+
+void PrintUsageAndExit( BOOL bListTests );
+long InitializeRegistryForLocal();
+long InitializeRegistryForInproc();
+long InitializeRegistryForCustom();
+long InitializeRegistryForRemote();
+long InitializeRegistryForService();
+
+BOOL Tests();
+
+
diff --git a/private/oleutest/act/tstsvc/daytona/makefile b/private/oleutest/act/tstsvc/daytona/makefile
new file mode 100644
index 000000000..5acbbd24c
--- /dev/null
+++ b/private/oleutest/act/tstsvc/daytona/makefile
@@ -0,0 +1 @@
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/oleutest/act/tstsvc/daytona/sources b/private/oleutest/act/tstsvc/daytona/sources
new file mode 100644
index 000000000..8b3f29902
--- /dev/null
+++ b/private/oleutest/act/tstsvc/daytona/sources
@@ -0,0 +1,77 @@
+!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:
+
+ Steve Wood (stevewo) 12-Apr-1989
+
+
+Revision History:
+ Modified by Steve Blanding 15-Jan 1996 for DCOM performance tests
+
+!ENDIF
+
+#
+# The TARGETNAME variable is defined by the developer. It is the name of
+# the target (component) that is being built by this makefile. It
+# should NOT include any path or file extension information.
+#
+
+TARGETNAME=tstsvc
+
+#
+# The TARGETPATH and TARGETTYPE varialbes are defined by the developer.
+# The first specifies where the target is to be build. The second specifies
+# the type of target (either PROGRAM, DYNLINK or LIBRARY)
+#
+
+TARGETPATH=.
+TARGETTYPE=PROGRAM
+
+#
+# The INCLUDES variable specifies any include paths that are specific to
+# this source directory. Separate multiple directory paths with single
+# semicolons. Relative path specifications are okay.
+#
+
+INCLUDES=.
+
+#
+# The SOURCES variable is defined by the developer. It is a list of all the
+# source files for this component. Each source file should be on a separate
+# line using the line continuation character. This will minimize merge
+# conflicts if two developers adding source files to the same component.
+#
+
+SOURCES=\
+ ..\client.cxx \
+ ..\pswrd.cxx \
+ ..\reg.cxx
+
+C_DEFINES=-DUNICODE
+
+LINKLIBS=\
+ $(BASEDIR)\public\sdk\lib\*\kernel32.lib \
+ $(BASEDIR)\public\sdk\lib\*\user32.lib \
+ $(BASEDIR)\public\sdk\lib\*\advapi32.lib \
+ $(BASEDIR)\public\sdk\lib\*\ntdll.lib \
+ $(BASEDIR)\public\sdk\lib\*\ole32.lib \
+ $(BASEDIR)\public\sdk\lib\*\rpcrt4.lib \
+ $(BASEDIR)\public\sdk\lib\*\uuid.lib \
+ $(BASEDIR)\public\sdk\lib\*\mpr.lib \
+ ..\..\common\*\common.lib
+
+UMTYPE=console
diff --git a/private/oleutest/act/tstsvc/dirs b/private/oleutest/act/tstsvc/dirs
new file mode 100644
index 000000000..35b6c7372
--- /dev/null
+++ b/private/oleutest/act/tstsvc/dirs
@@ -0,0 +1,27 @@
+!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:
+
+ Steve Wood (stevewo) 17-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\dirs.tpl
+
+!ENDIF
+
+DIRS=
+
+OPTIONAL_DIRS=\
+ daytona \
+
diff --git a/private/oleutest/act/tstsvc/pswrd.cxx b/private/oleutest/act/tstsvc/pswrd.cxx
new file mode 100644
index 000000000..d504539b7
--- /dev/null
+++ b/private/oleutest/act/tstsvc/pswrd.cxx
@@ -0,0 +1,56 @@
+extern "C"
+{
+#include <nt.h>
+#include <ntrtl.h>
+#include <nturtl.h>
+#include <ntlsa.h>
+}
+#include <stdarg.h>
+#include <windef.h>
+#include <winbase.h>
+#include <winnls.h>
+#include <stdio.h>
+
+BOOL SetPassword(WCHAR * szCID, WCHAR * szPw)
+{
+ LSA_OBJECT_ATTRIBUTES sObjAttributes;
+ LSA_HANDLE hPolicy;
+ LSA_UNICODE_STRING sKey;
+ LSA_UNICODE_STRING sPassword;
+ WCHAR szKey[256];
+
+ swprintf(szKey, L"SCM:%s", szCID);
+ sKey.Length = (wcslen(szKey) + 1) * sizeof(WCHAR);
+ sKey.MaximumLength = (wcslen(szKey) + 1) * sizeof(WCHAR);
+ sKey.Buffer = szKey;
+ sPassword.Length = (wcslen(szPw) + 1) * sizeof(WCHAR);
+ sPassword.MaximumLength = 80 * sizeof(WCHAR);
+ sPassword.Buffer = szPw;
+
+ InitializeObjectAttributes(&sObjAttributes, NULL, 0L, NULL, NULL);
+
+ // open the local security policy
+ if (!NT_SUCCESS(
+ LsaOpenPolicy(
+ NULL,
+ &sObjAttributes,
+ POLICY_CREATE_SECRET,
+ &hPolicy)))
+ {
+ printf("LsaOpenPolicy failed with %d\n",GetLastError());
+ return(FALSE);
+ }
+
+ // store private data
+ if (!NT_SUCCESS(
+ LsaStorePrivateData(hPolicy, &sKey, &sPassword)))
+ {
+ printf("LsaStorePrivateData failed with %d\n",GetLastError());
+ return(FALSE);
+ }
+
+ LsaClose(hPolicy);
+ return(TRUE);
+}
+
+
diff --git a/private/oleutest/act/tstsvc/reg.cxx b/private/oleutest/act/tstsvc/reg.cxx
new file mode 100644
index 000000000..74cc6e4a1
--- /dev/null
+++ b/private/oleutest/act/tstsvc/reg.cxx
@@ -0,0 +1,859 @@
+//
+// reg.cxx
+//
+
+#include "client.hxx"
+
+BOOL SetPassword(WCHAR * szCID, WCHAR * szPw);
+
+WCHAR * ServiceName = L"ActTestService";
+WCHAR * ServiceDisplayName = L"ActTestService";
+WCHAR * UserName = L"redmond\\oleuser";
+WCHAR * Password = L"stocksplit";
+
+long InitializeRegistryForLocal()
+{
+ SYSTEM_INFO SystemInfo;
+ long RegStatus;
+ ulong Disposition;
+ HKEY hInterface;
+ HKEY hClsidKey;
+ HKEY hActKey;
+ HKEY hActValueKey;
+ WCHAR Path[256];
+
+ //
+ // Get CLASSES_ROOT.
+ //
+ RegStatus = RegOpenKeyEx( HKEY_CLASSES_ROOT,
+ L"CLSID",
+ 0,
+ KEY_ALL_ACCESS,
+ &hClsidKey );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ //
+ // Local CLSID entries.
+ //
+
+ RegStatus = RegCreateKeyEx(
+ hClsidKey,
+ ClsidActLocalString,
+ 0,
+ L"REG_SZ",
+ REG_OPTION_NON_VOLATILE,
+ KEY_ALL_ACCESS,
+ NULL,
+ &hActKey,
+ &Disposition );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ RegStatus = RegCreateKeyEx(
+ hActKey,
+ L"LocalServer32",
+ 0,
+ L"REG_SZ",
+ REG_OPTION_NON_VOLATILE,
+ KEY_ALL_ACCESS,
+ NULL,
+ &hActValueKey,
+ &Disposition );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ if ( ! GetModuleFileName( 0, Path, sizeof(Path) ) )
+ return RegStatus;
+
+ _wcslwr( Path );
+ wcscpy( wcsstr( Path, L"actclt" ), L"actsrv.exe 2" );
+
+ RegStatus = RegSetValueEx(
+ hActValueKey,
+ L"",
+ 0,
+ REG_SZ,
+ (const BYTE *)Path,
+ (wcslen(Path) + 1) * sizeof(WCHAR) );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ RegStatus = RegSetValueEx(
+ hClsidKey,
+ L"AppID",
+ 0,
+ REG_SZ,
+ (const BYTE *) ClsidActLocalString,
+ (wcslen(ClsidActLocalString)+1)*sizeof(WCHAR));
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ RegStatus = SetAppIDSecurity( ClsidActLocalString );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ return ERROR_SUCCESS;
+}
+
+long InitializeRegistryForInproc()
+{
+ SYSTEM_INFO SystemInfo;
+ long RegStatus;
+ ulong Disposition;
+ HKEY hInterface;
+ HKEY hClsidKey;
+ HKEY hActKey;
+ HKEY hActValueKey;
+ WCHAR Path[256];
+
+ //
+ // Get CLASSES_ROOT.
+ //
+ RegStatus = RegOpenKeyEx( HKEY_CLASSES_ROOT,
+ L"CLSID",
+ 0,
+ KEY_ALL_ACCESS,
+ &hClsidKey );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ //
+ // Local CLSID entries.
+ //
+
+ RegStatus = RegCreateKeyEx(
+ hClsidKey,
+ ClsidActInprocString,
+ 0,
+ L"REG_SZ",
+ REG_OPTION_NON_VOLATILE,
+ KEY_ALL_ACCESS,
+ NULL,
+ &hActKey,
+ &Disposition );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ // if ( Disposition == REG_OPENED_EXISTING_KEY )
+ // return TRUE;
+
+ RegStatus = RegCreateKeyEx(
+ hActKey,
+ L"InprocServer32",
+ 0,
+ L"REG_SZ",
+ REG_OPTION_NON_VOLATILE,
+ KEY_ALL_ACCESS,
+ NULL,
+ &hActValueKey,
+ &Disposition );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ if ( ! GetModuleFileName( 0, Path, sizeof(Path) ) )
+ return RegStatus;
+
+ _wcslwr( Path );
+ wcscpy( wcsstr( Path, L"actclt" ), L"actsrvd.dll" );
+
+ RegStatus = RegSetValueEx(
+ hActValueKey,
+ L"",
+ 0,
+ REG_SZ,
+ (const BYTE *)Path,
+ (wcslen(Path) + 1) * sizeof(WCHAR) );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ RegStatus = RegSetValueEx(
+ hActValueKey,
+ L"ThreadingModel",
+ 0,
+ REG_SZ,
+ (const BYTE *)L"Both",
+ (wcslen(L"Both") + 1) * sizeof(WCHAR) );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ return ERROR_SUCCESS;
+}
+
+WCHAR * StringIidIGoober = L"{ffffffff-0000-0000-0000-000000000000}";
+
+long InitializeRegistryForCustom()
+{
+ SYSTEM_INFO SystemInfo;
+ long RegStatus;
+ ulong Disposition;
+ HKEY hInterface;
+ HKEY hClsidKey;
+ HKEY hActKey;
+ HKEY hActValueKey;
+ WCHAR Path[256];
+
+ RegStatus = RegOpenKeyEx( HKEY_CLASSES_ROOT,
+ L"Interface",
+ 0,
+ KEY_ALL_ACCESS,
+ &hInterface );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ RegStatus = RegCreateKeyEx(
+ hInterface,
+ StringIidIGoober,
+ 0,
+ L"REG_SZ",
+ REG_OPTION_NON_VOLATILE,
+ KEY_ALL_ACCESS,
+ NULL,
+ &hInterface,
+ &Disposition );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ RegStatus = RegSetValueEx(
+ hInterface,
+ L"",
+ 0,
+ REG_SZ,
+ (const BYTE *)L"IGoober",
+ (wcslen(L"IGoober") + 1) * sizeof(WCHAR) );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ RegStatus = RegCreateKeyEx(
+ hInterface,
+ L"ProxyStubClsid32",
+ 0,
+ L"REG_SZ",
+ REG_OPTION_NON_VOLATILE,
+ KEY_ALL_ACCESS,
+ NULL,
+ &hInterface,
+ &Disposition );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ RegStatus = RegSetValueEx(
+ hInterface,
+ L"",
+ 0,
+ REG_SZ,
+ (const BYTE *)ClsidGoober32String,
+ (wcslen(ClsidGoober32String) + 1) * sizeof(WCHAR) );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ RegStatus = RegOpenKeyEx( HKEY_CLASSES_ROOT,
+ L"CLSID",
+ 0,
+ KEY_ALL_ACCESS,
+ &hClsidKey );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ RegStatus = RegCreateKeyEx(
+ hClsidKey,
+ ClsidGoober32String,
+ 0,
+ L"REG_SZ",
+ REG_OPTION_NON_VOLATILE,
+ KEY_ALL_ACCESS,
+ NULL,
+ &hActKey,
+ &Disposition );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ // if ( Disposition == REG_OPENED_EXISTING_KEY )
+ // return TRUE;
+
+ RegStatus = RegCreateKeyEx(
+ hActKey,
+ L"InProcServer32",
+ 0,
+ L"REG_SZ",
+ REG_OPTION_NON_VOLATILE,
+ KEY_ALL_ACCESS,
+ NULL,
+ &hActValueKey,
+ &Disposition );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ if ( ! GetModuleFileName( 0, Path, sizeof(Path) ) )
+ return RegStatus;
+
+ _wcslwr( Path );
+ wcscpy( wcsstr( Path, L"actclt" ), L"goober.dll" );
+
+ RegStatus = RegSetValueEx(
+ hActValueKey,
+ L"",
+ 0,
+ REG_SZ,
+ (const BYTE *)Path,
+ (wcslen(Path) + 1) * sizeof(WCHAR) );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ return ERROR_SUCCESS;
+}
+
+long InitializeRegistryForRemote()
+{
+ long RegStatus;
+ ulong Disposition;
+ HKEY hClsidKey;
+ HKEY hAppIDKey;
+ HKEY hThisClsidKey;
+ HKEY hActKey;
+ HKEY hActValueKey;
+ WCHAR Path[256];
+
+ RegStatus = RegOpenKeyEx( HKEY_CLASSES_ROOT,
+ L"CLSID",
+ 0,
+ KEY_ALL_ACCESS,
+ &hClsidKey );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ //
+ // CLSID_ActRemote
+ //
+
+ RegStatus = RegCreateKeyEx(
+ hClsidKey,
+ ClsidActRemoteString,
+ 0,
+ L"REG_SZ",
+ REG_OPTION_NON_VOLATILE,
+ KEY_ALL_ACCESS,
+ NULL,
+ &hThisClsidKey,
+ &Disposition );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ RegStatus = RegSetValueEx(
+ hThisClsidKey,
+ L"AppID",
+ 0,
+ REG_SZ,
+ (const BYTE *) ClsidActRemoteString,
+ (wcslen(ClsidActRemoteString)+1)*sizeof(WCHAR));
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ RegStatus = SetAppIDSecurity( ClsidActRemoteString );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ RegStatus = RegCreateKeyEx(
+ HKEY_CLASSES_ROOT,
+ L"AppID",
+ 0,
+ L"REG_SZ",
+ REG_OPTION_NON_VOLATILE,
+ KEY_ALL_ACCESS,
+ NULL,
+ &hAppIDKey,
+ &Disposition );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ RegStatus = RegCreateKeyEx(
+ hAppIDKey,
+ ClsidActRemoteString,
+ 0,
+ L"REG_SZ",
+ REG_OPTION_NON_VOLATILE,
+ KEY_ALL_ACCESS,
+ NULL,
+ &hActKey,
+ &Disposition );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ RegStatus = RegSetValueEx(
+ hActKey,
+ L"RemoteServerName",
+ 0,
+ REG_SZ,
+ (const BYTE *)ServerName,
+ (wcslen(ServerName) + 1) * sizeof(WCHAR) );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ //
+ // CLSID_ActAtStorage
+ //
+
+ RegStatus = RegCreateKeyEx(
+ hClsidKey,
+ ClsidActAtStorageString,
+ 0,
+ L"REG_SZ",
+ REG_OPTION_NON_VOLATILE,
+ KEY_ALL_ACCESS,
+ NULL,
+ &hThisClsidKey,
+ &Disposition );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ RegStatus = RegSetValueEx(
+ hThisClsidKey,
+ L"AppID",
+ 0,
+ REG_SZ,
+ (const BYTE *) ClsidActAtStorageString,
+ (wcslen(ClsidActAtStorageString)+1)*sizeof(WCHAR));
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ RegStatus = SetAppIDSecurity( ClsidActAtStorageString );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ RegStatus = RegCreateKeyEx(
+ hAppIDKey,
+ ClsidActAtStorageString,
+ 0,
+ L"REG_SZ",
+ REG_OPTION_NON_VOLATILE,
+ KEY_ALL_ACCESS,
+ NULL,
+ &hActKey,
+ &Disposition );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ RegStatus = RegSetValueEx(
+ hActKey,
+ L"ActivateAtStorage",
+ 0,
+ REG_SZ,
+ (const BYTE *)L"Y",
+ (wcslen(L"Y") + 1) * sizeof(WCHAR) );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ //
+ // CLSID_ActRunAsLoggedOnUser
+ //
+
+ RegStatus = RegCreateKeyEx(
+ hClsidKey,
+ ClsidActRunAsLoggedOnString,
+ 0,
+ L"REG_SZ",
+ REG_OPTION_NON_VOLATILE,
+ KEY_ALL_ACCESS,
+ NULL,
+ &hThisClsidKey,
+ &Disposition );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ RegStatus = SetAppIDSecurity( ClsidActRunAsLoggedOnString );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ RegStatus = RegSetValueEx(
+ hThisClsidKey,
+ L"AppID",
+ 0,
+ REG_SZ,
+ (const BYTE *) ClsidActRunAsLoggedOnString,
+ (wcslen(ClsidActRunAsLoggedOnString)+1)*sizeof(WCHAR));
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ RegStatus = RegCreateKeyEx(
+ hAppIDKey,
+ ClsidActRunAsLoggedOnString,
+ 0,
+ L"REG_SZ",
+ REG_OPTION_NON_VOLATILE,
+ KEY_ALL_ACCESS,
+ NULL,
+ &hActKey,
+ &Disposition );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ RegStatus = RegSetValueEx(
+ hActKey,
+ L"RemoteServerName",
+ 0,
+ REG_SZ,
+ (const BYTE *)ServerName,
+ (wcslen(ServerName) + 1) * sizeof(WCHAR) );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ RegStatus = RegCreateKeyEx(
+ hThisClsidKey,
+ L"LocalServer32",
+ 0,
+ L"REG_SZ",
+ REG_OPTION_NON_VOLATILE,
+ KEY_ALL_ACCESS,
+ NULL,
+ &hActValueKey,
+ &Disposition );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ if ( ! GetModuleFileName( 0, Path, sizeof(Path) ) )
+ return RegStatus;
+
+ _wcslwr( Path );
+ wcscpy( wcsstr( Path, L"actclt" ), L"actsrv.exe 7" );
+
+ RegStatus = RegSetValueEx(
+ hActValueKey,
+ L"",
+ 0,
+ REG_SZ,
+ (const BYTE *)Path,
+ (wcslen(Path) + 1) * sizeof(WCHAR) );
+
+ RegStatus = RegSetValueEx(
+ hActKey,
+ L"RunAs",
+ 0,
+ REG_SZ,
+ (const BYTE *)L"Interactive User",
+ (wcslen(L"Interactive User") + 1) * sizeof(WCHAR) );
+
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ //
+ // RunAs CLSID entries.
+ //
+
+ RegStatus = RegCreateKeyEx(
+ hClsidKey,
+ ClsidActPreConfigString,
+ 0,
+ L"REG_SZ",
+ REG_OPTION_NON_VOLATILE,
+ KEY_ALL_ACCESS,
+ NULL,
+ &hThisClsidKey,
+ &Disposition );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ RegStatus = RegSetValueEx(
+ hThisClsidKey,
+ L"AppID",
+ 0,
+ REG_SZ,
+ (const BYTE *) ClsidActPreConfigString,
+ (wcslen(ClsidActPreConfigString)+1)*sizeof(WCHAR));
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ RegStatus = SetAppIDSecurity( ClsidActPreConfigString );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ RegStatus = RegCreateKeyEx(
+ hAppIDKey,
+ ClsidActPreConfigString,
+ 0,
+ L"REG_SZ",
+ REG_OPTION_NON_VOLATILE,
+ KEY_ALL_ACCESS,
+ NULL,
+ &hActKey,
+ &Disposition );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ RegStatus = RegSetValueEx(
+ hActKey,
+ L"RemoteServerName",
+ 0,
+ REG_SZ,
+ (const BYTE *)ServerName,
+ (wcslen(ServerName) + 1) * sizeof(WCHAR) );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ RegStatus = RegCreateKeyEx(
+ hThisClsidKey,
+ L"LocalServer32",
+ 0,
+ L"REG_SZ",
+ REG_OPTION_NON_VOLATILE,
+ KEY_ALL_ACCESS,
+ NULL,
+ &hActValueKey,
+ &Disposition );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ if ( ! GetModuleFileName( 0, Path, sizeof(Path) ) )
+ return RegStatus;
+
+ _wcslwr( Path );
+ wcscpy( wcsstr( Path, L"actclt" ), L"actsrv.exe 6" );
+
+ RegStatus = RegSetValueEx(
+ hActValueKey,
+ L"",
+ 0,
+ REG_SZ,
+ (const BYTE *)Path,
+ (wcslen(Path) + 1) * sizeof(WCHAR) );
+
+ RegStatus = RegSetValueEx(
+ hActKey,
+ L"RunAs",
+ 0,
+ REG_SZ,
+ (const BYTE *)UserName,
+ (wcslen(UserName) + 1) * sizeof(WCHAR) );
+
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ if (!SetPassword(ClsidActPreConfigString, Password))
+ return(FALSE);
+
+ return ERROR_SUCCESS;
+}
+
+long InitializeRegistryForService()
+{
+ long RegStatus;
+ ulong Disposition;
+ HKEY hClsidKey;
+ HKEY hAppIDKey;
+ HKEY hThisClsidKey;
+ HKEY hActKey;
+ HKEY hActValueKey;
+ HKEY hServices;
+ WCHAR Path[256];
+
+ //
+ // Get CLASSES_ROOT.
+ //
+ RegStatus = RegOpenKeyEx( HKEY_CLASSES_ROOT,
+ L"CLSID",
+ 0,
+ KEY_ALL_ACCESS,
+ &hClsidKey );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ RegStatus = RegCreateKeyEx(
+ HKEY_CLASSES_ROOT,
+ L"AppID",
+ 0,
+ L"REG_SZ",
+ REG_OPTION_NON_VOLATILE,
+ KEY_ALL_ACCESS,
+ NULL,
+ &hAppIDKey,
+ &Disposition );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ //
+ // Local CLSID entries.
+ //
+
+ RegStatus = RegCreateKeyEx(
+ hClsidKey,
+ ClsidActServiceString,
+ 0,
+ L"REG_SZ",
+ REG_OPTION_NON_VOLATILE,
+ KEY_ALL_ACCESS,
+ NULL,
+ &hThisClsidKey,
+ &Disposition );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ RegStatus = SetAppIDSecurity( ClsidActServiceString );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ RegStatus = RegSetValueEx(
+ hThisClsidKey,
+ L"AppID",
+ 0,
+ REG_SZ,
+ (const BYTE *) ClsidActServiceString,
+ (wcslen(ClsidActServiceString)+1)*sizeof(WCHAR));
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ // if ( Disposition == REG_OPENED_EXISTING_KEY )
+ // return TRUE;
+
+ RegStatus = RegCreateKeyEx(
+ hAppIDKey,
+ ClsidActServiceString,
+ 0,
+ L"REG_SZ",
+ REG_OPTION_NON_VOLATILE,
+ KEY_ALL_ACCESS,
+ NULL,
+ &hActKey,
+ &Disposition );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ if ( ! GetModuleFileName( 0, Path, sizeof(Path) ) )
+ return RegStatus;
+
+ _wcslwr( Path );
+ wcscpy( wcsstr( Path, L"actclt" ), L"actsrv.exe 8" );
+
+ RegStatus = RegSetValueEx(
+ hActKey,
+ L"LocalService",
+ 0,
+ REG_SZ,
+ (const BYTE *)ServiceName,
+ (wcslen(ServiceName) + 1) * sizeof(WCHAR) );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ RegStatus = RegSetValueEx(
+ hActKey,
+ L"ActivateAtStorage",
+ 0,
+ REG_SZ,
+ (const BYTE *)L"Y",
+ (wcslen(L"Y") + 1) * sizeof(WCHAR) );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ RegStatus = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
+ L"SYSTEM\\CurrentControlSet\\Services",
+ 0,
+ KEY_READ,
+ &hServices );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ return RegStatus;
+
+ return InstallService(Path);
+}
+
+DWORD InstallService( WCHAR * Path )
+{
+ SC_HANDLE hManager;
+ SC_HANDLE hService;
+
+ hManager = OpenSCManager( NULL,
+ NULL,
+ SC_MANAGER_ALL_ACCESS );
+
+ if ( ! hManager )
+ {
+ printf( "OpenSCManager returned %d\n", GetLastError() );
+ return GetLastError();
+ }
+
+ hService = OpenService( hManager,
+ ServiceName,
+ SERVICE_ALL_ACCESS );
+
+ if ( ! hService )
+ {
+ hService = CreateService(
+ hManager,
+ ServiceName,
+ ServiceDisplayName,
+ SERVICE_ALL_ACCESS,
+ SERVICE_WIN32_OWN_PROCESS,
+ SERVICE_DEMAND_START,
+ SERVICE_ERROR_NORMAL,
+ Path,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+ }
+
+ if ( ! hService )
+ {
+ printf( "CreateService returned %d\n", GetLastError() );
+ CloseServiceHandle(hManager);
+ return GetLastError();
+ }
+
+ CloseServiceHandle(hService);
+ CloseServiceHandle(hManager);
+ return ERROR_SUCCESS;
+}
+
diff --git a/private/oleutest/act/tstsvc/service.cxx b/private/oleutest/act/tstsvc/service.cxx
new file mode 100644
index 000000000..689076d78
--- /dev/null
+++ b/private/oleutest/act/tstsvc/service.cxx
@@ -0,0 +1,92 @@
+
+BOOL TimeStartService(WCHAR * wszServiceName, WCHAR *pwszRegServiceArgs, HANDLE *phProcess)
+{
+ SC_HANDLE hSCManager;
+ SC_HANDLE hService;
+ WCHAR *pwszServiceArgs = NULL;
+ ULONG cArgs = 0;
+ WCHAR *apwszArgs[MAX_SERVICE_ARGS];
+
+ *phProcess = NULL;
+
+ // Get a handle to the Service Control Manager
+ if (hSCManager = OpenSCManager(NULL, NULL, GENERIC_EXECUTE))
+ {
+ // Open a handle to the requested service
+ if (hService = OpenService(hSCManager, wszServiceName, GENERIC_EXECUTE))
+ {
+ // Close the service manager's database
+ CloseServiceHandle(hSCManager);
+
+ // Formulate the arguments (if any)
+ if (pwszRegServiceArgs)
+ {
+ UINT k = 0;
+
+ // Make a copy of the service arguments
+ pwszServiceArgs = (WCHAR *) PrivMemAlloc(
+ (lstrlenW(pwszRegServiceArgs) + 1) * sizeof(WCHAR));
+ if (pwszServiceArgs == NULL)
+ {
+ CloseServiceHandle(hService);
+ return FALSE;
+ }
+ lstrcpyW(pwszServiceArgs, pwszRegServiceArgs);
+
+ // Scan the arguments
+ do
+ {
+ // Scan to the next non-whitespace character
+ while(pwszServiceArgs[k] &&
+ (pwszServiceArgs[k] == L' ' ||
+ pwszServiceArgs[k] == L'\t'))
+ {
+ k++;
+ }
+
+ // Store the next argument
+ if (pwszServiceArgs[k])
+ {
+ apwszArgs[cArgs++] = &pwszServiceArgs[k];
+ }
+
+ // Scan to the next whitespace char
+ while(pwszServiceArgs[k] &&
+ pwszServiceArgs[k] != L' ' &&
+ pwszServiceArgs[k] != L'\t')
+ {
+ k++;
+ }
+
+ // Null terminate the previous argument
+ if (pwszServiceArgs[k])
+ {
+ pwszServiceArgs[k++] = L'\0';
+ }
+ } while(pwszServiceArgs[k]);
+ }
+
+ // Start the service
+ if (StartService(hService, cArgs,
+ cArgs > 0 ? (LPCTSTR *) apwszArgs : NULL))
+ {
+ CloseServiceHandle(hService);
+ PrivMemFree(pwszServiceArgs);
+ return TRUE;
+ }
+ else
+ {
+ CloseServiceHandle(hService);
+ PrivMemFree(pwszServiceArgs);
+ }
+ }
+ else
+ {
+ CloseServiceHandle(hSCManager);
+ }
+ }
+
+ DWORD err = GetLastError();
+ return FALSE;
+}
+
diff --git a/private/oleutest/assert/assert.cxx b/private/oleutest/assert/assert.cxx
new file mode 100644
index 000000000..837017eeb
--- /dev/null
+++ b/private/oleutest/assert/assert.cxx
@@ -0,0 +1,391 @@
+//+---------------------------------------------------------------------------
+// Copyright (C) 1991, Microsoft Corporation.
+//
+// File: assert.cxx
+//
+// Contents: Debugging output routines for idsmgr.dll
+//
+// Functions: Assert
+// PopUpError
+//
+// History: 23-Jul-91 KyleP Created.
+// 09-Oct-91 KevinRo Major changes and comments added
+// 18-Oct-91 vich moved debug print routines out
+// 10-Jun-92 BryanT Switched to w4crt.h instead of wchar.h
+// 30-Sep-93 KyleP DEVL obsolete
+//
+//----------------------------------------------------------------------------
+
+#pragma hdrstop
+
+//
+// This one file **always** uses debugging options
+//
+
+#if DBG == 1
+
+// needed for CT TOM assert events trapping
+#include <assert.hxx>
+
+#include <stdarg.h>
+#include <stdio.h>
+
+
+# include <dprintf.h> // w4printf, w4dprintf prototypes
+# include <debnot.h>
+# ifdef FLAT
+# include <sem.hxx>
+# include <dllsem.hxx>
+# endif // FLAT
+
+extern "C"
+{
+
+# ifdef FLAT
+# undef FAR
+# undef NEAR
+# else
+# define MessageBoxA MessageBox
+# endif
+
+# include <windows.h>
+}
+
+
+extern BOOL gfService = FALSE;
+
+unsigned long Win4InfoLevel = DEF_INFOLEVEL;
+unsigned long Win4InfoMask = 0xffffffff;
+unsigned long Win4AssertLevel = ASSRT_MESSAGE | ASSRT_BREAK | ASSRT_POPUP;
+
+//+---------------------------------------------------------------------------
+//
+// Function: _asdprintf
+//
+// Synopsis: Calls vdprintf to output a formatted message.
+//
+// History: 18-Oct-91 vich Created
+//
+//----------------------------------------------------------------------------
+inline void _CRTAPI1
+_asdprintf(
+ char const *pszfmt, ...)
+{
+ va_list va;
+ va_start(va, pszfmt);
+
+ vdprintf(DEB_FORCE, "Assert", pszfmt, va);
+
+ va_end(va);
+}
+
+//+---------------------------------------------------------------------------
+//
+// Function: _Win4Assert, private
+//
+// Synopsis: Display assertion information
+//
+// Effects: Called when an assertion is hit.
+//
+// History: 12-Jul-91 AlexT Created.
+// 05-Sep-91 AlexT Catch Throws and Catches
+// 19-Oct-92 HoiV Added events for TOM
+//
+//----------------------------------------------------------------------------
+
+
+STDAPI_(void) Win4AssertEx(
+ char const * szFile,
+ int iLine,
+ char const * szMessage)
+{
+#if defined( FLAT )
+ //
+ // This code is for the CT Lab only. When running in the lab,
+ // all assert popups will be trapped and notifications will
+ // be sent to the manager. If running in the office (non-lab
+ // mode), the event CTTOMTrapAssertEvent will not exist and
+ // consequently, no event will be pulsed.
+ //
+
+ HANDLE hTrapAssertEvent,
+ hThreadStartEvent;
+
+ if (hTrapAssertEvent = OpenEvent(EVENT_ALL_ACCESS,
+ FALSE,
+ CAIRO_CT_TOM_TRAP_ASSERT_EVENT))
+ {
+ SetEvent(hTrapAssertEvent);
+
+ //
+ // This event is to allow TOM Manager time to perform
+ // a CallBack to the dispatcher.
+ //
+ if (hThreadStartEvent = OpenEvent(EVENT_ALL_ACCESS,
+ FALSE,
+ CAIRO_CT_TOM_THREAD_START_EVENT))
+ {
+ //
+ // Wait until it's ok to popup or until timed-out
+ //
+ WaitForSingleObject(hThreadStartEvent, TWO_MINUTES);
+ }
+ }
+#endif
+
+ if (Win4AssertLevel & ASSRT_MESSAGE)
+ {
+# ifdef FLAT
+ DWORD tid = GetCurrentThreadId();
+
+ _asdprintf("%s File: %s Line: %u, thread id %d\n",
+ szMessage, szFile, iLine, tid);
+# else // FLAT
+ _asdprintf("%s File: %s Line: %u\n", szMessage, szFile, iLine);
+# endif // FLAT
+ }
+
+ if (Win4AssertLevel & ASSRT_POPUP)
+ {
+ int id = PopUpError(szMessage,iLine,szFile);
+
+ if (id == IDCANCEL)
+ {
+#ifdef FLAT
+ DebugBreak();
+#else
+ _asm int 3;
+#endif
+ }
+ }
+ else if (Win4AssertLevel & ASSRT_BREAK)
+ {
+#ifdef FLAT
+ DebugBreak();
+#else
+ _asm int 3;
+#endif
+ }
+
+}
+
+
+//+------------------------------------------------------------
+// Function: SetWin4InfoLevel(unsigned long ulNewLevel)
+//
+// Synopsis: Sets the global info level for debugging output
+// Returns: Old info level
+//
+//-------------------------------------------------------------
+
+EXPORTIMP unsigned long APINOT
+SetWin4InfoLevel(
+ unsigned long ulNewLevel)
+{
+ unsigned long ul;
+
+ ul = Win4InfoLevel;
+ Win4InfoLevel = ulNewLevel;
+ return(ul);
+}
+
+
+//+------------------------------------------------------------
+// Function: _SetWin4InfoMask(unsigned long ulNewMask)
+//
+// Synopsis: Sets the global info mask for debugging output
+// Returns: Old info mask
+//
+//-------------------------------------------------------------
+
+EXPORTIMP unsigned long APINOT
+SetWin4InfoMask(
+ unsigned long ulNewMask)
+{
+ unsigned long ul;
+
+ ul = Win4InfoMask;
+ Win4InfoMask = ulNewMask;
+ return(ul);
+}
+
+
+//+------------------------------------------------------------
+// Function: _SetWin4AssertLevel(unsigned long ulNewLevel)
+//
+// Synopsis: Sets the global assert level for debugging output
+// Returns: Old assert level
+//
+//-------------------------------------------------------------
+
+EXPORTIMP unsigned long APINOT
+SetWin4AssertLevel(
+ unsigned long ulNewLevel)
+{
+ unsigned long ul;
+
+ ul = Win4AssertLevel;
+ Win4AssertLevel = ulNewLevel;
+ return(ul);
+}
+
+//+------------------------------------------------------------
+// Function: PopUpError
+//
+// Synopsis: Displays a dialog box using provided text,
+// and presents the user with the option to
+// continue or cancel.
+//
+// Arguments:
+// szMsg -- The string to display in main body of dialog
+// iLine -- Line number of file in error
+// szFile -- Filename of file in error
+//
+// Returns:
+// IDCANCEL -- User selected the CANCEL button
+// IDOK -- User selected the OK button
+//-------------------------------------------------------------
+
+STDAPI_(int) PopUpError(
+ char const *szMsg,
+ int iLine,
+ char const *szFile)
+{
+
+ int id;
+ static char szAssertCaption[128];
+ static char szModuleName[128];
+
+ DWORD tid = GetCurrentThreadId();
+ DWORD pid = GetCurrentProcessId();
+ char * pszModuleName;
+
+ if (GetModuleFileNameA(NULL, szModuleName, 128))
+ {
+ pszModuleName = strrchr(szModuleName, '\\');
+ if (!pszModuleName)
+ {
+ pszModuleName = szModuleName;
+ }
+ else
+ {
+ pszModuleName++;
+ }
+ }
+ else
+ {
+ pszModuleName = "Unknown";
+ }
+
+ sprintf(szAssertCaption,"Process: %s File: %s line %u, thread id %d.%d",
+ pszModuleName, szFile, iLine, pid, tid);
+
+
+ DWORD dwMessageFlags = MB_SETFOREGROUND | MB_TASKMODAL |
+ MB_ICONEXCLAMATION | MB_OKCANCEL;
+
+#ifndef _CHICAGO_
+ // Since this code is also used by SCM.EXE, we pass
+ // in the following flag which causes Service pop ups
+ // to appear on the desktop correctly
+
+ if (gfService)
+ {
+ dwMessageFlags |= MB_SERVICE_NOTIFICATION | MB_DEFAULT_DESKTOP_ONLY;
+ }
+#endif // _CHICAGO_
+
+ id = MessageBoxA(NULL,(char *) szMsg, (LPSTR) szAssertCaption,
+ dwMessageFlags);
+
+ // If id == 0, then an error occurred. There are two possibilities
+ // that can cause the error: Access Denied, which means that this
+ // process does not have access to the default desktop, and everything
+ // else (usually out of memory). Oh well.
+
+ return id;
+}
+
+//+------------------------------------------------------------
+// Function: vdprintf
+//
+// Synopsis: Prints debug output using a pointer to the
+// variable information. Used primarily by the
+// xxDebugOut macros
+//
+// Arguements:
+// ulCompMask -- Component level mask used to determine
+// output ability
+// pszComp -- String const of component prefix.
+// ppszfmt -- Pointer to output format and data
+//
+//-------------------------------------------------------------
+
+//
+// This semaphore is *outside* vdprintf because the compiler isn't smart
+// enough to serialize access for construction if it's function-local and
+// protected by a guard variable.
+//
+// KyleP - 20 May, 1993
+//
+
+static CDLLStaticMutexSem mxs;
+
+STDAPI_(void) vdprintf(
+ unsigned long ulCompMask,
+ char const *pszComp,
+ char const *ppszfmt,
+ va_list pargs)
+{
+ if ((ulCompMask & DEB_FORCE) == DEB_FORCE ||
+ ((ulCompMask | Win4InfoLevel) & Win4InfoMask))
+ {
+#if defined( FLAT )
+ mxs.Request();
+ DWORD tid = GetCurrentThreadId();
+ DWORD pid = GetCurrentProcessId();
+ if ((Win4InfoLevel & (DEB_DBGOUT | DEB_STDOUT)) != DEB_STDOUT)
+#endif // FLAT
+ {
+ if (! (ulCompMask & DEB_NOCOMPNAME))
+ {
+#ifdef FLAT
+#if defined(_CHICAGO_)
+ //
+ // Hex Process/Thread ID's are better for Chicago since both
+ // actually memory addresses.
+ //
+ w4dprintf( "%08x.%08x> ", pid, tid );
+#else
+ w4dprintf( "%d.%03d> ", pid, tid );
+#endif
+#endif // FLAT
+ w4dprintf("%s: ", pszComp);
+ }
+ w4vdprintf(ppszfmt, pargs);
+ }
+
+#if defined( FLAT )
+ if (Win4InfoLevel & DEB_STDOUT)
+ {
+ if (! (ulCompMask & DEB_NOCOMPNAME))
+ {
+ w4printf( "%03d> ", tid );
+ w4printf("%s: ", pszComp);
+ }
+ w4vprintf(ppszfmt, pargs);
+ }
+
+ mxs.Release();
+#endif // FLAT
+ }
+}
+
+#else
+
+int assertDontUseThisName(void)
+{
+ return 1;
+}
+
+#endif // DBG == 1
diff --git a/private/oleutest/assert/daytona/makefile b/private/oleutest/assert/daytona/makefile
new file mode 100644
index 000000000..1d3728d41
--- /dev/null
+++ b/private/oleutest/assert/daytona/makefile
@@ -0,0 +1,10 @@
+############################################################################
+#
+# Copyright (C) 1992, Microsoft Corporation.
+#
+# All rights reserved.
+#
+############################################################################
+
+!include $(NTMAKEENV)\makefile.def
+
diff --git a/private/oleutest/assert/daytona/sources b/private/oleutest/assert/daytona/sources
new file mode 100644
index 000000000..d5c2b99a2
--- /dev/null
+++ b/private/oleutest/assert/daytona/sources
@@ -0,0 +1,80 @@
+!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:
+
+ David Plummer (davepl) 19-Mar-94
+
+ Modifed by via awk to include global project include file
+ and to wrap precompiled header line within a conditional
+ that can be set in this include file.
+
+ Donna Liu (DonnaLi) 19-Dec-1993
+
+!ENDIF
+
+MAJORCOMP = cairole
+MINORCOMP = com
+
+#
+# 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= Assert
+
+#
+# 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= LIBRARY
+
+
+#
+# The following includes a global include file defined at the
+# base of the project for all components
+#
+
+!include ..\..\..\ole32\daytona.inc
+
+INCLUDES= ..\..\..\ole32\common\daytona;..\..\..\ole32\ih;..;..\..\inc;..\..\..\ole32\..\cinc
+
+C_DEFINES= \
+ $(C_DEFINES) \
+
+
+SOURCES= \
+ ..\assert.cxx \
+ ..\dprintf.c \
+ ..\output.c \
+ ..\printf.c \
+ ..\sprintf.c
+
+# ..\wsprintf.c
+
+UMTYPE= windows
+UMAPPL=
+UMTEST=
+UMLIBS=
diff --git a/private/oleutest/assert/dirs b/private/oleutest/assert/dirs
new file mode 100644
index 000000000..1d0b9edbb
--- /dev/null
+++ b/private/oleutest/assert/dirs
@@ -0,0 +1,38 @@
+!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/assert/dprintf.c b/private/oleutest/assert/dprintf.c
new file mode 100644
index 000000000..71acbcaeb
--- /dev/null
+++ b/private/oleutest/assert/dprintf.c
@@ -0,0 +1,15 @@
+/***
+*dprintf.c - print formatted to debug port
+*
+* Copyright (c) 1985-1991, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* defines w4dprintf() - print formatted data to debug port
+* defines w4vdprintf() - print formatted output to debug port, get data
+* from an argument ptr instead of explicit args.
+*******************************************************************************/
+
+#include "dprintf.h" // function prototypes
+
+#define _W4DPRINTF_
+#include "printf.h"
diff --git a/private/oleutest/assert/dprintf.h b/private/oleutest/assert/dprintf.h
new file mode 100644
index 000000000..f4af83504
--- /dev/null
+++ b/private/oleutest/assert/dprintf.h
@@ -0,0 +1,33 @@
+//+---------------------------------------------------------------------------
+// Copyright (C) 1991, Microsoft Corporation.
+//
+// File: dprintf.h
+//
+// Contents: Debugging output routine function prototypes
+//
+// Functions: w4printf
+// w4vprintf
+// w4dprintf
+// w4vdprintf
+//
+// History: 18-Oct-91 vich Created
+//
+//----------------------------------------------------------------------------
+
+#include <stdarg.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef WIN32
+int _cdecl w4printf(const char *format, ...);
+int _cdecl w4vprintf(const char *format, va_list arglist);
+#endif
+
+int _cdecl w4dprintf(const char *format, ...);
+int _cdecl w4vdprintf(const char *format, va_list arglist);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/private/oleutest/assert/filelist.mk b/private/oleutest/assert/filelist.mk
new file mode 100644
index 000000000..43639d898
--- /dev/null
+++ b/private/oleutest/assert/filelist.mk
@@ -0,0 +1,57 @@
+############################################################################
+#
+# Copyright (C) 1992, Microsoft Corporation.
+#
+# 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 = port.lib
+
+RELEASE =
+
+
+#
+# Source files. Remember to prefix each name with .\
+#
+
+CXXFILES = .\assert.cxx \
+
+
+CFILES = \
+ .\dprintf.c \
+ .\output.c \
+ .\printf.c
+
+RCFILES =
+
+
+#
+# Libraries and other object files to link.
+#
+
+DEFFILE =
+
+
+LIBS =
+
+OBJFILES =
+
+#
+# Precompiled headers. Name of .cxx file compiled.
+#
+
+PXXFILE =
+PFILE =
+
+CINC = $(CINC) -I. -I..\inc -I$(COMMON)\src\commnot -I$(COMMON)\src\misc
+
+MTHREAD = 1
+
+MULTIDEPEND = MERGED
diff --git a/private/oleutest/assert/makefile b/private/oleutest/assert/makefile
new file mode 100644
index 000000000..7f4951e2a
--- /dev/null
+++ b/private/oleutest/assert/makefile
@@ -0,0 +1,25 @@
+############################################################################
+#
+# Copyright (C) 1992, Microsoft Corporation.
+#
+# All rights reserved.
+#
+############################################################################
+
+!ifdef NTMAKEENV
+
+# We need to do the following so that build will stop reading from the
+# pipe.
+
+all :
+ echo $(BUILDMSG)
+
+clean : all
+
+!else # NTMAKEENV
+
+!include $(CAIROLE)\com\makefile
+
+!include $(DEPENDFILE)
+
+!endif # NTMAKEENV
diff --git a/private/oleutest/assert/output.c b/private/oleutest/assert/output.c
new file mode 100644
index 000000000..63dbfb3b8
--- /dev/null
+++ b/private/oleutest/assert/output.c
@@ -0,0 +1,804 @@
+/***
+*output.c - printf style output to a struct w4io
+*
+* Copyright (c) 1989-1991, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* This file contains the code that does all the work for the
+* printf family of functions. It should not be called directly, only
+* by the *printf functions. We don't make any assumtions about the
+* sizes of ints, longs, shorts, or long doubles, but if types do overlap, we
+* also try to be efficient. We do assume that pointers are the same size
+* as either ints or longs.
+*
+*Revision History:
+* 06-01-89 PHG Module created
+* 08-28-89 JCR Added cast to get rid of warning (no object changes)
+* 02-15-90 GJF Fixed copyright
+* 10-03-90 WHB Defined LOCAL(x) to "static x" for local procedures
+*
+*******************************************************************************/
+
+#include <stdlib.h>
+#include <limits.h>
+#include <string.h>
+#include <stdarg.h>
+#include "wchar.h"
+#include "w4io.h"
+
+
+/* this macro defines a function which is private and as fast as possible: */
+/* for example, in C 6.0, it might be static _fastcall <type>. */
+#define LOCAL(x) static x // 100390--WHB
+
+#define NOFLOATS // Win 4 doesn't need floating point
+
+/* int/long/short/pointer sizes */
+
+/* the following should be set depending on the sizes of various types */
+// FLAT or LARGE model is assumed
+#ifdef FLAT
+# define LONG_IS_INT 1 /* 1 means long is same size as int */
+# define SHORT_IS_INT 0 /* 1 means short is same size as int */
+# define PTR_IS_INT 1 /* 1 means ptr is same size as int */
+# define PTR_IS_LONG 0 /* 1 means ptr is same size as long */
+#else // LARGE model
+# define LONG_IS_INT 0 /* 1 means long is same size as int */
+# define SHORT_IS_INT 1 /* 1 means short is same size as int */
+# define PTR_IS_INT 0 /* 1 means ptr is same size as int */
+# define PTR_IS_LONG 1 /* 1 means ptr is same size as long */
+#endif
+#define LONGDOUBLE_IS_DOUBLE 0 /* 1 means long double is same as double */
+
+#if LONG_IS_INT
+ #define get_long_arg(x) (long)get_int_arg(x)
+#endif
+
+#if PTR_IS_INT
+ #define get_ptr_arg(x) (void *)get_int_arg(x)
+#elif PTR_IS_LONG
+ #define get_ptr_arg(x) (void *)get_long_arg(x)
+#else
+ #error Size of pointer must be same as size of int or long
+#endif
+
+#ifndef NOFLOATS
+/* These are "fake" double and long doubles to fool the compiler,
+ so we don't drag in floating point. */
+typedef struct {
+ char x[sizeof(double)];
+} DOUBLE;
+typedef struct {
+ char x[sizeof(long double)];
+} LONGDOUBLE;
+#endif
+
+
+/* CONSTANTS */
+
+//#define BUFFERSIZE CVTBUFSIZE /* buffer size for maximum double conv */
+#define BUFFERSIZE 20
+
+/* flag definitions */
+#define FL_SIGN 0x0001 /* put plus or minus in front */
+#define FL_SIGNSP 0x0002 /* put space or minus in front */
+#define FL_LEFT 0x0004 /* left justify */
+#define FL_LEADZERO 0x0008 /* pad with leading zeros */
+#define FL_LONG 0x0010 /* long value given */
+#define FL_SHORT 0x0020 /* short value given */
+#define FL_SIGNED 0x0040 /* signed data given */
+#define FL_ALTERNATE 0x0080 /* alternate form requested */
+#define FL_NEGATIVE 0x0100 /* value is negative */
+#define FL_FORCEOCTAL 0x0200 /* force leading '0' for octals */
+#define FL_LONGDOUBLE 0x0400 /* long double value given */
+#define FL_WIDE 0x0800 /* wide character/string given */
+
+/* state definitions */
+enum STATE {
+ ST_NORMAL, /* normal state; outputting literal chars */
+ ST_PERCENT, /* just read '%' */
+ ST_FLAG, /* just read flag character */
+ ST_WIDTH, /* just read width specifier */
+ ST_DOT, /* just read '.' */
+ ST_PRECIS, /* just read precision specifier */
+ ST_SIZE, /* just read size specifier */
+ ST_TYPE /* just read type specifier */
+};
+#define NUMSTATES (ST_TYPE + 1)
+
+/* character type values */
+enum CHARTYPE {
+ CH_OTHER, /* character with no special meaning */
+ CH_PERCENT, /* '%' */
+ CH_DOT, /* '.' */
+ CH_STAR, /* '*' */
+ CH_ZERO, /* '0' */
+ CH_DIGIT, /* '1'..'9' */
+ CH_FLAG, /* ' ', '+', '-', '#' */
+ CH_SIZE, /* 'h', 'l', 'L', 'N', 'F' */
+ CH_TYPE /* type specifying character */
+};
+
+/* static data (read only, since we are re-entrant) */
+char *nullstring = "(null)"; /* string to print on null ptr */
+
+/* The state table. This table is actually two tables combined into one. */
+/* The lower nybble of each byte gives the character class of any */
+/* character; while the uper nybble of the byte gives the next state */
+/* to enter. See the macros below the table for details. */
+/* */
+/* The table is generated by maketab.c -- use the maketab program to make */
+/* changes. */
+
+static char lookuptable[] = {
+ 0x06, 0x00, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00,
+ 0x10, 0x00, 0x03, 0x06, 0x00, 0x06, 0x02, 0x10,
+ 0x04, 0x45, 0x45, 0x45, 0x05, 0x05, 0x05, 0x05,
+ 0x05, 0x35, 0x30, 0x00, 0x50, 0x00, 0x00, 0x00,
+ 0x00, 0x20, 0x28, 0x38, 0x50, 0x58, 0x07, 0x08,
+ 0x00, 0x30, 0x30, 0x30, 0x57, 0x50, 0x07, 0x00,
+ 0x00, 0x20, 0x20, 0x08, 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x00,
+ 0x00, 0x70, 0x70, 0x78, 0x78, 0x78, 0x78, 0x08,
+ 0x07, 0x08, 0x00, 0x00, 0x07, 0x00, 0x08, 0x08,
+ 0x08, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x07,
+ 0x08
+};
+
+#define find_char_class(c) \
+ ((c) < ' ' || (c) > 'x' ? \
+ CH_OTHER \
+ : \
+ lookuptable[(c)-' '] & 0xF)
+
+#define find_next_state(class, state) \
+ (lookuptable[(class) * NUMSTATES + (state)] >> 4)
+
+#if !LONG_IS_INT
+LOCAL(long) get_long_arg(va_list *pargptr);
+#endif
+LOCAL(int) get_int_arg(va_list *pargptr);
+LOCAL(void) writestring(char *string,
+ int len,
+ struct w4io *f,
+ int *pcchwritten,
+ int fwide);
+
+#ifndef NOFLOATS
+/* extern float convert routines */
+typedef int (* PFI)();
+extern PFI _cfltcvt_tab[5];
+#define _cfltcvt(a,b,c,d,e) (*_cfltcvt_tab[0])(a,b,c,d,e)
+#define _cropzeros(a) (*_cfltcvt_tab[1])(a)
+#define _fassign(a,b,c) (*_cfltcvt_tab[2])(a,b,c)
+#define _forcdecpt(a) (*_cfltcvt_tab[3])(a)
+#define _positive(a) (*_cfltcvt_tab[4])(a)
+#define _cldcvt(a,b,c,d,e) (*_cfltcvt_tab[5])(a,b,c,d,e)
+#endif
+
+
+/***
+*int w4iooutput(f, format, argptr)
+*
+*Purpose:
+* Output performs printf style output onto a stream. It is called by
+* printf/fprintf/sprintf/vprintf/vfprintf/vsprintf to so the dirty
+* work. In multi-thread situations, w4iooutput assumes that the given
+* stream is already locked.
+*
+* Algorithm:
+* The format string is parsed by using a finite state automaton
+* based on the current state and the current character read from
+* the format string. Thus, looping is on a per-character basis,
+* not a per conversion specifier basis. Once the format specififying
+* character is read, output is performed.
+*
+*Entry:
+* struct w4io *f - stream for output
+* char *format - printf style format string
+* va_list argptr - pointer to list of subsidiary arguments
+*
+*Exit:
+* Returns the number of characters written, or -1 if an output error
+* occurs.
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+int _cdecl w4iooutput(struct w4io *f, const char *format, va_list argptr)
+{
+ int hexadd; /* offset to add to number to get 'a'..'f' */
+ char ch; /* character just read */
+ wchar_t wc; /* wide character temp */
+ wchar_t *pwc; /* wide character temp pointer */
+ int flags; /* flag word -- see #defines above for flag values */
+ enum STATE state; /* current state */
+ enum CHARTYPE chclass; /* class of current character */
+ int radix; /* current conversion radix */
+ int charsout; /* characters currently written so far, -1 = IO error */
+ int fldwidth; /* selected field with -- 0 means default */
+ int fwide;
+ int precision; /* selected precision -- -1 means default */
+ char prefix[2]; /* numeric prefix -- up to two characters */
+ int prefixlen; /* length of prefix -- 0 means no prefix */
+ int capexp; /* non-zero = 'E' exponent signifiet, zero = 'e' */
+ int no_output; /* non-zero = prodcue no output for this specifier */
+ char *text; /* pointer text to be printed, not zero terminated */
+ int textlen; /* length of the text to be printed */
+ char buffer[BUFFERSIZE]; /* buffer for conversions */
+
+ charsout = 0; /* no characters written yet */
+ state = ST_NORMAL; /* starting state */
+
+ /* main loop -- loop while format character exist and no I/O errors */
+ while ((ch = *format++) != '\0' && charsout >= 0) {
+ chclass = find_char_class(ch); /* find character class */
+ state = find_next_state(chclass, state); /* find next state */
+
+ /* execute code for each state */
+ switch (state) {
+
+ case ST_NORMAL:
+ /* normal state -- just write character */
+ f->writechar(ch, 1, f, &charsout);
+ break;
+
+ case ST_PERCENT:
+ /* set default value of conversion parameters */
+ prefixlen = fldwidth = no_output = capexp = 0;
+ flags = 0;
+ precision = -1;
+ fwide = 0;
+ break;
+
+ case ST_FLAG:
+ /* set flag based on which flag character */
+ switch (ch) {
+ case '-':
+ flags |= FL_LEFT; /* '-' => left justify */
+ break;
+ case '+':
+ flags |= FL_SIGN; /* '+' => force sign indicator */
+ break;
+ case ' ':
+ flags |= FL_SIGNSP; /* ' ' => force sign or space */
+ break;
+ case '#':
+ flags |= FL_ALTERNATE; /* '#' => alternate form */
+ break;
+ case '0':
+ flags |= FL_LEADZERO; /* '0' => pad with leading zeros */
+ break;
+ }
+ break;
+
+ case ST_WIDTH:
+ /* update width value */
+ if (ch == '*') {
+ /* get width from arg list */
+ fldwidth = get_int_arg(&argptr);
+ if (fldwidth < 0) {
+ /* ANSI says neg fld width means '-' flag and pos width */
+ flags |= FL_LEFT;
+ fldwidth = -fldwidth;
+ }
+ }
+ else {
+ /* add digit to current field width */
+ fldwidth = fldwidth * 10 + (ch - '0');
+ }
+ break;
+
+ case ST_DOT:
+ /* zero the precision, since dot with no number means 0
+ not default, according to ANSI */
+ precision = 0;
+ break;
+
+ case ST_PRECIS:
+ /* update precison value */
+ if (ch == '*') {
+ /* get precision from arg list */
+ precision = get_int_arg(&argptr);
+ if (precision < 0)
+ precision = -1; /* neg precision means default */
+ }
+ else {
+ /* add digit to current precision */
+ precision = precision * 10 + (ch - '0');
+ }
+ break;
+
+ case ST_SIZE:
+ /* just read a size specifier, set the flags based on it */
+ switch (ch) {
+#if !LONG_IS_INT
+ case 'l':
+ flags |= FL_LONG; /* 'l' => long int */
+ break;
+#endif
+
+#if !LONGDOUBLE_IS_DOUBLE
+ case 'L':
+ flags |= FL_LONGDOUBLE; /* 'L' => long double */
+ break;
+#endif
+
+#if !SHORT_IS_INT
+ case 'h':
+ flags |= FL_SHORT; /* 'h' => short int */
+ break;
+#endif
+ case 'w':
+ flags |= FL_WIDE; /* 'w' => wide character */
+ break;
+ }
+ break;
+
+ case ST_TYPE:
+ /* we have finally read the actual type character, so we */
+ /* now format and "print" the output. We use a big switch */
+ /* statement that sets 'text' to point to the text that should */
+ /* be printed, and 'textlen' to the length of this text. */
+ /* Common code later on takes care of justifying it and */
+ /* other miscellaneous chores. Note that cases share code, */
+ /* in particular, all integer formatting is doen in one place. */
+ /* Look at those funky goto statements! */
+
+ switch (ch) {
+
+ case 'c': {
+ /* print a single character specified by int argument */
+ wc = (wchar_t) get_int_arg(&argptr); /* get char to print */
+ * (wchar_t *) buffer = wc;
+ text = buffer;
+ textlen = 1; /* print just a single character */
+ }
+ break;
+
+ case 'S': {
+ /* print a Counted String */
+
+ struct string {
+ short Length;
+ short MaximumLength;
+ char *Buffer;
+ } *pstr;
+
+ pstr = get_ptr_arg(&argptr);
+ if (pstr == NULL || pstr->Buffer == NULL) {
+ /* null ptr passed, use special string */
+ text = nullstring;
+ textlen = strlen(text);
+ flags &= ~FL_WIDE;
+ } else {
+ text = pstr->Buffer;
+ /* The length field is a count of bytes, not characters. */
+ if (flags & FL_WIDE)
+ textlen = pstr->Length / sizeof( wchar_t );
+ else
+ textlen = pstr->Length;
+ if (precision != -1)
+ textlen = min( textlen, precision );
+ }
+
+ }
+ break;
+
+ case 's': {
+ /* print a string -- */
+ /* ANSI rules on how much of string to print: */
+ /* all if precision is default, */
+ /* min(precision, length) if precision given. */
+ /* prints '(null)' if a null string is passed */
+
+ int i;
+ char *p; /* temps */
+
+ text = get_ptr_arg(&argptr);
+ if (text == NULL) {
+ /* null ptr passed, use special string */
+ text = nullstring;
+ flags &= ~FL_WIDE;
+ }
+
+ /* At this point it is tempting to use strlen(), but */
+ /* if a precision is specified, we're not allowed to */
+ /* scan past there, because there might be no null */
+ /* at all. Thus, we must do our own scan. */
+
+ i = (precision == -1) ? INT_MAX : precision;
+
+ /* scan for null upto i characters */
+ if (flags & FL_WIDE) {
+ pwc = (wchar_t *) text;
+ while (i-- && (wc = *pwc) && (wc & 0x00ff)) {
+ ++pwc;
+ if (wc & 0xff00) { // if high byte set,
+ break; // error will be indicated
+ }
+ }
+ textlen = pwc - (wchar_t *) text; /* length of string */
+ } else {
+ p = text;
+ while (i-- && *p) {
+ ++p;
+ }
+ textlen = p - text; /* length of the string */
+ }
+ }
+ break;
+
+ case 'n': {
+ /* write count of characters seen so far into */
+ /* short/int/long thru ptr read from args */
+
+ void *p; /* temp */
+
+ p = get_ptr_arg(&argptr);
+
+ /* store chars out into short/long/int depending on flags */
+#if !LONG_IS_INT
+ if (flags & FL_LONG)
+ *(long *)p = charsout;
+ else
+#endif
+
+#if !SHORT_IS_INT
+ if (flags & FL_SHORT)
+ *(short *)p = (short) charsout;
+ else
+#endif
+ *(int *)p = charsout;
+
+ no_output = 1; /* force no output */
+ }
+ break;
+
+
+#ifndef NOFLOATS
+ case 'E':
+ case 'G':
+ capexp = 1; /* capitalize exponent */
+ ch += 'a' - 'A'; /* convert format char to lower */
+ /* DROP THROUGH */
+ case 'e':
+ case 'f':
+ case 'g': {
+ /* floating point conversion -- we call cfltcvt routines */
+ /* to do the work for us. */
+ flags |= FL_SIGNED; /* floating point is signed conversion */
+ text = buffer; /* put result in buffer */
+ flags &= ~FL_WIDE; /* 8 bit string */
+
+ /* compute the precision value */
+ if (precision < 0)
+ precision = 6; /* default precision: 6 */
+ else if (precision == 0 && ch == 'g')
+ precision = 1; /* ANSI specified */
+
+#if !LONGDOUBLE_IS_DOUBLE
+ /* do the conversion */
+ if (flags & FL_LONGDOUBLE) {
+ _cldcvt(argptr, text, ch, precision, capexp);
+ va_arg(argptr, LONGDOUBLE);
+ }
+ else
+#endif
+ {
+ _cfltcvt(argptr, text, ch, precision, capexp);
+ va_arg(argptr, DOUBLE);
+ }
+
+ /* '#' and precision == 0 means force a decimal point */
+ if ((flags & FL_ALTERNATE) && precision == 0)
+ _forcdecpt(text);
+
+ /* 'g' format means crop zero unless '#' given */
+ if (ch == 'g' && !(flags & FL_ALTERNATE))
+ _cropzeros(text);
+
+ /* check if result was negative, save '-' for later */
+ /* and point to positive part (this is for '0' padding) */
+ if (*text == '-') {
+ flags |= FL_NEGATIVE;
+ ++text;
+ }
+
+ textlen = strlen(text); /* compute length of text */
+ }
+ break;
+#endif // NOFLOATS
+
+ case 'd':
+ case 'i':
+ /* signed decimal output */
+ flags |= FL_SIGNED;
+ radix = 10;
+ goto COMMON_INT;
+
+ case 'u':
+ radix = 10;
+ goto COMMON_INT;
+
+ case 'p':
+ /* write a pointer -- this is like an integer or long */
+ /* except we force precision to pad with zeros and */
+ /* output in big hex. */
+
+ precision = 2 * sizeof(void *); /* number of hex digits needed */
+#if !PTR_IS_INT
+ flags |= FL_LONG; /* assume we're converting a long */
+#endif
+ /* DROP THROUGH to hex formatting */
+
+ case 'C':
+ case 'X':
+ /* unsigned upper hex output */
+ hexadd = 'A' - '9' - 1; /* set hexadd for uppercase hex */
+ goto COMMON_HEX;
+
+ case 'x':
+ /* unsigned lower hex output */
+ hexadd = 'a' - '9' - 1; /* set hexadd for lowercase hex */
+ /* DROP THROUGH TO COMMON_HEX */
+
+ COMMON_HEX:
+ radix = 16;
+ if (flags & FL_ALTERNATE) {
+ /* alternate form means '0x' prefix */
+ prefix[0] = '0';
+ prefix[1] = (char)('x' - 'a' + '9' + 1 + hexadd); /* 'x' or 'X' */
+ prefixlen = 2;
+ }
+ goto COMMON_INT;
+
+ case 'o':
+ /* unsigned octal output */
+ radix = 8;
+ if (flags & FL_ALTERNATE) {
+ /* alternate form means force a leading 0 */
+ flags |= FL_FORCEOCTAL;
+ }
+ /* DROP THROUGH to COMMON_INT */
+
+ COMMON_INT: {
+ /* This is the general integer formatting routine. */
+ /* Basically, we get an argument, make it positive */
+ /* if necessary, and convert it according to the */
+ /* correct radix, setting text and textlen */
+ /* appropriately. */
+
+ unsigned long number; /* number to convert */
+ int digit; /* ascii value of digit */
+ long l; /* temp long value */
+
+ /* 1. read argument into l, sign extend as needed */
+#if !LONG_IS_INT
+ if (flags & FL_LONG)
+ l = get_long_arg(&argptr);
+ else
+#endif
+
+#if !SHORT_IS_INT
+ if (flags & FL_SHORT) {
+ if (flags & FL_SIGNED)
+ l = (short) get_int_arg(&argptr); /* sign extend */
+ else
+ l = (unsigned short) get_int_arg(&argptr); /* zero-extend*/
+ }
+ else
+#endif
+ {
+ if (flags & FL_SIGNED)
+ l = get_int_arg(&argptr); /* sign extend */
+ else
+ l = (unsigned int) get_int_arg(&argptr); /* zero-extend*/
+ }
+
+ /* 2. check for negative; copy into number */
+ if ( (flags & FL_SIGNED) && l < 0) {
+ number = -l;
+ flags |= FL_NEGATIVE; /* remember negative sign */
+ }
+ else {
+ number = l;
+ }
+
+ /* 3. check precision value for default; non-default */
+ /* turns off 0 flag, according to ANSI. */
+ if (precision < 0)
+ precision = 1; /* default precision */
+ else
+ flags &= ~FL_LEADZERO;
+
+ /* 4. Check if data is 0; if so, turn off hex prefix */
+ if (number == 0)
+ prefixlen = 0;
+
+ /* 5. Convert data to ASCII -- note if precision is zero */
+ /* and number is zero, we get no digits at all. */
+
+ text = &buffer[BUFFERSIZE-1]; // last digit at end of buffer
+ flags &= ~FL_WIDE; // 8 bit characters
+
+ while (precision-- > 0 || number != 0) {
+ digit = (int)(number % radix) + '0';
+ number /= radix; /* reduce number */
+ if (digit > '9') {
+ /* a hex digit, make it a letter */
+ digit += hexadd;
+ }
+ *text-- = (char)digit; /* store the digit */
+ }
+
+ textlen = (char *)&buffer[BUFFERSIZE-1] - text; /* compute length of number */
+ ++text; /* text points to first digit now */
+
+
+ /* 6. Force a leading zero if FORCEOCTAL flag set */
+ if ((flags & FL_FORCEOCTAL) && (text[0] != '0' || textlen == 0)) {
+ *--text = '0';
+ ++textlen; /* add a zero */
+ }
+ }
+ break;
+ }
+
+ /* At this point, we have done the specific conversion, and */
+ /* 'text' points to text to print; 'textlen' is length. Now we */
+ /* justify it, put on prefixes, leading zeros, and then */
+ /* print it. */
+
+ if (!no_output) {
+ int padding; /* amount of padding, negative means zero */
+
+ if (flags & FL_SIGNED) {
+ if (flags & FL_NEGATIVE) {
+ /* prefix is a '-' */
+ prefix[0] = '-';
+ prefixlen = 1;
+ }
+ else if (flags & FL_SIGN) {
+ /* prefix is '+' */
+ prefix[0] = '+';
+ prefixlen = 1;
+ }
+ else if (flags & FL_SIGNSP) {
+ /* prefix is ' ' */
+ prefix[0] = ' ';
+ prefixlen = 1;
+ }
+ }
+
+ /* calculate amount of padding -- might be negative, */
+ /* but this will just mean zero */
+ padding = fldwidth - textlen - prefixlen;
+
+ /* put out the padding, prefix, and text, in the correct order */
+
+ if (!(flags & (FL_LEFT | FL_LEADZERO))) {
+ /* pad on left with blanks */
+ f->writechar(' ', padding, f, &charsout);
+ }
+
+ /* write prefix */
+ writestring(prefix, prefixlen, f, &charsout, 0);
+
+ if ((flags & FL_LEADZERO) && !(flags & FL_LEFT)) {
+ /* write leading zeros */
+ f->writechar('0', padding, f, &charsout);
+ }
+
+ /* write text */
+ writestring(text, textlen, f, &charsout, flags & FL_WIDE);
+
+ if (flags & FL_LEFT) {
+ /* pad on right with blanks */
+ f->writechar(' ', padding, f, &charsout);
+ }
+
+ /* we're done! */
+ }
+ break;
+ }
+ }
+
+ return charsout; /* return value = number of characters written */
+}
+
+
+/***
+*int get_int_arg(va_list pargptr)
+*
+*Purpose:
+* Gets an int argument off the given argument list and updates *pargptr.
+*
+*Entry:
+* va_list pargptr - pointer to argument list; updated by function
+*
+*Exit:
+* Returns the integer argument read from the argument list.
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+LOCAL(int) get_int_arg(va_list *pargptr)
+{
+ return va_arg(*pargptr, int);
+}
+
+/***
+*long get_long_arg(va_list pargptr)
+*
+*Purpose:
+* Gets an long argument off the given argument list and updates pargptr.
+*
+*Entry:
+* va_list pargptr - pointer to argument list; updated by function
+*
+*Exit:
+* Returns the long argument read from the argument list.
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+
+#if !LONG_IS_INT
+LOCAL(long) get_long_arg(va_list *pargptr)
+{
+ return va_arg(*pargptr, long);
+}
+#endif
+
+
+
+/***
+*void writestring(char *string, int len, struct w4io *f, int *pcchwritten, int fwide)
+*
+*Purpose:
+* Writes a string of the given length to the given file. If no error occurs,
+* then *pcchwritten is incremented by len; otherwise, *pcchwritten is set
+* to -1. If len is negative, it is treated as zero.
+*
+*Entry:
+* char *string - string to write (NOT null-terminated)
+* int len - length of string
+* struct w4io *f - file to write to
+* int *pcchwritten - pointer to integer to update with total chars written
+* int fwide - wide character flag
+*
+*Exit:
+* No return value.
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+LOCAL(void) writestring(
+ char *string,
+ int len,
+ struct w4io *f,
+ int *pcchwritten,
+ int fwide)
+{
+ wchar_t *pwc;
+
+ //printf("string: str=%.*s, len=%d, cch=%d, f=%d\n", len, string, len, *pcchwritten, fwide);
+ if (fwide) {
+ pwc = (wchar_t *) string;
+ while (len-- > 0) {
+ if (*pwc & 0xff00) {
+ f->writechar('^', 1, f, pcchwritten);
+ }
+ f->writechar((char) *pwc++, 1, f, pcchwritten);
+ }
+ } else {
+ while (len-- > 0) {
+ f->writechar(*string++, 1, f, pcchwritten);
+ }
+ }
+}
diff --git a/private/oleutest/assert/printf.c b/private/oleutest/assert/printf.c
new file mode 100644
index 000000000..9d6f6403e
--- /dev/null
+++ b/private/oleutest/assert/printf.c
@@ -0,0 +1,17 @@
+/***
+*printf.c - print formatted to stdout
+*
+* Copyright (c) 1985-1991, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* defines w4printf() - print formatted data to stdout
+* defines w4vprintf() - print formatted output to stdout, get data
+* from an argument ptr instead of explicit args.
+*******************************************************************************/
+
+#ifdef FLAT
+#include "dprintf.h" // function prototypes
+
+#define _W4PRINTF_
+#include "printf.h"
+#endif
diff --git a/private/oleutest/assert/printf.h b/private/oleutest/assert/printf.h
new file mode 100644
index 000000000..2a03d6b64
--- /dev/null
+++ b/private/oleutest/assert/printf.h
@@ -0,0 +1,245 @@
+/***
+*printf.h - print formatted
+*
+* Copyright (c) 1985-1991, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* defines w4*printf() - print formatted data
+* defines w4v*printf() - print formatted output, get data from an
+* argument ptr instead of explicit args.
+*
+*Revision History:
+* 09-02-83 RN original sprintf
+* 06-17-85 TC rewrote to use new varargs macros, and to be vsprintf
+* 04-13-87 JCR added const to declaration
+* 11-07-87 JCR Multi-thread support
+* 12-11-87 JCR Added "_LOAD_DS" to declaration
+* 05-27-88 PHG Merged DLL and normal versions
+* 06-13-88 JCR Fake _iob entry is now static so that other routines
+* can assume _iob entries are in DGROUP.
+* 08-25-88 GJF Define MAXSTR to be INT_MAX (from LIMITS.H).
+* 06-06-89 JCR 386 mthread support
+* 08-18-89 GJF Clean up, now specific to OS/2 2.0 (i.e., 386 WIN32
+* model). Also fixed copyright and indents.
+* 02-16-90 GJF Fixed copyright
+*
+*******************************************************************************/
+
+#include <windows.h>
+#include <wchar.h>
+#include <stdarg.h>
+#include <limits.h>
+#include "w4io.h"
+
+#if defined(_W4PRINTF_)
+ static long fh;
+// extern long GetStdHandle(long);
+// extern void WriteFile(long fh, char *s, long cch, long * pcchret, long);
+# define _PRINTF_
+#elif defined(_W4DPRINTF_)
+# define _pwritechar _dwritechar
+# define _pflushbuf _dflushbuf
+# define w4printf w4dprintf
+# define w4vprintf w4vdprintf
+# define _PRINTF_
+#elif defined(_W4SPRINTF_)
+# define _pwritechar _swritechar
+# define w4printf w4sprintf
+# define w4vprintf w4vsprintf
+#elif defined(_W4WCSPRINTF_)
+# define _TCHAR_ wchar_t
+# define _PBUF_ pwcbuf
+# define _PSTART_ pwcstart
+# define w4printf w4wcsprintf
+# define w4vprintf w4vwcsprintf
+# define _pwritechar _wwritechar
+#else
+# error configuration problem
+#endif
+
+#ifndef _TCHAR_
+# define _TCHAR_ char
+# define _PBUF_ pchbuf
+# define _PSTART_ pchstart
+#endif
+
+
+#ifdef _PRINTF_
+# ifdef WIN32
+# undef OutputDebugString
+# define OutputDebugString OutputDebugStringA
+# else
+ extern void _pascal OutputDebugString(char *);
+# endif
+ int _cdecl _pflushbuf(struct w4io *f);
+# define SPR(a)
+# define MAXSTR 128
+#else
+# define SPR(a) a,
+# define MAXSTR INT_MAX
+#endif
+
+void _cdecl _pwritechar(int ch, int num, struct w4io *f, int *pcchwritten);
+int _cdecl w4vprintf(SPR(_TCHAR_ *string) const char *format, va_list arglist);
+
+
+/***
+*int w4printf(format, ...) - print formatted data
+*
+*Purpose:
+* Prints formatted data using the format string to
+* format data and getting as many arguments as called for
+* Sets up a w4io so file i/o operations can be used.
+* w4iooutput does the real work here
+*
+*Entry:
+* char *format - format string to control data format/number
+* of arguments followed by list of arguments, number and type
+* controlled by format string
+*
+*Exit:
+* returns number of characters written
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+
+int _cdecl
+w4printf(SPR(_TCHAR_ *string) const char *format, ...)
+/*
+ * 'PRINT', 'F'ormatted
+ */
+{
+ va_list arglist;
+
+ va_start(arglist, format);
+ return(w4vprintf(SPR(string) format, arglist));
+}
+
+
+/***
+*int w4vprintf(format, arglist) - print formatted data from arg ptr
+*
+*Purpose:
+* Prints formatted data, but gets data from an argument pointer.
+* Sets up a w4io so file i/o operations can be used, make string look
+* like a huge buffer to it, but _flsbuf will refuse to flush it if it
+* fills up. Appends '\0' to make it a true string.
+*
+* Multi-thread: (1) Since there is no stream, this routine must never try
+* to get the stream lock (i.e., there is no stream lock either). (2)
+* Also, since there is only one staticly allocated 'fake' iob, we must
+* lock/unlock to prevent collisions.
+*
+*Entry:
+* char *format - format string, describes format of data
+* va_list arglist - varargs argument pointer
+*
+*Exit:
+* returns number of characters written
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+int _cdecl
+w4vprintf(SPR(_TCHAR_ *string) const char *format, va_list arglist)
+/*
+ * 'V'ariable argument 'PRINT', 'F'ormatted
+ */
+{
+ struct w4io outfile;
+ register int retval;
+#ifdef _PRINTF_
+ char string[MAXSTR + 1]; // leave room for null termination
+#else
+ int dummy;
+#endif
+
+#ifdef _W4PRINTF_
+ long ldummy;
+
+ if (fh == 0 || fh == -1)
+ {
+ ldummy = -11; // C7 bug workaround
+ if ((fh = (long)GetStdHandle(ldummy)) == 0 || fh == -1)
+ {
+ OutputDebugString("GetStdHandle in " __FILE__ " failed\n");
+ return(-1);
+ }
+ }
+#endif
+
+ outfile._PBUF_ = outfile._PSTART_ = string;
+ outfile.cchleft = MAXSTR;
+ outfile.writechar = _pwritechar;
+
+ retval = w4iooutput(&outfile, format, arglist);
+
+#ifdef _PRINTF_
+ if (_pflushbuf(&outfile) == -1) {
+ return(-1);
+ }
+#else
+ _pwritechar('\0', 1, &outfile, &dummy);
+#endif
+ return(retval);
+}
+
+
+void _cdecl _pwritechar(int ch, int num, struct w4io *f, int *pcchwritten)
+{
+ //printf(" char: ch=%c, cnt=%d, cch=%d\n", ch, num, *pcchwritten);
+ while (num-- > 0) {
+#ifdef _PRINTF_
+ if (f->cchleft < 2 && _pflushbuf(f) == -1) {
+ *pcchwritten = -1;
+ return;
+ }
+#endif
+#ifdef _W4DPRINTF_
+# ifndef WIN32
+ if (ch == '\n')
+ {
+ *f->_PBUF_++ = '\r';
+ f->cchleft--;
+ (*pcchwritten)++;
+ }
+# endif
+#endif
+ *f->_PBUF_++ = (char) ch;
+ f->cchleft--;
+ (*pcchwritten)++;
+ }
+}
+
+
+#ifdef _PRINTF_
+int _cdecl _pflushbuf(struct w4io *f)
+{
+ int cch;
+
+ if (cch = (f->pchbuf - f->pchstart))
+ {
+#ifdef _W4DPRINTF_
+ *f->pchbuf = '\0'; // null terminate
+ OutputDebugString(f->pchstart);
+#else
+ long cchret;
+
+ //*f->pchbuf = '\0'; // null terminate
+ //printf("%d chars: \"%s\"\n", cch, f->pchstart);
+ WriteFile((HANDLE)fh, f->pchstart, cch, &cchret, 0);
+ if (cch != cchret)
+ {
+ OutputDebugString("WriteFile in " __FILE__ " failed\n");
+ return(-1);
+ }
+#endif
+ f->pchbuf -= cch; // reset pointer
+ f->cchleft += cch; // reset count
+ }
+ return(0);
+}
+#endif // _PRINTF_
diff --git a/private/oleutest/assert/sprintf.c b/private/oleutest/assert/sprintf.c
new file mode 100644
index 000000000..8fa23b0f4
--- /dev/null
+++ b/private/oleutest/assert/sprintf.c
@@ -0,0 +1,13 @@
+/***
+*sprintf.c - print formatted to string
+*
+* Copyright (c) 1985-1991, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* defines w4sprintf() - print formatted data to string
+* defines w4vsprintf() - print formatted output to a string, get data
+* from an argument ptr instead of explicit args.
+*******************************************************************************/
+
+#define _W4SPRINTF_
+#include "printf.h"
diff --git a/private/oleutest/assert/w4io.h b/private/oleutest/assert/w4io.h
new file mode 100644
index 000000000..e88fd62b4
--- /dev/null
+++ b/private/oleutest/assert/w4io.h
@@ -0,0 +1,49 @@
+/***
+*w4io.h - fake FILE structure for Win 4 printf/sprintf/debug printf support
+*
+*/
+
+#if defined(M_I386) || defined(WIN32)
+# ifndef WIN32
+# define WIN32
+# endif
+#elif !defined(M_I86LM)
+# error Must be FLAT or LARGE model.
+#endif
+
+#ifndef NULL
+# define NULL 0
+#endif
+
+struct w4io
+{
+ union
+ {
+ struct
+ {
+ wchar_t *_pwcbuf; // wchar_t output buffer
+ wchar_t *_pwcstart;
+ } wc;
+ struct
+ {
+ char *_pchbuf; // char output buffer
+ char *_pchstart;
+ } ch;
+ } buf ;
+ unsigned int cchleft; // output buffer character count
+ void (_cdecl *writechar)(int ch,
+ int num,
+ struct w4io *f,
+ int *pcchwritten);
+};
+
+#define pwcbuf buf.wc._pwcbuf
+#define pwcstart buf.wc._pwcstart
+#define pchbuf buf.ch._pchbuf
+#define pchstart buf.ch._pchstart
+
+#define REG1 register
+#define REG2 register
+
+/* prototypes */
+int _cdecl w4iooutput(struct w4io *stream, const char *format, va_list argptr);
diff --git a/private/oleutest/assert/wsprintf.c b/private/oleutest/assert/wsprintf.c
new file mode 100644
index 000000000..83a74fb76
--- /dev/null
+++ b/private/oleutest/assert/wsprintf.c
@@ -0,0 +1,14 @@
+/***
+*sprintf.c - print formatted to string
+*
+* Copyright (c) 1985-1991, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* defines w4wcsprintf() - print formatted data to wide character string
+* defines w4vwcsprintf() - print formatted output to a wide character
+* string, get data from argument ptr instead
+* of explicit args.
+*******************************************************************************/
+
+#define _W4WCSPRINTF_
+#include "printf.h"
diff --git a/private/oleutest/balls/cairo.inc b/private/oleutest/balls/cairo.inc
new file mode 100644
index 000000000..bc59a5677
--- /dev/null
+++ b/private/oleutest/balls/cairo.inc
@@ -0,0 +1,38 @@
+# This is the global include file for the daytona version of CairOLE.
+# It is included by all project sources files.
+
+MAJORCOMP = oletest
+MINORCOMP = com
+
+OLEDIR= $(BASEDIR)\private\ole32
+OLEUTESTDIR= $(BASEDIR)\private\oleutest
+
+INCLUDES= ..\;($BASEDIR)\cinc;$(OLEUTESTDIR)\oleprx32\proxy
+INCLUDES= $(INCLUDES);$(OLEUTESTDIR)\balls\common
+
+C_DEFINES= \
+ $(C_DEFINES) \
+ -DFLAT \
+ -DUNICODE \
+ -D_UNICODE \
+ -DINC_OLE2 \
+ -DNOEXCEPTIONS \
+ -DWIN32=300 \
+ -D_NT1X_=100 \
+ -DCAIROLE_DOWNLEVEL \
+ -D_CAIRO_=300 \
+ -D_DCOM_ \
+ -DTHREADING_SUPPORT \
+ $(TRACELOG)
+
+
+BLDCRT= 1
+
+# For the Daytona build, we do not want statically linked compiler runtimes,
+# so leave this commented out.
+#
+# USE_LIBCMT= 1
+
+CAIRO_PRODUCT=1
+
+USE_CRTDLL=1
diff --git a/private/oleutest/balls/cballs.reg b/private/oleutest/balls/cballs.reg
new file mode 100644
index 000000000..005111324
--- /dev/null
+++ b/private/oleutest/balls/cballs.reg
@@ -0,0 +1,97 @@
+REGEDIT
+HKEY_CLASSES_ROOT\CLSID
+HKEY_CLASSES_ROOT\Interface
+
+
+HKEY_CLASSES_ROOT\CLSID\{00000138-0001-0008-C000-000000000046} = CPrxyBalls
+HKEY_CLASSES_ROOT\CLSID\{00000138-0001-0008-C000-000000000046}\InprocServer32 = d:\sur1173\dump\iballs.dll
+
+HKEY_CLASSES_ROOT\Interface\{00000138-0001-0008-C000-000000000046} = IBalls
+HKEY_CLASSES_ROOT\Interface\{00000138-0001-0008-C000-000000000046}\ProxyStubClsid32 = {00000138-0001-0008-C000-000000000046}
+
+HKEY_CLASSES_ROOT\Interface\{00000139-0001-0008-C000-000000000046} = ICube
+HKEY_CLASSES_ROOT\Interface\{00000139-0001-0008-C000-000000000046}\ProxyStubClsid32 = {00000138-0001-0008-C000-000000000046}
+
+HKEY_CLASSES_ROOT\Interface\{00000136-0001-0008-C000-000000000046} = ILoops
+HKEY_CLASSES_ROOT\Interface\{00000136-0001-0008-C000-000000000046}\ProxyStubClsid32 = {00000138-0001-0008-C000-000000000046}
+
+HKEY_CLASSES_ROOT\Interface\{00000137-0001-0008-C000-000000000046} = IRpcTest
+HKEY_CLASSES_ROOT\Interface\{00000137-0001-0008-C000-000000000046}\ProxyStubClsid32 = {00000138-0001-0008-C000-000000000046}
+
+
+
+
+
+HKEY_CLASSES_ROOT\CLSID\{0000013a-0001-0008-C000-000000000046} = CBallsClassFactory
+HKEY_CLASSES_ROOT\CLSID\{0000013a-0001-0008-C000-000000000046}\LocalServer32 = d:\sur1173\dump\ballsrv.exe
+HKEY_CLASSES_ROOT\CLSID\{0000013a-0001-0008-C000-000000000046}\ProgID = ProgID60
+
+HKEY_CLASSES_ROOT\CLSID\{0000013b-0001-0008-C000-000000000046} = CCubesClassFactory
+HKEY_CLASSES_ROOT\CLSID\{0000013b-0001-0008-C000-000000000046}\LocalServer32 = d:\sur1173\dump\cubesrv.exe
+
+HKEY_CLASSES_ROOT\CLSID\{0000013c-0001-0008-C000-000000000046} = CLoopClassFactory
+HKEY_CLASSES_ROOT\CLSID\{0000013c-0001-0008-C000-000000000046}\LocalServer32 = d:\sur1173\dump\loopsrv.exe
+
+HKEY_CLASSES_ROOT\CLSID\{0000013d-0001-0008-C000-000000000046} = CRpcTestClassFactory
+HKEY_CLASSES_ROOT\CLSID\{0000013d-0001-0008-C000-000000000046}\LocalServer32 = d:\sur1173\dump\rpctst.exe
+
+HKEY_CLASSES_ROOT\CLSID\{0000013e-0001-0008-C000-000000000046} = ICubesHandCraftedProxy
+HKEY_CLASSES_ROOT\CLSID\{0000013e-0001-0008-C000-000000000046}\InprocServer32 = d:\sur1173\dump\myproxy.dll
+
+HKEY_CLASSES_ROOT\CLSID\{00000140-0000-0008-C000-000000000046} = CQueryInterface
+HKEY_CLASSES_ROOT\CLSID\{00000140-0000-0008-C000-000000000046}\LocalServer32 = d:\sur1173\dump\qisrv.exe
+HKEY_CLASSES_ROOT\CLSID\{00000140-0000-0008-C000-000000000046}\InprocServer32 = d:\sur1173\dump\qisrv.dll
+
+HKEY_CLASSES_ROOT\CLSID\{00000141-0000-0008-C000-000000000046} = CQueryInterfaceHandler
+HKEY_CLASSES_ROOT\CLSID\{00000141-0000-0008-C000-000000000046}\LocalServer32 = d:\sur1173\dump\qisrv.exe
+HKEY_CLASSES_ROOT\CLSID\{00000141-0000-0008-C000-000000000046}\InprocHandler32 = ole32.dll
+
+HKEY_CLASSES_ROOT\.ut4 = ProgID50
+HKEY_CLASSES_ROOT\.ut5 = ProgID51
+HKEY_CLASSES_ROOT\.ut6 = ProgID52
+HKEY_CLASSES_ROOT\.ut7 = ProgID53
+HKEY_CLASSES_ROOT\.ut8 = ProgID54
+HKEY_CLASSES_ROOT\.ut9 = ProgID55
+HKEY_CLASSES_ROOT\.bls = ProgID60
+
+
+HKEY_CLASSES_ROOT\CLSID\{99999999-0000-0008-C000-000000000050} = SDI
+HKEY_CLASSES_ROOT\CLSID\{99999999-0000-0008-C000-000000000050}\LocalServer32 = d:\sur1173\dump\sdi.exe
+
+HKEY_CLASSES_ROOT\CLSID\{99999999-0000-0008-C000-000000000051} = MDI
+HKEY_CLASSES_ROOT\CLSID\{99999999-0000-0008-C000-000000000051}\LocalServer32 = d:\sur1173\dump\mdi.exe
+
+HKEY_CLASSES_ROOT\CLSID\{99999999-0000-0008-C000-000000000052} = InprocNoRegister
+HKEY_CLASSES_ROOT\CLSID\{99999999-0000-0008-C000-000000000052}\InprocServer32 = d:\sur1173\dump\dlltest.dll
+
+HKEY_CLASSES_ROOT\CLSID\{99999999-0000-0008-C000-000000000053} = InprocRegister
+HKEY_CLASSES_ROOT\CLSID\{99999999-0000-0008-C000-000000000053}\InprocServer32 = d:\sur1173\dump\dlltest.dll
+
+HKEY_CLASSES_ROOT\CLSID\{99999999-0000-0008-C000-000000000054} = InprocRegister
+HKEY_CLASSES_ROOT\CLSID\{99999999-0000-0008-C000-000000000054}\TreatAs = {99999999-0000-0008-C000-000000000050}
+
+HKEY_CLASSES_ROOT\CLSID\{99999999-0000-0008-C000-000000000055} = MDI
+HKEY_CLASSES_ROOT\CLSID\{99999999-0000-0008-C000-000000000055}\LocalServer32 = d:\sur1173\dump\db.exe
+HKEY_CLASSES_ROOT\CLSID\{99999999-0000-0008-C000-000000000055}\ActivateAtBits = Y
+
+
+HKEY_CLASSES_ROOT\ProgID50 = objact sdi
+HKEY_CLASSES_ROOT\ProgID50\CLSID = {99999999-0000-0008-C000-000000000050}
+
+HKEY_CLASSES_ROOT\ProgID51 = objact mdi
+HKEY_CLASSES_ROOT\ProgID51\CLSID = {99999999-0000-0008-C000-000000000051}
+
+HKEY_CLASSES_ROOT\ProgID52 = objact dll
+HKEY_CLASSES_ROOT\ProgID52\CLSID = {99999999-0000-0008-C000-000000000052}
+
+HKEY_CLASSES_ROOT\ProgID53 = objact dll reg
+HKEY_CLASSES_ROOT\ProgID53\CLSID = {99999999-0000-0008-C000-000000000053}
+
+HKEY_CLASSES_ROOT\ProgID54 = objact dll reg
+HKEY_CLASSES_ROOT\ProgID54\CLSID = {99999999-0000-0008-C000-000000000054}
+
+HKEY_CLASSES_ROOT\ProgID55 = remote activation
+HKEY_CLASSES_ROOT\ProgID55\CLSID = {99999999-0000-0008-C000-000000000055}
+
+HKEY_CLASSES_ROOT\ProgID60 = CLSIDFromProgID test
+HKEY_CLASSES_ROOT\ProgID60\CLSID = {0000013a-0001-0008-C000-000000000046}
diff --git a/private/oleutest/balls/chicago.inc b/private/oleutest/balls/chicago.inc
new file mode 100644
index 000000000..886f54d4d
--- /dev/null
+++ b/private/oleutest/balls/chicago.inc
@@ -0,0 +1,28 @@
+# This is the global include file for the daytona version of CairOLE.
+# It is included by all project sources files.
+
+C_DEFINES= \
+ $(C_DEFINES) \
+ -DFLAT \
+ -DWIN32=200 \
+ -D_CHICAGO_=200 \
+ -DINC_OLE2 \
+ -DNOEXCEPTIONS \
+ -DCAIROLE_DOWNLEVEL \
+ $(TRACELOG)
+
+
+BLDCRT= 1
+
+# For the Daytona build, we do not want statically linked compiler runtimes,
+# so leave this commented out.
+#
+# USE_LIBCMT= 1
+
+
+USE_CRTDLL=1
+
+
+OLEDIR= $(BASEDIR)\private\ole32
+OLEUTESTDIR= $(BASEDIR)\private\oleutest
+OLEBALLSDIR= $(BASEDIR)\private\oleutest\balls
diff --git a/private/oleutest/balls/client/cfrace/cfrace.cxx b/private/oleutest/balls/client/cfrace/cfrace.cxx
new file mode 100644
index 000000000..4a5a87733
--- /dev/null
+++ b/private/oleutest/balls/client/cfrace/cfrace.cxx
@@ -0,0 +1,118 @@
+//+------------------------------------------------------------------
+//
+// File: cfrace.cxx
+//
+// Contents: test for class factory race condition
+//
+//--------------------------------------------------------------------
+#include <tstmain.hxx>
+#include "cfrace.h"
+#include <iballs.h>
+
+// BUGBUG: these should be in a public place somewhere.
+DEFINE_OLEGUID(CLSID_Balls, 0x0000013a, 1, 8);
+DEFINE_OLEGUID(CLSID_Cubes, 0x0000013b, 1, 8);
+DEFINE_OLEGUID(CLSID_LoopSrv, 0x0000013c, 1, 8);
+
+DEFINE_OLEGUID(CLSID_QI, 0x00000140, 0, 8);
+const GUID CLSID_QI =
+ {0x00000140,0x0000,0x0008,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}};
+
+DWORD gdwSleepValue = 400;
+
+LONG gcFails = 0;
+
+void TEST_FAILED2(HRESULT hRes, CHAR *pszMsg)
+{
+ BOOL RetVal = TRUE;
+ CHAR szMsg2[80];
+
+ if (FAILED(hRes))
+ {
+ gcFails++;
+ sprintf(szMsg2, "Error:%x %s", hRes, pszMsg);
+ }
+
+ TEST_FAILED(FAILED(hRes), (FAILED(hRes)) ? szMsg2 : pszMsg);
+}
+
+void TEST_FAILED3(ULONG cRefs, CHAR *pszMsg)
+{
+ BOOL RetVal = TRUE;
+ CHAR szMsg2[80];
+
+ if (cRefs != 0)
+ {
+ gcFails++;
+ sprintf(szMsg2, "cRefs:%x %s", cRefs, pszMsg);
+ }
+
+ TEST_FAILED(cRefs != 0, (cRefs != 0) ? szMsg2 : pszMsg);
+}
+
+// ----------------------------------------------------------------------
+//
+// TestCFRace - main test driver. read the ini file to determine
+// which tests to run.
+//
+// ----------------------------------------------------------------------
+BOOL TestCFRace(void)
+{
+ BOOL RetVal = TRUE;
+ CHAR szMsg[80];
+ LONG cLoops = 0;
+
+ while (1)
+ {
+ IClassFactory *pICF = NULL;
+ IBalls *pIBalls = NULL;
+ ULONG cRefs = 0;
+
+ // get the class object
+ HRESULT hRes = CoGetClassObject(CLSID_Balls, CLSCTX_LOCAL_SERVER, NULL,
+ IID_IClassFactory, (void **)&pICF);
+
+ TEST_FAILED2(hRes, "CoGetClassObject failed\n");
+
+ if (SUCCEEDED(hRes))
+ {
+ // lock server
+ hRes = pICF->LockServer(TRUE);
+ TEST_FAILED2(hRes, "LockServer TRUE failed\n");
+
+ if (SUCCEEDED(hRes))
+ {
+ // create instance
+ hRes = pICF->CreateInstance(NULL, IID_IBalls, (void **)&pIBalls);
+ TEST_FAILED2(hRes, "CreateInstance failed\n");
+
+ // unlock server
+ hRes = pICF->LockServer(FALSE);
+ TEST_FAILED2(hRes, "LockServer FALSE failed\n");
+ }
+
+ // release class object
+ cRefs = pICF->Release();
+ TEST_FAILED3(cRefs, "Release pICF not 0\n");
+
+ if (pIBalls)
+ {
+ // call instance
+ hRes = pIBalls->MoveBall(10, 20);
+ TEST_FAILED2(hRes, "pIBalls MoveBall failed\n");
+
+ // release instance
+ cRefs = pIBalls->Release();
+ TEST_FAILED3(cRefs, "Release pIBalls not 0\n");
+ }
+ }
+
+ cLoops++;
+ sprintf(szMsg, " - Iterations:%x Fails:%x\n", cLoops, gcFails);
+ OUTPUT(szMsg);
+ Sleep(gdwSleepValue);
+ }
+
+ return RetVal;
+}
+
diff --git a/private/oleutest/balls/client/cfrace/cfrace.h b/private/oleutest/balls/client/cfrace/cfrace.h
new file mode 100644
index 000000000..bcd7b6e0c
--- /dev/null
+++ b/private/oleutest/balls/client/cfrace/cfrace.h
@@ -0,0 +1,6 @@
+#ifndef __CFRACE_H__
+#define __CFRACE_H__
+
+BOOL TestCFRace(void);
+
+#endif // __CFRACE_H__
diff --git a/private/oleutest/balls/client/cfrace/daytona/makefile b/private/oleutest/balls/client/cfrace/daytona/makefile
new file mode 100644
index 000000000..1d3728d41
--- /dev/null
+++ b/private/oleutest/balls/client/cfrace/daytona/makefile
@@ -0,0 +1,10 @@
+############################################################################
+#
+# Copyright (C) 1992, Microsoft Corporation.
+#
+# All rights reserved.
+#
+############################################################################
+
+!include $(NTMAKEENV)\makefile.def
+
diff --git a/private/oleutest/balls/client/cfrace/daytona/sources b/private/oleutest/balls/client/cfrace/daytona/sources
new file mode 100644
index 000000000..5386688b6
--- /dev/null
+++ b/private/oleutest/balls/client/cfrace/daytona/sources
@@ -0,0 +1,57 @@
+!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.
+
+!ENDIF
+
+#
+# The following includes a global include file defined at the
+# base of the project for all components
+#
+
+!include ..\..\daytona.inc
+
+#
+# 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= cfrace
+
+#
+# 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= $(INCLUDES);$(BASEDIR)\private\dcomidl\obj
+C_DEFINES= $(C_DEFINES)
+
+
+SOURCES= \
+ ..\cfrace.cxx \
+ ..\main.cxx
+
+
+UMTYPE= console
+UMENTRY= main
diff --git a/private/oleutest/balls/client/cfrace/dirs b/private/oleutest/balls/client/cfrace/dirs
new file mode 100644
index 000000000..4d3d49b1f
--- /dev/null
+++ b/private/oleutest/balls/client/cfrace/dirs
@@ -0,0 +1,38 @@
+!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= \
+ cairo \
+ chicago \
+ daytona
diff --git a/private/oleutest/balls/client/cfrace/main.cxx b/private/oleutest/balls/client/cfrace/main.cxx
new file mode 100644
index 000000000..078d6fe82
--- /dev/null
+++ b/private/oleutest/balls/client/cfrace/main.cxx
@@ -0,0 +1,28 @@
+//+------------------------------------------------------------------
+//
+// File: main.cxx
+//
+// Contents: common entry point for test drivers.
+//
+//--------------------------------------------------------------------
+#include <tstmain.hxx>
+#include <cfrace.h>
+
+//+-------------------------------------------------------------------
+//
+// Function: main
+//
+// Synopsis: Entry point to EXE
+//
+// Returns: TRUE
+//
+// History: 21-Nov-92 Rickhi Created
+//
+// Just delegates to a <main> subroutine that is common for all test
+// drivers.
+//
+//--------------------------------------------------------------------
+int _cdecl main(int argc, char **argv)
+{
+ return DriverMain(argc, argv, "Class Factory Race", &TestCFRace);
+}
diff --git a/private/oleutest/balls/client/daytona.inc b/private/oleutest/balls/client/daytona.inc
new file mode 100644
index 000000000..dc2575b32
--- /dev/null
+++ b/private/oleutest/balls/client/daytona.inc
@@ -0,0 +1,41 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the general build options for this subtree.
+
+!ENDIF
+
+MAJORCOMP = oletest
+MINORCOMP = com
+
+!include ..\..\..\daytona.inc
+
+INCLUDES= ;..;$(OLEBALLSDIR)\common;
+INCLUDES= $(INCLUDES);$(OLEUTESTDIR)\balls\oleprx32\daytona
+
+UMTYPE= windows
+UMENTRY= winmain
+UMAPPL=
+UMTEST=
+
+UMLIBS= $(OLEBALLSDIR)\common\daytona\obj\*\servers.lib \
+ $(OLEUTESTDIR)\balls\oleprx32\uuid\daytona\obj\*\uuid.lib \
+ $(OLEDIR)\common\daytona\obj\*\common.lib \
+ $(BASEDIR)\public\sdk\lib\*\uuid.lib \
+ $(BASEDIR)\public\sdk\lib\*\ole32.lib \
+ $(BASEDIR)\public\sdk\lib\*\rpcndr.lib \
+ $(BASEDIR)\public\sdk\lib\*\rpcrt4.lib \
+ $(BASEDIR)\public\sdk\lib\*\rpcns4.lib \
+ $(BASEDIR)\public\sdk\lib\*\mpr.lib \
+ $(BASEDIR)\public\sdk\lib\*\netapi32.lib \
+ $(BASEDIR)\public\sdk\lib\*\kernel32.lib \
+ $(BASEDIR)\public\sdk\lib\*\user32.lib \
+ $(BASEDIR)\public\sdk\lib\*\gdi32.lib \
+ $(BASEDIR)\public\sdk\lib\*\advapi32.lib
diff --git a/private/oleutest/balls/client/dirs b/private/oleutest/balls/client/dirs
new file mode 100644
index 000000000..c774ff18f
--- /dev/null
+++ b/private/oleutest/balls/client/dirs
@@ -0,0 +1,34 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dirs.
+
+Abstract:
+
+ This file specifies the subdirectories of the current directory that
+ contain component makefiles.
+
+!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= \
+ tmarshal \
+ dllhost \
+ cfrace
+
+
+#
+# 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=
diff --git a/private/oleutest/balls/client/dllhost/daytona/makefile b/private/oleutest/balls/client/dllhost/daytona/makefile
new file mode 100644
index 000000000..1d3728d41
--- /dev/null
+++ b/private/oleutest/balls/client/dllhost/daytona/makefile
@@ -0,0 +1,10 @@
+############################################################################
+#
+# Copyright (C) 1992, Microsoft Corporation.
+#
+# All rights reserved.
+#
+############################################################################
+
+!include $(NTMAKEENV)\makefile.def
+
diff --git a/private/oleutest/balls/client/dllhost/daytona/sources b/private/oleutest/balls/client/dllhost/daytona/sources
new file mode 100644
index 000000000..a7e5b1a25
--- /dev/null
+++ b/private/oleutest/balls/client/dllhost/daytona/sources
@@ -0,0 +1,57 @@
+!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.
+
+!ENDIF
+
+#
+# The following includes a global include file defined at the
+# base of the project for all components
+#
+
+!include ..\..\daytona.inc
+
+#
+# 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= tdllhost
+
+#
+# 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= $(INCLUDES);$(BASEDIR)\private\dcomidl\obj
+C_DEFINES= $(C_DEFINES)
+
+
+SOURCES= \
+ ..\tdllhost.cxx \
+ ..\main.cxx
+
+
+UMTYPE= console
+UMENTRY= main
diff --git a/private/oleutest/balls/client/dllhost/dirs b/private/oleutest/balls/client/dllhost/dirs
new file mode 100644
index 000000000..4d3d49b1f
--- /dev/null
+++ b/private/oleutest/balls/client/dllhost/dirs
@@ -0,0 +1,38 @@
+!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= \
+ cairo \
+ chicago \
+ daytona
diff --git a/private/oleutest/balls/client/dllhost/main.cxx b/private/oleutest/balls/client/dllhost/main.cxx
new file mode 100644
index 000000000..f76ae336c
--- /dev/null
+++ b/private/oleutest/balls/client/dllhost/main.cxx
@@ -0,0 +1,28 @@
+//+------------------------------------------------------------------
+//
+// File: main.cxx
+//
+// Contents: common entry point for test drivers.
+//
+//--------------------------------------------------------------------
+#include <tstmain.hxx>
+#include <tdllhost.h>
+
+//+-------------------------------------------------------------------
+//
+// Function: main
+//
+// Synopsis: Entry point to EXE
+//
+// Returns: TRUE
+//
+// History: 21-Nov-92 Rickhi Created
+//
+// Just delegates to a <main> subroutine that is common for all test
+// drivers.
+//
+//--------------------------------------------------------------------
+int _cdecl main(int argc, char **argv)
+{
+ return DriverMain(argc, argv, "Dll Host", &TestDllHost);
+}
diff --git a/private/oleutest/balls/client/dllhost/tdllhost.cxx b/private/oleutest/balls/client/dllhost/tdllhost.cxx
new file mode 100644
index 000000000..97d91e6f1
--- /dev/null
+++ b/private/oleutest/balls/client/dllhost/tdllhost.cxx
@@ -0,0 +1,600 @@
+//+------------------------------------------------------------------
+//
+// File: tdllhost.cxx
+//
+// Contents: test for dll hosting
+//
+//--------------------------------------------------------------------
+#include <tstmain.hxx>
+#include "tdllhost.h"
+
+
+// BUGBUG: these should be in a public place somewhere.
+DEFINE_OLEGUID(CLSID_Balls, 0x0000013a, 1, 8);
+DEFINE_OLEGUID(CLSID_Cubes, 0x0000013b, 1, 8);
+DEFINE_OLEGUID(CLSID_LoopSrv, 0x0000013c, 1, 8);
+
+DEFINE_OLEGUID(CLSID_QI, 0x00000140, 0, 8);
+const GUID CLSID_QI =
+ {0x00000140,0x0000,0x0008,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}};
+
+const GUID CLSID_QIHANDLER1 =
+ {0x00000141,0x0000,0x0008,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}};
+
+
+const TCHAR *pszRegValThreadModel = TEXT("ThreadingModel");
+const TCHAR *pszSingleModel = TEXT("Single");
+const TCHAR *pszApartmentModel = TEXT("Apartment");
+const TCHAR *pszMultiThreadedModel = TEXT("Free");
+const TCHAR *pszBothModel = TEXT("Both");
+
+BOOL gfApt;
+
+// ----------------------------------------------------------------------
+//
+// Structures and Function Prototypes
+//
+// ----------------------------------------------------------------------
+typedef struct tagLoadDLLParams
+{
+ DWORD dwCallingTID; // tid of calling thread
+ DWORD dwCoInitFlag; // flag to initialize OLE with
+ DWORD dwItfFlag; // flag if the resulting object should be a proxy
+ BOOL RetVal; // return value
+ HANDLE hEvent; // thread completion event
+} SLoadDLLParam;
+
+typedef enum tagITFFLAGS
+{
+ ITF_REAL = 1, // expect ptr to real object
+ ITF_PROXY = 2 // expect ptr to proxy object
+} ITFFLAGS;
+
+
+// worker subroutines
+BOOL SpinThread(DWORD dwInitFlag, DWORD dwItfFlag);
+DWORD _stdcall LoadDLLOnThread(void *param);
+BOOL LoadClassObject(DWORD dwItfFlag);
+BOOL SetRegForDll(REFCLSID rclsid, const TCHAR *pszThreadModel);
+
+
+// test routines - return value of TRUE return means the test passed
+BOOL TestLoadSingleThreaded(void);
+BOOL TestLoadApartmentThreaded(void);
+BOOL TestLoadMultiThreaded(void);
+BOOL TestLoadBothThreaded(void);
+
+
+// ----------------------------------------------------------------------
+//
+// TestDllHost - main test driver. read the ini file to determine
+// which tests to run.
+//
+// ----------------------------------------------------------------------
+BOOL TestDllHost(void)
+{
+ BOOL RetVal = TRUE;
+
+ gfApt = (gInitFlag == COINIT_APARTMENTTHREADED) ? TRUE : FALSE;
+
+ // the driver did a CoInitialize, we dont want one so do CoUninit.
+ CoUninitialize();
+
+ if (GetProfileInt(TEXT("DllHost Test"),TEXT("LoadSingleThreaded"),1))
+ RetVal &= TestLoadSingleThreaded();
+
+ if (GetProfileInt(TEXT("DllHost Test"),TEXT("LoadApartmentThreaded"),1))
+ RetVal &= TestLoadApartmentThreaded();
+
+ if (GetProfileInt(TEXT("DllHost Test"),TEXT("LoadMultiThreaded"),1))
+ RetVal &= TestLoadMultiThreaded();
+
+ if (GetProfileInt(TEXT("DllHost Test"),TEXT("LoadBothThreaded"),1))
+ RetVal &= TestLoadBothThreaded();
+
+ // re-initialize so we dont get a complaint from OLE in debug builds
+ // about an unbalanced call to Uninitialize.
+ CoInitializeEx(NULL, gInitFlag);
+
+ return RetVal;
+}
+
+
+
+// ----------------------------------------------------------------------
+//
+// TestLoadSingleThreaded
+//
+// Tests loading a single-threaded DLL
+//
+// ----------------------------------------------------------------------
+BOOL TestLoadSingleThreaded(void)
+{
+ BOOL RetVal = TRUE, RetVal2 = TRUE;
+ HRESULT hRes = S_OK;
+
+ OUTPUT ("\n\nStarting TestLoadSingleThreaded\n");
+
+ // First, mark the DLL appropriately in the registry.
+ RetVal2 = SetRegForDll(CLSID_QI, pszSingleModel);
+ TEST_FAILED(!RetVal2, "SetRegForDLL Failed\n");
+
+
+ hRes = CoInitializeEx(NULL, gInitFlag);
+ TEST_FAILED(FAILED(hRes), "CoInitializeEx Failed\n");
+
+// ----------------------------------------------------------------------
+ OUTPUT ("\n Load Single-Threaded DLL on Main Thread\n");
+
+ RetVal2 = LoadClassObject((gfApt) ? ITF_REAL : ITF_PROXY);
+ TEST_FAILED(!RetVal2, "SingleThreadedDLL on Main Thread Failed\n");
+
+ OUTPUT (" Done Load Single-Threaded DLL on Main Thread\n");
+
+ OUTPUT ("\n Load Single-Threaded DLL on Main Thread\n");
+
+ RetVal2 = LoadClassObject((gfApt) ? ITF_REAL : ITF_PROXY);
+ TEST_FAILED(!RetVal2, "SingleThreadedDLL on Main Thread Failed\n");
+
+ OUTPUT (" Done Load Single-Threaded DLL on Main Thread\n");
+
+// ----------------------------------------------------------------------
+ OUTPUT ("\n Load Single-Threaded DLL on Different Apartment Thread\n");
+
+ hRes = SpinThread(COINIT_APARTMENTTHREADED, ITF_PROXY);
+ TEST_FAILED(!RetVal2, "SingleThreadedDLL on Apartment Thread Failed\n");
+
+ OUTPUT (" Done Load Single-Threaded DLL on Different Apartment Thread\n");
+
+ OUTPUT ("\n Second Load Single-Threaded DLL on Different Apartment Thread\n");
+
+ hRes = SpinThread(COINIT_APARTMENTTHREADED, ITF_PROXY);
+ TEST_FAILED(!RetVal2, "Single-ThreadedDLL on Apartment Thread Failed\n");
+
+ OUTPUT (" Second Done Load Single-Threaded DLL on Different Apartment Thread\n");
+
+
+// ----------------------------------------------------------------------
+ OUTPUT ("\n Load Single-Thread DLL on Multi-Threaded Apartment Thread\n");
+
+ hRes = SpinThread(COINIT_MULTITHREADED, ITF_PROXY);
+ TEST_FAILED(!RetVal2, "SingleThreadedDLL on Multi Thread Failed\n");
+
+ OUTPUT (" Done Load Single-Thread DLL on Multi-Threaded Apartment Thread\n");
+
+ OUTPUT ("\n Load Single-Thread DLL on Multi-Threaded Apartment Thread\n");
+
+ hRes = SpinThread(COINIT_MULTITHREADED, ITF_PROXY);
+ TEST_FAILED(!RetVal2, "SingleThreadedDLL on Multi Thread Failed\n");
+
+ OUTPUT (" Done Load Single-Thread DLL on Multi-Threaded Apartment Thread\n");
+
+// ----------------------------------------------------------------------
+ OUTPUT (" - Test Complete. Doing Cleanup\n");
+
+ CoUninitialize();
+
+ BOOL fResult = TestResult(RetVal, "TestLoadSingleThreaded");
+ Sleep(2000);
+ return fResult;
+}
+
+
+// ----------------------------------------------------------------------
+//
+// TestLoadApartmentThreaded
+//
+// Tests loading an apartment-threaded DLL
+//
+// ----------------------------------------------------------------------
+BOOL TestLoadApartmentThreaded(void)
+{
+ BOOL RetVal = TRUE, RetVal2 = FALSE;
+ HRESULT hRes = S_OK;
+
+ OUTPUT ("\n\nStarting TestLoadApartmentThreaded\n");
+
+ // First, mark the DLL appropriately in the registry.
+ RetVal2 = SetRegForDll(CLSID_QI, pszApartmentModel);
+ TEST_FAILED(!RetVal2, "SetRegForDLL Failed\n");
+
+ hRes = CoInitializeEx(NULL, gInitFlag);
+ TEST_FAILED(FAILED(hRes), "CoInitializeEx Failed\n");
+
+// ----------------------------------------------------------------------
+ OUTPUT ("\n Load Apartment-Threaded DLL on Main Thread\n");
+
+ RetVal2 = LoadClassObject((gfApt) ? ITF_REAL : ITF_PROXY);
+ TEST_FAILED(!RetVal2, "Apartment-ThreadedDLL on Main Thread Failed\n");
+
+ OUTPUT (" Done Load Apartment-Threaded DLL on Main Thread\n");
+
+ OUTPUT ("\n Load Apartment-Threaded DLL on Main Thread\n");
+
+ RetVal2 = LoadClassObject((gfApt) ? ITF_REAL : ITF_PROXY);
+ TEST_FAILED(!RetVal2, "Apartment-ThreadedDLL on Main Thread Failed\n");
+
+ OUTPUT (" Done Load Apartment-Threaded DLL on Main Thread\n");
+
+// ----------------------------------------------------------------------
+ OUTPUT ("\n Load Apartment-Threaded DLL on Different Apartment Thread\n");
+
+ hRes = SpinThread(COINIT_APARTMENTTHREADED, ITF_REAL);
+ TEST_FAILED(!RetVal2, "Apartment-ThreadedDLL on Apartment Thread Failed\n");
+
+ OUTPUT (" Done Load Apartment-Threaded DLL on Different Apartment Thread\n");
+
+ OUTPUT ("\n Second Load Apartment-Threaded DLL on Different Apartment Thread\n");
+
+ hRes = SpinThread(COINIT_APARTMENTTHREADED, ITF_REAL);
+ TEST_FAILED(!RetVal2, "Apartment-ThreadedDLL on Apartment Thread Failed\n");
+
+ OUTPUT (" Second Done Load Apartment-Threaded DLL on Different Apartment Thread\n");
+
+// ----------------------------------------------------------------------
+ OUTPUT ("\n Load Apartment-Thread DLL on Multi-Threaded Apartment Thread\n");
+
+ hRes = SpinThread(COINIT_MULTITHREADED, ITF_PROXY);
+ TEST_FAILED(!RetVal2, "Apartment-ThreadedDLL on Multi Thread Failed\n");
+
+ OUTPUT (" Done Load Apartment-Thread DLL on Multi-Threaded Apartment Thread\n");
+
+ OUTPUT ("\n Load Apartment-Thread DLL on Multi-Threaded Apartment Thread\n");
+
+ hRes = SpinThread(COINIT_MULTITHREADED, ITF_PROXY);
+ TEST_FAILED(!RetVal2, "Apartment-ThreadedDLL on Multi Thread Failed\n");
+
+ OUTPUT (" Done Load Apartment-Thread DLL on Multi-Threaded Apartment Thread\n");
+
+// ----------------------------------------------------------------------
+ OUTPUT (" - Test Complete. Doing Cleanup\n");
+
+ CoUninitialize();
+
+ BOOL fResult = TestResult(RetVal, "TestLoadApartmentThreaded");
+ Sleep(2000);
+ return fResult;
+}
+
+
+// ----------------------------------------------------------------------
+//
+// TestLoadMultiThreaded
+//
+// Tests loading a multi-threaded DLL
+//
+// ----------------------------------------------------------------------
+BOOL TestLoadMultiThreaded(void)
+{
+ BOOL RetVal = TRUE, RetVal2 = FALSE;;
+ HRESULT hRes = S_OK;
+
+ OUTPUT ("\n\nStarting TestLoadMultiThreaded\n");
+
+ // First, mark the DLL appropriately in the registry.
+ RetVal2 = SetRegForDll(CLSID_QI, pszMultiThreadedModel);
+ TEST_FAILED(!RetVal2, "SetRegForDLL Failed\n");
+
+ hRes = CoInitializeEx(NULL, gInitFlag);
+ TEST_FAILED(FAILED(hRes), "CoInitializeEx Failed\n");
+
+// ----------------------------------------------------------------------
+ OUTPUT ("\n Load Free-Threaded DLL on Main Thread\n");
+
+ RetVal2 = LoadClassObject((gfApt) ? ITF_PROXY : ITF_REAL);
+ TEST_FAILED(!RetVal2, "Free-ThreadedDLL on Main Thread Failed\n");
+
+ OUTPUT (" Done Load Free-Threaded DLL on Main Thread\n");
+
+ OUTPUT ("\n Load Free-Threaded DLL on Main Thread\n");
+
+ RetVal2 = LoadClassObject((gfApt) ? ITF_PROXY : ITF_REAL);
+ TEST_FAILED(!RetVal2, "Free-ThreadedDLL on Main Thread Failed\n");
+
+ OUTPUT (" Done Load Free-Threaded DLL on Main Thread\n");
+
+// ----------------------------------------------------------------------
+ OUTPUT ("\n Load Free-Threaded DLL on Different Apartment Thread\n");
+
+ hRes = SpinThread(COINIT_APARTMENTTHREADED, ITF_PROXY);
+ TEST_FAILED(!RetVal2, "Free-ThreadedDLL on Apartment Thread Failed\n");
+
+ OUTPUT (" Done Load Free-Threaded DLL on Different Apartment Thread\n");
+
+ OUTPUT ("\n Second Load Free-Threaded DLL on Different Apartment Thread\n");
+
+ hRes = SpinThread(COINIT_APARTMENTTHREADED, ITF_PROXY);
+ TEST_FAILED(!RetVal2, "Free-ThreadedDLL on Apartment Thread Failed\n");
+
+ OUTPUT (" Second Done Load Apartment-Threaded DLL on Different Apartment Thread\n");
+
+// ----------------------------------------------------------------------
+ OUTPUT ("\n Load Apartment-Thread DLL on Multi-Threaded Apartment Thread\n");
+
+ hRes = SpinThread(COINIT_MULTITHREADED, ITF_REAL);
+ TEST_FAILED(!RetVal2, "Free-ThreadedDLL on Multi Thread Failed\n");
+
+ OUTPUT (" Done Load Free-Thread DLL on Multi-Threaded Apartment Thread\n");
+
+ OUTPUT ("\n Load Apartment-Thread DLL on Multi-Threaded Apartment Thread\n");
+
+ hRes = SpinThread(COINIT_MULTITHREADED, ITF_REAL);
+ TEST_FAILED(!RetVal2, "Free-ThreadedDLL on Multi Thread Failed\n");
+
+ OUTPUT (" Done Load Free-Thread DLL on Multi-Threaded Apartment Thread\n");
+
+// ----------------------------------------------------------------------
+ OUTPUT (" - Test Complete. Doing Cleanup\n");
+
+ CoUninitialize();
+
+ BOOL fResult = TestResult(RetVal, "TestLoadMultiThreaded");
+ Sleep(2000);
+ return fResult;
+}
+
+
+// ----------------------------------------------------------------------
+//
+// TestLoadBothThreaded
+//
+// Tests loading a both-threaded DLL
+//
+// ----------------------------------------------------------------------
+BOOL TestLoadBothThreaded(void)
+{
+ BOOL RetVal = TRUE, RetVal2 = FALSE;;
+ HRESULT hRes = S_OK;
+
+ OUTPUT ("\n\nStarting TestLoadBothThreaded\n");
+
+ // First, mark the DLL appropriately in the registry.
+ RetVal2 = SetRegForDll(CLSID_QI, pszBothModel);
+ TEST_FAILED(!RetVal2, "SetRegForDLL Failed\n");
+
+ hRes = CoInitializeEx(NULL, gInitFlag);
+ TEST_FAILED(FAILED(hRes), "CoInitializeEx Failed\n");
+
+// ----------------------------------------------------------------------
+ OUTPUT ("\n Load Both-Threaded DLL on Main Thread\n");
+
+ RetVal2 = LoadClassObject(ITF_REAL);
+ TEST_FAILED(!RetVal2, "Both-ThreadedDLL on Main Thread Failed\n");
+
+ OUTPUT (" Done Load Both-Threaded DLL on Main Thread\n");
+
+// ----------------------------------------------------------------------
+ OUTPUT ("\n Load Both-Threaded DLL on Different Apartment Thread\n");
+
+ hRes = SpinThread(COINIT_APARTMENTTHREADED, ITF_REAL);
+ TEST_FAILED(!RetVal2, "Free-ThreadedDLL on Apartment Thread Failed\n");
+
+ OUTPUT (" Done Load Free-Threaded DLL on Different Apartment Thread\n");
+
+ OUTPUT ("\n Second Load Free-Threaded DLL on Different Apartment Thread\n");
+
+ hRes = SpinThread(COINIT_APARTMENTTHREADED, ITF_REAL);
+ TEST_FAILED(!RetVal2, "Free-ThreadedDLL on Apartment Thread Failed\n");
+
+ OUTPUT (" Second Done Load Free-Threaded DLL on Different Apartment Thread\n");
+
+// ----------------------------------------------------------------------
+ OUTPUT ("\n Load Apartment-Thread DLL on Multi-Threaded Apartment Thread\n");
+
+ hRes = SpinThread(COINIT_MULTITHREADED, ITF_REAL);
+ TEST_FAILED(!RetVal2, "Free-ThreadedDLL on Multi Thread Failed\n");
+
+ OUTPUT (" Done Load Free-Thread DLL on Multi-Threaded Apartment Thread\n");
+
+ OUTPUT ("\n Load Apartment-Thread DLL on Multi-Threaded Apartment Thread\n");
+
+ hRes = SpinThread(COINIT_MULTITHREADED, ITF_REAL);
+ TEST_FAILED(!RetVal2, "Free-ThreadedDLL on Multi Thread Failed\n");
+
+ OUTPUT (" Done Load Free-Thread DLL on Multi-Threaded Apartment Thread\n");
+
+// ----------------------------------------------------------------------
+ OUTPUT (" - Test Complete. Doing Cleanup\n");
+
+ CoUninitialize();
+
+ BOOL fResult = TestResult(RetVal, "TestLoadBothThreaded");
+ Sleep(2000);
+ return fResult;
+}
+
+
+// ----------------------------------------------------------------------
+//
+// Function: SpinThread
+//
+// Synopsis: Creates a thread to do some work for us. Waits for it to
+// complete. Returns the results.
+//
+// ----------------------------------------------------------------------
+BOOL SpinThread(DWORD dwInitFlag, DWORD dwItfFlag)
+{
+ BOOL RetVal = FALSE;
+
+ // set up paramters to pass to the thread
+
+ SLoadDLLParam LoadParam;
+ LoadParam.dwCallingTID = GetCurrentThreadId();
+ LoadParam.dwCoInitFlag = dwInitFlag;
+ LoadParam.dwItfFlag = dwItfFlag;
+ LoadParam.RetVal = FALSE;
+ LoadParam.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+
+ // create the thread
+
+ DWORD dwThrdId = 0;
+ HANDLE hThrd = CreateThread(NULL, 0,
+ LoadDLLOnThread,
+ &LoadParam, 0, &dwThrdId);
+ if (hThrd)
+ {
+ // enter a message loop and wait for the other thread to run
+ // We stay here until the thread posts a QUIT message.
+
+ MSG msg;
+ while (GetMessage(&msg, NULL, 0, 0))
+ {
+ DispatchMessage(&msg);
+ }
+
+ // close the thread handle
+ CloseHandle(hThrd);
+ }
+ else
+ {
+ HRESULT hRes = GetLastError();
+ TEST_FAILED(hRes, "CreateThread failed\n")
+ LoadParam.RetVal = RetVal;
+ }
+
+ // wait for the other thread to complete
+ WaitForSingleObject(LoadParam.hEvent, 0xffffffff);
+ CloseHandle(LoadParam.hEvent);
+
+ return LoadParam.RetVal;
+}
+
+// ----------------------------------------------------------------------
+//
+// Function: LoadDLLOnThread
+//
+// Synopsis: Initializes COM, loads the class object and creates an
+// instance, releases them, Posts a message to wake up the
+// calling thread, Uninitializes COM, then exits.
+//
+// ----------------------------------------------------------------------
+DWORD _stdcall LoadDLLOnThread(void *param)
+{
+ BOOL RetVal = TRUE;
+ HRESULT hRes = S_OK;
+ SLoadDLLParam *pLoadParam = (SLoadDLLParam *)param;
+
+ OUTPUT (" - LoadDLLOnThread Entered\n");
+ hRes = CoInitializeEx(NULL, pLoadParam->dwCoInitFlag);
+ TEST_FAILED(FAILED(hRes), "CoInitialize failed\n")
+
+ if (SUCCEEDED(hRes))
+ {
+ // attempt to load the class object on this thread.
+ pLoadParam->RetVal = LoadClassObject(pLoadParam->dwItfFlag);
+ CoUninitialize();
+ }
+
+ // post a message to the server thread to exit now that we are done.
+ PostThreadMessage(pLoadParam->dwCallingTID, WM_QUIT, 0, 0);
+ SetEvent(pLoadParam->hEvent);
+
+ OUTPUT (" - LoadDLLOnThread Exit\n");
+ return RetVal;
+}
+
+// ----------------------------------------------------------------------
+//
+// Function: LoadClassObject
+//
+// Synopsis: Loads the class object, creates an instance, releases
+// them, returns the results.
+//
+// ----------------------------------------------------------------------
+BOOL LoadClassObject(DWORD dwItfFlag)
+{
+ BOOL RetVal = TRUE;
+ IClassFactory *pICF = NULL;
+ IUnknown *pIPM = NULL;
+
+ // try to load the dll class object
+ HRESULT hRes = CoGetClassObject(CLSID_QI, CLSCTX_INPROC_SERVER, NULL,
+ IID_IClassFactory, (void **)&pICF);
+
+ TEST_FAILED(FAILED(hRes), "CoGetClassObject failed\n");
+
+ if (SUCCEEDED(hRes))
+ {
+ hRes = pICF->QueryInterface(IID_IProxyManager, (void **)&pIPM);
+
+ if (SUCCEEDED(hRes))
+ {
+ pIPM->Release();
+ TEST_FAILED(dwItfFlag != ITF_PROXY, "Got Proxy when expected Real\n");
+ }
+ else
+ {
+ TEST_FAILED(dwItfFlag != ITF_REAL, "Got Real when expected Proxy\n");
+ }
+
+ // CODEWORK: create an instance, then release them
+
+ // release the class object.
+ OUTPUT (" - CoGetClassObject succeeded\n");
+
+ ULONG ulRefCnt = pICF->Release();
+ TEST_FAILED(ulRefCnt != 0, "pICF RefCnt not zero\n");
+ pICF = NULL;
+ OUTPUT (" - Released ClassObject\n");
+ }
+
+ return RetVal;
+}
+
+
+
+//+-------------------------------------------------------------------
+//
+// Function: SetRegForDll, private
+//
+// Synopsis: Set registry entry for a DLL
+//
+// Arguments: [rclsid] - clsid for reg entry
+// [pszThreadModel] - threading model can be NULL.
+//
+// Returns: TRUE - Registry entry set successfully.
+// FALSE - Registry entry set successfully.
+//
+// History: 01-Nov-94 Ricksa Created
+//
+//--------------------------------------------------------------------
+BOOL SetRegForDll(REFCLSID rclsid, const TCHAR *pszThreadModel)
+{
+ BOOL fResult = FALSE;
+ HKEY hKeyClass = NULL;
+ HKEY hKeyDll = NULL;
+ TCHAR aszWkBuf[MAX_PATH]; // String buffer used for various purposes
+
+ // Build clsid registry key
+ wsprintf(aszWkBuf,
+ TEXT("CLSID\\{%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}"),
+ rclsid.Data1, rclsid.Data2, rclsid.Data3,
+ rclsid.Data4[0], rclsid.Data4[1],
+ rclsid.Data4[2], rclsid.Data4[3],
+ rclsid.Data4[4], rclsid.Data4[5],
+ rclsid.Data4[6], rclsid.Data4[7]);
+
+ // Create the key for the class
+ if (RegCreateKey(HKEY_CLASSES_ROOT, aszWkBuf, &hKeyClass) == ERROR_SUCCESS)
+ {
+ // Create the key for the DLL
+ if (RegCreateKey(hKeyClass, TEXT("InprocServer32"), &hKeyDll) == ERROR_SUCCESS)
+ {
+ // Set the value for the Threading Model
+ if (RegSetValueEx(hKeyDll, pszRegValThreadModel, 0,
+ REG_SZ,
+ (const unsigned char*) pszThreadModel,
+ (wcslen(pszThreadModel) + 1) * sizeof(WCHAR))
+ == ERROR_SUCCESS)
+ {
+ fResult = TRUE;
+ }
+
+ RegCloseKey(hKeyDll);
+ }
+
+ RegCloseKey(hKeyClass);
+ }
+
+ return fResult;
+}
diff --git a/private/oleutest/balls/client/dllhost/tdllhost.h b/private/oleutest/balls/client/dllhost/tdllhost.h
new file mode 100644
index 000000000..72dcdc7b5
--- /dev/null
+++ b/private/oleutest/balls/client/dllhost/tdllhost.h
@@ -0,0 +1,6 @@
+#ifndef __TDLLHOST_H__
+#define __TDLLHOST_H__
+
+BOOL TestDllHost(void);
+
+#endif // __TDLLHOST_H__
diff --git a/private/oleutest/balls/client/prxytest/daytona/makefile b/private/oleutest/balls/client/prxytest/daytona/makefile
new file mode 100644
index 000000000..1d3728d41
--- /dev/null
+++ b/private/oleutest/balls/client/prxytest/daytona/makefile
@@ -0,0 +1,10 @@
+############################################################################
+#
+# Copyright (C) 1992, Microsoft Corporation.
+#
+# All rights reserved.
+#
+############################################################################
+
+!include $(NTMAKEENV)\makefile.def
+
diff --git a/private/oleutest/balls/client/prxytest/daytona/sources b/private/oleutest/balls/client/prxytest/daytona/sources
new file mode 100644
index 000000000..bc5c87565
--- /dev/null
+++ b/private/oleutest/balls/client/prxytest/daytona/sources
@@ -0,0 +1,67 @@
+!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:
+
+ David Plummer (davepl) 19-Mar-94
+
+ Modifed by via awk to include global project include file
+ and to wrap precompiled header line within a conditional
+ that can be set in this include file.
+
+ Donna Liu (DonnaLi) 19-Dec-1993
+
+!ENDIF
+
+MAJORCOMP = cairole
+MINORCOMP = com
+
+#
+# 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= prxytest
+
+#
+# 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
+
+
+#
+# The following includes a global include file defined at the
+# base of the project for all components
+#
+
+!include ..\..\daytona.inc
+
+C_DEFINES= \
+ $(C_DEFINES)
+
+
+SOURCES= \
+ ..\prxytest.cxx
diff --git a/private/oleutest/balls/client/prxytest/dirs b/private/oleutest/balls/client/prxytest/dirs
new file mode 100644
index 000000000..1d0b9edbb
--- /dev/null
+++ b/private/oleutest/balls/client/prxytest/dirs
@@ -0,0 +1,38 @@
+!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/balls/client/prxytest/prxytest.cxx b/private/oleutest/balls/client/prxytest/prxytest.cxx
new file mode 100644
index 000000000..8ad293ebb
--- /dev/null
+++ b/private/oleutest/balls/client/prxytest/prxytest.cxx
@@ -0,0 +1,152 @@
+//+-------------------------------------------------------------------
+//
+// File: climain.cxx
+//
+// Contents: server test program to test OLE2 RPC
+//
+// Classes: None
+//
+// Functions:
+//
+// History: 23-Nov-92 Rickhi Created
+//
+//--------------------------------------------------------------------
+
+#include <windows.h>
+#include <ole2.h>
+#include <stdio.h>
+
+#include <rpctyp.h> // IRpcTypes interface
+
+
+
+SCODE TestGuids(IRpcTypes *pRpc);
+SCODE TestDwords(IRpcTypes *pRpc);
+
+#define DebugOut(x) printf x
+
+
+
+int WINAPI WinMain(HINSTANCE hinst, HINSTANCE hinstPrev, LPSTR lpCmdLine, int nCmdShow)
+{
+ DebugOut (("Test: Starting\n"));
+
+ // initialize with OLE2
+ SCODE sc = OleInitialize(NULL);
+ if (FAILED(sc))
+ {
+ DebugOut (("Test: OleInitialize = %x\n", sc));
+ return sc;
+ }
+
+ // create an instance
+ sc = CoGetClassObject(CLSID_RpcTypes,
+ CLSCTX_LOCAL_SERVER,
+ NULL,
+ IID_IClassFactory,
+ (void **)&pCF);
+
+ if (FAILED(sc))
+ {
+ DebugOut (("Test: CoGetClassObject=%x\n", sc));
+ return sc;
+ }
+
+ sc = pCF->CreateInstance(NULL, IID_IRpcTypes, (void **)&pRpc);
+ sc = pCF->Release();
+
+ if (FAILED(sc))
+ {
+ DebugOut(("Test: CreateInstance=%x\n", sc));
+ return sc;
+ }
+
+
+ sc = TestVoid(pRpc);
+
+ sc = TestGuids(pRpc);
+
+ sc = TestDwords(pRpc)
+
+ sc = TestWindows(pRpc);
+
+ sc = TestOleData(pRpc);
+
+
+ // finished with OLE2
+
+ OleUninitialize();
+ DebugOut (("Test: CoUninitialize called.\n"));
+
+ return sc;
+}
+
+
+
+
+
+SCODE TestGuids(IRpcTypes *pRpc)
+{
+ REFCLSID rclsid;
+ CLSID clsid;
+ REFIID riid;
+ IID iid;
+ GUID guid;
+
+ // initialize the parameters
+
+ SCODE sc = pRpc->GuidsIn(rclsid, clsid, riid, iid, guid);
+
+ if (FAILED(sc))
+ {
+ DebugOut (("\n"));
+ }
+
+
+ sc = pRpc->GuidsOut(&clsid, &iid, &guid);
+
+ if (FAILED(sc))
+ {
+ DebugOut (("\n"));
+ }
+
+ // check the return values
+
+
+ return S_OK;
+}
+
+
+SCODE TestDwords(IRpcTypes *pRpc)
+{
+ DWORD dw = 1;
+ ULONG ul = 2;
+ LONG lg = 3;
+ LARGE_INTEGER li;
+ ULARGE_INTEGER uli;
+
+ // methods to test DWORD / LARGE_INTEGER parameter passing
+ li.LowPart = 4;
+ li.HighPart = 5;
+
+ uli.LowPart = 6;
+ uli.HighPart = 7;
+
+ sc = pRpc->DwordIn(dw, ul, lg, li, uli);
+
+ if (FAILED(sc))
+ {
+ DebugOut (("\n"));
+ }
+
+ sc = pRpc->DwordIn(&dw, &ul, &lg, &li, &uli);
+
+ if (FAILED(sc))
+ {
+ DebugOut (("\n"));
+ }
+
+ // check the return values
+
+ return S_OK;
+}
diff --git a/private/oleutest/balls/client/smarshal/daytona/makefile b/private/oleutest/balls/client/smarshal/daytona/makefile
new file mode 100644
index 000000000..1d3728d41
--- /dev/null
+++ b/private/oleutest/balls/client/smarshal/daytona/makefile
@@ -0,0 +1,10 @@
+############################################################################
+#
+# Copyright (C) 1992, Microsoft Corporation.
+#
+# All rights reserved.
+#
+############################################################################
+
+!include $(NTMAKEENV)\makefile.def
+
diff --git a/private/oleutest/balls/client/smarshal/daytona/sources b/private/oleutest/balls/client/smarshal/daytona/sources
new file mode 100644
index 000000000..9e6c62c80
--- /dev/null
+++ b/private/oleutest/balls/client/smarshal/daytona/sources
@@ -0,0 +1,59 @@
+!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.
+
+!ENDIF
+
+#
+# The following includes a global include file defined at the
+# base of the project for all components
+#
+
+!include ..\..\daytona.inc
+
+#
+# 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= smarshal
+
+#
+# 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= $(INCLUDES)
+C_DEFINES= $(C_DEFINES)
+
+
+SOURCES= \
+ ..\smarshal.cxx \
+ ..\testvars.cxx \
+ ..\tunk.cxx \
+ ..\stream.cxx
+
+
+UMTYPE= console
+UMENTRY= main
diff --git a/private/oleutest/balls/client/smarshal/dirs b/private/oleutest/balls/client/smarshal/dirs
new file mode 100644
index 000000000..4aca16d25
--- /dev/null
+++ b/private/oleutest/balls/client/smarshal/dirs
@@ -0,0 +1,38 @@
+!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= \
+ \
+ chicago \
+ daytona
diff --git a/private/oleutest/balls/client/smarshal/smarshal.cxx b/private/oleutest/balls/client/smarshal/smarshal.cxx
new file mode 100644
index 000000000..a8afb5d1a
--- /dev/null
+++ b/private/oleutest/balls/client/smarshal/smarshal.cxx
@@ -0,0 +1,862 @@
+//+-------------------------------------------------------------------
+//
+// File: smarshal.cxx
+//
+// Synopsis: Source code for Interface Marshaling stress test main
+// driver functions. Source for individual tests is in
+// testvar.cxx
+//
+// History: 21-Aug-95 Rickhi Created
+//
+//--------------------------------------------------------------------
+#include <smarshal.hxx>
+
+//+-------------------------------------------------------------------
+//
+// Globals:
+//
+//--------------------------------------------------------------------
+BOOL gfVerbose = FALSE; // print execution messages
+BOOL gfDebug = FALSE; // print debug messages
+
+DWORD giThreadModel = OPF_INITAPARTMENT; // threading model to use
+int giTestVar = 0; // test variation to run
+int giHighestTestVar = 2; // highest test var supported
+
+int gicReps = 5; // number of repetitions of each test
+int gicThreads = 1; // number of threads to use on each test
+
+
+//+-------------------------------------------------------------------
+//
+// Private Function ProtoTypes:
+//
+//--------------------------------------------------------------------
+HRESULT DoIfOperation(DWORD dwFlags, INTERFACEPARAMS *pIFD);
+void DisplayHelp(void);
+BOOL GetSwitch(CHAR *pCmdParam, CHAR *pszSwitch);
+BOOL GetSwitchInt(CHAR *pCmdParam, CHAR *pszSwitch, int *pInt);
+BOOL ParseCmdLine(int argc, char **argv);
+int _cdecl main(int argc, char **argv);
+
+BOOL FreeWaitForEvent(HANDLE hEvent);
+BOOL AptWaitForEvent(HANDLE hEvent);
+
+STDAPI_(LPSTREAM) CreateMemStm(DWORD cb, LPHANDLE phdl);
+
+//+-------------------------------------------------------------------
+//
+// Misc:
+//
+//--------------------------------------------------------------------
+
+#ifndef _CAIRO_
+// COM initialization flags; passed to CoInitialize.
+typedef enum tagCOINIT
+{
+ COINIT_MULTITHREADED = 0, // OLE calls objects on any thread.
+ COINIT_SINGLETHREADED = 1, // OLE calls objects on single thread.
+ COINIT_APARTMENTTHREADED = 2 // Apartment model
+} COINIT;
+
+WINOLEAPI CoInitializeEx(LPVOID pvReserved, DWORD);
+#endif
+
+
+
+//+-------------------------------------------------------------------
+//
+// Function: main
+//
+// Synopsis: Entry point to EXE. Parse the command line, then run
+// whatever test variations were selected.
+//
+// Notes: The test variation code is in testvars.cxx.
+// The rest of this file is helper routines.
+//
+//--------------------------------------------------------------------
+int _cdecl main(int argc, char **argv)
+{
+ // parse the command line
+ BOOL fRes = ParseCmdLine(argc, argv);
+
+ if (fRes)
+ {
+ // run the selected test variations
+ switch (giTestVar)
+ {
+ case 1: fRes = TestVar1();
+ break;
+ case 2: fRes = TestVar2();
+ break;
+ default: break;
+ }
+ }
+
+ // check the results
+ CHKTESTRESULT(fRes, "Marshal Stress Tests");
+ return 0;
+}
+
+//+-------------------------------------------------------------------
+//
+// Function: ParseCmdLine
+//
+// Synopsis: parses the execution parameters
+//
+//--------------------------------------------------------------------
+BOOL ParseCmdLine(int argc, char **argv)
+{
+ BOOL fDontRun = (argc == 1) ? TRUE : FALSE;
+
+ // the first parameter is the EXE name, skip it.
+ argc--;
+ argv++;
+
+ for (int i=0; i<argc; i++, argv++)
+ {
+ if (GetSwitch(*argv, "v"))
+ {
+ // run verbose
+ gfVerbose = TRUE;
+ }
+ else if (GetSwitch(*argv, "d"))
+ {
+ // run debug mode
+ gfVerbose = TRUE;
+ gfDebug = TRUE;
+ }
+ else if (GetSwitch(*argv, "h") || GetSwitch(*argv, "?"))
+ {
+ // help wanted
+ fDontRun = TRUE;
+ }
+ else if (GetSwitchInt(*argv, "var:", &giTestVar))
+ {
+ // selected test variation, ensure the variation is valid
+ if (giTestVar > giHighestTestVar)
+ {
+ ERROUT("Unknown Test Variation:%x\n", giTestVar);
+ fDontRun = TRUE;
+ }
+ }
+ else if (GetSwitchInt(*argv, "reps:", &gicReps))
+ {
+ ; // selected repetition count
+ }
+ else if (GetSwitchInt(*argv, "threads:", &gicThreads))
+ {
+ ; // selected thread count
+ }
+ else if (GetSwitch(*argv, "model:apt"))
+ {
+ // run apartment model
+ giThreadModel = OPF_INITAPARTMENT;
+ }
+ else if (GetSwitch(*argv, "model:free"))
+ {
+ // run freethreaded model
+ giThreadModel = OPF_INITFREE;
+ }
+ else
+ {
+ // unknown switch, show help
+ ERROUT("Unknown command line switch:<%s>\n", *argv);
+ fDontRun = TRUE;
+ }
+ }
+
+ if (fDontRun)
+ {
+ // help is wanted
+ DisplayHelp();
+ return FALSE;
+ }
+
+ // success, run the test
+ return TRUE;
+}
+
+//+-------------------------------------------------------------------
+//
+// Function: DisplayHelp
+//
+// Synopsis: displays a command line help message
+//
+//--------------------------------------------------------------------
+void DisplayHelp(void)
+{
+ printf("\nCommand Line Switches for Marshal Stress Test:\n\n");
+
+ printf("-d - debug mode\n");
+ printf("-v - verbose mode\n");
+ printf("-h | -? - display this help message\n\n");
+
+ printf("-model:[apt|free] - threading model to use for test\n");
+ printf("-var:# - test variation to execute 1-%x\n", giHighestTestVar);
+ printf("-threads:# - number of threads per variation\n");
+ printf("-reps:# - number of repetitions of the test\n");
+
+ printf("\n");
+}
+
+//+-------------------------------------------------------------------
+//
+// Function: GetSwitch
+//
+// Synopsis: returns TRUE if the specified cmd line switch is set.
+//
+//--------------------------------------------------------------------
+BOOL GetSwitch(CHAR *pCmdParam, CHAR *pszSwitch)
+{
+ if (*pCmdParam == '-' || *pCmdParam == '/')
+ {
+ pCmdParam++;
+ return (!stricmp(pCmdParam, pszSwitch));
+ }
+ return FALSE;
+}
+
+//+-------------------------------------------------------------------
+//
+// Function: GetSwitchInt
+//
+// Synopsis: returns TRUE if the specified cmd line switch is set,
+// and sets the value of that switch.
+//
+//--------------------------------------------------------------------
+BOOL GetSwitchInt(CHAR *pCmdParam, CHAR *pszSwitch, int *pInt)
+{
+ if (*pCmdParam == '-' || *pCmdParam == '/')
+ {
+ pCmdParam++;
+ int len = strlen(pszSwitch);
+ if (!strnicmp(pCmdParam, pszSwitch, len))
+ {
+ pCmdParam += len;
+ *pInt = atoi(pCmdParam);
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+//+-------------------------------------------------------------------
+//
+// Function: CHKRESULT
+//
+// Synopsis: prints a failure message if the result code indicates
+// failure., and success message only in verbose mode.
+//
+//--------------------------------------------------------------------
+void CHKRESULT(HRESULT hr, CHAR *pszOperation)
+{
+ if (FAILED(hr))
+ {
+ printf("FAILED hr:%x Op:%s\n", hr, pszOperation);
+ }
+ else if (gfVerbose)
+ {
+ printf("PASSED hr:%x Op:%s\n", hr, pszOperation);
+ }
+}
+
+//+-------------------------------------------------------------------
+//
+// Function: CHKOP
+//
+// Synopsis: prints a failure message if the result code indicates
+// failure, and success message only in debug mode.
+//
+//--------------------------------------------------------------------
+void CHKOP(HRESULT hr, CHAR *pszOperation)
+{
+ if (FAILED(hr))
+ {
+ printf("FAILED hr:%x Op:%s\n", hr, pszOperation);
+ }
+ else if (gfDebug)
+ {
+ printf("PASSED hr:%x Op:%s\n", hr, pszOperation);
+ }
+}
+
+//+-------------------------------------------------------------------
+//
+// Function: CHKTESTRESULT
+//
+// Synopsis: prints a pass or fail message
+//
+//--------------------------------------------------------------------
+void CHKTESTRESULT(BOOL fRes, CHAR *pszMsg)
+{
+ if (fRes)
+ printf("%s PASSED\n", pszMsg);
+ else
+ printf("%s FAILED\n", pszMsg);
+}
+
+//+-------------------------------------------------------------------
+//
+// Function: GetEvent / ReleaseEvent
+//
+// Synopsis: allocates or releases an event
+//
+// CODEWORK: cache these for frequent use
+//
+//--------------------------------------------------------------------
+HANDLE GetEvent()
+{
+ HANDLE hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+ if (hEvent == NULL)
+ {
+ ERROUT("GetEvent FAILED\n");
+ }
+ DBGOUT("CreateEvent hEvent:%x\n", hEvent);
+ return hEvent;
+}
+
+void ReleaseEvent(HANDLE hEvent)
+{
+ if (hEvent)
+ {
+ DBGOUT("ReleaseEvent hEvent:%x\n", hEvent);
+ CloseHandle(hEvent);
+ }
+}
+
+//+-------------------------------------------------------------------
+//
+// Function: WaitForEvent
+//
+// Synopsis: waits on the given event (if there is one) for a
+// certain amount of time, returns FALSE if timedout.
+//
+//--------------------------------------------------------------------
+BOOL WaitForEvent(HANDLE hEvent)
+{
+ if (hEvent)
+ {
+ // CODEWORK: base off the Threading Model
+
+ return (TRUE) ? AptWaitForEvent(hEvent) :
+ FreeWaitForEvent(hEvent);
+ }
+ return TRUE;
+}
+
+//+-------------------------------------------------------------------
+//
+// Function: FreeWaitForEvent
+//
+// Synopsis: FreeThreaded version of WaitForEvent. Waits on the
+// given event.
+//
+//--------------------------------------------------------------------
+BOOL FreeWaitForEvent(HANDLE hEvent)
+{
+ DBGOUT("FreeWaitForEvent hEvent:%x\n", hEvent);
+ if (WaitForSingleObject(hEvent, 30000) == WAIT_TIMEOUT)
+ {
+ ERROUT("WaitForSingleObject TimedOut");
+ return FALSE;
+ }
+ return TRUE;
+}
+
+//+-------------------------------------------------------------------
+//
+// Function: AptWaitForEvent
+//
+// Synopsis: Apartment model version of WaitForEvent. Waits on the
+// given event. Dispatches all incoming windows messages
+// while waiting.
+//
+//--------------------------------------------------------------------
+BOOL AptWaitForEvent(HANDLE hEvent)
+{
+ DBGOUT("AptWaitForEvent hEvent:%x\n", hEvent);
+
+ while (1)
+ {
+ HANDLE arEvent[] = {hEvent};
+ DWORD dwWakeReason = MsgWaitForMultipleObjects(1, arEvent, FALSE,
+ 1000, QS_ALLINPUT);
+
+ if (dwWakeReason == WAIT_OBJECT_0)
+ {
+ // event was signalled. exit.
+ break;
+ }
+ else
+ {
+ // check for and dispatch any messages that have arrived
+ MSG msg;
+ while (PeekMessage(&msg, 0, WM_NULL, WM_NULL, PM_REMOVE))
+ {
+ DispatchMessage(&msg);
+ }
+ }
+ }
+ return TRUE;
+}
+
+//+-------------------------------------------------------------------
+//
+// Function: SignalEvent
+//
+// Synopsis: signals an event (if there is one)
+//
+//--------------------------------------------------------------------
+void SignalEvent(HANDLE hEvent)
+{
+ if (hEvent)
+ {
+ DBGOUT("SignalEvent hEvent:%x\n", hEvent);
+ SetEvent(hEvent);
+ }
+}
+
+//+-------------------------------------------------------------------
+//
+// Function: GetStream / ReleaseStream
+//
+// Synopsis: allocates or releases a Stream
+//
+// CODEWORK: cache these for frequent use
+// CODEWORK: use CStreamOnFile for cross process/machine marshaling.
+//
+//--------------------------------------------------------------------
+IStream * GetStream(void)
+{
+ IStream *pStm = CreateMemStm(600, NULL);
+ if (pStm == NULL)
+ {
+ ERROUT("ERROR: GetStream FAILED\n");
+ }
+ DBGOUT("GetStream pStm:%x\n", pStm);
+ return pStm;
+}
+
+void ReleaseStream(IStream *pStm)
+{
+ if (pStm)
+ {
+ DBGOUT("ReleaseStream pStm:%x\n", pStm);
+ pStm->Release();
+ }
+}
+
+//+-------------------------------------------------------------------
+//
+// Function: ResetStream
+//
+// Synopsis: resets a steam back to the start
+//
+//--------------------------------------------------------------------
+HRESULT ResetStream(IStream *pStm)
+{
+ DBGOUT("ResetStream pStm:%x\n", pStm);
+
+ LARGE_INTEGER libMove;
+ libMove.LowPart = 0;
+ libMove.HighPart = 0;
+
+ HRESULT hr = pStm->Seek(libMove, STREAM_SEEK_SET, 0);
+ if (FAILED(hr))
+ {
+ ERROUT("ERROR: ResetStream FAILED hr:%x\n",hr);
+ }
+ return hr;
+}
+
+//+-------------------------------------------------------------------
+//
+// Function: GetInterface / ReleaseInterface
+//
+// Synopsis: allocates or releases an object interface
+//
+//--------------------------------------------------------------------
+IUnknown *GetInterface(void)
+{
+ IUnknown *punk = (IUnknown *) new CTestUnk();
+ if (punk == NULL)
+ {
+ ERROUT("ERROR: GetInterface FAILED\n");
+ }
+ DBGOUT("GetInterface punk:%x\n", punk);
+ return punk;
+}
+
+void ReleaseInterface(IUnknown *punk)
+{
+ if (punk)
+ {
+ DBGOUT("ReleaseInterface punk:%x\n", punk);
+ punk->Release();
+ }
+}
+
+//+-------------------------------------------------------------------
+//
+// Function: GenericExecute
+//
+// Synopsis: run all the parameter blocks on different threads
+// simultaneously.
+//
+//--------------------------------------------------------------------
+BOOL GenericExecute(ULONG cEPs, EXECPARAMS *pEP[])
+{
+ BOOL fRes = TRUE;
+ DBGOUT("Start GenericExecute cEPs:%x\n", cEPs);
+
+ HANDLE hThread[50];
+
+ // launch a thread to run each command block
+ for (ULONG i=0; i<cEPs; i++)
+ {
+ // launch a thread to execute the parameter block
+ DWORD dwThreadId;
+ hThread[i] = CreateThread(NULL, 0,
+ WorkerThread,
+ pEP[i],
+ 0,
+ &dwThreadId);
+ }
+
+ // signal all the threads to start their work
+ for (i=0; i<cEPs; i++)
+ {
+ SignalEvent(pEP[i]->hEventThreadStart);
+ }
+
+ // wait for all the threads to complete their work
+ for (i=0; i<cEPs; i++)
+ {
+ if (pEP[i]->hEventThreadDone)
+ {
+ WaitForSingleObject(pEP[i]->hEventThreadDone, 60000);
+ }
+ }
+
+ // signal all the threads to exit
+ for (i=0; i<cEPs; i++)
+ {
+ HANDLE hEventThreadExit = pEP[i]->hEventThreadExit;
+ pEP[i]->hEventThreadExit = NULL;// set to NULL so only the thread will
+ // release it, genericcleanup wont.
+ SignalEvent(hEventThreadExit);
+ }
+
+ // wait for all the threads to exit
+ for (i=0; i<cEPs; i++)
+ {
+ WaitForSingleObject(hThread[i], 5000);
+ CloseHandle(hThread[i]);
+ }
+
+ DBGOUT("Done GenericExecute fRes:%x\n", fRes);
+ return fRes;
+}
+
+//+-------------------------------------------------------------------
+//
+// Function: GenericCleanup
+//
+// Synopsis: clean all the parameter blocks
+//
+//--------------------------------------------------------------------
+void GenericCleanup(ULONG cEPs, EXECPARAMS *pEP[])
+{
+ DBGOUT("GenericCleanup\n");
+
+ // delete the execution parameter blocks
+ for (ULONG i=0; i<cEPs; i++)
+ {
+ ReleaseExecParam(pEP[i]);
+ // CODEWORK: get results from the parameter block?
+ }
+}
+
+//+-------------------------------------------------------------------
+//
+// Function: WorkerThread
+//
+// Synopsis: entry point for thread that executes a series of
+// interface commands
+//
+//--------------------------------------------------------------------
+DWORD _stdcall WorkerThread(void *params)
+{
+ DBGOUT("StartWorkerThread TID:%x pEP:%x\n", GetCurrentThreadId(), params);
+
+ EXECPARAMS *pEP = (EXECPARAMS *)params;
+ if (pEP == NULL)
+ {
+ return E_OUTOFMEMORY;
+ }
+
+ HRESULT hr = S_OK;
+
+ // Initialize OLE for this thread.
+ if (pEP->dwFlags & OPF_INITAPARTMENT)
+ {
+ hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
+ }
+ else
+ {
+ hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
+ }
+
+ if (FAILED(hr))
+ {
+ ERROUT("ERROR: CoInitializeEx FAILED\n");
+ return hr;
+ }
+
+ // wait for signal to start the test
+ if (!WaitForEvent(pEP->hEventThreadStart))
+ {
+ return E_OUTOFMEMORY; // BUGBUG
+ }
+
+ // loop for the number of reps requested
+ for (ULONG iRep = 0; iRep < pEP->cReps; iRep++)
+ {
+ // wait for the start signal
+ if (!WaitForEvent(pEP->hEventRepStart))
+ {
+ return E_OUTOFMEMORY; // BUGBUG
+ }
+
+ MSGOUT(" TID:%x Rep:%x of %x\n",
+ GetCurrentThreadId(), iRep, pEP->cReps);
+
+ // loop for the number of INTERFACEPARAMSs, performing
+ // the requested operation(s) on each interface.
+
+ for (ULONG iIP=0; iIP < pEP->cIPs; iIP++)
+ {
+ hr = DoIfOperation(pEP->dwFlags, &(pEP->aIP[iIP]));
+ }
+
+ // signal the completion event
+ SignalEvent(pEP->hEventRepDone);
+ }
+
+ // signal the thread completion event. Cant touch pEP after this
+ // point in time since the main thread may delete it. We extract
+ // the ThreadExit event and NULL it in the parameter block so that
+ // the main thread wont release it. We release it after the event
+ // has been signaled.
+
+ HANDLE hEventThreadExit = pEP->hEventThreadExit;
+ SignalEvent(pEP->hEventThreadDone);
+
+ // wait on the thread exit event. This allows other threads to
+ // complete their work (eg unmarshaling/Releasing interfaces on
+ // object in this thread.
+
+ WaitForEvent(hEventThreadExit);
+ ReleaseEvent(hEventThreadExit);
+
+ // uninitialize OLE for this thread
+ CoUninitialize();
+
+ DBGOUT("ExitWorkerThread TID:%x hr:%x\n", GetCurrentThreadId(), hr);
+ return hr;
+}
+
+//+-------------------------------------------------------------------
+//
+// Function: DoIfOperation
+//
+// Synopsis: executes one interface operation
+//
+//--------------------------------------------------------------------
+HRESULT DoIfOperation(DWORD dwFlags, INTERFACEPARAMS *pIP)
+{
+ // find the interface pointers and IID in the params
+ IUnknown *punk = pIP->punk;
+ IStream *pStm = pIP->pStm;
+ REFIID riid = pIP->iid;
+ HRESULT hr = S_OK;
+
+ DBGOUT("DoIfOperation Oper:%x pUnk:%x pStm:%x\n", dwFlags, punk, pStm);
+
+ // wait for the start signal
+ if (!WaitForEvent(pIP->hEventStart))
+ {
+ return -1;
+ }
+
+ // do the requested operation(s) on the interface
+ if (dwFlags & OPF_MARSHAL)
+ {
+ // marshal the interface into the stream
+ ResetStream(pStm);
+ hr = CoMarshalInterface(pStm, riid, punk, 0, NULL, MSHLFLAGS_NORMAL);
+ CHKOP(hr, "CoMarshalInterface");
+ }
+
+ if (dwFlags & OPF_DISCONNECT)
+ {
+ hr = CoDisconnectObject(punk, 0);
+ CHKOP(hr, "CoDisconnectObject");
+ }
+
+ if (dwFlags & OPF_RELEASEMARSHALDATA)
+ {
+ // call RMD on the stream
+ ResetStream(pStm);
+ hr = CoReleaseMarshalData(pStm);
+ CHKOP(hr, "CoReleaseMarshalData");
+ }
+
+ if (dwFlags & OPF_UNMARSHAL)
+ {
+ // unmarshal the interface from the stream
+ ResetStream(pStm);
+ hr = CoUnmarshalInterface(pStm, riid, (void **)&punk);
+ CHKOP(hr, "CoUnmarshalInterface");
+ }
+
+ if (dwFlags & OPF_RELEASE)
+ {
+ // release the interface pointer (if there is one).
+ if (punk != NULL)
+ {
+ ULONG cRefs = punk->Release();
+ }
+ }
+
+ SignalEvent(pIP->hEventDone);
+
+ DBGOUT("DoIfOperation Oper:%x hr:%x\n", dwFlags, hr);
+ return hr;
+}
+
+//+-------------------------------------------------------------------
+//
+// Function: CreateExecParam
+//
+// Synopsis: allocates an exec parameter packet for the given # of
+// INTERFACEPARAMSs.
+//
+//--------------------------------------------------------------------
+EXECPARAMS *CreateExecParam(ULONG cIP)
+{
+ // allocate memory
+ ULONG ulSize = sizeof(EXECPARAMS) + (cIP * sizeof(INTERFACEPARAMS));
+
+ EXECPARAMS *pEP = (EXECPARAMS *) new BYTE[ulSize];
+ if (pEP == NULL)
+ {
+ DBGOUT("CreateExecParams OOM\n");
+ return NULL;
+ }
+
+ // zero fill the packet
+ memset((BYTE*)pEP, 0, ulSize);
+ pEP->cIPs = cIP;
+
+ DBGOUT("CreateExecParam pEP:%x\n", pEP);
+ return pEP;
+}
+
+//+-------------------------------------------------------------------
+//
+// Function: FillExecParam
+//
+// Synopsis: fills an exec parameter packet
+//
+//--------------------------------------------------------------------
+void FillExecParam(EXECPARAMS *pEP, DWORD dwFlags, ULONG cReps,
+ HANDLE hEventRepStart, HANDLE hEventRepDone,
+ HANDLE hEventThreadStart, HANDLE hEventThreadDone)
+{
+ DBGOUT("FillExecParam pEP:%x\n", pEP);
+
+ pEP->dwFlags = dwFlags;
+ pEP->hEventThreadStart = hEventThreadStart;
+ pEP->hEventThreadDone = hEventThreadDone;
+ pEP->hEventThreadExit = GetEvent();
+
+ pEP->cReps = cReps;
+ pEP->hEventRepStart = hEventRepStart;
+ pEP->hEventRepDone = hEventRepDone;
+}
+
+//+-------------------------------------------------------------------
+//
+// Function: ReleaseExecParam
+//
+// Synopsis: releases an exec parameter packet
+//
+//--------------------------------------------------------------------
+void ReleaseExecParam(EXECPARAMS *pEP)
+{
+ DBGOUT("ReleaseExecParam pEP:%x\n", pEP);
+
+ if (!pEP)
+ return;
+
+ // release the events.
+ ReleaseEvent(pEP->hEventThreadStart);
+ ReleaseEvent(pEP->hEventThreadDone);
+ ReleaseEvent(pEP->hEventThreadExit);
+ ReleaseEvent(pEP->hEventRepStart);
+ ReleaseEvent(pEP->hEventRepDone);
+
+ // release the interface parameter blocks
+ for (ULONG i=0; i<pEP->cIPs; i++)
+ {
+ ReleaseInterfaceParam(&(pEP->aIP[i]));
+ }
+
+ // free the memory
+ delete pEP;
+}
+
+//+-------------------------------------------------------------------
+//
+// Function: FillInterfaceParam
+//
+// Synopsis: fills default info into the interface parms
+//
+//--------------------------------------------------------------------
+void FillInterfaceParam(INTERFACEPARAMS *pIP, REFIID riid, IUnknown *punk,
+ IStream *pStm, HANDLE hEventStart, HANDLE hEventDone)
+{
+ DBGOUT("FillInterfaceParam pIP:%x\n", pIP);
+
+ pIP->iid = riid;
+ pIP->punk = punk;
+ pIP->pStm = pStm;
+ pIP->hEventStart = hEventStart;
+ pIP->hEventDone = hEventDone;
+}
+
+//+-------------------------------------------------------------------
+//
+// Function: ReleaseInterfaceParam
+//
+// Synopsis: releases an interface parameter packet
+//
+//--------------------------------------------------------------------
+void ReleaseInterfaceParam(INTERFACEPARAMS *pIP)
+{
+ DBGOUT("ReleaseInterfaceParam pIP:%x\n", pIP);
+
+ if (!pIP)
+ return;
+
+ // release the interfaces
+ ReleaseInterface(pIP->punk);
+ ReleaseInterface(pIP->pStm);
+
+ // release the events
+ ReleaseEvent(pIP->hEventStart);
+ ReleaseEvent(pIP->hEventDone);
+}
diff --git a/private/oleutest/balls/client/smarshal/smarshal.hxx b/private/oleutest/balls/client/smarshal/smarshal.hxx
new file mode 100644
index 000000000..828a0935e
--- /dev/null
+++ b/private/oleutest/balls/client/smarshal/smarshal.hxx
@@ -0,0 +1,124 @@
+//+-------------------------------------------------------------------
+//
+// File: smarshal.hxx
+//
+// Synopsis: definitions for interface marshaling stress test
+// main driver code.
+//
+// History: 21-Aug-95 Rickhi Created
+//
+//--------------------------------------------------------------------
+#include <windows.h>
+#include <ole2.h>
+#include <stdio.h>
+
+#include <tunk.h> // IUnknown interface
+#include <stream.hxx> // CStreamOnFile
+
+
+//+-------------------------------------------------------------------
+//
+// Defintions:
+//
+//--------------------------------------------------------------------
+typedef struct INTERFACEPARAMS
+{
+ IID iid; // IID of interface punk
+ IUnknown *punk; // interface pointer
+ IStream *pStm; // stream pointer
+ HANDLE hEventStart; // start event
+ HANDLE hEventDone; // done event
+} INTERFACEPARAMS;
+
+typedef struct tagEXECPARAMS
+{
+ DWORD dwFlags; // execution flags
+ HANDLE hEventThreadStart;// wait event before starting thread
+ HANDLE hEventThreadDone; // signal event when done thread
+ HANDLE hEventThreadExit; // wait event before exiting thread
+ ULONG cReps; // test reps
+ HANDLE hEventRepStart; // wait event before starting next rep
+ HANDLE hEventRepDone; // signal event when done next rep
+ ULONG cIPs; // count of interfaces that follow
+ INTERFACEPARAMS aIP[1]; // interface parameter blocks
+} EXECPARAMS;
+
+typedef enum tagOPFLAGS
+{
+ OPF_MARSHAL = 1, // marshal interface
+ OPF_UNMARSHAL = 2, // unmarshal interface
+ OPF_DISCONNECT = 4, // disconnect interface
+ OPF_RELEASEMARSHALDATA = 8, // release the marshal data
+ OPF_RELEASE = 16, // release interface
+ OPF_INITAPARTMENT = 32, // initialize apartment model
+ OPF_INITFREE = 64 // initialize freethreaded model
+} OPFLAGS;
+
+
+//+-------------------------------------------------------------------
+//
+// Globals:
+//
+//--------------------------------------------------------------------
+extern BOOL gfVerbose; // print execution messages
+extern BOOL gfDebug; // print debug messages
+
+extern int gicReps; // number of repetitions of each test
+extern int gicThreads; // number of threads to use on each test
+extern DWORD giThreadModel; // threading model to use on each test
+
+
+//+-------------------------------------------------------------------
+//
+// Macros:
+//
+//--------------------------------------------------------------------
+#define MSGOUT if (gfVerbose) printf
+#define DBGOUT if (gfDebug) printf
+#define ERROUT printf
+
+
+//+-------------------------------------------------------------------
+//
+// Function ProtoTypes:
+//
+//--------------------------------------------------------------------
+void CHKRESULT(HRESULT hr, CHAR *pszOperation);
+void CHKTESTRESULT(BOOL fRes, CHAR *pszMsg);
+
+HANDLE GetEvent(void);
+void ReleaseEvent(HANDLE hEvent);
+BOOL WaitForEvent(HANDLE hEvent);
+void SignalEvent(HANDLE hEvent);
+
+IStream * GetStream(void);
+void ReleaseStream(IStream *pStm);
+HRESULT ResetStream(IStream *pStm);
+
+IUnknown * GetInterface(void);
+void ReleaseInterface(IUnknown *punk);
+
+EXECPARAMS * CreateExecParam(ULONG cIP);
+void FillExecParam(EXECPARAMS *pEP, DWORD dwFlags, ULONG cReps,
+ HANDLE hEventRepStart, HANDLE hEventRepDone,
+ HANDLE hEventThreadStart, HANDLE hEventThreadDone);
+void ReleaseExecParam(EXECPARAMS *pEP);
+
+void FillInterfaceParam(INTERFACEPARAMS *pIP, REFIID riid,
+ IUnknown *punk, IStream *pStm,
+ HANDLE hEventStart, HANDLE hEventDone);
+void ReleaseInterfaceParam(INTERFACEPARAMS *pIP);
+
+
+DWORD _stdcall WorkerThread(void *params);
+BOOL GenericExecute(ULONG cEPs, EXECPARAMS *pEP[]);
+void GenericCleanup(ULONG cEPs, EXECPARAMS *pEP[]);
+
+
+//+-------------------------------------------------------------------
+//
+// Test Variation ProtoTypes:
+//
+//--------------------------------------------------------------------
+BOOL TestVar1(void);
+BOOL TestVar2(void);
diff --git a/private/oleutest/balls/client/smarshal/stream.cxx b/private/oleutest/balls/client/smarshal/stream.cxx
new file mode 100644
index 000000000..b99c562c3
--- /dev/null
+++ b/private/oleutest/balls/client/smarshal/stream.cxx
@@ -0,0 +1,315 @@
+//+-------------------------------------------------------------------
+//
+// File: stream.cxx
+//
+// Contents: Stream interface on flat File.
+//
+// Classes: CStreamOnFile
+//
+// Macros: DEFINE_INTERFACE_XMIT_ROUTINES
+//
+// History: 08-08-95 Rickhi Created
+//
+//--------------------------------------------------------------------
+#include <ole2.h>
+#include <stream.hxx>
+
+
+CStreamOnFile::CStreamOnFile(const WCHAR *pwszFileName, SCODE &sc, BOOL fRead) :
+ _clRefs(1),
+ _hFile(NULL),
+ _lOffset(0),
+ _cSize(0),
+ _cbData(0),
+ _fRead(fRead)
+{
+ _pbData = new BYTE[2048]; // should be big enough
+ if (!_pbData)
+ {
+ sc = E_OUTOFMEMORY;
+ return;
+ }
+
+ _cbData = 2048;
+
+ // open the file.
+ DWORD fdwCreate = (_fRead) ? OPEN_EXISTING : CREATE_ALWAYS;
+
+
+ _hFile = CreateFile(pwszFileName,
+ GENERIC_READ | GENERIC_WRITE, // fdwAccess
+ FILE_SHARE_READ | FILE_SHARE_WRITE, // fdwShareMode
+ NULL, // lpsaSecurity
+ fdwCreate, // creation options
+ FILE_ATTRIBUTE_NORMAL, // attributes & flags
+ NULL // hTemplateFile
+ );
+
+ if (_hFile == INVALID_HANDLE_VALUE)
+ {
+ sc = HRESULT_FROM_WIN32(GetLastError());
+ return;
+ }
+
+ // read the file into the memory block
+ DWORD cbRead = 0;
+ if (_fRead && ! ReadFile(_hFile,
+ _pbData,
+ _cbData,
+ &cbRead,
+ NULL))
+ {
+ sc = HRESULT_FROM_WIN32(GetLastError());
+ return;
+ }
+
+ if (_fRead)
+ {
+ _cSize = _cbData;
+ }
+
+ sc = S_OK;
+}
+
+CStreamOnFile::~CStreamOnFile(void)
+{
+ if (_hFile)
+ {
+ if (!_fRead)
+ {
+ // write the data to the file
+ DWORD cbWritten = 0;
+ if (!WriteFile(_hFile,
+ _pbData,
+ _cbData,
+ &cbWritten,
+ NULL))
+ {
+ SCODE sc = HRESULT_FROM_WIN32(GetLastError());
+ }
+ }
+
+ CloseHandle(_hFile);
+ }
+}
+
+
+
+STDMETHODIMP CStreamOnFile::QueryInterface(
+ REFIID iidInterface,
+ void FAR* FAR* ppvObj)
+{
+ HRESULT hresult = S_OK;
+
+ // We only support IUnknown and IStream
+ if (IsEqualIID(iidInterface, IID_IUnknown) ||
+ IsEqualIID(iidInterface, IID_IStream))
+ {
+ *ppvObj = this;
+ AddRef();
+ }
+ else
+ {
+ *ppvObj = NULL;
+ hresult = E_NOINTERFACE;
+ }
+
+ return hresult;
+}
+
+STDMETHODIMP_(ULONG) CStreamOnFile::AddRef(void)
+{
+ InterlockedIncrement(&_clRefs);
+ return _clRefs;
+}
+
+STDMETHODIMP_(ULONG) CStreamOnFile::Release(void)
+{
+ if (InterlockedDecrement(&_clRefs) == 0)
+ {
+ delete this;
+ return 0;
+ }
+
+ return _clRefs;
+}
+
+STDMETHODIMP CStreamOnFile::Read(
+ VOID HUGEP* pv,
+ ULONG cb,
+ ULONG FAR* pcbRead)
+{
+ HRESULT hresult = S_OK;
+
+ if (pcbRead)
+ {
+ *pcbRead = 0L;
+ }
+
+ if ((LONG)cb + _lOffset > _cSize)
+ {
+ cb = _cSize - _lOffset;
+ hresult = STG_E_READFAULT;
+ }
+
+ memcpy(pv, _pbData + _lOffset, (size_t) cb);
+ _lOffset += cb;
+
+ if (pcbRead != NULL)
+ {
+ *pcbRead = cb;
+ }
+
+ return hresult;
+}
+
+STDMETHODIMP CStreamOnFile::Write(
+ VOID const HUGEP* pv,
+ ULONG cbToWrite,
+ ULONG FAR* pcbWritten)
+{
+ HRESULT hresult = S_OK;
+
+ if (pcbWritten)
+ {
+ *pcbWritten = 0L;
+ }
+
+ if (cbToWrite + _lOffset > _cbData)
+ {
+ return E_OUTOFMEMORY;
+ }
+
+ // copy in the new data
+ memcpy(_pbData + _lOffset, pv, (size_t) cbToWrite);
+ _lOffset += cbToWrite;
+
+ if (pcbWritten != NULL)
+ {
+ *pcbWritten = cbToWrite;
+ }
+
+ // We assume maxium size of buffer is the size to send on the network.
+ if (_cSize < _lOffset)
+ {
+ _cSize = _lOffset;
+ }
+
+ return hresult;
+}
+
+
+
+STDMETHODIMP CStreamOnFile::Seek(
+ LARGE_INTEGER dlibMoveIN,
+ DWORD dwOrigin,
+ ULARGE_INTEGER FAR* plibNewPosition)
+{
+ HRESULT hresult = S_OK;
+
+ LONG dlibMove = dlibMoveIN.LowPart;
+ ULONG cbNewPos = dlibMove;
+
+ switch(dwOrigin)
+ {
+ case STREAM_SEEK_SET:
+
+ if (dlibMove >= 0)
+ {
+ _lOffset = dlibMove;
+ }
+ else
+ {
+ hresult = STG_E_SEEKERROR;
+ }
+ break;
+
+ case STREAM_SEEK_CUR:
+
+ if (!(dlibMove < 0 && (-dlibMove > _lOffset)))
+ {
+ _lOffset += (ULONG) dlibMove;
+ }
+ else
+ {
+ hresult = STG_E_SEEKERROR;
+ }
+ break;
+
+ case STREAM_SEEK_END:
+
+ if (!(dlibMove < 0 && ((ULONG) -dlibMove) > _cbData))
+ {
+ _lOffset = _cbData + dlibMove;
+ }
+ else
+ {
+ hresult = STG_E_SEEKERROR;
+ }
+ break;
+
+ default:
+
+ hresult = STG_E_SEEKERROR;
+ }
+
+ if (plibNewPosition != NULL)
+ {
+ ULISet32(*plibNewPosition, _lOffset);
+ }
+
+ return hresult;
+}
+
+STDMETHODIMP CStreamOnFile::SetSize(ULARGE_INTEGER cb)
+{
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP CStreamOnFile::CopyTo(
+ IStream FAR* pstm,
+ ULARGE_INTEGER cb,
+ ULARGE_INTEGER FAR* pcbRead,
+ ULARGE_INTEGER FAR* pcbWritten)
+{
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP CStreamOnFile::Commit(DWORD grfCommitFlags)
+{
+ return NOERROR;
+}
+
+STDMETHODIMP CStreamOnFile::Revert(void)
+{
+ return NOERROR;
+}
+
+STDMETHODIMP CStreamOnFile::LockRegion(
+ ULARGE_INTEGER libOffset,
+ ULARGE_INTEGER cb,
+ DWORD dwLockType)
+{
+ return STG_E_INVALIDFUNCTION;
+}
+
+STDMETHODIMP CStreamOnFile::UnlockRegion(
+ ULARGE_INTEGER libOffset,
+ ULARGE_INTEGER cb,
+ DWORD dwLockType)
+{
+ return STG_E_INVALIDFUNCTION;
+}
+
+STDMETHODIMP CStreamOnFile::Stat(
+ STATSTG FAR* pstatstg,
+ DWORD statflag)
+{
+ memset(pstatstg, 0, sizeof(STATSTG));
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP CStreamOnFile::Clone(IStream FAR * FAR *ppstm)
+{
+ return E_NOTIMPL;
+}
diff --git a/private/oleutest/balls/client/smarshal/stream.hxx b/private/oleutest/balls/client/smarshal/stream.hxx
new file mode 100644
index 000000000..0c6d62760
--- /dev/null
+++ b/private/oleutest/balls/client/smarshal/stream.hxx
@@ -0,0 +1,96 @@
+//+-------------------------------------------------------------------
+//
+// File: stream.hxx
+//
+// Contents: Stream class on a file.
+//
+// Classes: CStreamOnFile
+//
+// History: 08-08-95 Rickhi Created
+//
+//--------------------------------------------------------------------
+#ifndef __STREAMONFILE_HXX__
+#define __STREAMONFILE_HXX__
+
+
+//+-------------------------------------------------------------------
+//
+// Class: CStreamOnFile
+//
+// Purpose: Stream wrapper for a flat file.
+//
+// History: 08-08-95 Rickhi Created
+//
+//--------------------------------------------------------------------
+class CStreamOnFile : public IStream
+{
+public:
+ CStreamOnFile(const WCHAR *pwszFileName, SCODE &sc, BOOL fRead);
+ ~CStreamOnFile(void);
+
+ STDMETHOD(QueryInterface)(
+ REFIID iidInterface,
+ void FAR* FAR* ppvObj);
+
+ STDMETHOD_(ULONG,AddRef)(void);
+
+ STDMETHOD_(ULONG,Release)(void);
+
+ STDMETHOD(Read)(
+ VOID HUGEP* pv,
+ ULONG cb,
+ ULONG FAR* pcbRead);
+
+ STDMETHOD(Write)(
+ VOID const HUGEP* pv,
+ ULONG cb,
+ ULONG FAR* pcbWritten);
+
+ STDMETHOD(Seek)(
+ LARGE_INTEGER dlibMove,
+ DWORD dwOrigin,
+ ULARGE_INTEGER FAR* plibNewPosition);
+
+ STDMETHOD(SetSize) (ULARGE_INTEGER cb);
+
+ STDMETHOD(CopyTo)(
+ IStream FAR* pstm,
+ ULARGE_INTEGER cb,
+ ULARGE_INTEGER FAR* pcbRead,
+ ULARGE_INTEGER FAR* pcbWritten);
+
+ STDMETHOD(Commit)(DWORD grfCommitFlags);
+
+ STDMETHOD(Revert)(void);
+
+ STDMETHOD(LockRegion)(
+ ULARGE_INTEGER libOffset,
+ ULARGE_INTEGER cb,
+ DWORD dwLockType);
+
+ STDMETHOD(UnlockRegion)(
+ ULARGE_INTEGER libOffset,
+ ULARGE_INTEGER cb,
+ DWORD dwLockType);
+
+ STDMETHOD(Stat)(
+ STATSTG FAR* pstatstg,
+ DWORD statflag);
+
+ STDMETHOD(Clone)(IStream FAR * FAR *ppstm);
+
+private:
+
+ LONG _clRefs; // reference count
+ HANDLE _hFile; // file handle
+ BOOL _fRead; // read or write side
+
+ LONG _lOffset; // current seek ptr
+ LONG _cSize; // number of bytes written
+
+ ULONG _cbData; // size of data
+ BYTE *_pbData; // ptr to data
+
+};
+
+#endif // _STREAMONFILE_HXX__
diff --git a/private/oleutest/balls/client/smarshal/testvars.cxx b/private/oleutest/balls/client/smarshal/testvars.cxx
new file mode 100644
index 000000000..6cf2ed214
--- /dev/null
+++ b/private/oleutest/balls/client/smarshal/testvars.cxx
@@ -0,0 +1,301 @@
+//+-------------------------------------------------------------------
+//
+// File: testvars.cxx
+//
+// Synopsis: source code for Interface Marshaling stress test
+// variations.
+//
+// History: 21-Aug-95 Rickhi Created
+//
+//--------------------------------------------------------------------
+#include <smarshal.hxx>
+
+//+-------------------------------------------------------------------
+//
+// Private Function ProtoTypes:
+//
+//--------------------------------------------------------------------
+BOOL SingleThreadOps(ULONG cThreads, ULONG cReps, DWORD dwFlags);
+
+BOOL ThreadPairOps(ULONG cThreadPairs, ULONG cReps,
+ DWORD dwServerFlags, DWORD dwClientFlags);
+
+
+//+-------------------------------------------------------------------
+//
+// Function: TestVar1
+//
+// Synopsis: Multiple Operations on the Same Thread.
+//
+// History: 21-Aug-95 Rickhi Created
+//
+//--------------------------------------------------------------------
+BOOL TestVar1(void)
+{
+ MSGOUT("TestStart: TestLevel1\n");
+
+ ULONG cThreads = gicThreads;
+ ULONG cReps = gicReps;
+ DWORD dwOps = 0;
+ BOOL fRes;
+
+
+ // VAR1: test Marshal + ReleaseMarshalData
+
+ dwOps = giThreadModel | OPF_MARSHAL | OPF_RELEASEMARSHALDATA;
+ fRes = SingleThreadOps(cThreads, cReps, dwOps);
+ CHKTESTRESULT(fRes, "TestVar1");
+
+
+ // VAR2: test Marshal + Unmarshal + Release
+
+ dwOps = giThreadModel | OPF_MARSHAL | OPF_UNMARSHAL | OPF_RELEASE;
+ fRes = SingleThreadOps(cThreads, cReps, dwOps);
+ CHKTESTRESULT(fRes, "TestVar2");
+
+
+ // VAR3: test Marshal + Disconnect
+
+ dwOps = giThreadModel | OPF_MARSHAL | OPF_DISCONNECT;
+ fRes = SingleThreadOps(cThreads, cReps, dwOps);
+ CHKTESTRESULT(fRes, "TestVar3");
+
+
+
+ CHKTESTRESULT(fRes, "TestLevel1");
+ return fRes;
+}
+
+//+-------------------------------------------------------------------
+//
+// Function: SingleThreadOps
+//
+// Synopsis: Perform Operations on the Same Thread.
+//
+// History: 21-Aug-95 Rickhi Created
+//
+//--------------------------------------------------------------------
+BOOL SingleThreadOps(ULONG cThreads, ULONG cReps, DWORD dwFlags)
+{
+ BOOL fRes = TRUE;
+ MSGOUT("SingleThreadOps Start\n");
+
+ // CODEWORK: multiple interfaces
+ ULONG cIPs = 1;
+
+ EXECPARAMS *pEP[20]; // can launch up to 20 threads at once
+
+ for (ULONG i=0; i<cThreads; i++)
+ {
+ // build an execution parameter block
+ pEP[i] = CreateExecParam(cIPs);
+
+ // fill in the execution parameter block. we dont need events
+ // to synchronize the repetitions since all operations are done
+ // on the same thread.
+
+ FillExecParam(pEP[i],
+ dwFlags, // dwFlags (operations to perform)
+ cReps, // cReps
+ NULL, // hEventRepStart
+ NULL, // hEventRepDone
+ GetEvent(), // hEventThreadStart
+ GetEvent()); // hEventThreadDone
+
+ // fill in the INTERFACEPARAMSs
+ for (ULONG j=0; j<cIPs; j++)
+ {
+ INTERFACEPARAMS *pIP = &(pEP[i]->aIP[j]);
+
+ FillInterfaceParam(pIP,
+ IID_IUnknown, // iid to operate on
+ GetInterface(), // interface pointer to operate on
+ GetStream(), // stream to use
+ NULL, // per interface start event
+ NULL); // per interface done event
+ }
+ }
+
+ // Execute all the command blocks simultaneously
+ fRes = GenericExecute(cThreads, pEP);
+
+ GenericCleanup(cThreads, pEP);
+
+ CHKTESTRESULT(fRes, "SingleThreadOps");
+ return fRes;
+}
+
+//+-------------------------------------------------------------------
+//
+// Function: TestVar2
+//
+// Synopsis: Operations on Thread Pairs (1 server, 1 client)
+//
+// History: 21-Aug-95 Rickhi Created
+//
+//--------------------------------------------------------------------
+BOOL TestVar2(void)
+{
+ MSGOUT("TestStart: TestLevel2\n");
+
+ ULONG cThreads = gicThreads;
+ ULONG cReps = gicReps;
+ DWORD dwOps = 0;
+ BOOL fRes;
+
+
+ // VAR1: test Marshal on Server, Unmarshal + Release on Client.
+
+ DWORD dwSrvOps = giThreadModel | OPF_MARSHAL;
+ DWORD dwCliOps = giThreadModel | OPF_UNMARSHAL | OPF_RELEASE;
+ fRes = ThreadPairOps(cThreads, cReps, dwSrvOps, dwCliOps);
+ CHKTESTRESULT(fRes, "TestVar1");
+
+
+ // VAR2: test Marshal on Server, RMD on Client.
+
+#if 0
+ dwSrvOps = giThreadModel | OPF_MARSHAL;
+ dwCliOps = giThreadModel | OPF_RELEASEMARSHALDATA;
+ fRes = ThreadPairOps(cThreads, cReps, dwSrvOps, dwCliOps);
+ CHKTESTRESULT(fRes, "TestVar1");
+#endif
+
+
+ CHKTESTRESULT(fRes, "TestLevel2");
+ return fRes;
+}
+
+//+-------------------------------------------------------------------
+//
+// Function: ThreadPairOps
+//
+// Synopsis: Perform Operations on two synchronized threads.
+//
+// History: 21-Aug-95 Rickhi Created
+//
+//--------------------------------------------------------------------
+BOOL ThreadPairOps(ULONG cThreadPairs, ULONG cReps,
+ DWORD dwServerFlags, DWORD dwClientFlags)
+{
+ BOOL fRes = TRUE;
+ MSGOUT("ThreadPairOps Start\n");
+
+ // CODEWORK: multiple interfaces
+ ULONG cIPs = 1;
+
+ EXECPARAMS *pEP[20]; // can launch up to 20 threads at once
+
+ for (ULONG i=0; i<cThreadPairs * 2; i+=2)
+ {
+ // build execution parameter blocks for the server and client threads.
+ EXECPARAMS *pEPSrv = CreateExecParam(cIPs);
+ EXECPARAMS *pEPCli = CreateExecParam(cIPs);
+ pEP[i] = pEPSrv;
+ pEP[i+1] = pEPCli;
+
+
+ // fill in the server execution parameter block.
+ FillExecParam(pEPSrv,
+ dwServerFlags, // dwFlags (operations to perform)
+ cReps, // cReps
+ GetEvent(), // hEventRepStart
+ GetEvent(), // hEventRepDone
+ GetEvent(), // hEventThreadStart
+ GetEvent()); // hEventThreadDone
+
+ // we need to kick the hEventRepStart in order to get the ball rolling,
+ // since the server thread will be waiting on it.
+
+ SignalEvent(pEPSrv->hEventRepStart);
+
+ // client waits for the server to complete his first repetition
+ // before starting. Server waits for the client to complete his
+ // first repetition before starting the next iteration.
+
+ FillExecParam(pEPCli,
+ dwClientFlags, // dwFlags (operations to perform)
+ cReps, // cReps
+ pEPSrv->hEventRepDone, // hEventRepStart
+ pEPSrv->hEventRepStart, // hEventRepDone
+ GetEvent(), // hEventThreadStart
+ GetEvent()); // hEventThreadDone
+
+
+ // fill in the INTERFACEPARAMSs
+ // CODEWORK: when multiple interfaces, will need to use events.
+
+ for (ULONG j=0; j<cIPs; j++)
+ {
+ INTERFACEPARAMS *pIPSrv = &(pEPSrv->aIP[j]);
+ INTERFACEPARAMS *pIPCli = &(pEPCli->aIP[j]);
+
+ FillInterfaceParam(pIPSrv,
+ IID_IUnknown, // iid to operate on
+ GetInterface(), // interface pointer to operate on
+ GetStream(), // stream to use
+ NULL, // per interface start event
+ NULL); // per interface done event
+
+ // AddRef the stream pointer since both the client and server
+ // will hold pointers to it.
+
+ pIPSrv->pStm->AddRef();
+
+ FillInterfaceParam(pIPCli,
+ IID_IUnknown, // iid to operate on
+ NULL, // interface pointer to operate on
+ pIPSrv->pStm, // use same stream as the server
+ NULL, // per interface start event
+ NULL); // per interface done event
+ }
+ }
+
+ // Execute all the command blocks simultaneously
+ fRes = GenericExecute(cThreadPairs * 2, pEP);
+
+ // cleanup all the command blocks. We need to NULL out one copy of
+ // those events that are shared between two command blocks.
+ for (i=0; i<cThreadPairs * 2; i+=2)
+ {
+ EXECPARAMS *pEPCli = pEP[i+1];
+ pEPCli->hEventRepStart = NULL;
+ pEPCli->hEventRepDone = NULL;
+
+ for (ULONG j=0; j<cIPs; j++)
+ {
+ INTERFACEPARAMS *pIPCli = &(pEPCli->aIP[j]);
+ pIPCli->hEventStart = NULL;
+ pIPCli->hEventDone = NULL;
+ }
+ }
+
+ GenericCleanup(cThreadPairs * 2, pEP);
+
+
+ CHKTESTRESULT(fRes, "ThreadPairOps");
+ return fRes;
+}
+
+//+-------------------------------------------------------------------
+//
+// Function: TestLevel3
+//
+// Synopsis: Operations on Thread Pools (1 server, n clients)
+//
+// History: 21-Aug-95 Rickhi Created
+//
+//--------------------------------------------------------------------
+BOOL TestLevel3(void)
+{
+ BOOL fRes = TRUE;
+ MSGOUT("TestStart: TestLevel3\n");
+
+ // build a command block
+
+ // launch a thread to run the command block
+
+
+ CHKTESTRESULT(fRes, "TestLevel3");
+ return fRes;
+}
diff --git a/private/oleutest/balls/client/smarshal/tunk.cxx b/private/oleutest/balls/client/smarshal/tunk.cxx
new file mode 100644
index 000000000..981c3b72b
--- /dev/null
+++ b/private/oleutest/balls/client/smarshal/tunk.cxx
@@ -0,0 +1,66 @@
+
+
+// #include <oleport.h>
+#include <windows.h>
+#include <ole2.h>
+#include <stdio.h>
+#include <tunk.h>
+
+
+CTestUnk::CTestUnk(void) : _cRefs(1)
+{
+}
+
+CTestUnk::~CTestUnk(void)
+{
+}
+
+
+STDMETHODIMP CTestUnk::QueryInterface(REFIID riid, LPVOID FAR* ppvObj)
+{
+ HRESULT hRslt = S_OK;
+
+ if (IsEqualIID(riid, IID_IUnknown) ||
+ IsEqualIID(riid, IID_IParseDisplayName))
+ {
+ *ppvObj = (void *)(IParseDisplayName *)this;
+ AddRef();
+ }
+ else
+ {
+ *ppvObj = NULL;
+ hRslt = E_NOINTERFACE;
+ }
+
+ return hRslt;
+}
+
+
+
+STDMETHODIMP_(ULONG) CTestUnk::AddRef(void)
+{
+ _cRefs++;
+ return _cRefs;
+}
+
+
+STDMETHODIMP_(ULONG) CTestUnk::Release(void)
+{
+ _cRefs--;
+ if (_cRefs == 0)
+ {
+ delete this;
+ return 0;
+ }
+ else
+ {
+ return _cRefs;
+ }
+}
+
+
+STDMETHODIMP CTestUnk::ParseDisplayName(LPBC pbc, LPOLESTR lpszDisplayName,
+ ULONG *pchEaten, LPMONIKER *ppmkOut)
+{
+ return S_OK;
+}
diff --git a/private/oleutest/balls/client/smarshal/tunk.h b/private/oleutest/balls/client/smarshal/tunk.h
new file mode 100644
index 000000000..d767f15aa
--- /dev/null
+++ b/private/oleutest/balls/client/smarshal/tunk.h
@@ -0,0 +1,26 @@
+#ifndef _TUNK_
+#define _TUNK_
+
+class CTestUnk : public IParseDisplayName
+{
+public:
+ CTestUnk(void);
+
+ // IUnknown
+ STDMETHODIMP QueryInterface(REFIID iid, void FAR * FAR * ppv);
+ STDMETHODIMP_(ULONG) AddRef(void);
+ STDMETHODIMP_(ULONG) Release(void);
+
+ // IParseDisplayName
+ STDMETHODIMP ParseDisplayName(LPBC pbc, LPOLESTR lpszDisplayName,
+ ULONG *pchEaten, LPMONIKER *ppmkOut);
+
+private:
+
+ ~CTestUnk(void);
+
+ ULONG _cRefs;
+
+};
+
+#endif // _TUNK_
diff --git a/private/oleutest/balls/client/tmarshal/daytona/makefile b/private/oleutest/balls/client/tmarshal/daytona/makefile
new file mode 100644
index 000000000..1d3728d41
--- /dev/null
+++ b/private/oleutest/balls/client/tmarshal/daytona/makefile
@@ -0,0 +1,10 @@
+############################################################################
+#
+# Copyright (C) 1992, Microsoft Corporation.
+#
+# All rights reserved.
+#
+############################################################################
+
+!include $(NTMAKEENV)\makefile.def
+
diff --git a/private/oleutest/balls/client/tmarshal/daytona/sources b/private/oleutest/balls/client/tmarshal/daytona/sources
new file mode 100644
index 000000000..64d949d7d
--- /dev/null
+++ b/private/oleutest/balls/client/tmarshal/daytona/sources
@@ -0,0 +1,60 @@
+!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.
+
+!ENDIF
+
+#
+# The following includes a global include file defined at the
+# base of the project for all components
+#
+
+!include ..\..\daytona.inc
+
+#
+# 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= tmarshal
+
+#
+# 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= $(INCLUDES);$(BASEDIR)\private\dcomidl\obj
+C_DEFINES= $(C_DEFINES)
+
+
+SOURCES= \
+ ..\tmarshal.cxx \
+ ..\tunk.cxx \
+ ..\main.cxx \
+ ..\stream.cxx \
+ ..\objref.cxx
+
+
+UMTYPE= console
+UMENTRY= main
diff --git a/private/oleutest/balls/client/tmarshal/dirs b/private/oleutest/balls/client/tmarshal/dirs
new file mode 100644
index 000000000..1d0b9edbb
--- /dev/null
+++ b/private/oleutest/balls/client/tmarshal/dirs
@@ -0,0 +1,38 @@
+!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/balls/client/tmarshal/main.cxx b/private/oleutest/balls/client/tmarshal/main.cxx
new file mode 100644
index 000000000..539cdc436
--- /dev/null
+++ b/private/oleutest/balls/client/tmarshal/main.cxx
@@ -0,0 +1,29 @@
+//+------------------------------------------------------------------
+//
+// File: main.cxx
+//
+// Contents: common entry point for test drivers.
+//
+//--------------------------------------------------------------------
+#include <tstmain.hxx>
+#include <tmarshal.h>
+
+//+-------------------------------------------------------------------
+//
+// Function: main
+//
+// Synopsis: Entry point to EXE
+//
+// Returns: TRUE
+//
+// History: 21-Nov-92 Rickhi Created
+//
+// Just delegates to a <main> subroutine that is common for all test
+// drivers.
+//
+//
+//--------------------------------------------------------------------
+int _cdecl main(int argc, char **argv)
+{
+ return DriverMain(argc, argv, "InterfaceMarshal", &TestMarshal);
+}
diff --git a/private/oleutest/balls/client/tmarshal/objref.cxx b/private/oleutest/balls/client/tmarshal/objref.cxx
new file mode 100644
index 000000000..c9d7eb3ce
--- /dev/null
+++ b/private/oleutest/balls/client/tmarshal/objref.cxx
@@ -0,0 +1,270 @@
+
+#include <windows.h>
+#include <ole2.h>
+#include <stdio.h>
+#include <malloc.h> // _alloca
+#include <obase.h> // def'n of OBJREF
+
+//-------------------------------------------------------------------------
+
+// convenient mappings
+#define ORCST(objref) objref.u_objref.u_custom
+#define ORSTD(objref) objref.u_objref.u_standard
+#define ORHDL(objref) objref.u_objref.u_handler
+
+
+// bits that must be zero in the flags fields
+#define OBJREF_RSRVD_MBZ ~(OBJREF_STANDARD | OBJREF_HANDLER | OBJREF_CUSTOM)
+
+#define SORF_RSRVD_MBZ ~(SORF_NOPING | SORF_OXRES1 | SORF_OXRES2 | \
+ SORF_OXRES3 | SORF_OXRES4 | SORF_OXRES5 | \
+ SORF_OXRES6 | SORF_OXRES7 | SORF_OXRES8)
+
+
+// Internal Uses of the reserved SORF_OXRES flags.
+
+// SORF_TBLWEAK is needed so that RMD works correctly on TABLEWEAK
+// marshaling, so it is ignored by unmarshalers. Therefore, we use one of
+// the bits reserved for the object exporter that must be ignored by
+// unmarshalers.
+//
+// SORF_WEAKREF is needed for container weak references, when handling
+// an IRemUnknown::RemQueryInterface on a weak interface. This is a strictly
+// local (windows) machine protocol, so we use a reserved bit.
+//
+// SORF_NONNDR is needed for interop of 16bit custom (non-NDR) marshalers
+// with 32bit, since the 32bit guys want to use MIDL (NDR) to talk to other
+// 32bit processes and remote processes, but the custom (non-NDR) format to
+// talk to local 16bit guys. In particular, this is to support OLE Automation.
+//
+// SORF_FREETHREADED is needed when we create a proxy to the SCM interface
+// in the apartment model. All apartments can use the same proxy so we avoid
+// the test for calling on the correct thread.
+
+#define SORF_TBLWEAK SORF_OXRES1 // (table) weak reference
+#define SORF_WEAKREF SORF_OXRES2 // (normal) weak reference
+#define SORF_NONNDR SORF_OXRES3 // stub does not use NDR marshaling
+#define SORF_FREETHREADED SORF_OXRES4 // proxy may be used on any thread
+
+
+// definition to simplify coding
+const DWORD MSHLFLAGS_TABLE = MSHLFLAGS_TABLESTRONG | MSHLFLAGS_TABLEWEAK;
+
+const DWORD MSHLFLAGS_USER_MASK = MSHLFLAGS_NORMAL | MSHLFLAGS_TABLE |
+ MSHLFLAGS_NOPING;
+
+
+// return codes
+#define INVALID_SORFFLAG 90000001
+#define INVALID_REFCNT 90000002
+#define INVALID_MSHLFLAG 90000003
+
+//-------------------------------------------------------------------------
+
+//+-------------------------------------------------------------------------
+//
+// Function: StRead
+//
+// Synopsis: Stream read that only succeeds if all requested bytes read
+//
+// Arguments: [pStm] -- source stream
+// [pvBuffer] -- destination buffer
+// [ulcb] -- bytes to read
+//
+// Returns: S_OK if successful, else error code
+//
+//--------------------------------------------------------------------------
+HRESULT StRead(IStream *pStm, void *pvBuffer, ULONG ulcb)
+{
+ ULONG cbRead;
+ HRESULT hr = pStm->Read(pvBuffer, ulcb, &cbRead);
+
+ if (SUCCEEDED(hr))
+ {
+ if (ulcb != cbRead)
+ {
+ hr = STG_E_READFAULT;
+ }
+ }
+
+ return hr;
+}
+
+void DbgDumpSTD(STDOBJREF *pStd)
+{
+
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: ReadObjRef
+//
+// Synopsis: Reads an OBJREF from the stream
+//
+// Arguments: [pStm] -- source stream
+// [objref] -- destination buffer
+//
+// Returns: S_OK if successful, else error code
+//
+//--------------------------------------------------------------------------
+HRESULT ReadObjRef(IStream *pStm, OBJREF &objref, STDOBJREF **ppStd)
+{
+ HRESULT hr = StRead(pStm, &objref, 2*sizeof(ULONG)+sizeof(IID));
+
+ if (SUCCEEDED(hr))
+ {
+ if ((objref.signature != OBJREF_SIGNATURE) ||
+ (objref.flags & OBJREF_RSRVD_MBZ) ||
+ (objref.flags == 0))
+ {
+ // the objref signature is bad, or one of the reserved
+ // bits in the flags is set, or none of the required bits
+ // in the flags is set. the objref cant be interpreted so
+ // fail the call.
+
+ return E_UNEXPECTED; // BUGBUG:
+ }
+
+ // compute the size of the remainder of the objref and
+ // include the size fields for the resolver string array
+
+ STDOBJREF *pStd = &ORSTD(objref).std;
+ DUALSTRINGARRAY *psa;
+ ULONG cbToRead;
+
+ if (objref.flags & OBJREF_STANDARD)
+ {
+ cbToRead = sizeof(STDOBJREF) + sizeof(ULONG);
+ psa = &ORSTD(objref).saResAddr;
+ }
+ else if (objref.flags & OBJREF_HANDLER)
+ {
+ cbToRead = sizeof(STDOBJREF) + sizeof(CLSID) + sizeof(ULONG);
+ psa = &ORHDL(objref).saResAddr;
+ }
+ else if (objref.flags & OBJREF_CUSTOM)
+ {
+ cbToRead = sizeof(CLSID) + sizeof(DWORD); // clsid + data size
+ psa = NULL;
+ }
+
+ // return ptr to STDOBJREF
+ *ppStd = pStd;
+
+ // read the rest of the (fixed sized) objref from the stream
+ hr = StRead(pStm, pStd, cbToRead);
+
+ if (SUCCEEDED(hr) && psa)
+ {
+ // Non custom interface. Make sure the resolver string array
+ // has some sensible values.
+
+ if (psa->wSecurityOffset >= psa->wNumEntries)
+ {
+ hr = E_UNEXPECTED; // BUGBUG: correct return code
+ }
+ }
+
+ if (SUCCEEDED(hr) && psa)
+ {
+ // Non custom interface. The data that follows is a variable
+ // sized string array. Allocate memory for it and then read it.
+
+ DbgDumpSTD(pStd);
+
+ cbToRead = psa->wNumEntries * sizeof(WCHAR);
+
+ DUALSTRINGARRAY *psaNew = (DUALSTRINGARRAY *) _alloca(cbToRead +
+ sizeof(ULONG));
+ if (psaNew != NULL)
+ {
+ // update the size fields and read in the rest of the data
+ psaNew->wSecurityOffset = psa->wSecurityOffset;
+ psaNew->wNumEntries = psa->wNumEntries;
+
+ hr = StRead(pStm, psaNew->aStringArray, cbToRead);
+ }
+ else
+ {
+ psa->wNumEntries = 0;
+ psa->wSecurityOffset = 0;
+ hr = E_OUTOFMEMORY;
+
+ // seek the stream past what we should have read, ignore
+ // seek errors, since the OOM takes precedence.
+
+ LARGE_INTEGER libMove;
+ libMove.LowPart = cbToRead;
+ libMove.HighPart = 0;
+ pStm->Seek(libMove, STREAM_SEEK_CUR, 0);
+ }
+ }
+ }
+
+ return hr;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: VerifyOBJREFFormat
+//
+// Synopsis: Checks the format of the marshal packet
+//
+// Arguments: [pStm] -- source stream
+// [mshlflags] -- destination buffer
+//
+// Returns: S_OK if successful, else error code
+//
+//--------------------------------------------------------------------------
+HRESULT VerifyOBJREFFormat(IStream *pStm, DWORD mshlflags)
+{
+ OBJREF objref;
+ STDOBJREF *pStd;
+ HRESULT hr = ReadObjRef(pStm, objref, &pStd);
+
+ // now verify the format
+ if (SUCCEEDED(hr))
+ {
+ if (mshlflags & MSHLFLAGS_NOPING)
+ {
+ // SORF_NOPING should be set (unless previously marshaled PING)
+ if (!(pStd->flags & SORF_NOPING))
+ return INVALID_SORFFLAG;
+ }
+
+ if ((mshlflags & MSHLFLAGS_TABLE) == MSHLFLAGS_NORMAL)
+ {
+ // refcnt should be non-zero
+ if (pStd->cPublicRefs == 0)
+ return INVALID_REFCNT;
+
+ // table flags should not be set
+ if (pStd->flags & (SORF_WEAKREF | SORF_TBLWEAK))
+ return INVALID_SORFFLAG;
+ }
+ else if ((mshlflags & MSHLFLAGS_TABLE) == MSHLFLAGS_TABLESTRONG)
+ {
+ // refcnt should be zero
+ if (pStd->cPublicRefs != 0)
+ return INVALID_REFCNT;
+
+ }
+ else if ((mshlflags & MSHLFLAGS_TABLE) == MSHLFLAGS_TABLEWEAK)
+ {
+ // refcnt should be zero
+ if (pStd->cPublicRefs != 0)
+ return INVALID_REFCNT;
+
+ // SORF_TBLWEAK should be set
+ if (!(pStd->flags & SORF_TBLWEAK))
+ return INVALID_SORFFLAG;
+ }
+ else
+ {
+ // unknown flags
+ return INVALID_MSHLFLAG;
+ }
+ }
+
+ return hr;
+}
diff --git a/private/oleutest/balls/client/tmarshal/stream.cxx b/private/oleutest/balls/client/tmarshal/stream.cxx
new file mode 100644
index 000000000..5c6f34717
--- /dev/null
+++ b/private/oleutest/balls/client/tmarshal/stream.cxx
@@ -0,0 +1,315 @@
+//+-------------------------------------------------------------------
+//
+// File: stream.cxx
+//
+// Contents: Stream interface on flat File.
+//
+// Classes: CStreamOnFile
+//
+// Macros: DEFINE_INTERFACE_XMIT_ROUTINES
+//
+// History: 08-08-95 Rickhi Created
+//
+//--------------------------------------------------------------------
+#include <ole2.h>
+#include <stream.hxx>
+
+
+CStreamOnFile::CStreamOnFile(const WCHAR *pwszFileName, SCODE &sc, BOOL fRead) :
+ _clRefs(1),
+ _hFile(NULL),
+ _lOffset(0),
+ _cSize(0),
+ _cbData(0),
+ _fRead(fRead)
+{
+ _pbData = new BYTE[2048]; // should be big enough
+ if (!_pbData)
+ {
+ sc = E_OUTOFMEMORY;
+ return;
+ }
+
+ _cbData = 2048;
+
+ // open the file.
+ DWORD fdwCreate = (_fRead) ? OPEN_EXISTING : CREATE_ALWAYS;
+
+
+ _hFile = CreateFileW(pwszFileName,
+ GENERIC_READ | GENERIC_WRITE, // fdwAccess
+ FILE_SHARE_READ | FILE_SHARE_WRITE, // fdwShareMode
+ NULL, // lpsaSecurity
+ fdwCreate, // creation options
+ FILE_ATTRIBUTE_NORMAL, // attributes & flags
+ NULL // hTemplateFile
+ );
+
+ if (_hFile == INVALID_HANDLE_VALUE)
+ {
+ sc = HRESULT_FROM_WIN32(GetLastError());
+ return;
+ }
+
+ // read the file into the memory block
+ DWORD cbRead = 0;
+ if (_fRead && ! ReadFile(_hFile,
+ _pbData,
+ _cbData,
+ &cbRead,
+ NULL))
+ {
+ sc = HRESULT_FROM_WIN32(GetLastError());
+ return;
+ }
+
+ if (_fRead)
+ {
+ _cSize = _cbData;
+ }
+
+ sc = S_OK;
+}
+
+CStreamOnFile::~CStreamOnFile(void)
+{
+ if (_hFile)
+ {
+ if (!_fRead)
+ {
+ // write the data to the file
+ DWORD cbWritten = 0;
+ if (!WriteFile(_hFile,
+ _pbData,
+ _cbData,
+ &cbWritten,
+ NULL))
+ {
+ SCODE sc = HRESULT_FROM_WIN32(GetLastError());
+ }
+ }
+
+ CloseHandle(_hFile);
+ }
+}
+
+
+
+STDMETHODIMP CStreamOnFile::QueryInterface(
+ REFIID iidInterface,
+ void FAR* FAR* ppvObj)
+{
+ HRESULT hresult = S_OK;
+
+ // We only support IUnknown and IStream
+ if (IsEqualIID(iidInterface, IID_IUnknown) ||
+ IsEqualIID(iidInterface, IID_IStream))
+ {
+ *ppvObj = this;
+ AddRef();
+ }
+ else
+ {
+ *ppvObj = NULL;
+ hresult = E_NOINTERFACE;
+ }
+
+ return hresult;
+}
+
+STDMETHODIMP_(ULONG) CStreamOnFile::AddRef(void)
+{
+ InterlockedIncrement(&_clRefs);
+ return _clRefs;
+}
+
+STDMETHODIMP_(ULONG) CStreamOnFile::Release(void)
+{
+ if (InterlockedDecrement(&_clRefs) == 0)
+ {
+ delete this;
+ return 0;
+ }
+
+ return _clRefs;
+}
+
+STDMETHODIMP CStreamOnFile::Read(
+ VOID HUGEP* pv,
+ ULONG cb,
+ ULONG FAR* pcbRead)
+{
+ HRESULT hresult = S_OK;
+
+ if (pcbRead)
+ {
+ *pcbRead = 0L;
+ }
+
+ if ((LONG)cb + _lOffset > _cSize)
+ {
+ cb = _cSize - _lOffset;
+ hresult = STG_E_READFAULT;
+ }
+
+ memcpy(pv, _pbData + _lOffset, (size_t) cb);
+ _lOffset += cb;
+
+ if (pcbRead != NULL)
+ {
+ *pcbRead = cb;
+ }
+
+ return hresult;
+}
+
+STDMETHODIMP CStreamOnFile::Write(
+ VOID const HUGEP* pv,
+ ULONG cbToWrite,
+ ULONG FAR* pcbWritten)
+{
+ HRESULT hresult = S_OK;
+
+ if (pcbWritten)
+ {
+ *pcbWritten = 0L;
+ }
+
+ if (cbToWrite + _lOffset > _cbData)
+ {
+ return E_OUTOFMEMORY;
+ }
+
+ // copy in the new data
+ memcpy(_pbData + _lOffset, pv, (size_t) cbToWrite);
+ _lOffset += cbToWrite;
+
+ if (pcbWritten != NULL)
+ {
+ *pcbWritten = cbToWrite;
+ }
+
+ // We assume maxium size of buffer is the size to send on the network.
+ if (_cSize < _lOffset)
+ {
+ _cSize = _lOffset;
+ }
+
+ return hresult;
+}
+
+
+
+STDMETHODIMP CStreamOnFile::Seek(
+ LARGE_INTEGER dlibMoveIN,
+ DWORD dwOrigin,
+ ULARGE_INTEGER FAR* plibNewPosition)
+{
+ HRESULT hresult = S_OK;
+
+ LONG dlibMove = dlibMoveIN.LowPart;
+ ULONG cbNewPos = dlibMove;
+
+ switch(dwOrigin)
+ {
+ case STREAM_SEEK_SET:
+
+ if (dlibMove >= 0)
+ {
+ _lOffset = dlibMove;
+ }
+ else
+ {
+ hresult = STG_E_SEEKERROR;
+ }
+ break;
+
+ case STREAM_SEEK_CUR:
+
+ if (!(dlibMove < 0 && (-dlibMove > _lOffset)))
+ {
+ _lOffset += (ULONG) dlibMove;
+ }
+ else
+ {
+ hresult = STG_E_SEEKERROR;
+ }
+ break;
+
+ case STREAM_SEEK_END:
+
+ if (!(dlibMove < 0 && ((ULONG) -dlibMove) > _cbData))
+ {
+ _lOffset = _cbData + dlibMove;
+ }
+ else
+ {
+ hresult = STG_E_SEEKERROR;
+ }
+ break;
+
+ default:
+
+ hresult = STG_E_SEEKERROR;
+ }
+
+ if (plibNewPosition != NULL)
+ {
+ ULISet32(*plibNewPosition, _lOffset);
+ }
+
+ return hresult;
+}
+
+STDMETHODIMP CStreamOnFile::SetSize(ULARGE_INTEGER cb)
+{
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP CStreamOnFile::CopyTo(
+ IStream FAR* pstm,
+ ULARGE_INTEGER cb,
+ ULARGE_INTEGER FAR* pcbRead,
+ ULARGE_INTEGER FAR* pcbWritten)
+{
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP CStreamOnFile::Commit(DWORD grfCommitFlags)
+{
+ return NOERROR;
+}
+
+STDMETHODIMP CStreamOnFile::Revert(void)
+{
+ return NOERROR;
+}
+
+STDMETHODIMP CStreamOnFile::LockRegion(
+ ULARGE_INTEGER libOffset,
+ ULARGE_INTEGER cb,
+ DWORD dwLockType)
+{
+ return STG_E_INVALIDFUNCTION;
+}
+
+STDMETHODIMP CStreamOnFile::UnlockRegion(
+ ULARGE_INTEGER libOffset,
+ ULARGE_INTEGER cb,
+ DWORD dwLockType)
+{
+ return STG_E_INVALIDFUNCTION;
+}
+
+STDMETHODIMP CStreamOnFile::Stat(
+ STATSTG FAR* pstatstg,
+ DWORD statflag)
+{
+ memset(pstatstg, 0, sizeof(STATSTG));
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP CStreamOnFile::Clone(IStream FAR * FAR *ppstm)
+{
+ return E_NOTIMPL;
+}
diff --git a/private/oleutest/balls/client/tmarshal/stream.hxx b/private/oleutest/balls/client/tmarshal/stream.hxx
new file mode 100644
index 000000000..0c6d62760
--- /dev/null
+++ b/private/oleutest/balls/client/tmarshal/stream.hxx
@@ -0,0 +1,96 @@
+//+-------------------------------------------------------------------
+//
+// File: stream.hxx
+//
+// Contents: Stream class on a file.
+//
+// Classes: CStreamOnFile
+//
+// History: 08-08-95 Rickhi Created
+//
+//--------------------------------------------------------------------
+#ifndef __STREAMONFILE_HXX__
+#define __STREAMONFILE_HXX__
+
+
+//+-------------------------------------------------------------------
+//
+// Class: CStreamOnFile
+//
+// Purpose: Stream wrapper for a flat file.
+//
+// History: 08-08-95 Rickhi Created
+//
+//--------------------------------------------------------------------
+class CStreamOnFile : public IStream
+{
+public:
+ CStreamOnFile(const WCHAR *pwszFileName, SCODE &sc, BOOL fRead);
+ ~CStreamOnFile(void);
+
+ STDMETHOD(QueryInterface)(
+ REFIID iidInterface,
+ void FAR* FAR* ppvObj);
+
+ STDMETHOD_(ULONG,AddRef)(void);
+
+ STDMETHOD_(ULONG,Release)(void);
+
+ STDMETHOD(Read)(
+ VOID HUGEP* pv,
+ ULONG cb,
+ ULONG FAR* pcbRead);
+
+ STDMETHOD(Write)(
+ VOID const HUGEP* pv,
+ ULONG cb,
+ ULONG FAR* pcbWritten);
+
+ STDMETHOD(Seek)(
+ LARGE_INTEGER dlibMove,
+ DWORD dwOrigin,
+ ULARGE_INTEGER FAR* plibNewPosition);
+
+ STDMETHOD(SetSize) (ULARGE_INTEGER cb);
+
+ STDMETHOD(CopyTo)(
+ IStream FAR* pstm,
+ ULARGE_INTEGER cb,
+ ULARGE_INTEGER FAR* pcbRead,
+ ULARGE_INTEGER FAR* pcbWritten);
+
+ STDMETHOD(Commit)(DWORD grfCommitFlags);
+
+ STDMETHOD(Revert)(void);
+
+ STDMETHOD(LockRegion)(
+ ULARGE_INTEGER libOffset,
+ ULARGE_INTEGER cb,
+ DWORD dwLockType);
+
+ STDMETHOD(UnlockRegion)(
+ ULARGE_INTEGER libOffset,
+ ULARGE_INTEGER cb,
+ DWORD dwLockType);
+
+ STDMETHOD(Stat)(
+ STATSTG FAR* pstatstg,
+ DWORD statflag);
+
+ STDMETHOD(Clone)(IStream FAR * FAR *ppstm);
+
+private:
+
+ LONG _clRefs; // reference count
+ HANDLE _hFile; // file handle
+ BOOL _fRead; // read or write side
+
+ LONG _lOffset; // current seek ptr
+ LONG _cSize; // number of bytes written
+
+ ULONG _cbData; // size of data
+ BYTE *_pbData; // ptr to data
+
+};
+
+#endif // _STREAMONFILE_HXX__
diff --git a/private/oleutest/balls/client/tmarshal/tmarshal.cxx b/private/oleutest/balls/client/tmarshal/tmarshal.cxx
new file mode 100644
index 000000000..5d303e5ab
--- /dev/null
+++ b/private/oleutest/balls/client/tmarshal/tmarshal.cxx
@@ -0,0 +1,5634 @@
+// tmarsh.cxx : various tests related to marshalling...
+//
+#include <windows.h>
+#include <ole2.h>
+#include <stdio.h>
+
+#include "tmarshal.h"
+#include "tunk.h"
+#include <iballs.h>
+#include <icube.h>
+#include <iloop.h>
+#include <stream.hxx> // CStreamOnFile
+#include <tstmain.hxx> // fQuiet
+
+// BUGBUG: these should be in a public place somewhere.
+DEFINE_OLEGUID(CLSID_Balls, 0x0000013a, 1, 8);
+DEFINE_OLEGUID(CLSID_Cubes, 0x0000013b, 1, 8);
+DEFINE_OLEGUID(CLSID_LoopSrv, 0x0000013c, 1, 8);
+DEFINE_OLEGUID(CLSID_QI, 0x00000140, 0, 8);
+DEFINE_OLEGUID(CLSID_QIHANDLER1, 0x00000141, 0, 8);
+
+DEFINE_OLEGUID(IID_IInternalUnknown,0x00000021, 0, 0);
+DEFINE_OLEGUID(IID_IStdIdentity, 0x0000001b, 0, 0);
+DEFINE_OLEGUID(CLSID_OLEPSFACTORY, 0x00000320, 0, 0);
+
+const GUID CLSID_LoopSrv =
+ {0x0000013c,0x0001,0x0008,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}};
+
+// testsrv.exe
+const GUID CLSID_TestEmbed =
+ {0x99999999,0x0000,0x0008,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x47}};
+
+const GUID CLSID_Async =
+ {0x00000401,0x0000,0x0000,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}};
+
+const GUID CLSID_QI =
+ {0x00000140,0x0000,0x0008,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}};
+
+const GUID CLSID_QIHANDLER1 =
+ {0x00000141,0x0000,0x0008,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}};
+
+//const GUID IID_IMultiQI =
+// {0x00000020,0x0000,0x0000,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}};
+
+const GUID IID_IInternalUnknown =
+ {0x00000021,0x0000,0x0000,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}};
+
+const GUID IID_IStdIdentity =
+ {0x0000001b,0x0000,0x0000,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}};
+
+const GUID CLSID_OLEPSFACTORY =
+ {0x00000320,0x0000,0x0000,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}};
+
+extern "C" const GUID CLSID_TestEmbed;
+
+
+// external functions
+STDAPI_(LPSTREAM) CreateMemStm(DWORD cb, LPHANDLE phdl);
+HRESULT VerifyOBJREFFormat(IStream *pStm, DWORD mshlflags);
+DWORD _stdcall RundownClient(void *param);
+
+// APIs exported by OLE32 but not in the header files.
+STDAPI CoGetIIDFromMarshaledInterface(IStream *pStm, IID *piid);
+
+
+// function prototypes - TRUE return means the test passed
+BOOL TestMarshalFormat(void);
+BOOL TestGetIIDFromMI(void);
+BOOL TestLocalInterfaceNormal(void);
+BOOL TestUnmarshalGUIDNULL(void);
+BOOL TestUnmarshalDifferentIID(void);
+BOOL TestUniqueQIPointer(void);
+BOOL TestLocalInterfaceTableStrong(void);
+BOOL TestLocalInterfaceTableWeak(void);
+BOOL TestRemoteInterfaceNormal(void);
+BOOL TestRemoteInterfaceTableStrong(void);
+BOOL TestNoPing(void);
+BOOL TestEcho(void);
+BOOL TestMiddleMan(void);
+BOOL TestLoop(void);
+BOOL TestLockObjectExternal(void);
+BOOL TestDisconnectObject(void);
+BOOL TestHandler(void);
+BOOL TestReleaseMarshalData(void);
+BOOL TestCustomMarshalNormal(void);
+BOOL TestCustomMarshalTable(void);
+BOOL TestGetStandardMarshal(void);
+BOOL TestLocalInterfaceDiffMachine(void);
+BOOL TestRemoteInterfaceDiffMachine(void);
+BOOL TestExpiredOXIDs(void);
+BOOL TestNonNDRProxy(void);
+BOOL TestTIDAndLID(void);
+BOOL TestMarshalSizeMax(void);
+BOOL TestMarshalStorage(void);
+BOOL TestMultiQINormal(void);
+BOOL TestMultiQIHandler(void);
+BOOL TestCrossThread(void);
+BOOL TestPSClsid(void);
+BOOL TestPSClsid2(void);
+
+BOOL TestAsync(void);
+BOOL TestRundown(void);
+BOOL TestAggregate(void);
+BOOL TestCreateRemoteHandler(void);
+BOOL TestStorageInterfaceDiffMachine(void);
+
+
+WCHAR *pwszFileName[] = {L"c:\\mshlfile.1",
+ L"c:\\mshlfile.2",
+ L"c:\\mshlfile.3"};
+
+
+
+
+// internal subroutines
+void VerifyRHRefCnt(IUnknown *punk, ULONG ulExpectedRefCnt);
+void VerifyObjRefCnt(IUnknown *punk, ULONG ulExpectedRefCnt);
+
+TCHAR g_szIniFile[MAX_PATH];
+
+
+// ----------------------------------------------------------------------
+//
+// TestMarshal - main test driver
+//
+// ----------------------------------------------------------------------
+BOOL GetProfileValue(TCHAR *pszKeyName, int nDefault)
+{
+ return (GetPrivateProfileInt(TEXT("Marshal Test"),
+ pszKeyName,
+ nDefault,
+ g_szIniFile));
+}
+
+// ----------------------------------------------------------------------
+//
+// TestMarshal - main test driver
+//
+// ----------------------------------------------------------------------
+BOOL TestMarshal(void)
+{
+ BOOL RetVal = TRUE;
+
+ // Get file name of .ini file, TMARSHAL.INI in the current directory
+ GetCurrentDirectory (MAX_PATH, g_szIniFile);
+ lstrcat(g_szIniFile, TEXT("\\TMARSHAL.INI"));
+
+
+ if (GetProfileValue(TEXT("Format"),1))
+ RetVal &= TestMarshalFormat();
+
+ if (GetProfileValue(TEXT("GetIIDFromMI"),1))
+ RetVal &= TestGetIIDFromMI();
+
+ if (GetProfileValue(TEXT("MarshalSizeMax"),1))
+ RetVal &= TestMarshalSizeMax();
+
+ if (GetProfileValue(TEXT("GetStandardMarshal"),1))
+ RetVal &= TestGetStandardMarshal();
+
+ if (GetProfileValue(TEXT("LocalInterfaceNormal"),1))
+ RetVal &= TestLocalInterfaceNormal();
+
+ if (GetProfileValue(TEXT("UniqueQIPointer"),1))
+ RetVal &= TestUniqueQIPointer();
+
+ if (GetProfileValue(TEXT("LocalInterfaceTableStrong"),1))
+ RetVal &= TestLocalInterfaceTableStrong();
+
+ if (GetProfileValue(TEXT("LocalInterfaceTableWeak"),1))
+ RetVal &= TestLocalInterfaceTableWeak();
+
+ if (GetProfileValue(TEXT("RemoteInterfaceNormal"),1))
+ RetVal &= TestRemoteInterfaceNormal();
+
+ if (GetProfileValue(TEXT("UnmarshalGUIDNULL"),1))
+ RetVal &= TestUnmarshalGUIDNULL();
+
+ if (GetProfileValue(TEXT("UnmarshalDifferentIID"),1))
+ RetVal &= TestUnmarshalDifferentIID();
+
+ if (GetProfileValue(TEXT("RemoteInterfaceTableStrong"),1))
+ RetVal &= TestRemoteInterfaceTableStrong();
+
+ if (GetProfileValue(TEXT("CrossThread"),1))
+ RetVal &= TestCrossThread();
+
+ if (GetProfileValue(TEXT("CustomMarshalNormal"),1))
+ RetVal &= TestCustomMarshalNormal();
+
+ if (GetProfileValue(TEXT("CustomMarshalTable"),1))
+ RetVal &= TestCustomMarshalTable();
+
+ if (GetProfileValue(TEXT("Echo"),1))
+ RetVal &= TestEcho();
+
+ if (GetProfileValue(TEXT("Loop"),1))
+ RetVal &= TestLoop();
+
+ if (GetProfileValue(TEXT("LockObjectExternal"),1))
+ RetVal &= TestLockObjectExternal();
+
+ if (GetProfileValue(TEXT("DisconnectObject"),1))
+ RetVal &= TestDisconnectObject();
+
+ if (GetProfileValue(TEXT("ReleaseMarshalData"),1))
+ RetVal &= TestReleaseMarshalData();
+
+ if (GetProfileValue(TEXT("MultiQINormal"),1))
+ RetVal &= TestMultiQINormal();
+
+ if (GetProfileValue(TEXT("MultiQIHandler"),1))
+ RetVal &= TestMultiQIHandler();
+
+ if (GetProfileValue(TEXT("Handler"),1))
+ RetVal &= TestHandler();
+
+ if (GetProfileValue(TEXT("MiddleMan"),1))
+ RetVal &= TestMiddleMan();
+
+ if (GetProfileValue(TEXT("MarshalStorage"),1))
+ RetVal &= TestMarshalStorage();
+
+ if (GetProfileValue(TEXT("LocalDiffMachine"),1))
+ RetVal &= TestLocalInterfaceDiffMachine();
+
+ if (GetProfileValue(TEXT("RemoteDiffMachine"),1))
+ RetVal &= TestRemoteInterfaceDiffMachine();
+
+ if (GetProfileValue(TEXT("ExpiredOXIDs"),1))
+ RetVal &= TestExpiredOXIDs();
+
+ if (GetProfileValue(TEXT("NonNDRProxy"),1))
+ RetVal &= TestNonNDRProxy();
+
+ if (GetProfileValue(TEXT("TIDAndLID"),1))
+ RetVal &= TestTIDAndLID();
+
+ if (GetProfileValue(TEXT("NoPing"),1))
+ RetVal &= TestNoPing();
+
+ if (GetProfileValue(TEXT("PSClsid"),1))
+ RetVal &= TestPSClsid();
+
+ if (GetProfileValue(TEXT("PSClsid2"),1))
+ RetVal &= TestPSClsid2();
+
+ // -------------------------------------------------------------------
+
+ if (GetProfileValue(TEXT("Rundown"),0))
+ RetVal &= TestRundown();
+
+ if (GetProfileValue(TEXT("Async"),0))
+ RetVal &= TestAsync();
+
+ if (GetProfileValue(TEXT("StorageDiffMachine"),0))
+ RetVal &= TestStorageInterfaceDiffMachine();
+
+ if (GetProfileValue(TEXT("Aggregate"),0))
+ RetVal &= TestAggregate();
+
+ if (GetProfileValue(TEXT("CreateRemoteHandler"),0))
+ RetVal &= TestCreateRemoteHandler();
+
+ return RetVal;
+}
+
+// ----------------------------------------------------------------------
+//
+// subroutine to verify that the RH RefCnt is as expected.
+//
+// ----------------------------------------------------------------------
+
+typedef IMarshal * (* PFNDBG_FINDRH)(IUnknown *punk);
+PFNDBG_FINDRH gpfnFindRH = NULL;
+
+HMODULE ghOle32Dll = NULL;
+BOOL gfTriedToLoad = FALSE;
+
+
+void LoadProc()
+{
+ if (!gfTriedToLoad)
+ {
+ gfTriedToLoad = TRUE;
+
+ ghOle32Dll = LoadLibrary(TEXT("OLE32.DLL"));
+ if (ghOle32Dll)
+ {
+ gpfnFindRH = (PFNDBG_FINDRH) GetProcAddress(ghOle32Dll,
+ "Dbg_FindRemoteHdlr");
+ }
+ }
+}
+
+void FreeProc()
+{
+ if (ghOle32Dll)
+ {
+ FreeLibrary(ghOle32Dll);
+ }
+}
+
+// ----------------------------------------------------------------------
+//
+// subroutine to verify that the RH RefCnt is as expected.
+//
+// ----------------------------------------------------------------------
+
+void VerifyRHRefCnt(IUnknown *punk, ULONG ulExpectedRefCnt)
+{
+ if (gpfnFindRH == NULL)
+ {
+ LoadProc();
+ }
+
+ if (gpfnFindRH)
+ {
+ // this function is internal to COMPOBJ marshalling.
+ IMarshal *pIM = (gpfnFindRH)(punk);
+ if (pIM == NULL)
+ {
+ if (ulExpectedRefCnt != 0)
+ printf ("ERROR: RH RefCnt 0, expected=%x\n", ulExpectedRefCnt);
+ return;
+ }
+
+ ULONG ulRefCnt = pIM->Release();
+ if (ulRefCnt != ulExpectedRefCnt)
+ {
+ printf ("ERROR: RH RefCnt=%x, expected=%x\n", ulRefCnt, ulExpectedRefCnt);
+ }
+ }
+}
+
+// ----------------------------------------------------------------------
+//
+// subroutine to verify that the Object RefCnt is as expected.
+//
+// ----------------------------------------------------------------------
+
+void VerifyObjRefCnt(IUnknown *punk, ULONG ulExpectedRefCnt)
+{
+ if (ulExpectedRefCnt == 0)
+ return; // cant verify this
+
+//#if DBG==1
+ // this function is internal to COMPOBJ marshalling.
+ punk->AddRef();
+ ULONG ulRefCnt = punk->Release();
+ if (ulRefCnt != ulExpectedRefCnt)
+ {
+ printf ("ERROR: Object RefCnt=%x, expected=%x\n", ulRefCnt, ulExpectedRefCnt);
+ }
+//#endif
+}
+
+
+// ----------------------------------------------------------------------
+//
+// MarshalAndRead
+//
+// ----------------------------------------------------------------------
+HRESULT MarshalAndRead(IUnknown *punkIn, BYTE *pbuf, ULONG *pulSize)
+{
+ BOOL RetVal = TRUE;
+ HRESULT hres;
+
+ ULARGE_INTEGER ulSeekEnd;
+ LARGE_INTEGER lSeekStart;
+ LISet32(lSeekStart, 0);
+
+ IStream *pStm = CreateMemStm(600, NULL);
+ TEST_FAILED_EXIT((pStm == NULL), "CreateMemStm failed\n")
+ VerifyObjRefCnt((IUnknown *)pStm, 1);
+
+ hres = CoMarshalInterface(pStm, IID_IUnknown, punkIn, 0, NULL, MSHLFLAGS_NORMAL);
+ TEST_FAILED_EXIT(FAILED(hres), "CoMarshalInterface failed\n")
+ OUTPUT (" - CoMarshalInterface OK\n");
+
+ // get current seek position
+ hres = pStm->Seek(lSeekStart, STREAM_SEEK_CUR, &ulSeekEnd);
+ TEST_FAILED_EXIT(FAILED(hres), "Seek on shared stream failed\n")
+ OUTPUT (" - Seek Current OK\n");
+
+ // go back to begining
+ hres = pStm->Seek(lSeekStart, STREAM_SEEK_SET, NULL);
+ TEST_FAILED_EXIT(FAILED(hres), "Seek on shared stream failed\n")
+ OUTPUT (" - Seek Start OK\n");
+
+ // read in the data
+ hres = pStm->Read(pbuf ,ulSeekEnd.LowPart, pulSize);
+ TEST_FAILED_EXIT(FAILED(hres), "Read on stream failed\n")
+ OUTPUT (" - Read OK\n");
+
+Cleanup:
+
+ // release the stream
+ pStm->Release();
+
+ if (RetVal == TRUE)
+ return S_OK;
+ else
+ return hres;
+}
+
+// ----------------------------------------------------------------------
+//
+// GetTestUnk - return an inproc IUnknown ptr.
+//
+// ----------------------------------------------------------------------
+IUnknown *GetTestUnk()
+{
+ IUnknown *punkIn = (IUnknown *)(IParseDisplayName *) new CTestUnk();
+ return punkIn;
+}
+
+
+// ----------------------------------------------------------------------
+//
+// RunThread - runs a thread and waits for it to complete
+//
+// ----------------------------------------------------------------------
+void RunThread(void *param, HANDLE hEvent, LPTHREAD_START_ROUTINE pfn)
+{
+ DWORD dwThrdId;
+ HANDLE hThrd = CreateThread(NULL, 0, pfn, param, 0, &dwThrdId);
+
+ if (hThrd)
+ {
+ if (gInitFlag == COINIT_APARTMENTTHREADED)
+ {
+ // enter a message pump to accept incoming calls from the
+ // other thread.
+
+ MSG msg;
+ while (GetMessage(&msg, NULL, 0, 0))
+ {
+ DispatchMessage(&msg);
+ }
+ }
+ else
+ {
+ // wait for the other thread to run to completion
+ WaitForSingleObject(hEvent, 0xffffffff);
+ }
+
+ // close the thread handle
+ CloseHandle(hThrd);
+ }
+}
+
+
+// ----------------------------------------------------------------------
+//
+// TestAsync
+//
+// ----------------------------------------------------------------------
+BOOL TestAsync(void)
+{
+ BOOL RetVal = TRUE;
+ HRESULT hRes = S_OK;
+ ULONG ulRefCnt = 0;
+ IUnknown *pUnkSrv = NULL;
+ IAdviseSink *pAdvSnk = NULL;
+
+ OUTPUT ("Starting TestAsync\n");
+
+ // create our interface to pass to the remote object.
+ hRes = CoCreateInstance(CLSID_Async, NULL, CLSCTX_LOCAL_SERVER,
+ IID_IUnknown, (void **)&pUnkSrv);
+ TEST_FAILED_EXIT(FAILED(hRes), "CoCreateInstance First failed\n")
+
+ OUTPUT (" - QI for IAdviseSink\n");
+ hRes = pUnkSrv->QueryInterface(IID_IAdviseSink, (void **)&pAdvSnk);
+ TEST_FAILED_EXIT(FAILED(hRes), "QI for IAdviseSink failed\n")
+
+ // now call on the IAdviseSink Interface
+ pAdvSnk->OnSave();
+
+ Sleep(30);
+
+ // release the interface
+ pAdvSnk->Release();
+ pAdvSnk = NULL;
+
+// ----------------------------------------------------------------------
+
+Cleanup:
+
+ OUTPUT (" - Test Complete. Doing Cleanup\n");
+
+ // Dump interfaces we are done with
+ if (pAdvSnk)
+ {
+ ulRefCnt = pAdvSnk->Release();
+ TEST_FAILED(ulRefCnt != 1, "pAdvSnk RefCnt not zero\n");
+ }
+
+ if (pUnkSrv)
+ {
+ ulRefCnt = pUnkSrv->Release();
+ TEST_FAILED(ulRefCnt != 0, "PunkSrv RefCnt not zero\n");
+ }
+
+ return TestResult(RetVal, "TestAsync");
+}
+
+
+// ----------------------------------------------------------------------
+//
+// test marshal format
+//
+// ----------------------------------------------------------------------
+BOOL TestMarshalFormat(void)
+{
+ BOOL RetVal = TRUE;
+ BOOL fSame = TRUE;
+ HRESULT hres;
+ ULONG ulRefCnt = 0;
+ IUnknown *punkIn = NULL;
+ BYTE buf1[600];
+ BYTE buf2[600];
+ ULONG ulSize1 = sizeof(buf1);
+ ULONG ulSize2 = sizeof(buf2);
+
+ OUTPUT ("Starting TestMarshalFormat\n");
+
+ punkIn = GetTestUnk();
+ TEST_FAILED_EXIT((punkIn == NULL), "new CTestUnk failed\n")
+ VerifyObjRefCnt(punkIn, 1);
+
+// ----------------------------------------------------------------------
+
+ hres = MarshalAndRead(punkIn, buf1, &ulSize1);
+ TEST_FAILED_EXIT(FAILED(hres), "MarshalAndRead failed\n")
+ OUTPUT (" - First MarshalAndRead OK\n");
+
+ hres = MarshalAndRead(punkIn, buf2, &ulSize2);
+ TEST_FAILED_EXIT(FAILED(hres), "MarshalAndRead failed\n")
+ OUTPUT (" - Second MarshalAndRead OK\n");
+
+ TEST_FAILED_EXIT((ulSize1 != ulSize2), "Buffer Sizes Differ\n")
+ fSame = !memcmp(buf1, buf2, ulSize1);
+
+ TEST_FAILED_EXIT(!fSame, "Buffer Contents Differ\n")
+ OUTPUT (" - Buffers Compare OK\n");
+
+// ----------------------------------------------------------------------
+
+Cleanup:
+
+ OUTPUT (" - Test Complete. Doing Cleanup\n");
+
+ CoDisconnectObject(punkIn,0);
+
+ if (punkIn)
+ {
+ ulRefCnt = punkIn->Release();
+ TEST_FAILED(ulRefCnt != 0, "punkIn RefCnt not zero\n");
+ }
+
+ return TestResult(RetVal, "TestMarshalFormat");
+}
+
+
+// ----------------------------------------------------------------------
+//
+// test CoGetMarshalSizeMax
+//
+// ----------------------------------------------------------------------
+BOOL TestMarshalSizeMax(void)
+{
+ BOOL RetVal = TRUE;
+ HRESULT hres;
+ ULONG ulRefCnt = 0;
+ IUnknown *punkIn = NULL;
+ ULONG ulSize = 0;
+
+ OUTPUT ("Starting TestMarshalSizeMax\n");
+
+ punkIn = GetTestUnk();
+ TEST_FAILED_EXIT((punkIn == NULL), "new CTestUnk failed\n")
+ VerifyObjRefCnt(punkIn, 1);
+
+// ----------------------------------------------------------------------
+
+ hres = CoGetMarshalSizeMax(&ulSize, IID_IUnknown, punkIn, 0, NULL, MSHLFLAGS_NORMAL);
+ TEST_FAILED_EXIT(FAILED(hres), "CoGetMarshalSizeMax failed\n")
+ VerifyRHRefCnt(punkIn, 0);
+ OUTPUT (" - CoGetMarshalSizeMax OK\n");
+
+// ----------------------------------------------------------------------
+
+Cleanup:
+
+ OUTPUT (" - Test Complete. Doing Cleanup\n");
+ if (punkIn)
+ {
+ punkIn->Release();
+ punkIn = NULL;
+ }
+
+ return TestResult(RetVal, "TestMarshalSizeMax");
+}
+
+
+// ----------------------------------------------------------------------
+//
+// test LOCAL interface MSHLFLAGS_NORMAL
+//
+// ----------------------------------------------------------------------
+
+BOOL TestLocalInterfaceNormal(void)
+{
+ BOOL RetVal = TRUE;
+ HRESULT hres;
+ LPSTREAM pStm = NULL;
+ ULONG ulRefCnt = 0;
+ IUnknown *punkIn = NULL;
+ IUnknown *punkOut = NULL;
+ IUnknown *punkOut2 = NULL;
+
+ LARGE_INTEGER large_int;
+ LISet32(large_int, 0);
+
+ OUTPUT ("Starting TestLocalInterfaceNormal\n");
+
+ punkIn = GetTestUnk();
+ TEST_FAILED_EXIT((punkIn == NULL), "new CTestUnk failed\n")
+ VerifyObjRefCnt(punkIn, 1);
+
+ pStm = CreateMemStm(600, NULL);
+ TEST_FAILED_EXIT((pStm == NULL), "CreateMemStm failed\n")
+ VerifyObjRefCnt((IUnknown *)pStm, 1);
+
+// ----------------------------------------------------------------------
+ hres = CoMarshalInterface(pStm, IID_IUnknown, punkIn, 0, NULL, MSHLFLAGS_NORMAL);
+ TEST_FAILED_EXIT(FAILED(hres), "CoMarshalInterface failed\n")
+ VerifyRHRefCnt(punkIn, 1);
+ OUTPUT (" - CoMarshalInterface OK\n");
+
+ hres = pStm->Seek(large_int, STREAM_SEEK_SET, NULL);
+ TEST_FAILED_EXIT(FAILED(hres), "Seek on shared stream failed\n")
+
+ // since we are unmarshalling in the same process, the RH should go away.
+ hres = CoUnmarshalInterface(pStm, IID_IUnknown, (LPVOID FAR*)&punkOut);
+ TEST_FAILED_EXIT(FAILED(hres), "CoUnmarshalInterface failed\n")
+ VerifyRHRefCnt(punkIn, 0);
+ VerifyObjRefCnt(punkIn, 2);
+
+ // make sure the interface pointers are identical
+ if (punkIn != punkOut)
+ TEST_FAILED_EXIT(TRUE, "Interface ptrs dont match...1st Local Unmarshal\n")
+ OUTPUT (" - CoUnmarshalInterface OK\n");
+
+ // release it and make sure it does not go away - refcnt > 0
+ ulRefCnt = punkOut->Release();
+ TEST_FAILED_EXIT(ulRefCnt == 0, "punkOut RefCnt is zero");
+ punkOut = NULL;
+ OUTPUT (" - Release OK\n");
+
+ // the RH should have gone away, and we should have only the original
+ // refcnt from creation left on the object.
+ VerifyObjRefCnt(punkIn, 1);
+
+// ----------------------------------------------------------------------
+#if 0
+ // this test disabled for DCOM since we no longer write into the stream
+ // to mark the thing as having been unmarshaled. This lets unmarshals
+ // work with read-only streams.
+
+
+ // test unmarshalling twice. this should fail since we did marshal
+ // flags normal and already unmarshalled it once.
+
+ hres = pStm->Seek(large_int, STREAM_SEEK_SET, NULL);
+ TEST_FAILED_EXIT(FAILED(hres), "Seek on shared stream failed\n")
+
+ hres = CoUnmarshalInterface(pStm, IID_IUnknown, (LPVOID FAR*)&punkOut2);
+ TEST_FAILED_EXIT(SUCCEEDED(hres), "CoUnmarshalInterface second time succeeded but should have failed\n")
+ OUTPUT (" - Second CoUnmarshalInterface OK\n");
+
+// ----------------------------------------------------------------------
+
+ // CoReleaseMarshalData should fail because Unmarshall already called it.
+ hres = pStm->Seek(large_int, STREAM_SEEK_SET, NULL);
+ TEST_FAILED_EXIT(FAILED(hres), "Seek on shared stream failed\n")
+
+ hres = CoReleaseMarshalData(pStm);
+ TEST_FAILED_EXIT(SUCCEEDED(hres), "CoReleaseMarshalData succeeded but should have failed.\n")
+ OUTPUT (" - CoReleaseMarshalData OK\n");
+
+#endif
+// ----------------------------------------------------------------------
+
+ // marshal again and try CoRelease without having first done an
+ // unmarshal. this should work.
+ hres = pStm->Seek(large_int, STREAM_SEEK_SET, NULL);
+ TEST_FAILED_EXIT(FAILED(hres), "Seek on shared stream failed\n")
+
+ hres = CoMarshalInterface(pStm, IID_IUnknown, punkIn, 0, NULL, MSHLFLAGS_NORMAL);
+ TEST_FAILED_EXIT(FAILED(hres), "CoMarshalInterface failed\n")
+ OUTPUT (" - CoMarshalInterface OK\n");
+ VerifyRHRefCnt(punkIn, 1);
+
+ hres = pStm->Seek(large_int, STREAM_SEEK_SET, NULL);
+ TEST_FAILED_EXIT(FAILED(hres), "Seek on shared stream failed\n")
+
+ hres = CoReleaseMarshalData(pStm);
+ TEST_FAILED_EXIT(FAILED(hres), "CoReleaseMarshalData failed.\n")
+ VerifyRHRefCnt(punkIn, 0);
+ VerifyObjRefCnt(punkIn, 1);
+ OUTPUT (" - CoReleaseMarshalData OK\n");
+
+// ----------------------------------------------------------------------
+
+ // release the object and try to unmarshal it again. Should fail
+ // since the object has gone away.
+
+ ulRefCnt = punkIn->Release();
+ TEST_FAILED_EXIT(ulRefCnt != 0, "punkOut RefCnt not zero\n");
+ punkIn = NULL;
+
+ // go back to start of stream
+ hres = pStm->Seek(large_int, STREAM_SEEK_SET, NULL);
+ TEST_FAILED_EXIT(FAILED(hres), "Seek on shared stream failed\n")
+
+ hres = CoUnmarshalInterface(pStm, IID_IUnknown, (LPVOID FAR*)&punkOut);
+ TEST_FAILED_EXIT(SUCCEEDED(hres), "CoUnmarshalInterface should have failed\n")
+
+// ----------------------------------------------------------------------
+
+Cleanup:
+
+ OUTPUT (" - Test Complete. Doing Cleanup\n");
+
+ // Dump interfaces we are done with
+ if (pStm)
+ {
+ ulRefCnt = pStm->Release();
+ TEST_FAILED(ulRefCnt != 0, "Stream RefCnt not zero\n");
+ }
+
+ if (punkOut)
+ {
+ ulRefCnt = punkOut->Release();
+ TEST_FAILED(ulRefCnt != 0, "punkOut RefCnt not zero\n");
+ }
+
+ if (punkOut2)
+ {
+ ulRefCnt = punkOut2->Release();
+ TEST_FAILED(ulRefCnt != 0, "punkOut2 RefCnt not zero\n");
+ }
+
+ if (punkIn)
+ {
+ ulRefCnt = punkIn->Release();
+ TEST_FAILED(ulRefCnt != 0, "punkIn RefCnt not zero\n");
+ }
+
+ return TestResult(RetVal, "TestLocalInterfaceNormal");
+}
+
+
+// ----------------------------------------------------------------------
+//
+// test LOCAL interface MSHLFLAGS_NORMAL when the object returns a
+// differnt interface pointer on each subsequent QI for the same
+// interface
+//
+// ----------------------------------------------------------------------
+BOOL TestUniqueQIPointer(void)
+{
+ BOOL RetVal = TRUE;
+ HRESULT hres;
+ LPSTREAM pStm = NULL;
+ ULONG ulRefCnt = 0;
+ IUnknown *punkIn = NULL;
+ IUnknown *punkOut = NULL;
+ ICube *pCubeIn = NULL;
+ ICube *pCubeOut = NULL;
+
+ LARGE_INTEGER large_int;
+ LISet32(large_int, 0);
+
+ OUTPUT ("Starting TestUniqueQIPointer\n");
+
+ punkIn = GetTestUnk();
+ TEST_FAILED_EXIT((punkIn == NULL), "new CTestUnk failed\n")
+ VerifyObjRefCnt(punkIn, 1);
+
+ hres = punkIn->QueryInterface(IID_ICube, (void **)&pCubeIn);
+ TEST_FAILED_EXIT((pCubeIn == NULL), "QI for IID_ICube failed\n")
+ VerifyObjRefCnt(punkIn, 2);
+
+ pStm = CreateMemStm(600, NULL);
+ TEST_FAILED_EXIT((pStm == NULL), "CreateMemStm failed\n")
+ VerifyObjRefCnt((IUnknown *)pStm, 1);
+
+// ----------------------------------------------------------------------
+ hres = CoMarshalInterface(pStm, IID_ICube, pCubeIn, 0, NULL, MSHLFLAGS_NORMAL);
+ TEST_FAILED_EXIT(FAILED(hres), "CoMarshalInterface failed\n")
+ VerifyRHRefCnt(pCubeIn, 1);
+ OUTPUT (" - CoMarshalInterface OK\n");
+
+ hres = pStm->Seek(large_int, STREAM_SEEK_SET, NULL);
+ TEST_FAILED_EXIT(FAILED(hres), "Seek on shared stream failed\n")
+
+ // since we are unmarshalling in the same process, the RH should go away.
+ hres = CoUnmarshalInterface(pStm, IID_ICube, (LPVOID FAR*)&pCubeOut);
+ TEST_FAILED_EXIT(FAILED(hres), "CoUnmarshalInterface failed\n")
+ VerifyRHRefCnt(pCubeIn, 0);
+ VerifyRHRefCnt(pCubeOut, 0);
+ VerifyRHRefCnt(punkIn, 0);
+
+ VerifyObjRefCnt(pCubeIn, 1);
+ VerifyObjRefCnt(pCubeOut, 1);
+ VerifyObjRefCnt(punkIn, 3);
+
+ // make sure the Ctrl Unknown interface pointers are identical
+ hres = pCubeOut->QueryInterface(IID_IUnknown, (void **)&punkOut);
+ TEST_FAILED_EXIT((punkOut == NULL), "QI for IID_IUnknown failed\n")
+ VerifyObjRefCnt(punkOut, 4);
+
+ if (punkIn != punkOut)
+ TEST_FAILED_EXIT(TRUE, "Interface ptrs dont match...1st Local Unmarshal\n")
+ OUTPUT (" - CoUnmarshalInterface OK\n");
+
+ // attempt a call on the in interface pointer.
+ hres = pCubeIn->MoveCube(0,0);
+ TEST_FAILED_EXIT(FAILED(hres), "pCubeIn->MoveCube failed\n")
+
+ // release the in-pointer
+ ulRefCnt = pCubeIn->Release();
+ TEST_FAILED(ulRefCnt != 0, "pCubeIn RefCnt not zero\n");
+ pCubeIn = NULL;
+
+ // now call on the out interface pointer
+ hres = pCubeOut->MoveCube(0,0);
+ TEST_FAILED_EXIT(FAILED(hres), "pCubeOut->MoveCube failed\n")
+
+ // release the out-pointer
+ ulRefCnt = pCubeOut->Release();
+ TEST_FAILED(ulRefCnt != 0, "pCubeOut RefCnt not zero\n");
+ pCubeOut = NULL;
+
+
+Cleanup:
+
+ OUTPUT (" - Test Complete. Doing Cleanup\n");
+
+ // Dump interfaces we are done with
+ if (pStm)
+ {
+ ulRefCnt = pStm->Release();
+ TEST_FAILED(ulRefCnt != 0, "Stream RefCnt not zero\n");
+ }
+
+ if (pCubeIn)
+ {
+ ulRefCnt = pCubeIn->Release();
+ TEST_FAILED(ulRefCnt != 0, "pCubeIn RefCnt not zero\n");
+ }
+
+ if (pCubeOut)
+ {
+ ulRefCnt = pCubeOut->Release();
+ TEST_FAILED(ulRefCnt != 0, "pCubeOut RefCnt not zero\n");
+ }
+
+ if (punkOut)
+ {
+ ulRefCnt = punkOut->Release();
+ TEST_FAILED(ulRefCnt == 0, "punkOut RefCnt not zero\n");
+ }
+
+ if (punkIn)
+ {
+ ulRefCnt = punkIn->Release();
+ TEST_FAILED(ulRefCnt != 0, "punkIn RefCnt not zero\n");
+ }
+
+ return TestResult(RetVal, "TestUniqueQIPointer");
+}
+
+
+
+// ----------------------------------------------------------------------
+//
+// test LOCAL interface MSHLFLAGS_TABLESTRONG
+//
+// ----------------------------------------------------------------------
+
+BOOL TestLocalInterfaceTableStrong(void)
+{
+ BOOL RetVal = TRUE;
+ HRESULT hres;
+ LPSTREAM pStm = NULL;
+ ULONG ulRefCnt = 0;
+ IUnknown *punkIn = NULL;
+ IUnknown *punkOut = NULL;
+ IUnknown *punkOut2 = NULL;
+
+ LARGE_INTEGER large_int;
+ LISet32(large_int, 0);
+
+ OUTPUT ("Starting TestLocalInterfaceTableStrong\n");
+
+ punkIn = GetTestUnk();
+ TEST_FAILED_EXIT((punkIn == NULL), "new CTestUnk failed\n")
+ VerifyObjRefCnt(punkIn, 1);
+
+ pStm = CreateMemStm(600, NULL);
+ TEST_FAILED_EXIT((pStm == NULL), "CreateMemStm failed\n")
+ VerifyObjRefCnt((IUnknown *)pStm, 1);
+
+// ----------------------------------------------------------------------
+
+ hres = CoMarshalInterface(pStm, IID_IUnknown, punkIn, 0, NULL, MSHLFLAGS_TABLESTRONG);
+ TEST_FAILED_EXIT(FAILED(hres), "CoMarshalInterface failed\n")
+ VerifyRHRefCnt(punkIn, 1);
+ OUTPUT (" - CoMarshalInterface OK\n");
+
+ hres = pStm->Seek(large_int, STREAM_SEEK_SET, NULL);
+ TEST_FAILED_EXIT(FAILED(hres), "Seek on shared stream failed\n")
+
+ // unmarshalling should leave the RH intact, as it is marshalled for TABLE.
+ hres = CoUnmarshalInterface(pStm, IID_IUnknown, (LPVOID FAR*)&punkOut);
+ TEST_FAILED_EXIT(FAILED(hres), "CoUnmarshalInterface failed\n")
+ VerifyRHRefCnt(punkIn, 1);
+
+ // make sure the interface pointers are identical
+ if (punkIn != punkOut)
+ TEST_FAILED_EXIT(TRUE, "Interface ptrs dont match...1st Local Unmarshal\n")
+ OUTPUT (" - CoUnmarshalInterface OK\n");
+
+ // release it and make sure it does not go away - refcnt > 0
+ ulRefCnt = punkOut->Release();
+ TEST_FAILED_EXIT(ulRefCnt == 0, "punkOut RefCnt is zero");
+ punkOut = NULL;
+ VerifyRHRefCnt(punkIn, 1);
+ OUTPUT (" - Release OK\n");
+
+// ----------------------------------------------------------------------
+
+ // test unmarshalling twice - should work since we used flags table
+ hres = pStm->Seek(large_int, STREAM_SEEK_SET, NULL);
+ TEST_FAILED_EXIT(FAILED(hres), "Seek on shared stream failed\n")
+
+ hres = CoUnmarshalInterface(pStm, IID_IUnknown, (LPVOID FAR*)&punkOut2);
+ TEST_FAILED_EXIT(FAILED(hres), "CoUnmarshalInterface second time succeeded but should have failed\n")
+ VerifyRHRefCnt(punkIn, 1);
+ OUTPUT (" - Second CoUnmarshalInterface OK\n");
+
+ // release it and make sure it does not go away - refcnt > 0
+ ulRefCnt = punkOut2->Release();
+ TEST_FAILED_EXIT(ulRefCnt == 0, "punkOut2 RefCnt is zero");
+ punkOut2 = NULL;
+ VerifyRHRefCnt(punkIn, 1);
+ OUTPUT (" - Release OK\n");
+
+// ----------------------------------------------------------------------
+
+ // CoReleaseMarshalData should release the marshalled data TABLESTRONG
+ hres = pStm->Seek(large_int, STREAM_SEEK_SET, NULL);
+ TEST_FAILED_EXIT(FAILED(hres), "Seek on shared stream failed\n")
+
+ hres = CoReleaseMarshalData(pStm);
+ TEST_FAILED_EXIT(FAILED(hres), "CoReleaseMarshalData failed.\n")
+ VerifyRHRefCnt(punkIn, 0);
+ OUTPUT (" - CoReleaseMarshalData OK\n");
+
+// ----------------------------------------------------------------------
+
+Cleanup:
+
+ OUTPUT (" - Test Complete. Doing Cleanup\n");
+
+ // Dump interfaces we are done with
+ if (pStm)
+ {
+ ulRefCnt = pStm->Release();
+ TEST_FAILED(ulRefCnt != 0, "Stream RefCnt not zero\n");
+ }
+
+ if (punkOut)
+ {
+ ulRefCnt = punkOut->Release();
+ TEST_FAILED(ulRefCnt != 0, "punkOut RefCnt not zero\n");
+ }
+
+ if (punkOut2)
+ {
+ ulRefCnt = punkOut2->Release();
+ TEST_FAILED(ulRefCnt != 0, "punkOut2 RefCnt not zero\n");
+ }
+
+ if (punkIn)
+ {
+ ulRefCnt = punkIn->Release();
+ TEST_FAILED(ulRefCnt != 0, "punkIn RefCnt not zero\n");
+ }
+
+ return TestResult(RetVal, "TestLocalInterfaceTableStrong");
+}
+
+
+// ----------------------------------------------------------------------
+//
+// test LOCAL interface MSHLFLAGS_TABLEWEAK
+//
+// ----------------------------------------------------------------------
+
+BOOL TestLocalInterfaceTableWeak(void)
+{
+ BOOL RetVal = TRUE;
+ HRESULT hres;
+ LPSTREAM pStm = NULL;
+ ULONG ulRefCnt = 0;
+ IUnknown *punkIn = NULL;
+ IUnknown *punkOut = NULL;
+ IUnknown *punkOut2 = NULL;
+
+ LARGE_INTEGER large_int;
+ LISet32(large_int, 0);
+
+ OUTPUT ("Starting TestLocalInterfaceTableWeak\n");
+
+ punkIn = GetTestUnk();
+ TEST_FAILED_EXIT((punkIn == NULL), "new CTestUnk failed\n")
+ VerifyObjRefCnt(punkIn, 1);
+
+ pStm = CreateMemStm(600, NULL);
+ TEST_FAILED_EXIT((pStm == NULL), "CreateMemStm failed\n")
+ VerifyObjRefCnt((IUnknown *)pStm, 1);
+
+// ----------------------------------------------------------------------
+
+ hres = CoMarshalInterface(pStm, IID_IParseDisplayName, punkIn, 0, NULL, MSHLFLAGS_TABLEWEAK);
+ TEST_FAILED_EXIT(FAILED(hres), "CoMarshalInterface failed\n")
+ VerifyRHRefCnt(punkIn, 1);
+ OUTPUT (" - CoMarshalInterface OK\n");
+
+ hres = pStm->Seek(large_int, STREAM_SEEK_SET, NULL);
+ TEST_FAILED_EXIT(FAILED(hres), "Seek on shared stream failed\n")
+
+ // unmarshalling should leave the RH intact, as it is marshalled for TABLE.
+ hres = CoUnmarshalInterface(pStm, IID_IParseDisplayName, (LPVOID FAR*)&punkOut);
+ TEST_FAILED_EXIT(FAILED(hres), "CoUnmarshalInterface failed\n")
+ VerifyRHRefCnt(punkIn, 1);
+
+ // make sure the interface pointers are identical
+ if (punkIn != punkOut)
+ TEST_FAILED_EXIT(TRUE, "Interface ptrs dont match...1st Local Unmarshal\n")
+ OUTPUT (" - CoUnmarshalInterface OK\n");
+
+ // release it and make sure it does not go away - refcnt > 0
+ ulRefCnt = punkOut->Release();
+ TEST_FAILED_EXIT(ulRefCnt == 0, "punkOut RefCnt is zero");
+ punkOut = NULL;
+ VerifyRHRefCnt(punkIn, 1);
+ OUTPUT (" - Release OK\n");
+
+// ----------------------------------------------------------------------
+
+ // test unmarshalling twice - should work since we used flags table
+ hres = pStm->Seek(large_int, STREAM_SEEK_SET, NULL);
+ TEST_FAILED_EXIT(FAILED(hres), "Seek on shared stream failed\n")
+
+ hres = CoUnmarshalInterface(pStm, IID_IParseDisplayName, (LPVOID FAR*)&punkOut2);
+ TEST_FAILED_EXIT(FAILED(hres), "CoUnmarshalInterface second time succeeded but should have failed\n")
+ VerifyRHRefCnt(punkIn, 1);
+
+ // make sure the interface pointers are identical
+ if (punkIn != punkOut2)
+ TEST_FAILED_EXIT(TRUE, "Interface ptrs dont match...2nd Local Unmarshal\n")
+ OUTPUT (" - Second CoUnmarshalInterface OK\n");
+
+ // release it and make sure it does not go away - refcnt > 0
+ ulRefCnt = punkOut2->Release();
+ TEST_FAILED_EXIT(ulRefCnt == 0, "punkOut2 RefCnt is zero");
+ punkOut2 = NULL;
+ VerifyRHRefCnt(punkIn, 1);
+ OUTPUT (" - Release OK\n");
+
+// ----------------------------------------------------------------------
+
+ // CoReleaseMarshalData should release the marshalled data TABLEWEAK
+ hres = pStm->Seek(large_int, STREAM_SEEK_SET, NULL);
+ TEST_FAILED_EXIT(FAILED(hres), "Seek on shared stream failed\n")
+
+ hres = CoReleaseMarshalData(pStm);
+ TEST_FAILED_EXIT(FAILED(hres), "CoReleaseMarshalData failed.\n")
+ VerifyRHRefCnt(punkIn, 0);
+ VerifyObjRefCnt(punkIn, 1);
+ OUTPUT (" - CoReleaseMarshalData OK\n");
+
+
+ ulRefCnt = punkIn->Release();
+ TEST_FAILED_EXIT(ulRefCnt != 0, "punkIn RefCnt is not zero");
+ punkIn = NULL;
+
+// ----------------------------------------------------------------------
+
+Cleanup:
+
+ OUTPUT (" - Test Complete. Doing Cleanup\n");
+
+ // Dump interfaces we are done with
+ if (pStm)
+ {
+ ulRefCnt = pStm->Release();
+ TEST_FAILED(ulRefCnt != 0, "Stream RefCnt not zero\n");
+ }
+
+ if (punkOut)
+ {
+ ulRefCnt = punkOut->Release();
+ TEST_FAILED(ulRefCnt != 0, "punkOut RefCnt not zero\n");
+ }
+
+ if (punkOut2)
+ {
+ ulRefCnt = punkOut2->Release();
+ TEST_FAILED(ulRefCnt != 0, "punkOut2 RefCnt not zero\n");
+ }
+
+ if (punkIn)
+ {
+ ulRefCnt = punkIn->Release();
+ TEST_FAILED(ulRefCnt != 0, "punkIn RefCnt not zero\n");
+ }
+
+ return TestResult(RetVal, "TestLocalInterfaceTableWeak");
+}
+
+// ----------------------------------------------------------------------
+//
+// test calling CoUmarshalInterface with GUID_NULL
+//
+// ----------------------------------------------------------------------
+
+// ----------------------------------------------------------------------
+//
+// Structure passed between apartments.
+//
+// ----------------------------------------------------------------------
+typedef struct tagThreadUnmarshalInfo
+{
+ HANDLE hEvent;
+ IStream *pStm;
+ IUnknown *pUnk;
+ IID iid;
+ DWORD dwInitFlag;
+ DWORD dwThreadId;
+ ULONG RelRefCnt;
+ HRESULT hr;
+} ThreadUnmarshalInfo;
+
+
+DWORD _stdcall ThreadTestUnmarshal(void *params)
+{
+ ThreadUnmarshalInfo *pInfo = (ThreadUnmarshalInfo *)params;
+ BOOL RetVal = TRUE;
+ ULONG ulRefCnt= 0;
+ IUnknown *punkOut = NULL;
+ HRESULT hres;
+
+ hres = CoInitializeEx(NULL, pInfo->dwInitFlag);
+
+ hres = CoUnmarshalInterface(pInfo->pStm, pInfo->iid, (LPVOID FAR*)&punkOut);
+ TEST_FAILED(FAILED(hres), "CoUnmarshalInterface failed\n")
+
+ if (SUCCEEDED(hres))
+ {
+ // make sure the interface pointers are identical
+ if (pInfo->pUnk != NULL && pInfo->pUnk != punkOut)
+ {
+ TEST_FAILED(TRUE, "Interface ptrs are wrong\n")
+ }
+ else
+ {
+ OUTPUT (" - CoUnmarshalInterface OK.\n");
+ }
+
+ // release the interface
+ ulRefCnt = punkOut->Release();
+ punkOut = NULL;
+ TEST_FAILED(ulRefCnt != pInfo->RelRefCnt, "Released punkOut RefCnt is wrong\n");
+
+ OUTPUT (" - Release OK\n");
+ }
+
+ pInfo->hr = hres;
+
+ CoUninitialize();
+
+ // signal the other thread we are done.
+ // but only if we were called from a different thread
+
+ if (pInfo->dwThreadId != 0)
+ {
+ if (gInitFlag == COINIT_APARTMENTTHREADED)
+ {
+ PostThreadMessage(pInfo->dwThreadId, WM_QUIT, 0, 0);
+ }
+ else
+ {
+ SetEvent(pInfo->hEvent);
+ }
+ }
+
+ return 0;
+}
+
+
+BOOL TestUnmarshalGUIDNULL(void)
+{
+ BOOL RetVal = TRUE;
+ HRESULT hres;
+ LPSTREAM pStm = NULL;
+ IUnknown *punkIn = NULL;
+ ULONG ulRefCnt, i;
+ HANDLE hEvent = NULL;
+ ThreadUnmarshalInfo Info;
+
+
+ LARGE_INTEGER large_int;
+ LISet32(large_int, 0);
+
+ OUTPUT ("Starting TestUnmarshalGUIDNULL\n");
+
+ // Create a shared memory stream for the marshaled interface
+ pStm = CreateMemStm(600, NULL);
+ TEST_FAILED_EXIT((pStm == NULL), "CreateMemStm failed\n")
+
+// ----------------------------------------------------------------------
+
+ for (i=0; i<2; i++)
+ {
+ hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+ TEST_FAILED_EXIT(hEvent == NULL, "CreateEvent failed\n")
+
+ punkIn = GetTestUnk();
+ TEST_FAILED_EXIT((punkIn == NULL), "new CTestUnk failed\n")
+ VerifyObjRefCnt(punkIn, 1);
+
+ // reset the stream ptr
+ hres = pStm->Seek(large_int, STREAM_SEEK_SET, NULL);
+ TEST_FAILED_EXIT(FAILED(hres), "Seek on shared stream failed\n")
+
+ // Marshal the interface into the stream
+ hres = CoMarshalInterface(pStm, IID_IParseDisplayName, punkIn,
+ 0, 0, MSHLFLAGS_NORMAL);
+ TEST_FAILED_EXIT(FAILED(hres), "CoMarshalInterface failed\n")
+ VerifyRHRefCnt(punkIn, 1);
+ OUTPUT (" - CoMarshalInterface OK.\n");
+
+ // reset the stream ptr
+ hres = pStm->Seek(large_int, STREAM_SEEK_SET, NULL);
+ TEST_FAILED_EXIT(FAILED(hres), "Seek on shared stream failed\n")
+
+ Info.hEvent = hEvent;
+ Info.pStm = pStm;
+ Info.iid = GUID_NULL;
+ Info.dwInitFlag = gInitFlag;
+ Info.dwThreadId = 0;
+
+ if (i==0)
+ {
+ // first time, call on same thread, expect original ptr and
+ // non-zero refcnt after release
+ Info.pUnk = punkIn;
+ Info.RelRefCnt = 1;
+
+ ThreadTestUnmarshal(&Info);
+ }
+ else
+ {
+ // second time, call on different thread
+ if (gInitFlag == COINIT_APARTMENTTHREADED)
+ {
+ // apartment thread, expect differnt ptr and
+ // zero refcnt after release
+
+ Info.dwThreadId = GetCurrentThreadId();
+ Info.pUnk = 0;
+ Info.RelRefCnt = 0;
+ }
+ else
+ {
+ // multi-thread, expect same ptr and non-zero refcnt
+ // after release
+
+ Info.dwThreadId = GetCurrentThreadId();
+ Info.pUnk = punkIn;
+ Info.RelRefCnt = 1;
+ }
+
+ RunThread(&Info, hEvent, ThreadTestUnmarshal);
+ CloseHandle(hEvent);
+ }
+
+ // release the punkIn.
+ ulRefCnt = punkIn->Release();
+ TEST_FAILED(ulRefCnt != 0, "punkIn RefCnt not zero\n");
+ punkIn = NULL;
+
+ hres = Info.hr;
+ OUTPUT (" - Run Complete\n");
+ }
+
+// ----------------------------------------------------------------------
+
+Cleanup:
+
+ OUTPUT (" - Test Complete. Doing Cleanup\n");
+
+ // Dump interfaces we are done with
+ if (pStm)
+ {
+ ulRefCnt = pStm->Release();
+ TEST_FAILED(ulRefCnt != 0, "Stream RefCnt not zero\n");
+ }
+
+ if (punkIn)
+ {
+ ulRefCnt = punkIn->Release();
+ TEST_FAILED(ulRefCnt != 0, "punkIn RefCnt not zero\n");
+ }
+
+ return TestResult(RetVal, "TestUnmarshalGUIDNULL");
+}
+
+// ----------------------------------------------------------------------
+//
+// test calling CoUmarshalInterface with an IID different from
+// the IID that was marshaled.
+//
+// ----------------------------------------------------------------------
+
+BOOL TestUnmarshalDifferentIID(void)
+{
+ BOOL RetVal = TRUE;
+ HRESULT hres;
+ LPSTREAM pStm = NULL;
+ IUnknown *punkIn = NULL;
+ ULONG ulRefCnt, i;
+ HANDLE hEvent = NULL;
+ ThreadUnmarshalInfo Info;
+
+ LARGE_INTEGER large_int;
+ LISet32(large_int, 0);
+
+ OUTPUT ("Starting TestUnmarshalDifferentIID\n");
+
+ // Create a shared memory stream for the marshaled interface
+ pStm = CreateMemStm(600, NULL);
+ TEST_FAILED_EXIT((pStm == NULL), "CreateMemStm failed\n")
+
+// ----------------------------------------------------------------------
+
+ for (i=0; i<2; i++)
+ {
+ hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+ TEST_FAILED_EXIT(hEvent == NULL, "CreateEvent failed\n")
+
+ punkIn = GetTestUnk();
+ TEST_FAILED_EXIT((punkIn == NULL), "new CTestUnk failed\n")
+ VerifyObjRefCnt(punkIn, 1);
+
+ // reset the stream ptr
+ hres = pStm->Seek(large_int, STREAM_SEEK_SET, NULL);
+ TEST_FAILED_EXIT(FAILED(hres), "Seek on shared stream failed\n")
+
+ // Marshal the interface into the stream
+ hres = CoMarshalInterface(pStm, IID_IParseDisplayName, punkIn,
+ 0, 0, MSHLFLAGS_NORMAL);
+ TEST_FAILED_EXIT(FAILED(hres), "CoMarshalInterface failed\n")
+ VerifyRHRefCnt(punkIn, 1);
+ OUTPUT (" - CoMarshalInterface OK.\n");
+
+ // reset the stream ptr
+ hres = pStm->Seek(large_int, STREAM_SEEK_SET, NULL);
+ TEST_FAILED_EXIT(FAILED(hres), "Seek on shared stream failed\n")
+
+ Info.hEvent = hEvent;
+ Info.pStm = pStm;
+ Info.iid = IID_IOleWindow;
+ Info.pUnk = punkIn;
+ Info.dwInitFlag = gInitFlag;
+ Info.dwThreadId = 0;
+
+ if (i==0)
+ {
+ // first time, call on same thread, expect different ptr and
+ // non-zero refcnt after release
+ Info.pUnk = 0;
+ Info.RelRefCnt = 1;
+
+ ThreadTestUnmarshal(&Info);
+ }
+ else
+ {
+ if (gInitFlag == COINIT_APARTMENTTHREADED)
+ {
+ // apartment thread, expect differnt ptr and
+ // zero refcnt after release
+
+ Info.dwThreadId = GetCurrentThreadId();
+ Info.pUnk = 0;
+ Info.RelRefCnt = 0;
+ }
+ else
+ {
+ // multi-thread, expect same ptr and non-zero refcnt
+ // after release
+
+ Info.dwThreadId = GetCurrentThreadId();
+ Info.pUnk = 0;
+ Info.RelRefCnt = 1;
+ }
+
+ RunThread(&Info, hEvent, ThreadTestUnmarshal);
+ CloseHandle(hEvent);
+ }
+
+ // release the punkIn.
+ ulRefCnt = punkIn->Release();
+ TEST_FAILED(ulRefCnt != 0, "punkIn RefCnt not zero\n");
+ punkIn = NULL;
+
+ hres = Info.hr;
+ OUTPUT (" - Run Complete\n");
+ }
+
+// ----------------------------------------------------------------------
+
+Cleanup:
+
+ OUTPUT (" - Test Complete. Doing Cleanup\n");
+
+ // Dump interfaces we are done with
+ if (pStm)
+ {
+ ulRefCnt = pStm->Release();
+ TEST_FAILED(ulRefCnt != 0, "Stream RefCnt not zero\n");
+ }
+
+ if (punkIn)
+ {
+ ulRefCnt = punkIn->Release();
+ TEST_FAILED(ulRefCnt != 0, "punkIn RefCnt not zero\n");
+ }
+
+ return TestResult(RetVal, "TestUnmarshalDifferentIID");
+}
+
+
+// ----------------------------------------------------------------------
+//
+// test REMOTE interface MSHLFLAGS_NORMAL
+//
+// ----------------------------------------------------------------------
+
+BOOL TestRemoteInterfaceNormal(void)
+{
+ BOOL RetVal = TRUE;
+ HRESULT hres;
+ LPSTREAM pStm = NULL;
+ LPCLASSFACTORY pICF = NULL;
+ ULONG ulRefCnt;
+ IUnknown *punkOut = NULL;
+ IUnknown *punkIn = NULL;
+
+ LARGE_INTEGER large_int;
+ LISet32(large_int, 0);
+
+ OUTPUT ("Starting TestRemoteInterfaceNormal\n");
+
+ // Create an IClassFactory Interface.
+ DWORD grfContext=CLSCTX_LOCAL_SERVER; // handler/server/local server
+ hres = CoGetClassObject(CLSID_Balls,
+ grfContext,
+ NULL, // pvReserved
+ IID_IClassFactory,
+ (void **)&pICF);
+
+ TEST_FAILED_EXIT(FAILED(hres), "CoGetClassObject failed\n")
+ TEST_FAILED_EXIT((pICF == NULL), "CoGetClassObject failed\n")
+ VerifyRHRefCnt((IUnknown *)pICF, 1);
+ OUTPUT (" - Aquired Remote Class Object.\n");
+
+// ----------------------------------------------------------------------
+
+ // note, since pICF is a class object, it has special super secret
+ // behaviour to make it go away. create an instance, release the
+ // class object, then release the instance.
+
+ hres = pICF->CreateInstance(NULL, IID_IUnknown, (void **)&punkIn);
+ TEST_FAILED_EXIT(FAILED(hres), "CreateInstance failed\n")
+ TEST_FAILED_EXIT((punkIn == NULL), "CreateInstance failed\n")
+ VerifyRHRefCnt(punkIn, 1);
+ OUTPUT (" - Created Instance.\n");
+
+ // release class object
+ ulRefCnt = pICF->Release();
+ TEST_FAILED(ulRefCnt != 0, "pICF RefCnt not zero\n");
+// VerifyRHRefCnt((IUnknown *)pICF, 0);
+ pICF = NULL;
+ OUTPUT (" - Released Class Object.\n");
+
+// ----------------------------------------------------------------------
+
+ // Create a shared memory stream for the marshaled interface
+ pStm = CreateMemStm(600, NULL);
+ TEST_FAILED_EXIT((pStm == NULL), "CreateMemStm failed\n")
+
+ // Marshal the interface into the stream
+ hres = CoMarshalInterface(pStm, IID_IUnknown, punkIn, 0, NULL, MSHLFLAGS_NORMAL);
+ TEST_FAILED_EXIT(FAILED(hres), "CoMarshalInterface failed\n")
+ OUTPUT (" - CoMarshalInterface OK.\n");
+ VerifyRHRefCnt(punkIn, 1);
+
+ // unmarshal the interface. should get the same proxy back.
+ hres = pStm->Seek(large_int, STREAM_SEEK_SET, NULL);
+ TEST_FAILED_EXIT(FAILED(hres), "Seek on shared stream failed\n")
+
+ hres = CoUnmarshalInterface(pStm, IID_IUnknown, (LPVOID FAR*)&punkOut);
+ TEST_FAILED_EXIT(FAILED(hres), "CoUnmarshalInterface failed\n")
+ VerifyRHRefCnt(punkIn, 2);
+
+ // make sure the interface pointers are identical
+ if (punkIn != punkOut)
+ TEST_FAILED_EXIT(TRUE, "Interface ptrs dont match..1st Remote Unmarshal\n")
+ OUTPUT (" - CoUnmarshalInterface OK.\n");
+
+
+ // release the interface
+ ulRefCnt = punkOut->Release();
+ punkOut = NULL;
+ TEST_FAILED_EXIT(ulRefCnt == 0, "punkOut RefCnt is zero\n");
+ VerifyRHRefCnt(punkIn, 1);
+ OUTPUT (" - Release OK\n");
+
+// ----------------------------------------------------------------------
+
+#if 0
+ // test unmarshalling twice. this should fail since we marshalled normal
+ hres = pStm->Seek(large_int, STREAM_SEEK_SET, NULL);
+ TEST_FAILED_EXIT(FAILED(hres), "Seek on shared stream failed\n")
+
+ hres = CoUnmarshalInterface(pStm, IID_IUnknown, (LPVOID FAR*)&punkOut);
+ TEST_FAILED_EXIT(SUCCEEDED(hres), "CoUnmarshalInterface succeeded but should have failed\n")
+ VerifyRHRefCnt(punkIn, 1);
+ OUTPUT (" - Second CoUnmarshalInterface OK.\n");
+ punkOut = NULL;
+
+// ----------------------------------------------------------------------
+
+ // CoReleaseMarshalData should FAIL since we already unmarshalled it
+ hres = pStm->Seek(large_int, STREAM_SEEK_SET, NULL);
+ TEST_FAILED_EXIT(FAILED(hres), "Seek on shared stream failed\n")
+
+ hres = CoReleaseMarshalData(pStm);
+ TEST_FAILED_EXIT(SUCCEEDED(hres), "CoReleaseMarshalData succeeded but should have failed.\n")
+ VerifyRHRefCnt(punkIn, 1);
+ OUTPUT (" - CoReleaseMarshalData OK\n");
+
+#endif
+// ----------------------------------------------------------------------
+
+ // marshal again and try CoRelease without having first done an
+ // unmarshal. this should work.
+ hres = pStm->Seek(large_int, STREAM_SEEK_SET, NULL);
+ TEST_FAILED_EXIT(FAILED(hres), "Seek on shared stream failed\n")
+
+ hres = CoMarshalInterface(pStm, IID_IUnknown, punkIn, 0, NULL, MSHLFLAGS_NORMAL);
+ TEST_FAILED_EXIT(FAILED(hres), "CoMarshalInterface failed\n")
+ VerifyRHRefCnt(punkIn, 1);
+ OUTPUT (" - CoMarshalInterface OK\n");
+
+ hres = pStm->Seek(large_int, STREAM_SEEK_SET, NULL);
+ TEST_FAILED_EXIT(FAILED(hres), "Seek on shared stream failed\n")
+
+ hres = CoReleaseMarshalData(pStm);
+ TEST_FAILED_EXIT(FAILED(hres), "CoReleaseMarshalData failed.\n")
+ VerifyRHRefCnt(punkIn, 1);
+ OUTPUT (" - CoReleaseMarshalData OK\n");
+
+// ----------------------------------------------------------------------
+
+Cleanup:
+
+ OUTPUT (" - Test Complete. Doing Cleanup\n");
+
+ // Dump interfaces we are done with
+ if (pStm)
+ {
+ ulRefCnt = pStm->Release();
+ TEST_FAILED(ulRefCnt != 0, "Stream RefCnt not zero\n");
+ }
+
+ if (pICF)
+ {
+ ulRefCnt = pICF->Release();
+ TEST_FAILED(ulRefCnt != 0, "pICF RefCnt not zero\n");
+ }
+
+ if (punkOut)
+ {
+ ulRefCnt = punkOut->Release();
+ TEST_FAILED(ulRefCnt == 0, "punkOut RefCnt is zero\n");
+ }
+
+ if (punkIn)
+ {
+ ulRefCnt = punkIn->Release();
+ TEST_FAILED(ulRefCnt != 0, "punkIn RefCnt not zero\n");
+ }
+
+ return TestResult(RetVal, "TestRemoteInterfaceNormal");
+}
+
+
+// ----------------------------------------------------------------------
+//
+// test REMOTE interface MSHLFLAGS_TABLESTRONG
+//
+// ----------------------------------------------------------------------
+
+BOOL TestRemoteInterfaceTableStrong(void)
+{
+ BOOL RetVal = TRUE;
+ HRESULT hres;
+ LPSTREAM pStm = NULL;
+ LPCLASSFACTORY pICF = NULL;
+ ULONG ulRefCnt;
+ IUnknown *punkIn = NULL;
+ IUnknown *punkOut = NULL;
+
+ LARGE_INTEGER large_int;
+ LISet32(large_int, 0);
+
+ OUTPUT ("Starting TestRemoteInterfaceTableStrong\n");
+
+ // Create an IClassFactory Interface.
+ DWORD grfContext=CLSCTX_LOCAL_SERVER; // handler/server/local server
+ hres = CoGetClassObject(CLSID_Balls,
+ grfContext,
+ NULL, // pvReserved
+ IID_IClassFactory,
+ (void **)&pICF);
+
+ TEST_FAILED_EXIT(FAILED(hres), "CoGetClassObject failed\n")
+ TEST_FAILED_EXIT((pICF == NULL), "CoGetClassObject failed\n")
+ OUTPUT (" - Aquired Remote Class Object.\n");
+
+// ----------------------------------------------------------------------
+
+ // note, since pICF is a class object, it has special super secret
+ // behaviour to make it go away. create an instance, release the
+ // class object, then release the instance.
+
+ hres = pICF->CreateInstance(NULL, IID_IUnknown, (void **)&punkIn);
+ TEST_FAILED_EXIT(FAILED(hres), "CreateInstance failed\n")
+ TEST_FAILED_EXIT((punkIn == NULL), "CreateInstance failed\n")
+ OUTPUT (" - Created Instance.\n");
+
+ // release class object
+ ulRefCnt = pICF->Release();
+ TEST_FAILED(ulRefCnt != 0, "pICF RefCnt not zero\n");
+ pICF = NULL;
+ OUTPUT (" - Released Class Object.\n");
+
+// ----------------------------------------------------------------------
+
+ // Create a shared memory stream for the marshaled moniker
+ pStm = CreateMemStm(600, NULL);
+ TEST_FAILED_EXIT((pStm == NULL), "CreateMemStm failed\n")
+
+ // Marshal the interface into the stream
+ hres = CoMarshalInterface(pStm, IID_IUnknown, punkIn, 0, NULL, MSHLFLAGS_TABLESTRONG);
+ TEST_FAILED_EXIT(SUCCEEDED(hres), "CoMarshalInterface succeeded but should have failed\n")
+ OUTPUT (" - CoMarshalInterface OK.\n");
+
+ LISet32(large_int, 0);
+ hres = pStm->Seek(large_int, STREAM_SEEK_SET, NULL);
+ TEST_FAILED_EXIT(FAILED(hres), "Seek on shared stream failed\n")
+
+#if 0
+ hres = CoUnmarshalInterface(pStm, IID_IUnknown, (LPVOID FAR*)&punkOut);
+ TEST_FAILED_EXIT(FAILED(hres), "CoUnmarshalInterface failed\n")
+
+ // make sure the interface pointers are identical
+ if (punkIn != punkOut)
+ TEST_FAILED_EXIT(TRUE, "Interface ptrs dont match..1st Remote Unmarshal\n")
+ OUTPUT (" - CoUnmarshalInterface OK.\n");
+
+ // release it
+ ulRefCnt = punkOut->Release();
+ TEST_FAILED_EXIT(ulRefCnt == 0, "punkOut RefCnt is zero\n");
+ punkOut = NULL;
+ OUTPUT (" - Release OK\n");
+
+// ----------------------------------------------------------------------
+
+ // test unmarshalling twice.
+ // this should work since we did marshal flags TABLE_STRONG
+ hres = pStm->Seek(large_int, STREAM_SEEK_SET, NULL);
+ TEST_FAILED_EXIT(FAILED(hres), "Seek on shared stream failed\n")
+
+ hres = CoUnmarshalInterface(pStm, IID_IUnknown, (LPVOID FAR*)&punkOut);
+ TEST_FAILED_EXIT(FAILED(hres), "CoUnmarshalInterface failed\n")
+ OUTPUT (" - Second CoUnmarshalInterface OK.\n");
+
+// ----------------------------------------------------------------------
+
+ // CoReleaseMarshalData should WORK for TABLESTRONG interfaces
+ hres = pStm->Seek(large_int, STREAM_SEEK_SET, NULL);
+ TEST_FAILED_EXIT(FAILED(hres), "Seek on shared stream failed\n")
+
+ hres = CoReleaseMarshalData(pStm);
+ TEST_FAILED_EXIT(FAILED(hres), "CoReleaseMarshalData failed.\n")
+ OUTPUT (" - CoReleaseMarshalData OK\n");
+
+// ----------------------------------------------------------------------
+#endif
+Cleanup:
+
+ OUTPUT (" - Test Complete. Doing Cleanup\n");
+
+ // Dump interfaces we are done with
+ if (pStm)
+ {
+ ulRefCnt = pStm->Release();
+ TEST_FAILED(ulRefCnt != 0, "Stream RefCnt not zero\n");
+ }
+
+ if (punkOut)
+ {
+ ulRefCnt = punkOut->Release();
+ TEST_FAILED(ulRefCnt == 0, "punkOut RefCnt is zero\n");
+ }
+
+ if (punkIn)
+ {
+ // release instance
+ ulRefCnt = punkIn->Release();
+ TEST_FAILED(ulRefCnt != 0,"punkIn RefCnt not zero\n");
+ }
+
+ return TestResult(RetVal, "TestRemoteInterfaceTableStrong");
+}
+
+// ----------------------------------------------------------------------
+//
+// test CUSTOM interface MSHLFLAGS_NORMAL --- CODEWORK
+//
+// ----------------------------------------------------------------------
+
+BOOL TestCustomMarshalNormal(void)
+{
+ BOOL RetVal = TRUE;
+
+ return TestResult(RetVal, "TestCustomMarshalNormal");
+}
+
+
+// ----------------------------------------------------------------------
+//
+// test CUSTOM interface MSHLFLAGS_TABLESTRONG --- CODEWORK
+//
+// ----------------------------------------------------------------------
+
+BOOL TestCustomMarshalTable(void)
+{
+ BOOL RetVal = TRUE;
+
+ return TestResult(RetVal, "TestCustomMarshalTableStrong");
+}
+
+
+// ----------------------------------------------------------------------
+//
+// TestEcho
+//
+// test sending an interface to a remote server and getting the same
+// interface back again. the test is done with once with a local
+// interface and once with a remote interface.
+//
+// Local Interface Remote Interface
+//
+// 1. marshal [in] local marshal [in] remote proxy
+// 2. unmarshal [in] remote unmarshal [in] local proxy
+// 3. marshal [out] remote proxy marshal [out] local
+// 4. unmarshal [in] local proxy unmarshal [out] remote
+//
+// ----------------------------------------------------------------------
+
+BOOL TestEcho(void)
+{
+ BOOL RetVal = TRUE;
+ HRESULT hres;
+ ULONG ulRefCnt;
+ LPCLASSFACTORY pICF = NULL;
+ IBalls *pIBalls = NULL;
+ IUnknown *punkIn = NULL;
+ IUnknown *punkIn2 = NULL;
+ IUnknown *punkOut = NULL;
+
+ LARGE_INTEGER large_int;
+ LISet32(large_int, 0);
+
+ OUTPUT ("Starting TestEcho\n");
+
+ // Create an IBall ClassFactory Interface.
+ DWORD grfContext=CLSCTX_LOCAL_SERVER; // handler/server/local server
+ hres = CoGetClassObject(CLSID_Balls,
+ grfContext,
+ NULL, // pvReserved
+ IID_IClassFactory,
+ (void **)&pICF);
+
+ TEST_FAILED_EXIT(FAILED(hres), "CoGetClassObject failed\n")
+ TEST_FAILED_EXIT((pICF == NULL), "CoGetClassObject failed\n")
+ OUTPUT (" - Aquired Remote Class Object.\n");
+
+// ----------------------------------------------------------------------
+
+ // note, since pICF is a class object, it has special super secret
+ // behaviour to make it go away. create an instance, release the
+ // class object, then release the instance.
+
+ hres = pICF->CreateInstance(NULL, IID_IBalls, (void **)&pIBalls);
+ TEST_FAILED_EXIT(FAILED(hres), "CreateInstance failed\n")
+ TEST_FAILED_EXIT((pIBalls == NULL), "CreateInstance failed\n")
+ OUTPUT (" - Created First Instance.\n");
+
+ hres = pICF->CreateInstance(NULL, IID_IUnknown, (void **)&punkIn2);
+ TEST_FAILED_EXIT(FAILED(hres), "CreateInstance failed\n")
+ TEST_FAILED_EXIT((punkIn2 == NULL), "CreateInstance failed\n")
+ OUTPUT (" - Created Second Instance.\n");
+
+ // release class object
+ ulRefCnt = pICF->Release();
+ TEST_FAILED(ulRefCnt != 0, "pICF RefCnt not zero\n");
+ pICF = NULL;
+ OUTPUT (" - Released Class Object.\n");
+
+// ----------------------------------------------------------------------
+
+ // create a local interface
+ punkIn = GetTestUnk();
+ TEST_FAILED_EXIT((punkIn == NULL), "new CTestUnk failed\n")
+ VerifyObjRefCnt(punkIn, 1);
+
+ // call a method that echos the local interface right back to us.
+ hres = pIBalls->Echo(punkIn, &punkOut);
+ TEST_FAILED_EXIT(FAILED(hres), "Echo on IBalls failed\n")
+ TEST_FAILED_EXIT((punkOut == NULL), "Echo on IBalls failed\n")
+
+ // make sure the interface pointers are identical
+ if (punkIn != punkOut)
+ TEST_FAILED_EXIT(TRUE, "Interface ptrs dont match..Echo\n")
+
+ VerifyObjRefCnt(punkIn, 2);
+ VerifyRHRefCnt(punkIn, 0);
+ OUTPUT (" - Echo OK.\n");
+
+ // release the out interface
+ ulRefCnt = punkOut->Release();
+ punkOut = NULL;
+ TEST_FAILED_EXIT(ulRefCnt != 1, "punkOut RefCnt is not 1\n");
+ OUTPUT (" - Released punkOut OK\n");
+
+ // release the In interface
+ ulRefCnt = punkIn->Release();
+ punkIn = NULL;
+ TEST_FAILED_EXIT(ulRefCnt != 0, "punkIn RefCnt is not zero\n");
+ OUTPUT (" - Released punkIn OK\n");
+
+ OUTPUT (" - Echo Local Interface OK\n");
+
+// ----------------------------------------------------------------------
+
+ // call a method that echos a remote interface right back to us.
+ hres = pIBalls->Echo(punkIn2, &punkOut);
+ TEST_FAILED_EXIT(FAILED(hres), "Echo on IBalls failed\n")
+ TEST_FAILED_EXIT((punkOut == NULL), "Echon on IBalls failed\n")
+
+ // make sure the interface pointers are identical
+ if (punkIn2 != punkOut)
+ TEST_FAILED_EXIT(TRUE, "Interface ptrs dont match..Echo\n")
+
+ VerifyObjRefCnt(punkIn2, 2);
+ VerifyRHRefCnt(punkIn2, 2);
+ OUTPUT (" - Echo OK.\n");
+
+ // release the out interface
+ ulRefCnt = punkOut->Release();
+ punkOut = NULL;
+ TEST_FAILED_EXIT(ulRefCnt != 1, "punkOut RefCnt is not 1\n");
+ OUTPUT (" - Released punkOut OK\n");
+
+ // release the In interface
+ ulRefCnt = punkIn2->Release();
+ punkIn2 = NULL;
+ TEST_FAILED_EXIT(ulRefCnt != 0, "punkIn2 RefCnt is not zero\n");
+ OUTPUT (" - Released punkIn2 OK\n");
+
+ OUTPUT (" - Echo Remote Interface OK\n");
+
+// ----------------------------------------------------------------------
+
+ // release the IBalls interface
+ ulRefCnt = pIBalls->Release();
+ TEST_FAILED_EXIT(ulRefCnt != 0, "pIBalls RefCnt is not zero\n");
+ pIBalls = NULL;
+ OUTPUT (" - Released IBalls OK\n");
+
+// ----------------------------------------------------------------------
+
+Cleanup:
+
+ OUTPUT (" - Test Complete. Doing Cleanup\n");
+
+ // Dump interfaces we are done with
+ if (pICF)
+ {
+ ulRefCnt = pICF->Release();
+ TEST_FAILED(ulRefCnt != 0, "pICF RefCnt not zero\n");
+ }
+
+ if (punkOut)
+ {
+ ulRefCnt = punkOut->Release();
+ TEST_FAILED(ulRefCnt == 0, "punkOut RefCnt is zero\n");
+ }
+
+ if (punkIn)
+ {
+ ulRefCnt = punkIn->Release();
+ TEST_FAILED(ulRefCnt != 0, "punkIn RefCnt not zero\n");
+ }
+
+ if (pIBalls)
+ {
+ ulRefCnt = pIBalls->Release();
+ TEST_FAILED(ulRefCnt != 0, "pIBalls RefCnt not zero\n");
+ }
+
+ if (punkIn2)
+ {
+ ulRefCnt = punkIn2->Release();
+ TEST_FAILED(ulRefCnt != 0, "punkIn2 RefCnt not zero\n");
+ }
+
+ return TestResult(RetVal, "TestEcho");
+}
+
+
+
+// ----------------------------------------------------------------------
+//
+// TestMiddleMan
+//
+// test sending an remote interface to a second different process.
+//
+// 1. marshal [in] remote proxy
+// 2. unmarshal [in] remote proxy
+// 3. marshal [out] remote proxy
+// 4. unmarshal [in] local proxy
+//
+// ----------------------------------------------------------------------
+
+BOOL TestMiddleMan(void)
+{
+ BOOL RetVal = TRUE;
+ HRESULT hres;
+ ULONG ulRefCnt;
+ LPCLASSFACTORY pICF = NULL;
+ IBalls *pIBalls = NULL;
+ ICube *pICubes = NULL;
+ IUnknown *punkIn = NULL;
+ IUnknown *punkOut = NULL;
+
+ LARGE_INTEGER large_int;
+ LISet32(large_int, 0);
+
+ OUTPUT ("Starting TestMiddleMan\n");
+
+ // Create an IBall ClassFactory Interface.
+ DWORD grfContext=CLSCTX_LOCAL_SERVER; // handler/server/local server
+ hres = CoGetClassObject(CLSID_Balls,
+ grfContext,
+ NULL, // pvReserved
+ IID_IClassFactory,
+ (void **)&pICF);
+
+ TEST_FAILED_EXIT(FAILED(hres), "CoGetClassObject Balls failed\n")
+ TEST_FAILED_EXIT((pICF == NULL), "CoGetClassObject Balls failed\n")
+ OUTPUT (" - Aquired Remote Balls Class Object.\n");
+ VerifyObjRefCnt(pICF, 1);
+ VerifyRHRefCnt(pICF, 1);
+
+// ----------------------------------------------------------------------
+
+ // note, since pICF is a class object, it has special super secret
+ // behaviour to make it go away. create an instance, release the
+ // class object, then release the instance.
+
+ hres = pICF->CreateInstance(NULL, IID_IBalls, (void **)&pIBalls);
+ TEST_FAILED_EXIT(FAILED(hres), "CreateInstance failed\n")
+ TEST_FAILED_EXIT((pIBalls == NULL), "CreateInstance failed\n")
+ OUTPUT (" - Created Balls Instance.\n");
+
+ VerifyObjRefCnt(pIBalls, 1);
+ VerifyRHRefCnt(pIBalls, 1);
+
+ // release class object
+ ulRefCnt = pICF->Release();
+ TEST_FAILED(ulRefCnt != 0, "pICF RefCnt not zero\n");
+ pICF = NULL;
+ OUTPUT (" - Released Balls Class Object.\n");
+
+// ----------------------------------------------------------------------
+
+ // Create an ICube ClassFactory Interface.
+ grfContext=CLSCTX_LOCAL_SERVER; // handler/server/local server
+ hres = CoGetClassObject(CLSID_Cubes,
+ grfContext,
+ NULL, // pvReserved
+ IID_IClassFactory,
+ (void **)&pICF);
+
+ TEST_FAILED_EXIT(FAILED(hres), "CoGetClassObject Cubes failed\n")
+ TEST_FAILED_EXIT((pICF == NULL), "CoGetClassObject Cubes failed\n")
+ OUTPUT (" - Aquired Remote Cubes Class Object.\n");
+ VerifyObjRefCnt(pICF, 1);
+ VerifyRHRefCnt(pICF, 1);
+
+// ----------------------------------------------------------------------
+
+ // note, since pICF is a class object, it has special super secret
+ // behaviour to make it go away. create an instance, release the
+ // class object, then release the instance.
+
+ hres = pICF->CreateInstance(NULL, IID_ICube, (void **)&pICubes);
+ TEST_FAILED_EXIT(FAILED(hres), "CreateInstance Cubes failed\n")
+ TEST_FAILED_EXIT((pICubes == NULL), "CreateInstance Cubes failed\n")
+ OUTPUT (" - Created Cubes Instance.\n");
+
+ VerifyObjRefCnt(pICubes, 1);
+ VerifyRHRefCnt(pICubes, 1);
+
+ // release class object
+ ulRefCnt = pICF->Release();
+ TEST_FAILED(ulRefCnt != 0, "pICF RefCnt not zero\n");
+ pICF = NULL;
+ OUTPUT (" - Released Cubes Class Object.\n");
+
+// ----------------------------------------------------------------------
+
+ // pass the remote cubes interface to the balls interface.
+ hres = pIBalls->IsContainedIn(pICubes);
+ TEST_FAILED_EXIT(FAILED(hres), "IsContainedIn failed\n")
+ VerifyObjRefCnt(pIBalls, 1);
+ VerifyRHRefCnt(pIBalls, 1);
+ VerifyObjRefCnt(pICubes, 1);
+ VerifyRHRefCnt(pICubes, 1);
+ OUTPUT (" - IsContainedIn OK.\n");
+
+// ----------------------------------------------------------------------
+
+ // pass the remote balls interface to the cubes interface.
+ hres = pICubes->Contains(pIBalls);
+ TEST_FAILED_EXIT(FAILED(hres), "Contains failed\n")
+ VerifyObjRefCnt(pIBalls, 1);
+ VerifyRHRefCnt(pIBalls, 1);
+ VerifyObjRefCnt(pICubes, 1);
+ VerifyRHRefCnt(pICubes, 1);
+ OUTPUT (" - Contains OK.\n");
+
+// ----------------------------------------------------------------------
+
+ // echo the remote ICubes interface to the remote IBalls interface
+ hres = pICubes->QueryInterface(IID_IUnknown, (void **)&punkIn);
+ TEST_FAILED_EXIT(FAILED(hres), "QueryInterface IUnknown failed\n")
+ VerifyRHRefCnt(pICubes, 2);
+ VerifyObjRefCnt(pICubes, 2);
+ OUTPUT (" - QueryInterface OK.\n");
+
+ hres = pIBalls->Echo(punkIn, &punkOut);
+ TEST_FAILED_EXIT(FAILED(hres), "Echo on IBalls failed\n")
+ TEST_FAILED_EXIT((punkOut == NULL), "Echo on IBalls failed\n")
+
+ // make sure the interface pointers are identical
+ if (punkIn != punkOut)
+ TEST_FAILED_EXIT(TRUE, "Interface ptrs dont match..Echo\n")
+
+ VerifyObjRefCnt(punkIn, 3);
+ VerifyRHRefCnt(punkIn, 3);
+ OUTPUT (" - Echo OK.\n");
+
+ // release the out interface
+ ulRefCnt = punkOut->Release();
+ punkOut = NULL;
+ TEST_FAILED(ulRefCnt != 2, "punkOut RefCnt is not 2\n");
+ OUTPUT (" - Released punkOut OK\n");
+
+ // release the In interface
+ ulRefCnt = punkIn->Release();
+ punkIn = NULL;
+ TEST_FAILED(ulRefCnt != 1, "punkIn RefCnt is not 1\n");
+ OUTPUT (" - Released punkIn OK\n");
+
+// ----------------------------------------------------------------------
+
+ // release the ICubes interface
+ ulRefCnt = pICubes->Release();
+ TEST_FAILED(ulRefCnt != 0, "pICubes RefCnt is not zero\n");
+ pICubes = NULL;
+ OUTPUT (" - Released ICubes OK\n");
+
+// ----------------------------------------------------------------------
+
+ // release the IBalls interface
+ ulRefCnt = pIBalls->Release();
+ TEST_FAILED(ulRefCnt != 0, "pIBalls RefCnt is not zero\n");
+ pIBalls = NULL;
+ OUTPUT (" - Released IBalls OK\n");
+
+// ----------------------------------------------------------------------
+
+
+Cleanup:
+
+ OUTPUT (" - Test Complete. Doing Cleanup\n");
+
+ // Dump interfaces we are done with
+ if (pICF)
+ {
+ ulRefCnt = pICF->Release();
+ TEST_FAILED(ulRefCnt != 0, "pICF RefCnt not zero\n");
+ }
+
+ if (pIBalls)
+ {
+ ulRefCnt = pIBalls->Release();
+ TEST_FAILED(ulRefCnt != 0, "pIBalls RefCnt not zero\n");
+ }
+
+ if (pICubes)
+ {
+ ulRefCnt = pICubes->Release();
+ TEST_FAILED(ulRefCnt != 0, "pICubes RefCnt not zero\n");
+ }
+
+ return TestResult(RetVal, "TestMiddleMan");
+}
+
+
+// ----------------------------------------------------------------------
+//
+// TestLoop
+//
+// tests A calling B calling A calling B etc n times, to see if Rpc
+// can handle this.
+//
+// ----------------------------------------------------------------------
+
+BOOL TestLoop(void)
+{
+ BOOL RetVal = TRUE;
+ HRESULT hRes = S_OK;
+ ILoop *pLocalLoop = NULL;
+ ILoop *pRemoteLoop = NULL;
+
+ OUTPUT ("Starting TestLoop\n");
+
+ // create our interface to pass to the remote object.
+ hRes = CoCreateInstance(CLSID_LoopSrv, NULL, CLSCTX_LOCAL_SERVER,
+ IID_ILoop, (void **)&pLocalLoop);
+ TEST_FAILED_EXIT(FAILED(hRes), "CoCreateInstance First failed\n")
+
+ // create the remote object
+ hRes = CoCreateInstance(CLSID_LoopSrv, NULL, CLSCTX_LOCAL_SERVER,
+ IID_ILoop, (void **)&pRemoteLoop);
+ TEST_FAILED_EXIT(FAILED(hRes), "CoCreateInstance Second failed\n")
+
+ // initialize the two instances
+ OUTPUT (" - Initializing Instances\n");
+ hRes = pLocalLoop->Init(pRemoteLoop);
+ TEST_FAILED_EXIT(FAILED(hRes), "Initialize First failed\n")
+ hRes = pRemoteLoop->Init(pLocalLoop);
+ TEST_FAILED_EXIT(FAILED(hRes), "Initialize Second failed\n")
+
+ // now start the test
+ OUTPUT (" - Running LoopTest\n");
+ hRes = pLocalLoop->Loop(10);
+ TEST_FAILED(FAILED(hRes), "Loop failed\n")
+
+ // uninitialize the two instances
+ OUTPUT (" - Uninitializing Instances\n");
+ hRes = pLocalLoop->Uninit();
+ TEST_FAILED_EXIT(FAILED(hRes), "Uninitialize First failed\n")
+ hRes = pRemoteLoop->Uninit();
+ TEST_FAILED_EXIT(FAILED(hRes), "Uninitialize Second failed\n")
+
+Cleanup:
+
+ // release the two instances
+ OUTPUT (" - Releasing Instances\n");
+
+ if (pRemoteLoop)
+ pRemoteLoop->Release();
+
+ if (pLocalLoop)
+ pLocalLoop->Release();
+
+ return TestResult(RetVal, "TestLoop");
+}
+
+// ----------------------------------------------------------------------
+//
+// TestMultiQINormal
+//
+// tests IMultiQI interface on Normal proxies
+//
+// ----------------------------------------------------------------------
+
+ULONG cMisc = 4;
+const IID *iidMisc[] = {
+ &IID_IParseDisplayName, &IID_IPersistStorage,
+ &IID_IPersistFile, &IID_IStorage,
+ &IID_IOleContainer, &IID_IOleItemContainer,
+ &IID_IOleInPlaceSite, &IID_IOleInPlaceActiveObject,
+ &IID_IOleInPlaceObject, &IID_IOleInPlaceUIWindow,
+ &IID_IOleInPlaceFrame, &IID_IOleWindow};
+
+MULTI_QI arMQI[20];
+MULTI_QI *pMQIResStart = arMQI;
+
+BOOL TestMultiQINormal(void)
+{
+ BOOL RetVal = TRUE;
+ HRESULT hRes = S_OK;
+ IUnknown *pUnk = NULL;
+ IUnknown *pUnk2 = NULL;
+ IMultiQI *pMQI = NULL;
+ ULONG i = 0, j=0, cRefs = 0;
+ MULTI_QI *pMQIRes = NULL;
+
+// ----------------------------------------------------------------------
+ ULONG cSupported = 4;
+ const IID *iidSupported[] = {&IID_IUnknown, &IID_IMultiQI,
+ &IID_IClientSecurity, &IID_IMarshal,
+ &IID_IStdIdentity, &IID_IProxyManager};
+
+ ULONG cUnSupported = 2;
+ const IID *iidUnSupported[] = {&IID_IInternalUnknown,
+ &IID_IServerSecurity};
+
+// ----------------------------------------------------------------------
+
+ OUTPUT ("Starting TestMultiQINormal\n");
+
+ // create our interface to pass to the remote object.
+ hRes = CoCreateInstance(CLSID_QI, NULL, CLSCTX_LOCAL_SERVER,
+ IID_IUnknown, (void **)&pUnk);
+ TEST_FAILED_EXIT(FAILED(hRes), "CoCreateInstance QISRV failed\n")
+
+ VerifyObjRefCnt(pUnk, 1);
+ VerifyRHRefCnt(pUnk, 1);
+
+// ----------------------------------------------------------------------
+
+ OUTPUT ("\n - NormalQI for supported interfaces\n");
+
+ // loop through all the supported interfaces doing a normal QI.
+
+ for (i=0; i<cSupported; i++)
+ {
+ hRes = pUnk->QueryInterface(*iidSupported[i], (void **)&pUnk2);
+ TEST_FAILED(FAILED(hRes), "QueryInterface on supported interfaces failed\n")
+ if (SUCCEEDED(hRes))
+ {
+ // release the interface
+ VerifyObjRefCnt(pUnk, 2);
+ VerifyRHRefCnt(pUnk, 2);
+
+ OUTPUT (" - QI for supported interface OK\n");
+ pUnk2->Release();
+ }
+ }
+
+
+ OUTPUT ("\n - NormalQI for unsupported interfaces\n");
+
+ // loop through all the unsupported interfaces doing a normal QI.
+
+ for (i=0; i<cUnSupported; i++)
+ {
+ hRes = pUnk->QueryInterface(*iidUnSupported[i], (void **)&pUnk2);
+ TEST_FAILED(SUCCEEDED(hRes), "QueryInterface on unsupported interface succeeded but should have failed\n")
+
+ if (SUCCEEDED(hRes))
+ {
+ // release the interface
+ pUnk2->Release();
+ }
+ else
+ {
+ VerifyObjRefCnt(pUnk, 1);
+ VerifyRHRefCnt(pUnk, 1);
+
+ OUTPUT (" - QI for unsupported interface OK.\n");
+ }
+ }
+
+ // should be back to normal (IUnknown)
+ VerifyObjRefCnt(pUnk, 1);
+ VerifyRHRefCnt(pUnk, 1);
+
+// ----------------------------------------------------------------------
+
+ hRes = pUnk->QueryInterface(IID_IMultiQI, (void **)&pMQI);
+ TEST_FAILED_EXIT(FAILED(hRes), "QI for IMultiQI failed\n")
+ VerifyObjRefCnt(pUnk, 2);
+ VerifyRHRefCnt(pUnk, 2);
+
+
+ OUTPUT ("\n - MultiQI for supported interfaces\n");
+
+ // now issue a MultiQI for the supported interfaces
+ pMQIRes = pMQIResStart;
+ for (i=0; i<cSupported; i++, pMQIRes++)
+ {
+ pMQIRes->pIID = iidSupported[i];
+ pMQIRes->pItf = NULL;
+ }
+
+ pMQIRes = pMQIResStart;
+ hRes = pMQI->QueryMultipleInterfaces(cSupported, pMQIRes);
+ TEST_FAILED(hRes != S_OK, "QueryMultipleInterfaces should have return S_OK\n")
+ VerifyObjRefCnt(pUnk, 2 + cSupported);
+ VerifyRHRefCnt(pUnk, 2 + cSupported);
+
+ for (i=0; i<cSupported; i++, pMQIRes++)
+ {
+ TEST_FAILED(pMQIRes->pItf == NULL, "QueryMultipleInterfaces on supported interfaces returned NULL\n")
+ TEST_FAILED(FAILED(pMQIRes->hr), "QueryMultipleInterfaces on supported interfaces failed\n")
+
+ if (pMQIRes->pItf != NULL)
+ {
+ OUTPUT (" - MultiQI for supported interface OK\n");
+ pMQIRes->pItf->Release();
+
+ VerifyObjRefCnt(pUnk, 2 + cSupported - (i+1));
+ VerifyRHRefCnt(pUnk, 2 + cSupported - (i+1));
+ }
+ }
+
+ // should be back to normal (IUnknown + IMultiQI)
+ VerifyObjRefCnt(pUnk, 2);
+ VerifyRHRefCnt(pUnk, 2);
+
+// ----------------------------------------------------------------------
+
+ OUTPUT ("\n - MultiQI for unsupported interfaces\n");
+
+ // now issue a MultiQI for the unsupported interfaces
+ pMQIRes = pMQIResStart;
+ for (i=0; i<cUnSupported; i++, pMQIRes++)
+ {
+ pMQIRes->pIID = iidUnSupported[i];
+ pMQIRes->pItf = NULL;
+ }
+
+ pMQIRes = pMQIResStart;
+ hRes = pMQI->QueryMultipleInterfaces(cUnSupported, pMQIRes);
+ TEST_FAILED(hRes != E_NOINTERFACE, "QueryMultipleInterfaces should have return E_NOINTERFACES\n")
+ VerifyObjRefCnt(pUnk, 2);
+ VerifyRHRefCnt(pUnk, 2);
+
+ for (i=0; i<cUnSupported; i++, pMQIRes++)
+ {
+ TEST_FAILED(pMQIRes->pItf != NULL, "QueryMultipleInterfaces on supported interfaces returned NULL\n")
+ TEST_FAILED(SUCCEEDED(pMQIRes->hr), "QueryMultipleInterfaces on supported interfaces failed\n")
+
+ if (pMQIRes->pItf != NULL)
+ {
+ pMQIRes->pItf->Release();
+ }
+ else
+ {
+ OUTPUT (" - MultiQI for unsupported interface OK\n");
+ }
+ }
+
+ // should back to normal refcnts (IUnknown + IMultiQI)
+ VerifyObjRefCnt(pUnk, 2);
+ VerifyRHRefCnt(pUnk, 2);
+
+// ----------------------------------------------------------------------
+
+ // repeat this test twice, first time goes remote for the misc interfaces,
+ // second time finds them already instantiated.
+
+ for (j=0; j<2; j++)
+ {
+ OUTPUT ("\n - MultiQI for combination of interfaces\n");
+
+ pMQIRes = pMQIResStart;
+ for (i=0; i<cMisc; i++, pMQIRes++)
+ {
+ pMQIRes->pIID = iidMisc[i];
+ pMQIRes->pItf = NULL;
+ }
+
+ for (i=0; i<cSupported; i++, pMQIRes++)
+ {
+ pMQIRes->pIID = iidSupported[i];
+ pMQIRes->pItf = NULL;
+ }
+
+ for (i=0; i<cUnSupported; i++, pMQIRes++)
+ {
+ pMQIRes->pIID = iidUnSupported[i];
+ pMQIRes->pItf = NULL;
+ }
+
+ pMQIRes = pMQIResStart;
+ hRes = pMQI->QueryMultipleInterfaces(cSupported + cUnSupported + cMisc, pMQIRes);
+ TEST_FAILED(hRes != S_FALSE, "QueryMultipleInterfaces should have return S_FALSE\n")
+ VerifyObjRefCnt(pUnk, 2 + cSupported + cMisc);
+ VerifyRHRefCnt(pUnk, 2 + cSupported + cMisc);
+
+ for (i=0; i<cMisc; i++, pMQIRes++)
+ {
+ TEST_FAILED(pMQIRes->pItf == NULL, "QueryMultipleInterfaces on supported interfaces returned NULL\n")
+ TEST_FAILED(FAILED(pMQIRes->hr), "QueryMultipleInterfaces on supported interfaces failed\n")
+
+ if (pMQIRes->pItf != NULL)
+ {
+ OUTPUT (" - MultiQI for supported remote interface OK\n");
+ pMQIRes->pItf->Release();
+
+ VerifyObjRefCnt(pUnk, 2 + cSupported + cMisc - (i+1));
+ VerifyRHRefCnt(pUnk, 2 + cSupported + cMisc - (i+1));
+ }
+ }
+
+ for (i=0; i<cSupported; i++, pMQIRes++)
+ {
+ TEST_FAILED(pMQIRes->pItf == NULL, "QueryMultipleInterfaces on supported interfaces returned NULL\n")
+ TEST_FAILED(FAILED(pMQIRes->hr), "QueryMultipleInterfaces on supported interfaces failed\n")
+
+ if (pMQIRes->pItf != NULL)
+ {
+ OUTPUT (" - MultiQI for supported local interface OK\n");
+ pMQIRes->pItf->Release();
+
+ VerifyObjRefCnt(pUnk, 2 + cSupported - (i+1));
+ VerifyRHRefCnt(pUnk, 2 + cSupported - (i+1));
+ }
+ }
+
+ for (i=0; i<cUnSupported; i++, pMQIRes++)
+ {
+ TEST_FAILED(pMQIRes->pItf != NULL, "QueryMultipleInterfaces on supported interfaces returned NULL\n")
+ TEST_FAILED(SUCCEEDED(pMQIRes->hr), "QueryMultipleInterfaces on supported interfaces failed\n")
+
+ if (pMQIRes->pItf != NULL)
+ {
+ pMQIRes->pItf->Release();
+ }
+ else
+ {
+ OUTPUT (" - MultiQI for unsupported local interface OK\n");
+ }
+ }
+
+ // should back to normal refcnts (IUnknown + IMultiQI)
+ VerifyObjRefCnt(pUnk, 2);
+ VerifyRHRefCnt(pUnk, 2);
+
+ } // for (j=...)
+
+// ----------------------------------------------------------------------
+Cleanup:
+
+ // release the two instances
+ OUTPUT (" - Releasing Instances\n");
+
+ if (pMQI)
+ {
+ pMQI->Release();
+ }
+
+ if (pUnk)
+ {
+ cRefs = pUnk->Release();
+ TEST_FAILED(cRefs != 0, "Last release not zero\n");
+ }
+
+ return TestResult(RetVal, "TestMultiQINormal");
+}
+
+// ----------------------------------------------------------------------
+//
+// TestMultiQIHandler
+//
+// tests IMultiQI interface on Handlers
+//
+// ----------------------------------------------------------------------
+BOOL TestMultiQIHandler(void)
+{
+ BOOL RetVal = TRUE;
+ HRESULT hRes = S_OK;
+ IUnknown *pUnk = NULL;
+ IUnknown *pUnk2 = NULL;
+ ULONG i = 0;
+ MULTI_QI *pMQIRes = NULL;
+
+// ----------------------------------------------------------------------
+ ULONG cSupported = 4;
+ const IID *iidSupported[] = {&IID_IUnknown, &IID_IMarshal,
+ &IID_IStdIdentity, &IID_IProxyManager};
+
+ ULONG cUnSupported = 4;
+ const IID *iidUnSupported[] = {&IID_IInternalUnknown, &IID_IClientSecurity,
+ &IID_IServerSecurity, &IID_IMultiQI};
+
+
+// ----------------------------------------------------------------------
+
+ OUTPUT ("Starting TestMultiQIHandler\n");
+
+ // create our interface to pass to the remote object.
+ hRes = CoCreateInstance(CLSID_QIHANDLER1, NULL, CLSCTX_LOCAL_SERVER,
+ IID_IUnknown, (void **)&pUnk);
+ TEST_FAILED_EXIT(FAILED(hRes), "CoCreateInstance QIHANDLER1 failed\n")
+
+// ----------------------------------------------------------------------
+
+ OUTPUT ("\n - NormalQI for supported interfaces\n");
+
+ // loop through all the supported interfaces doing a normal QI.
+
+ for (i=0; i<cSupported; i++)
+ {
+ hRes = pUnk->QueryInterface(*iidSupported[i], (void **)&pUnk2);
+ TEST_FAILED(FAILED(hRes), "QueryInterface on supported interfaces failed\n")
+ if (SUCCEEDED(hRes))
+ {
+ // release the interface
+ OUTPUT (" - QI for supported interface OK\n");
+ pUnk2->Release();
+ }
+ }
+
+ OUTPUT ("\n - NormalQI for unsupported interfaces\n");
+
+ // loop through all the unsupported interfaces doing a normal QI.
+
+ for (i=0; i<cUnSupported; i++)
+ {
+ hRes = pUnk->QueryInterface(*iidUnSupported[i], (void **)&pUnk2);
+ TEST_FAILED(SUCCEEDED(hRes), "QueryInterface on unsupported interface succeeded but should have failed\n")
+
+ if (SUCCEEDED(hRes))
+ {
+ // release the interface
+ pUnk2->Release();
+ }
+ else
+ {
+ OUTPUT (" - QI for unsupported interface OK.\n");
+ }
+ }
+// ----------------------------------------------------------------------
+Cleanup:
+
+ // release the two instances
+ OUTPUT (" - Releasing Instances\n");
+
+ if (pUnk)
+ pUnk->Release();
+
+ return TestResult(RetVal, "TestMultiQIHandler");
+}
+
+
+// ----------------------------------------------------------------------
+//
+// TestHandler
+//
+// tests activating a server that has a handler
+//
+// ----------------------------------------------------------------------
+
+BOOL TestHandler(void)
+{
+ BOOL RetVal = TRUE;
+ ULONG cRefs = 0;
+ HRESULT hRes = S_OK;
+ IUnknown *pUnkSrv = NULL;
+ IUnknown *pUnkHdl = NULL;
+ IRunnableObject *pIRO = NULL;
+ IOleObject *pIOO = NULL;
+ IDropTarget *pIDT = NULL;
+
+
+ OUTPUT ("Starting TestHandler\n");
+
+ // create our interface to pass to the remote object.
+ hRes = CoCreateInstance(CLSID_TestEmbed, NULL, CLSCTX_LOCAL_SERVER,
+ IID_IUnknown, (void **)&pUnkSrv);
+ TEST_FAILED_EXIT(FAILED(hRes), "CoCreateInstance LOCAL_SERVER failed\n")
+ VerifyObjRefCnt(pUnkSrv, 1);
+ OUTPUT (" - CoCreateInstance LOCAL_SERVER succeeded\n");
+
+ OUTPUT (" - QI for IRunnableObject\n");
+ hRes = pUnkSrv->QueryInterface(IID_IRunnableObject, (void **)&pIRO);
+ TEST_FAILED(SUCCEEDED(hRes), "QI for IRO on LOCAL_SERVER succeeded\n")
+
+ if (pIRO)
+ {
+ pIRO->Release();
+ pIRO = NULL;
+ }
+
+ OUTPUT (" - Releasing Instance\n");
+ if (pUnkSrv)
+ {
+ cRefs = pUnkSrv->Release();
+ TEST_FAILED(cRefs != 0, "REFCNT wrong on Release\n")
+ pUnkSrv = NULL;
+ }
+ OUTPUT (" - LOCAL_SERVER case complete\n");
+
+// ----------------------------------------------------------------------
+ // create the remote object
+
+ hRes = CoCreateInstance(CLSID_TestEmbed, NULL, CLSCTX_INPROC_HANDLER,
+ IID_IUnknown, (void **)&pUnkHdl);
+ TEST_FAILED_EXIT(FAILED(hRes), "CoCreateInstance INPROC_HANDLER failed\n")
+ VerifyObjRefCnt(pUnkHdl, 1);
+ VerifyRHRefCnt(pUnkHdl, 1);
+ OUTPUT (" - CoCreateInstance INPROC_HANDLER succeeded\n");
+
+// ----------------------------------------------------------------------
+ // query for some unsupported interface to ensure OLE handles QI
+ // when not yet connected to the server.
+
+ OUTPUT (" - QI for IDropTarget\n");
+ hRes = pUnkHdl->QueryInterface(IID_IDropTarget, (void **)&pIDT);
+ VerifyObjRefCnt(pUnkHdl, 1);
+ VerifyRHRefCnt(pUnkHdl, 1);
+ TEST_FAILED_EXIT(SUCCEEDED(hRes),
+ "QI for IDropTarget on INPROC_HANDLER worked but should have failed!\n")
+
+ // the return value from failed QI on a handler that was never connected
+ // must be E_NOINTERFACE
+ TEST_FAILED_EXIT(hRes != E_NOINTERFACE,
+ "QI for IDropTarget on INPROC_HANDLER did not return E_NOINTERFACE!\n")
+
+ OUTPUT (" - Query for remote Interface before connected OK.\n");
+
+// ----------------------------------------------------------------------
+ // run the remote server
+
+ OUTPUT (" - QI for IRunnableObject\n");
+ hRes = pUnkHdl->QueryInterface(IID_IRunnableObject, (void **)&pIRO);
+ VerifyObjRefCnt(pUnkHdl, 2);
+ VerifyRHRefCnt(pUnkHdl, 2);
+ TEST_FAILED_EXIT(FAILED(hRes), "QI for IRO on INPROC_HANDLER failed\n")
+
+ hRes = pIRO->Run(NULL);
+ VerifyObjRefCnt(pUnkHdl, 2);
+ VerifyRHRefCnt(pUnkHdl, 2);
+ TEST_FAILED(FAILED(hRes), "IRO->Run on INPROC_HANDLER failed\n")
+ OUTPUT (" - INPROC_HANDLER run OK\n");
+
+// ----------------------------------------------------------------------
+ // test stoping the server
+
+ OUTPUT (" - Stop the Server\n");
+ hRes = pUnkHdl->QueryInterface(IID_IOleObject, (void **)&pIOO);
+ VerifyObjRefCnt(pUnkHdl, 3);
+ VerifyRHRefCnt(pUnkHdl, 3);
+
+ TEST_FAILED_EXIT(FAILED(hRes), "QI for IOleObject on INPROC_HANDLER failed\n")
+
+ hRes = pIOO->Close(OLECLOSE_NOSAVE);
+ VerifyObjRefCnt(pUnkHdl, 3);
+ VerifyRHRefCnt(pUnkHdl, 3);
+
+ TEST_FAILED(FAILED(hRes), "IOO->Close on INPROC_HANDLER failed\n")
+ pIOO->Release();
+ pIOO = NULL;
+ VerifyObjRefCnt(pUnkHdl, 2);
+ VerifyRHRefCnt(pUnkHdl, 2);
+ OUTPUT (" - INPROC_HANDLER Close OK\n");
+
+// ----------------------------------------------------------------------
+ // query again for some unsupported interface to ensure OLE handles QI
+ // when disconnected from the server.
+
+ OUTPUT (" - QI for IDropTarget\n");
+ hRes = pUnkHdl->QueryInterface(IID_IDropTarget, (void **)&pIDT);
+ VerifyObjRefCnt(pUnkHdl, 2);
+ VerifyRHRefCnt(pUnkHdl, 2);
+ TEST_FAILED_EXIT(SUCCEEDED(hRes),
+ "QI for IDropTarget on disconnected INPROC_HANDLER worked but should have failed!\n")
+
+ // the return value from failed QI on a handler that has been disconnected
+ // must be CO_O_OBJNOTCONNECTED
+
+ TEST_FAILED_EXIT(hRes != CO_E_OBJNOTCONNECTED,
+ "QI for IDropTarget on INPROC_HANDLER did not return CO_E_OBJNOTCONNECTED!\n")
+
+ OUTPUT (" - Query for remote Interface after disconnected OK.\n");
+
+// ----------------------------------------------------------------------
+ // test restarting the server
+
+ Sleep(500);
+ OUTPUT (" - Run the Server Again\n");
+ hRes = pIRO->Run(NULL);
+ VerifyObjRefCnt(pUnkHdl, 2);
+ VerifyRHRefCnt(pUnkHdl, 2);
+
+ TEST_FAILED(FAILED(hRes), "Second IRO->Run on INPROC_HANDLER failed\n")
+ OUTPUT (" - Second INPROC_HANDLER Run OK\n");
+
+// ----------------------------------------------------------------------
+ // test stoping the server
+
+ OUTPUT (" - Stop the Server\n");
+ hRes = pUnkHdl->QueryInterface(IID_IOleObject, (void **)&pIOO);
+ VerifyObjRefCnt(pUnkHdl, 3);
+ VerifyRHRefCnt(pUnkHdl, 3);
+
+ TEST_FAILED_EXIT(FAILED(hRes), "QI for IOleObject on INPROC_HANDLER failed\n")
+
+ hRes = pIOO->Close(OLECLOSE_NOSAVE);
+ VerifyObjRefCnt(pUnkHdl, 3);
+ VerifyRHRefCnt(pUnkHdl, 3);
+
+ TEST_FAILED(FAILED(hRes), "IOO->Close on INPROC_HANDLER failed\n")
+ pIOO->Release();
+ pIOO = NULL;
+ VerifyObjRefCnt(pUnkHdl, 2);
+ VerifyRHRefCnt(pUnkHdl, 2);
+ OUTPUT (" - INPROC_HANDLER Close OK\n");
+
+// ----------------------------------------------------------------------
+ // test using weak references
+
+ OUTPUT (" - Call OleSetContainedObject TRUE\n");
+ hRes = OleSetContainedObject(pUnkHdl, 1);
+ TEST_FAILED(FAILED(hRes), "1st OleSetContainedObject on pUnkHdl failed\n")
+ OUTPUT (" - OleSetContainedObject OK\n");
+
+ Sleep(500);
+ OUTPUT (" - Run the Server Again\n");
+ hRes = pIRO->Run(NULL);
+ VerifyObjRefCnt(pUnkHdl, 2);
+ VerifyRHRefCnt(pUnkHdl, 2);
+
+ TEST_FAILED(FAILED(hRes), "Third IRO->Run on INPROC_HANDLER failed\n")
+ OUTPUT (" - Third INPROC_HANDLER Run OK\n");
+
+ // try making the references strong again
+ OUTPUT (" - Call OleSetContainedObject FALSE\n");
+ hRes = OleSetContainedObject(pUnkHdl, 0);
+ TEST_FAILED(FAILED(hRes), "2nd OleSetContainedObject on pUnkHdl failed\n")
+ OUTPUT (" - OleSetContainedObject OK\n");
+
+ // try making the references weak again
+ OUTPUT (" - Call OleSetContainedObject TRUE\n");
+ hRes = OleSetContainedObject(pUnkHdl, 1);
+ TEST_FAILED(FAILED(hRes), "3rd OleSetContainedObject on pUnkHdl failed\n")
+ OUTPUT (" - OleSetContainedObject OK\n");
+
+// ----------------------------------------------------------------------
+ // cleanup
+
+ pIRO->Release();
+ pIRO = NULL;
+ VerifyObjRefCnt(pUnkHdl, 1);
+ VerifyRHRefCnt(pUnkHdl, 1);
+
+// ----------------------------------------------------------------------
+
+ OUTPUT (" - Releasing Instance\n");
+ if (pUnkHdl)
+ {
+ cRefs = pUnkHdl->Release();
+ TEST_FAILED(cRefs != 0, "REFCNT wrong on Release\n")
+ pUnkHdl = NULL;
+ }
+ OUTPUT (" - INPROC_HANDLER case complete\n");
+
+// ----------------------------------------------------------------------
+
+Cleanup:
+
+ // release the two instances
+ OUTPUT (" - Test Complete. Doing Cleanup\n");
+
+ if (pIDT)
+ {
+ pIDT->Release();
+ }
+
+ if (pIRO)
+ {
+ pIRO->Release();
+ }
+
+ if (pIOO)
+ {
+ pIOO->Release();
+ }
+
+ if (pUnkSrv)
+ {
+ pUnkSrv->Release();
+ }
+
+ if (pUnkHdl)
+ {
+ pUnkHdl->Release();
+ }
+
+ return TestResult(RetVal, "TestHandler");
+}
+
+// ----------------------------------------------------------------------
+//
+// TestGetStandardMarshal
+//
+// test CoGetStandardMarshal API
+//
+// ----------------------------------------------------------------------
+
+BOOL TestGetStandardMarshal(void)
+{
+ BOOL RetVal = TRUE;
+ HRESULT hres;
+ ULONG ulRefCnt;
+ IMarshal *pIM = NULL, *pIM2 = NULL;
+ IStream *pStm;
+ IUnknown *punkIn = NULL;
+ IUnknown *punkOut = NULL;
+
+
+ LARGE_INTEGER large_int;
+ LISet32(large_int, 0);
+
+ OUTPUT ("Starting TestGetStandardMarshal\n");
+
+ punkIn = GetTestUnk();
+ TEST_FAILED_EXIT((punkIn == NULL), "new CTestUnk failed\n")
+ VerifyObjRefCnt(punkIn, 1);
+
+ pStm = CreateMemStm(600, NULL);
+ TEST_FAILED_EXIT((pStm == NULL), "CreateMemStm failed\n")
+ VerifyObjRefCnt((IUnknown *)pStm, 1);
+
+// ----------------------------------------------------------------------
+ hres = CoGetStandardMarshal(IID_IUnknown, punkIn, 0, NULL, MSHLFLAGS_NORMAL, &pIM);
+ TEST_FAILED_EXIT(FAILED(hres), "CoGetStandardMarshal failed\n")
+ VerifyRHRefCnt(punkIn, 1);
+
+ hres = CoGetStandardMarshal(IID_IUnknown, punkIn, 0, NULL, MSHLFLAGS_NORMAL, &pIM2);
+ TEST_FAILED_EXIT(FAILED(hres), "second CoGetStandardMarshal failed\n")
+ VerifyRHRefCnt(punkIn, 2);
+
+ TEST_FAILED((pIM != pIM2), "CoGetStandardMarshal returned two different interfaces.\n")
+ ulRefCnt = pIM2->Release();
+ TEST_FAILED_EXIT(ulRefCnt != 1, "pIM2 RefCnt is wrong");
+ pIM2 = NULL;
+
+ hres = CoGetStandardMarshal(IID_IUnknown, NULL, 0, NULL, MSHLFLAGS_NORMAL, &pIM2);
+ TEST_FAILED_EXIT(FAILED(hres), "third CoGetStandardMarshal failed\n")
+ VerifyRHRefCnt(punkIn, 1);
+
+ OUTPUT (" - CoGetStandardMarshal OK\n");
+
+// ----------------------------------------------------------------------
+ hres = pIM->MarshalInterface(pStm, IID_IUnknown, punkIn, 0, NULL, MSHLFLAGS_NORMAL);
+ TEST_FAILED_EXIT(FAILED(hres), "MarshalInterface failed\n")
+
+ hres = pStm->Seek(large_int, STREAM_SEEK_SET, NULL);
+ TEST_FAILED_EXIT(FAILED(hres), "Seek on shared stream failed\n")
+
+ // since we are unmarshalling in the same process, the RH should go away.
+ hres = pIM->UnmarshalInterface(pStm, IID_IUnknown, (LPVOID FAR*)&punkOut);
+ TEST_FAILED_EXIT(FAILED(hres), "UnmarshalInterface failed\n")
+ VerifyRHRefCnt(punkIn, 1);
+
+ // make sure the interface pointers are identical
+ if (punkIn != punkOut)
+ TEST_FAILED_EXIT(TRUE, "Interface ptrs dont match...1st Local Unmarshal\n")
+ OUTPUT (" - UnmarshalInterface OK\n");
+
+ // release interface and make sure it does not go away - refcnt > 0
+ ulRefCnt = punkOut->Release();
+ TEST_FAILED_EXIT(ulRefCnt == 0, "punkOut RefCnt is zero");
+ punkOut = NULL;
+ OUTPUT (" - Release OK\n");
+
+
+// ----------------------------------------------------------------------
+ hres = pStm->Seek(large_int, STREAM_SEEK_SET, NULL);
+ TEST_FAILED_EXIT(FAILED(hres), "Seek on shared stream failed\n")
+
+ hres = pIM->MarshalInterface(pStm, IID_IUnknown, punkIn, 0, NULL, MSHLFLAGS_NORMAL);
+ TEST_FAILED_EXIT(FAILED(hres), "MarshalInterface failed\n")
+
+ hres = pStm->Seek(large_int, STREAM_SEEK_SET, NULL);
+ TEST_FAILED_EXIT(FAILED(hres), "Seek on shared stream failed\n")
+
+ // since we are unmarshalling in the same process, the RH should go away.
+ hres = pIM2->UnmarshalInterface(pStm, IID_IUnknown, (LPVOID FAR*)&punkOut);
+ TEST_FAILED_EXIT(FAILED(hres), "UnmarshalInterface failed\n")
+ VerifyRHRefCnt(punkIn, 1);
+
+ // make sure the interface pointers are identical
+ if (punkIn != punkOut)
+ TEST_FAILED_EXIT(TRUE, "Interface ptrs dont match...1st Local Unmarshal\n")
+ OUTPUT (" - Second UnmarshalInterface OK\n");
+
+ // release interface and make sure it does not go away - refcnt > 0
+ ulRefCnt = punkOut->Release();
+ TEST_FAILED_EXIT(ulRefCnt == 0, "punkOut RefCnt is zero");
+ punkOut = NULL;
+ OUTPUT (" - Release OK\n");
+
+ ulRefCnt = pIM2->Release();
+ TEST_FAILED_EXIT(ulRefCnt == 0, "pIM2 RefCnt is zero");
+ pIM2 = NULL;
+ OUTPUT (" - Release OK\n");
+
+// ----------------------------------------------------------------------
+
+ // release the marshalled data
+ hres = pStm->Seek(large_int, STREAM_SEEK_SET, NULL);
+ TEST_FAILED_EXIT(FAILED(hres), "Seek on shared stream failed\n")
+
+ hres = pIM->MarshalInterface(pStm, IID_IUnknown, punkIn, 0, NULL, MSHLFLAGS_NORMAL);
+ TEST_FAILED_EXIT(FAILED(hres), "MarshalInterface failed\n")
+
+ hres = pStm->Seek(large_int, STREAM_SEEK_SET, NULL);
+ TEST_FAILED_EXIT(FAILED(hres), "Seek on shared stream failed\n")
+
+ hres = pIM->ReleaseMarshalData(pStm);
+ TEST_FAILED_EXIT(FAILED(hres), "Release Marshal Data failed\n.");
+ OUTPUT (" - ReleaseMarshalData OK\n");
+
+
+ // the RH should go away, and we should have only the original
+ // refcnt from creation left on the object.
+ ulRefCnt = pIM->Release();
+ TEST_FAILED_EXIT(ulRefCnt != 0, "pIM RefCnt not zero");
+ pIM = NULL;
+
+ // release the original object
+ ulRefCnt = punkIn->Release();
+ TEST_FAILED_EXIT(ulRefCnt != 0, "punkIn RefCnt not zero");
+ punkIn = NULL;
+
+// ----------------------------------------------------------------------
+
+Cleanup:
+
+ OUTPUT (" - Test Complete. Doing Cleanup\n");
+
+ // Dump interfaces we are done with
+ if (pStm)
+ {
+ ulRefCnt = pStm->Release();
+ TEST_FAILED(ulRefCnt != 0, "Stream RefCnt not zero\n");
+ }
+
+ if (punkOut)
+ {
+ ulRefCnt = punkOut->Release();
+ TEST_FAILED(ulRefCnt != 0, "punkOut RefCnt not zero\n");
+ }
+
+ if (punkIn)
+ {
+ ulRefCnt = punkIn->Release();
+ TEST_FAILED(ulRefCnt != 0, "punkIn RefCnt not zero\n");
+ }
+
+ return TestResult(RetVal, "TestGetStandardMarshal");
+}
+
+
+
+// ----------------------------------------------------------------------
+//
+// TestLockObjectExternal
+//
+// test CoLockObjectExternal API
+//
+// ----------------------------------------------------------------------
+
+BOOL TestLockObjectExternal(void)
+{
+ BOOL RetVal = TRUE;
+ HRESULT hres;
+ ULONG ulRefCnt;
+ IUnknown *punkIn = NULL;
+ IStream *pStm = NULL;
+
+ OUTPUT ("Starting TestLockObjectExternal\n");
+
+ punkIn = GetTestUnk();
+ TEST_FAILED_EXIT((punkIn == NULL), "new CTestUnk failed\n")
+ VerifyObjRefCnt(punkIn, 1);
+
+
+// ----------------------------------------------------------------------
+ // test calling it once, then releasing it once
+
+ hres = CoLockObjectExternal(punkIn, TRUE, FALSE);
+ TEST_FAILED_EXIT(FAILED(hres), "CoLockObjectExternal failed.\n")
+ VerifyRHRefCnt(punkIn, 1);
+ VerifyObjRefCnt(punkIn, 2);
+ OUTPUT (" - CoLockObjectExternal TRUE OK\n");
+
+ hres = CoLockObjectExternal(punkIn, FALSE, FALSE);
+ TEST_FAILED_EXIT(FAILED(hres), "second CoLockObjectExternal failed\n")
+ VerifyRHRefCnt(punkIn, 0);
+ VerifyObjRefCnt(punkIn, 1);
+ OUTPUT (" - CoLockObjectExternal FALSE OK\n");
+
+// ----------------------------------------------------------------------
+ // test calling it twice, then releasing it twice
+
+ // the first AddRef inc's the StrongCnt, the RH, and the real object.
+ hres = CoLockObjectExternal(punkIn, TRUE, FALSE);
+ TEST_FAILED_EXIT(FAILED(hres), "CoLockObjectExternal failed.\n")
+ VerifyRHRefCnt(punkIn, 1);
+ VerifyObjRefCnt(punkIn, 2);
+ OUTPUT (" - CoLockObjectExternal TRUE OK\n");
+
+ // the second AddRef inc's the StrongCnt and the RH, but not the
+ // real object.
+ hres = CoLockObjectExternal(punkIn, TRUE, FALSE);
+ TEST_FAILED_EXIT(FAILED(hres), "CoLockObjectExternal failed.\n")
+ VerifyRHRefCnt(punkIn, 2);
+ VerifyObjRefCnt(punkIn, 2);
+ OUTPUT (" - CoLockObjectExternal TRUE OK\n");
+
+ // the second release Dec's the StrongCnt and the RH, but not the
+ // real object.
+ hres = CoLockObjectExternal(punkIn, FALSE, FALSE);
+ TEST_FAILED_EXIT(FAILED(hres), "second CoLockObjectExternal failed\n")
+ VerifyRHRefCnt(punkIn, 1);
+ VerifyObjRefCnt(punkIn, 2);
+ OUTPUT (" - CoLockObjectExternal FALSE OK\n");
+
+ // the last Release dec's the StrongCnt, the RH, and the real object.
+ hres = CoLockObjectExternal(punkIn, FALSE, FALSE);
+ TEST_FAILED_EXIT(FAILED(hres), "second CoLockObjectExternal failed\n")
+ VerifyRHRefCnt(punkIn, 0);
+ VerifyObjRefCnt(punkIn, 1);
+ OUTPUT (" - CoLockObjectExternal FALSE OK\n");
+
+// ----------------------------------------------------------------------
+ // test calling it once, then releasing the punkIn and ensuring
+ // the object is still alive.
+
+ hres = CoLockObjectExternal(punkIn, TRUE, FALSE);
+ TEST_FAILED_EXIT(FAILED(hres), "CoLockObjectExternal failed.\n")
+ VerifyRHRefCnt(punkIn, 1);
+ VerifyObjRefCnt(punkIn, 2);
+ OUTPUT (" - CoLockObjectExternal TRUE OK\n");
+
+ ulRefCnt = punkIn->Release();
+ TEST_FAILED(ulRefCnt != 1, "Release returned incorrect value.\n");
+ VerifyRHRefCnt(punkIn, 1);
+ OUTPUT (" - punkIn->Release OK\n");
+
+ hres = CoLockObjectExternal(punkIn, FALSE, FALSE);
+ TEST_FAILED_EXIT(FAILED(hres), "second CoLockObjectExternal failed\n")
+ punkIn = NULL;
+ OUTPUT (" - CoLockObjectExternal FALSE OK\n");
+
+// ----------------------------------------------------------------------
+ // test calling marshal interface, followed by CLOE(F,T). This
+ // should disconnect the object. This is bizarre backward compatibility
+ // semantics that some LOTUS apps do rely on.
+
+ punkIn = GetTestUnk();
+ TEST_FAILED_EXIT((punkIn == NULL), "new CTestUnk failed\n")
+ VerifyObjRefCnt(punkIn, 1);
+
+ pStm = CreateMemStm(600, NULL);
+ TEST_FAILED_EXIT((pStm == NULL), "CreateMemStm failed\n")
+ VerifyObjRefCnt((IUnknown *)pStm, 1);
+
+ hres = CoMarshalInterface(pStm, IID_IUnknown, punkIn, 0, NULL,
+ MSHLFLAGS_TABLESTRONG);
+ TEST_FAILED_EXIT(FAILED(hres), "CoMarshalInterface failed\n")
+ VerifyRHRefCnt(punkIn, 1);
+ OUTPUT (" - CoMarshalInterface TABLE_STRONG OK\n");
+
+ hres = CoLockObjectExternal(punkIn, FALSE, TRUE);
+ TEST_FAILED_EXIT(FAILED(hres), "CoLockObjectExternal(F,T) failed\n")
+ VerifyObjRefCnt(punkIn, 1);
+ VerifyRHRefCnt(punkIn, 0);
+ OUTPUT (" - CoLockObjectExternal FALSE TRUE OK\n");
+
+
+ hres = CoMarshalInterface(pStm, IID_IUnknown, punkIn, 0, NULL,
+ MSHLFLAGS_NORMAL);
+ TEST_FAILED_EXIT(FAILED(hres), "CoMarshalInterface failed\n")
+ VerifyRHRefCnt(punkIn, 1);
+ OUTPUT (" - CoMarshalInterface NORMAL OK\n");
+
+ hres = CoLockObjectExternal(punkIn, FALSE, TRUE);
+ TEST_FAILED_EXIT(FAILED(hres), "CoLockObjectExternal(F,T) failed\n")
+ VerifyObjRefCnt(punkIn, 1);
+ VerifyRHRefCnt(punkIn, 0);
+ OUTPUT (" - CoLockObjectExternal FALSE TRUE OK\n");
+
+
+ hres = CoMarshalInterface(pStm, IID_IUnknown, punkIn, 0, NULL,
+ MSHLFLAGS_TABLEWEAK);
+ TEST_FAILED_EXIT(FAILED(hres), "CoMarshalInterface failed\n")
+ VerifyRHRefCnt(punkIn, 1);
+ OUTPUT (" - CoMarshalInterface TABLEWEAK OK\n");
+
+ // BUGBUG: refcnts seem to be wrong on the following call:
+
+ hres = CoLockObjectExternal(punkIn, FALSE, TRUE);
+ TEST_FAILED_EXIT(FAILED(hres), "CoLockObjectExternal(F,T) failed\n")
+ VerifyObjRefCnt(punkIn, 1);
+ VerifyRHRefCnt(punkIn, 0);
+ OUTPUT (" - CoLockObjectExternal FALSE TRUE OK\n");
+
+ punkIn->Release();
+ punkIn = NULL;
+
+Cleanup:
+
+ OUTPUT (" - Test Complete. Doing Cleanup\n");
+
+ // Dump interfaces we are done with
+ if (punkIn)
+ {
+ ulRefCnt = punkIn->Release();
+ TEST_FAILED(ulRefCnt != 0, "punkIn RefCnt not zero\n");
+ }
+
+ if (pStm)
+ {
+ pStm->Release();
+ }
+
+ return TestResult(RetVal, "TestLockObjectExternal");
+}
+
+
+// ----------------------------------------------------------------------
+//
+// TestReleaseMarshalData
+//
+// test CoReleaseMarshalData API
+//
+// ----------------------------------------------------------------------
+
+BOOL TestReleaseMarshalData(void)
+{
+ BOOL RetVal = TRUE;
+ HRESULT hres;
+ ULONG cRefs;
+ IUnknown *punkIn = NULL;
+ IStream *pStm = NULL;
+ LARGE_INTEGER large_int;
+
+
+ OUTPUT ("Starting TestReleaseMarshalData\n");
+
+ punkIn = GetTestUnk();
+ TEST_FAILED_EXIT((punkIn == NULL), "new CTestUnk failed\n")
+ VerifyObjRefCnt(punkIn, 1);
+
+ // Create a shared memory stream for the marshaled object
+ pStm = CreateMemStm(600, NULL);
+ TEST_FAILED_EXIT((pStm == NULL), "CreateMemStm failed\n")
+
+// ----------------------------------------------------------------------
+
+ // try RMD on NORMAL marshal
+
+ hres = CoMarshalInterface(pStm, IID_IUnknown, punkIn, 0, NULL, MSHLFLAGS_NORMAL);
+ TEST_FAILED_EXIT(FAILED(hres), "CoMarshalInterface failed.\n")
+ VerifyRHRefCnt(punkIn, 1);
+ VerifyObjRefCnt(punkIn, 2);
+ OUTPUT (" - MarshalInterface NORMAL OK\n");
+
+ LISet32(large_int, 0);
+ hres = pStm->Seek(large_int, STREAM_SEEK_SET, NULL);
+ TEST_FAILED_EXIT(FAILED(hres), "Seek on shared stream failed\n")
+
+ hres = CoReleaseMarshalData(pStm);
+ TEST_FAILED_EXIT(FAILED(hres), "CoReleaseMarshalData failed.\n")
+ VerifyRHRefCnt(punkIn, 0);
+ VerifyObjRefCnt(punkIn, 1);
+ OUTPUT (" - CoReleaseMarshalData NORMAL OK\n");
+
+
+ // try RMD on TABLESTRONG marshal
+
+ LISet32(large_int, 0);
+ hres = pStm->Seek(large_int, STREAM_SEEK_SET, NULL);
+ TEST_FAILED_EXIT(FAILED(hres), "Seek on shared stream failed\n")
+
+ hres = CoMarshalInterface(pStm, IID_IUnknown, punkIn, 0, NULL, MSHLFLAGS_TABLESTRONG);
+ TEST_FAILED_EXIT(FAILED(hres), "CoMarshalInterface failed.\n")
+ VerifyRHRefCnt(punkIn, 1);
+ VerifyObjRefCnt(punkIn, 2);
+ OUTPUT (" - MarshalInterface TABLESTRONG OK\n");
+
+ LISet32(large_int, 0);
+ hres = pStm->Seek(large_int, STREAM_SEEK_SET, NULL);
+ TEST_FAILED_EXIT(FAILED(hres), "Seek on shared stream failed\n")
+
+ hres = CoReleaseMarshalData(pStm);
+ TEST_FAILED_EXIT(FAILED(hres), "CoReleaseMarshalData failed.\n")
+ VerifyRHRefCnt(punkIn, 0);
+ VerifyObjRefCnt(punkIn, 1);
+ OUTPUT (" - CoReleaseMarshalData TABLESTRONG OK\n");
+
+ // try RMD on TABLEWEAK marshal
+
+
+ LISet32(large_int, 0);
+ hres = pStm->Seek(large_int, STREAM_SEEK_SET, NULL);
+ TEST_FAILED_EXIT(FAILED(hres), "Seek on shared stream failed\n")
+
+ hres = CoMarshalInterface(pStm, IID_IUnknown, punkIn, 0, NULL, MSHLFLAGS_TABLEWEAK);
+ TEST_FAILED_EXIT(FAILED(hres), "CoMarshalInterface failed.\n")
+ VerifyRHRefCnt(punkIn, 1);
+ VerifyObjRefCnt(punkIn, 2);
+ OUTPUT (" - MarshalInterface TABLEWEAK OK\n");
+
+ LISet32(large_int, 0);
+ hres = pStm->Seek(large_int, STREAM_SEEK_SET, NULL);
+ TEST_FAILED_EXIT(FAILED(hres), "Seek on shared stream failed\n")
+
+ hres = CoReleaseMarshalData(pStm);
+ TEST_FAILED_EXIT(FAILED(hres), "CoReleaseMarshalData failed.\n")
+ VerifyRHRefCnt(punkIn, 0);
+ VerifyObjRefCnt(punkIn, 1);
+ OUTPUT (" - CoReleaseMarshalData TABLEWEAK OK\n");
+
+// ----------------------------------------------------------------------
+
+Cleanup:
+
+ OUTPUT (" - Test Complete. Doing Cleanup\n");
+
+ // Dump interfaces we are done with
+ if (punkIn)
+ {
+ cRefs = punkIn->Release();
+ TEST_FAILED(cRefs != 0, "punkIn RefCnt not zero\n");
+ }
+
+ if (pStm)
+ {
+ pStm->Release();
+ }
+
+ return TestResult(RetVal, "TestReleaseMarshalData");
+}
+
+
+
+// ----------------------------------------------------------------------
+//
+// TestDisconnectObject
+//
+// test CoDisconnectObject API
+//
+// ----------------------------------------------------------------------
+
+BOOL TestDisconnectObject(void)
+{
+ BOOL RetVal = TRUE;
+ HRESULT hres;
+ ULONG ulRefCnt;
+ IUnknown *punkIn = NULL;
+ IStream *pStm = NULL;
+ LARGE_INTEGER large_int;
+
+
+ OUTPUT ("Starting TestDisconnectObject\n");
+
+ punkIn = GetTestUnk();
+ TEST_FAILED_EXIT((punkIn == NULL), "new CTestUnk failed\n")
+ VerifyObjRefCnt(punkIn, 1);
+
+ // Create a shared memory stream for the marshaled object
+ pStm = CreateMemStm(600, NULL);
+ TEST_FAILED_EXIT((pStm == NULL), "CreateMemStm failed\n")
+
+// ----------------------------------------------------------------------
+ // test calling it without having ever marshalled it.
+
+ hres = CoDisconnectObject(punkIn, 0);
+ TEST_FAILED_EXIT(FAILED(hres), "CoDisconnectObject succeeded but should have failed.\n")
+ VerifyRHRefCnt(punkIn, 0);
+ VerifyObjRefCnt(punkIn, 1);
+
+ OUTPUT (" - first CoDisconnectObject OK\n");
+
+
+ // test calling after having marshalled it.
+
+ hres = CoMarshalInterface(pStm, IID_IUnknown, punkIn, 0, NULL, MSHLFLAGS_TABLEWEAK);
+ TEST_FAILED_EXIT(FAILED(hres), "CoMarshalInterface failed.\n")
+ VerifyRHRefCnt(punkIn, 1);
+ VerifyObjRefCnt(punkIn, 2);
+
+ OUTPUT (" - CoMarshalInterface OK\n");
+
+ hres = CoDisconnectObject(punkIn, 0);
+ TEST_FAILED_EXIT(FAILED(hres), "second CoDisconnectObject failed\n")
+ VerifyRHRefCnt(punkIn, 0);
+ VerifyObjRefCnt(punkIn, 1);
+
+ OUTPUT (" - second CoDisconnectObject OK\n");
+
+ // now release the marshalled data
+
+ LISet32(large_int, 0);
+ hres = pStm->Seek(large_int, STREAM_SEEK_SET, NULL);
+ TEST_FAILED_EXIT(FAILED(hres), "Seek on shared stream failed\n")
+
+ hres = CoReleaseMarshalData(pStm);
+ TEST_FAILED_EXIT(FAILED(hres), "CoReleaseMarshalData failed.\n")
+ VerifyRHRefCnt(punkIn, 0);
+ VerifyObjRefCnt(punkIn, 1);
+
+ OUTPUT (" - CoReleaseMarshalData OK\n");
+
+// ----------------------------------------------------------------------
+
+Cleanup:
+
+ OUTPUT (" - Test Complete. Doing Cleanup\n");
+
+ // Dump interfaces we are done with
+ if (punkIn)
+ {
+ ulRefCnt = punkIn->Release();
+ TEST_FAILED(ulRefCnt != 0, "punkIn RefCnt not zero\n");
+ }
+
+ if (pStm)
+ {
+ pStm->Release();
+ }
+
+ return TestResult(RetVal, "TestDisconnectObject");
+}
+
+// ----------------------------------------------------------------------
+//
+// TestOXIDs
+//
+// tests A calling B calling A calling B etc n times, to see if Rpc
+// can handle this.
+//
+// ----------------------------------------------------------------------
+BOOL TestExpiredOXIDs(void)
+{
+ BOOL RetVal = TRUE;
+ HRESULT hRes = S_OK;
+ ILoop *pLocalLoop = NULL;
+ IClassFactory *pUnk = NULL;
+
+ OUTPUT ("Starting TestExpiredOXIDs\n");
+
+ // start the local server process manually so it stays alive for the
+ // duration of the test (even though we dont have an OXIDEntry for it.
+
+ STARTUPINFO startupInfo;
+ PROCESS_INFORMATION processInfo;
+ memset(&processInfo, 0, sizeof(processInfo));
+ memset(&startupInfo, 0, sizeof(startupInfo));
+
+ RetVal = CreateProcess(TEXT("ballsrv.exe"),
+ NULL, // command line
+ NULL, // security for process
+ NULL, // security for thread
+ FALSE, // inherit handles
+ NORMAL_PRIORITY_CLASS,
+ NULL, // environment block
+ NULL, // current directory
+ &startupInfo,
+ &processInfo);
+
+ if (RetVal == FALSE)
+ {
+ hRes = GetLastError();
+ OUTPUT (" - CreateProcess Failed\n");
+ }
+ else
+ {
+ // give the process time to register its class object
+ Sleep(2000);
+ }
+
+ for (ULONG i=0; i<7; i++)
+ {
+ // create a new instance of a local server that is already running,
+ // causing us to reuse the same OXID.
+
+ hRes = CoGetClassObject(CLSID_Balls,
+ CLSCTX_LOCAL_SERVER,
+ NULL, // pvReserved
+ IID_IClassFactory,
+ (void **)&pUnk);
+
+ TEST_FAILED_EXIT(FAILED(hRes), "CoGetClassObject ballsrv failed\n")
+
+ // release interface (lets OXIDEntry be placed on the expired list)
+ pUnk->Release();
+ pUnk = NULL;
+
+ for (ULONG j=0; j<i; j++)
+ {
+ // create (i) new instances of another class and release them
+ // right away. This causes (i) new processes to start and (i)
+ // entries of the OXID table expired list to get flushed.
+
+ hRes = CoCreateInstance(CLSID_LoopSrv, NULL, CLSCTX_LOCAL_SERVER,
+ IID_ILoop, (void **)&pLocalLoop);
+ TEST_FAILED_EXIT(FAILED(hRes), "CoCreateInstance First failed\n")
+ pLocalLoop->Release();
+ pLocalLoop = NULL;
+ }
+ }
+
+Cleanup:
+
+ // release the two instances
+ OUTPUT (" - Releasing Instances\n");
+
+ if (pUnk)
+ pUnk->Release();
+
+ if (pLocalLoop)
+ pLocalLoop->Release();
+
+ // kill the server process
+ if (processInfo.hProcess != 0)
+ {
+ BOOL fKill = TerminateProcess(processInfo.hProcess, 0);
+ if (!fKill)
+ {
+ hRes = GetLastError();
+ OUTPUT (" - TermintateProcess Failed\n");
+ }
+
+ CloseHandle(processInfo.hThread);
+ CloseHandle(processInfo.hProcess);
+ }
+
+ return TestResult(RetVal, "TestExpiredOXIDs");
+}
+
+
+
+
+// ----------------------------------------------------------------------
+//
+// TestAggregate
+//
+// tests creating an RH that is aggregated.
+//
+// ----------------------------------------------------------------------
+
+BOOL TestAggregate(void)
+{
+ BOOL RetVal = TRUE;
+ HRESULT hRes = S_OK;
+ IUnknown *punkOuter = NULL;
+ IUnknown *pUnk = NULL;
+ IBalls *pIBall = NULL;
+ ULONG ulRefCnt = 0;
+
+ OUTPUT ("Starting TestAggregate\n");
+
+ punkOuter = GetTestUnk();
+ TEST_FAILED_EXIT((punkOuter == NULL), "new CTestUnk failed\n")
+ VerifyObjRefCnt(punkOuter, 1);
+
+ // create our interface to pass to the remote object.
+ hRes = CoCreateInstance(CLSID_Balls, punkOuter, CLSCTX_LOCAL_SERVER,
+ IID_IUnknown, (void **)&pUnk);
+ TEST_FAILED_EXIT(FAILED(hRes), "CoCreateInstance First failed\n")
+
+ // now release the object
+ ulRefCnt = pUnk->Release();
+ TEST_FAILED_EXIT(ulRefCnt != 0, "Release failed\n")
+
+// ----------------------------------------------------------------------
+
+ // create our interface to pass to the remote object.
+ hRes = CoCreateInstance(CLSID_Balls, punkOuter, CLSCTX_LOCAL_SERVER,
+ IID_IUnknown, (void **)&pUnk);
+ TEST_FAILED_EXIT(FAILED(hRes), "CoCreateInstance First failed\n")
+
+ hRes = pUnk->QueryInterface(IID_IBalls, (void **)&pIBall);
+ TEST_FAILED_EXIT(FAILED(hRes), "QueryInterface failed\n")
+
+ // now release the interface
+ ulRefCnt = pIBall->Release();
+ TEST_FAILED_EXIT(ulRefCnt == 0, "Release failed\n")
+
+ // now release the object
+ ulRefCnt = pUnk->Release();
+ TEST_FAILED_EXIT(ulRefCnt != 0, "Release failed\n")
+
+ // now release the punkOuter
+ ulRefCnt = punkOuter->Release();
+ TEST_FAILED_EXIT(ulRefCnt != 0, "Release failed\n")
+
+Cleanup:
+
+ OUTPUT (" - Test Complete. Doing Cleanup\n");
+
+ return TestResult(RetVal, "TestAggregate");
+}
+
+
+
+// ----------------------------------------------------------------------
+//
+// TestCreateRemoteHandler
+//
+// test CoCreateRemoteHandler API and unmarshalling data into it.
+//
+// ----------------------------------------------------------------------
+
+BOOL TestCreateRemoteHandler(void)
+{
+ BOOL RetVal = TRUE;
+ HRESULT hres;
+ ULONG ulRefCnt;
+ IUnknown *punkBall = NULL;
+ IUnknown *punkOuter = NULL;
+ IClassFactory *pICF = NULL;
+
+
+ OUTPUT ("Starting TestCreateRemoteHandler\n");
+
+
+ // create the controlling unknown for the remote object.
+ punkOuter = GetTestUnk();
+
+// ----------------------------------------------------------------------
+
+ // create a remote object that we will aggregate.
+
+ // Create an IBall ClassFactory Interface.
+ DWORD grfContext=CLSCTX_LOCAL_SERVER; // handler/server/local server
+ hres = CoGetClassObject(CLSID_Balls,
+ grfContext,
+ NULL, // pvReserved
+ IID_IClassFactory,
+ (void **)&pICF);
+
+ TEST_FAILED_EXIT(FAILED(hres), "CoGetClassObject Balls failed\n")
+ TEST_FAILED_EXIT((pICF == NULL), "CoGetClassObject Balls failed\n")
+ OUTPUT (" - Aquired Remote Balls Class Object.\n");
+ VerifyObjRefCnt(pICF, 1);
+ VerifyRHRefCnt(pICF, 1);
+
+// ----------------------------------------------------------------------
+
+ // note, since pICF is a class object, it has special super secret
+ // behaviour to make it go away. create an instance, release the
+ // class object, then release the instance.
+
+ hres = pICF->CreateInstance(punkOuter, IID_IUnknown, (void **)&punkBall);
+ TEST_FAILED_EXIT(FAILED(hres), "CreateInstance failed\n")
+ TEST_FAILED_EXIT((punkBall == NULL), "CreateInstance failed\n")
+ OUTPUT (" - Created Balls Instance.\n");
+
+ VerifyObjRefCnt(punkBall, 1);
+ VerifyRHRefCnt(punkBall, 1);
+
+// ----------------------------------------------------------------------
+
+ // release class object
+ ulRefCnt = pICF->Release();
+ TEST_FAILED(ulRefCnt != 0, "pICF RefCnt not zero\n");
+ pICF = NULL;
+ OUTPUT (" - Released Balls Class Object.\n");
+
+ // release the remote object handler
+ ulRefCnt = punkBall->Release();
+ TEST_FAILED_EXIT(ulRefCnt != 0, "punkBall RefCnt not zero");
+ punkBall = NULL;
+
+ // release the outer
+ ulRefCnt = punkOuter->Release();
+ TEST_FAILED_EXIT(ulRefCnt != 0, "punkOuter RefCnt not zero");
+ punkOuter = NULL;
+
+// ----------------------------------------------------------------------
+
+Cleanup:
+
+ OUTPUT (" - Test Complete. Doing Cleanup\n");
+
+ if (punkBall)
+ {
+ ulRefCnt = punkBall->Release();
+ TEST_FAILED(ulRefCnt != 0, "punkBall RefCnt not zero\n");
+ }
+
+ if (punkOuter)
+ {
+ ulRefCnt = punkOuter->Release();
+ TEST_FAILED(ulRefCnt != 0, "punkOuter RefCnt not zero\n");
+ }
+
+ return TestResult(RetVal, "TestCreateRemoteHandler");
+}
+
+
+// ----------------------------------------------------------------------
+//
+// TestTIDAndLID
+//
+// test the values of TID and MID to ensure they are correct across
+// calls.
+//
+// ----------------------------------------------------------------------
+HRESULT TIDAndLIDSubroutine();
+DWORD _stdcall TIDAndLIDServer(void *param);
+
+
+BOOL TestTIDAndLID(void)
+{
+ BOOL RetVal = TRUE;
+ HRESULT hRes;
+
+ // First, try it across process boundaries.
+ hRes = TIDAndLIDSubroutine();
+ TEST_FAILED(FAILED(hRes), "TIDAndLID different process failed\n")
+
+
+ // Next, try it across thread boundaries.
+ // Spin a thread to be the server of the TIDAndLID
+
+ HANDLE hEvent[2];
+ hEvent[0]= CreateEvent(NULL, FALSE, FALSE, NULL);
+ hEvent[1]= CreateEvent(NULL, FALSE, FALSE, NULL);
+
+ DWORD dwThrdId = 0;
+ HANDLE hThrd = CreateThread(NULL, 0,
+ TIDAndLIDServer,
+ &hEvent[0], 0, &dwThrdId);
+ if (hThrd)
+ {
+ // wait for thread to register its class object
+ WaitForSingleObject(hEvent[0], 0xffffffff);
+ Sleep(0);
+
+ // Now run the whole test again. This time CoGetClassObject should
+ // find the server running in the other thread.
+
+ hRes = TIDAndLIDSubroutine();
+ TEST_FAILED(FAILED(hRes), "TIDAndLID different process failed\n")
+
+ // signal the other thread to exit
+ CloseHandle(hThrd);
+ PostThreadMessage(dwThrdId, WM_QUIT, 0, 0);
+
+ // wait for other thread to call CoUninitialize
+ WaitForSingleObject(hEvent[1], 0xffffffff);
+ CloseHandle(hEvent[0]);
+ CloseHandle(hEvent[1]);
+ }
+ else
+ {
+ hRes = GetLastError();
+ TEST_FAILED(hRes, "CreateThread failed\n")
+ }
+
+ return TestResult(RetVal, "TestTIDAndLID");
+}
+
+HRESULT TIDAndLIDSubroutine()
+{
+ BOOL RetVal = TRUE;
+ ULONG ulRefCnt;
+ ICube *pCube = NULL;
+ IUnknown *pUnk = NULL;
+ HRESULT hRes;
+
+ // create our interface to pass to the remote object.
+ OUTPUT (" - Create Instance of ICube\n");
+ hRes = CoCreateInstance(CLSID_Cubes, NULL, CLSCTX_LOCAL_SERVER,
+ IID_ICube, (void **)&pCube);
+ TEST_FAILED_EXIT(FAILED(hRes), "CoCreateInstance CLSID_Cubes failed\n")
+ OUTPUT (" - Instance of ICubes created OK\n");
+
+ pUnk = GetTestUnk();
+
+ hRes = pCube->PrepForInputSyncCall(pUnk);
+ TEST_FAILED(FAILED(hRes), "pCube->PreForInputSyncCall failed\n")
+
+ hRes = pCube->InputSyncCall();
+ if (gInitFlag == COINIT_APARTMENTTHREADED)
+ {
+ TEST_FAILED(FAILED(hRes), "pCube->InputSyncCall failed\n")
+ }
+ else
+ {
+ TEST_FAILED(SUCCEEDED(hRes), "pCube->InputSyncCall should have failed\n")
+ }
+ OUTPUT (" - Completed Release inside InputSync call\n");
+
+
+ OUTPUT (" - Get the current LID information\n");
+ UUID lidCaller;
+ CoGetCurrentLogicalThreadId(&lidCaller);
+
+ OUTPUT (" - call on ICube interface\n");
+ hRes = pCube->SimpleCall(GetCurrentProcessId(),
+ GetCurrentThreadId(),
+ lidCaller);
+
+ TEST_FAILED(FAILED(hRes), "pCube->SimpleCall failed\n")
+
+ // release the interface
+ OUTPUT (" - Release the ICube interface\n");
+ ulRefCnt = pCube->Release();
+ TEST_FAILED(ulRefCnt != 0, "pCube RefCnt not zero\n");
+ pCube = NULL;
+
+Cleanup:
+
+ OUTPUT (" - Subroutine Complete. Doing Cleanup\n");
+
+ if (pCube != NULL)
+ {
+ pCube->Release();
+ pCube = NULL;
+ }
+
+ return hRes;
+}
+
+// current COINIT flag used on main thread
+extern DWORD gInitFlag;
+
+DWORD _stdcall TIDAndLIDServer(void *param)
+{
+ BOOL RetVal = TRUE;
+
+ HANDLE *pHandle = (HANDLE *) param;
+
+ HANDLE hEvent[2];
+ hEvent[0] = *pHandle;
+ hEvent[1] = *(pHandle+1);
+
+ OUTPUT (" - TIDAndLIDServer Start\n");
+
+ HRESULT hRes = CoInitializeEx(NULL, gInitFlag);
+ TEST_FAILED(FAILED(hRes), "TIDAndLIDServer CoInitialize failed\n")
+
+ if (SUCCEEDED(hRes))
+ {
+ DWORD dwReg;
+ IClassFactory *pICF = new CTestUnkCF();
+
+ if (pICF)
+ {
+ hRes = CoRegisterClassObject(CLSID_Cubes, pICF,
+ CLSCTX_LOCAL_SERVER,
+ REGCLS_MULTIPLEUSE, &dwReg);
+
+ TEST_FAILED(FAILED(hRes), "TIDAndLID CoRegisterClassObject failed\n")
+ SetEvent(hEvent[0]);
+
+ if (SUCCEEDED(hRes))
+ {
+ MSG msg;
+ while (GetMessage(&msg, NULL, 0, 0))
+ {
+ DispatchMessage(&msg);
+ }
+
+ hRes = CoRevokeClassObject(dwReg);
+ TEST_FAILED(FAILED(hRes), "TIDAndLID CoRevokeClassObject failed\n")
+ }
+ }
+ else
+ {
+ // set the event anyway
+ TEST_FAILED(TRUE, "TIDAndLID new CTestUnkCF failed\n")
+ SetEvent(hEvent[0]);
+ }
+
+ CoUninitialize();
+ }
+ else
+ {
+ // wake the other guy anyway
+ SetEvent(hEvent[0]);
+ }
+
+ // signal we've called CoUninitialize
+ SetEvent(hEvent[1]);
+
+ OUTPUT (" - TIDAndLIDServer done\n");
+ return hRes;
+}
+
+
+// ----------------------------------------------------------------------
+//
+// TestNonNDRProxy
+//
+// test using a non-NDR proxy and stub for ICube interface.
+//
+// ----------------------------------------------------------------------
+BOOL TestNonNDRProxy(void)
+{
+ BOOL RetVal = TRUE;
+ HRESULT hRes;
+ ULONG ulRefCnt;
+ ICube *pCube = NULL;
+
+
+ OUTPUT ("Starting TestNonNDR\n");
+
+ // stomp on the registry to use our custom proxy dll for ICube interface
+ BYTE szValueSave[MAX_PATH];
+ DWORD cbValue = sizeof(szValueSave);
+ DWORD dwType;
+
+ LONG lRes = RegQueryValueEx(HKEY_CLASSES_ROOT,
+ TEXT("Interface\\{00000139-0001-0008-C000-000000000046}\\ProxyStubClsid32"),
+ NULL,
+ &dwType,
+ szValueSave,
+ &cbValue);
+
+ if (lRes == ERROR_SUCCESS)
+ {
+ BYTE szValueNew[40];
+ strcpy((char *)&szValueNew[0], "{0000013e-0001-0008-C000-000000000046}");
+
+ lRes = RegSetValueEx(HKEY_CLASSES_ROOT,
+ TEXT("Interface\\{00000139-0001-0008-C000-000000000046}\\ProxyStubClsid32"),
+ NULL,
+ dwType,
+ szValueNew,
+ sizeof(szValueNew));
+ }
+
+ // create our interface to pass to the remote object.
+ OUTPUT (" - Create Instance of ICube\n");
+ hRes = CoCreateInstance(CLSID_Cubes, NULL, CLSCTX_LOCAL_SERVER,
+ IID_ICube, (void **)&pCube);
+ TEST_FAILED_EXIT(FAILED(hRes), "CoCreateInstance failed\n")
+ OUTPUT (" - Instance of ICube created OK\n");
+
+
+ OUTPUT (" - Make first call on ICube interface\n");
+ hRes = pCube->MoveCube(23, 34);
+ TEST_FAILED(FAILED(hRes), "ICube->MoveCube failed\n")
+
+ // release the interface
+ OUTPUT (" - Release the ICube interface\n");
+ ulRefCnt = pCube->Release();
+ TEST_FAILED(ulRefCnt != 0, "pCube RefCnt not zero\n");
+ pCube = NULL;
+
+// ----------------------------------------------------------------------
+
+Cleanup:
+
+ OUTPUT (" - Test Complete. Doing Cleanup\n");
+
+ // restore the registry to use real proxy dll for ICube interface
+ if (lRes == ERROR_SUCCESS)
+ {
+ lRes = RegSetValueEx(HKEY_CLASSES_ROOT,
+ TEXT("Interface\\{00000139-0001-0008-C000-000000000046}\\ProxyStubClsid32"),
+ NULL,
+ dwType,
+ szValueSave,
+ cbValue);
+ }
+
+ return TestResult(RetVal, "TestNonNDR");
+}
+
+
+// ----------------------------------------------------------------------
+//
+// test rundown
+//
+// - build 9 objects
+// - marshal 3 NORMAL, 3 TABLE_STRONG, 3 TABLE_WEAK.
+// - start 3 clients that each do 3 things...
+// Unmarshal Objects
+// Call Method on each object
+// Release Objects
+// each client has a sleep before one of the operations to let rundown
+// happen.
+// - CoDisconnectObject each of the 9 objects
+//
+// ----------------------------------------------------------------------
+BOOL TestRundown(void)
+{
+ BOOL RetVal = TRUE;
+ BOOL fSame = TRUE;
+ ULONG k = 0;
+ HRESULT hres;
+ IStream *pstm[3] = {NULL, NULL, NULL};
+ IUnknown *punk[9] = {NULL, NULL, NULL,
+ NULL, NULL, NULL,
+ NULL, NULL, NULL};
+
+ DWORD mshlflags[3] = {MSHLFLAGS_NORMAL,
+ MSHLFLAGS_TABLESTRONG,
+ MSHLFLAGS_TABLEWEAK};
+
+ MSG msg;
+ DWORD dwEndTime;
+
+
+ OUTPUT ("Starting TestRundown\n");
+
+
+ // create 9 objects to play with
+ OUTPUT ("Creating Nine Objects\n");
+ for (ULONG i=0; i<9; i++)
+ {
+ punk[i] = GetTestUnk();
+ TEST_FAILED_EXIT((punk[i] == NULL), "new CTestUnk failed\n")
+ VerifyObjRefCnt(punk[i], 1);
+ }
+
+
+ // create 3 streams on files
+ OUTPUT ("Creating Three Streams\n");
+ for (i=0; i<3; i++)
+ {
+ pstm[i] = (IStream *) new CStreamOnFile(pwszFileName[i] ,hres, FALSE);
+ TEST_FAILED_EXIT((pstm[i] == NULL), "new CStreamOnFile failed\n")
+ TEST_FAILED_EXIT(FAILED(hres), "CStreamOnFile failed\n")
+ VerifyObjRefCnt(pstm[i], 1);
+ }
+
+// ----------------------------------------------------------------------
+
+ // marshal the nine objects into 3 different streams on files.
+ OUTPUT ("Marshal Nine Objects into Three Streams\n");
+
+
+ // loop on stream
+ for (i=0; i<3; i++)
+ {
+ // loop on marshal flags
+ for (ULONG j=0; j<3; j++)
+ {
+ hres = CoMarshalInterface(pstm[i], IID_IParseDisplayName, punk[k++],
+ 0, NULL, mshlflags[j]);
+ TEST_FAILED_EXIT(FAILED(hres), "CoMarshalInterface failed\n")
+ }
+ }
+
+
+ // release the streams
+ OUTPUT ("Releasing the streams\n");
+ for (i=0; i<3; i++)
+ {
+ pstm[i]->Release();
+ pstm[i] = NULL;
+ }
+
+
+ // start the 3 client processes
+ OUTPUT ("Start Three Client Processes\n");
+
+#if 0
+ for (i=0; i<3; i++)
+ {
+ DWORD dwThrdId = 0;
+ HANDLE hThrd = CreateThread(NULL, 0,
+ RundownClient,
+ (void *)i,
+ 0, &dwThrdId);
+
+ if (hThrd)
+ {
+ CloseHandle(hThrd);
+ }
+ else
+ {
+ hres = GetLastError();
+ TEST_FAILED_EXIT(hres, "CreateThread failed\n")
+ }
+ }
+#endif
+
+ // sleep for some time to let the clients run
+ OUTPUT ("Waiting 12 minutes to let clients run\n");
+
+ dwEndTime = GetTickCount() + 780000;
+
+ while (GetTickCount() < dwEndTime)
+
+ {
+ if (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))
+ {
+ if (GetMessage(&msg, NULL, 0, 0))
+ DispatchMessage(&msg);
+ }
+ else
+ {
+ Sleep(250);
+ }
+ }
+
+// ----------------------------------------------------------------------
+
+Cleanup:
+
+ OUTPUT (" - Test Complete. Doing Cleanup\n");
+
+ // disconnect the nine objects
+ OUTPUT ("Disconnecting Nine Objects\n");
+ for (i=0; i<9; i++)
+ {
+ if (punk[i] != NULL)
+ {
+ hres = CoDisconnectObject(punk[i], 0);
+ punk[i] = NULL;
+ TEST_FAILED(FAILED(hres), "CoDisconnectObject failed\n")
+ }
+ }
+
+ // release the streams
+ OUTPUT ("Releasing the streams\n");
+ for (i=0; i<3; i++)
+ {
+ if (pstm[i] != NULL)
+ {
+ pstm[i]->Release();
+ pstm[i] = NULL;
+ }
+ }
+
+ return TestResult(RetVal, "TestRundown");
+}
+
+// ----------------------------------------------------------------------
+//
+// test rundown worker thread
+//
+// starts a thread that will do...
+// Unmarshal Objects
+// Call Method on each object
+// Release Objects
+//
+// perform a sleep before one of the operations to let rundown
+// happen.
+//
+// ----------------------------------------------------------------------
+DWORD _stdcall RundownClient(void *param)
+{
+ BOOL RetVal = TRUE;
+ ULONG i = 0;
+ HRESULT hres;
+ IStream *pstm = NULL;
+ IBindCtx *pbctx = NULL;
+ IParseDisplayName *punk[3] = {NULL, NULL, NULL};
+
+
+ OUTPUT (" Starting RundownClient\n");
+
+ // get the filename from the passed in parameter
+ DWORD dwThreadNum = (DWORD)param;
+
+ hres = CoInitialize(NULL);
+ TEST_FAILED_EXIT(FAILED(hres), "CoInitialzie failed\n")
+
+
+ // create a stream on the file
+ OUTPUT (" - CreateStreamOnFile\n");
+ pstm = (IStream *) new CStreamOnFile(pwszFileName[dwThreadNum], hres, TRUE);
+ TEST_FAILED_EXIT((pstm == NULL), "CStreamOnFile failed\n")
+ TEST_FAILED_EXIT(FAILED(hres), "CStreamOnFile failed\n")
+ VerifyObjRefCnt(pstm, 1);
+
+// ----------------------------------------------------------------------
+
+ if (dwThreadNum == 2)
+ Sleep(5000);
+
+ // unmarshal the interfaces
+ OUTPUT (" - Unmarshal the interfaces\n");
+ for (i=0; i<3; i++)
+ {
+ hres = CoUnmarshalInterface(pstm, IID_IParseDisplayName,
+ (void **)&punk[i]);
+ TEST_FAILED_EXIT(FAILED(hres), "CoUnmarshalInterface failed\n")
+ }
+ OUTPUT (" - Unmarshaled the interfaces OK.\n");
+
+// ----------------------------------------------------------------------
+
+ if (dwThreadNum == 1)
+ Sleep(5000);
+
+ hres = CreateBindCtx(0, &pbctx);
+ TEST_FAILED_EXIT(FAILED(hres), "CreateBindCtx failed\n")
+
+ // call the objects
+ for (i=0; i<3; i++)
+ {
+ ULONG cbEaten = 0;
+ IMoniker *pmnk = NULL;
+
+ hres = punk[i]->ParseDisplayName(pbctx, pwszFileName[dwThreadNum],
+ &cbEaten, &pmnk);
+ TEST_FAILED(FAILED(hres), "call on object failed\n")
+
+ if (pmnk)
+ {
+ pmnk->Release();
+ }
+ }
+ OUTPUT (" - Called the interfaces OK.\n");
+
+ pbctx->Release();
+
+// ----------------------------------------------------------------------
+
+ if (dwThreadNum == 0)
+ Sleep(5000);
+
+// ----------------------------------------------------------------------
+
+Cleanup:
+
+ OUTPUT (" - Rundown Thread Complete. Doing Cleanup\n");
+
+ // release the objects
+ for (i=0; i<3; i++)
+ {
+ if (punk[i] != NULL)
+ {
+ punk[i]->Release();
+ punk[i] = NULL;
+ }
+ }
+ OUTPUT (" - Released the interfaces OK.\n");
+
+ // release the stream
+ pstm->Release();
+
+ CoUninitialize();
+
+ return TestResult(RetVal, "TestRundown");
+}
+
+
+
+// ----------------------------------------------------------------------
+//
+// TestMarshalStorage
+//
+// test marshalling a docfile
+//
+// ----------------------------------------------------------------------
+
+BOOL TestMarshalStorage(void)
+{
+ BOOL RetVal = TRUE;
+ HRESULT hres;
+ ULONG ulRefCnt;
+ IStorage *pStgIn = NULL;
+ IStorage *pStgOut = NULL;
+ IStream *pStm = NULL;
+
+ LARGE_INTEGER large_int;
+ LISet32(large_int, 0);
+
+ OUTPUT ("Starting TestMarshalStorage\n");
+
+ // create a docfile
+ hres = StgCreateDocfile(L"foo.bar",
+ STGM_READWRITE | STGM_CREATE | STGM_SHARE_EXCLUSIVE,
+ 0, &pStgIn);
+
+ TEST_FAILED_EXIT(FAILED(hres), "StgCreateDocFile failed\n")
+
+ // create a stream to marshal the storage into
+ pStm = CreateMemStm(600, NULL);
+ TEST_FAILED_EXIT((pStm == NULL), "CreateMemStm failed\n")
+ VerifyObjRefCnt((IUnknown *)pStm, 1);
+
+
+// ----------------------------------------------------------------------
+
+ // marshal the interface
+ hres = CoMarshalInterface(pStm, IID_IStorage, pStgIn, 0, NULL, MSHLFLAGS_NORMAL);
+ TEST_FAILED_EXIT(FAILED(hres), "CoMarshalInterface failed\n")
+ OUTPUT (" - CoMarshalInterface OK\n");
+
+ hres = pStm->Seek(large_int, STREAM_SEEK_SET, NULL);
+ TEST_FAILED_EXIT(FAILED(hres), "Seek on shared stream failed\n")
+
+ // since we are unmarshalling in the same process, the RH should go away.
+ hres = CoUnmarshalInterface(pStm, IID_IStorage, (LPVOID FAR*)&pStgOut);
+ TEST_FAILED_EXIT(FAILED(hres), "CoUnmarshalInterface failed\n")
+
+ // make sure the interface pointers are identical
+ if (pStgIn != pStgOut)
+ OUTPUT("WARNING: CoUnmarshalInterface Local...ptrs dont match\n")
+ else
+ OUTPUT (" - CoUnmarshalInterface OK\n");
+
+ // release it and make sure it does not go away - refcnt > 0
+ ulRefCnt = pStgOut->Release();
+ pStgOut = NULL;
+ TEST_FAILED(ulRefCnt == 0, "pStgOut RefCnt is not zero");
+ OUTPUT (" - Release OK\n");
+
+ // the RH should have gone away, and we should have only the original
+ // refcnt from creation left on the object.
+ VerifyObjRefCnt(pStgIn, 1);
+
+
+// ----------------------------------------------------------------------
+
+Cleanup:
+
+ OUTPUT (" - Test Complete. Doing Cleanup\n");
+
+ if (pStgIn)
+ {
+ ulRefCnt = pStgIn->Release();
+ TEST_FAILED(ulRefCnt != 0, "pStgIn RefCnt not zero\n");
+ }
+
+ if (pStgOut)
+ {
+ ulRefCnt = pStgOut->Release();
+ TEST_FAILED(ulRefCnt != 0, "pStgOut RefCnt not zero\n");
+ }
+
+ if (pStm)
+ {
+ ulRefCnt = pStm->Release();
+ TEST_FAILED(ulRefCnt != 0, "pStm RefCnt not zero\n");
+ }
+
+ return TestResult(RetVal, "TestMarshalStorage");
+}
+
+
+
+// ----------------------------------------------------------------------
+//
+// test LOCAL interface MSHLFLAGS_NORMAL, MSHCTX_DIFFERENTMACHINE
+//
+// ----------------------------------------------------------------------
+
+BOOL TestStorageInterfaceDiffMachine(void)
+{
+ BOOL RetVal = TRUE;
+ HRESULT hres;
+ LPSTREAM pStm = NULL;
+ ULONG ulRefCnt = 0;
+ IStorage *pStgIn = NULL;
+ IStorage *pStgOut = NULL;
+
+ LARGE_INTEGER large_int;
+ LISet32(large_int, 0);
+
+ OUTPUT ("Starting TestStorageInterfaceDiffMachine\n");
+
+ // create a docfile
+ hres = StgCreateDocfile(L"foo.bar",
+ STGM_READWRITE | STGM_CREATE | STGM_SHARE_EXCLUSIVE,
+ 0, &pStgIn);
+ TEST_FAILED_EXIT(FAILED(hres), "CreateDocfile failed\n")
+
+ pStm = CreateMemStm(600, NULL);
+ TEST_FAILED_EXIT((pStm == NULL), "CreateMemStm failed\n")
+ VerifyObjRefCnt((IUnknown *)pStm, 1);
+
+
+// ----------------------------------------------------------------------
+ hres = CoMarshalInterface(pStm, IID_IStorage, pStgIn,
+ MSHCTX_DIFFERENTMACHINE, 0,
+ MSHLFLAGS_NORMAL);
+
+ TEST_FAILED_EXIT(FAILED(hres), "CoMarshalInterface failed\n")
+ VerifyRHRefCnt(pStgIn, 1);
+ OUTPUT (" - CoMarshalInterface OK\n");
+
+ hres = pStm->Seek(large_int, STREAM_SEEK_SET, NULL);
+ TEST_FAILED_EXIT(FAILED(hres), "Seek on shared stream failed\n")
+
+ hres = CoUnmarshalInterface(pStm, IID_IStorage, (LPVOID FAR*)&pStgOut);
+ TEST_FAILED_EXIT(FAILED(hres), "CoUnmarshalInterface failed\n")
+ VerifyRHRefCnt(pStgIn, 0);
+
+ // release them
+ ulRefCnt = pStgOut->Release();
+ pStgOut = NULL;
+ OUTPUT (" - Release OK\n");
+
+ ulRefCnt = pStgIn->Release();
+ pStgIn = NULL;
+ OUTPUT (" - Release OK\n");
+
+// ----------------------------------------------------------------------
+
+Cleanup:
+
+ OUTPUT (" - Test Complete. Doing Cleanup\n");
+
+ if (pStgIn)
+ {
+ ulRefCnt = pStgIn->Release();
+ TEST_FAILED(ulRefCnt != 0, "pStgIn RefCnt not zero\n");
+ }
+
+ if (pStgOut)
+ {
+ ulRefCnt = pStgOut->Release();
+ TEST_FAILED(ulRefCnt != 0, "pStgOut RefCnt not zero\n");
+ }
+
+ if (pStm)
+ {
+ ulRefCnt = pStm->Release();
+ TEST_FAILED(ulRefCnt != 0, "pStm RefCnt not zero\n");
+ }
+
+ return TestResult(RetVal, "TestStorageInterfaceDiffMachine");
+}
+
+
+
+// ----------------------------------------------------------------------
+//
+// test REMOTE interface MSHLFLAGS_NORMAL, MSHCTX_DIFFERENTMACHINE
+//
+// ----------------------------------------------------------------------
+
+BOOL TestRemoteInterfaceDiffMachine(void)
+{
+ BOOL RetVal = TRUE;
+ HRESULT hres;
+ LPSTREAM pStm = NULL;
+ LPCLASSFACTORY pICF = NULL;
+ ULONG ulRefCnt;
+ IUnknown *punkOut = NULL;
+ IUnknown *punkIn = NULL;
+
+ LARGE_INTEGER large_int;
+ LISet32(large_int, 0);
+
+ OUTPUT ("Starting TestRemoteInterfaceDifferentMachine\n");
+
+ // Create an IClassFactory Interface.
+ DWORD grfContext=CLSCTX_LOCAL_SERVER; // handler/server/local server
+ hres = CoGetClassObject(CLSID_Balls,
+ grfContext,
+ NULL, // pvReserved
+ IID_IClassFactory,
+ (void **)&pICF);
+
+ TEST_FAILED_EXIT(FAILED(hres), "CoGetClassObject failed\n")
+ TEST_FAILED_EXIT((pICF == NULL), "CoGetClassObject failed\n")
+ VerifyRHRefCnt((IUnknown *)pICF, 1);
+ OUTPUT (" - Aquired Remote Class Object.\n");
+
+// ----------------------------------------------------------------------
+
+ // note, since pICF is a class object, it has special super secret
+ // behaviour to make it go away. create an instance, release the
+ // class object, then release the instance.
+
+ hres = pICF->CreateInstance(NULL, IID_IUnknown, (void **)&punkIn);
+ TEST_FAILED_EXIT(FAILED(hres), "CreateInstance failed\n")
+ TEST_FAILED_EXIT((punkIn == NULL), "CreateInstance failed\n")
+ VerifyRHRefCnt(punkIn, 1);
+ OUTPUT (" - Created Instance.\n");
+
+ // release class object
+ ulRefCnt = pICF->Release();
+ TEST_FAILED(ulRefCnt != 0, "pICF RefCnt not zero\n");
+ // VerifyRHRefCnt((IUnknown *)pICF, 0);
+ pICF = NULL;
+ OUTPUT (" - Released Class Object.\n");
+
+// ----------------------------------------------------------------------
+
+ // Create a shared memory stream for the marshaled interface
+ pStm = CreateMemStm(600, NULL);
+ TEST_FAILED_EXIT((pStm == NULL), "CreateMemStm failed\n")
+
+ // Marshal the interface into the stream
+ hres = CoMarshalInterface(pStm, IID_IUnknown, punkIn,
+ MSHCTX_DIFFERENTMACHINE, 0,
+ MSHLFLAGS_NORMAL);
+ TEST_FAILED_EXIT(FAILED(hres), "CoMarshalInterface failed\n")
+ OUTPUT (" - CoMarshalInterface OK.\n");
+ VerifyRHRefCnt(punkIn, 1);
+
+ // unmarshal the interface. should get the same proxy back.
+ hres = pStm->Seek(large_int, STREAM_SEEK_SET, NULL);
+ TEST_FAILED_EXIT(FAILED(hres), "Seek on shared stream failed\n")
+
+ hres = CoUnmarshalInterface(pStm, IID_IUnknown, (LPVOID FAR*)&punkOut);
+ TEST_FAILED_EXIT(FAILED(hres), "CoUnmarshalInterface failed\n")
+ VerifyRHRefCnt(punkIn, 2);
+
+ // make sure the interface pointers are identical
+ if (punkIn != punkOut)
+ TEST_FAILED_EXIT(TRUE, "Interface ptrs dont match..1st Remote Unmarshal\n")
+ OUTPUT (" - CoUnmarshalInterface OK.\n");
+
+
+ // release the interface
+ ulRefCnt = punkOut->Release();
+ punkOut = NULL;
+ TEST_FAILED_EXIT(ulRefCnt == 0, "punkOut RefCnt is zero\n");
+ VerifyRHRefCnt(punkIn, 1);
+ OUTPUT (" - Release OK\n");
+
+// ----------------------------------------------------------------------
+
+Cleanup:
+
+ OUTPUT (" - Test Complete. Doing Cleanup\n");
+
+ // Dump interfaces we are done with
+ if (pStm)
+ {
+ ulRefCnt = pStm->Release();
+ TEST_FAILED(ulRefCnt != 0, "Stream RefCnt not zero\n");
+ }
+
+ if (punkOut)
+ {
+ ulRefCnt = punkOut->Release();
+ TEST_FAILED(ulRefCnt != 0, "punkOut RefCnt not zero\n");
+ }
+
+ if (punkIn)
+ {
+ ulRefCnt = punkIn->Release();
+ TEST_FAILED(ulRefCnt != 0, "punkIn RefCnt not zero\n");
+ }
+
+ return TestResult(RetVal, "TestRemoteInterfaceDiffMachine");
+}
+
+// ----------------------------------------------------------------------
+//
+// test LOCAL interface MSHLFLAGS_NORMAL, MSHCTX_DIFFERENTMACHINE
+//
+// ----------------------------------------------------------------------
+
+BOOL TestLocalInterfaceDiffMachine(void)
+{
+ BOOL RetVal = TRUE;
+ HRESULT hres;
+ LPSTREAM pStm = NULL;
+ LPCLASSFACTORY pICF = NULL;
+ ULONG ulRefCnt;
+ IUnknown *punkOut = NULL;
+ IUnknown *punkIn = NULL;
+
+ LARGE_INTEGER large_int;
+ LISet32(large_int, 0);
+
+ OUTPUT ("Starting TestLocalInterfaceDifferentMachine\n");
+
+ punkIn = GetTestUnk();
+ TEST_FAILED_EXIT((punkIn == NULL), "new CTestUnk failed\n")
+ VerifyObjRefCnt(punkIn, 1);
+
+// ----------------------------------------------------------------------
+
+ // Create a shared memory stream for the marshaled interface
+ pStm = CreateMemStm(600, NULL);
+ TEST_FAILED_EXIT((pStm == NULL), "CreateMemStm failed\n")
+
+ // Marshal the interface into the stream
+ hres = CoMarshalInterface(pStm, IID_IUnknown, punkIn,
+ MSHCTX_DIFFERENTMACHINE, 0,
+ MSHLFLAGS_NORMAL);
+ TEST_FAILED_EXIT(FAILED(hres), "CoMarshalInterface failed\n")
+ OUTPUT (" - CoMarshalInterface OK.\n");
+ VerifyRHRefCnt(punkIn, 1);
+
+ // unmarshal the interface. should get the same proxy back.
+ hres = pStm->Seek(large_int, STREAM_SEEK_SET, NULL);
+ TEST_FAILED_EXIT(FAILED(hres), "Seek on shared stream failed\n")
+
+ hres = CoUnmarshalInterface(pStm, IID_IUnknown, (LPVOID FAR*)&punkOut);
+ TEST_FAILED_EXIT(FAILED(hres), "CoUnmarshalInterface failed\n")
+ VerifyRHRefCnt(punkIn, 0);
+
+ // make sure the interface pointers are identical
+ if (punkIn != punkOut)
+ TEST_FAILED_EXIT(TRUE, "Interface ptrs dont match..1st Local Unmarshal\n")
+ OUTPUT (" - CoUnmarshalInterface OK.\n");
+
+
+ // release the interface
+ ulRefCnt = punkOut->Release();
+ punkOut = NULL;
+ TEST_FAILED_EXIT(ulRefCnt == 0, "punkOut RefCnt is zero\n");
+ VerifyRHRefCnt(punkIn, 0);
+ OUTPUT (" - Release OK\n");
+
+// ----------------------------------------------------------------------
+
+Cleanup:
+
+ OUTPUT (" - Test Complete. Doing Cleanup\n");
+
+ // Dump interfaces we are done with
+ if (pStm)
+ {
+ ulRefCnt = pStm->Release();
+ TEST_FAILED(ulRefCnt != 0, "Stream RefCnt not zero\n");
+ }
+
+ if (punkOut)
+ {
+ ulRefCnt = punkOut->Release();
+ TEST_FAILED(ulRefCnt != 0, "punkOut RefCnt not zero\n");
+ }
+
+ if (punkIn)
+ {
+ ulRefCnt = punkIn->Release();
+ TEST_FAILED(ulRefCnt != 0, "punkIn RefCnt not zero\n");
+ }
+
+ return TestResult(RetVal, "TestLocalInterfaceDiffMachine");
+}
+
+// ----------------------------------------------------------------------
+//
+// test NOPING with MSHLFLAGS NORMAL, TABLEWEAK and TABLESTRONG
+//
+// CodeWork: ensure SORF_FLAG set correctly.
+// ensure precedence rules are followed.
+// ensure protocol is followed.
+//
+// ----------------------------------------------------------------------
+typedef struct tagNoPingThreadInfo
+{
+ HANDLE hEvent;
+ IStream *pStm;
+ HRESULT hr;
+} NoPingThreadInfo;
+
+DWORD _stdcall NoPingThread(void *param);
+
+BOOL TestNoPing(void)
+{
+ BOOL RetVal = TRUE;
+ HRESULT hres;
+ LPSTREAM pStm = NULL;
+ ULONG ulRefCnt, i;
+ IUnknown *punkOut = NULL;
+ IUnknown *punkIn = NULL;
+ IUnknown *punk[5] = {NULL, NULL, NULL, NULL, NULL};
+ NoPingThreadInfo npInfo;
+ DWORD dwThrdId = 0;
+ HANDLE hThrd;
+ IMarshal *pIM = NULL;
+
+ LARGE_INTEGER large_int;
+ LISet32(large_int, 0);
+
+ OUTPUT ("Starting TestNoPing\n");
+
+ punkIn = GetTestUnk();
+ TEST_FAILED_EXIT((punkIn == NULL), "new CTestUnk failed\n")
+ VerifyObjRefCnt(punkIn, 1);
+
+// ----------------------------------------------------------------------
+
+ // Create a shared memory stream for the marshaled interface
+ pStm = CreateMemStm(600, NULL);
+ TEST_FAILED_EXIT((pStm == NULL), "CreateMemStm failed\n")
+
+ // marshal it NORMAL, TABLEWEAK and TABLESTRONG with the NOPING flag
+ // set, and unmarshal each in the server apartment.
+
+ for (i=0; i<3; i++)
+ {
+ // Marshal the interface into the stream
+ hres = CoMarshalInterface(pStm, IID_IUnknown, punkIn,
+ 0, 0, (i | MSHLFLAGS_NOPING));
+
+ TEST_FAILED_EXIT(FAILED(hres), "CoMarshalInterface failed\n")
+ OUTPUT (" - CoMarshalInterface OK.\n");
+ VerifyRHRefCnt(punkIn, 1);
+
+
+ // verify the marshal format
+ hres = pStm->Seek(large_int, STREAM_SEEK_SET, NULL);
+ TEST_FAILED_EXIT(FAILED(hres), "Seek on shared stream failed\n")
+
+ hres = VerifyOBJREFFormat(pStm, (i | MSHLFLAGS_NOPING));
+ TEST_FAILED_EXIT(FAILED(hres), "VerifyOBJREFFormat failed\n")
+ OUTPUT (" - VerifyOBJREFFormat OK.\n");
+
+
+ // unmarshal the interface. should get the same proxy back.
+ hres = pStm->Seek(large_int, STREAM_SEEK_SET, NULL);
+ TEST_FAILED_EXIT(FAILED(hres), "Seek on shared stream failed\n")
+
+ hres = CoUnmarshalInterface(pStm, IID_IUnknown, (LPVOID FAR*)&punkOut);
+ TEST_FAILED_EXIT(FAILED(hres), "CoUnmarshalInterface failed\n")
+
+
+ // make sure the interface pointers are identical
+ if (punkIn != punkOut)
+ TEST_FAILED_EXIT(TRUE, "Interface ptrs dont match..1st Local Unmarshal\n")
+ OUTPUT (" - CoUnmarshalInterface OK.\n");
+
+ // check the refcnt on the stdid
+ if (i == 0)
+ {
+ // normal case, stdid should have been cleaned up
+ VerifyRHRefCnt(punkIn, 0);
+ }
+ else
+ {
+ // table case, stdid should still exist
+ VerifyRHRefCnt(punkIn, 1);
+ }
+
+ // release the interface
+ ulRefCnt = punkOut->Release();
+ punkOut = NULL;
+
+ TEST_FAILED_EXIT(ulRefCnt == 0, "punkOut RefCnt is zero\n");
+ VerifyRHRefCnt(punkIn, (i == 0) ? 0 : 1);
+ OUTPUT (" - Release OK\n");
+
+ if (i > 0)
+ {
+ // need to release marshal data on table marshaled interfaces
+ // reset the stream
+ hres = pStm->Seek(large_int, STREAM_SEEK_SET, NULL);
+ TEST_FAILED_EXIT(FAILED(hres), "Seek on shared stream failed\n")
+
+ hres = CoReleaseMarshalData(pStm);
+ TEST_FAILED_EXIT(FAILED(hres), "ReleaseMarshalData failed\n")
+ }
+
+ // reset the stream
+ hres = pStm->Seek(large_int, STREAM_SEEK_SET, NULL);
+ TEST_FAILED_EXIT(FAILED(hres), "Seek on shared stream failed\n")
+ }
+
+
+ // check the precedence rules
+
+ // Whatever an interface is first marshaled as is what sets the
+ // PING / NOPING flags. Marshal first as normal then noping and
+ // expect a normal 2nd marshal. Then marshal first as noping then
+ // normal and expect a noping 2nd marshal.
+
+ for (i=0; i<2; i++)
+ {
+ DWORD mshlflags1 = (i==0) ? MSHLFLAGS_NORMAL : MSHLFLAGS_NOPING;
+ DWORD mshlflags2 = (i==0) ? MSHLFLAGS_NOPING : MSHLFLAGS_NORMAL;
+
+ // Marshal the interface into the stream
+ hres = CoMarshalInterface(pStm, IID_IUnknown, punkIn,
+ 0, 0, mshlflags1);
+
+ TEST_FAILED_EXIT(FAILED(hres), "CoMarshalInterface failed\n")
+ OUTPUT (" - CoMarshalInterface OK.\n");
+ VerifyRHRefCnt(punkIn, 1);
+
+ // verify the marshal format
+ hres = pStm->Seek(large_int, STREAM_SEEK_SET, NULL);
+ TEST_FAILED_EXIT(FAILED(hres), "Seek on shared stream failed\n")
+
+ hres = VerifyOBJREFFormat(pStm, mshlflags1);
+ TEST_FAILED_EXIT(FAILED(hres), "VerifyOBJREFFormat failed\n")
+ OUTPUT (" - VerifyOBJREFFormat OK.\n");
+
+
+ // marshal it again, with the opposite flags then check the value
+ hres = pStm->Seek(large_int, STREAM_SEEK_SET, NULL);
+ TEST_FAILED_EXIT(FAILED(hres), "Seek on shared stream failed\n")
+
+ hres = CoMarshalInterface(pStm, IID_IUnknown, punkIn,
+ 0, 0, mshlflags2);
+
+ TEST_FAILED_EXIT(FAILED(hres), "CoMarshalInterface failed\n")
+ OUTPUT (" - CoMarshalInterface OK.\n");
+ VerifyRHRefCnt(punkIn, 1);
+
+ // verify the marshal format
+ hres = pStm->Seek(large_int, STREAM_SEEK_SET, NULL);
+ TEST_FAILED_EXIT(FAILED(hres), "Seek on shared stream failed\n")
+
+ hres = VerifyOBJREFFormat(pStm, mshlflags1);
+ TEST_FAILED_EXIT(FAILED(hres), "VerifyOBJREFFormat failed\n")
+ OUTPUT (" - VerifyOBJREFFormat OK.\n");
+
+ // release the marshaled data
+ hres = CoDisconnectObject(punkIn, 0);
+ TEST_FAILED_EXIT(FAILED(hres), "CoDisconnectObject failed\n")
+ OUTPUT (" - CoDisconnectObject OK.\n");
+
+ // reset the stream
+ hres = pStm->Seek(large_int, STREAM_SEEK_SET, NULL);
+ TEST_FAILED_EXIT(FAILED(hres), "Seek on shared stream failed\n")
+
+
+
+ // check CoGetStandardMarshal.
+ hres = CoGetStandardMarshal(IID_IUnknown, punkIn, 0, 0,
+ mshlflags1, &pIM);
+ TEST_FAILED_EXIT(FAILED(hres), "CoGetStandardMarshal failed\n")
+ OUTPUT (" - CoGetStandardMarshal OK.\n");
+
+ // Marshal the interface into the stream
+ hres = pIM->MarshalInterface(pStm, IID_IUnknown, punkIn,
+ 0, 0, mshlflags2);
+ TEST_FAILED_EXIT(FAILED(hres), "pIM->MarshalInterface failed\n")
+ OUTPUT (" - pIM->MarshalInterface OK.\n");
+
+ // verify the marshal format
+ hres = pStm->Seek(large_int, STREAM_SEEK_SET, NULL);
+ TEST_FAILED_EXIT(FAILED(hres), "Seek on shared stream failed\n")
+
+ hres = VerifyOBJREFFormat(pStm, mshlflags1);
+ TEST_FAILED_EXIT(FAILED(hres), "VerifyOBJREFFormat failed\n")
+ OUTPUT (" - VerifyOBJREFFormat OK.\n");
+
+ // release the IMarshal
+ pIM->Release();
+
+ // release the marshal data
+ hres = CoDisconnectObject(punkIn, 0);
+ TEST_FAILED_EXIT(FAILED(hres), "CoDisconnectObject failed\n")
+ OUTPUT (" - CoDisconnectObject OK.\n");
+
+ // reset the stream
+ hres = pStm->Seek(large_int, STREAM_SEEK_SET, NULL);
+ TEST_FAILED_EXIT(FAILED(hres), "Seek on shared stream failed\n")
+ }
+
+
+
+ // marshal 3 objects, NORMAL, TABLEWEAK, and TABLESTRONG, then
+ // pass the stream to another apartment and unmarshal them.
+
+ for (i=0; i<3; i++)
+ {
+ punk[i] = GetTestUnk();
+ TEST_FAILED_EXIT((punk[i] == NULL), "new CTestUnk failed\n")
+ VerifyObjRefCnt(punk[i], 1);
+
+ // Marshal the interface into the stream
+ hres = CoMarshalInterface(pStm, IID_IUnknown, punk[i],
+ 0, 0, (i | MSHLFLAGS_NOPING));
+
+ TEST_FAILED_EXIT(FAILED(hres), "CoMarshalInterface failed\n")
+ OUTPUT (" - CoMarshalInterface OK.\n");
+ VerifyRHRefCnt(punk[i], 1);
+ }
+
+ // marshal one more object, NOPING
+ punk[i] = GetTestUnk();
+ TEST_FAILED_EXIT((punk[i] == NULL), "new CTestUnk failed\n")
+ VerifyObjRefCnt(punk[i], 1);
+
+ // Marshal the interface into the stream
+ hres = CoMarshalInterface(pStm, IID_IUnknown, punk[i],
+ 0, 0, (MSHLFLAGS_NORMAL | MSHLFLAGS_NOPING));
+
+ TEST_FAILED_EXIT(FAILED(hres), "CoMarshalInterface failed\n")
+ OUTPUT (" - CoMarshalInterface OK.\n");
+ VerifyRHRefCnt(punk[i], 1);
+
+
+ // marshal a second interface on the same object as PING
+ hres = CoMarshalInterface(pStm, IID_IParseDisplayName, punk[i],
+ 0, 0, MSHLFLAGS_NORMAL);
+
+ TEST_FAILED_EXIT(FAILED(hres), "CoMarshalInterface failed\n")
+ OUTPUT (" - CoMarshalInterface OK.\n");
+ VerifyRHRefCnt(punk[i], 2);
+
+
+ // pass one more interface that does custom marshaling delegating
+ // to standard marshaling and replacing the PING option with NOPING.
+ i++;
+ punk[i] = (IUnknown *) new CTestUnkMarshal();
+ TEST_FAILED_EXIT((punk[i] == NULL), "new CTestUnkMarshal failed\n")
+ VerifyObjRefCnt(punk[i], 1);
+
+ // Marshal the interface into the stream
+ hres = CoMarshalInterface(pStm, IID_IUnknown, punk[i],
+ 0, 0, MSHLFLAGS_NORMAL);
+
+ TEST_FAILED_EXIT(FAILED(hres), "CoMarshalInterface failed\n")
+ OUTPUT (" - CoMarshalInterface OK.\n");
+ VerifyRHRefCnt(punk[i], 2);
+
+
+ // reset the stream seek ptr
+ hres = pStm->Seek(large_int, STREAM_SEEK_SET, NULL);
+ TEST_FAILED_EXIT(FAILED(hres), "Seek on shared stream failed\n")
+
+ for (i=0; i<6; i++)
+ {
+ // verify the marshal format
+ hres = VerifyOBJREFFormat(pStm, (i | MSHLFLAGS_NOPING));
+ TEST_FAILED_EXIT(FAILED(hres), "VerifyOBJREFFormat failed\n")
+ OUTPUT (" - VerifyOBJREFFormat OK.\n");
+ }
+
+ // reset the stream seek ptr
+ hres = pStm->Seek(large_int, STREAM_SEEK_SET, NULL);
+ TEST_FAILED_EXIT(FAILED(hres), "Seek on shared stream failed\n")
+
+ // create thread and wait for it to complete
+ npInfo.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+ npInfo.pStm = pStm;
+ npInfo.hr = S_OK;
+
+ hThrd = CreateThread(NULL, 0, NoPingThread,
+ &npInfo, 0, &dwThrdId);
+ if (hThrd)
+ {
+ // wait for thread to register run to completetion. Note that
+ // we dont have to provide a message pump because with the NOPING
+ // flag set the other thread should never call back to get or release
+ // any references.
+
+ WaitForSingleObject(npInfo.hEvent, 0xffffffff);
+ Sleep(0);
+ CloseHandle(npInfo.hEvent);
+
+ // close the thread handle
+ CloseHandle(hThrd);
+ }
+
+ // cleanup the leftover objects.
+ for (i=0; i<5; i++)
+ {
+ hres = CoDisconnectObject(punk[i], 0);
+ TEST_FAILED_EXIT(FAILED(hres), "CoDisconnectObject failed\n")
+ OUTPUT (" - CoDisconnectObject OK.\n");
+ }
+
+
+// ----------------------------------------------------------------------
+
+Cleanup:
+
+ OUTPUT (" - Test Complete. Doing Cleanup\n");
+
+ // Dump interfaces we are done with
+ if (pStm)
+ {
+ ulRefCnt = pStm->Release();
+ TEST_FAILED(ulRefCnt != 0, "Stream RefCnt not zero\n");
+ }
+
+ if (punkOut)
+ {
+ ulRefCnt = punkOut->Release();
+ TEST_FAILED(ulRefCnt != 0, "punkOut RefCnt not zero\n");
+ }
+
+ if (punkIn)
+ {
+ ulRefCnt = punkIn->Release();
+ TEST_FAILED(ulRefCnt != 0, "punkIn RefCnt not zero\n");
+ }
+
+ for (i=0; i<5; i++)
+ {
+ if (punk[i] != NULL)
+ {
+ ulRefCnt = punk[i]->Release();
+ TEST_FAILED(ulRefCnt != 0, "punk[i] RefCnt not zero\n");
+ }
+ }
+
+ return TestResult(RetVal, "TestNoPing");
+}
+
+
+// ----------------------------------------------------------------------
+//
+// Thread SubRoutine for testing NOPING.
+//
+// ----------------------------------------------------------------------
+DWORD _stdcall NoPingThread(void *param)
+{
+ BOOL RetVal = TRUE;
+ IUnknown *punk = NULL;
+ ULONG i = 0;
+
+ NoPingThreadInfo *npInfo = (NoPingThreadInfo *) param;
+ OUTPUT (" - NoPingThread Start\n");
+
+ HRESULT hRes = CoInitializeEx(NULL, gInitFlag);
+ TEST_FAILED(FAILED(hRes), "NoPingThread CoInitialize failed\n")
+
+ // Create a shared memory stream for the marshaled interface
+ IStream *pStm = CreateMemStm(600, NULL);
+ if (pStm == NULL)
+ {
+ TEST_FAILED((pStm == NULL), "CreateMemStm failed\n")
+ hRes = E_OUTOFMEMORY;
+ }
+
+ LARGE_INTEGER large_int;
+ LISet32(large_int, 0);
+
+ if (SUCCEEDED(hRes))
+ {
+ // unmarshal the interfaces
+ for (i=0; i<6; i++)
+ {
+
+ REFIID riid = (i==4) ? IID_IParseDisplayName : IID_IUnknown;
+
+ hRes = CoUnmarshalInterface(npInfo->pStm, riid, (void **)&punk);
+ TEST_FAILED(FAILED(hRes), "NoPingThread CoUnmarshalInterface failed\n")
+ OUTPUT(" - NoPingThread CoUnmarshalInterface done\n");
+
+ if (SUCCEEDED(hRes))
+ {
+ if (i==3)
+ {
+ // try remarshaling NOPING client as normal. Should end up
+ // as NOPING.
+
+ hRes = CoMarshalInterface(pStm, IID_IUnknown, punk,
+ 0, 0, MSHLFLAGS_NORMAL);
+ TEST_FAILED(FAILED(hRes), "CoMarshalInterface failed\n")
+ OUTPUT (" - CoMarshalInterface OK.\n");
+
+ // reset the stream seek ptr
+ hRes = pStm->Seek(large_int, STREAM_SEEK_SET, NULL);
+ TEST_FAILED(FAILED(hRes), "Seek on shared stream failed\n")
+
+ // verify the marshal format
+ hRes = VerifyOBJREFFormat(pStm, MSHLFLAGS_NOPING);
+ TEST_FAILED(FAILED(hRes), "VerifyOBJREFFormat failed\n")
+ OUTPUT (" - VerifyOBJREFFormat OK.\n");
+ }
+
+ punk->Release();
+ punk = NULL;
+ OUTPUT(" - NoPingThread Release done\n");
+ }
+ }
+
+ // uninit OLE
+ CoUninitialize();
+ }
+
+ if (pStm)
+ {
+ // release stream we created above
+ pStm->Release();
+ }
+
+ OUTPUT (" - NoPingThread Exit\n");
+ npInfo->hr = hRes;
+ SetEvent(npInfo->hEvent);
+ return RetVal;
+}
+
+
+// ----------------------------------------------------------------------
+//
+// test marshaling between apartments in the same process using
+// MSHLFLAGS_NORMAL, MSHLFLAGS_TABLEWEAK, and MSHLFLAGS_TABLESTRONG
+//
+// ----------------------------------------------------------------------
+typedef struct tagCrossThreadCallInfo
+{
+ HANDLE hEvent;
+ IStream *pStm;
+ DWORD dwInitFlag;
+ DWORD dwThreadId;
+ HRESULT hr;
+} CrossThreadCallInfo;
+
+
+DWORD _stdcall CrossThreadCalls(void *param);
+DWORD _stdcall CrossThreadLoops(void *param);
+DWORD _stdcall CrossThreadActivate(void *param);
+
+
+BOOL TestCrossThread(void)
+{
+ BOOL RetVal = TRUE;
+ HRESULT hres;
+ LPSTREAM pStm = NULL;
+ ULONG ulRefCnt, i, j;
+ IUnknown *punk[3] = {NULL, NULL, NULL};
+ IUnknown *pUnk;
+ ILoop *pLocalLoop = NULL;
+ CrossThreadCallInfo ctInfo;
+ DWORD dwThrdId = 0;
+ HANDLE hThrd;
+ DWORD mshlflags[3] = {MSHLFLAGS_NORMAL,
+ MSHLFLAGS_TABLEWEAK,
+ MSHLFLAGS_TABLESTRONG};
+
+ DWORD dwInitFlags[4] = {COINIT_APARTMENTTHREADED,
+ COINIT_APARTMENTTHREADED,
+ COINIT_MULTITHREADED,
+ COINIT_MULTITHREADED};
+
+
+ LARGE_INTEGER large_int;
+ LISet32(large_int, 0);
+
+ OUTPUT ("Starting TestCrossThread\n");
+
+ // Create a shared memory stream for the marshaled interface
+ pStm = CreateMemStm(600, NULL);
+ TEST_FAILED_EXIT((pStm == NULL), "CreateMemStm failed\n")
+
+// ----------------------------------------------------------------------
+
+ for (j=0; j<4; j++)
+ {
+ // reset the stream seek ptr
+ hres = pStm->Seek(large_int, STREAM_SEEK_SET, NULL);
+ TEST_FAILED_EXIT(FAILED(hres), "Seek on shared stream failed\n")
+
+ // marshal an interface NORMAL, TABLEWEAK and TABLESTRONG
+ // and unmarshal each in another apartment.
+
+ for (i=0; i<3; i++)
+ {
+ punk[i] = GetTestUnk();
+ TEST_FAILED_EXIT((punk[i] == NULL), "new CTestUnkCube failed\n")
+ VerifyObjRefCnt(punk[i], 1);
+
+ // Marshal the interface into the stream
+ hres = CoMarshalInterface(pStm, IID_ICube, punk[i],
+ 0, 0, mshlflags[i]);
+
+ TEST_FAILED_EXIT(FAILED(hres), "CoMarshalInterface failed\n")
+ OUTPUT (" - CoMarshalInterface OK.\n");
+ VerifyRHRefCnt(punk[i], 1);
+ }
+
+ // reset the stream seek ptr
+ hres = pStm->Seek(large_int, STREAM_SEEK_SET, NULL);
+ TEST_FAILED_EXIT(FAILED(hres), "Seek on shared stream failed\n")
+
+ for (i=0; i<3; i++)
+ {
+ hres = VerifyOBJREFFormat(pStm, mshlflags[i]);
+ TEST_FAILED_EXIT(FAILED(hres), "VerifyOBJREFFormat failed\n")
+ OUTPUT (" - VerifyOBJREFFormat OK.\n");
+ }
+
+ // reset the stream seek ptr
+ hres = pStm->Seek(large_int, STREAM_SEEK_SET, NULL);
+ TEST_FAILED_EXIT(FAILED(hres), "Seek on shared stream failed\n")
+
+
+ // create thread and wait for it to complete
+ ctInfo.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+ ctInfo.pStm = pStm;
+ ctInfo.dwInitFlag = dwInitFlags[j];
+ ctInfo.dwThreadId = GetCurrentThreadId();
+ ctInfo.hr = S_OK;
+
+ RunThread(&ctInfo, ctInfo.hEvent, CrossThreadCalls);
+ CloseHandle(ctInfo.hEvent);
+
+
+ // cleanup the leftover objects.
+ for (i=0; i<3; i++)
+ {
+ hres = CoDisconnectObject(punk[i], 0);
+ punk[i] = NULL;
+ TEST_FAILED_EXIT(FAILED(hres), "CoDisconnectObject failed\n")
+ OUTPUT (" - CoDisconnectObject OK.\n");
+ }
+ }
+
+// ----------------------------------------------------------------------
+ // Now test out doing activation from different apartments.
+ // create thread and wait for it to complete
+
+ for (j=0; j<2; j++)
+ {
+ ctInfo.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+ ctInfo.pStm = NULL;
+ ctInfo.dwInitFlag = dwInitFlags[j];
+ ctInfo.dwThreadId = GetCurrentThreadId();
+ ctInfo.hr = S_OK;
+
+ RunThread(&ctInfo, ctInfo.hEvent, CrossThreadActivate);
+ CloseHandle(ctInfo.hEvent);
+
+ // create an interface
+ hres = CoCreateInstance(CLSID_LoopSrv, NULL, CLSCTX_LOCAL_SERVER,
+ IID_ILoop, (void **)&pLocalLoop);
+ TEST_FAILED(FAILED(hres), "CoCreateInstance Second failed\n")
+
+ if (SUCCEEDED(hres))
+ {
+ pLocalLoop->Release();
+ }
+ }
+
+
+// ----------------------------------------------------------------------
+
+ // Now test doing nested calls between apartments.
+#if 0
+ for (j=0; j<2; j++)
+ {
+ // reset the stream seek ptr
+ hres = pStm->Seek(large_int, STREAM_SEEK_SET, NULL);
+ TEST_FAILED_EXIT(FAILED(hres), "Seek on shared stream failed\n")
+
+ pUnk = GetTestUnk();
+ TEST_FAILED_EXIT((pUnk == NULL), "new GetTestUnk failed\n")
+ VerifyObjRefCnt(pUnk, 1);
+
+ // Marshal the interface into the stream
+ hres = CoMarshalInterface(pStm, IID_ILoop, pUnk,
+ 0, 0, MSHLFLAGS_NORMAL);
+
+ TEST_FAILED_EXIT(FAILED(hres), "CoMarshalInterface failed\n")
+ OUTPUT (" - CoMarshalInterface OK.\n");
+ VerifyRHRefCnt(pUnk, 1);
+
+ // reset the stream seek ptr
+ hres = pStm->Seek(large_int, STREAM_SEEK_SET, NULL);
+ TEST_FAILED_EXIT(FAILED(hres), "Seek on shared stream failed\n")
+
+
+ ctInfo.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+ ctInfo.pStm = pStm;
+ ctInfo.dwInitFlag = dwInitFlags[j];
+ ctInfo.dwThreadId = GetCurrentThreadId();
+ ctInfo.hr = S_OK;
+
+ RunThread(&ctInfo, ctInfo.hEvent, CrossThreadLoops);
+ CloseHandle(ctInfo.hEvent);
+
+ pUnk->Release();
+ }
+#endif
+
+// ----------------------------------------------------------------------
+
+Cleanup:
+
+ OUTPUT (" - Test Complete. Doing Cleanup\n");
+
+ // Dump interfaces we are done with
+ if (pStm)
+ {
+ ulRefCnt = pStm->Release();
+ TEST_FAILED(ulRefCnt != 0, "Stream RefCnt not zero\n");
+ }
+
+ for (i=0; i<3; i++)
+ {
+ if (punk[i] != NULL)
+ {
+ ulRefCnt = punk[i]->Release();
+ TEST_FAILED(ulRefCnt != 0, "punk[i] RefCnt not zero\n");
+ }
+ }
+
+ return TestResult(RetVal, "TestCrossThread");
+}
+
+
+// ----------------------------------------------------------------------
+//
+// Thread SubRoutine for testing CROSSTHREAD calls.
+//
+// ----------------------------------------------------------------------
+DWORD _stdcall CrossThreadCalls(void *param)
+{
+ BOOL RetVal = TRUE;
+ ICube *pCube = NULL;
+ IOleWindow *pIOW = NULL;
+ IAdviseSink *pIAS = NULL;
+ ULONG i = 0;
+
+ // get the execution parameters
+ CrossThreadCallInfo *ctInfo = (CrossThreadCallInfo *) param;
+ OUTPUT (" - CrossThreadCalls Start\n");
+
+ // initialize COM
+ HRESULT hRes = CoInitializeEx(NULL, ctInfo->dwInitFlag);
+ TEST_FAILED(FAILED(hRes), "CrossThreadCalls CoInitializeEx failed\n")
+
+ if (SUCCEEDED(hRes))
+ {
+ // unmarshal the interfaces
+ for (i=0; i<3; i++)
+ {
+ hRes = CoUnmarshalInterface(ctInfo->pStm, IID_ICube, (void **)&pCube);
+ TEST_FAILED(FAILED(hRes), "CrossThread CoUnmarshalInterface failed\n")
+ OUTPUT(" - CrossThread CoUnmarshalInterface done\n");
+
+ if (SUCCEEDED(hRes))
+ {
+ // test a synchronous method call between apartments
+ // (also checks the lid & tid)
+
+ UUID lidCaller;
+ CoGetCurrentLogicalThreadId(&lidCaller);
+ hRes = pCube->SimpleCall(GetCurrentProcessId(),
+ GetCurrentThreadId(),
+ lidCaller);
+ TEST_FAILED(FAILED(hRes), "pCube->SimpleCall failed\n")
+ OUTPUT(" - Synchronous call done\n");
+
+ // test an input-sync method call between apartments
+ hRes = pCube->QueryInterface(IID_IOleWindow, (void **)&pIOW);
+
+ if (SUCCEEDED(hRes))
+ {
+ HWND hWnd;
+ hRes = pIOW->GetWindow(&hWnd);
+
+ // input sync is only allowed between two apartment
+ // threaded apartments.
+ if (ctInfo->dwInitFlag == gInitFlag)
+ {
+ TEST_FAILED(FAILED(hRes), "pIOW->GetWindow failed\n");
+ }
+ else
+ {
+ TEST_FAILED(SUCCEEDED(hRes), "pIOW->GetWindow should have failed\n");
+ }
+
+ pIOW->Release();
+ OUTPUT(" - Input-Synchronous call done\n");
+ }
+
+
+ // test an async method call between apartments
+ hRes = pCube->QueryInterface(IID_IAdviseSink, (void **)&pIAS);
+
+ if (SUCCEEDED(hRes))
+ {
+ // no return code to check
+ pIAS->OnViewChange(1,2);
+ pIAS->Release();
+ OUTPUT(" - ASynchronous call done\n");
+ }
+
+ // release the object
+ pCube->Release();
+ pCube = NULL;
+ OUTPUT(" - CrossThread Calls and Release done\n");
+ }
+ }
+
+ // uninit OLE
+ CoUninitialize();
+ }
+
+ OUTPUT (" - CrossThreadCalls Exit\n");
+ ctInfo->hr = hRes;
+
+ // signal the other thread we are done.
+ if (gInitFlag == COINIT_APARTMENTTHREADED)
+ {
+ PostThreadMessage(ctInfo->dwThreadId, WM_QUIT, 0, 0);
+ }
+ else
+ {
+ SetEvent(ctInfo->hEvent);
+ }
+
+ return hRes;
+}
+
+
+// ----------------------------------------------------------------------
+//
+// Thread SubRoutine for testing CROSSTHREAD activation
+//
+// ----------------------------------------------------------------------
+DWORD _stdcall CrossThreadActivate(void *param)
+{
+ BOOL RetVal = TRUE;
+ ILoop *pLocalLoop = NULL;
+
+ // get the execution parameters
+ CrossThreadCallInfo *ctInfo = (CrossThreadCallInfo *) param;
+ OUTPUT (" - CrossThreadActivate Start\n");
+
+ // initialize COM
+ HRESULT hRes = CoInitializeEx(NULL, ctInfo->dwInitFlag);
+ TEST_FAILED(FAILED(hRes), "CrossThreadActivate CoInitializeEx failed\n")
+
+ if (SUCCEEDED(hRes))
+ {
+ // create an interface
+ hRes = CoCreateInstance(CLSID_LoopSrv, NULL, CLSCTX_LOCAL_SERVER,
+ IID_ILoop, (void **)&pLocalLoop);
+ TEST_FAILED(FAILED(hRes), "CoCreateInstance First failed\n")
+
+ if (SUCCEEDED(hRes))
+ {
+ pLocalLoop->Release();
+ }
+
+ // uninit OLE
+ CoUninitialize();
+ }
+
+ OUTPUT (" - CrossThreadActivate Exit\n");
+ ctInfo->hr = hRes;
+
+ // signal the other thread we are done.
+ if (gInitFlag == COINIT_APARTMENTTHREADED)
+ {
+ PostThreadMessage(ctInfo->dwThreadId, WM_QUIT, 0, 0);
+ }
+ else
+ {
+ SetEvent(ctInfo->hEvent);
+ }
+
+ return hRes;
+}
+
+
+
+
+
+
+
+
+#if 0
+// ----------------------------------------------------------------------
+//
+// Thread SubRoutine for testing CROSSTHREAD calls.
+//
+// ----------------------------------------------------------------------
+DWORD _stdcall CrossThreadLoops(void *param)
+{
+ BOOL RetVal = TRUE;
+ ILoop *pLoop = NULL;
+ IUnknown *punk = NULL;
+ ILoop *pLoopLocal = NULL;
+
+ // get the execution parameters
+ CrossThreadCallInfo *ctInfo = (CrossThreadCallInfo *) param;
+ OUTPUT (" - CrossThreadLoops Start\n");
+
+ // initialize COM
+ HRESULT hRes = CoInitializeEx(NULL, ctInfo->dwInitFlag);
+ TEST_FAILED(FAILED(hRes), "CrossThreadLoops CoInitializeEx failed\n")
+
+ if (SUCCEEDED(hRes))
+ {
+ punk = GetTestUnk();
+ punk->QueryInterface(IID_ILoop, (void **)&pLoopLocal);
+ punk->Release();
+
+ // unmarshal the interface
+ hRes = CoUnmarshalInterface(ctInfo->pStm, IID_ILoop, (void **)&pLoop);
+ TEST_FAILED(FAILED(hRes), "CrossThreadLoop CoUnmarshalInterface failed\n")
+ OUTPUT(" - CrossThreadLoop CoUnmarshalInterface done\n");
+
+ if (SUCCEEDED(hRes))
+ {
+ // test nested synchronous method calls between apartments
+
+ hRes = pLoop->Init(pLoopLocal);
+ TEST_FAILED(FAILED(hRes), "pLoop->Init failed\n")
+
+ if (SUCCEEDED(hRes))
+ {
+ hRes = pLoop->Loop(5);
+ TEST_FAILED(FAILED(hRes), "pLoop->Loop failed\n")
+
+ hRes = pLoop->Uninit();
+ TEST_FAILED(FAILED(hRes), "pLoop->Uninit failed\n")
+ }
+
+ pLoop->Release();
+ pLoop = NULL;
+
+ OUTPUT(" - CrossThreadLoop Calls and Release done\n");
+ }
+
+ // uninit OLE
+ CoUninitialize();
+ }
+
+ OUTPUT (" - CrossThreadLoops Exit\n");
+ ctInfo->hr = hRes;
+
+ // signal the other thread we are done.
+ if (gInitFlag == COINIT_APARTMENTTHREADED)
+ {
+ PostThreadMessage(ctInfo->dwThreadId, WM_QUIT, 0, 0);
+ }
+ else
+ {
+ SetEvent(ctInfo->hEvent);
+ }
+
+ return hRes;
+}
+#endif
+
+
+
+// ----------------------------------------------------------------------
+//
+// Test calling CoGetPSClsid and CoRegisterPSClsid
+//
+// ----------------------------------------------------------------------
+BOOL TestPSClsid(void)
+{
+ BOOL RetVal = TRUE;
+ HRESULT hRes;
+ CLSID clsidOriginal, clsidNew;
+
+ OUTPUT ("Starting TestPSClsid\n");
+
+// ----------------------------------------------------------------------
+
+ // get the PSClsid that is currently registered for this interface.
+
+ hRes = CoGetPSClsid(IID_IViewObject, &clsidOriginal);
+ TEST_FAILED(FAILED(hRes), "Failed 1st CoGetPSClsid\n");
+ OUTPUT (" - Done 1st CoGetPSClsid\n");
+
+ // Set a new PSClsid for this interface for this process. Note that
+ // if we have used the interface before, we will get an error back,
+ // otherwise, this will succeed.
+
+ hRes = CoRegisterPSClsid(IID_IViewObject, CLSID_Balls);
+ TEST_FAILED(FAILED(hRes), "Failed 1st CoGRegisterPSClsid\n");
+ OUTPUT (" - Done 1st CoRegisterPSClsid\n");
+
+ // now get the PSClsid that is registered for this interface. This
+ // should match the value we just passed in.
+
+ hRes = CoGetPSClsid(IID_IViewObject, &clsidNew);
+ TEST_FAILED(FAILED(hRes), "Failed 2nd CoGetPSClsid\n");
+ OUTPUT (" - Done 2nd CoGetPSClsid\n");
+
+ if (memcmp(&clsidNew, &CLSID_Balls, sizeof(CLSID)))
+ {
+ TEST_FAILED(TRUE, "Failed Compare of CLSIDs\n");
+ }
+
+ // now try to register it again. This should fail since it has
+ // already been registered.
+
+ hRes = CoRegisterPSClsid(IID_IViewObject, clsidOriginal);
+ TEST_FAILED(FAILED(hRes), "Failed 2nd CoGRegisterPSClsid\n");
+ OUTPUT (" - Done 2nd CoRegisterPSClsid\n");
+
+ // now get the PSClsid that is registered for this interface. This
+ // should match the value we just passed in.
+
+ hRes = CoGetPSClsid(IID_IViewObject, &clsidNew);
+ TEST_FAILED(FAILED(hRes), "Failed 3rd CoGetPSClsid\n");
+ OUTPUT (" - Done 3rd CoGetPSClsid\n");
+
+ if (memcmp(&clsidNew, &clsidOriginal, sizeof(CLSID)))
+ {
+ TEST_FAILED(TRUE, "Failed 2nd Compare of CLSIDs\n");
+ }
+
+// ----------------------------------------------------------------------
+
+ OUTPUT (" - Test Complete. Doing Cleanup\n");
+ return TestResult(RetVal, "TestPSClsid");
+}
+
+// ----------------------------------------------------------------------
+//
+// Test calling CoGetPSClsid for a LONG IID/PSCLSID pair.
+//
+// ----------------------------------------------------------------------
+BOOL TestPSClsid2(void)
+{
+ BOOL RetVal = TRUE;
+ HRESULT hRes = S_OK;
+ CLSID clsidOriginal;
+
+ OUTPUT ("Starting TestPSClsid2\n");
+
+// ----------------------------------------------------------------------
+
+ // get the PSClsid that is currently registered for this interface.
+ hRes = CoGetPSClsid(IID_IViewObject, &clsidOriginal);
+ TEST_FAILED(FAILED(hRes), "Failed 1st CoGetPSClsid\n");
+ OUTPUT (" - Done 1st CoGetPSClsid\n");
+
+ if (!IsEqualGUID(clsidOriginal, CLSID_OLEPSFACTORY))
+ {
+ TEST_FAILED(FAILED(hRes), "CoGetPSClsid returned wrong value\n");
+ }
+
+// ----------------------------------------------------------------------
+
+ OUTPUT (" - Test Complete. Doing Cleanup\n");
+ return TestResult(RetVal, "TestPSClsid2");
+}
+
+
+
+// ----------------------------------------------------------------------
+//
+// TestGetIIDFromMI
+//
+// ----------------------------------------------------------------------
+BOOL TestGetIIDFromMI(void)
+{
+ BOOL RetVal = TRUE;
+ HRESULT hres;
+ IUnknown *punkIn = NULL;
+ IID iid;
+
+ OUTPUT ("Starting TestGetIIDFromMI\n");
+
+// ----------------------------------------------------------------------
+
+ ULARGE_INTEGER ulSeekEnd;
+ LARGE_INTEGER lSeekStart;
+ LISet32(lSeekStart, 0);
+
+ IStream *pStm = CreateMemStm(600, NULL);
+ TEST_FAILED_EXIT((pStm == NULL), "CreateMemStm failed\n")
+ VerifyObjRefCnt((IUnknown *)pStm, 1);
+
+ punkIn = GetTestUnk();
+
+ hres = CoMarshalInterface(pStm, IID_IUnknown, punkIn, 0, NULL, MSHLFLAGS_NORMAL);
+ TEST_FAILED_EXIT(FAILED(hres), "CoMarshalInterface failed\n")
+ OUTPUT (" - CoMarshalInterface OK\n");
+
+ // go back to begining
+ hres = pStm->Seek(lSeekStart, STREAM_SEEK_SET, NULL);
+ TEST_FAILED_EXIT(FAILED(hres), "Seek on shared stream failed\n")
+ OUTPUT (" - Seek Start OK\n");
+
+#if 0 // BUGBUG: RICKHI
+ // get the IID from the stream, and ensure it matches the IID we
+ // marshaled. Also, ensure the stream is left where it was. This
+ // is accomplished by calling CRMD on the stream.
+
+ hres = CoGetIIDFromMarshaledInterface(pStm, &iid);
+ TEST_FAILED(FAILED(hres), "CoGetIIDFromMarshaledInterface failed\n")
+ OUTPUT (" - CoGetIIDFromMarshaledInterface Done\n");
+
+ if (!IsEqualIID(IID_IUnknown, iid))
+ {
+ TEST_FAILED(TRUE, "IID read does not match IID marshaled\n")
+ }
+#endif
+ // release the marshaled interface
+ hres = CoReleaseMarshalData(pStm);
+ TEST_FAILED(FAILED(hres), "CoReleaseMarshalData failed\n")
+ OUTPUT (" - CoReleaseMarshalData Done\n");
+
+// ----------------------------------------------------------------------
+Cleanup:
+
+ if (punkIn)
+ {
+ punkIn->Release();
+ punkIn = NULL;
+ }
+
+ OUTPUT (" - Test Complete. Doing Cleanup\n");
+ return TestResult(RetVal, "TestGetIIDFromMI");
+}
diff --git a/private/oleutest/balls/client/tmarshal/tmarshal.h b/private/oleutest/balls/client/tmarshal/tmarshal.h
new file mode 100644
index 000000000..8890695fa
--- /dev/null
+++ b/private/oleutest/balls/client/tmarshal/tmarshal.h
@@ -0,0 +1,6 @@
+#ifndef __TMARSH_H__
+#define __TMARSH_H__
+
+BOOL TestMarshal(void);
+
+#endif // __TMARSH_H__
diff --git a/private/oleutest/balls/client/tmarshal/tmarshal.ini b/private/oleutest/balls/client/tmarshal/tmarshal.ini
new file mode 100644
index 000000000..aee8665f3
--- /dev/null
+++ b/private/oleutest/balls/client/tmarshal/tmarshal.ini
@@ -0,0 +1,92 @@
+;
+; Run All the Marshal Tests
+;
+
+[Marshal Test]
+; these first few are not run due to test bugs
+Aggregate = 0
+CreateRemoteHandler = 0
+StorageDiffMachine = 0
+Rundown = 0
+Async = 0
+
+; all the rest are run
+GetStandardMarshal = 1
+Format = 1
+GetIIDFromMI = 1
+MarshalSizeMax = 1
+LocalInterfaceNormal = 1
+UniqueQIPointer = 1
+LocalInterfaceTableStrong = 1
+LocalInterfaceTableWeak = 1
+UnmarshalGUIDNULL = 1
+UnmarshalDifferentIID = 1
+RemoteInterfaceNormal = 1
+RemoteInterfaceTableStrong = 1
+CustomMarshalNormal = 1
+CustomMarshalTable = 1
+Echo = 1
+MultiQINormal = 1
+MultiQIHandler = 1
+Handler = 1
+Loop = 1
+LockObjectExternal = 1
+DisconnectObject = 1
+ReleaseMarshalData = 1
+MiddleMan = 1
+LocalDiffMachine = 1
+RemoteDiffMachine = 1
+ExpiredOXIDs = 1
+NonNDRProxy = 1
+MarshalStorage = 1
+TIDAndLID = 1
+CrossThread = 1
+NoPing = 1
+PSClsid = 1
+PSClsid2 = 1
+
+
+;
+; Run Selected Marshal Tests
+;
+
+;[Marshal Test]
+Aggregate = 0
+CreateRemoteHandler = 0
+StorageDiffMachine = 0
+Rundown = 0
+Async = 0
+
+GetStandardMarshal = 0
+Format = 0
+GetIIDFromMI = 0
+MarshalSizeMax = 0
+LocalInterfaceNormal = 0
+UniqueQIPointer = 0
+LocalInterfaceTableStrong = 0
+LocalInterfaceTableWeak = 0
+UnmarshalGUIDNULL = 0
+UnmarshalDifferentIID = 0
+RemoteInterfaceNormal = 0
+RemoteInterfaceTableStrong = 0
+CustomMarshalNormal = 0
+CustomMarshalTable = 0
+Echo = 0
+MultiQINormal = 0
+MultiQIHandler = 0
+Handler = 0
+Loop = 0
+LockObjectExternal = 0
+DisconnectObject = 0
+ReleaseMarshalData = 0
+MiddleMan = 1
+LocalDiffMachine = 0
+RemoteDiffMachine = 0
+ExpiredOXIDs = 0
+NonNDRProxy = 0
+MarshalStorage = 0
+TIDAndLID = 0
+CrossThread = 0
+NoPing = 0
+PSClsid = 0
+PSClsid2 = 0
diff --git a/private/oleutest/balls/client/tmarshal/tunk.cxx b/private/oleutest/balls/client/tmarshal/tunk.cxx
new file mode 100644
index 000000000..e236c64a5
--- /dev/null
+++ b/private/oleutest/balls/client/tmarshal/tunk.cxx
@@ -0,0 +1,482 @@
+
+
+#include <windows.h>
+#include <ole2.h>
+#include <stdio.h>
+#include <tunk.h>
+
+
+CTestUnk::CTestUnk(void) : _cRefs(1)
+{
+}
+
+CTestUnk::~CTestUnk(void)
+{
+}
+
+
+STDMETHODIMP CTestUnk::QueryInterface(REFIID riid, LPVOID FAR* ppvObj)
+{
+ HRESULT hRslt = S_OK;
+
+ if (IsEqualIID(riid, IID_IUnknown) ||
+ IsEqualIID(riid, IID_IParseDisplayName))
+ {
+ *ppvObj = (void *)(IParseDisplayName *)this;
+ AddRef();
+ }
+ else if (IsEqualIID(riid, IID_ICube))
+ {
+ *ppvObj = (void *) new CTestUnkCube((IUnknown *)(IParseDisplayName *)this);
+ if (*ppvObj == NULL)
+ {
+ hRslt = E_NOINTERFACE;
+ }
+ }
+ else if (IsEqualIID(riid, IID_IOleWindow))
+ {
+ *ppvObj = (void *)(IOleWindow *)this;
+ AddRef();
+ }
+ else if (IsEqualIID(riid, IID_IAdviseSink))
+ {
+ *ppvObj = (void *)(IAdviseSink *)this;
+ AddRef();
+ }
+ else
+ {
+ *ppvObj = NULL;
+ hRslt = E_NOINTERFACE;
+ }
+
+ return hRslt;
+}
+
+
+
+STDMETHODIMP_(ULONG) CTestUnk::AddRef(void)
+{
+ _cRefs++;
+ return _cRefs;
+}
+
+
+STDMETHODIMP_(ULONG) CTestUnk::Release(void)
+{
+ _cRefs--;
+ if (_cRefs == 0)
+ {
+ delete this;
+ return 0;
+ }
+ else
+ {
+ return _cRefs;
+ }
+}
+
+
+STDMETHODIMP CTestUnk::ParseDisplayName(LPBC pbc, LPOLESTR lpszDisplayName,
+ ULONG *pchEaten, LPMONIKER *ppmkOut)
+{
+ return S_OK;
+}
+
+STDMETHODIMP CTestUnk::GetWindow(HWND *phwnd)
+{
+ *phwnd = NULL;
+ return S_OK;
+}
+
+STDMETHODIMP CTestUnk::ContextSensitiveHelp(BOOL fEnterMode)
+{
+ return S_OK;
+}
+
+STDMETHODIMP_(void) CTestUnk::OnDataChange(FORMATETC *pFormatetc,
+ STGMEDIUM *pStgmed)
+{
+ return;
+}
+
+STDMETHODIMP_(void) CTestUnk::OnViewChange(DWORD dwAspect,
+ LONG lindex)
+{
+ return;
+}
+
+STDMETHODIMP_(void) CTestUnk::OnRename(IMoniker *pmk)
+{
+ return;
+}
+
+STDMETHODIMP_(void) CTestUnk::OnSave()
+{
+ return;
+}
+
+STDMETHODIMP_(void) CTestUnk::OnClose()
+{
+ return;
+}
+
+
+
+CTestUnkCube::CTestUnkCube(IUnknown *pUnkCtrl) :
+ _cRefs(1),
+ _pUnkCtrl(pUnkCtrl),
+ _pUnkIn(NULL)
+{
+ _pUnkCtrl->AddRef();
+}
+
+CTestUnkCube::~CTestUnkCube(void)
+{
+ _pUnkCtrl->Release();
+}
+
+
+STDMETHODIMP CTestUnkCube::QueryInterface(REFIID riid, LPVOID FAR* ppvObj)
+{
+ return _pUnkCtrl->QueryInterface(riid, ppvObj);
+}
+
+
+
+STDMETHODIMP_(ULONG) CTestUnkCube::AddRef(void)
+{
+ _cRefs++;
+ return _cRefs;
+}
+
+
+STDMETHODIMP_(ULONG) CTestUnkCube::Release(void)
+{
+ _cRefs--;
+ if (_cRefs == 0)
+ {
+ delete this;
+ return 0;
+ }
+ else
+ {
+ return _cRefs;
+ }
+}
+
+
+// these methods dont really have to do anything, we are just testing that
+// they are callable.
+
+STDMETHODIMP CTestUnkCube::MoveCube(ULONG xPos, ULONG yPos)
+{
+ if (_cRefs > 0)
+ return S_OK;
+
+ return E_UNEXPECTED;
+}
+
+STDMETHODIMP CTestUnkCube::GetCubePos(ULONG *xPos, ULONG *yPos)
+{
+ if (_cRefs > 0)
+ return S_OK;
+
+ return E_UNEXPECTED;
+}
+
+STDMETHODIMP CTestUnkCube::Contains(IBalls *pIFDb)
+{
+ if (_cRefs > 0)
+ return S_OK;
+
+ return E_UNEXPECTED;
+}
+
+STDMETHODIMP CTestUnkCube::SimpleCall(DWORD pidCaller, DWORD tidCaller, GUID lidCaller)
+{
+ HRESULT hr = S_OK;
+
+ GUID lid;
+ HRESULT hr2 = CoGetCurrentLogicalThreadId(&lid);
+
+ if (SUCCEEDED(hr2))
+ {
+ if (!IsEqualGUID(lid, lidCaller))
+ {
+ // LIDs dont match, error
+ hr |= 0x80000001;
+ }
+ }
+ else
+ {
+ return hr2;
+ }
+
+ DWORD tid;
+ hr2 = CoGetCallerTID(&tid);
+
+ if (SUCCEEDED(hr2))
+ {
+ if (pidCaller == GetCurrentProcessId())
+ {
+ // if in same process, CoGetCallerTID should return S_OK
+ if (hr2 != S_OK)
+ {
+ hr |= 0x80000002;
+ }
+ }
+ else
+ {
+ // if in different process, CoGetCallerTID should return S_FALSE
+ if (hr2 != S_FALSE)
+ {
+ hr |= 0x80000004;
+ }
+ }
+ }
+ else
+ {
+ return hr2;
+ }
+
+ return hr;
+}
+
+STDMETHODIMP CTestUnkCube::PrepForInputSyncCall(IUnknown *pUnkIn)
+{
+ // just remember the input ptr
+
+ _pUnkIn = pUnkIn;
+ _pUnkIn->AddRef();
+
+ return S_OK;
+}
+
+STDMETHODIMP CTestUnkCube::InputSyncCall()
+{
+ // just attempt to release an Interface Pointer inside an InputSync
+ // method.
+
+ if (_pUnkIn)
+ {
+ if (_pUnkIn->Release() != 0)
+ return RPC_E_CANTCALLOUT_ININPUTSYNCCALL;
+ }
+
+ return S_OK;
+}
+
+//+-------------------------------------------------------------------
+//
+// Member: CTestUnkCF::CTestUnkCF, public
+//
+// Algorithm:
+//
+// History: 23-Nov-92 Rickhi Created
+//
+//--------------------------------------------------------------------
+CTestUnkCF::CTestUnkCF()
+{
+ _cRefs = 1;
+}
+
+//+-------------------------------------------------------------------
+//
+// Member: CTestUnkCF::QueryInterface, public
+//
+// Algorithm: if the interface is not one implemented by us,
+// pass the request to the proxy manager
+//
+// History: 23-Nov-92 Rickhi Created
+//
+//--------------------------------------------------------------------
+STDMETHODIMP CTestUnkCF::QueryInterface(REFIID riid, void **ppUnk)
+{
+ if (IsEqualIID(riid, IID_IUnknown) ||
+ IsEqualIID(riid, IID_IClassFactory))
+ {
+ *ppUnk = (void *)(IClassFactory *) this;
+ AddRef();
+ return S_OK;
+ }
+
+ *ppUnk = NULL;
+ return E_NOINTERFACE;
+}
+
+STDMETHODIMP_(ULONG) CTestUnkCF::AddRef(void)
+{
+ _cRefs++;
+ return _cRefs;
+}
+
+
+STDMETHODIMP_(ULONG) CTestUnkCF::Release(void)
+{
+ _cRefs--;
+ if (_cRefs == 0)
+ {
+ delete this;
+ return 0;
+ }
+
+ return _cRefs;
+}
+
+//+-------------------------------------------------------------------
+//
+// Member: CTestUnkCF::CreateInstance, public
+//
+// Synopsis: create a new object with the same class
+//
+// History: 23-Nov-92 Rickhi Created
+//
+//--------------------------------------------------------------------
+STDMETHODIMP CTestUnkCF::CreateInstance(IUnknown *punkOuter,
+ REFIID riid,
+ void **ppunkObject)
+{
+ SCODE sc = E_OUTOFMEMORY;
+ *ppunkObject = NULL; // in case of failure
+
+ // create an instance object.
+ IUnknown *punk = (IUnknown *)(IParseDisplayName *) new CTestUnk();
+
+ if (punk)
+ {
+ // get the interface the caller wants to use
+ sc = punk->QueryInterface(riid, ppunkObject);
+
+ // release our hold, since the QI got a hold for the client.
+ punk->Release();
+ }
+
+ return sc;
+}
+
+//+-------------------------------------------------------------------
+//
+// Member: CTestUnkCF::LockServer, public
+//
+// Synopsis:
+//
+// History: 23-Nov-92 Rickhi Created
+//
+//--------------------------------------------------------------------
+STDMETHODIMP CTestUnkCF::LockServer(BOOL fLock)
+{
+ return S_OK;
+}
+
+
+
+CTestUnkMarshal::CTestUnkMarshal(void) : _cRefs(1), _pIM(NULL)
+{
+}
+
+CTestUnkMarshal::~CTestUnkMarshal(void)
+{
+ if (_pIM)
+ {
+ _pIM->Release();
+ }
+}
+
+STDMETHODIMP CTestUnkMarshal::QueryInterface(REFIID riid, LPVOID FAR* ppvObj)
+{
+ HRESULT hRslt = S_OK;
+
+ if (IsEqualIID(riid, IID_IUnknown) ||
+ IsEqualIID(riid, IID_IMarshal))
+ {
+ *ppvObj = (void *)(IMarshal *)this;
+ AddRef();
+ }
+ else
+ {
+ *ppvObj = NULL;
+ hRslt = E_NOINTERFACE;
+ }
+
+ return hRslt;
+}
+
+STDMETHODIMP_(ULONG) CTestUnkMarshal::AddRef(void)
+{
+ _cRefs++;
+ return _cRefs;
+}
+
+STDMETHODIMP_(ULONG) CTestUnkMarshal::Release(void)
+{
+ _cRefs--;
+ if (_cRefs == 0)
+ {
+ delete this;
+ return 0;
+ }
+ else
+ {
+ return _cRefs;
+ }
+}
+
+STDMETHODIMP CTestUnkMarshal::GetUnmarshalClass(REFIID riid, LPVOID pv,
+ DWORD dwDestCtx, LPVOID pvDestCtx, DWORD mshlflags, LPCLSID pClsid)
+{
+ if (GetStdMarshal() == NULL)
+ return E_OUTOFMEMORY;
+
+ return _pIM->GetUnmarshalClass(riid, pv, dwDestCtx, pvDestCtx,
+ (mshlflags | MSHLFLAGS_NOPING), pClsid);
+}
+
+STDMETHODIMP CTestUnkMarshal::GetMarshalSizeMax(REFIID riid, LPVOID pv,
+ DWORD dwDestCtx, LPVOID pvDestCtx, DWORD mshlflags, LPDWORD pSize)
+{
+ if (GetStdMarshal() == NULL)
+ return E_OUTOFMEMORY;
+
+ return _pIM->GetMarshalSizeMax(riid, pv, dwDestCtx, pvDestCtx,
+ (mshlflags | MSHLFLAGS_NOPING), pSize);
+}
+
+STDMETHODIMP CTestUnkMarshal::MarshalInterface(LPSTREAM pStm, REFIID riid,
+ LPVOID pv, DWORD dwDestCtx, LPVOID pvDestCtx, DWORD mshlflags)
+{
+ if (GetStdMarshal() == NULL)
+ return E_OUTOFMEMORY;
+
+ return _pIM->MarshalInterface(pStm, riid, pv, dwDestCtx, pvDestCtx,
+ (mshlflags | MSHLFLAGS_NOPING));
+}
+
+STDMETHODIMP CTestUnkMarshal::UnmarshalInterface(LPSTREAM pStm, REFIID riid,
+ LPVOID *ppv)
+{
+ return CoUnmarshalInterface(pStm, riid, ppv);
+}
+
+STDMETHODIMP CTestUnkMarshal::ReleaseMarshalData(LPSTREAM pStm)
+{
+ return CoReleaseMarshalData(pStm);
+}
+
+STDMETHODIMP CTestUnkMarshal::DisconnectObject(DWORD dwReserved)
+{
+ if (GetStdMarshal() == NULL)
+ return E_OUTOFMEMORY;
+
+ return _pIM->DisconnectObject(dwReserved);
+}
+
+IMarshal *CTestUnkMarshal::GetStdMarshal(void)
+{
+ if (_pIM == NULL)
+ {
+ HRESULT hr = CoGetStandardMarshal(IID_IUnknown, (IUnknown *)this, 0,
+ 0, MSHLFLAGS_NOPING, &_pIM);
+ }
+
+ return _pIM;
+}
diff --git a/private/oleutest/balls/client/tmarshal/tunk.h b/private/oleutest/balls/client/tmarshal/tunk.h
new file mode 100644
index 000000000..333f580db
--- /dev/null
+++ b/private/oleutest/balls/client/tmarshal/tunk.h
@@ -0,0 +1,130 @@
+#ifndef _TUNK_
+#define _TUNK_
+
+STDAPI CoGetCallerTID(DWORD *pTIDCaller);
+STDAPI CoGetCurrentLogicalThreadId(GUID *pguid);
+
+#include <icube.h>
+
+class CTestUnk : public IParseDisplayName, public IOleWindow,
+ public IAdviseSink
+{
+public:
+ CTestUnk(void);
+
+ // IUnknown
+ STDMETHOD(QueryInterface)(REFIID iid, void FAR * FAR * ppv);
+ STDMETHOD_(ULONG, AddRef)(void);
+ STDMETHOD_(ULONG, Release)(void);
+
+ // IParseDisplayName
+ STDMETHODIMP ParseDisplayName(LPBC pbc, LPOLESTR lpszDisplayName,
+ ULONG *pchEaten, LPMONIKER *ppmkOut);
+
+ // IOleWinodw methods
+ STDMETHODIMP GetWindow(HWND *phwnd);
+ STDMETHODIMP ContextSensitiveHelp(BOOL fEnterMode);
+
+
+ // IAdviseSink
+ STDMETHOD_(void, OnDataChange)(FORMATETC *pFormatetc,
+ STGMEDIUM *pStgmed);
+ STDMETHOD_(void, OnViewChange)(DWORD dwAspect,
+ LONG lindex);
+ STDMETHOD_(void, OnRename)(IMoniker *pmk);
+ STDMETHOD_(void, OnSave)();
+ STDMETHOD_(void, OnClose)();
+
+private:
+
+ ~CTestUnk(void);
+
+ ULONG _cRefs;
+};
+
+
+// A new instance of this object gets created each time the caller
+// does a QI for ICube on the CTestUnk object above (or on the ICube
+// interface iteself). The reason for this is to test that the remoting
+// layer supports this capability correctly.
+
+class CTestUnkCube : public ICube
+{
+public:
+ CTestUnkCube(IUnknown *pUnkCtrl);
+
+ // IUnknown
+ STDMETHODIMP QueryInterface(REFIID iid, void FAR * FAR * ppv);
+ STDMETHODIMP_(ULONG) AddRef(void);
+ STDMETHODIMP_(ULONG) Release(void);
+
+ // ICube implementation
+ STDMETHODIMP MoveCube(ULONG xPos, ULONG yPos);
+ STDMETHODIMP GetCubePos(ULONG *xPos, ULONG *yPos);
+ STDMETHODIMP Contains(IBalls *pIFDb);
+ STDMETHODIMP SimpleCall(DWORD pid, DWORD tid, GUID lidCaller);
+ STDMETHODIMP PrepForInputSyncCall(IUnknown *pUnkIn);
+ STDMETHODIMP InputSyncCall();
+
+private:
+
+ ~CTestUnkCube(void);
+
+ ULONG _cRefs;
+ IUnknown *_pUnkCtrl;
+ IUnknown *_pUnkIn;
+};
+
+
+class CTestUnkCF : public IClassFactory
+{
+public:
+ CTestUnkCF(void);
+
+ // IUnknown
+ STDMETHODIMP QueryInterface(REFIID iid, void FAR * FAR * ppv);
+ STDMETHODIMP_(ULONG) AddRef(void);
+ STDMETHODIMP_(ULONG) Release(void);
+
+ // IClassFactory
+ STDMETHOD(CreateInstance)(IUnknown *punkOuter,
+ REFIID riid,
+ void **ppunkObject);
+ STDMETHOD(LockServer)(BOOL fLock);
+
+private:
+ ULONG _cRefs;
+};
+
+
+class CTestUnkMarshal : public IMarshal
+{
+public:
+ CTestUnkMarshal(void);
+
+ // IUnknown
+ STDMETHODIMP QueryInterface(REFIID iid, void FAR * FAR * ppv);
+ STDMETHODIMP_(ULONG) AddRef(void);
+ STDMETHODIMP_(ULONG) Release(void);
+
+ // IMarshal - IUnknown taken from derived classes
+ STDMETHOD(GetUnmarshalClass)(REFIID riid, LPVOID pv, DWORD dwDestCtx,
+ LPVOID pvDestCtx, DWORD mshlflags, LPCLSID pClsid);
+ STDMETHOD(GetMarshalSizeMax)(REFIID riid, LPVOID pv, DWORD dwDestCtx,
+ LPVOID pvDestCtx, DWORD mshlflags, LPDWORD pSize);
+ STDMETHOD(MarshalInterface)(LPSTREAM pStm, REFIID riid, LPVOID pv,
+ DWORD dwDestCtx, LPVOID pvDestCtx, DWORD mshlflags);
+ STDMETHOD(UnmarshalInterface)(LPSTREAM pStm, REFIID riid, LPVOID *ppv);
+ STDMETHOD(ReleaseMarshalData)(LPSTREAM pStm);
+ STDMETHOD(DisconnectObject)(DWORD dwReserved);
+
+private:
+
+ IMarshal *GetStdMarshal(void);
+ ~CTestUnkMarshal(void);
+
+ ULONG _cRefs;
+ IMarshal *_pIM;
+};
+
+#endif // _TUNK_
diff --git a/private/oleutest/balls/coffbase.txt b/private/oleutest/balls/coffbase.txt
new file mode 100644
index 000000000..58676b202
--- /dev/null
+++ b/private/oleutest/balls/coffbase.txt
@@ -0,0 +1,456 @@
+;
+; This file defines the base virtual address for Dynamic Link Libraries (DLL)
+; that are part of the NT OS/2 System. The first token on a line is the name
+; of the DLL and the second token is the base virtual address, in hexidecimal.
+; The third token is the maximum size of the DLL image file, including symbols.
+;
+
+usermode 0x00010000 0x60000000
+
+
+;
+; This section lists all the Cairo DLL's. Until we merge with the NT
+; group, limit yourself to the range 0x10000000 - 0x20000000.
+;
+
+cardf 0x10000000 0x00200000
+eventsys 0x10200000 0x00200000
+commnot 0x10400000 0x00200000
+cryptdll 0x10600000 0x00200000
+demoif 0x10800000 0x00200000
+menuedt 0x10a00000 0x00200000
+dfsm 0x10c00000 0x00200000
+clockctl 0x10e00000 0x00200000
+calendar 0x11000000 0x00200000
+report 0x11200000 0x00200000
+desk 0x11400000 0x00200000
+filter 0x11600000 0x00200000
+datetime 0x11800000 0x00200000
+dtsrv 0x11a00000 0x00200000
+iclass 0x11c00000 0x00200000
+dfsinit 0x11e00000 0x00200000
+cpshare 0x12000000 0x00200000
+iprod 0x12200000 0x00200000
+kerberos 0x12400000 0x00200000
+kerbsupp 0x12600000 0x00200000
+applet1 0x12800000 0x00200000
+cairocpl 0x12a00000 0x00200000
+cpo 0x12c00000 0x00200000
+deskapp 0x12e00000 0x00200000
+ntlm 0x13000000 0x00200000
+objsrv 0x13200000 0x00200000
+ole2 0x13400000 0x00200000
+lnktrack 0x13600000 0x00200000
+pocket 0x13800000 0x00200000
+dsfsmsgs 0x13a00000 0x00200000
+stemdll 0x13c00000 0x00200000
+propset 0x13e00000 0x00200000
+prsht 0x14000000 0x00200000
+bmpctl 0x14200000 0x00200000
+spintime 0x14400000 0x00200000
+grpbox 0x14600000 0x00200000
+security 0x14800000 0x00200000
+
+; uofs needs two slots worth:
+uofs 0x14a00000 0x00400000
+;uofs 0x14c00000 0x00200000
+
+; Query needs four slots worth:
+query 0x14e00000 0x00800000
+;query 0x15000000 0x00200000
+;query 0x15200000 0x00200000
+;query 0x15400000 0x00200000
+
+;unused 0x15600000 0x00200000
+dafs 0x15800000 0x00200000
+dahard 0x15a00000 0x00200000
+stdobj 0x15c00000 0x00200000
+csumcat 0x15e00000 0x00200000
+sysmgmt 0x16000000 0x00200000
+cpdskadm 0x16200000 0x00200000
+idfsvol 0x16400000 0x00200000
+testdll 0x16600000 0x00400000
+cap 0x16a00000 0x00200000
+sysinf 0x16c00000 0x00200000
+shtypes 0x16e00000 0x00200000
+shexplor 0x17000000 0x00300000
+popups 0x17300000 0x00100000
+replsup 0x17400000 0x00200000
+schema 0x17700000 0x00200000
+useragnt 0x18000000 0x00200000
+vpcont 0x18200000 0x00200000
+uares 0x18400000 0x00200000
+rndrevrp 0x18600000 0x00200000
+pdfpage 0x18800000 0x00200000
+pkgpage 0x18a00000 0x00200000
+package 0x18e00000 0x00200000
+pdf 0x19000000 0x00200000
+dsys 0x19200000 0x00200000
+dfssetup 0x19400000 0x00200000
+dfsinstr 0x19600000 0x00200000
+lprofile 0x19800000 0x00200000
+ole232 0x19a00000 0x00400000
+compob32 0x19e00000 0x00400000
+docfile 0x1a200000 0x00400000
+tlib34 0x1a600000 0x00200000
+storage 0x1aa00000 0x00600000
+ole2pr32 0x1b000000 0x00500000
+piballs 0x1b500000 0x00100000
+testext 0x1b600000 0x00200000
+loghrs 0x1b800000 0x00100000
+scstg 0x1b900000 0x00100000
+smoke 0x1ba00000 0x00100000
+shview 0x1bc00000 0x00200000
+shtcmcli 0x1be00000 0x00200000
+shdebug 0x1c000000 0x00200000
+shell232 0x1c200000 0x00200000
+shhdlr 0x1c400000 0x00200000
+shprop 0x1c600000 0x00200000
+shtcmsrv 0x1c800000 0x00200000
+spincube 0x1ca00000 0x00200000
+
+; Repl dlls
+chglogdb 0x1cc00000 0x00100000
+dumyrclr 0x1cd00000 0x00100000
+flatrst 0x1ce00000 0x00100000
+lastwins 0x1cf00000 0x00100000
+ofsrs 0x1d000000 0x00100000
+ora 0x1d100000 0x00100000
+orarcnlr 0x1d200000 0x00100000
+replui 0x1d300000 0x00100000
+roschlog 0x1d400000 0x00100000
+rsmgr 0x1d500000 0x00100000
+dsobjs 0x1d600000 0x00200000
+account 0x1d800000 0x00200000
+rcon 0x1da00000 0x00100000
+robj 0x1db00000 0x00100000
+rset 0x1dc00000 0x00100000
+chgp 0x1dd00000 0x00100000
+
+; Old Forms DLLs
+
+form 0x1e000000 0x00200000
+formctls 0x1e200000 0x00200000
+crstdctl 0x1e400000 0x00200000
+formtoc 0x1e600000 0x00200000
+proppage 0x1e800000 0x00100000
+timing 0x1e900000 0x00100000
+
+;RTO dlls
+rtfdisp 0x1eA00000 0x00200000
+rtfmle 0x1eC00000 0x00200000
+webcore 0x1eE00000 0x00200000
+rtfdoc 0x1f000000 0x00200000
+ctlrto 0x1f200000 0x00200000
+
+shctrls 0x1f400000 0x00600000
+shfx 0x1fa00000 0x00100000
+shcommon 0x1fb00000 0x00300000
+shtaskhk 0x1fe00000 0x00100000
+
+;
+smss 0x20000000 0x40000000
+dbgss 0x30000000 0x30000000
+csrss 0x40000000 0x20000000
+os2ss 0x40000000 0x20000000
+psxss 0x40000000 0x20000000
+cmd 0x50000000 0x10000000
+ntdll 0x60100000 0x00100000
+dbgdll 0x60200000 0x00100000
+csr 0x60300000 0x00100000
+csrrtl 0x60400000 0x00100000
+csrsrv 0x60500000 0x00100000
+kernel32 0x60600000 0x00100000
+basertl 0x60700000 0x00100000
+basesrv 0x60800000 0x00100000
+consrv 0x60900000 0x00100000
+console 0x60A00000 0x00100000
+user32 0x60B00000 0x00200000
+gdi32 0x60D00000 0x00100000
+gdisrv 0x60E00000 0x00200000
+jazz 0x61000000 0x00100000
+gre 0x61100000 0x00200000
+rasdd 0x61300000 0x00100000
+sysmono 0x61400000 0x00100000
+courier 0x61500000 0x00100000
+helv 0x61600000 0x00100000
+times 0x61700000 0x00100000
+netapi32 0x61800000 0x00200000
+winmgr 0x62100000 0x00100000
+display 0x62200000 0x00100000
+vga 0x62200000 0x00100000
+bmfd 0x62300000 0x00100000
+ttfd 0x62400000 0x00100000
+vtfd 0x62500000 0x00100000
+winspool 0x62600000 0x00100000
+splsrv 0x62700000 0x00100000
+ntprint 0x62800000 0x00100000
+pscript 0x62900000 0x00100000
+halftone 0x62A00000 0x00100000
+lmspool 0x62B00000 0x00100000
+os2dll 0x63000000 0x00100000
+services 0x63100000 0x00100000
+psxdll 0x63200000 0x00100000
+userrtl 0x63300000 0x00100000
+winnet 0x63400000 0x00100000
+msv1_0 0x63500000 0x00100000
+samlib 0x635A0000 0x00100000
+lsaap 0x63600000 0x00100000
+netrap 0x63700000 0x00100000
+TEMPNAME2 0x63800000 0x00700000
+usersrv 0x63f00000 0x00300000
+media 0x65000000 0x00100000
+mediasrv 0x66000000 0x00100000
+canon330 0x66100000 0x00100000
+cit24us 0x66200000 0x00100000
+canon10e 0x66300000 0x00100000
+canon130 0x66400000 0x00100000
+qwiii 0x66500000 0x00100000
+citoh 0x66600000 0x00100000
+deskjet 0x66700000 0x00100000
+epson24 0x66800000 0x00100000
+epson9 0x66900000 0x00100000
+fuji24 0x66A00000 0x00100000
+fuji9 0x66B00000 0x00100000
+fujimtrx 0x66C00000 0x00100000
+hpdskjet 0x66D00000 0x00100000
+hppcl 0x66E00000 0x00100000
+ibmgrx 0x66F00000 0x00100000
+lq2500 0x67000000 0x00100000
+nec24pin 0x67100000 0x00100000
+oki24 0x67200000 0x00100000
+oki9 0x67300000 0x00100000
+oki9ibm 0x67400000 0x00100000
+paintjet 0x67500000 0x00100000
+proprint 0x67600000 0x00100000
+proprn24 0x67700000 0x00100000
+thinkjet 0x67800000 0x00100000
+ntsdexts 0x67900000 0x00100000
+plotter 0x67A00000 0x00100000
+rpcrt4 0x67B00000 0x00100000
+winmm 0x67D00000 0x00100000
+rpcssp 0x67E00000 0x00100000
+mciwave 0x67F00000 0x00100000
+rpclts1 0x68000000 0x00100000
+rpcltc1 0x68100000 0x00100000
+ldrdll 0x68200000 0x00100000
+mcicda 0x68300000 0x00100000
+plottrui 0x68400000 0x00100000
+rasddui 0x68500000 0x00100000
+pscrptui 0x68600000 0x00100000
+mmio 0x68700000 0x00100000
+rpcnts1 0x68800000 0x00100000
+rpcntc1 0x68900000 0x00100000
+nlsapi 0x68A00000 0x00100000
+ibm5204 0x68B00000 0x00100000
+ti850 0x68C00000 0x00100000
+olesvr32 0x68D00000 0x00100000
+olecli32 0x68E00000 0x00100000
+diconix 0x68F00000 0x00100000
+fscaler 0x69000000 0x00100000
+sys003 0x69100000 0x00100000
+cit9us 0x69200000 0x00100000
+escp2 0x69300000 0x00100000
+execjet 0x69400000 0x00100000
+panson24 0x69500000 0x00100000
+panson9 0x69600000 0x00100000
+ps1 0x69700000 0x00100000
+toshiba 0x69800000 0x00100000
+thinkjet 0x69900000 0x00100000
+svcctrl 0x69A00000 0x00100000
+xactsrv 0x69B00000 0x00100000
+winreg 0x69C00000 0x00100000
+samsrv 0x69D00000 0x00100000
+mmdrv 0x69F00000 0x00100000
+dlcapi 0x6A000000 0x00100000
+win32spl 0x6A100000 0x00100000
+localspl 0x6A200000 0x00100000
+rpclts5 0x6A300000 0x00100000
+rpcltc5 0x6A400000 0x00100000
+netlogon 0x6A500000 0x00200000
+tmsre32 0x6A600000 0x00100000
+lsaudll 0x6A700000 0x00100000
+mciseq 0x6A800000 0x00100000
+winprint 0x6A900000 0x00100000
+localmon 0x6AA00000 0x00100000
+msaudite 0x6AB00000 0x00100000
+msauditt 0x6AC00000 0x00100000
+hpmon 0x6AD00000 0x00100000
+alrsvc 0x6AE00000 0x00100000
+srvsvc 0x6AF00000 0x00100000
+wkssvc 0x6B000000 0x00100000
+xssvc 0x6B100000 0x00100000
+rpclts3 0x6B200000 0x00100000
+rpcltc3 0x6B300000 0x00100000
+htui 0x6B400000 0x00100000
+lsasrv 0x6B500000 0x00100000
+mmsndsrv 0x6B600000 0x00100000
+midi 0x6B700000 0x00100000
+bowsvc 0x6B800000 0x00100000
+drivers 0x6B900000 0x00100000
+lmmon 0x6BA00000 0x00100000
+
+; RTO Toolbar dlls
+
+hyprgzmo 0x6BB00000 0x00100000
+hyprbttn 0x6BC00000 0x00100000
+
+;
+; The following is an extension for NTSD which traces memory usage in the
+; ULIB utilities...
+;
+memtrace 0x6BF00000 0x00100000
+
+; shell
+
+shamu 0x6C000000 0x00800000
+
+; CD Forms
+
+formkrnl 0x6C800000 0x00200000
+cdform2c 0x6CA00000 0x00200000
+cdproppg 0x6CC00000 0x00200000
+basectrl 0x6CE00000 0x00200000
+cdctrls 0x6D000000 0x00200000
+cdbase 0x6D200000 0x00200000
+
+; Win32 shell apps/dlls
+
+control 0x70000000 0x00100000
+color 0x70100000 0x00100000
+sound 0x70200000 0x00100000
+ports 0x70300000 0x00100000
+intl 0x70400000 0x00100000
+date 0x70500000 0x00100000
+mouse 0x70600000 0x00100000
+keybd 0x70700000 0x00100000
+desktop 0x70800000 0x00100000
+fonts 0x70900000 0x00100000
+security 0x70A00000 0x00100000
+main 0x70B00000 0x00100000
+ups 0x70C00000 0x00100000
+
+; Win32 National Keyboard Layers
+
+kbdbe 0x72000000 0x00100000
+kbdca 0x72100000 0x00100000
+kbdda 0x72200000 0x00100000
+kbddv 0x72300000 0x00100000
+kbdes 0x72400000 0x00100000
+kbdfc 0x72500000 0x00100000
+kbdfr 0x72600000 0x00100000
+kbdfs 0x72700000 0x00100000
+kbdgr 0x72800000 0x00100000
+kbdic 0x72900000 0x00100000
+kbdit 0x72A00000 0x00100000
+kbdla 0x72B00000 0x00100000
+kbdne 0x72C00000 0x00100000
+kbdno 0x72D00000 0x00100000
+kbdpo 0x72E00000 0x00100000
+kbdsf 0x72F00000 0x00100000
+kbdsg 0x73000000 0x00100000
+kbdsp 0x73100000 0x00100000
+kbduk 0x73200000 0x00100000
+kbdus 0x73300000 0x00100000
+kbdusx 0x73400000 0x00100000
+
+;
+; The following is not currently used until we switch to the new image
+; format with the new section headers.
+;
+executive 0xD0020000 0x18000000
+
+
+
+
+
+;
+; The following are the Mep extensions
+;
+tglcase 0x09080000 0x00100000
+pmatch 0x09090000 0x00100000
+justify 0x090a0000 0x00100000
+ulcase 0x090b0000 0x00100000
+filter 0x090c0000 0x00100000
+mhelp 0x090d0000 0x00100000
+mepparty 0x090e0000 0x00100000
+srmep 0x090f0000 0x00100000
+mshelp 0x09100000 0x00100000
+mbrowse 0x09110000 0x00100000
+
+
+
+;
+; The following are for the utilities
+;
+ulib 0x09800000 0x00200000
+uhpfs 0x09a10000 0x00100000
+ufat 0x09b20000 0x00100000
+untfs 0x09c30000 0x00100000
+ifsutil 0x09d40000 0x00100000
+cufat 0x09e50000 0x00100000
+cuhpfs 0x09f60000 0x00100000
+fmifs 0x0a070000 0x00100000
+uspifs 0x0a180000 0x00100000
+
+;
+; The following are for the net error messages
+;
+netmsg 0x09600000 0x00080000
+neth 0x09680000 0x00080000
+netevent 0x09700000 0x00080000
+
+;
+; The following is the I/O error log messages.
+;
+iologmsg 0x09700000 0x00080000
+
+;
+; The following is for the 16-bit loader for the OS/2 subsystem
+;
+loader 0x20000000 0x01000000
+
+;
+; The following is for the Streams/Sockets dll's
+;
+winsock 0x75000000 0x00200000
+winstrm 0x75200000 0x00100000
+sockutil 0x75300000 0x00100000
+resolver 0x75400000 0x00100000
+inetmib1 0x75500000 0x00100000
+lmmib2 0x75600000 0x00100000
+tcpipsvc 0x75700000 0x00100000
+nbtsvc 0x75800000 0x00100000
+
+;
+; The following are for the windowed debugger (windbg)
+;
+
+eecan 0x40000000 0x00200000
+em 0x48000000 0x00200000
+shcoff 0x50000000 0x00200000
+shcv 0x58000000 0x00200000
+tlloc 0x60000000 0x00200000
+
+;
+; The following are for the NetUI components.
+;
+
+acledit 0x76000000 0x00100000
+mprmain 0x76100000 0x00100000
+ntlanman 0x76200000 0x00100000
+srvmgr 0x76300000 0x00100000
+ncpa 0x76400000 0x00100000
+
+;
+; The following are for OFS Utilities (CONVERT and REPART)
+;
+ofsutil 0x76600000 0x00400000
+fmtmnofs 0x77000000 0x00200000
+cfrtulib 0x77200000 0x00100000
+
+;
+; User object property pages.
+;
+
+user_ui 0x73000000 0x00400000
diff --git a/private/oleutest/balls/common/actcf.cxx b/private/oleutest/balls/common/actcf.cxx
new file mode 100644
index 000000000..371bf0c5a
--- /dev/null
+++ b/private/oleutest/balls/common/actcf.cxx
@@ -0,0 +1,133 @@
+//+-------------------------------------------------------------------
+//
+// File: actcf.cxx
+//
+// Contents: object activation test class factory
+//
+// Classes: CActClassFactory
+//
+// Functions:
+//
+// History: 23-Nov-92 Ricksa Created
+//
+//--------------------------------------------------------------------
+
+#include <pch.cxx>
+#pragma hdrstop
+#include <actcf.hxx> // CActClassFactory
+#include <cact.hxx> // CTestAct
+
+
+
+const GUID CLSID_TestSingleUse =
+ {0x99999999,0x0000,0x0008,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x50}};
+
+const GUID CLSID_TestMultipleUse =
+ {0x99999999,0x0000,0x0008,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x51}};
+
+const GUID CLSID_DistBind =
+ {0x99999999,0x0000,0x0008,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x55}};
+
+
+
+
+
+CActClassFactory::CActClassFactory(REFCLSID rclsid, BOOL fServer)
+ : _fServer(fServer), _clsid(rclsid), _cRefs(1), _cLocks(0)
+{
+ // Header does all the work
+}
+
+CActClassFactory::~CActClassFactory()
+{
+ // Default actions are enough
+}
+
+
+STDMETHODIMP CActClassFactory::QueryInterface(REFIID iid, void FAR * FAR * ppv)
+{
+ if (IsEqualIID(iid, IID_IUnknown) ||
+ IsEqualIID(iid, IID_IClassFactory))
+ {
+ *ppv = (IUnknown *) this;
+ AddRef();
+ return S_OK;
+ }
+
+ *ppv = NULL;
+ return E_NOINTERFACE;
+}
+
+STDMETHODIMP_(ULONG) CActClassFactory::AddRef(void)
+{
+ InterlockedIncrement(&_cRefs);
+
+ if (!_fServer)
+ {
+ // This is not being used in a server so we want to bump the
+ // reference count. In a server we use the lock count rather
+ // than the reference count to tell whether we should go away.
+ GlobalRefs(TRUE);
+ }
+
+ return _cRefs;
+}
+
+STDMETHODIMP_(ULONG) CActClassFactory::Release(void)
+{
+ BOOL fKeepObject = InterlockedDecrement(&_cRefs);
+
+ if (!_fServer)
+ {
+ // This is not being used in a server so we want to bump the
+ // reference count. In a server we use the lock count rather
+ // than the reference count to tell whether we should go away.
+ GlobalRefs(FALSE);
+ }
+
+ if (!fKeepObject)
+ {
+ delete this;
+ return 0;
+ }
+
+ return _cRefs;
+}
+
+STDMETHODIMP CActClassFactory::CreateInstance(
+ IUnknown FAR* pUnkOuter,
+ REFIID iidInterface,
+ void FAR* FAR* ppv)
+{
+ if (pUnkOuter != NULL)
+ {
+ // Object does not support aggregation
+ return E_NOINTERFACE;
+ }
+
+ CTestAct *ptballs = new CTestAct(_clsid);
+
+ HRESULT hr = ptballs->QueryInterface(iidInterface, ppv);
+
+ ptballs->Release();
+
+ return hr;
+}
+
+STDMETHODIMP CActClassFactory::LockServer(BOOL fLock)
+{
+ if (fLock)
+ {
+ InterlockedIncrement(&_cLocks);
+
+ GlobalRefs(TRUE);
+ }
+ else
+ {
+ InterlockedDecrement(&_cLocks);
+
+ GlobalRefs(FALSE);
+ }
+
+ return S_OK;
+}
diff --git a/private/oleutest/balls/common/actcf.hxx b/private/oleutest/balls/common/actcf.hxx
new file mode 100644
index 000000000..243b76a01
--- /dev/null
+++ b/private/oleutest/balls/common/actcf.hxx
@@ -0,0 +1,73 @@
+//+-------------------------------------------------------------------
+//
+// File: actcf.hxx
+//
+// Contents: object activation test class factory
+//
+// Classes: CActClassFactory
+//
+// Functions: None
+//
+// History: 23-Nov-92 Rickhi Created
+//
+//--------------------------------------------------------------------
+
+#ifndef __CACTCLASSFACTORY__
+#define __CACTCLASSFACTORY__
+
+#include <win4p.hxx>
+
+
+extern "C" const GUID CLSID_TestSingleUse;
+extern "C" const GUID CLSID_TestMultipleUse;
+extern "C" const GUID CLSID_DistBind;
+
+
+//+-------------------------------------------------------------------
+//
+// Class: CActClassFactory
+//
+// Purpose: object activation test class factory
+//
+// Interface:
+//
+// History: 23-Nov-92 Rickhi Created
+//
+// Notes:
+//
+//--------------------------------------------------------------------
+
+class CActClassFactory : public IClassFactory
+{
+public:
+
+ CActClassFactory(REFCLSID rclsid, BOOL fServer);
+
+ ~CActClassFactory(void);
+
+ // IUnknown
+ STDMETHOD(QueryInterface)(REFIID iid, void **ppv);
+ STDMETHOD_(ULONG, AddRef)(void);
+ STDMETHOD_(ULONG, Release)(void);
+
+
+ // IClassFactory
+ STDMETHOD(CreateInstance)(
+ IUnknown FAR* pUnkOuter,
+ REFIID riid,
+ LPVOID FAR* ppunkObject);
+
+ STDMETHOD(LockServer)(BOOL fLock);
+
+private:
+
+
+ BOOL _fServer;
+ CLSID _clsid;
+ LONG _cRefs;
+ LONG _cLocks;
+};
+
+
+
+#endif // __CACTCLASSFACTORY__
diff --git a/private/oleutest/balls/common/advbnd.cxx b/private/oleutest/balls/common/advbnd.cxx
new file mode 100644
index 000000000..161e79c1e
--- /dev/null
+++ b/private/oleutest/balls/common/advbnd.cxx
@@ -0,0 +1,442 @@
+//+-------------------------------------------------------------------
+//
+// Class: CAdvBndCF
+//
+// Synopsis: Class Factory for CAdvBnd
+//
+// Interfaces: IUnknown - QueryInterface, AddRef, Release
+// IClassFactory - CreateInstance
+//
+// History: 21-Nov-92 SarahJ Created
+//
+//--------------------------------------------------------------------
+
+#include <pch.cxx>
+#pragma hdrstop
+#include <advbnd.hxx>
+
+
+const GUID CLSID_AdvBnd =
+ {0x99999999,0x0000,0x0008,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x48}};
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CAdvBndCF::CAdvBndCF()
+//
+// Synopsis: The constructor for CAdvBnd.
+//
+// Arguments: None
+//
+// History: 21-Nov-92 SarahJ Created
+//
+//--------------------------------------------------------------------
+
+CAdvBndCF::CAdvBndCF() : _cRefs(1), _pCF(NULL)
+{
+ return;
+}
+
+//+-------------------------------------------------------------------
+//
+// Member: CAdvBnd::~CAdvBndObj()
+//
+// Synopsis: The destructor for CAdvBnd.
+//
+// History: 21-Nov-92 SarahJ Created
+//
+//--------------------------------------------------------------------
+
+CAdvBndCF::~CAdvBndCF()
+{
+ if (_pCF)
+ {
+ _pCF->Release();
+ }
+ return;
+}
+
+
+//+-------------------------------------------------------------------
+//
+// Method: CAdvBndCF::QueryInterface
+//
+// Synopsis: Only IUnknown and IClassFactory supported
+//
+//--------------------------------------------------------------------
+STDMETHODIMP CAdvBndCF::QueryInterface(REFIID iid, void FAR * FAR * ppv)
+{
+ if (IsEqualIID(iid, IID_IUnknown) ||
+ IsEqualIID(iid, IID_IClassFactory))
+ {
+ *ppv = (IUnknown *) this;
+ AddRef();
+ return S_OK;
+ }
+ else
+ {
+ *ppv = NULL;
+ return E_NOINTERFACE;
+ }
+}
+
+STDMETHODIMP_(ULONG) CAdvBndCF::AddRef(void)
+{
+ return ++_cRefs;
+}
+
+STDMETHODIMP_(ULONG) CAdvBndCF::Release(void)
+{
+ if (--_cRefs == 0)
+ {
+ delete this;
+ }
+
+ return _cRefs;
+}
+
+
+
+//+-------------------------------------------------------------------
+//
+// Method: CAdvBndCF::CreateInstance
+//
+// Synopsis: This is called by Binding process to create the
+// actual class object
+//
+//--------------------------------------------------------------------
+
+STDMETHODIMP CAdvBndCF::CreateInstance(
+ IUnknown FAR* pUnkOuter,
+ REFIID iidInterface,
+ void FAR* FAR* ppv)
+{
+ Display(TEXT("CAdvBndCF::CreateInstance called\n"));
+
+ HRESULT hresult;
+
+ if (!_pCF)
+ {
+ // Load the class object for the class to aggregate.
+ hresult = CoGetClassObject(CLSID_BasicBnd, CLSCTX_SERVER, NULL,
+ IID_IClassFactory, (void **) &_pCF);
+
+ Win4Assert(SUCCEEDED(hresult)
+ && "CAdvBnd::CAdvBnd CoGetClassObject failed");
+
+ if (FAILED(hresult))
+ {
+ return hresult;
+ }
+ }
+
+ if (pUnkOuter != NULL)
+ {
+ return E_FAIL;
+ }
+
+ CAdvBnd * lpcBB = new FAR CAdvBnd((IClassFactory *) _pCF);
+
+ if (lpcBB == NULL)
+ {
+ return E_OUTOFMEMORY;
+ }
+
+ hresult = lpcBB->QueryInterface(iidInterface, ppv);
+
+ lpcBB->Release();
+
+ return hresult;
+}
+
+STDMETHODIMP CAdvBndCF::LockServer(BOOL fLock)
+{
+ if (fLock)
+ GlobalRefs(TRUE);
+ else
+ GlobalRefs(FALSE);
+
+ return S_OK;
+}
+
+
+
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CAdvBnd::CAdvBnd()
+//
+// Synopsis: The constructor for CAdvBnd. I
+//
+// Arguments: None
+//
+// History: 21-Nov-92 SarahJ Created
+//
+//--------------------------------------------------------------------
+
+CAdvBnd::CAdvBnd(IClassFactory *pcfBase) : _xiunk(), _dwRegister(0), _cRefs(1)
+{
+ HRESULT hresult = pcfBase->CreateInstance((IUnknown *) this, IID_IUnknown,
+ (void **) &_xiunk);
+
+ GlobalRefs(TRUE);
+}
+
+//+-------------------------------------------------------------------
+//
+// Member: CAdvBnd::~CAdvBndObj()
+//
+// Synopsis: The destructor for CAdvBnd.
+//
+// History: 21-Nov-92 SarahJ Created
+//
+//--------------------------------------------------------------------
+
+CAdvBnd::~CAdvBnd()
+{
+ Display(TEXT("CAdvBndCF::~CAdvBnd called\n"));
+
+ if (_dwRegister != 0)
+ {
+ // Get the running object table
+ IRunningObjectTable *prot;
+
+ HRESULT hresult = GetRunningObjectTable(0, &prot);
+
+ Win4Assert(SUCCEEDED(hresult)
+ && "CAdvBnd::~CAdvBnd GetRunningObjectTable failed");
+
+ hresult = prot->Revoke(_dwRegister);
+
+ Win4Assert(SUCCEEDED(hresult)
+ && "CAdvBnd::~CAdvBnd Revoke failed");
+
+ prot->Release();
+ }
+
+ GlobalRefs(FALSE);
+}
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CAdvBnd::QueryInterface
+//
+// Returns: SUCCESS_SUCCCESS
+//
+// History: 21-Nov-92 SarahJ Created
+//
+//--------------------------------------------------------------------
+STDMETHODIMP CAdvBnd::QueryInterface(REFIID iid, void ** ppunk)
+{
+ Display(TEXT("CAdvBnd::QueryInterface called\n"));
+
+ if (IsEqualIID(iid, IID_IUnknown))
+ {
+ *ppunk = (IUnknown *) this;
+ AddRef();
+ return S_OK;
+ }
+ else if ((IsEqualIID(iid, IID_IPersistFile)) ||
+ (IsEqualIID(iid, IID_IPersist)))
+ {
+ *ppunk = (IPersistFile *) this;
+ AddRef();
+ return S_OK;
+ }
+
+ return _xiunk->QueryInterface(iid, ppunk);
+}
+
+STDMETHODIMP_(ULONG) CAdvBnd::AddRef(void)
+{
+ return ++_cRefs;
+}
+
+STDMETHODIMP_(ULONG) CAdvBnd::Release(void)
+{
+ if (--_cRefs == 0)
+ {
+ delete this;
+ }
+
+ return _cRefs;
+}
+
+//+-------------------------------------------------------------------
+//
+// Member: CAdvBnd::Load
+//
+// Synopsis: IPeristFile interface - needed 'cause we bind with
+// file moniker and BindToObject insists on calling this
+//
+// History: 21-Nov-92 SarahJ Created
+//
+//--------------------------------------------------------------------
+STDMETHODIMP CAdvBnd::Load(LPCOLESTR lpszFileName, DWORD grfMode)
+{
+ Display(TEXT("CAdvBndCF::Load called\n"));
+
+ // Forward call to delegated class
+ IPersistFile *pipfile;
+
+ HRESULT hresult = _xiunk->QueryInterface(IID_IPersistFile,
+ (void **) &pipfile);
+
+ hresult = pipfile->Load(lpszFileName, grfMode);
+
+ pipfile->Release();
+
+ if (FAILED(hresult))
+ {
+ // Make sure delegated too class liked what it got/
+ // BUGBUG: Can't just forward hresults!
+ return hresult;
+ }
+
+ // Create a file moniker. Cast to avoid const problem.
+ IMoniker *pmk;
+ hresult = CreateFileMoniker((LPOLESTR)lpszFileName, &pmk);
+
+ Win4Assert(SUCCEEDED(hresult)
+ && "CAdvBnd::Load CreateFileMoniker failed");
+
+ // Get the running object table
+ IRunningObjectTable *prot;
+
+ hresult = GetRunningObjectTable(0, &prot);
+
+ Win4Assert(SUCCEEDED(hresult)
+ && "CAdvBnd::Load GetRunningObjectTable failed");
+
+ // Register in the running object table
+ IUnknown *punk;
+ QueryInterface(IID_IUnknown, (void **) &punk);
+ hresult = prot->Register(0, punk, pmk, &_dwRegister);
+
+ Win4Assert(SUCCEEDED(hresult)
+ && "CAdvBnd::Load Register failed");
+
+ // Set filetime to known value
+ FILETIME filetime;
+ memset(&filetime, 'B', sizeof(filetime));
+
+ // Set time to some known value
+ prot->NoteChangeTime(_dwRegister, &filetime);
+
+ // Release uneeded objects
+ pmk->Release();
+ prot->Release();
+ punk->Release();
+
+ return S_OK;
+}
+
+//+-------------------------------------------------------------------
+//
+// Member: CAdvBnd::Save
+//
+// Synopsis: IPeristFile interface - save
+// does little but here for commentry
+//
+// History: 21-Nov-92 SarahJ Created
+//
+//--------------------------------------------------------------------
+STDMETHODIMP CAdvBnd::Save(LPCOLESTR lpszFileName, BOOL fRemember)
+{
+ Display(TEXT("CAdvBndCF::Save called\n"));
+
+ // Forward call to delegated class
+ IPersistFile *pipfile;
+
+ HRESULT hresult = _xiunk->QueryInterface(IID_IPersistFile,
+ (void **) &pipfile);
+
+ hresult = pipfile->Save(lpszFileName, fRemember);
+
+ pipfile->Release();
+
+ return hresult;
+}
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CAdvBnd::SaveCpmpleted
+// CAdvBnd::GetCurFile
+// CAdvBnd::IsDirty
+//
+// Synopsis: More IPeristFile interface methods
+//
+// History: 21-Nov-92 SarahJ Created
+//
+//--------------------------------------------------------------------
+STDMETHODIMP CAdvBnd::SaveCompleted(LPCOLESTR lpszFileName)
+{
+ Display(TEXT("CAdvBndCF::SaveCompleted called\n"));
+
+ // Forward call to delegated class
+ IPersistFile *pipfile;
+
+ HRESULT hresult = _xiunk->QueryInterface(IID_IPersistFile,
+ (void **) &pipfile);
+
+ hresult = pipfile->SaveCompleted(lpszFileName);
+
+ pipfile->Release();
+
+ return hresult;
+}
+
+STDMETHODIMP CAdvBnd::GetCurFile(LPOLESTR FAR *lpszFileName)
+{
+ Display(TEXT("CAdvBndCF::GetCurFile called\n"));
+
+ // Forward call to delegated class
+ IPersistFile *pipfile;
+
+ HRESULT hresult = _xiunk->QueryInterface(IID_IPersistFile,
+ (void **) &pipfile);
+
+ hresult = pipfile->GetCurFile(lpszFileName);
+
+ pipfile->Release();
+
+ return hresult;
+}
+
+STDMETHODIMP CAdvBnd::IsDirty()
+{
+ Display(TEXT("CAdvBndCF::IsDirty called\n"));
+
+ // Forward call to delegated class
+ IPersistFile *pipfile;
+
+ HRESULT hresult = _xiunk->QueryInterface(IID_IPersistFile,
+ (void **) &pipfile);
+
+ hresult = pipfile->IsDirty();
+
+ pipfile->Release();
+
+ return hresult;
+}
+
+//+-------------------------------------------------------------------
+//
+// Interface: IPersist
+//
+// Synopsis: IPersist interface methods
+// Need to return a valid class id here
+//
+// History: 21-Nov-92 SarahJ Created
+//
+
+STDMETHODIMP CAdvBnd::GetClassID(LPCLSID classid)
+{
+ Display(TEXT("CAdvBndCF::GetClassID called\n"));
+
+ *classid = CLSID_AdvBnd;
+ return S_OK;
+}
diff --git a/private/oleutest/balls/common/advbnd.hxx b/private/oleutest/balls/common/advbnd.hxx
new file mode 100644
index 000000000..cd9f2bed0
--- /dev/null
+++ b/private/oleutest/balls/common/advbnd.hxx
@@ -0,0 +1,111 @@
+//+-------------------------------------------------------------------
+//
+// File: advbnd.hxx
+//
+// Contents: This file contins the advanced binding test class
+//
+// Classes: CAdvBndCF (class factory)
+// CAdvBnd
+//
+// History: 30-Mar-92 SarahJ Created
+//
+//---------------------------------------------------------------------
+
+#ifndef __ADVBND_H__
+#define __ADVBND_H__
+
+//#include <win4p.hxx>
+#include <smartp.hxx>
+
+extern "C" const GUID CLSID_BasicBnd;
+extern "C" const GUID CLSID_AdvBnd;
+
+// DefineSmartItfP(IClassFactory)
+
+
+//+-------------------------------------------------------------------
+//
+// Class: CBasicBndCF
+//
+// Synopsis: Class Factory for CBasicBnd
+//
+// Methods: IUnknown - QueryInterface, AddRef, Release
+// IClassFactory - CreateInstance
+//
+// History: 21-Mar-92 SarahJ Created
+//
+//--------------------------------------------------------------------
+
+class CAdvBndCF: public IClassFactory
+{
+public:
+
+ // Constructor/Destructor
+ CAdvBndCF();
+ ~CAdvBndCF();
+ static IClassFactory FAR * Create();
+
+ // IUnknown
+ STDMETHOD(QueryInterface)(REFIID iid, void FAR * FAR * ppv);
+ STDMETHOD_(ULONG, AddRef)(void);
+ STDMETHOD_(ULONG, Release)(void);
+
+ // IClassFactory
+ STDMETHOD(CreateInstance)(IUnknown FAR* pUnkOuter,
+ REFIID iidInterface,
+ void FAR* FAR* ppv);
+
+ STDMETHOD(LockServer)(BOOL fLock);
+
+private:
+
+ IClassFactory *_pCF;
+
+ DWORD _dwRegistration;
+
+ ULONG _cRefs;
+};
+
+//+-------------------------------------------------------------------
+//
+// Class: CAdvBnd
+//
+// Synopsis: Test class CBasicBnd
+//
+// Methods:
+//
+// History: 21-Mar-92 SarahJ Created
+//
+//--------------------------------------------------------------------
+
+
+class CAdvBnd: public IPersistFile
+{
+public:
+ CAdvBnd(IClassFactory *pFactory);
+ ~CAdvBnd();
+
+ // IUnknown
+ STDMETHOD(QueryInterface)(REFIID iid, void FAR * FAR * ppv);
+ STDMETHOD_(ULONG, AddRef)(void);
+ STDMETHOD_(ULONG, Release)(void);
+
+ // IPersitFile
+ STDMETHOD(GetClassID)(LPCLSID lpClassID);
+ STDMETHOD(IsDirty)();
+ STDMETHOD(Load)(LPCOLESTR lpszFileName, DWORD grfMode);
+ STDMETHOD(Save)(LPCOLESTR lpszFileName, BOOL fRemember);
+ STDMETHOD(SaveCompleted)(LPCOLESTR lpszFileName);
+ STDMETHOD(GetCurFile)(LPOLESTR FAR * lpszFileName);
+
+private:
+
+ XIUnknown _xiunk;
+
+ DWORD _dwRegister;
+
+ ULONG _cRefs;
+};
+
+
+#endif // __ADVBND_H__
diff --git a/private/oleutest/balls/common/ballscf.cxx b/private/oleutest/balls/common/ballscf.cxx
new file mode 100644
index 000000000..dcdd0470b
--- /dev/null
+++ b/private/oleutest/balls/common/ballscf.cxx
@@ -0,0 +1,151 @@
+//+-------------------------------------------------------------------
+//
+// File: ballscf.cxx
+//
+// Contents: test class factory object implementation
+//
+// Classes: CBallClassFactory
+//
+// Functions:
+//
+// History: 23-Nov-92 Rickhi Created
+//
+//--------------------------------------------------------------------
+
+#include <pch.cxx>
+#pragma hdrstop
+#include <ballscf.hxx> // class definiton
+#include <cballs.hxx> // CBalls defines
+
+
+const GUID CLSID_Balls =
+ {0x0000013a,0x0001,0x0008,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}};
+
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CBallClassFactory::CBallClassFactory, public
+//
+// Algorithm:
+//
+// History: 23-Nov-92 Rickhi Created
+//
+//--------------------------------------------------------------------
+
+CBallClassFactory::CBallClassFactory(IUnknown *punkOuter) :
+ _punkOuter(punkOuter)
+{
+ ENLIST_TRACKING(CBallClassFactory);
+}
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CBallClassFactory::~CBallClassFactory, public
+//
+// Algorithm:
+//
+// History: 23-Nov-92 Rickhi Created
+//
+//--------------------------------------------------------------------
+
+CBallClassFactory::~CBallClassFactory(void)
+{
+ // automatic actions do the rest of the work
+}
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CBallClassFactory::QueryInterface, public
+//
+// Algorithm: if the interface is not one implemented by us,
+// pass the request to the proxy manager
+//
+// History: 23-Nov-92 Rickhi Created
+//
+//--------------------------------------------------------------------
+
+STDMETHODIMP CBallClassFactory::QueryInterface(REFIID riid, void **ppUnk)
+{
+ SCODE sc = S_OK;
+
+ if (IsEqualIID(riid, IID_IUnknown) ||
+ IsEqualIID(riid, IID_IClassFactory))
+ {
+ *ppUnk = (void *)(IClassFactory *) this;
+ AddRef();
+ }
+ else
+ {
+ if (_punkOuter)
+ {
+ sc = _punkOuter->QueryInterface(riid, ppUnk);
+ }
+ else
+ {
+ *ppUnk = NULL;
+ sc = E_NOINTERFACE;
+ }
+ }
+ return sc;
+}
+
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CBallClassFactory::CreateInstance, public
+//
+// Synopsis: create a new object with the same class
+//
+// History: 23-Nov-92 Rickhi Created
+//
+//--------------------------------------------------------------------
+
+STDMETHODIMP CBallClassFactory::CreateInstance(IUnknown *punkOuter,
+ REFIID riid,
+ void **ppunkObject)
+{
+ SCODE sc = E_OUTOFMEMORY;
+
+ *ppunkObject = NULL; // in case of failure
+
+ // create a ball object.
+ IUnknown *punk = (IUnknown *) new CBallCtrlUnk(punkOuter);
+
+ if (punk)
+ {
+ // get the interface the caller wants to use
+ sc = punk->QueryInterface(riid, ppunkObject);
+
+ // release our hold on the ball, since the QI got a hold for
+ // the client.
+ punk->Release();
+ }
+
+ return sc;
+}
+
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CBallClassFactory::LockServer, public
+//
+// Synopsis: create a new object with the same class
+//
+// History: 23-Nov-92 Rickhi Created
+//
+//--------------------------------------------------------------------
+
+STDMETHODIMP CBallClassFactory::LockServer(BOOL fLock)
+{
+ if (fLock)
+ GlobalRefs(TRUE);
+ else
+ GlobalRefs(FALSE);
+
+ return S_OK;
+}
diff --git a/private/oleutest/balls/common/ballscf.hxx b/private/oleutest/balls/common/ballscf.hxx
new file mode 100644
index 000000000..2cdcf0a32
--- /dev/null
+++ b/private/oleutest/balls/common/ballscf.hxx
@@ -0,0 +1,63 @@
+//+-------------------------------------------------------------------
+//
+// File: ballscf.hxx
+//
+// Contents: test class factory object implementation
+//
+// Classes: CBallClassFactory
+//
+// Functions: None
+//
+// History: 23-Nov-92 Rickhi Created
+//
+//--------------------------------------------------------------------
+
+#ifndef __CBALLCLASSFACTORY__
+#define __CBALLCLASSFACTORY__
+
+#include <win4p.hxx>
+#include <otrack.hxx> // object tracking
+
+extern "C" const GUID CLSID_Balls;
+
+//+-------------------------------------------------------------------
+//
+// Class: CBallClassFactory
+//
+// Purpose: test class factory object implementation
+//
+// Interface:
+//
+// History: 23-Nov-92 Rickhi Created
+//
+// Notes:
+//
+//--------------------------------------------------------------------
+
+class CBallClassFactory : INHERIT_TRACKING,
+ public IClassFactory
+{
+public:
+ // Constructor & Destructor
+ CBallClassFactory(IUnknown *punkOuter);
+
+ // IUnknown methods
+ STDMETHOD(QueryInterface)(REFIID riid, void **ppUnk);
+ DECLARE_STD_REFCOUNTING;
+
+
+ // IClassFactory methods
+ STDMETHOD(CreateInstance)(IUnknown *punkOuter,
+ REFIID riid,
+ void **ppunkObject);
+
+ STDMETHOD(LockServer)(BOOL fLock);
+
+private:
+ ~CBallClassFactory(void);
+
+ IUnknown *_punkOuter;
+};
+
+
+#endif // __CBALLCLASSFACTORY__
diff --git a/private/oleutest/balls/common/bscbnd.cxx b/private/oleutest/balls/common/bscbnd.cxx
new file mode 100644
index 000000000..b4197ffd1
--- /dev/null
+++ b/private/oleutest/balls/common/bscbnd.cxx
@@ -0,0 +1,826 @@
+//+-------------------------------------------------------------------
+//
+// Class: CBasicBndCF
+//
+// Synopsis: Class Factory for CBasicBnd
+//
+// Interfaces: IUnknown - QueryInterface, AddRef, Release
+// IClassFactory - CreateInstance
+//
+// History: 21-Nov-92 SarahJ Created
+//
+//--------------------------------------------------------------------
+
+#include <pch.cxx>
+#pragma hdrstop
+#include <bscbnd.hxx>
+
+
+const GUID CLSID_BasicBnd =
+ {0x99999999,0x0000,0x0008,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x49}};
+
+const GUID CLSID_TestEmbed =
+ {0x99999999,0x0000,0x0008,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x47}};
+
+ULONG g_UseCount = 0;
+
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CBasicBndCF::CBasicBndCF()
+//
+// Synopsis: The constructor for CBAsicBnd.
+//
+// Arguments: None
+//
+// History: 21-Nov-92 SarahJ Created
+//
+//--------------------------------------------------------------------
+
+CBasicBndCF::CBasicBndCF() : _cRefs(1)
+{
+ g_UseCount++;
+}
+
+//+-------------------------------------------------------------------
+//
+// Member: CBasicBnd::~CBasicBndObj()
+//
+// Synopsis: The destructor for CBAsicBnd.
+//
+// History: 21-Nov-92 SarahJ Created
+//
+//--------------------------------------------------------------------
+
+CBasicBndCF::~CBasicBndCF()
+{
+ g_UseCount--;
+ return;
+}
+
+
+//+-------------------------------------------------------------------
+//
+// Method: CBasicBndCF::QueryInterface
+//
+// Synopsis: Only IUnknown and IClassFactory supported
+//
+//--------------------------------------------------------------------
+
+STDMETHODIMP CBasicBndCF::QueryInterface(REFIID iid, void FAR * FAR * ppv)
+{
+ if (IsEqualIID(iid, IID_IUnknown) ||
+ IsEqualIID(iid, IID_IClassFactory))
+ {
+ *ppv = this;
+ AddRef();
+ return S_OK;
+ }
+ else
+ {
+ *ppv = NULL;
+ return E_NOINTERFACE;
+ }
+}
+
+STDMETHODIMP_(ULONG) CBasicBndCF::AddRef(void)
+{
+ return ++_cRefs;
+}
+
+STDMETHODIMP_(ULONG) CBasicBndCF::Release(void)
+{
+ if (--_cRefs == 0)
+ {
+ delete this;
+ return 0;
+ }
+
+ return _cRefs;
+}
+
+
+
+//+-------------------------------------------------------------------
+//
+// Method: CBasicBndCF::CreateInstance
+//
+// Synopsis: This is called by Binding process to create the
+// actual class object
+//
+//--------------------------------------------------------------------
+STDMETHODIMP CBasicBndCF::CreateInstance(IUnknown FAR* pUnkOuter,
+ REFIID iidInterface,
+ void FAR* FAR* ppv)
+{
+ HRESULT hresult = S_OK;
+
+ class CUnknownBasicBnd *pubb = new FAR CUnknownBasicBnd(pUnkOuter);
+
+ if (pubb == NULL)
+ {
+ return E_OUTOFMEMORY;
+ }
+
+ // Because when an aggregate is being requested, the controlling
+ // must be returned, no QI is necessary.
+ if (pUnkOuter == NULL)
+ {
+ hresult = pubb->QueryInterface(iidInterface, ppv);
+
+ pubb->Release();
+ }
+ else
+ {
+ *ppv = (void *) pubb;
+ }
+
+ return hresult;
+}
+
+//+-------------------------------------------------------------------
+//
+// Method: CBasicBndCF::LockServer
+//
+// Synopsis: Who knows what this is for?
+//
+//--------------------------------------------------------------------
+
+STDMETHODIMP CBasicBndCF::LockServer(BOOL fLock)
+{
+ return E_FAIL;
+}
+
+
+
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CBasicBnd::CBasicBnd()
+//
+// Synopsis: The constructor for CBAsicBnd. I
+//
+// Arguments: None
+//
+// History: 21-Nov-92 SarahJ Created
+//
+//--------------------------------------------------------------------
+
+CBasicBnd::CBasicBnd(IUnknown *punk)
+ : _punk(punk), _pmkContainer(NULL)
+{
+ // Create storage for "contained" objects
+ SCODE sc = StgCreateDocfile(NULL,
+ STGM_DELETEONRELEASE|STGM_DFRALL|STGM_CREATE, 0, &_psStg1);
+
+ Win4Assert((sc == S_OK) && "Create of first storage failed");
+
+ sc = StgCreateDocfile(NULL,
+ STGM_DELETEONRELEASE|STGM_DFRALL|STGM_CREATE, 0, &_psStg2);
+
+ Win4Assert((sc == S_OK) && "Create of second storage failed");
+}
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CBasicBnd::~CBasicBndObj()
+//
+// Synopsis: The destructor for CBAsicBnd.
+//
+// History: 21-Nov-92 SarahJ Created
+//
+//--------------------------------------------------------------------
+
+CBasicBnd::~CBasicBnd()
+{
+ if (_pmkContainer)
+ {
+ _pmkContainer->Release();
+ }
+
+ if (_psStg1)
+ {
+ _psStg1->Release();
+ }
+
+ if (_psStg2)
+ {
+ _psStg2->Release();
+ }
+
+ return;
+}
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CBasicBnd::QueryInterface
+//
+// Returns: S_OK
+//
+// History: 21-Nov-92 SarahJ Created
+//
+//--------------------------------------------------------------------
+
+STDMETHODIMP CBasicBnd::QueryInterface(REFIID iid, void **ppiuk)
+{
+ return _punk->QueryInterface(iid, ppiuk);
+}
+
+//+-------------------------------------------------------------------
+//
+// Member: CBasicBnd::AddRef
+//
+// Synopsis: Standard stuff
+//
+// History: 21-Nov-92 SarahJ Created
+//
+//--------------------------------------------------------------------
+
+STDMETHODIMP_(ULONG) CBasicBnd::AddRef(void)
+{
+ return _punk->AddRef();
+}
+
+//+-------------------------------------------------------------------
+//
+// Member: CBasicBnd::Release
+//
+// Synopsis: Standard stuff
+//
+// History: 21-Nov-92 SarahJ Created
+//
+//--------------------------------------------------------------------
+
+STDMETHODIMP_(ULONG) CBasicBnd::Release(void)
+{
+ return _punk->Release();
+}
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CBasicBnd::Load
+//
+// Synopsis: IPeristFile interface - needed 'cause we bind with
+// file moniker and BindToObject insists on calling this
+//
+// History: 21-Nov-92 SarahJ Created
+//
+//--------------------------------------------------------------------
+STDMETHODIMP CBasicBnd::Load(LPCOLESTR lpszFileName, DWORD grfMode)
+{
+ if (grfMode & ~(STGM_READWRITE | STGM_SHARE_EXCLUSIVE))
+ {
+ // Test requires default bind storage request and caller
+ // has set some other bits so we fail.
+ return STG_E_INVALIDPARAMETER;
+ }
+
+ return S_OK;
+}
+
+//+-------------------------------------------------------------------
+//
+// Member: CBasicBnd::Save
+//
+// Synopsis: IPeristFile interface - save
+// does little but here for commentry
+//
+// History: 21-Nov-92 SarahJ Created
+//
+//--------------------------------------------------------------------
+
+STDMETHODIMP CBasicBnd::Save(LPCOLESTR lpszFileName, BOOL fRemember)
+{
+ return S_OK;
+}
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CBasicBnd::SaveCpmpleted
+// CBasicBnd::GetCurFile
+// CBasicBnd::IsDirty
+//
+// Synopsis: More IPeristFile interface methods
+//
+// History: 21-Nov-92 SarahJ Created
+//
+//--------------------------------------------------------------------
+
+STDMETHODIMP CBasicBnd::SaveCompleted(LPCOLESTR lpszFileName)
+{
+ return S_OK;
+}
+
+STDMETHODIMP CBasicBnd::GetCurFile(LPOLESTR FAR *lpszFileName)
+{
+ return S_OK;
+}
+
+STDMETHODIMP CBasicBnd::IsDirty()
+{
+ return S_OK;
+}
+
+
+//+-------------------------------------------------------------------
+//
+// Interface: IPersist
+//
+// Synopsis: IPersist interface methods
+// Need to return a valid class id here
+//
+// History: 21-Nov-92 SarahJ Created
+//
+//--------------------------------------------------------------------
+
+STDMETHODIMP CBasicBnd::GetClassID(LPCLSID classid)
+{
+ *classid = CLSID_BasicBnd;
+ return S_OK;
+}
+
+
+//+-------------------------------------------------------------------
+//
+// Interface: IOleObject
+//
+// Synopsis: IOleObject interface methods
+//
+// History: 21-Nov-92 SarahJ Created
+//
+//--------------------------------------------------------------------
+
+STDMETHODIMP CBasicBnd::SetClientSite(LPOLECLIENTSITE pClientSite)
+{
+ return E_FAIL;
+}
+
+STDMETHODIMP CBasicBnd::GetClientSite(LPOLECLIENTSITE FAR* ppClientSite)
+{
+ return E_FAIL;
+}
+
+STDMETHODIMP CBasicBnd::SetHostNames(
+ LPCOLESTR szContainerApp,
+ LPCOLESTR szContainerObj)
+{
+ return E_FAIL;
+}
+
+STDMETHODIMP CBasicBnd::Close(DWORD dwSaveOption)
+{
+ return E_FAIL;
+}
+
+STDMETHODIMP CBasicBnd::SetMoniker(DWORD dwWhichMoniker, LPMONIKER pmk)
+{
+ if (_pmkContainer)
+ {
+ _pmkContainer->Release();
+
+ }
+
+ _pmkContainer = pmk;
+
+ pmk->AddRef();
+
+ return S_OK;
+}
+
+STDMETHODIMP CBasicBnd::GetMoniker(
+ DWORD dwAssign,
+ DWORD dwWhichMoniker,
+ LPMONIKER FAR* ppmk)
+{
+ if (_pmkContainer != NULL)
+ {
+ *ppmk = _pmkContainer;
+ _pmkContainer->AddRef();
+ return S_OK;
+ }
+
+ return E_FAIL;
+}
+
+STDMETHODIMP CBasicBnd::InitFromData(
+ LPDATAOBJECT pDataObject,
+ BOOL fCreation,
+ DWORD dwReserved)
+{
+ return E_FAIL;
+}
+
+STDMETHODIMP CBasicBnd::GetClipboardData(
+ DWORD dwReserved,
+ LPDATAOBJECT FAR* ppDataObject)
+{
+ return E_FAIL;
+}
+
+STDMETHODIMP CBasicBnd::DoVerb(
+ LONG iVerb,
+ LPMSG lpmsg,
+ LPOLECLIENTSITE pActiveSite,
+ LONG reserved,
+ HWND hwndParent,
+ LPCRECT lprcPosRect)
+{
+ return E_FAIL;
+}
+
+STDMETHODIMP CBasicBnd::EnumVerbs(IEnumOLEVERB FAR* FAR* ppenumOleVerb)
+{
+ return E_FAIL;
+}
+
+STDMETHODIMP CBasicBnd::Update(void)
+{
+ return E_FAIL;
+}
+
+STDMETHODIMP CBasicBnd::IsUpToDate(void)
+{
+ return E_FAIL;
+}
+
+STDMETHODIMP CBasicBnd::GetUserClassID(CLSID FAR* pClsid)
+{
+ return E_FAIL;
+}
+
+STDMETHODIMP CBasicBnd::GetUserType(DWORD dwFormOfType, LPOLESTR FAR* pszUserType)
+{
+ return E_FAIL;
+}
+
+STDMETHODIMP CBasicBnd::SetExtent(DWORD dwDrawAspect, LPSIZEL lpsizel)
+{
+ return E_FAIL;
+}
+
+STDMETHODIMP CBasicBnd::GetExtent(DWORD dwDrawAspect, LPSIZEL lpsizel)
+{
+ return E_FAIL;
+}
+
+STDMETHODIMP CBasicBnd::Advise(
+ IAdviseSink FAR* pAdvSink,
+ DWORD FAR* pdwConnection)
+{
+ *pdwConnection = 0;
+ return S_OK;
+}
+
+STDMETHODIMP CBasicBnd::Unadvise(DWORD dwConnection)
+{
+ return E_FAIL;
+}
+
+STDMETHODIMP CBasicBnd::EnumAdvise(LPENUMSTATDATA FAR* ppenumAdvise)
+{
+ return E_FAIL;
+}
+
+STDMETHODIMP CBasicBnd::GetMiscStatus(DWORD dwAspect, DWORD FAR* pdwStatus)
+{
+ return E_FAIL;
+}
+
+STDMETHODIMP CBasicBnd::SetColorScheme(LPLOGPALETTE lpLogpal)
+{
+ return E_FAIL;
+}
+
+
+//+-------------------------------------------------------------------
+//
+// Interface: IParseDisplayName
+//
+// Synopsis: IParseDisplayName interface methods
+//
+// History: 21-Nov-92 SarahJ Created
+//
+//--------------------------------------------------------------------
+
+STDMETHODIMP CBasicBnd::ParseDisplayName(
+ LPBC pbc,
+ LPOLESTR lpszDisplayName,
+ ULONG FAR* pchEaten,
+ LPMONIKER FAR* ppmkOut)
+{
+ *pchEaten = olestrlen(lpszDisplayName);
+ return CreateItemMoniker(OLESTR("\\"), lpszDisplayName, ppmkOut);
+}
+
+//+-------------------------------------------------------------------
+//
+// Interface: IOleContainer
+//
+// Synopsis: IOleContainer interface methods
+//
+// History: 21-Nov-92 SarahJ Created
+//
+//--------------------------------------------------------------------
+
+STDMETHODIMP CBasicBnd::EnumObjects(
+ DWORD grfFlags,
+ LPENUMUNKNOWN FAR* ppenumUnknown)
+{
+ return E_FAIL;
+}
+
+STDMETHODIMP CBasicBnd::LockContainer(BOOL fLock)
+{
+ return E_FAIL;
+}
+
+//+-------------------------------------------------------------------
+//
+// Interface: IOleItemContainer
+//
+// Synopsis: IOleItemContainer interface methods
+//
+// History: 21-Nov-92 SarahJ Created
+//
+//--------------------------------------------------------------------
+
+STDMETHODIMP CBasicBnd::GetObject(
+ LPOLESTR lpszItem,
+ DWORD dwSpeedNeeded,
+ LPBINDCTX pbc,
+ REFIID riid,
+ LPVOID FAR* ppvObject)
+{
+ IStorage *psStorage;
+ IOleObject *poo;
+ IUnknown *punk;
+
+ if (olestrcmp(lpszItem, OLESTR("1")) == 0)
+ {
+ psStorage = _psStg1;
+ }
+ else if (olestrcmp(lpszItem, OLESTR("2")) == 0)
+ {
+ psStorage = _psStg2;
+ }
+ else
+ {
+ return E_FAIL;
+ }
+
+ IOleClientSite * pocsObjCliSite;
+
+ HRESULT hresult = QueryInterface(IID_IOleClientSite,
+ (void **) &pocsObjCliSite);
+
+ // Call OleCreate to create our embedded object
+ hresult = OleCreate(
+ CLSID_TestEmbed, // Class ID of the object we are
+ // creating
+ IID_IOleObject, // Interface by which we want to talk
+ // to the object
+ OLERENDER_NONE, // We don't want to draw the object
+ // when it is not active
+ NULL, // Used if we do draw the object when
+ // it is non-active
+ pocsObjCliSite, // IOleClientSite the server will use
+ psStorage, // IStorage the server will use
+ (void **) &poo); // Pointer to the object
+
+ Win4Assert(SUCCEEDED(hresult)
+ && "CBasicBnd::GetObject OlCreate Failed!\n");
+
+ // Set the client site
+ hresult = poo->SetClientSite(pocsObjCliSite);
+
+ hresult = poo->QueryInterface(IID_IUnknown, (void **)&punk);
+
+ Win4Assert(SUCCEEDED(hresult)
+ && "CBasicBnd::GetObject QI to IUnknown failed!\n");
+
+ hresult = OleRun(punk);
+
+ Win4Assert(SUCCEEDED(hresult)
+ && "CBasicBnd::GetObject OleRun!\n");
+
+ punk->Release();
+
+ LPRECT lprPosRect = (LPRECT) new RECT;
+
+ hresult = poo->DoVerb(
+ OLEIVERB_SHOW, // Verb we are invoking
+ NULL, // MSG that causes us to do this verb
+ pocsObjCliSite, // Client site of this object
+ 0, // Reserved - definitive value?
+ 0, // hwndParent - ???
+ lprPosRect); // lprcPosRect - rectangle wrt hwndParent
+
+ Win4Assert(SUCCEEDED(hresult)
+ && "CBasicBnd::GetObject DoVerb failed!\n");
+
+ delete lprPosRect;
+
+ pocsObjCliSite->Release();
+
+ *ppvObject = (void *) poo;
+
+ return hresult;
+}
+
+STDMETHODIMP CBasicBnd::GetObjectStorage(
+ LPOLESTR lpszItem,
+ LPBINDCTX pbc,
+ REFIID riid,
+ LPVOID FAR* ppvStorage)
+{
+ return E_FAIL;
+}
+
+STDMETHODIMP CBasicBnd::IsRunning(LPOLESTR lpszItem)
+{
+ return E_FAIL;
+}
+
+CUnknownBasicBnd::CUnknownBasicBnd(IUnknown *punk)
+ : _pbasicbnd(NULL), _cRefs(1)
+{
+ if (punk == NULL)
+ {
+ punk = (IUnknown *) this;
+ }
+
+ // BUGBUG: No error checking!
+ _pbasicbnd = new CBasicBnd(punk);
+ g_UseCount++;
+}
+
+CUnknownBasicBnd::~CUnknownBasicBnd(void)
+{
+ g_UseCount--;
+ delete _pbasicbnd;
+}
+
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CUnknownBasicBnd::QueryInterface
+//
+// Returns: S_OK
+//
+// History: 21-Nov-92 SarahJ Created
+//
+//--------------------------------------------------------------------
+
+
+STDMETHODIMP CUnknownBasicBnd::QueryInterface(
+ REFIID iid,
+ void **ppiuk)
+{
+ if (IsEqualIID(iid, IID_IUnknown))
+ {
+ *ppiuk = (IUnknown *) this;
+ }
+ else if (IsEqualIID(iid, IID_IOleClientSite))
+ {
+ *ppiuk = (IOleClientSite *) _pbasicbnd;
+ }
+ else if (IsEqualIID(iid, IID_IPersistFile)
+ || IsEqualIID(iid, IID_IPersist))
+ {
+ *ppiuk = (IPersistFile *) _pbasicbnd;
+ }
+ else if (IsEqualIID(iid, IID_IOleObject))
+ {
+ *ppiuk = (IOleObject *) _pbasicbnd;
+ }
+ else if (IsEqualIID(iid, IID_IOleItemContainer))
+ {
+ *ppiuk = (IOleItemContainer *)_pbasicbnd;
+ }
+ else if (IsEqualIID(iid, IID_IOleContainer))
+ {
+ *ppiuk = (IOleContainer *)_pbasicbnd;
+ }
+ else if (IsEqualIID(iid, IID_IParseDisplayName))
+ {
+ *ppiuk = (IParseDisplayName *)_pbasicbnd;
+ }
+ else
+ {
+ *ppiuk = NULL;
+ return E_NOINTERFACE;
+ }
+
+ _pbasicbnd->AddRef();
+ return S_OK;
+}
+
+
+STDMETHODIMP_(ULONG) CUnknownBasicBnd::AddRef(void)
+{
+ return ++_cRefs;
+}
+
+STDMETHODIMP_(ULONG) CUnknownBasicBnd::Release(void)
+{
+ if (--_cRefs == 0)
+ {
+ delete this;
+ return 0;
+ }
+
+ return _cRefs;
+}
+
+
+
+//+-------------------------------------------------------------------
+// Method: CBasicBnd::SaveObject
+//
+// Synopsis: See spec 2.00.09 p107. This object should be saved.
+//
+// Returns: Should always return S_OK.
+//
+// History: 04-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP CBasicBnd::SaveObject(void)
+{
+ // BUGBUG - NYI
+ // Returning S_OK tells OLE that we actually saved this object
+ return(S_OK);
+}
+
+
+//+-------------------------------------------------------------------
+// Method: CBasicBnd::GetContainer
+//
+// Synopsis: See spec 2.00.09 p108. Return the container in which
+// this object is found.
+//
+// Returns: Should return S_OK.
+//
+// History: 04-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP CBasicBnd::GetContainer(LPOLECONTAINER FAR *ppContainer)
+{
+ return QueryInterface(IID_IOleContainer, (void **) ppContainer);
+}
+
+
+//+-------------------------------------------------------------------
+// Method: CBasicBnd::ShowObject
+//
+// Synopsis: See spec 2.00.09 p109. Server for this object is asking
+// us to display it. Caller should not assume we have
+// actually worked, but we return S_OK either way. Great!
+//
+// Returns: S_OK whether we work or not...
+//
+// History: 04-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP CBasicBnd::ShowObject(void)
+{
+ return(S_OK);
+}
+
+
+//+-------------------------------------------------------------------
+// Method: CBasicBnd::OnShowWindow
+//
+// Synopsis: ???
+//
+// Parameters: [fShow] -
+//
+// Returns: S_OK?
+//
+// History: 16-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP CBasicBnd::OnShowWindow(BOOL fShow)
+{
+ return(S_OK);
+}
+
+
+
+//+-------------------------------------------------------------------
+// Method: CBasicBnd::RequestNewObjectLayout
+//
+// Synopsis: ???
+//
+// Parameters: [fShow] -
+//
+// Returns: S_OK?
+//
+// History: 16-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP CBasicBnd::RequestNewObjectLayout(void)
+{
+ return(S_OK);
+}
diff --git a/private/oleutest/balls/common/bscbnd.hxx b/private/oleutest/balls/common/bscbnd.hxx
new file mode 100644
index 000000000..1822fcd36
--- /dev/null
+++ b/private/oleutest/balls/common/bscbnd.hxx
@@ -0,0 +1,208 @@
+//+-------------------------------------------------------------------
+//
+// File: bscbnd.hxx
+//
+// Contents: This file contins the DLL entry points
+// LibMain
+// DllGetClassObject (Bindings key func)
+// DllCanUnloadNow
+// CBasicBndCF (class factory)
+// History: 30-Mar-92 SarahJ Created
+//
+//---------------------------------------------------------------------
+
+#ifndef __BSCBND_H__
+#define __BSCBND_H__
+
+
+extern "C" const GUID CLSID_BasicBnd;
+extern "C" const GUID CLSID_TestEmbed;
+
+
+#define STGM_DFRALL (STGM_READWRITE | STGM_TRANSACTED | STGM_SHARE_DENY_WRITE)
+
+//
+// Define the interface we are going to use here - avoiding MIDL stuff
+//
+
+//+-------------------------------------------------------------------
+//
+// Class: CBasicBndCF
+//
+// Synopsis: Class Factory for CBasicBnd
+//
+// Methods: IUnknown - QueryInterface, AddRef, Release
+// IClassFactory - CreateInstance
+//
+// History: 21-Mar-92 SarahJ Created
+//
+//--------------------------------------------------------------------
+
+
+class FAR CBasicBndCF: public IClassFactory
+{
+public:
+
+ // Constructor/Destructor
+ CBasicBndCF();
+ ~CBasicBndCF();
+
+ // IUnknown
+ STDMETHODIMP QueryInterface(REFIID iid, void FAR * FAR * ppv);
+ STDMETHODIMP_(ULONG) AddRef(void);
+ STDMETHODIMP_(ULONG) Release(void);
+
+
+ // IClassFactory
+ STDMETHODIMP CreateInstance(IUnknown FAR* pUnkOuter,
+ REFIID iidInterface,
+ void FAR* FAR* ppv);
+
+ STDMETHODIMP LockServer(BOOL fLock);
+
+ BOOL ReleaseClass(void);
+
+private:
+
+ ULONG _cRefs;
+};
+
+
+
+//+-------------------------------------------------------------------
+//
+// Class: CBasicBnd
+//
+// Synopsis: Test class CBasicBnd
+//
+// Methods:
+//
+// History: 21-Mar-92 SarahJ Created
+//
+//--------------------------------------------------------------------
+
+
+class FAR CBasicBnd: public IPersistFile, public IOleClientSite,
+ public IOleObject, public IOleItemContainer
+{
+public:
+ // *** Constructor/Destructor
+ CBasicBnd(IUnknown *punk);
+ ~CBasicBnd();
+
+ // *** IUnknown
+ STDMETHODIMP QueryInterface(REFIID iid, void FAR * FAR * ppv);
+ STDMETHODIMP_(ULONG) AddRef(void);
+ STDMETHODIMP_(ULONG) Release(void);
+
+ // *** IPersist
+ STDMETHODIMP GetClassID(LPCLSID lpClassID);
+
+ // *** IPersitFile
+ STDMETHODIMP IsDirty();
+ STDMETHODIMP Load(LPCOLESTR lpszFileName, DWORD grfMode);
+ STDMETHODIMP Save(LPCOLESTR lpszFileName, BOOL fRemember);
+ STDMETHODIMP SaveCompleted(LPCOLESTR lpszFileName);
+ STDMETHODIMP GetCurFile(LPOLESTR FAR * lplpszFileName);
+
+ // *** IOleObject methods ***
+ STDMETHODIMP SetClientSite( LPOLECLIENTSITE pClientSite);
+ STDMETHODIMP GetClientSite( LPOLECLIENTSITE FAR* ppClientSite);
+ STDMETHODIMP SetHostNames( LPCOLESTR szContainerApp, LPCOLESTR szContainerObj);
+ STDMETHODIMP Close(DWORD dwSaveOption);
+ STDMETHODIMP SetMoniker( DWORD dwWhichMoniker, LPMONIKER pmk);
+ STDMETHODIMP GetMoniker( DWORD dwAssign, DWORD dwWhichMoniker,
+ LPMONIKER FAR* ppmk);
+ STDMETHODIMP InitFromData( LPDATAOBJECT pDataObject,
+ BOOL fCreation,
+ DWORD dwReserved);
+ STDMETHODIMP GetClipboardData( DWORD dwReserved,
+ LPDATAOBJECT FAR* ppDataObject);
+ STDMETHODIMP DoVerb( LONG iVerb,
+ LPMSG lpmsg,
+ LPOLECLIENTSITE pActiveSite,
+ LONG lindex,
+ HWND hwndParent,
+ LPCRECT lprcPosRect);
+ STDMETHODIMP EnumVerbs(LPENUMOLEVERB FAR* ppenumOleVerb);
+ STDMETHODIMP Update(void);
+ STDMETHODIMP IsUpToDate(void);
+ STDMETHODIMP GetUserClassID(CLSID FAR *pClsid);
+ STDMETHODIMP GetUserType(DWORD dwFormOfType, LPOLESTR FAR* pszUserType);
+ STDMETHODIMP SetExtent( DWORD dwDrawAspect, LPSIZEL lpsizel);
+ STDMETHODIMP GetExtent( DWORD dwDrawAspect, LPSIZEL lpsizel);
+
+ STDMETHODIMP Advise( LPADVISESINK pAdvSink, DWORD FAR* pdwConnection);
+ STDMETHODIMP Unadvise( DWORD dwConnection);
+ STDMETHODIMP EnumAdvise( LPENUMSTATDATA FAR* ppenumAdvise);
+ STDMETHODIMP GetMiscStatus(DWORD dwAspect, DWORD FAR* pdwStatus);
+ STDMETHODIMP SetColorScheme( LPLOGPALETTE lpLogpal);
+
+ // *** IParseDisplayName method ***
+ STDMETHODIMP ParseDisplayName(
+ LPBC pbc,
+ LPOLESTR lpszDisplayName,
+ ULONG FAR* pchEaten,
+ LPMONIKER FAR* ppmkOut) ;
+
+ // *** IOleContainer methods ***
+ STDMETHODIMP EnumObjects(DWORD grfFlags, LPENUMUNKNOWN FAR* ppenumUnknown);
+ STDMETHODIMP LockContainer(BOOL fLock);
+
+ // *** IOleItemContainer methods ***
+ STDMETHODIMP GetObject(
+ LPOLESTR lpszItem,
+ DWORD dwSpeedNeeded,
+ LPBINDCTX pbc,
+ REFIID riid,
+ LPVOID FAR* ppvObject);
+
+ STDMETHODIMP GetObjectStorage(
+ LPOLESTR lpszItem,
+ LPBINDCTX pbc,
+ REFIID riid,
+ LPVOID FAR* ppvStorage);
+
+ STDMETHODIMP IsRunning(LPOLESTR lpszItem) ;
+
+ // *** IOleClientSite
+ STDMETHODIMP SaveObject (void);
+ STDMETHODIMP GetContainer (LPOLECONTAINER FAR *ppContainer);
+ STDMETHODIMP ShowObject (void);
+ STDMETHODIMP OnShowWindow (BOOL fShow);
+ STDMETHODIMP RequestNewObjectLayout (void);
+
+private:
+
+ IUnknown * _punk;
+
+ IMoniker * _pmkContainer;
+
+ IStorage * _psStg1;
+
+ IStorage * _psStg2;
+};
+
+
+class CUnknownBasicBnd : public IUnknown
+{
+public:
+
+ CUnknownBasicBnd(IUnknown *punk);
+
+ ~CUnknownBasicBnd(void);
+
+ // *** IUnknown
+ STDMETHODIMP QueryInterface(REFIID iid, void FAR * FAR * ppv);
+ STDMETHODIMP_(ULONG) AddRef(void);
+ STDMETHODIMP_(ULONG) Release(void);
+
+private:
+
+ CBasicBnd * _pbasicbnd;
+
+ ULONG _cRefs;
+};
+
+
+#endif // __BSCBND_H__
diff --git a/private/oleutest/balls/common/cact.cxx b/private/oleutest/balls/common/cact.cxx
new file mode 100644
index 000000000..07006830c
--- /dev/null
+++ b/private/oleutest/balls/common/cact.cxx
@@ -0,0 +1,547 @@
+//+-------------------------------------------------------------------
+//
+// File: cact.cxx
+//
+// Contents: object activation test class
+//
+// Classes: CActTest
+//
+// Functions:
+//
+// History: 23-Nov-92 Ricksa Created
+//
+//--------------------------------------------------------------------
+
+#include <pch.cxx>
+#pragma hdrstop
+#include <cact.hxx> // CTestAct
+
+// We need a semaphore to synchronize loads and releases.
+CMutexSem mxsLoadRelease;
+
+SAFE_INTERFACE_PTR(XIStream, IStream)
+
+#define XPOS OLESTR("XPOS")
+#define YPOS OLESTR("YPOS")
+
+
+HRESULT ReadPos(IStorage *pstg, LPOLESTR pwszStream, ULONG *pulPos)
+{
+ HRESULT hr;
+
+ BEGIN_BLOCK
+
+ XIStream xstrm;
+
+ // Read the streams for xpos and ypos
+ hr = pstg->OpenStream(pwszStream, NULL,
+ STGM_READ | STGM_SHARE_EXCLUSIVE, NULL, &xstrm);
+
+ if (FAILED(hr))
+ {
+ EXIT_BLOCK;
+ }
+
+ ULONG cb;
+
+ hr = xstrm->Read(pulPos, sizeof(*pulPos), &cb);
+
+ if (FAILED(hr))
+ {
+ EXIT_BLOCK;
+ }
+
+ hr = ResultFromScode(S_OK);
+
+ END_BLOCK
+
+ return hr;
+}
+
+HRESULT WritePos(IStorage *pstg, LPOLESTR pwszStream, ULONG ulPos)
+{
+ HRESULT hr;
+
+ BEGIN_BLOCK
+
+ XIStream xstrm;
+
+ // Read the streams for xpos and ypos
+ hr = pstg->CreateStream(pwszStream,
+ STGM_CREATE | STGM_WRITE | STGM_SHARE_EXCLUSIVE, NULL, NULL,
+ &xstrm);
+
+ if (FAILED(hr))
+ {
+ EXIT_BLOCK;
+ }
+
+
+ ULONG cb;
+
+ hr = xstrm->Write(&ulPos, sizeof(ulPos), &cb);
+
+ if (FAILED(hr))
+ {
+ EXIT_BLOCK;
+ }
+
+ hr = ResultFromScode(S_OK);
+
+ END_BLOCK
+
+ return hr;
+}
+
+CTestAct::CTestAct(REFCLSID rclsid)
+ : _rclsid(rclsid), _fDirty(FALSE), _xPos(0), _yPos(0),
+ _fSaveInprogress(FALSE), _pstg(NULL), _dwRegister(0), _cRefs(1)
+{
+ // Use as a flag for whether a file name has been assigned
+ _awszCurFile[0] = 0;
+
+ GlobalRefs(TRUE);
+}
+
+CTestAct::~CTestAct(void)
+{
+ if (_pstg != NULL)
+ {
+ // Release the storage because we are done with it
+ ULONG ulCnt = _pstg->Release();
+
+#if 0
+ // this test is not valid when running stress
+ if (ulCnt != 0)
+ {
+ DebugBreak();
+ }
+#endif
+
+ }
+
+ if (_dwRegister)
+ {
+ IRunningObjectTable *prot;
+ GetRunningObjectTable(NULL, &prot);
+ prot->Revoke(_dwRegister);
+ prot->Release();
+ }
+
+ GlobalRefs(FALSE);
+}
+
+STDMETHODIMP CTestAct::QueryInterface(REFIID iid, void **ppv)
+{
+ HRESULT hr = ResultFromScode(S_OK);
+
+ // We support IUnknown, IPersistFile and IBalls
+ if (IsEqualIID(iid, IID_IUnknown))
+ {
+ *ppv = (IBalls *) this;
+ }
+ else if (IsEqualIID(iid, IID_IPersistFile))
+ {
+ *ppv = (IPersistFile *) this;
+ }
+ else if (IsEqualIID(iid, IID_IPersistStorage))
+ {
+ *ppv = (IPersistStorage *) this;
+ }
+ else if (IsEqualIID(iid, IID_IBalls))
+ {
+ *ppv = (IBalls *) this;
+ }
+ else
+ {
+ *ppv = NULL;
+ hr = ResultFromScode(E_NOINTERFACE);
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ AddRef();
+ }
+
+ return hr;
+}
+
+STDMETHODIMP_(ULONG) CTestAct::AddRef(void)
+{
+ InterlockedIncrement(&_cRefs);
+ return _cRefs;
+}
+
+STDMETHODIMP_(ULONG) CTestAct::Release(void)
+{
+ CLock lck(mxsLoadRelease);
+
+ if (InterlockedDecrement(&_cRefs) == 0)
+ {
+ delete this;
+ return 0;
+ }
+
+ return _cRefs;
+}
+
+STDMETHODIMP CTestAct::GetClassID(LPCLSID lpClassID)
+{
+ *lpClassID = _rclsid;
+ return ResultFromScode(S_OK);
+}
+
+STDMETHODIMP CTestAct::IsDirty()
+{
+ return (_fDirty) ? ResultFromScode(S_OK) : ResultFromScode(S_FALSE);
+}
+
+STDMETHODIMP CTestAct::Load(LPCOLESTR lpszFileName, DWORD grfMode)
+{
+ CLock lck(mxsLoadRelease);
+
+ HRESULT hr;
+
+ BEGIN_BLOCK
+
+ hr = StgOpenStorage(lpszFileName, NULL,
+ STGM_READWRITE | STGM_SHARE_EXCLUSIVE, NULL, NULL, &_pstg);
+
+ if (FAILED(hr))
+ {
+#if 0
+ // this test is not valid when running stress
+ if (hr == STG_E_LOCKVIOLATION)
+ {
+ DebugBreak();
+ }
+#endif
+
+ EXIT_BLOCK;
+ }
+
+ // Get the saved xposition
+ hr = GetData();
+
+ if (FAILED(hr))
+ {
+ EXIT_BLOCK;
+ }
+
+ // Since everything went Ok save the file name
+ olestrcpy(_awszCurFile, lpszFileName);
+
+ // Create a file moniker for the object.
+ // Cast to non-constant string.
+ IMoniker *pmk;
+ CreateFileMoniker((LPOLESTR)lpszFileName, &pmk);
+
+ // Register it in the running object table.
+ IRunningObjectTable *prot;
+ GetRunningObjectTable(NULL, &prot);
+ prot->Register(NULL, (IPersistFile *) this, pmk, &_dwRegister);
+
+ // Release the temporary objects
+ pmk->Release();
+ prot->Release();
+
+ END_BLOCK
+
+ return hr;
+}
+
+STDMETHODIMP CTestAct::Save(LPCOLESTR lpszFileName, BOOL fRemember)
+{
+ HRESULT hr;
+
+ BEGIN_BLOCK
+
+ IStorage *pstgNew;
+
+ // Save the data
+ if (olestrcmp(lpszFileName, _awszCurFile) == 0)
+ {
+ pstgNew = _pstg;
+ _fDirty = FALSE;
+ }
+ else
+ {
+ hr = StgCreateDocfile(lpszFileName,
+ STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
+ NULL, &pstgNew);
+ }
+
+ if (FAILED(hr))
+ {
+ EXIT_BLOCK;
+ }
+
+ WriteClassStg(pstgNew, _rclsid);
+
+ hr = SaveData(pstgNew);
+
+ if (FAILED(hr))
+ {
+ EXIT_BLOCK;
+ }
+
+ if (fRemember)
+ {
+ // Save the file name
+ olestrcpy(_awszCurFile, lpszFileName);
+
+
+ // Replace the storage
+ if (_pstg && pstgNew != _pstg)
+ {
+ _pstg->Release();
+ }
+ _pstg = pstgNew;
+
+ _fDirty = FALSE;
+ }
+ else
+ {
+ pstgNew->Release();
+ }
+
+ _fSaveInprogress = TRUE;
+
+ hr = ResultFromScode(S_OK);
+
+ END_BLOCK;
+
+ return hr;
+}
+
+STDMETHODIMP CTestAct::SaveCompleted(LPCOLESTR lpszFileName)
+{
+ _fSaveInprogress = FALSE;
+ return ResultFromScode(S_OK);
+}
+
+STDMETHODIMP CTestAct::GetCurFile(LPOLESTR FAR *lpszFileName)
+{
+ // Allocate a buffer for the file and copy in the data
+ if (_awszCurFile[0] == 0)
+ {
+ return ResultFromScode(S_FALSE);
+ }
+
+
+ IMalloc *pIMalloc;
+
+ HRESULT hr = CoGetMalloc(MEMCTX_TASK, &pIMalloc);
+
+ if (SUCCEEDED(hr))
+ {
+ *lpszFileName = (OLECHAR *) pIMalloc->Alloc(
+ olestrlen((_awszCurFile) + 1) * sizeof(OLECHAR));
+
+ olestrcpy(*lpszFileName, _awszCurFile);
+
+ hr = ResultFromScode(S_OK);
+ }
+
+ return hr;
+}
+
+STDMETHODIMP CTestAct::MoveBall(ULONG xPos, ULONG yPos)
+{
+ if (!_fSaveInprogress)
+ {
+ _fDirty = TRUE;
+ _xPos = xPos;
+ _yPos = yPos;
+ return S_OK;
+ }
+
+ // Can't change state because a save is still pending
+ return ResultFromScode(E_UNEXPECTED);
+}
+
+STDMETHODIMP CTestAct::GetBallPos(ULONG *xPos, ULONG *yPos)
+{
+ *xPos = _xPos;
+ *yPos = _yPos;
+ return S_OK;
+}
+
+STDMETHODIMP CTestAct::IsOverLapped(IBalls *pIBall)
+{
+ ULONG xPos;
+ ULONG yPos;
+
+ HRESULT hr = pIBall->GetBallPos(&xPos, &yPos);
+
+ if (SUCCEEDED(hr))
+ {
+ if ((xPos == _xPos) && (yPos == _yPos))
+ {
+ hr = ResultFromScode(S_OK);
+ }
+ else
+ {
+ hr = ResultFromScode(S_FALSE);
+ }
+ }
+
+ return hr;
+}
+
+STDMETHODIMP CTestAct::IsContainedIn(ICube *pICube)
+{
+ ULONG xPos;
+ ULONG yPos;
+
+ HRESULT hr = pICube->GetCubePos(&xPos, &yPos);
+
+ if (SUCCEEDED(hr))
+ {
+ if ((xPos == _xPos) && (yPos == _yPos))
+ {
+ hr = ResultFromScode(S_OK);
+ }
+ else
+ {
+ hr = ResultFromScode(S_FALSE);
+ }
+ }
+
+ return hr;
+
+}
+
+STDMETHODIMP CTestAct::Clone(IBalls **ppIBall)
+{
+ CTestAct *ptballs = new CTestAct(_rclsid);
+
+ ptballs->_xPos = _xPos;
+ ptballs->_yPos = _yPos;
+ ptballs->_fDirty = _fDirty;
+ _pstg->AddRef();
+ ptballs->_pstg = _pstg;
+ olestrcpy(ptballs->_awszCurFile, _awszCurFile);
+ return ResultFromScode(S_OK);
+}
+
+STDMETHODIMP CTestAct::Echo(IUnknown *punkIn, IUnknown**ppunkOut)
+{
+ *ppunkOut = punkIn;
+ return S_OK;
+}
+
+STDMETHODIMP CTestAct::InitNew(LPSTORAGE pStg)
+{
+ pStg->AddRef();
+ _pstg = pStg;
+ WriteClassStg(_pstg, _rclsid);
+
+ return ResultFromScode(S_OK);
+}
+
+STDMETHODIMP CTestAct::Load(LPSTORAGE pStg)
+{
+ HRESULT hr;
+
+ _pstg = pStg;
+
+ hr = GetData();
+
+ if (SUCCEEDED(hr))
+ {
+ _pstg->AddRef();
+ }
+ else
+ {
+ _pstg = NULL;
+ }
+
+ return hr;
+}
+
+STDMETHODIMP CTestAct::Save(
+ LPSTORAGE pStgSave,
+ BOOL fSameAsLoad)
+{
+ HRESULT hr;
+
+ if (!fSameAsLoad)
+ {
+ if (_pstg)
+ _pstg->Release();
+
+ _pstg = pStgSave;
+
+ pStgSave->AddRef();
+ }
+ else
+ {
+ pStgSave = _pstg;
+ }
+
+ WriteClassStg(pStgSave, _rclsid);
+
+ hr = SaveData(pStgSave);
+
+ _fSaveInprogress = TRUE;
+
+ return hr;
+}
+
+STDMETHODIMP CTestAct::SaveCompleted(LPSTORAGE pStgSaved)
+{
+ _fSaveInprogress = FALSE;
+ return ResultFromScode(S_OK);
+}
+
+STDMETHODIMP CTestAct::HandsOffStorage(void)
+{
+ // Figure out what to do here!
+ return ResultFromScode(E_UNEXPECTED);
+}
+
+HRESULT CTestAct::GetData(void)
+{
+ HRESULT hr;
+
+ BEGIN_BLOCK
+
+ // Get the saved xposition
+ hr = ReadPos(_pstg, XPOS, &_xPos);
+
+ if (FAILED(hr))
+ {
+ EXIT_BLOCK;
+ }
+
+ // Get the saved yposition
+ hr = ReadPos(_pstg, YPOS, &_yPos);
+
+ END_BLOCK
+
+ return hr;
+}
+
+HRESULT CTestAct::SaveData(IStorage *pstg)
+{
+ HRESULT hr;
+
+ BEGIN_BLOCK
+
+ // Get the saved xposition
+ hr = WritePos(pstg, XPOS, _xPos);
+
+ if (FAILED(hr))
+ {
+ EXIT_BLOCK;
+ }
+
+ // Get the saved yposition
+ hr = WritePos(pstg, YPOS, _yPos);
+
+
+ END_BLOCK
+
+ return hr;
+}
diff --git a/private/oleutest/balls/common/cact.hxx b/private/oleutest/balls/common/cact.hxx
new file mode 100644
index 000000000..e0a39f95c
--- /dev/null
+++ b/private/oleutest/balls/common/cact.hxx
@@ -0,0 +1,94 @@
+#ifndef __CACT_HXX__
+#define __CACT_HXX__
+
+#include <otrack.hxx>
+#include <icube.h>
+#include <iballs.h>
+
+
+
+#define BEGIN_BLOCK do {
+#define EXIT_BLOCK break
+#define END_BLOCK }while(FALSE);
+
+class CTestAct : public IPersistFile, public IBalls, public IPersistStorage
+{
+public:
+ CTestAct(REFCLSID rclsid);
+
+ ~CTestAct(void);
+
+ // IUnknown
+ STDMETHOD(QueryInterface)(REFIID iid, void **ppv);
+
+ STDMETHODIMP_(ULONG) AddRef(void);
+
+ STDMETHODIMP_(ULONG) Release(void);
+
+ // IPersist
+ STDMETHOD(GetClassID)(LPCLSID lpClassID);
+
+ // IPersistFile
+ STDMETHOD(IsDirty)();
+
+ STDMETHOD(Load)(LPCOLESTR lpszFileName, DWORD grfMode);
+
+ STDMETHOD(Save)(LPCOLESTR lpszFileName, BOOL fRemember);
+
+ STDMETHOD(SaveCompleted)(LPCOLESTR lpszFileName);
+
+ STDMETHOD(GetCurFile)(LPOLESTR FAR * lpszFileName);
+
+ // IPersistStorage
+ STDMETHOD(InitNew)(LPSTORAGE pStg);
+
+ STDMETHOD(Load)(LPSTORAGE pStg);
+
+ STDMETHOD(Save)(
+ LPSTORAGE pStgSave,
+ BOOL fSameAsLoad);
+
+ STDMETHOD(SaveCompleted)(LPSTORAGE pStgSaved);
+
+ STDMETHOD(HandsOffStorage)(void);
+
+ // IBalls
+ STDMETHOD(MoveBall)(ULONG xPos, ULONG yPos);
+
+ STDMETHOD(GetBallPos)(ULONG *xPos, ULONG *yPos);
+
+ STDMETHOD(IsOverLapped)(IBalls *pIBall);
+
+ STDMETHOD(IsContainedIn)(ICube *pICube);
+
+ STDMETHOD(Clone)(IBalls **ppIBall);
+
+ STDMETHOD(Echo)(IUnknown *punkIn, IUnknown**ppunkOut);
+
+private:
+
+ HRESULT GetData(void);
+
+ HRESULT SaveData(IStorage *pstg);
+
+ REFCLSID _rclsid;
+
+ IStorage * _pstg;
+
+ OLECHAR _awszCurFile[MAX_PATH];
+
+ BOOL _fDirty;
+
+ BOOL _fSaveInprogress;
+
+ ULONG _xPos;
+
+ ULONG _yPos;
+
+ DWORD _dwRegister;
+
+ LONG _cRefs;
+};
+
+
+#endif // __CACT_HXX__
diff --git a/private/oleutest/balls/common/cballs.cxx b/private/oleutest/balls/common/cballs.cxx
new file mode 100644
index 000000000..f9736c0a3
--- /dev/null
+++ b/private/oleutest/balls/common/cballs.cxx
@@ -0,0 +1,435 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1992.
+//
+// File: cballs.cxx
+//
+// Contents: implementations for CBall
+//
+// Functions:
+// CBall::CBall
+// CBall::~CBall
+// CBall::QueryInterface
+// CBall::CreateBall
+// CBall::MoveBall
+// CBall::GetBallPos
+// CBall::IsOverLapped
+// CBall::IsContainedIn
+// CBall::Clone
+// CBall::Echo
+//
+// CBallCtrlUnk::CBallCtrlUnk
+// CBallCtrlUnk::~CBallCtrlUnk
+// CBallCtrlUnk::QueryInterface
+// CBallCtrlUnk::AddRef
+// CBallCtrlUnk::Release
+//
+// History: 06-Aug-92 Ricksa Created
+//
+//--------------------------------------------------------------------------
+
+#include <pch.cxx>
+#pragma hdrstop
+#include <cballs.hxx> // class definition
+#include <icube.h> // ICube definition
+
+
+#define CUBE_WIDTH 20
+
+
+//+-------------------------------------------------------------------------
+//
+// Method: CBall::CBall
+//
+// Synopsis: Creates the application window
+//
+// Arguments: [pisb] - ISysBind instance
+//
+// History: 06-Aug-92 Ricksa Created
+//
+//--------------------------------------------------------------------------
+CBall::CBall(IUnknown *punkOuter)
+ : _xPos(BALL_UNDEF),
+ _yPos(BALL_UNDEF),
+ _punkOuter(punkOuter)
+{
+ CreateBall(0,0);
+
+ GlobalRefs(TRUE);
+}
+
+//+-------------------------------------------------------------------------
+//
+// Method: CBall::~CBall
+//
+// Synopsis: Cleans up object
+//
+// History: 06-Aug-92 Ricksa Created
+//
+//--------------------------------------------------------------------------
+CBall::~CBall(void)
+{
+ GlobalRefs(FALSE);
+
+ // automatic actions are enough
+}
+
+
+//+-------------------------------------------------------------------------
+//
+// Method: CBall::QueryInterface
+//
+// Synopsis: Gets called when a WM_COMMAND message received.
+//
+// Arguments: [ifid] - interface instance requested
+// [ppunk] - where to put pointer to interface instance
+//
+// Returns: S_OK or ERROR_BAD_COMMAND
+//
+// History: 06-Aug-92 Ricksa Created
+//
+//--------------------------------------------------------------------------
+STDMETHODIMP CBall::QueryInterface(REFIID riid, void **ppunk)
+{
+ return _punkOuter->QueryInterface(riid, ppunk);
+}
+
+//+-------------------------------------------------------------------------
+//
+// Method: CBall::AddRef
+//
+// History: 06-Aug-92 Ricksa Created
+//
+//--------------------------------------------------------------------------
+STDMETHODIMP_(ULONG) CBall::AddRef(void)
+{
+ return _punkOuter->AddRef();
+}
+
+//+-------------------------------------------------------------------------
+//
+// Method: CBall::Release
+//
+// History: 06-Aug-92 Ricksa Created
+//
+//--------------------------------------------------------------------------
+STDMETHODIMP_(ULONG) CBall::Release(void)
+{
+ return _punkOuter->Release();
+}
+
+
+//+-------------------------------------------------------------------------
+//
+// Method: CBall::QueryInternalIface
+//
+// Synopsis: Gets called when a WM_COMMAND message received.
+//
+// Arguments: [ifid] - interface instance requested
+// [ppunk] - where to put pointer to interface instance
+//
+// Returns: S_OK or ERROR_BAD_COMMAND
+//
+// History: 06-Aug-92 Ricksa Created
+//
+//--------------------------------------------------------------------------
+STDMETHODIMP CBall::QueryInternalIface(REFIID riid, void **ppunk)
+{
+ SCODE sc = E_FAIL;
+
+ if (IsEqualIID(riid,IID_IUnknown) ||
+ IsEqualIID(riid,IID_IBalls))
+ {
+ // Increase the reference count
+ *ppunk = (void *)(IBalls *) this;
+ AddRef();
+
+ // Set to success
+ sc = S_OK;
+ }
+
+ return sc;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Method: CBall::CreateBall
+//
+// Synopsis: Creates a ball on the screen
+//
+// Arguments: [xPos] - x position for new ball
+// [yPos] - y position for new ball
+//
+// Returns: S_OK or ERROR_BAD_COMMAND
+//
+// History: 06-Aug-92 Ricksa Created
+//
+//--------------------------------------------------------------------------
+STDMETHODIMP CBall::CreateBall(ULONG xPos, ULONG yPos)
+{
+ SCODE sc = E_FAIL;
+
+ if (xPos != (ULONG) -1)
+ {
+ // Update data
+ _xPos = xPos;
+ _yPos = yPos;
+ sc = S_OK;
+
+ // Format message for the screen
+ Display(TEXT("Create Ball xPos = %ld yPos = %ld\n"), xPos, yPos);
+ }
+
+ return sc;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: CBall::MoveBall
+//
+// Synopsis: Move the ball from one position to another
+//
+// Arguments: [xPos] - new x position for the ball
+// [yPos] - new y position for the ball
+//
+// Returns: S_OK
+//
+// History: 06-Aug-92 Ricksa Created
+//
+//--------------------------------------------------------------------------
+STDMETHODIMP CBall::MoveBall(ULONG xPos, ULONG yPos)
+{
+ // Set the position
+ _xPos = xPos;
+ _yPos = yPos;
+
+ // Format message for the screen
+ Display(TEXT("Move Ball xPos = %ld yPos = %ld\n"), xPos, yPos);
+ return S_OK;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: CBall::GetBallPos
+//
+// Synopsis: Get the current position of the ball
+//
+// Arguments: [hWindow] - handle for the window
+//
+// Returns: S_OK
+//
+// History: 06-Aug-92 Ricksa Created
+//
+//--------------------------------------------------------------------------
+STDMETHODIMP CBall::GetBallPos(ULONG *pxPos, ULONG *pyPos)
+{
+ *pxPos = _xPos;
+ *pyPos = _yPos;
+
+ // Format message for the screen
+ Display(TEXT("Get Ball Pos xPos = %ld yPos = %ld\n"), _xPos, _yPos);
+ return S_OK;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: CBall::IsOverLapped
+//
+// Synopsis: Check if this ball overlaps the given ball.
+//
+// Arguments: [hWindow] - handle for the window
+// [pIBall] - other ball to compare with
+//
+// Returns: S_OK
+//
+// History: 06-Aug-92 Ricksa Created
+//
+//--------------------------------------------------------------------------
+STDMETHODIMP CBall::IsOverLapped(IBalls *pIBall)
+{
+ ULONG xPos, yPos;
+
+ SCODE sc = pIBall->GetBallPos(&xPos, &yPos);
+
+ if (SUCCEEDED(sc))
+ {
+ if ((abs(xPos - _xPos) < BALL_DIAMETER) &&
+ (abs(yPos - _yPos) < BALL_DIAMETER))
+ {
+ // Format message for the screen
+ Display(TEXT("Balls OverLap. xpos = %ld yPos = %ld\n"), xPos, yPos);
+ }
+ else
+ {
+ // Format message for the screen
+ Display(TEXT("Balls Dont OverlLap. xPos = %ld yPos = %ld\n"), xPos, yPos);
+ }
+ }
+
+ return sc;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: CBall::IsContainedIn
+//
+// Synopsis: Check if this ball is contained in the given cube.
+//
+// Arguments: [hWindow] - handle for the window
+// [pICube] - cube to compare with
+//
+// Returns: S_OK
+//
+// History: 06-Aug-92 Ricksa Created
+//
+//--------------------------------------------------------------------------
+STDMETHODIMP CBall::IsContainedIn(ICube *pICube)
+{
+ ULONG xPos, yPos;
+
+ SCODE sc = pICube->GetCubePos(&xPos, &yPos);
+
+ if (SUCCEEDED(sc))
+ {
+ if ((abs(xPos - _xPos) < CUBE_WIDTH) &&
+ (abs(yPos - _yPos) < CUBE_WIDTH))
+ {
+ // Format message for the screen
+ Display(TEXT("Ball Contained in Cube. xPos = %ld yPos = %ld\n"), xPos, yPos);
+ }
+ else
+ {
+ // Format message for the screen
+ Display(TEXT("Ball Outside Cube. xPos = %ld yPos = %ld\n"), xPos, yPos);
+ }
+ }
+
+ return sc;
+}
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: CBall::Clone
+//
+// Synopsis: make a copy of this ball
+//
+// Arguments: [hWindow] - handle for the window
+// [ppIBall] - new ball to return
+//
+// Returns: S_OK
+//
+// History: 06-Aug-92 Ricksa Created
+//
+//--------------------------------------------------------------------------
+STDMETHODIMP CBall::Clone(IBalls **ppIBall)
+{
+ Display(TEXT("Clone Ball\n"));
+
+ CBallCtrlUnk *pNew = new CBallCtrlUnk(NULL);
+
+ SCODE sc = pNew->QueryInterface(IID_IBalls, (void **)ppIBall);
+
+ pNew->Release();
+
+ return sc;
+}
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: CBall::Echo
+//
+// Synopsis: returns the same interface passed in. this is just to test
+// marshalling in and out interfaces.
+//
+// Arguments: [hWindow] - handle for the window
+// [punkIn] - IUnknown in
+// [ppunkOut] - IUnknown out
+//
+// Returns: S_OK
+//
+// History: 06-Aug-92 Ricksa Created
+//
+//--------------------------------------------------------------------------
+STDMETHODIMP CBall::Echo(IUnknown *punkIn, IUnknown **ppunkOut)
+{
+ Display(TEXT("Echo Interface\n"));
+
+ punkIn->AddRef(); // keep the in parameter...
+ *ppunkOut = punkIn; // cause we're gonna return it.
+
+ return S_OK;
+}
+
+
+#pragma warning(disable:4355) // 'this' used in base member init list
+//+-------------------------------------------------------------------------
+//
+// Method: CBallCtrlUnk::CBallCtrlUnk
+//
+// Synopsis:
+//
+// Arguments:
+//
+// History: 06-Aug-92 Ricksa Created
+//
+//--------------------------------------------------------------------------
+CBallCtrlUnk::CBallCtrlUnk(IUnknown *punkOuter)
+ : _ball((punkOuter) ? punkOuter : this)
+{
+ ENLIST_TRACKING(CBallCtrlUnk);
+}
+#pragma warning(default:4355) // 'this' used in base member init list
+
+
+//+-------------------------------------------------------------------------
+//
+// Method: CBallCtrlUnk::~CBallCtrlUnk
+//
+// Synopsis: Cleans up object
+//
+// History: 06-Aug-92 Ricksa Created
+//
+//--------------------------------------------------------------------------
+CBallCtrlUnk::~CBallCtrlUnk(void)
+{
+ // automatic actions are enough
+}
+
+
+//+-------------------------------------------------------------------------
+//
+// Method: CBallCtrlUnk::QueryInterface
+//
+// Synopsis: Gets called when a WM_COMMAND message received.
+//
+// Arguments: [ifid] - interface instance requested
+// [ppunk] - where to put pointer to interface instance
+//
+// Returns: S_OK or ERROR_BAD_COMMAND
+//
+// History: 06-Aug-92 Ricksa Created
+//
+//--------------------------------------------------------------------------
+STDMETHODIMP CBallCtrlUnk::QueryInterface(REFIID riid, void **ppunk)
+{
+ SCODE sc = E_FAIL;
+
+ if (IsEqualIID(riid,IID_IUnknown))
+ {
+ // Increase the reference count
+ *ppunk = (void *)(IUnknown *) this;
+ AddRef();
+
+ // Set to success
+ sc = S_OK;
+ }
+ else
+ {
+ sc = _ball.QueryInternalIface(riid, ppunk);
+ }
+
+ return sc;
+}
diff --git a/private/oleutest/balls/common/cballs.hxx b/private/oleutest/balls/common/cballs.hxx
new file mode 100644
index 000000000..a4eb87f2d
--- /dev/null
+++ b/private/oleutest/balls/common/cballs.hxx
@@ -0,0 +1,107 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1992.
+//
+// File: cballs.hxx
+//
+// Contents: Class to encapsulate demo of distributed binding interface
+//
+// Classes: CBall
+//
+// History: 06-Aug-92 Ricksa Created
+//
+//--------------------------------------------------------------------------
+#ifndef __BALLS__
+#define __BALLS__
+
+#include <sem.hxx>
+#include <otrack.hxx>
+#include <iballs.h>
+#include <ballscf.hxx>
+
+
+#define BALL_UNDEF 0xFFFFFFFF
+#define BALL_DIAMETER 10
+
+
+//+-------------------------------------------------------------------------
+//
+// Class: CBall
+//
+// Purpose: Class to demostrate remote binding functionality
+//
+// Interface: QueryInterface
+// AddRef
+// Release
+// CreateBall - create a ball
+// MoveBall - move a ball
+// GetBallPos - get the ball position (x,y)
+// IsOverLapped - see if other ball is overlapped with this ball
+// IsContainedIn - see if ball is inside given cube
+// Clone - make a new ball at the same position as this
+// Echo - returns the same interface passed in
+//
+// History: 06-Aug-92 Ricksa Created
+//
+//--------------------------------------------------------------------------
+class CBall : public IBalls
+{
+public:
+ CBall(IUnknown *punkOuter);
+ ~CBall(void);
+
+ STDMETHOD(QueryInterface)(REFIID riid, void **ppunk);
+ STDMETHOD_(ULONG, AddRef)(void);
+ STDMETHOD_(ULONG, Release)(void);
+
+ STDMETHOD(QueryInternalIface)(REFIID riid, void **ppunk);
+
+ STDMETHOD(CreateBall)(ULONG xPos, ULONG yPos);
+ STDMETHOD(MoveBall)(ULONG xPos, ULONG yPos);
+ STDMETHOD(GetBallPos)(ULONG *xPos, ULONG *yPos);
+ STDMETHOD(IsOverLapped)(IBalls *pIBall);
+ STDMETHOD(IsContainedIn)(ICube *pICube);
+ STDMETHOD(Clone)(IBalls **ppIBall);
+ STDMETHOD(Echo)(IUnknown *punkIn, IUnknown **ppunkOut);
+
+private:
+
+ ULONG _xPos;
+ ULONG _yPos;
+
+ IUnknown * _punkOuter;
+};
+
+
+//+-------------------------------------------------------------------------
+//
+// Class: CBallCtrlUnk
+//
+// Purpose: Class to demostrate remote binding functionality
+//
+// Interface: QueryInterface
+// AddRef
+// Release
+//
+// History: 06-Aug-92 Ricksa Created
+//
+//--------------------------------------------------------------------------
+class CBallCtrlUnk : INHERIT_TRACKING,
+ public IUnknown
+{
+public:
+
+ CBallCtrlUnk(IUnknown *punkOuter);
+
+ STDMETHOD(QueryInterface)(REFIID riid, void **ppunk);
+ DECLARE_STD_REFCOUNTING;
+
+private:
+ ~CBallCtrlUnk(void);
+
+ CBall _ball;
+};
+
+
+#endif // __BALLS__
diff --git a/private/oleutest/balls/common/ccubes.cxx b/private/oleutest/balls/common/ccubes.cxx
new file mode 100644
index 000000000..13606fea8
--- /dev/null
+++ b/private/oleutest/balls/common/ccubes.cxx
@@ -0,0 +1,314 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1992.
+//
+// File: cubes.cxx
+//
+// Contents: implementations for CCube
+//
+// Functions:
+// CCube::CCube
+// CCube::~CCube
+// CCube::QueryInterface
+// CCube::CreateCube
+// CCube::MoveCube
+// CCube::GetCubePos
+//
+// History: 06-Aug-92 Ricksa Created
+//
+//--------------------------------------------------------------------------
+
+#include <pch.cxx>
+#pragma hdrstop
+#include <ccubes.hxx> // class definition
+#include <iballs.h> // IBalls interface definiton
+
+
+#define CUBE_WIDTH 20
+
+
+//+-------------------------------------------------------------------------
+//
+// Method: CCube::CCube
+//
+// Synopsis: Creates the application window
+//
+// Arguments: [pisb] - ISysBind instance
+//
+// History: 06-Aug-92 Ricksa Created
+//
+//--------------------------------------------------------------------------
+CCube::CCube(void)
+ : _xPos(CUBE_UNDEF),
+ _yPos(CUBE_UNDEF)
+{
+ CreateCube(0,0);
+ GlobalRefs(TRUE);
+
+ ENLIST_TRACKING(CCube);
+}
+
+
+//+-------------------------------------------------------------------------
+//
+// Method: CCube::~CCube
+//
+// Synopsis: Cleans up object
+//
+// History: 06-Aug-92 Ricksa Created
+//
+//--------------------------------------------------------------------------
+CCube::~CCube(void)
+{
+ GlobalRefs(FALSE);
+
+ // automatic actions are enough
+}
+
+
+//+-------------------------------------------------------------------------
+//
+// Method: CCube::QueryInterface
+//
+// Synopsis: Gets called when a WM_COMMAND message received.
+//
+// Arguments: [ifid] - interface instance requested
+// [ppunk] - where to put pointer to interface instance
+//
+// Returns: S_OK or ERROR_BAD_COMMAND
+//
+// History: 06-Aug-92 Ricksa Created
+//
+//--------------------------------------------------------------------------
+STDMETHODIMP CCube::QueryInterface(REFIID riid, void **ppunk)
+{
+ SCODE sc = E_NOINTERFACE;
+ *ppunk = NULL;
+
+ if (IsEqualIID(riid, IID_IUnknown) ||
+ IsEqualIID(riid, IID_ICube))
+ {
+ // Increase the reference count
+ *ppunk = (void *)(ICube *) this;
+ AddRef();
+
+ // Set to success
+ sc = S_OK;
+ }
+
+ return sc;
+}
+
+
+//+-------------------------------------------------------------------------
+//
+// Method: CCube::CreateCube
+//
+// Synopsis: Creates a Cube on the screen
+//
+// Arguments: [xPos] - x position for new Cube
+// [yPos] - y position for new Cube
+//
+// Returns: S_OK or ERROR_BAD_COMMAND
+//
+// History: 06-Aug-92 Ricksa Created
+//
+//--------------------------------------------------------------------------
+STDMETHODIMP CCube::CreateCube(ULONG xPos, ULONG yPos)
+{
+ SCODE sc = E_FAIL;
+
+ if (xPos != (ULONG) -1)
+ {
+ // Update data
+ _xPos = xPos;
+ _yPos = yPos;
+ sc = S_OK;
+
+ // Format message for the screen
+ Display(TEXT("Create Cube xPos = %ld yPos = %ld\n"), xPos, yPos);
+ }
+
+ return sc;
+}
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: CCube::MoveCube
+//
+// Synopsis: Move the Cube from one position to another
+//
+// Arguments: [xPos] - new x position for the Cube
+// [yPos] - new y position for the Cube
+//
+// Returns: S_OK
+//
+// History: 06-Aug-92 Ricksa Created
+//
+//--------------------------------------------------------------------------
+STDMETHODIMP CCube::MoveCube(ULONG xPos, ULONG yPos)
+{
+ // Set the position
+ _xPos = xPos;
+ _yPos = yPos;
+
+ // Format message for the screen
+ Display(TEXT("Move Cube xPos = %ld yPos = %ld\n"), xPos, yPos);
+ return S_OK;
+}
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: CCube::GetCubePos
+//
+// Synopsis: Get the current position of the Cube
+//
+// Arguments: [hWindow] - handle for the window
+//
+// Returns: S_OK
+//
+// History: 06-Aug-92 Ricksa Created
+//
+//--------------------------------------------------------------------------
+STDMETHODIMP CCube::GetCubePos(ULONG *pxPos, ULONG *pyPos)
+{
+ *pxPos = _xPos;
+ *pyPos = _yPos;
+
+ // Format message for the screen
+ Display(TEXT("Get Cube Pos xPos = %ld yPos = %ld\n"), _xPos, _yPos);
+ return S_OK;
+}
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: CCube::Contains
+//
+// Synopsis: Check if this Cube is contained in the given cube.
+//
+// Arguments: [hWindow] - handle for the window
+// [pICube] - cube to compare with
+//
+// Returns: S_OK
+//
+// History: 06-Aug-92 Ricksa Created
+//
+//--------------------------------------------------------------------------
+STDMETHODIMP CCube::Contains(IBalls *pIBall)
+{
+ ULONG xPos, yPos;
+
+ SCODE sc = pIBall->GetBallPos(&xPos, &yPos);
+
+ if (SUCCEEDED(sc))
+ {
+ if ((abs(xPos - _xPos) < CUBE_WIDTH) &&
+ (abs(yPos - _yPos) < CUBE_WIDTH))
+ {
+ // Format message for the screen
+ Display(TEXT("Cube contains in Ball. xPos = %ld yPos = %ld\n"), xPos, yPos);
+ }
+ else
+ {
+ // Format message for the screen
+ Display(TEXT("Ball Outside Cube. xPos = %ld yPos = %ld\n"), xPos, yPos);
+ }
+ }
+
+ return sc;
+}
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: CCube::SimpleCall
+//
+// Synopsis: checks the TID and LID to make sure they match the callers.
+//
+// Arguments:
+//
+// Returns: S_OK
+//
+// History: 16-Jan-96 RickHi Created
+//
+//--------------------------------------------------------------------------
+STDMETHODIMP CCube::SimpleCall(DWORD pidCaller, DWORD tidCaller, GUID lidCaller)
+{
+ HRESULT hr = S_OK;
+
+ GUID lid;
+ HRESULT hr2 = CoGetCurrentLogicalThreadId(&lid);
+
+ if (SUCCEEDED(hr2))
+ {
+ if (!IsEqualGUID(lid, lidCaller))
+ {
+ // LIDs dont match, error
+ hr |= 0x80000001;
+ }
+ }
+ else
+ {
+ return hr2;
+ }
+
+ DWORD tid;
+ hr2 = CoGetCallerTID(&tid);
+
+ if (SUCCEEDED(hr2))
+ {
+ if (pidCaller == GetCurrentProcessId())
+ {
+ // if in same process, CoGetCallerTID should return S_OK
+ if (hr2 != S_OK)
+ {
+ hr |= 0x80000002;
+ }
+ }
+ else
+ {
+ // if in different process, CoGetCallerTID should return S_FALSE
+ if (hr2 != S_FALSE)
+ {
+ hr |= 0x80000004;
+ }
+ }
+ }
+ else
+ {
+ return hr2;
+ }
+
+ return hr;
+}
+
+
+
+STDMETHODIMP CCube::PrepForInputSyncCall(IUnknown *pUnkIn)
+{
+ // just remember the input ptr
+
+ _pUnkIn = pUnkIn;
+ _pUnkIn->AddRef();
+
+ return S_OK;
+}
+
+STDMETHODIMP CCube::InputSyncCall()
+{
+ // just attempt to release an Interface Pointer inside an InputSync
+ // method.
+
+ if (_pUnkIn)
+ {
+ if (_pUnkIn->Release() != 0)
+ return RPC_E_CANTCALLOUT_ININPUTSYNCCALL;
+ }
+
+ return S_OK;
+}
diff --git a/private/oleutest/balls/common/ccubes.hxx b/private/oleutest/balls/common/ccubes.hxx
new file mode 100644
index 000000000..16dfbfca3
--- /dev/null
+++ b/private/oleutest/balls/common/ccubes.hxx
@@ -0,0 +1,77 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1992.
+//
+// File: cubes.hxx
+//
+// Contents: Class to encapsulate demo of distributed binding interface
+//
+// Classes: CCube
+//
+// History: 06-Aug-92 Rickhi Created
+//
+//--------------------------------------------------------------------------
+#ifndef __CUBES__
+#define __CUBES__
+
+#include <otrack.hxx>
+#include <icube.h> // interface def
+
+
+#define CUBE_UNDEF 0xFFFFFFFF
+#define CUBE_DIAMETER 10
+
+
+STDAPI CoGetCallerTID(DWORD *pTIDCaller);
+STDAPI CoGetCurrentLogicalThreadId(GUID *pguid);
+
+//+-------------------------------------------------------------------------
+//
+// Class: CCube
+//
+// Purpose: Class to demostrate remote binding functionality
+//
+// Interface: QueryInterface
+// AddRef
+// Release
+// CreateCube - create a Cube
+// MoveCube - move a Cube
+// GetCubePos - get the Cube position (x,y)
+// IsOverLapped - see if other Cube is overlapped with this Cube
+// IsContainedIn - see if Cube is inside given cube
+// Clone - make a new Cube at the same position as this
+//
+// History: 06-Aug-92 Rickhi Created
+//
+//--------------------------------------------------------------------------
+
+class CCube : INHERIT_TRACKING,
+ public ICube
+{
+public:
+ CCube(void);
+
+ STDMETHOD(QueryInterface)(REFIID riid, void **ppunk);
+ DECLARE_STD_REFCOUNTING;
+
+ // ICube interface
+ STDMETHOD(CreateCube)(ULONG xPos, ULONG yPos);
+ STDMETHOD(MoveCube)(ULONG xPos, ULONG yPos);
+ STDMETHOD(GetCubePos)(ULONG *xPos, ULONG *yPos);
+ STDMETHOD(Contains)(IBalls *pIBall);
+ STDMETHOD(SimpleCall)(DWORD pidCaller, DWORD tidCaller, GUID lidCaller);
+ STDMETHODIMP PrepForInputSyncCall(IUnknown *pUnkIn);
+ STDMETHODIMP InputSyncCall();
+
+private:
+ ~CCube(void);
+
+ ULONG _xPos;
+ ULONG _yPos;
+
+ IUnknown *_pUnkIn;
+};
+
+
+#endif // __CUBES__
diff --git a/private/oleutest/balls/common/cfballs.cxx b/private/oleutest/balls/common/cfballs.cxx
new file mode 100644
index 000000000..ae989da0c
--- /dev/null
+++ b/private/oleutest/balls/common/cfballs.cxx
@@ -0,0 +1,127 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1992.
+//
+// File: cfballs.cxx
+//
+// Contents: implementations for CFactory
+//
+// Functions:
+// CCube::CCube
+// CCube::~CCube
+// CCube::QueryInterface
+// CCube::CreateCube
+// CCube::MoveCube
+// CCube::GetCubePos
+//
+// History: 06-Aug-92 Ricksa Created
+//
+//--------------------------------------------------------------------------
+
+#include <pch.cxx>
+#pragma hdrstop
+
+#include <ctballs.hxx>
+#include <cfballs.hxx>
+
+
+CFactory::CFactory(REFCLSID rclsid, BOOL fServer)
+ : _fServer(fServer), _clsid(rclsid), _cRefs(1), _cLocks(0)
+{
+ // Header does all the work
+}
+
+CFactory::~CFactory()
+{
+ // Default actions are enough
+}
+
+
+STDMETHODIMP CFactory::QueryInterface(REFIID iid, void FAR * FAR * ppv)
+{
+ if (IsEqualIID(iid, IID_IUnknown)
+ || IsEqualIID(iid, IID_IClassFactory))
+ {
+ *ppv = (IUnknown *) this;
+ AddRef();
+ return ResultFromSCode(S_OK);
+ }
+
+ *ppv = NULL;
+ return ResultFromSCode(E_NOINTERFACE);
+}
+
+STDMETHODIMP_(ULONG) CFactory::AddRef(void)
+{
+ InterlockedIncrement(&_cRefs);
+
+ if (!_fServer)
+ {
+ // This is not being used in a server so we want to bump the
+ // reference count. In a server we use the lock count rather
+ // than the reference count to tell whether we should go away.
+ GlobalRefs(TRUE);
+ }
+
+ return _cRefs;
+}
+
+STDMETHODIMP_(ULONG) CFactory::Release(void)
+{
+ BOOL fKeepObject = InterlockedDecrement(&_cRefs);
+
+ if (!_fServer)
+ {
+ // This is not being used in a server so we want to bump the
+ // reference count. In a server we use the lock count rather
+ // than the reference count to tell whether we should go away.
+ GlobalRefs(FALSE);
+ }
+
+ if (!fKeepObject)
+ {
+ delete this;
+ return 0;
+ }
+
+ return _cRefs;
+}
+
+STDMETHODIMP CFactory::CreateInstance(
+ IUnknown FAR* pUnkOuter,
+ REFIID iidInterface,
+ void FAR* FAR* ppv)
+{
+ if (pUnkOuter != NULL)
+ {
+ // Object does not support aggregation
+ return ResultFromSCode(E_NOINTERFACE);
+ }
+
+ CTestBalls *ptballs = new CTestBalls(_clsid);
+
+ HRESULT hr = ptballs->QueryInterface(iidInterface, ppv);
+
+ ptballs->Release();
+
+ return hr;
+}
+
+STDMETHODIMP CFactory::LockServer(BOOL fLock)
+{
+ if (fLock)
+ {
+ InterlockedIncrement(&_cLocks);
+
+ GlobalRefs(TRUE);
+ }
+ else
+ {
+ InterlockedDecrement(&_cLocks);
+
+ GlobalRefs(FALSE);
+ }
+
+ return ResultFromSCode(S_OK);
+}
diff --git a/private/oleutest/balls/common/cfballs.hxx b/private/oleutest/balls/common/cfballs.hxx
new file mode 100644
index 000000000..0b8705ad0
--- /dev/null
+++ b/private/oleutest/balls/common/cfballs.hxx
@@ -0,0 +1,38 @@
+
+
+
+class CFactory : public IClassFactory
+{
+public:
+
+ CFactory(REFCLSID rclsid, BOOL fServer);
+
+ ~CFactory(void);
+
+ // IUnknown
+ STDMETHOD(QueryInterface)(REFIID iid, void **ppv);
+
+ STDMETHOD_(ULONG, AddRef)(void);
+
+ STDMETHOD_(ULONG, Release)(void);
+
+
+ // IClassFactory
+ STDMETHOD(CreateInstance)(
+ IUnknown FAR* pUnkOuter,
+ REFIID riid,
+ LPVOID FAR* ppunkObject);
+
+ STDMETHOD(LockServer)(BOOL fLock);
+
+private:
+
+
+ BOOL _fServer;
+
+ CLSID _clsid;
+
+ LONG _cRefs;
+
+ LONG _cLocks;
+};
diff --git a/private/oleutest/balls/common/cloop.cxx b/private/oleutest/balls/common/cloop.cxx
new file mode 100644
index 000000000..f10a9d8fd
--- /dev/null
+++ b/private/oleutest/balls/common/cloop.cxx
@@ -0,0 +1,171 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1992.
+//
+// File: cloop.cxx
+//
+// Contents: implementations for CBall
+//
+// Functions:
+// CLoop::CLoop
+// CLoop::~CLoop
+// CLoop::QueryInterface
+//
+// History: 06-Aug-92 Ricksa Created
+//
+//--------------------------------------------------------------------------
+
+#include <pch.cxx>
+#pragma hdrstop
+#include <cloop.hxx> // class definition
+
+
+//+-------------------------------------------------------------------------
+//
+// Method: CLoop::CLoop
+//
+// Synopsis: Creates the application window
+//
+// Arguments: [pisb] - ISysBind instance
+//
+// History: 06-Aug-92 Ricksa Created
+//
+//--------------------------------------------------------------------------
+CLoop::CLoop(void)
+ : _pRemoteLoop(NULL)
+{
+ GlobalRefs(TRUE);
+
+ ENLIST_TRACKING(CLoop);
+}
+
+//+-------------------------------------------------------------------------
+//
+// Method: CLoop::~CLoop
+//
+// Synopsis: Cleans up object
+//
+// History: 06-Aug-92 Ricksa Created
+//
+//--------------------------------------------------------------------------
+CLoop::~CLoop(void)
+{
+ if (_pRemoteLoop)
+ {
+ _pRemoteLoop->Release();
+ }
+
+ GlobalRefs(FALSE);
+}
+
+
+//+-------------------------------------------------------------------------
+//
+// Method: CLoop::QueryInterface
+//
+// Synopsis: Gets called when a WM_COMMAND message received.
+//
+// Arguments: [ifid] - interface instance requested
+// [ppunk] - where to put pointer to interface instance
+//
+// Returns: S_OK or ERROR_BAD_COMMAND
+//
+// History: 06-Aug-92 Ricksa Created
+//
+//--------------------------------------------------------------------------
+STDMETHODIMP CLoop::QueryInterface(REFIID riid, void **ppunk)
+{
+ SCODE sc = E_NOINTERFACE;
+ *ppunk = NULL;
+
+ if (IsEqualIID(riid,IID_IUnknown) ||
+ IsEqualIID(riid,IID_ILoop))
+ {
+ // Increase the reference count
+ *ppunk = (void *)(ILoop *) this;
+ AddRef();
+
+ // Set to success
+ sc = S_OK;
+ }
+
+ return sc;
+}
+
+
+//+-------------------------------------------------------------------------
+//
+// Method: CLoop::Init
+//
+// Synopsis:
+//
+// Arguments:
+//
+// Returns: S_OK or ERROR_BAD_COMMAND
+//
+// History: 06-Aug-92 Ricksa Created
+//
+//--------------------------------------------------------------------------
+STDMETHODIMP CLoop::Init(ILoop *pRemoteLoop)
+{
+ _pRemoteLoop = pRemoteLoop;
+ _pRemoteLoop->AddRef();
+
+ // Format message for the screen
+ Display(TEXT("Loop Init %ld\n"), pRemoteLoop);
+
+ return S_OK;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: CLoop::Uninit
+//
+// Synopsis:
+//
+// Arguments:
+//
+// Returns: S_OK
+//
+// History: 06-Aug-92 Ricksa Created
+//
+//--------------------------------------------------------------------------
+STDMETHODIMP CLoop::Uninit(void)
+{
+ // Format message for the screen
+ Display(TEXT("Uninit %ld\n"), _pRemoteLoop);
+
+ if (_pRemoteLoop)
+ {
+ _pRemoteLoop->Release();
+ _pRemoteLoop = NULL;
+ }
+
+ return S_OK;
+}
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: CLoop::Loop
+//
+// Synopsis:
+//
+// Arguments:
+//
+// Returns: S_OK
+//
+// History: 06-Aug-92 Ricksa Created
+//
+//--------------------------------------------------------------------------
+STDMETHODIMP CLoop::Loop(ULONG ulLoopCount)
+{
+ // Format message for the screen
+ Display(TEXT("Loop Count = %ld\n"), ulLoopCount);
+
+ if (--ulLoopCount == 0)
+ return S_OK;
+ else
+ return _pRemoteLoop->Loop(ulLoopCount);
+}
diff --git a/private/oleutest/balls/common/cloop.hxx b/private/oleutest/balls/common/cloop.hxx
new file mode 100644
index 000000000..0ef2b21f9
--- /dev/null
+++ b/private/oleutest/balls/common/cloop.hxx
@@ -0,0 +1,57 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1992.
+//
+// File: CLoops.hxx
+//
+// Contents: Class to encapsulate demo of distributed binding interface
+//
+// Classes: CLoop
+//
+// History: 06-Aug-92 Ricksa Created
+//
+//--------------------------------------------------------------------------
+#ifndef __LOOPS__
+#define __LOOPS__
+
+#include <otrack.hxx>
+#include <iloop.h>
+#include <loopscf.hxx>
+
+
+//+-------------------------------------------------------------------------
+//
+// Class: CLoop
+//
+// Purpose: Class to demostrate remote binding functionality
+//
+// Interface: QueryInterface
+// AddRef
+// Release
+//
+// History: 06-Aug-92 Ricksa Created
+//
+//--------------------------------------------------------------------------
+class CLoop : INHERIT_TRACKING,
+ public ILoop
+{
+public:
+ CLoop(void);
+
+ STDMETHOD(QueryInterface)(REFIID riid, void **ppunk);
+ DECLARE_STD_REFCOUNTING;
+
+ STDMETHOD(Init)(ILoop *pRemoteLoop);
+ STDMETHOD(Uninit)(void);
+ STDMETHOD(Loop)(ULONG ulLoopCount);
+
+private:
+ ~CLoop(void);
+
+ ILoop * _pRemoteLoop;
+};
+
+
+
+#endif // __LOOPS__
diff --git a/private/oleutest/balls/common/common.h b/private/oleutest/balls/common/common.h
new file mode 100644
index 000000000..77ac16980
--- /dev/null
+++ b/private/oleutest/balls/common/common.h
@@ -0,0 +1,56 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1991 - 1992.
+//
+// File: common.h
+//
+// Contents: headers shared by sources in common and in the servers and
+// clients.
+//
+// History: 04-Feb-94 Rickhi Created
+//
+//--------------------------------------------------------------------------
+#include <windows.h>
+#include <ole2.h>
+
+#ifdef THREADING_SUPPORT
+#include <olecairo.h> //
+#include <oleext.h> // OleInitializeEx, etc.
+#endif
+
+#include <srvmain.hxx> // COM Server entry points
+
+
+#ifdef WIN32
+#define olestrlen(x) wcslen(x)
+#define olestrcmp(x,y) wcscmp(x,y)
+#define olestrcpy(x,y) wcscpy(x,y)
+#define olestrcat(x,y) wcscat(x,y)
+#define olestrchr(x,y) wcsrchr(x,y)
+#else
+#define olestrlen(x) strlen(x)
+#define olestrcmp(x,y) strcmp(x,y)
+#define olestrcpy(x,y) strcpy(x,y)
+#define olestrcat(x,y) strcat(x,y)
+#define olestrchr(x,y) strchr(x,y)
+#endif
+
+
+#ifdef WIN32
+#ifdef UNICODE
+#define TEXT_TO_OLESTR(ole,wsz) wcscpy(ole,wsz)
+#define OLESTR_TO_TEXT(wsz,ole) wcscpy(wsz,ole)
+#else
+#define TEXT_TO_OLESTR(ole,str) mbstowcs(ole,str,strlen(str)+1)
+#define OLESTR_TO_TEXT(str,ole) wcstombs(str,ole,wcslen(ole)+1)
+#endif // UNICODE
+#else
+#ifdef UNICODE
+#define TEXT_TO_OLESTR(ole,wsz) wcstombs(ole,wsz,wcslen(wsz)+1)
+#define OLESTR_TO_TEXT(wsz,ole) mbstowcs(wsz,ole,strlen(ole)+1)
+#else
+#define TEXT_TO_OLESTR(ole,str) strcpy(ole,str)
+#define OLESTR_TO_TEXT(str,ole) strcpy(str,ole)
+#endif // UNICODE
+#endif // WIN32
diff --git a/private/oleutest/balls/common/cqi.hxx b/private/oleutest/balls/common/cqi.hxx
new file mode 100644
index 000000000..73a13da53
--- /dev/null
+++ b/private/oleutest/balls/common/cqi.hxx
@@ -0,0 +1,59 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1992.
+//
+// File: cqi.hxx
+//
+// Contents: Class to answer YES to any QueryInterface call.
+//
+// Classes: CQI
+//
+// History: 06-Aug-92 Rickhi Created
+//
+//--------------------------------------------------------------------------
+#ifndef __CQI__
+#define __CQI__
+
+#include <otrack.hxx>
+
+extern "C" const GUID CLSID_QI;
+extern "C" const GUID CLSID_QIHANDLER;
+
+//+-------------------------------------------------------------------------
+//
+// Class: CQI
+//
+// Purpose: Class to answer YES to many QueryInterface calls.
+// It's behavior differ's slightly depending on what class it
+// is acting as. It may or may not know IStdMarshalInfo.
+//
+// Interface: QueryInterface
+// AddRef
+// Release
+// GetUnmarshalClass
+//
+// History: 06-Aug-92 Rickhi Created
+//
+//--------------------------------------------------------------------------
+
+class CQI : INHERIT_TRACKING,
+ public IStdMarshalInfo
+{
+public:
+ CQI(REFCLSID rclsid);
+
+ STDMETHOD(QueryInterface)(REFIID riid, void **ppunk);
+ DECLARE_STD_REFCOUNTING;
+
+ STDMETHOD(GetClassForHandler)(DWORD dwDestContext,
+ void *pvDestContext,
+ CLSID *pClsid);
+
+private:
+ ~CQI(void);
+
+ CLSID _clsid;
+};
+
+#endif // __CQI__
diff --git a/private/oleutest/balls/common/cqisrv.cxx b/private/oleutest/balls/common/cqisrv.cxx
new file mode 100644
index 000000000..2132080cc
--- /dev/null
+++ b/private/oleutest/balls/common/cqisrv.cxx
@@ -0,0 +1,130 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1992.
+//
+// File: cqi.cxx
+//
+// Contents: implementations for QueryInterface test
+//
+// Functions:
+// CQI::CQI
+// CQI::~CQI
+// CQI::QueryInterface
+// CQI::GetClassForHandler
+//
+// History: 06-Aug-92 Rickhi Created
+//
+//--------------------------------------------------------------------------
+#include <pch.cxx>
+#pragma hdrstop
+#include <cqi.hxx> // class definition
+
+//+-------------------------------------------------------------------------
+//
+// Method: CQI::CQI
+//
+// Synopsis: Creates an instance of CQI
+//
+// History: 06-Aug-92 Rickhi Created
+//
+//--------------------------------------------------------------------------
+CQI::CQI(REFCLSID rclsid) : _clsid(rclsid)
+{
+ Display(TEXT("CQI created.\n"));
+ GlobalRefs(TRUE);
+
+ ENLIST_TRACKING(CQI);
+}
+
+//+-------------------------------------------------------------------------
+//
+// Method: CQI::~CQI
+//
+// Synopsis: Cleans up object
+//
+// History: 06-Aug-92 Rickhi Created
+//
+//--------------------------------------------------------------------------
+CQI::~CQI(void)
+{
+ Display(TEXT("CQI deleted.\n"));
+ GlobalRefs(FALSE);
+
+ // automatic actions are enough
+}
+
+//+-------------------------------------------------------------------------
+//
+// Method: CQI::QueryInterface
+//
+// Synopsis: returns ptr to requested interface.
+//
+// DANGER: this returns SUCCESS on almost every interface,
+// though the only valid methods on any interface are IUnknown
+// and IStdMarshalInfo.
+//
+// Arguments: [riid] - interface instance requested
+// [ppv] - where to put pointer to interface instance
+//
+// Returns: S_OK or E_NOINTERFACE
+//
+// History: 06-Aug-92 Rickhi Created
+//
+//--------------------------------------------------------------------------
+STDMETHODIMP CQI::QueryInterface(REFIID riid, void **ppv)
+{
+ if (IsEqualIID(riid, IID_IStdMarshalInfo))
+ {
+ if (IsEqualCLSID(_clsid, CLSID_QIHANDLER))
+ {
+ *ppv = (IStdMarshalInfo *)this;
+ AddRef();
+ return S_OK;
+ }
+ }
+
+ if (IsEqualIID(riid,IID_IUnknown) ||
+ IsEqualIID(riid,IID_IAdviseSink) ||
+ IsEqualIID(riid,IID_IDataObject) ||
+ IsEqualIID(riid,IID_IOleObject) ||
+ IsEqualIID(riid,IID_IOleClientSite) ||
+ IsEqualIID(riid,IID_IParseDisplayName) ||
+ IsEqualIID(riid,IID_IPersistStorage) ||
+ IsEqualIID(riid,IID_IPersistFile) ||
+ IsEqualIID(riid,IID_IStorage) ||
+ IsEqualIID(riid,IID_IOleContainer) ||
+ IsEqualIID(riid,IID_IOleItemContainer) ||
+ IsEqualIID(riid,IID_IOleInPlaceSite) ||
+ IsEqualIID(riid,IID_IOleInPlaceActiveObject) ||
+ IsEqualIID(riid,IID_IOleInPlaceObject) ||
+ IsEqualIID(riid,IID_IOleInPlaceUIWindow) ||
+ IsEqualIID(riid,IID_IOleInPlaceFrame) ||
+ IsEqualIID(riid,IID_IOleWindow))
+ {
+ *ppv = (void *)(IUnknown *) this;
+ AddRef();
+ return S_OK;
+ }
+
+ *ppv = NULL;
+ return E_NOINTERFACE;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Method: CQI::GetClassForHandler
+//
+// Synopsis: returns the classid for the inproc handler of this object.
+// Used to test handler marshaling.
+//
+// History: 06-Aug-92 Rickhi Created
+//
+//--------------------------------------------------------------------------
+STDMETHODIMP CQI::GetClassForHandler(DWORD dwDestContext,
+ void *pvDestContext,
+ CLSID *pClsid)
+{
+ *pClsid = CLSID_QIHANDLER;
+ return S_OK;
+}
diff --git a/private/oleutest/balls/common/crpc.cxx b/private/oleutest/balls/common/crpc.cxx
new file mode 100644
index 000000000..305f324b2
--- /dev/null
+++ b/private/oleutest/balls/common/crpc.cxx
@@ -0,0 +1,347 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1992.
+//
+// File: crpc.cxx
+//
+// Contents: implementations for rpc test
+//
+// Functions:
+// CRpcTest::CRpcTest
+// CRpcTest::~CRpcTest
+// CRpcTest::QueryInterface
+//
+// History: 06-Aug-92 Ricksa Created
+//
+//--------------------------------------------------------------------------
+
+#include <pch.cxx>
+#pragma hdrstop
+#include <crpc.hxx> // class definition
+
+IUnknown *gpPunk = NULL;
+
+//+-------------------------------------------------------------------------
+//
+// Method: CRpcTest::CRpcTest
+//
+// Synopsis: Creates the application window
+//
+// Arguments: [pisb] - ISysBind instance
+//
+// History: 06-Aug-92 Ricksa Created
+//
+//--------------------------------------------------------------------------
+CRpcTest::CRpcTest(void) : _punkIn(NULL)
+{
+ GlobalRefs(TRUE);
+
+ ENLIST_TRACKING(CRpcTest);
+}
+
+
+//+-------------------------------------------------------------------------
+//
+// Method: CRpcTest::~CRpcTest
+//
+// Synopsis: Cleans up object
+//
+// History: 06-Aug-92 Ricksa Created
+//
+//--------------------------------------------------------------------------
+CRpcTest::~CRpcTest(void)
+{
+ GlobalRefs(FALSE);
+}
+
+
+//+-------------------------------------------------------------------------
+//
+// Method: CRpcTest::QueryInterface
+//
+// Synopsis: Gets called when a WM_COMMAND message received.
+//
+// Arguments: [ifid] - interface instance requested
+// [ppunk] - where to put pointer to interface instance
+//
+// Returns: S_OK or ERROR_BAD_COMMAND
+//
+// History: 06-Aug-92 Ricksa Created
+//
+//--------------------------------------------------------------------------
+STDMETHODIMP CRpcTest::QueryInterface(REFIID riid, void **ppunk)
+{
+ SCODE sc = S_OK;
+
+ if (IsEqualIID(riid,IID_IUnknown) ||
+ IsEqualIID(riid,IID_IRpcTest))
+ {
+ // Increase the reference count
+ *ppunk = (void *)(IRpcTest *) this;
+ AddRef();
+ }
+ else
+ {
+ *ppunk = NULL;
+ sc = E_NOINTERFACE;
+ }
+
+ return sc;
+}
+
+
+//+-------------------------------------------------------------------------
+//
+// Method: CRpcTest::Void
+//
+// Synopsis: tests passing no parameters
+//
+// Arguments:
+//
+// Returns: S_OK or ERROR_BAD_COMMAND
+//
+// History: 06-Aug-92 Ricksa Created
+//
+//--------------------------------------------------------------------------
+STDMETHODIMP CRpcTest::Void(void)
+{
+ return S_OK;
+}
+
+STDMETHODIMP CRpcTest::VoidRC(void)
+{
+ return S_OK;
+}
+
+STDMETHODIMP CRpcTest::VoidPtrIn(ULONG cb, BYTE *pv)
+{
+ return S_OK;
+}
+
+STDMETHODIMP CRpcTest::VoidPtrOut(ULONG cb, ULONG *pcb, BYTE *pv)
+{
+ memset(pv, 1, cb);
+ *pcb = cb;
+ return S_OK;
+}
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: CRpcTest::Dword
+//
+// Synopsis: tests passing dwords in and out
+//
+// Arguments:
+//
+// Returns: S_OK
+//
+// History: 06-Aug-92 Ricksa Created
+//
+//--------------------------------------------------------------------------
+STDMETHODIMP CRpcTest::DwordIn(DWORD dw)
+{
+ return S_OK;
+}
+
+
+STDMETHODIMP CRpcTest::DwordOut(DWORD *pdw)
+{
+ *pdw = 1;
+ return S_OK;
+}
+
+
+STDMETHODIMP CRpcTest::DwordInOut(DWORD *pdw)
+{
+ *pdw = 1;
+ return S_OK;
+}
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: CRpcTest::Li
+//
+// Synopsis: tests passing LARGE INTEGERS in and out
+//
+// Arguments:
+//
+// Returns: S_OK
+//
+// History: 06-Aug-92 Ricksa Created
+//
+//--------------------------------------------------------------------------
+
+STDMETHODIMP CRpcTest::LiIn(LARGE_INTEGER li)
+{
+ return S_OK;
+}
+
+
+STDMETHODIMP CRpcTest::LiOut(LARGE_INTEGER *pli)
+{
+ pli->LowPart = 0;
+ pli->HighPart = 1;
+ return S_OK;
+}
+
+
+STDMETHODIMP CRpcTest::ULiIn(ULARGE_INTEGER uli)
+{
+ return S_OK;
+}
+
+
+STDMETHODIMP CRpcTest::ULiOut(ULARGE_INTEGER *puli)
+{
+ puli->LowPart = 0;
+ puli->HighPart = 1;
+ return S_OK;
+}
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: CRpcTest::String
+//
+// Synopsis: tests passing strings in and out
+//
+// Arguments:
+//
+// Returns: S_OK
+//
+// History: 06-Aug-92 Ricksa Created
+//
+//--------------------------------------------------------------------------
+STDMETHODIMP CRpcTest::StringIn(LPOLESTR pwsz)
+{
+ return S_OK;
+}
+
+
+STDMETHODIMP CRpcTest::StringOut(LPOLESTR *ppwsz)
+{
+ // LPOLESTR pwsz = new OLECHAR[80];
+ // *ppwsz = pwsz;
+ olestrcpy(*ppwsz, OLESTR("Hello World This is a Message"));
+ return S_OK;
+}
+
+
+STDMETHODIMP CRpcTest::StringInOut(LPOLESTR pwsz)
+{
+ olestrcpy(pwsz, OLESTR("Hello World This is a Message"));
+ return S_OK;
+}
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: CRpcTest::Guid
+//
+// Synopsis: tests passing GUIDs in and out
+//
+// Arguments:
+//
+// Returns: S_OK
+//
+// History: 06-Aug-92 Ricksa Created
+//
+//--------------------------------------------------------------------------
+STDMETHODIMP CRpcTest::GuidIn(GUID guid)
+{
+ return S_OK;
+}
+
+STDMETHODIMP CRpcTest::GuidOut(GUID *piid)
+{
+ memcpy(piid, &IID_IRpcTest, sizeof(GUID));
+ return S_OK;
+}
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: CRpcTest::IUnknown
+//
+// Synopsis: tests passing IUnknown interfaces in and out
+//
+// Arguments:
+//
+// Returns: S_OK
+//
+// History: 06-Aug-92 Ricksa Created
+//
+//--------------------------------------------------------------------------
+STDMETHODIMP CRpcTest::IUnknownIn(IUnknown *punkIn)
+{
+ return S_OK;
+}
+
+STDMETHODIMP CRpcTest::IUnknownOut(IUnknown **ppunk)
+{
+ gpPunk->AddRef();
+ *ppunk = gpPunk;
+ return S_OK;
+}
+
+STDMETHODIMP CRpcTest::IUnknownInKeep(IUnknown *punkIn)
+{
+ if (punkIn)
+ {
+ punkIn->AddRef();
+
+ if (punkIn != _punkIn)
+ {
+ _punkIn->Release();
+ _punkIn = punkIn;
+ }
+ }
+
+ return S_OK;
+}
+
+STDMETHODIMP CRpcTest::IUnknownInRelease()
+{
+ if (_punkIn)
+ {
+ _punkIn->Release();
+ }
+
+ return S_OK;
+}
+
+STDMETHODIMP CRpcTest::IUnknownOutKeep(IUnknown **ppunk)
+{
+ *ppunk = (IUnknown *)this;
+ AddRef();
+ return S_OK;
+}
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: CRpcTest::Interface
+//
+// Synopsis: tests passing whose iid is specified by riid in and out
+//
+// Arguments:
+//
+// Returns: S_OK
+//
+// History: 06-Aug-92 Ricksa Created
+//
+//--------------------------------------------------------------------------
+STDMETHODIMP CRpcTest::InterfaceIn(REFIID riid, IUnknown *punk)
+{
+ return S_OK;
+}
+
+STDMETHODIMP CRpcTest::InterfaceOut(REFIID riid, IUnknown **ppunk)
+{
+ this->QueryInterface(riid, (void **)ppunk);
+ return S_OK;
+}
diff --git a/private/oleutest/balls/common/crpc.hxx b/private/oleutest/balls/common/crpc.hxx
new file mode 100644
index 000000000..b7649a67c
--- /dev/null
+++ b/private/oleutest/balls/common/crpc.hxx
@@ -0,0 +1,86 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1992.
+//
+// File: crpc.hxx
+//
+// Contents: test basice rpc method calls
+//
+// Classes: CRpcTest
+//
+// History: 06-Aug-92 Ricksa Created
+//
+//--------------------------------------------------------------------------
+#ifndef __RPCTEST__
+#define __RPCTEST__
+
+#include <otrack.hxx>
+#include <rpctst.h> // interface definition
+
+
+//+-------------------------------------------------------------------------
+//
+// Class: CRpcTest
+//
+// Purpose: Class to demostrate remote binding functionality
+//
+// Interface: QueryInterface
+// AddRef
+// Release
+//
+// History: 06-Aug-92 Ricksa Created
+//
+//--------------------------------------------------------------------------
+class CRpcTest : INHERIT_TRACKING,
+ public IRpcTest
+{
+public:
+ CRpcTest(void);
+
+ STDMETHOD(QueryInterface)(REFIID riid, void **ppunk);
+ DECLARE_STD_REFCOUNTING;
+
+ // IRpcTest methods
+ STDMETHOD(Void) (void);
+ STDMETHOD(VoidRC) (void);
+
+ STDMETHOD(VoidPtrIn)(ULONG cb, BYTE *pv);
+ STDMETHOD(VoidPtrOut)(ULONG cb, ULONG *pcb, BYTE *pv);
+
+ STDMETHOD(DwordIn) (DWORD dw);
+ STDMETHOD(DwordOut) (DWORD *pdw);
+ STDMETHOD(DwordInOut) (DWORD *pdw);
+
+ STDMETHOD(LiIn)(LARGE_INTEGER li);
+ STDMETHOD(LiOut)(LARGE_INTEGER *pli);
+ STDMETHOD(ULiIn)(ULARGE_INTEGER uli);
+ STDMETHOD(ULiOut)(ULARGE_INTEGER *puli);
+
+ STDMETHOD(StringIn) (LPOLESTR pwsz);
+ STDMETHOD(StringOut) (LPOLESTR *ppwsz);
+ STDMETHOD(StringInOut) (LPOLESTR pwsz);
+
+ STDMETHOD(GuidIn)(GUID guid);
+ STDMETHOD(GuidOut)(GUID *pguid);
+
+ STDMETHOD(IUnknownIn) (IUnknown *punk);
+ STDMETHOD(IUnknownOut) (IUnknown **ppunk);
+
+ STDMETHOD(IUnknownInKeep) (IUnknown *punk);
+ STDMETHOD(IUnknownInRelease) (void);
+
+ STDMETHOD(IUnknownOutKeep) (IUnknown **ppunk);
+
+ STDMETHOD(InterfaceIn)(REFIID riid, IUnknown *punk);
+ STDMETHOD(InterfaceOut)(REFIID riid, IUnknown **ppunk);
+
+private:
+ ~CRpcTest(void);
+
+ IUnknown *_punkIn;
+};
+
+
+
+#endif // __RPCTEST__
diff --git a/private/oleutest/balls/common/crpctyp.cxx b/private/oleutest/balls/common/crpctyp.cxx
new file mode 100644
index 000000000..472117d06
--- /dev/null
+++ b/private/oleutest/balls/common/crpctyp.cxx
@@ -0,0 +1,393 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1992.
+//
+// File: crpctyp.cxx
+//
+// Contents: implementations for rpc test
+//
+// Functions:
+// CRpcTypes::CRpcTypes
+// CRpcTypes::~CRpcTypes
+// CRpcTypes::QueryInterface
+//
+// History: 06-Aug-92 Ricksa Created
+//
+//--------------------------------------------------------------------------
+
+#include <pch.cxx>
+#pragma hdrstop
+#include <crpctyp.hxx> // class definition
+
+
+const GUID CLSID_RpcTypes =
+ {0x00000132,0x0001,0x0008,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}};
+
+
+//+-------------------------------------------------------------------------
+//
+// Method: CRpcTypes::CRpcTypes
+//
+// Synopsis: Creates the application window
+//
+// Arguments: [pisb] - ISysBind instance
+//
+// History: 06-Aug-92 Ricksa Created
+//
+//--------------------------------------------------------------------------
+CRpcTypes::CRpcTypes(void)
+{
+ GlobalRefs(TRUE);
+
+ ENLIST_TRACKING(CRpcTypes);
+}
+
+
+//+-------------------------------------------------------------------------
+//
+// Method: CRpcTypes::~CRpcTypes
+//
+// Synopsis: Cleans up object
+//
+// History: 06-Aug-92 Ricksa Created
+//
+//--------------------------------------------------------------------------
+CRpcTypes::~CRpcTypes(void)
+{
+ GlobalRefs(FALSE);
+}
+
+
+//+-------------------------------------------------------------------------
+//
+// Method: CRpcTypes::QueryInterface
+//
+// Synopsis: Gets called when a WM_COMMAND message received.
+//
+// Arguments: [ifid] - interface instance requested
+// [ppunk] - where to put pointer to interface instance
+//
+// Returns: S_OK or E_NOINTERFACE
+//
+// History: 06-Aug-92 Ricksa Created
+//
+//--------------------------------------------------------------------------
+STDMETHODIMP CRpcTypes::QueryInterface(REFIID riid, void **ppunk)
+{
+ SCODE sc = S_OK;
+
+ if (IsEqualIID(riid,IID_IUnknown) ||
+ IsEqualIID(riid,IID_IRpcTypes))
+ {
+ // Increase the reference count
+ *ppunk = (void *)(IRpcTypes *) this;
+ AddRef();
+ }
+ else
+ {
+ *ppunk = NULL;
+ sc = E_NOINTERFACE;
+ }
+
+ return sc;
+}
+
+
+//+-------------------------------------------------------------------------
+//
+// Method: CRpcTypes::GuidsIn
+//
+// Synopsis: tests passing GUID parameters
+//
+// Arguments:
+//
+// Returns: S_OK or error code with parm #s or'd in
+//
+// History: 06-Aug-92 Ricksa Created
+//
+//--------------------------------------------------------------------------
+
+STDMETHODIMP CRpcTypes::GuidsIn(
+ REFCLSID rclsid,
+ CLSID clsid,
+ REFIID riid,
+ IID iid,
+ GUID guid)
+{
+ SCODE sc = S_OK;
+
+ // compare each parameter with the expected value
+ if (!IsEqualCLSID(rclsid, CLSID_RpcTypes))
+ sc |= 1;
+
+ if (!IsEqualCLSID(clsid, CLSID_RpcTypes))
+ sc |= 2;
+
+ if (!IsEqualIID(riid, IID_IRpcTypes))
+ sc |= 4;
+
+ if (!IsEqualIID(iid, IID_IRpcTypes))
+ sc |= 8;
+
+ if (!IsEqualIID(guid, IID_IRpcTypes))
+ sc |= 8;
+
+ return sc;
+}
+
+
+STDMETHODIMP CRpcTypes::GuidsOut(
+ CLSID *pclsid,
+ IID *piid,
+ GUID *pguid)
+{
+ // copy in the expected return values
+ memcpy(pclsid, &CLSID_RpcTypes, sizeof(CLSID));
+
+ memcpy(piid, &IID_IRpcTypes, sizeof(IID));
+
+ memcpy(pguid, &CLSID_RpcTypes, sizeof(GUID));
+
+ return S_OK;
+}
+
+
+//+-------------------------------------------------------------------------
+//
+// Method: CRpcTypes::DwordIn
+//
+// Synopsis: tests passing dword and large integer parameters
+//
+// Arguments:
+//
+// Returns: S_OK or error code with parm #s or'd in
+//
+// History: 06-Aug-92 Ricksa Created
+//
+//--------------------------------------------------------------------------
+
+STDMETHODIMP CRpcTypes::DwordIn(
+ DWORD dw,
+ ULONG ul,
+ LONG lg,
+ LARGE_INTEGER li,
+ ULARGE_INTEGER uli)
+{
+ SCODE sc = S_OK;
+
+ // compare each parameter with the expected value
+ if (dw != 1)
+ sc |= 1;
+
+ if (ul != 2)
+ sc |= 2;
+
+ if (lg != 3)
+ sc |= 4;
+
+ if (li.LowPart != 4 ||
+ li.HighPart != 5)
+ sc |= 8;
+
+ if (uli.LowPart != 6 ||
+ uli.HighPart != 7)
+ sc |= 16;
+
+ return sc;
+}
+
+
+STDMETHODIMP CRpcTypes::DwordOut(
+ DWORD *pdw,
+ ULONG *pul,
+ LONG *plg,
+ LARGE_INTEGER *pli,
+ ULARGE_INTEGER *puli)
+{
+ // copy in the expected return values
+ *pdw = 1;
+ *pul = 2;
+ *plg = 3;
+
+ pli->LowPart = 4;
+ pli->HighPart = 5;
+
+ puli->LowPart = 6;
+ puli->HighPart = 7;
+
+ return S_OK;
+}
+
+
+//+-------------------------------------------------------------------------
+//
+// Method: CRpcTypes::WindowsIn
+//
+// Synopsis: tests passing windows structure parameters
+//
+// Arguments:
+//
+// Returns: S_OK or error code with parm #s or'd in
+//
+// History: 06-Aug-92 Ricksa Created
+//
+//--------------------------------------------------------------------------
+
+STDMETHODIMP CRpcTypes::WindowsIn(
+ POINTL pointl,
+ SIZEL sizel,
+ RECTL rectl,
+ FILETIME filetime,
+ PALETTEENTRY paletteentry,
+ LOGPALETTE *plogpalette)
+{
+ SCODE sc = S_OK;
+
+ // check the pointl structure
+ if (pointl.x != 1 || pointl.y != 2)
+ sc |= 1;
+
+ if (sizel.cx != 3 || sizel.cy != 4)
+ sc |= 2;
+
+ if (filetime.dwLowDateTime != 5 || filetime.dwHighDateTime != 6)
+ sc |= 4;
+
+ if (paletteentry.peRed != 7 ||
+ paletteentry.peGreen != 8 ||
+ paletteentry.peBlue != 9 ||
+ paletteentry.peFlags != 10)
+ sc |= 8;
+
+ if (plogpalette->palVersion != 11 ||
+ plogpalette->palNumEntries != 1)
+ sc |= 16;
+
+ if (plogpalette->palPalEntry[0].peRed != 12)
+ sc |= 32;
+
+ return sc;
+}
+
+
+STDMETHODIMP CRpcTypes::WindowsOut(
+ POINTL *ppointl,
+ SIZEL *psizel,
+ RECTL *prectl,
+ FILETIME *pfiletime,
+ PALETTEENTRY *ppaletteentry,
+ LOGPALETTE **pplogpalette)
+{
+ ppointl->x = 1;
+ ppointl->y = 2;
+
+ psizel->cx = 3;
+ psizel->cy = 4;
+
+ pfiletime->dwLowDateTime = 5;
+ pfiletime->dwHighDateTime = 6;
+
+ ppaletteentry->peRed = 7;
+ ppaletteentry->peGreen = 8;
+ ppaletteentry->peBlue = 9;
+ ppaletteentry->peFlags = 10;
+
+ *pplogpalette = new LOGPALETTE;
+ (*pplogpalette)->palVersion = 11;
+ (*pplogpalette)->palNumEntries = 1;
+ (*pplogpalette)->palPalEntry[0].peRed = 12;
+
+ return S_OK;
+}
+
+
+//+-------------------------------------------------------------------------
+//
+// Method: CRpcTypes::OleData
+//
+// Synopsis: tests passing OLE2 structure parameters
+//
+// Arguments:
+//
+// Returns: S_OK or error code with parm #s or'd in
+//
+// History: 06-Aug-92 Ricksa Created
+//
+//--------------------------------------------------------------------------
+
+STDMETHODIMP CRpcTypes::OleDataIn(
+ STATDATA statdata,
+ STATSTG statstg,
+ STGMEDIUM stgmedium,
+ FORMATETC formatetc,
+ DVTARGETDEVICE *pdvtargetdevice)
+{
+ SCODE sc = S_OK;
+
+ return sc;
+}
+
+
+STDMETHODIMP CRpcTypes::OleDataOut(
+ STATDATA *pstatdata,
+ STATSTG *pstatstg,
+ STGMEDIUM *pstgmedium,
+ FORMATETC *pformatetc,
+ DVTARGETDEVICE **ppdvtargetdevice)
+{
+ return S_OK;
+}
+
+
+//+-------------------------------------------------------------------------
+//
+// Method: CRpcTypes::VoidPtr
+//
+// Synopsis: tests passing arrays of byte parameters
+//
+// Arguments:
+//
+// Returns: S_OK or error code with parm #s or'd in
+//
+// History: 06-Aug-92 Ricksa Created
+//
+//--------------------------------------------------------------------------
+
+STDMETHODIMP CRpcTypes::VoidPtrIn(
+ ULONG cb,
+ void *pv)
+{
+ SCODE sc = S_OK;
+ BYTE *pb = (BYTE *)pv;
+
+ // check the contents of the buffer
+ for (ULONG i=0; i<cb, i++; pb++)
+ {
+ if (*pb != (BYTE)i)
+ sc = E_FAIL;
+ }
+
+ return sc;
+}
+
+
+STDMETHODIMP CRpcTypes::VoidPtrOut(
+ void *pv,
+ ULONG cb,
+ ULONG *pcb)
+{
+ BYTE *pb = (BYTE *)pv;
+
+ *pcb = 0;
+
+ // fill the buffer
+ for (ULONG i=0; i<cb; i++, pb++)
+ {
+ *pb = (BYTE)i;
+ }
+
+ *pcb = cb;
+
+ return S_OK;
+}
diff --git a/private/oleutest/balls/common/crpctyp.hxx b/private/oleutest/balls/common/crpctyp.hxx
new file mode 100644
index 000000000..f51d48739
--- /dev/null
+++ b/private/oleutest/balls/common/crpctyp.hxx
@@ -0,0 +1,129 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1992.
+//
+// File: crpctyp.hxx
+//
+// Contents: test basice rpc method calls
+//
+// Classes: CRpcTypes
+//
+// History: 06-Aug-92 Ricksa Created
+//
+//--------------------------------------------------------------------------
+#ifndef __RPCTYPES__
+#define __RPCTYPES__
+
+#include <otrack.hxx>
+#include <rpctyp.h> // interface definition
+
+extern "C" const GUID CLSID_RpcTypes;
+
+
+//+-------------------------------------------------------------------------
+//
+// Class: CRpcTypes
+//
+// Purpose: Class to test parameter passing in ole proxies
+//
+// Interface: QueryInterface
+// AddRef
+// Release
+//
+// History: 06-Aug-92 Ricksa Created
+//
+//--------------------------------------------------------------------------
+class CRpcTypes : INHERIT_TRACKING,
+ public IRpcTypes
+{
+public:
+ CRpcTypes(void);
+
+ STDMETHOD(QueryInterface)(REFIID riid, void **ppunk);
+ DECLARE_STD_REFCOUNTING;
+
+ // IRpcTypes methods
+ STDMETHOD(GuidsIn)(
+ REFCLSID rclsid,
+ CLSID clsid,
+ REFIID riid,
+ IID iid,
+ GUID guid);
+
+ STDMETHOD(GuidsOut)(
+ CLSID *pclsid,
+ IID *piid,
+ GUID *pguid);
+
+ STDMETHOD(DwordIn)(
+ DWORD dw,
+ ULONG ul,
+ LONG lg,
+ LARGE_INTEGER li,
+ ULARGE_INTEGER uli);
+
+ STDMETHOD(DwordOut)(
+ DWORD *pdw,
+ ULONG *pul,
+ LONG *plg,
+ LARGE_INTEGER *pli,
+ ULARGE_INTEGER *puli);
+
+ STDMETHOD(WindowsIn)(
+ POINTL pointl,
+ SIZEL sizel,
+ RECTL rectl,
+ FILETIME filetime,
+ PALETTEENTRY paletentry,
+ LOGPALETTE *plogpalet);
+
+ STDMETHOD(WindowsOut)(
+ POINTL *ppointl,
+ SIZEL *psizel,
+ RECTL *prectl,
+ FILETIME *pfiletime,
+ PALETTEENTRY *ppaletentry,
+ LOGPALETTE **pplogpalet);
+
+
+ STDMETHOD(OleStgmedIn)(STGMEDIUM *pstgmedium);
+ STDMETHOD(OleStgmedOut)(STGMEDIUM *pstgmedium);
+
+ STDMETHOD(OleClipFmtIn)(STGMEDIUM *pstgmedium);
+ STDMETHOD(OleClipFmtOut)(STGMEDIUM *pstgmedium);
+
+ STDMETHOD(OleStatdataOut)(STATDATA **ppstatdata);
+
+ STDMETHOD(OleStatStgOut)(STATSTG *pstatstg);
+
+ STDMETHOD(OleFormatEtcIn)(FORMATETC *pformatetc);
+ STDMETHOD(OleFormatEtcOut)(FORMATETC *pformatetc);
+
+ STDMETHOD(OleDvTargetIn)(DVTARGETDEVICE *pdvtargetdevice);
+
+ STDMETHOD(OleVerbIn)(OLEVERB *poleverb);
+
+ STDMETHOD(OleMenuIn)(OLEMENUGROUPWIDTHS *pmenugroup);
+
+ STDMETHOD(OleFrameOut)(OLEINPLACEFRAMEINFO *pframeinfo);
+
+ STDMETHOD(OleSnbIn)(SNB snb);
+
+
+ STDMETHOD(VoidPtrIn)(
+ ULONG cb,
+ void *pv);
+
+ STDMETHOD(VoidPtrOut)(
+ void *pv,
+ ULONG cb,
+ ULONG *pcb);
+
+private:
+ ~CRpcTypes(void);
+};
+
+
+
+#endif // __RPCTYPES__
diff --git a/private/oleutest/balls/common/csrvapp.hxx b/private/oleutest/balls/common/csrvapp.hxx
new file mode 100644
index 000000000..bae147da2
--- /dev/null
+++ b/private/oleutest/balls/common/csrvapp.hxx
@@ -0,0 +1,79 @@
+//+-------------------------------------------------------------------
+//
+// File: csrvapp.hxx
+//
+// Contents: CTestServerApp declarations &
+// miscellaneous tidbits.
+//
+// History: 24-Nov-92 DeanE Created
+//
+//---------------------------------------------------------------------
+
+#ifndef __CSRVAPP_HXX__
+#define __CSRVAPP_HXX__
+
+// #include <com.hxx>
+
+#define LOG_ABORT -1
+#define LOG_PASS 1
+#define LOG_FAIL 0
+
+// Application Window messages
+#define WM_RUNTEST (WM_USER + 1)
+#define WM_REPORT (WM_USER + 2)
+
+
+// WM_REPORT wParam codes
+#define MB_SHOWVERB 0x0001
+#define MB_PRIMVERB 0x0002
+
+
+// Global variables
+extern HWND g_hwndMain;
+
+
+// Forward declarations
+class FAR CDataObject;
+class FAR CPersistStorage;
+class FAR COleObject;
+class FAR CTestEmbedCF;
+
+
+//+-------------------------------------------------------------------
+// Class: CTestServerApp
+//
+// Synopsis: Class that holds application-wide data and methods
+//
+// Methods: InitApp
+// CloseApp
+// GetEmbeddedFlag
+//
+// History: 17-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+class FAR CTestServerApp
+{
+public:
+
+// Constructor/Destructor
+ CTestServerApp();
+ ~CTestServerApp();
+
+ SCODE InitApp (LPSTR lpszCmdline);
+ SCODE CloseApp (void);
+ BOOL GetEmbeddedFlag (void);
+ ULONG IncEmbeddedCount(void);
+ ULONG DecEmbeddedCount(void);
+
+private:
+ IClassFactory *_pteClassFactory;
+ ULONG _cEmbeddedObjs; // Count of embedded objects this server
+ // is controlling now
+ DWORD _dwRegId; // OLE registration ID
+ BOOL _fRegistered; // TRUE if srv was registered w/OLE
+ BOOL _fInitialized; // TRUE if OleInitialize was OK
+ BOOL _fEmbedded; // TRUE if OLE started us at the request
+ // of an embedded obj in a container app
+};
+
+
+#endif // __CSRVAPP_HXX__
diff --git a/private/oleutest/balls/common/ctballs.cxx b/private/oleutest/balls/common/ctballs.cxx
new file mode 100644
index 000000000..524ca8636
--- /dev/null
+++ b/private/oleutest/balls/common/ctballs.cxx
@@ -0,0 +1,532 @@
+#pragma hdrstop
+
+#include <ctballs.hxx>
+#include <sem32.hxx>
+
+
+// We need a semaphore to synchronize loads and releases.
+CMutexSem mxsLoadRelease;
+
+SAFE_INTERFACE_PTR(XIStream, IStream)
+
+#define XPOS L"XPOS"
+#define YPOS L"YPOS"
+
+
+HRESULT ReadPos(IStorage *pstg, LPOLESTR pwszStream, ULONG *pulPos)
+{
+ HRESULT hr;
+
+ BEGIN_BLOCK
+
+ XIStream xstrm;
+
+ // Read the streams for xpos and ypos
+ hr = pstg->OpenStream(pwszStream, NULL,
+ STGM_READ | STGM_SHARE_EXCLUSIVE, NULL, &xstrm);
+
+ if (FAILED(hr))
+ {
+ EXIT_BLOCK;
+ }
+
+ ULONG cb;
+
+ hr = xstrm->Read(pulPos, sizeof(*pulPos), &cb);
+
+ if (FAILED(hr))
+ {
+ EXIT_BLOCK;
+ }
+
+ hr = ResultFromScode(S_OK);
+
+ END_BLOCK
+
+ return hr;
+}
+
+HRESULT WritePos(IStorage *pstg, LPOLESTR pwszStream, ULONG ulPos)
+{
+ HRESULT hr;
+
+ BEGIN_BLOCK
+
+ XIStream xstrm;
+
+ // Read the streams for xpos and ypos
+ hr = pstg->CreateStream(pwszStream,
+ STGM_CREATE | STGM_WRITE | STGM_SHARE_EXCLUSIVE, NULL, NULL,
+ &xstrm);
+
+ if (FAILED(hr))
+ {
+ EXIT_BLOCK;
+ }
+
+
+ ULONG cb;
+
+ hr = xstrm->Write(&ulPos, sizeof(ulPos), &cb);
+
+ if (FAILED(hr))
+ {
+ EXIT_BLOCK;
+ }
+
+ hr = ResultFromScode(S_OK);
+
+ END_BLOCK
+
+ return hr;
+}
+
+CTestBalls::CTestBalls(REFCLSID rclsid)
+ : _rclsid(rclsid), _fDirty(FALSE), _xPos(0), _yPos(0),
+ _fSaveInprogress(FALSE), _pstg(NULL), _dwRegister(0), _cRefs(1)
+{
+ // Use as a flag for whether a file name has been assigned
+ _awszCurFile[0] = 0;
+
+ GlobalRefs(TRUE);
+}
+
+CTestBalls::~CTestBalls(void)
+{
+ if (_pstg != NULL)
+ {
+ // Release the storage because we are done with it
+ ULONG ulCnt = _pstg->Release();
+
+#if 0
+ // this test is not valud when running stress
+ if (ulCnt != 0)
+ {
+ DebugBreak();
+ }
+#endif
+ }
+
+ if (_dwRegister)
+ {
+ IRunningObjectTable *prot;
+ GetRunningObjectTable(NULL, &prot);
+ prot->Revoke(_dwRegister);
+ prot->Release();
+ }
+
+ GlobalRefs(FALSE);
+}
+
+STDMETHODIMP CTestBalls::QueryInterface(REFIID iid, void **ppv)
+{
+ HRESULT hr = ResultFromScode(S_OK);
+
+ // We support IUnknown, IPersistFile and IBalls
+ if (IsEqualIID(iid, IID_IUnknown))
+ {
+ *ppv = (IBalls *) this;
+ }
+ else if (IsEqualIID(iid, IID_IPersistFile))
+ {
+ *ppv = (IPersistFile *) this;
+ }
+ else if (IsEqualIID(iid, IID_IPersistStorage))
+ {
+ *ppv = (IPersistStorage *) this;
+ }
+ else if (IsEqualIID(iid, IID_IBalls))
+ {
+ *ppv = (IBalls *) this;
+ }
+ else
+ {
+ *ppv = NULL;
+ hr = ResultFromScode(E_NOINTERFACE);
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ AddRef();
+ }
+
+ return hr;
+}
+
+STDMETHODIMP_(ULONG) CTestBalls::AddRef(void)
+{
+ InterlockedIncrement(&_cRefs);
+ return _cRefs;
+}
+
+STDMETHODIMP_(ULONG) CTestBalls::Release(void)
+{
+ CLock lck(mxsLoadRelease);
+
+ if (InterlockedDecrement(&_cRefs) == 0)
+ {
+ delete this;
+ return 0;
+ }
+
+ return _cRefs;
+}
+
+STDMETHODIMP CTestBalls::GetClassID(LPCLSID lpClassID)
+{
+ *lpClassID = _rclsid;
+ return ResultFromScode(S_OK);
+}
+
+STDMETHODIMP CTestBalls::IsDirty()
+{
+ return (_fDirty) ? ResultFromScode(S_OK) : ResultFromScode(S_FALSE);
+}
+
+STDMETHODIMP CTestBalls::Load(LPCOLESTR lpszFileName, DWORD grfMode)
+{
+ CLock lck(mxsLoadRelease);
+
+ HRESULT hr;
+
+ BEGIN_BLOCK
+
+ hr = StgOpenStorage(lpszFileName, NULL,
+ STGM_READWRITE | STGM_SHARE_EXCLUSIVE, NULL, NULL, &_pstg);
+
+ if (FAILED(hr))
+ {
+#if 0
+ // this test is not valid when running stress
+ if (hr == STG_E_LOCKVIOLATION)
+ {
+ DebugBreak();
+ }
+#endif
+ EXIT_BLOCK;
+ }
+
+ // Get the saved xposition
+ hr = GetData();
+
+ if (FAILED(hr))
+ {
+ EXIT_BLOCK;
+ }
+
+ // Since everything went Ok save the file name
+ olestrcpy(_awszCurFile, lpszFileName);
+
+ // Create a file moniker for the object
+ IMoniker *pmk;
+ CreateFileMoniker(lpszFileName, &pmk);
+
+ // Register it in the running object table.
+ IRunningObjectTable *prot;
+ GetRunningObjectTable(NULL, &prot);
+ prot->Register(NULL, (IPersistFile *) this, pmk, &_dwRegister);
+
+ // Release the temporary objects
+ pmk->Release();
+ prot->Release();
+
+ END_BLOCK
+
+ return hr;
+}
+
+STDMETHODIMP CTestBalls::Save(LPCOLESTR lpszFileName, BOOL fRemember)
+{
+ HRESULT hr;
+
+ BEGIN_BLOCK
+
+ IStorage *pstgNew;
+
+ // Save the data
+ if (olestrcmp(lpszFileName, _awszCurFile) == 0)
+ {
+ pstgNew = _pstg;
+ _fDirty = FALSE;
+ }
+ else
+ {
+ hr = StgCreateDocfile(lpszFileName,
+ STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
+ NULL, &pstgNew);
+ }
+
+ if (FAILED(hr))
+ {
+ EXIT_BLOCK;
+ }
+
+ WriteClassStg(pstgNew, _rclsid);
+
+ hr = SaveData(pstgNew);
+
+ if (FAILED(hr))
+ {
+ EXIT_BLOCK;
+ }
+
+ if (fRemember)
+ {
+ // Save the file name
+ olestrcpy(_awszCurFile, lpszFileName);
+
+
+ // Replace the storage
+ if (_pstg && pstgNew != _pstg)
+ {
+ _pstg->Release();
+ }
+ _pstg = pstgNew;
+
+ _fDirty = FALSE;
+ }
+ else
+ {
+ pstgNew->Release();
+ }
+
+ _fSaveInprogress = TRUE;
+
+ hr = ResultFromScode(S_OK);
+
+ END_BLOCK;
+
+ return hr;
+}
+
+STDMETHODIMP CTestBalls::SaveCompleted(LPCOLESTR lpszFileName)
+{
+ _fSaveInprogress = FALSE;
+ return ResultFromScode(S_OK);
+}
+
+STDMETHODIMP CTestBalls::GetCurFile(LPOLESTR FAR * lpszFileName)
+{
+ // Allocate a buffer for the file and copy in the data
+ if (_awszCurFile[0] == 0)
+ {
+ return ResultFromScode(S_FALSE);
+ }
+
+
+ IMalloc *pIMalloc;
+
+ HRESULT hr = CoGetMalloc(MEMCTX_TASK, &pIMalloc);
+
+ if (SUCCEEDED(hr))
+ {
+ *lpszFileName = (WCHAR *) pIMalloc->Alloc(
+ olestrlen((_awszCurFile) + 1) * sizeof(WCHAR));
+
+ olestrcpy(*lpszFileName, _awszCurFile);
+
+ hr = ResultFromScode(S_OK);
+ }
+
+ return hr;
+}
+
+STDMETHODIMP CTestBalls::MoveBall(ULONG xPos, ULONG yPos)
+{
+ if (!_fSaveInprogress)
+ {
+ _fDirty = TRUE;
+ _xPos = xPos;
+ _yPos = yPos;
+ return S_OK;
+ }
+
+ // Can't change state because a save is still pending
+ return ResultFromScode(E_UNEXPECTED);
+}
+
+STDMETHODIMP CTestBalls::GetBallPos(ULONG *xPos, ULONG *yPos)
+{
+ *xPos = _xPos;
+ *yPos = _yPos;
+ return S_OK;
+}
+
+STDMETHODIMP CTestBalls::IsOverLapped(IBalls *pIBall)
+{
+ ULONG xPos;
+ ULONG yPos;
+
+ HRESULT hr = pIBall->GetBallPos(&xPos, &yPos);
+
+ if (SUCCEEDED(hr))
+ {
+ if ((xPos == _xPos) && (yPos == _yPos))
+ {
+ hr = ResultFromScode(S_OK);
+ }
+ else
+ {
+ hr = ResultFromScode(S_FALSE);
+ }
+ }
+
+ return hr;
+}
+
+STDMETHODIMP CTestBalls::IsContainedIn(ICube *pICube)
+{
+ ULONG xPos;
+ ULONG yPos;
+
+ HRESULT hr = pICube->GetCubePos(&xPos, &yPos);
+
+ if (SUCCEEDED(hr))
+ {
+ if ((xPos == _xPos) && (yPos == _yPos))
+ {
+ hr = ResultFromScode(S_OK);
+ }
+ else
+ {
+ hr = ResultFromScode(S_FALSE);
+ }
+ }
+
+ return hr;
+
+}
+
+STDMETHODIMP CTestBalls::Clone(IBalls **ppIBall)
+{
+ CTestBalls *ptballs = new CTestBalls(_rclsid);
+
+ ptballs->_xPos = _xPos;
+ ptballs->_yPos = _yPos;
+ ptballs->_fDirty = _fDirty;
+ _pstg->AddRef();
+ ptballs->_pstg = _pstg;
+ lstrcpy(ptballs->_awszCurFile, _awszCurFile);
+ return ResultFromScode(S_OK);
+}
+
+STDMETHODIMP CTestBalls::Echo(IUnknown *punkIn, IUnknown**ppunkOut)
+{
+ *ppunkOut = punkIn;
+ return S_OK;
+}
+
+STDMETHODIMP CTestBalls::InitNew(LPSTORAGE pStg)
+{
+ pStg->AddRef();
+ _pstg = pStg;
+ WriteClassStg(_pstg, _rclsid);
+
+ return ResultFromScode(S_OK);
+}
+
+STDMETHODIMP CTestBalls::Load(LPSTORAGE pStg)
+{
+ HRESULT hr;
+
+ _pstg = pStg;
+
+ hr = GetData();
+
+ if (SUCCEEDED(hr))
+ {
+ _pstg->AddRef();
+ }
+ else
+ {
+ _pstg = NULL;
+ }
+
+ return hr;
+}
+
+STDMETHODIMP CTestBalls::Save(
+ LPSTORAGE pStgSave,
+ BOOL fSameAsLoad)
+{
+ HRESULT hr;
+
+ if (!fSameAsLoad)
+ {
+ if (_pstg)
+ _pstg->Release();
+
+ _pstg = pStgSave;
+
+ pStgSave->AddRef();
+ }
+ else
+ {
+ pStgSave = _pstg;
+ }
+
+ WriteClassStg(pStgSave, _rclsid);
+
+ hr = SaveData(pStgSave);
+
+ _fSaveInprogress = TRUE;
+
+ return hr;
+}
+
+STDMETHODIMP CTestBalls::SaveCompleted(LPSTORAGE pStgSaved)
+{
+ _fSaveInprogress = FALSE;
+ return ResultFromScode(S_OK);
+}
+
+STDMETHODIMP CTestBalls::HandsOffStorage(void)
+{
+ // Figure out what to do here!
+ return ResultFromScode(E_UNEXPECTED);
+}
+
+HRESULT CTestBalls::GetData(void)
+{
+ HRESULT hr;
+
+ BEGIN_BLOCK
+
+ // Get the saved xposition
+ hr = ReadPos(_pstg, XPOS, &_xPos);
+
+ if (FAILED(hr))
+ {
+ EXIT_BLOCK;
+ }
+
+ // Get the saved yposition
+ hr = ReadPos(_pstg, YPOS, &_yPos);
+
+ END_BLOCK
+
+ return hr;
+}
+
+HRESULT CTestBalls::SaveData(IStorage *pstg)
+{
+ HRESULT hr;
+
+ BEGIN_BLOCK
+
+ // Get the saved xposition
+ hr = WritePos(pstg, XPOS, _xPos);
+
+ if (FAILED(hr))
+ {
+ EXIT_BLOCK;
+ }
+
+ // Get the saved yposition
+ hr = WritePos(pstg, YPOS, _yPos);
+
+
+ END_BLOCK
+
+ return hr;
+}
diff --git a/private/oleutest/balls/common/ctballs.hxx b/private/oleutest/balls/common/ctballs.hxx
new file mode 100644
index 000000000..3b7f549b8
--- /dev/null
+++ b/private/oleutest/balls/common/ctballs.hxx
@@ -0,0 +1,92 @@
+#ifndef __CTBALLS_HXX__
+#define __CTBALLS_HXX__
+
+#include <otrack.hxx>
+#include <icube.h>
+#include <iballs.h>
+
+#define BEGIN_BLOCK do {
+#define EXIT_BLOCK break
+#define END_BLOCK }while(FALSE);
+
+class CTestBalls : public IPersistFile, public IBalls, public IPersistStorage
+{
+public:
+ CTestBalls(REFCLSID rclsid);
+
+ ~CTestBalls(void);
+
+ // IUnknown
+ STDMETHOD(QueryInterface)(REFIID iid, void **ppv);
+
+ STDMETHODIMP_(ULONG) AddRef(void);
+
+ STDMETHODIMP_(ULONG) Release(void);
+
+ // IPersist
+ STDMETHOD(GetClassID)(LPCLSID lpClassID);
+
+ // IPersistFile
+ STDMETHOD(IsDirty)();
+
+ STDMETHOD(Load)(LPCOLESTR lpszFileName, DWORD grfMode);
+
+ STDMETHOD(Save)(LPCOLESTR lpszFileName, BOOL fRemember);
+
+ STDMETHOD(SaveCompleted)(LPCOLESTR lpszFileName);
+
+ STDMETHOD(GetCurFile)(LPOLESTR FAR * lpszFileName);
+
+ // IPersistStorage
+ STDMETHOD(InitNew)(LPSTORAGE pStg);
+
+ STDMETHOD(Load)(LPSTORAGE pStg);
+
+ STDMETHOD(Save)(
+ LPSTORAGE pStgSave,
+ BOOL fSameAsLoad);
+
+ STDMETHOD(SaveCompleted)(LPSTORAGE pStgSaved);
+
+ STDMETHOD(HandsOffStorage)(void);
+
+ // IBalls
+ STDMETHOD(MoveBall)(ULONG xPos, ULONG yPos);
+
+ STDMETHOD(GetBallPos)(ULONG *xPos, ULONG *yPos);
+
+ STDMETHOD(IsOverLapped)(IBalls *pIBall);
+
+ STDMETHOD(IsContainedIn)(ICube *pICube);
+
+ STDMETHOD(Clone)(IBalls **ppIBall);
+
+ STDMETHOD(Echo)(IUnknown *punkIn, IUnknown**ppunkOut);
+
+private:
+
+ HRESULT GetData(void);
+
+ HRESULT SaveData(IStorage *pstg);
+
+ REFCLSID _rclsid;
+
+ IStorage * _pstg;
+
+ OLECHAR _awszCurFile[MAX_PATH];
+
+ BOOL _fDirty;
+
+ BOOL _fSaveInprogress;
+
+ ULONG _xPos;
+
+ ULONG _yPos;
+
+ DWORD _dwRegister;
+
+ LONG _cRefs;
+};
+
+
+#endif // __CTBALLS_HXX__
diff --git a/private/oleutest/balls/common/ctext.cxx b/private/oleutest/balls/common/ctext.cxx
new file mode 100644
index 000000000..c243924a2
--- /dev/null
+++ b/private/oleutest/balls/common/ctext.cxx
@@ -0,0 +1,332 @@
+//+-------------------------------------------------------------------
+//
+// File: ctext.cxx
+//
+// Contents: Implementation for CRegTextFile class
+//
+// Classes: None.
+//
+// Functions: CRegTextFile::GetString -- get a string & convert to unicode
+// CRegTextFile::GetLong -- get a long from the file
+//
+// History: 18-Dec-91 Ricksa Created
+// 19-Mar-92 Rickhi Skip over comment lines in file
+//
+//--------------------------------------------------------------------
+
+#include <pch.cxx>
+#pragma hdrstop
+#include <ctext.hxx>
+
+
+TCHAR CRegTextFile::s_awcSysDir[MAX_PATH];
+
+int CRegTextFile::s_cSysDir = 0;
+
+//+-------------------------------------------------------------------
+//
+// Member: CRegTextFile::CRegTextFile, public
+//
+// Synopsis: Open a file
+//
+// Effects: File is open
+//
+// Arguments: [pszFile] -- name of file to open
+//
+// Requires: Nothing.
+//
+// Returns: Returns pointer to the file opened.
+//
+// Signals: CException.
+//
+// Modifies: None.
+//
+// Derivation: None.
+//
+// Algorithm: Attempt to open the file & throw an exception if
+// the open request fails.
+//
+// History: 19-Dec-91 Ricksa Created
+//
+// Notes:
+//
+//--------------------------------------------------------------------
+CRegTextFile::CRegTextFile(LPSTR pszFile)
+{
+ if (lstrcmpA(pszFile, "") == 0)
+ {
+ _fp = stdin;
+ }
+ else if ((_fp = fopen(pszFile, "r")) == NULL)
+ {
+ printf("Open of file failed %s", pszFile);
+ }
+
+ if (s_cSysDir == 0)
+ {
+ // Get the system directory -- we divide by 2 because we want
+ // cSysDir to be the number of characters *not* the number of
+ // bytes.
+ s_cSysDir = GetSystemDirectory(s_awcSysDir, sizeof(s_awcSysDir))
+ / sizeof(TCHAR);
+ }
+}
+
+
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CRegTextFile::~CRegTextFile, public
+//
+// Synopsis: Destroy object and close the file.
+//
+// Effects: Object is destroyed.
+//
+// Arguments: None.
+//
+// Requires: Valid pointer to CRegTextFile.
+//
+// Returns: Nothing.
+//
+// Signals: None.
+//
+// Modifies: Nothing global.
+//
+// Derivation: None.
+//
+// Algorithm: Simply closes the file.
+//
+// History: 19-Dec-91 Ricksa Created
+//
+// Notes:
+//
+//--------------------------------------------------------------------
+CRegTextFile::~CRegTextFile(void)
+{
+ if (_fp != stdin)
+ {
+ fclose(_fp);
+ }
+}
+
+
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CRegTextFile::GetString, public
+//
+// Synopsis: Reads an ASCII string from the
+//
+// Effects: Outputs a buffer filled with UNICODE text.
+//
+// Arguments: None.
+//
+// Requires: Pointer to CRegTextFile object.
+//
+// Returns: Pointer to a buffer filled with Unicode text.
+//
+// Signals: CException
+//
+// Algorithm: Read a line of ASCII text and convert it into
+// Unicode and return a pointer to the data.
+//
+// History: 19-Dec-91 Ricksa Created
+//
+// Notes: This method is not multithreaded and the output
+// buffer will be reset on the next call to GetString.
+//
+//--------------------------------------------------------------------
+LPTSTR
+CRegTextFile::GetString(void)
+{
+ do
+ {
+ if (fgets(_abuf, sizeof(_abuf), _fp) == NULL)
+ {
+ printf("Read of file failed");
+ }
+
+ } while (_abuf[0] == COMMENT_MARK);
+
+
+ int len = lstrlenA(_abuf);
+ int last = len - 1;
+
+ // Hack needed because standard libraries think '\r' is part
+ // of a string.
+ if (_abuf[last] == 0x0a)
+ {
+ _abuf[last] = '\0';
+ len = last;
+ }
+
+#ifdef UNICODE
+ // Convert to wide characters including trailing null
+ mbstowcs(_awcbuf, _abuf, len + 1);
+#else
+ memcpy(_awcbuf, _abuf, len+1);
+#endif
+
+ // return new string
+ return _awcbuf;
+}
+
+
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CRegTextFile::GetLong
+//
+// Synopsis: Get a string from a file and convert it to an unsigned long.
+//
+// Arguments: None.
+//
+// Requires: Pointer to valid CRegTextFile object.
+//
+// Returns: ULONG read from file.
+//
+// Signals: CException.
+//
+// Algorithm: Read string and covert data to a long.
+//
+// History: 19-Dec-91 Ricksa Created
+//
+// Notes: This method does no error checking.
+//
+//--------------------------------------------------------------------
+ULONG
+CRegTextFile::GetLong(void)
+{
+ do
+ {
+ if (fgets(_abuf, sizeof(_abuf), _fp) == NULL)
+ {
+ printf("Read of long failed");
+ }
+ } while (_abuf[0] == COMMENT_MARK);
+
+ return atol(_abuf);
+}
+
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CRegTextFile::GetGUID
+//
+// Synopsis: Get a string from a file and convert it to a GUID.
+//
+// Arguments: None.
+//
+// Returns: a pointer to the GUID in the string buffer.
+//
+// Signals: CException.
+//
+// Algorithm: Read string and covert data to a GUID.
+//
+// History: 19-Dec-91 Ricksa Created
+//
+// Notes: This is not guaranteed to work in a multithreaded
+// environment.
+//
+//--------------------------------------------------------------------
+GUID *
+CRegTextFile::GetGUID(void)
+{
+ GUID *pguid = (GUID *) _awcbuf;
+
+ do
+ {
+ if (fgets(_abuf, sizeof(_abuf), _fp) == NULL)
+ {
+ printf("Read of GUID failed");
+ }
+ } while (_abuf[0] == COMMENT_MARK);
+
+
+ // Convert the string to a GUID
+ sscanf(_abuf, "%08lX%04X%04X",
+ &pguid->Data1, &pguid->Data2, &pguid->Data3);
+
+ for (int i = 0; i < 8; i++)
+ {
+ int tmp;
+ sscanf(_abuf + 16 + (i * 2), "%02X", &tmp);
+ pguid->Data4[i] = (char) tmp;
+ }
+
+ return pguid;
+}
+
+
+
+
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CRegTextFile::GetPath
+//
+// Synopsis: Get a path to a file system object
+//
+// Returns: a pointer to the path in the string buffer.
+//
+// Algorithm: Read string and add the system directory
+//
+// History: 26-Mar-92 Ricksa Created
+//
+// Notes: This is not guaranteed to work in a multithreaded
+// environment.
+//
+//--------------------------------------------------------------------
+LPTSTR
+CRegTextFile::GetPath(void)
+{
+ GetString();
+
+ if (lstrcmpi(_awcbuf, TEXT("END_OF_FILE")) == 0)
+ {
+ return _awcbuf;
+ }
+
+ // Temporary buffer to store result
+ TCHAR awcTmp[MAX_PATH];
+
+ // If the first characters in the string are "@:" we
+ // want to prepend the string with the system directory.
+#ifdef UNICODE
+ if (wcsnicmp(SYS_DIR_STR, _awcbuf, SYS_DIR_STR_LEN) == 0)
+#else
+ if (strnicmp(SYS_DIR_STR, _awcbuf, SYS_DIR_STR_LEN) == 0)
+#endif
+ {
+ // Copy in the system directory
+ lstrcpy(awcTmp, s_awcSysDir);
+
+ // Copy in the relative path
+ lstrcat(awcTmp, _awcbuf + SYS_DIR_STR_LEN);
+
+ // Copy whole string to output buffer
+ lstrcpy(_awcbuf, awcTmp);
+ }
+ else if ((_awcbuf[1] != ':') && (_awcbuf[3] != ':') && (_awcbuf[1] != '\\'))
+ {
+ // Convert relative path to absolute path based in the current
+ // directory.
+ GetCurrentDirectory(sizeof(awcTmp), awcTmp);
+
+ // Add a slash to end of the current directory
+ lstrcat(awcTmp, TEXT("\\"));
+
+ // Copy in the relative path
+ lstrcat(awcTmp, _awcbuf);
+
+ // Copy whole string to output buffer
+ lstrcpy(_awcbuf, awcTmp);
+ }
+
+ return _awcbuf;
+}
diff --git a/private/oleutest/balls/common/ctext.hxx b/private/oleutest/balls/common/ctext.hxx
new file mode 100644
index 000000000..5dc9eaff6
--- /dev/null
+++ b/private/oleutest/balls/common/ctext.hxx
@@ -0,0 +1,75 @@
+//+-------------------------------------------------------------------
+//
+// File: ctext.hxx
+//
+// Contents: Definition of class for processing ASCII files
+// in unicode
+//
+// Classes: CRegTextFile
+//
+// Functions: None.
+//
+// History: 18-Dec-91 Ricksa Created
+//
+//--------------------------------------------------------------------
+#ifndef __CTEXT__
+#define __CTEXT__
+
+#include <windows.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+
+#define COMMENT_MARK ';'
+
+#define SYS_DIR_STR TEXT("@:")
+#define SYS_DIR_STR_LEN (sizeof(SYS_DIR_STR) / sizeof(TCHAR) - 1)
+
+
+//+-------------------------------------------------------------------
+//
+// Class: CRegTextFile
+//
+// Purpose: Read in string data from a file
+//
+// Interface: GetString -- get a string from the file
+// GetLong -- get a string & convert it to a long
+// GetGUID -- read string and convert to guid format
+// GetPath -- read path & possibly prepend system directory.
+//
+// History: 02-Jan-92 Ricksa Created
+//
+// Notes: This is a temporary file used to support loading
+// class data from a file.
+//
+//--------------------------------------------------------------------
+class CRegTextFile
+{
+public:
+
+ CRegTextFile(LPSTR);
+
+ ~CRegTextFile(void);
+
+ LPTSTR GetString(void);
+
+ ULONG GetLong(void);
+
+ GUID * GetGUID(void);
+
+ LPTSTR GetPath(void);
+
+private:
+
+ FILE * _fp;
+
+ char _abuf[MAX_PATH];
+
+ TCHAR _awcbuf[MAX_PATH];
+
+ static TCHAR s_awcSysDir[MAX_PATH];
+
+ static int s_cSysDir;
+};
+
+#endif // __CTEXT__
diff --git a/private/oleutest/balls/common/cubescf.cxx b/private/oleutest/balls/common/cubescf.cxx
new file mode 100644
index 000000000..9e31a02df
--- /dev/null
+++ b/private/oleutest/balls/common/cubescf.cxx
@@ -0,0 +1,142 @@
+//+-------------------------------------------------------------------
+//
+// File: cubescf.cxx
+//
+// Contents: test class factory object implementation
+//
+// Classes: CCubesClassFactory
+//
+// Functions:
+//
+// History: 23-Nov-92 Rickhi Created
+//
+//--------------------------------------------------------------------
+
+#include <pch.cxx>
+#pragma hdrstop
+#include <cubescf.hxx> // class definiton
+#include <ccubes.hxx> // CCubes defines
+
+
+const GUID CLSID_Cubes =
+ {0x0000013b,0x0001,0x0008,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}};
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CCubesClassFactory::CCubesClassFactory, public
+//
+// Algorithm:
+//
+// History: 23-Nov-92 Rickhi Created
+//
+//--------------------------------------------------------------------
+
+CCubesClassFactory::CCubesClassFactory(void)
+{
+ ENLIST_TRACKING(CCubesClassFactory);
+}
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CCubesClassFactory::~CCubesClassFactory, public
+//
+// Algorithm:
+//
+// History: 23-Nov-92 Rickhi Created
+//
+//--------------------------------------------------------------------
+
+CCubesClassFactory::~CCubesClassFactory(void)
+{
+ // automatic actions do the rest of the work
+}
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CCubesClassFactory::QueryInterface, public
+//
+// Algorithm: if the interface is not one implemented by us,
+// pass the request to the proxy manager
+//
+// History: 23-Nov-92 Rickhi Created
+//
+//--------------------------------------------------------------------
+
+STDMETHODIMP CCubesClassFactory::QueryInterface(REFIID riid, void **ppUnk)
+{
+ SCODE sc = S_OK;
+
+ if (IsEqualIID(riid, IID_IUnknown) ||
+ IsEqualIID(riid, IID_IClassFactory))
+ {
+ *ppUnk = (void *)(IClassFactory *) this;
+ AddRef();
+ }
+ else
+ {
+ *ppUnk = NULL;
+ sc = E_NOINTERFACE;
+ }
+ return sc;
+}
+
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CCubesClassFactory::CreateInstance, public
+//
+// Synopsis: create a new object with the same class
+//
+// History: 23-Nov-92 Rickhi Created
+//
+//--------------------------------------------------------------------
+
+STDMETHODIMP CCubesClassFactory::CreateInstance(IUnknown *punkOuter,
+ REFIID riid,
+ void **ppunkObject)
+{
+ SCODE sc = E_OUTOFMEMORY;
+
+ *ppunkObject = NULL; // in case of failure
+
+ // create a Cube object.
+ ICube *pCubes = (ICube *) new CCube();
+
+ if (pCubes)
+ {
+ // get the interface the caller wants to use
+ sc = pCubes->QueryInterface(riid, ppunkObject);
+
+ // release our hold on the Cube, since the QI got a hold for
+ // the client.
+ pCubes->Release();
+ }
+
+ return sc;
+}
+
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CCubesClassFactory::LockServer, public
+//
+// Synopsis: create a new object with the same class
+//
+// History: 23-Nov-92 Rickhi Created
+//
+//--------------------------------------------------------------------
+
+STDMETHODIMP CCubesClassFactory::LockServer(BOOL fLock)
+{
+ if (fLock)
+ GlobalRefs(TRUE);
+ else
+ GlobalRefs(FALSE);
+
+ return S_OK;
+}
diff --git a/private/oleutest/balls/common/cubescf.hxx b/private/oleutest/balls/common/cubescf.hxx
new file mode 100644
index 000000000..e72eedae6
--- /dev/null
+++ b/private/oleutest/balls/common/cubescf.hxx
@@ -0,0 +1,61 @@
+//+-------------------------------------------------------------------
+//
+// File: cubescf.hxx
+//
+// Contents: test class factory object implementation
+//
+// Classes: CCubesClassFactory
+//
+// Functions: None
+//
+// History: 23-Nov-92 Rickhi Created
+//
+//--------------------------------------------------------------------
+
+#ifndef __CCUBESCLASSFACTORY__
+#define __CCUBESCLASSFACTORY__
+
+#include <win4p.hxx>
+#include <otrack.hxx> // object tracking
+
+extern "C" const GUID CLSID_Cubes;
+
+//+-------------------------------------------------------------------
+//
+// Class: CCubesClassFactory
+//
+// Purpose: test class factory object implementation
+//
+// Interface:
+//
+// History: 23-Nov-92 Rickhi Created
+//
+// Notes:
+//
+//--------------------------------------------------------------------
+
+class CCubesClassFactory : INHERIT_TRACKING,
+ public IClassFactory
+{
+public:
+ // Constructor & Destructor
+ CCubesClassFactory(void);
+
+ // IUnknown methods
+ STDMETHOD(QueryInterface)(REFIID riid, void **ppUnk);
+ DECLARE_STD_REFCOUNTING;
+
+
+ // IClassFactory methods
+ STDMETHOD(CreateInstance)(IUnknown *punkOuter,
+ REFIID riid,
+ void **ppunkObject);
+
+ STDMETHOD(LockServer)(BOOL fLock);
+
+private:
+ ~CCubesClassFactory(void);
+};
+
+
+#endif // __CCUBESCLASSFACTORY__
diff --git a/private/oleutest/balls/common/dataobj.cxx b/private/oleutest/balls/common/dataobj.cxx
new file mode 100644
index 000000000..6dadc5ab4
--- /dev/null
+++ b/private/oleutest/balls/common/dataobj.cxx
@@ -0,0 +1,310 @@
+//+-------------------------------------------------------------------
+//
+// File: dataobj.cxx
+//
+// Contents: IDataObject methods of CTestEmbed class.
+//
+// Classes: CTestEmbed - IDataObject implementation
+//
+// History: 7-Dec-92 DeanE Created
+//
+//---------------------------------------------------------------------
+#pragma optimize("",off)
+
+#include <pch.cxx>
+#pragma hdrstop
+#include <embed.hxx>
+#include <dataobj.hxx>
+
+
+//+-------------------------------------------------------------------
+// Member: CDataObject::CDataObject()
+//
+// Synopsis: The constructor for CDataObject.
+//
+// Arguments: None
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+CDataObject::CDataObject(CTestEmbed *pteObject)
+{
+ _cRef = 1;
+ _pDAHolder = NULL;
+ _pteObject = pteObject;
+}
+
+
+//+-------------------------------------------------------------------
+// Member: CDataObject::~CDataObject()
+//
+// Synopsis: The destructor for CDataObject.
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+CDataObject::~CDataObject()
+{
+ // _cRef count should be 1
+ if (1 != _cRef)
+ {
+ // BUGBUG - Log error
+ // Someone hasn't released one of these - Log error
+ }
+ return;
+}
+
+
+//+-------------------------------------------------------------------
+// Method: CDataObject::QueryInterface
+//
+// Synopsis: Forward this to the object we're associated with
+//
+// Parameters: [iid] - Interface ID to return.
+// [ppv] - Pointer to pointer to object.
+//
+// Returns: S_OK if iid is supported, or E_NOINTERFACE if not.
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP CDataObject::QueryInterface(REFIID iid, void FAR * FAR *ppv)
+{
+ return(_pteObject->QueryInterface(iid, ppv));
+}
+
+
+//+-------------------------------------------------------------------
+// Method: CDataObject::AddRef
+//
+// Synopsis: Forward this to the object we're associated with
+//
+// Returns: New reference count.
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP_(ULONG) CDataObject::AddRef(void)
+{
+ ++_cRef;
+ return(_pteObject->AddRef());
+}
+
+
+//+-------------------------------------------------------------------
+// Method: CDataObject::Release
+//
+// Synopsis: Forward this to the object we're associated with
+//
+// Returns: New reference count.
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP_(ULONG) CDataObject::Release(void)
+{
+ --_cRef;
+ return(_pteObject->Release());
+}
+
+
+//+-------------------------------------------------------------------
+// Method: CDataObject::GetData
+//
+// Synopsis: See spec 2.00.09 p129. Retrieve data for this object
+// using the FORMATETC passed.
+//
+// Parameters: [pformatetcIn] - The format caller wants returned data
+// [pmedium] - Returned data
+//
+// Returns: S_OK, or E_FORMAT if we don't support the format requested
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP CDataObject::GetData(
+ LPFORMATETC pformatetcIn,
+ LPSTGMEDIUM pmedium)
+{
+ // BUGBUG - NYI
+ return(E_FAIL);
+}
+
+
+//+-------------------------------------------------------------------
+// Method: CDataObject::GetDataHere
+//
+// Synopsis: See spec 2.00.09 p130. Like GetData, but the pmedium is
+// allocated and ready for us to use.
+//
+// Parameters: [pformatetc] - The format caller wants returned data
+// [pmedium] - STGMEDIUM object ready for our use
+//
+// Returns: S_OK, E_FORMAT
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP CDataObject::GetDataHere(
+ LPFORMATETC pformatetc,
+ LPSTGMEDIUM pmedium)
+{
+ // BUGBUG - NYI
+ return(E_FAIL);
+}
+
+
+//+-------------------------------------------------------------------
+// Method: CDataObject::QueryGetData
+//
+// Synopsis: See spec 2.00.09 p130. Answer if the format requested
+// would be honored by GetData.
+//
+// Parameters: [pformatetc] - The format being queried about
+//
+// Returns: S_OK or S_FALSE
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP CDataObject::QueryGetData(LPFORMATETC pformatetc)
+{
+ // BUGBUG - NYI
+ return(E_FAIL);
+}
+
+
+//+-------------------------------------------------------------------
+// Method: CDataObject::GetCanonicalFormatEtc
+//
+// Synopsis: See spec 2.00.09 p131
+//
+// Parameters: [pformatetc] -
+// [pformatetcOut] -
+//
+// Returns: S_OK
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP CDataObject::GetCanonicalFormatEtc(
+ LPFORMATETC pformatetc,
+ LPFORMATETC pformatetcOut)
+
+{
+ // BUGBUG - NYI
+ return(E_FAIL);
+}
+
+
+//+-------------------------------------------------------------------
+// Method: CDataObject::SetData
+//
+// Synopsis: See spec 2.00.09 p131.
+//
+// Parameters: [pformatetc] -
+// [pmedium] -
+// [fRelease] -
+//
+// Returns: S_OK
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP CDataObject::SetData(
+ LPFORMATETC pformatetc,
+ STGMEDIUM FAR *pmedium,
+ BOOL fRelease)
+{
+ // BUGBUG - NYI
+ return(DV_E_CLIPFORMAT);
+}
+
+
+//+-------------------------------------------------------------------
+// Method: CDataObject::EnumFormatEtc
+//
+// Synopsis: See spec 2.00.09 p131.
+//
+// Parameters: [dwDirection] -
+// [ppenmFormatEtc] -
+//
+// Returns: S_OK
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP CDataObject::EnumFormatEtc(
+ DWORD dwDirection,
+ LPENUMFORMATETC FAR *ppenmFormatEtc)
+{
+ // BUGBUG - NYI
+ *ppenmFormatEtc = NULL;
+ return(E_FAIL);
+}
+
+
+//+-------------------------------------------------------------------
+// Method: CDataObject::DAdvise
+//
+// Synopsis: See spec 2.00.09 p132
+//
+// Parameters: [pFormatetc] -
+// [advf] -
+// [pAdvSink] -
+// [pdwConnection] -
+//
+// Returns: S_OK
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP CDataObject::DAdvise(
+ FORMATETC FAR *pFormatetc,
+ DWORD advf,
+ LPADVISESINK pAdvSink,
+ DWORD FAR *pdwConnection)
+{
+ if (NULL == _pDAHolder)
+ {
+ if (S_OK != CreateDataAdviseHolder(&_pDAHolder))
+ {
+ return(E_OUTOFMEMORY);
+ }
+ }
+
+ return(_pDAHolder->Advise(this, pFormatetc, advf, pAdvSink, pdwConnection));
+}
+
+
+//+-------------------------------------------------------------------
+// Method: CDataObject::DUnadvise
+//
+// Synopsis: See spec 2.00.09 p133
+//
+// Parameters: [dwConnection] -
+//
+// Returns: S_OK
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP CDataObject::DUnadvise(DWORD dwConnection)
+{
+ if (NULL == _pDAHolder)
+ {
+ // Nobody is registered
+ return(E_INVALIDARG);
+ }
+
+ return(_pDAHolder->Unadvise(dwConnection));
+}
+
+
+//+-------------------------------------------------------------------
+// Method: CDataObject::EnumDAdvise
+//
+// Synopsis: See spec 2.00.09 p133
+//
+// Parameters: [ppenmAdvise] -
+//
+// Returns: S_OK
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP CDataObject::EnumDAdvise(LPENUMSTATDATA FAR *ppenmAdvise)
+{
+ if (NULL == _pDAHolder)
+ {
+ return(E_FAIL);
+ }
+
+ return(_pDAHolder->EnumAdvise(ppenmAdvise));
+}
diff --git a/private/oleutest/balls/common/dataobj.hxx b/private/oleutest/balls/common/dataobj.hxx
new file mode 100644
index 000000000..8fd0dc87d
--- /dev/null
+++ b/private/oleutest/balls/common/dataobj.hxx
@@ -0,0 +1,75 @@
+//+-------------------------------------------------------------------
+//
+// File: dataobj.hxx
+//
+// Contents: CDataObject declaration
+//
+// History: 24-Nov-92 DeanE Created
+//
+//---------------------------------------------------------------------
+
+#ifndef __DATAOBJ_HXX__
+#define __DATAOBJ_HXX__
+
+
+//+-------------------------------------------------------------------
+// Class: CDataObject
+//
+// Synopsis: Test class CDataObject
+//
+// Methods: QueryInterface IUnknown
+// AddRef IUnknown
+// Release IUnknown
+// GetData IDataObject
+// GetDataHere IDataObject
+// QueryGetData IDataObject
+// GetCanonicalFormatEtc IDataObject
+// SetData IDataObject
+// EnumFormatEtc IDataObject
+// DAdvise IDataObject
+// DUnadvise IDataObject
+// EnumDAdvise IDataObject
+//
+// History: 24-Nov-92 DeanE Created
+//--------------------------------------------------------------------
+class FAR CDataObject : public IDataObject
+{
+public:
+// Constructor/Destructor
+ CDataObject(CTestEmbed *pteObject);
+ ~CDataObject();
+
+// IUnknown - Everyone inherits from this
+ STDMETHODIMP QueryInterface(REFIID iid, void FAR * FAR *ppv);
+ STDMETHODIMP_(ULONG) AddRef (void);
+ STDMETHODIMP_(ULONG) Release (void);
+
+// IDataObject
+ STDMETHODIMP GetData (LPFORMATETC pformatetcIn,
+ LPSTGMEDIUM pmedium);
+ STDMETHODIMP GetDataHere (LPFORMATETC pformatetc,
+ LPSTGMEDIUM pmedium);
+ STDMETHODIMP QueryGetData (LPFORMATETC pformatetc);
+ STDMETHODIMP GetCanonicalFormatEtc(
+ LPFORMATETC pformatetc,
+ LPFORMATETC pformatetcOut);
+ STDMETHODIMP SetData (LPFORMATETC pformatetc,
+ STGMEDIUM FAR *pmedium,
+ BOOL fRelease);
+ STDMETHODIMP EnumFormatEtc (DWORD dwDirection,
+ LPENUMFORMATETC FAR *ppenmFormatEtc);
+ STDMETHODIMP DAdvise (FORMATETC FAR *pFormatetc,
+ DWORD advf,
+ LPADVISESINK pAdvSink,
+ DWORD FAR *pdwConnection);
+ STDMETHODIMP DUnadvise (DWORD dwConnection);
+ STDMETHODIMP EnumDAdvise (LPENUMSTATDATA FAR *ppenmAdvise);
+
+private:
+ ULONG _cRef; // Reference count
+ IDataAdviseHolder FAR *_pDAHolder; // Advise Holder
+ CTestEmbed *_pteObject; // Object we're associated with
+};
+
+
+#endif // __DATAOBJ_HXX__
diff --git a/private/oleutest/balls/common/daytona/makefile b/private/oleutest/balls/common/daytona/makefile
new file mode 100644
index 000000000..1d3728d41
--- /dev/null
+++ b/private/oleutest/balls/common/daytona/makefile
@@ -0,0 +1,10 @@
+############################################################################
+#
+# Copyright (C) 1992, Microsoft Corporation.
+#
+# All rights reserved.
+#
+############################################################################
+
+!include $(NTMAKEENV)\makefile.def
+
diff --git a/private/oleutest/balls/common/daytona/sources b/private/oleutest/balls/common/daytona/sources
new file mode 100644
index 000000000..dc546af50
--- /dev/null
+++ b/private/oleutest/balls/common/daytona/sources
@@ -0,0 +1,103 @@
+!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:
+
+ David Plummer (davepl) 19-Mar-94
+
+ Modifed by via awk to include global project include file
+ and to wrap precompiled header line within a conditional
+ that can be set in this include file.
+
+ Donna Liu (DonnaLi) 19-Dec-1993
+
+!ENDIF
+
+MAJORCOMP = cairole
+MINORCOMP = com
+
+#
+# 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= servers
+
+#
+# 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= LIBRARY
+
+
+#
+# The following includes a global include file defined at the
+# base of the project for all components
+#
+
+!include ..\..\daytona.inc
+
+INCLUDES= ..\;..\..\oleprx32\proxy;
+
+C_DEFINES= \
+ $(C_DEFINES)
+
+
+SOURCES= \
+ ..\mixedcf.cxx \
+ ..\srvmain.cxx \
+ ..\tstmain.cxx \
+ ..\loopscf.cxx \
+ ..\cloop.cxx \
+ ..\ballscf.cxx \
+ ..\cballs.cxx \
+ ..\cubescf.cxx \
+ ..\ccubes.cxx \
+ ..\rpccf.cxx \
+ ..\crpc.cxx \
+ ..\memstm.cxx \
+ ..\qicf.cxx \
+ ..\cqisrv.cxx \
+ ..\actcf.cxx \
+ ..\cact.cxx \
+ ..\embed.cxx \
+ ..\bscbnd.cxx \
+ ..\ctext.cxx \
+ ..\wterm2.cxx \
+ ..\wterm.c \
+ ..\advbnd.cxx \
+ ..\persist.cxx \
+ ..\oleobj.cxx \
+ ..\dataobj.cxx \
+ ..\stream.cxx \
+ ..\regmain.cxx
+
+
+UMTYPE= console
+UMAPPL=
+UMTEST=
+UMLIBS=
+
+PRECOMPILED_INCLUDE= ..\pch.cxx
diff --git a/private/oleutest/balls/common/dirs b/private/oleutest/balls/common/dirs
new file mode 100644
index 000000000..1d0b9edbb
--- /dev/null
+++ b/private/oleutest/balls/common/dirs
@@ -0,0 +1,38 @@
+!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/balls/common/embed.cxx b/private/oleutest/balls/common/embed.cxx
new file mode 100644
index 000000000..8b798c9e1
--- /dev/null
+++ b/private/oleutest/balls/common/embed.cxx
@@ -0,0 +1,401 @@
+//+-------------------------------------------------------------------
+//
+// File: embed.cxx
+//
+// Contents:
+//
+// Classes: CTestEmbedCF - IClassFactory
+//
+// History: 7-Dec-92 DeanE Created
+//---------------------------------------------------------------------
+
+#include <pch.cxx>
+#pragma hdrstop
+#pragma optimize("",off)
+
+class CTestServerApp;
+class CDataObject;
+class COleObject;
+class CPersistStorage;
+
+
+#include <embed.hxx>
+#include <dataobj.hxx>
+#include <oleobj.hxx>
+#include <persist.hxx>
+#include <csrvapp.hxx>
+
+
+extern HWND g_hwndMain;
+
+
+//+-------------------------------------------------------------------
+// Member: CTestEmbedCF::CTestEmbedCF()
+//
+// Synopsis: The constructor for CTestEmbedCF.
+//
+// Arguments: None
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+CTestEmbedCF::CTestEmbedCF(CTestServerApp *ptsaServer) : _cRef(1)
+{
+ _ptsaServer = ptsaServer;
+
+ return;
+}
+
+
+//+-------------------------------------------------------------------
+// Member: CTestEmbedCF::~CTestEmbedCF()
+//
+// Synopsis: The destructor for CTestEmbedCF.
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+CTestEmbedCF::~CTestEmbedCF()
+{
+ _ptsaServer = NULL;
+}
+
+
+//+-------------------------------------------------------------------
+// Member: CTestEmbedCF::Create()
+//
+// Synopsis: Creates a new CTestEmbedCF object.
+//
+// Arguments: None
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+IClassFactory FAR* CTestEmbedCF::Create(CTestServerApp *ptsaServer)
+{
+ CTestEmbedCF FAR* pteCF = new FAR CTestEmbedCF(ptsaServer);
+ return(pteCF);
+}
+
+
+//+-------------------------------------------------------------------
+// Method: CTestEmbedCF::QueryInterface
+//
+// Synopsis: Only IUnknown and IClassFactory supported
+// return pointer to the actual object
+//
+// Parameters: [iid] - Interface ID to return.
+// [ppv] - Pointer to pointer to object.
+//
+// Returns: S_OK if iid is supported, or E_NOINTERFACE if not.
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP CTestEmbedCF::QueryInterface(REFIID iid, void FAR * FAR * ppv)
+{
+ if (IsEqualIID(iid, IID_IUnknown) || IsEqualIID(iid, IID_IClassFactory))
+ {
+ *ppv = this;
+ AddRef();
+ return(S_OK);
+ }
+ else
+ {
+ *ppv = NULL;
+ return(E_NOINTERFACE);
+ }
+}
+
+STDMETHODIMP_(ULONG) CTestEmbedCF::AddRef(void)
+{
+ return ++_cRef;
+}
+
+STDMETHODIMP_(ULONG) CTestEmbedCF::Release(void)
+{
+ if (--_cRef == 0)
+ {
+ delete this;
+ return 0;
+ }
+
+ return _cRef;
+}
+
+
+//+-------------------------------------------------------------------
+// Method: CTestEmbedCF::CreateInstance
+//
+// Synopsis: This is called by Binding process to create the
+// actual class object.
+//
+// Parameters: [pUnkOuter] - Ignored. Affects aggregation.
+// [iidInterface] - Interface ID object should support.
+// [ppv] - Pointer to the object.
+//
+// Returns: S_OOM if object couldn't be created, or SCODE from
+// QueryInterface call.
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP CTestEmbedCF::CreateInstance(
+ IUnknown FAR *pUnkOuter,
+ REFIID iidInterface,
+ void FAR* FAR *ppv)
+{
+ CTestEmbed FAR *pteObj;
+ SCODE sc;
+
+ pteObj = new FAR CTestEmbed();
+ if (pteObj == NULL)
+ {
+ return(E_OUTOFMEMORY);
+ }
+
+ sc = pteObj->InitObject(_ptsaServer, g_hwndMain);
+ if (S_OK != sc)
+ {
+ delete pteObj;
+ return(E_OUTOFMEMORY);
+ }
+
+ // Having created the actual object, ensure desired
+ // interfaces are available.
+ //
+ sc = pteObj->QueryInterface(iidInterface, ppv);
+
+
+ // We are done with the CTestEmbed instance - it's now referenced by ppv
+ pteObj->Release();
+
+ return(sc);
+}
+
+//+-------------------------------------------------------------------
+// Method: CTestEmbedCF::LockServer
+//
+// Synopsis: What does this do?
+//
+// Parameters: [fLock] - ???
+//
+// Returns: ???
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP CTestEmbedCF::LockServer(BOOL fLock)
+{
+ // BUGBUG - What does this do?
+ return(E_FAIL);
+}
+
+
+
+
+
+//+-------------------------------------------------------------------
+// Method: CTestEmbed::CTestEmbed
+//
+// Synopsis: Constructor for CTestEmbed objects
+//
+// Parameters: None
+//
+// Returns: None
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+CTestEmbed::CTestEmbed() : _cRef(1)
+{
+ _ptsaServer = NULL;
+ _pDataObject = NULL;
+ _pOleObject = NULL;
+ _pPersStg = NULL;
+ _hwnd = NULL;
+}
+
+
+//+-------------------------------------------------------------------
+// Method: CTestEmbed::~CTestEmbed
+//
+// Synopsis: Performs cleanup for CTestEmbed objects by releasing
+// internal pointers.
+//
+// Parameters: None
+//
+// Returns: None
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+CTestEmbed::~CTestEmbed()
+{
+ // Inform controlling server app this object is gone
+ _ptsaServer->DecEmbeddedCount();
+
+ // Delete all of this objects interface classes
+ delete _pDataObject;
+ delete _pOleObject;
+ delete _pPersStg;
+}
+
+
+//+-------------------------------------------------------------------
+// Method: CTestEmbed::InitObject
+//
+// Synopsis: Initialize this CTestEmbed object - ie, set everything
+// up for actual use.
+//
+// Parameters: None
+//
+// Returns: S_OK if everything is okay to use, or an error code
+//
+// History: 7-Dec-92 DeanE Created
+//
+// Notes: The state of the object must be cleaned up in case of
+// failure - so the destructor will not blow up.
+//--------------------------------------------------------------------
+SCODE CTestEmbed::InitObject(CTestServerApp *ptsaServer, HWND hwnd)
+{
+ SCODE sc = S_OK;
+
+ // Initialize controlling server app
+ if (NULL != ptsaServer)
+ {
+ _ptsaServer = ptsaServer;
+ }
+ else
+ {
+ sc = E_ABORT;
+ }
+
+ // Initilize this objects window handle
+ _hwnd = hwnd;
+
+ // Create a CDataObject
+ if (SUCCEEDED(sc))
+ {
+ _pDataObject = new CDataObject(this);
+ if (NULL == _pDataObject)
+ {
+ sc = E_ABORT;
+ }
+ }
+
+ // Create a COleObject
+ if (SUCCEEDED(sc))
+ {
+ _pOleObject = new COleObject(this);
+ if (NULL == _pOleObject)
+ {
+ sc = E_ABORT;
+ }
+ }
+
+ // Create a CPersistStorage
+ if (SUCCEEDED(sc))
+ {
+ _pPersStg = new CPersistStorage(this);
+ if (NULL == _pPersStg)
+ {
+ sc = E_ABORT;
+ }
+ }
+
+ if (FAILED(sc))
+ {
+ delete _pDataObject;
+ delete _pOleObject;
+ delete _pPersStg;
+ _pDataObject = NULL;
+ _pOleObject = NULL;
+ _pPersStg = NULL;
+ _ptsaServer = NULL;
+ _hwnd = NULL;
+ }
+
+ // Inform controlling server we are a new embedded object
+ if (SUCCEEDED(sc))
+ {
+ _ptsaServer->IncEmbeddedCount();
+ }
+
+ return(sc);
+}
+
+
+//+-------------------------------------------------------------------
+// Method: CTestEmbed::QueryInterface
+//
+// Synopsis: IUnknown, IOleObject, IPersist, IPersistStorage supported
+// return pointer to the actual object
+//
+// Parameters: [iid] - Interface ID to return.
+// [ppv] - Pointer to pointer to object.
+//
+// Returns: S_OK if iid is supported, or E_NOINTERFACE if not.
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP CTestEmbed::QueryInterface(REFIID iid, void FAR * FAR * ppv)
+{
+ SCODE scRet;
+
+ if (IsEqualIID(IID_IUnknown, iid))
+ {
+ *ppv = (IUnknown *)this;
+ AddRef();
+ scRet = S_OK;
+ }
+ else
+ if (IsEqualIID(IID_IOleObject, iid))
+ {
+ *ppv = _pOleObject;
+ AddRef();
+ scRet = S_OK;
+ }
+ else
+ if (IsEqualIID(IID_IPersist, iid) || IsEqualIID(IID_IPersistStorage, iid))
+ {
+ *ppv = _pPersStg;
+ AddRef();
+ scRet = S_OK;
+ }
+ else
+ if (IsEqualIID(IID_IDataObject, iid))
+ {
+ *ppv = _pDataObject;
+ AddRef();
+ scRet = S_OK;
+ }
+ else
+ {
+ *ppv = NULL;
+ scRet = E_NOINTERFACE;
+ }
+
+ return(scRet);
+}
+
+
+STDMETHODIMP_(ULONG) CTestEmbed::AddRef(void)
+{
+ return ++_cRef;
+}
+
+STDMETHODIMP_(ULONG) CTestEmbed::Release(void)
+{
+ if (--_cRef == 0)
+ {
+ delete this;
+ return 0;
+ }
+
+ return _cRef;
+}
+SCODE CTestEmbed::GetWindow(HWND *phwnd)
+{
+ if (NULL != phwnd)
+ {
+ *phwnd = _hwnd;
+ return(S_OK);
+ }
+ else
+ {
+ return(E_ABORT);
+ }
+}
diff --git a/private/oleutest/balls/common/embed.hxx b/private/oleutest/balls/common/embed.hxx
new file mode 100644
index 000000000..e5198e5a6
--- /dev/null
+++ b/private/oleutest/balls/common/embed.hxx
@@ -0,0 +1,103 @@
+//+-------------------------------------------------------------------
+//
+// File: embed.hxx
+//
+// Contents: CTestEmbedCF and CTestEmbed object declarations
+//
+// History: 24-Nov-92 DeanE Created
+//
+//---------------------------------------------------------------------
+
+#ifndef __EMBED_HXX__
+#define __EMBED_HXX__
+
+extern "C" const GUID CLSID_TestEmbed;
+
+class CTestServerApp;
+class CTestEmbedCF;
+class CDataObject;
+class COleObject;
+class CPersistStorage;
+
+
+//+-------------------------------------------------------------------
+// Class: CTestEmbedCF
+//
+// Synopsis: Class Factory for CTestEmbed object type
+//
+// Methods: QueryInterface - IUnknown
+// AddRef - IUnknown
+// Release - IUnknown
+// CreateInstance - IClassFactory
+// LockServer - IClassFactory
+//
+// History: 24-Nov-92 DeanE Created
+//--------------------------------------------------------------------
+
+class CTestEmbedCF : public IClassFactory
+{
+public:
+
+// Constructor/Destructor
+ CTestEmbedCF(CTestServerApp *ptsaServer);
+ ~CTestEmbedCF();
+ static IClassFactory FAR *Create(CTestServerApp *ptsaServer);
+
+// IUnknown
+ STDMETHODIMP QueryInterface (REFIID iid, void FAR * FAR *ppv);
+ STDMETHODIMP_(ULONG) AddRef (void);
+ STDMETHODIMP_(ULONG) Release (void);
+
+// IClassFactory
+ STDMETHODIMP CreateInstance (IUnknown FAR *pUnkOuter,
+ REFIID iidInterface,
+ void FAR * FAR *ppv);
+ STDMETHODIMP LockServer (BOOL fLock);
+
+private:
+
+ ULONG _cRef; // Reference count on this object
+
+ CTestServerApp *_ptsaServer; // Controlling server app
+};
+
+
+//+-------------------------------------------------------------------
+// Class: CTestEmbed
+//
+// Synopsis: CTestEmbed (one instance per object)
+//
+// Methods: QueryInterface IUnknown
+// AddRef IUnknown
+// Release IUnknown
+// InitObject
+//
+// History: 24-Nov-92 DeanE Created
+//--------------------------------------------------------------------
+class CTestEmbed : public IUnknown
+{
+public:
+// Constructor/Destructor
+ CTestEmbed();
+ ~CTestEmbed();
+
+// IUnknown
+ STDMETHODIMP QueryInterface(REFIID iid, void FAR * FAR *ppv);
+ STDMETHODIMP_(ULONG) AddRef (void);
+ STDMETHODIMP_(ULONG) Release (void);
+
+ SCODE InitObject (CTestServerApp *ptsaServer, HWND hwnd);
+ SCODE GetWindow (HWND *phwnd);
+
+private:
+
+ ULONG _cRef; // Reference counter
+ CTestServerApp *_ptsaServer; // Server "holding" this object
+ CDataObject *_pDataObject; // Points to object's IDataObject
+ COleObject *_pOleObject; // Points to object's IOleObject
+ CPersistStorage *_pPersStg; // Points to object's IPersistStorage
+ HWND _hwnd; // Window handle for this object
+};
+
+
+#endif // __EMBED_HXX__
diff --git a/private/oleutest/balls/common/loopscf.cxx b/private/oleutest/balls/common/loopscf.cxx
new file mode 100644
index 000000000..1426d1f8a
--- /dev/null
+++ b/private/oleutest/balls/common/loopscf.cxx
@@ -0,0 +1,141 @@
+//+-------------------------------------------------------------------
+//
+// File: loopscf.cxx
+//
+// Contents: test class factory object implementation
+//
+// Classes: CLoopClassFactory
+//
+// History: 23-Nov-92 Rickhi Created
+//
+//--------------------------------------------------------------------
+
+#include <pch.cxx>
+#pragma hdrstop
+#include <loopscf.hxx> // class definiton
+#include <cloop.hxx> // CLoop defines
+
+
+const GUID CLSID_Loop =
+ {0x0000013c,0x0001,0x0008,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}};
+
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CLoopClassFactory::CLoopClassFactory, public
+//
+// Algorithm:
+//
+// History: 23-Nov-92 Rickhi Created
+//
+//--------------------------------------------------------------------
+
+CLoopClassFactory::CLoopClassFactory(void)
+{
+ ENLIST_TRACKING(CLoopClassFactory);
+}
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CLoopClassFactory::~CLoopClassFactory, public
+//
+// Algorithm:
+//
+// History: 23-Nov-92 Rickhi Created
+//
+//--------------------------------------------------------------------
+
+CLoopClassFactory::~CLoopClassFactory(void)
+{
+ // automatic actions do the rest of the work
+}
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CLoopClassFactory::QueryInterface, public
+//
+// Algorithm: if the interface is not one implemented by us,
+// pass the request to the proxy manager
+//
+// History: 23-Nov-92 Rickhi Created
+//
+//--------------------------------------------------------------------
+
+STDMETHODIMP CLoopClassFactory::QueryInterface(REFIID riid, void **ppUnk)
+{
+ SCODE sc = S_OK;
+
+ if (IsEqualIID(riid, IID_IUnknown) ||
+ IsEqualIID(riid, IID_IClassFactory))
+ {
+ *ppUnk = (void *)(IClassFactory *) this;
+ AddRef();
+ }
+ else
+ {
+ *ppUnk = NULL;
+ sc = E_NOINTERFACE;
+ }
+ return sc;
+}
+
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CLoopClassFactory::CreateInstance, public
+//
+// Synopsis: create a new object with the same class
+//
+// History: 23-Nov-92 Rickhi Created
+//
+//--------------------------------------------------------------------
+
+STDMETHODIMP CLoopClassFactory::CreateInstance(IUnknown *punkOuter,
+ REFIID riid,
+ void **ppunkObject)
+{
+ SCODE sc = E_OUTOFMEMORY;
+
+ *ppunkObject = NULL; // in case of failure
+
+ // create a ball object.
+ IUnknown *punk = (IUnknown *) new CLoop();
+
+ if (punk)
+ {
+ // get the interface the caller wants to use
+ sc = punk->QueryInterface(riid, ppunkObject);
+
+ // release our hold on the ball, since the QI got a hold for
+ // the client.
+ punk->Release();
+ }
+
+ return sc;
+}
+
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CLoopClassFactory::LockServer, public
+//
+// Synopsis: create a new object with the same class
+//
+// History: 23-Nov-92 Rickhi Created
+//
+//--------------------------------------------------------------------
+
+STDMETHODIMP CLoopClassFactory::LockServer(BOOL fLock)
+{
+ if (fLock)
+ GlobalRefs(TRUE);
+ else
+ GlobalRefs(FALSE);
+
+ return S_OK;
+}
diff --git a/private/oleutest/balls/common/loopscf.hxx b/private/oleutest/balls/common/loopscf.hxx
new file mode 100644
index 000000000..5dace3a3f
--- /dev/null
+++ b/private/oleutest/balls/common/loopscf.hxx
@@ -0,0 +1,61 @@
+//+-------------------------------------------------------------------
+//
+// File: loopscf.hxx
+//
+// Contents: test class factory object implementation
+//
+// Classes: CLoopClassFactory
+//
+// Functions: None
+//
+// History: 23-Nov-92 Rickhi Created
+//
+//--------------------------------------------------------------------
+
+#ifndef __CLOOPCLASSFACTORY__
+#define __CLOOPCLASSFACTORY__
+
+#include <win4p.hxx>
+#include <otrack.hxx> // object tracking
+
+extern "C" const GUID CLSID_Loop;
+
+//+-------------------------------------------------------------------
+//
+// Class: CLoopClassFactory
+//
+// Purpose: test class factory object implementation
+//
+// Interface:
+//
+// History: 23-Nov-92 Rickhi Created
+//
+// Notes:
+//
+//--------------------------------------------------------------------
+
+class CLoopClassFactory : INHERIT_TRACKING,
+ public IClassFactory
+{
+public:
+ // Constructor & Destructor
+ CLoopClassFactory(void);
+
+ // IUnknown methods
+ STDMETHOD(QueryInterface)(REFIID riid, void **ppUnk);
+ DECLARE_STD_REFCOUNTING;
+
+
+ // IClassFactory methods
+ STDMETHOD(CreateInstance)(IUnknown *punkOuter,
+ REFIID riid,
+ void **ppunkObject);
+
+ STDMETHOD(LockServer)(BOOL fLock);
+
+private:
+ ~CLoopClassFactory(void);
+};
+
+
+#endif // __CLOOPCLASSFACTORY__
diff --git a/private/oleutest/balls/common/memstm.cxx b/private/oleutest/balls/common/memstm.cxx
new file mode 100644
index 000000000..058c0c0a2
--- /dev/null
+++ b/private/oleutest/balls/common/memstm.cxx
@@ -0,0 +1,1004 @@
+//+-------------------------------------------------------------------
+//
+// File: memstm.cxx
+//
+// Contents: test class for IStream
+//
+// Classes: CMemStm
+//
+// History: 23-Nov-92 Rickhi Created
+//
+//--------------------------------------------------------------------
+
+#include <pch.cxx>
+#pragma hdrstop
+#include "memstm.h"
+
+
+extern "C" {
+const GUID CLSID_StdMemStm =
+ {0x00000301,0x0000,0x0000,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}};
+
+const GUID CLSID_StdMemBytes =
+ {0x00000302,0x0000,0x0000,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}};
+}
+
+
+
+
+// Shared memory IStream implementation
+//
+
+STDMETHODIMP CMemStm::QueryInterface(REFIID iidInterface, void **ppvObj)
+{
+ SCODE error;
+ *ppvObj = NULL;
+
+ // Two interfaces supported: IUnknown, IStream
+
+ if (m_pData != NULL &&
+ (IsEqualIID(iidInterface,IID_IStream) ||
+ IsEqualIID(iidInterface,IID_IUnknown)))
+
+ {
+ m_refs++; // A pointer to this object is returned
+ *ppvObj = this;
+ error = S_OK;
+ }
+ else
+ { // Not accessible or unsupported interface
+ *ppvObj = NULL;
+ error = E_NOINTERFACE;
+ }
+
+ return error;
+}
+
+
+STDMETHODIMP_(ULONG) CMemStm::AddRef(void)
+{
+ ++ m_refs;
+ return m_refs;
+}
+
+
+STDMETHODIMP_(ULONG) CMemStm::Release(void)
+{
+ --m_refs;
+
+ if (m_refs != 0) // Still used by others
+ return m_refs;
+
+ // Matches the allocation in CMemStm::Create().
+ //
+ if (--m_pData->cRef == 0)
+ {
+ GlobalUnlock(m_hMem);
+ GlobalFree(m_hMem);
+ }
+ else
+ GlobalUnlock(m_hMem);
+
+ delete this; // Free storage
+ return 0;
+}
+
+
+STDMETHODIMP CMemStm::Read(void HUGEP* pb, ULONG cb, ULONG * pcbRead)
+{
+ SCODE error = S_OK;
+ ULONG cbRead = cb;
+
+ if (pcbRead)
+ *pcbRead = 0L;
+
+ if (cbRead + m_pos > m_pData->cb)
+ {
+ cbRead = m_pData->cb - m_pos;
+ error = E_FAIL;
+ }
+
+ // BUGBUG - size_t limit
+ memcpy(pb,m_pData->buf + m_pos,(size_t) cbRead);
+ m_pos += cbRead;
+
+ if (pcbRead != NULL)
+ *pcbRead = cbRead;
+
+ return error;
+}
+
+
+STDMETHODIMP CMemStm::Write(void const HUGEP* pb, ULONG cb, ULONG * pcbWritten)
+{
+ SCODE error = S_OK;
+ ULONG cbWritten = cb;
+ ULARGE_INTEGER ularge_integer;
+
+ if (pcbWritten)
+ *pcbWritten = 0L;
+
+ if (cbWritten + m_pos > m_pData->cb)
+ {
+ ULISet32( ularge_integer, m_pos+cbWritten );
+ error = SetSize(ularge_integer);
+ if (error != S_OK)
+ return error;
+ }
+
+ // BUGBUG - size_t limit
+ memcpy(m_pData->buf + m_pos,pb,(size_t) cbWritten);
+ m_pos += cbWritten;
+
+ if (pcbWritten != NULL)
+ *pcbWritten = cbWritten;
+
+ return error;
+}
+
+STDMETHODIMP CMemStm::Seek(LARGE_INTEGER dlibMoveIN, DWORD dwOrigin, ULARGE_INTEGER * plibNewPosition)
+{
+ SCODE error = S_OK;
+ LONG dlibMove = dlibMoveIN.LowPart ;
+ ULONG cbNewPos = dlibMove;
+
+ if (plibNewPosition != NULL)
+ {
+ ULISet32(*plibNewPosition, m_pos);
+ }
+
+ switch(dwOrigin)
+ {
+ case STREAM_SEEK_SET:
+ if (dlibMove >= 0)
+ m_pos = dlibMove;
+ else
+ error = E_FAIL;
+ break;
+
+ case STREAM_SEEK_CUR:
+ if (!(dlibMove < 0 && ((ULONG) -dlibMove) > m_pos))
+ m_pos += dlibMove;
+ else
+ error = E_FAIL;
+ break;
+
+ case STREAM_SEEK_END:
+ if (!(dlibMove < 0 && ((ULONG) -dlibMove) > m_pData->cb))
+ m_pos = m_pData->cb + dlibMove;
+ else
+ error = E_FAIL;
+ break;
+
+ default:
+ error = E_FAIL;
+ }
+
+ if (plibNewPosition != NULL)
+ ULISet32(*plibNewPosition, m_pos);
+
+ return error;
+}
+
+
+STDMETHODIMP CMemStm::SetSize(ULARGE_INTEGER cb)
+{
+ HANDLE hMemNew;
+ struct MEMSTM * pDataNew;
+
+ if (m_pData->cb == cb.LowPart)
+ return S_OK;
+
+ if (GlobalUnlock(m_hMem) != 0)
+ return E_FAIL;
+
+ hMemNew = GlobalReAlloc(m_hMem,sizeof(MEMSTM) -
+ sizeof(m_pData->buf) + cb.LowPart,GMEM_DDESHARE | GMEM_MOVEABLE);
+
+ if (hMemNew == NULL)
+ {
+ GlobalLock(m_hMem);
+ return E_OUTOFMEMORY;
+ }
+
+ pDataNew = (MEMSTM *) GlobalLock(hMemNew);
+
+ if (pDataNew == NULL) // Completely hosed
+ return E_FAIL;
+
+ m_hMem = hMemNew;
+ pDataNew->cb = cb.LowPart;
+ m_pData = pDataNew;
+
+ return S_OK;
+}
+
+STDMETHODIMP CMemStm::CopyTo(IStream *pstm, ULARGE_INTEGER cb,
+ ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *pcbWritten)
+{
+ SCODE hRslt;
+ ULONG cbWritten = 0;
+
+ if (!pstm)
+ return E_FAIL;
+
+ // write our data into the stream.
+ hRslt = pstm->Write(m_pData->buf, cb.LowPart, &cbWritten);
+
+ pcbRead->LowPart = cb.LowPart;
+ pcbRead->HighPart = 0;
+ pcbWritten->LowPart = cbWritten;
+ pcbWritten->HighPart = 0;
+
+ return hRslt;
+}
+
+STDMETHODIMP CMemStm::Commit(DWORD grfCommitFlags)
+{
+ return E_FAIL;
+}
+STDMETHODIMP CMemStm::Revert(void)
+{
+ return E_FAIL;
+}
+STDMETHODIMP CMemStm::LockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
+{
+ return E_FAIL;
+}
+STDMETHODIMP CMemStm::UnlockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
+{
+ return E_FAIL;
+}
+
+STDMETHODIMP CMemStm::Stat(STATSTG *pstatstg, DWORD statflag)
+{
+ pstatstg->pwcsName = NULL;
+ pstatstg->type = 0;
+ pstatstg->cbSize.HighPart = 0;
+ pstatstg->cbSize.LowPart = m_pData->cb;
+ pstatstg->mtime.dwLowDateTime = 0;
+ pstatstg->mtime.dwHighDateTime = 0;
+ pstatstg->ctime.dwLowDateTime = 0;
+ pstatstg->ctime.dwHighDateTime = 0;
+ pstatstg->atime.dwLowDateTime = 0;
+ pstatstg->atime.dwHighDateTime = 0;
+ pstatstg->grfMode = 0;
+ pstatstg->grfLocksSupported = 0;
+ pstatstg->clsid = CLSID_NULL;
+ pstatstg->grfStateBits = 0;
+
+#ifdef CAIROLE_DOWNLEVEL
+ pstatstg->reserved = 0;
+#else
+ pstatstg->dwStgFmt = 0;
+#endif
+
+ return S_OK;
+}
+
+STDMETHODIMP CMemStm::Clone(IStream * *ppstm)
+{
+ SCODE hRslt = E_FAIL;
+
+ // create a new stream
+ IStream *pIStm = CreateMemStm(m_pData->cb, NULL);
+
+ if (pIStm)
+ {
+ // copy data to it
+ ULARGE_INTEGER cbRead, cbWritten;
+ ULARGE_INTEGER cb;
+ cb.LowPart = m_pData->cb;
+ cb.HighPart = 0;
+
+ hRslt = CopyTo(pIStm, cb, &cbRead, &cbWritten);
+ if (hRslt == S_OK)
+ {
+ *ppstm = pIStm;
+ }
+ }
+
+ return hRslt;
+}
+
+
+// Create CMemStm.
+//
+CMemStm * CMemStm::Create(HANDLE hMem)
+{
+ CMemStm * pCMemStm;
+ struct MEMSTM * pData;
+
+ pData = (MEMSTM *) GlobalLock(hMem);
+ if (pData == NULL)
+ return NULL;
+
+ pCMemStm = new CMemStm;
+
+ if (pCMemStm == NULL)
+ {
+ GlobalUnlock(hMem);
+ return NULL;
+ }
+
+ // Initialize CMemStm
+ //
+ pCMemStm->m_hMem = hMem;
+ (pCMemStm->m_pData = pData)->cRef++;
+ pCMemStm->m_refs = 1;
+
+ return pCMemStm;
+}
+
+
+
+
+// Allocate shared memory and create CMemStm on top of it.
+// Return pointer to the stream if done, NULL if error.
+//
+STDAPI_(LPSTREAM) CreateMemStm(DWORD cb, LPHANDLE phMem)
+{
+ HANDLE hMem;
+ struct MEMSTM * pData;
+ IStream * pStm;
+
+ if ( phMem )
+ *phMem = NULL;
+
+ // Get shared memory
+ hMem = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE,
+ sizeof(MEMSTM) - sizeof(pData->buf) + cb);
+ if (hMem == NULL)
+ return NULL;
+
+ pData = (MEMSTM *) GlobalLock(hMem);
+ if (pData == NULL)
+ goto FreeMem;
+
+ pData->cb = cb;
+ // If caller doesn't ask for the memory handle
+ // Release() should free the memory.
+ //
+ pData->cRef = (phMem == NULL) ? 0 : 1;
+ GlobalUnlock(hMem);
+
+ pStm = CMemStm::Create(hMem); // Create the stream
+ if (pStm == NULL)
+ goto FreeMem;
+
+ if (phMem)
+ *phMem = hMem;
+
+ return pStm;
+
+FreeMem:
+ GlobalFree(hMem);
+ return NULL;
+}
+
+
+
+// Create CMemStm on top of the specified hMem.
+// Return pointer to the stream if done, NULL if error.
+//
+STDAPI_(LPSTREAM) CloneMemStm(HANDLE hMem)
+{
+ return CMemStm::Create(hMem); // Create the stream
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+// Shared memory ILockBytes implementation
+//
+
+STDMETHODIMP CMemBytes::QueryInterface(REFIID iidInterface,
+ void **ppvObj)
+{
+ SCODE error = S_OK;
+ *ppvObj = NULL;
+
+ // Two interfaces supported: IUnknown, ILockBytes
+
+ if (m_pData != NULL &&
+ (IsEqualIID(iidInterface,IID_ILockBytes) ||
+ IsEqualIID(iidInterface,IID_IUnknown)))
+ {
+
+ m_refs++; // A pointer to this object is returned
+ *ppvObj = this;
+ }
+ else if (IsEqualIID(iidInterface,IID_IMarshal))
+ {
+ *ppvObj = (LPVOID) CMarshalMemBytes::Create(this);
+ if (*ppvObj == NULL)
+ error = E_OUTOFMEMORY;
+ }
+ else
+ { // Not accessible or unsupported interface
+ *ppvObj = NULL;
+ error = E_NOINTERFACE;
+ }
+
+ return error;
+}
+
+
+STDMETHODIMP_(ULONG) CMemBytes::AddRef(void)
+{
+ return ++m_refs;
+}
+
+STDMETHODIMP_(ULONG) CMemBytes::Release(void)
+{
+ if (--m_refs != 0) // Still used by others
+ return m_refs;
+
+ // Matches the allocation in CMemBytes::Create().
+ //
+ if (--m_pData->cRef == 0)
+ {
+ if (m_pData->fDeleteOnRelease)
+ {
+ GlobalFree(m_pData->hGlobal);
+ }
+ GlobalUnlock(m_hMem);
+ GlobalFree(m_hMem);
+ }
+ else
+ GlobalUnlock(m_hMem);
+
+ delete this; // Free storage
+ return 0;
+}
+
+
+STDMETHODIMP CMemBytes::ReadAt(ULARGE_INTEGER ulOffset, void HUGEP* pb,
+ ULONG cb, ULONG * pcbRead)
+{
+ SCODE error = S_OK;
+ ULONG cbRead = cb;
+
+ if (pcbRead)
+ *pcbRead = 0L;
+
+ if (cbRead + ulOffset.LowPart > m_pData->cb)
+ {
+ if (ulOffset.LowPart > m_pData->cb)
+ cbRead = 0;
+ else
+ cbRead = m_pData->cb - ulOffset.LowPart;
+
+ error = E_FAIL;
+ }
+
+ char HUGEP* pGlobal = (char HUGEP*) GlobalLock (m_pData->hGlobal);
+ if (NULL==pGlobal)
+ {
+ return STG_E_READFAULT;
+ }
+
+ memcpy(pb, pGlobal + ulOffset.LowPart, cbRead);
+ GlobalUnlock (m_pData->hGlobal);
+
+ if (pcbRead != NULL)
+ *pcbRead = cbRead;
+
+ return error;
+}
+
+
+STDMETHODIMP CMemBytes::WriteAt(ULARGE_INTEGER ulOffset, void const HUGEP* pb,
+ ULONG cb, ULONG * pcbWritten)
+{
+ SCODE error = S_OK;
+ ULONG cbWritten = cb;
+ char HUGEP* pGlobal;
+
+ if (pcbWritten)
+ *pcbWritten = 0;
+
+ if (cbWritten + ulOffset.LowPart > m_pData->cb)
+ {
+ ULARGE_INTEGER ularge_integer;
+ ULISet32( ularge_integer, ulOffset.LowPart + cbWritten);
+ error = SetSize( ularge_integer );
+ if (error != S_OK)
+ return error;
+ }
+
+ pGlobal = (char HUGEP*) GlobalLock (m_pData->hGlobal);
+ if (NULL==pGlobal)
+ {
+ return STG_E_WRITEFAULT;
+ }
+
+ memcpy(pGlobal + ulOffset.LowPart, pb, cbWritten);
+ GlobalUnlock (m_pData->hGlobal);
+
+ if (pcbWritten != NULL)
+ *pcbWritten = cbWritten;
+
+ return error;
+}
+
+STDMETHODIMP CMemBytes::Flush(void)
+{
+ return S_OK;
+}
+
+
+STDMETHODIMP CMemBytes::SetSize(ULARGE_INTEGER cb)
+{
+ HANDLE hMemNew;
+
+ if (m_pData->cb == cb.LowPart)
+ return S_OK;
+
+ hMemNew = GlobalReAlloc(m_pData->hGlobal,
+ cb.LowPart,
+ GMEM_DDESHARE | GMEM_MOVEABLE);
+
+ if (hMemNew == NULL)
+ return E_OUTOFMEMORY;
+
+ m_pData->hGlobal = hMemNew;
+ m_pData->cb = cb.LowPart;
+
+ return S_OK;
+}
+
+
+STDMETHODIMP CMemBytes::LockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
+{
+ return S_OK;
+}
+
+STDMETHODIMP CMemBytes::UnlockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb,
+ DWORD dwLockType)
+{
+ return S_OK;
+}
+
+
+STDMETHODIMP CMemBytes::Stat(STATSTG *pstatstg, DWORD statflag)
+{
+ pstatstg->pwcsName = NULL;
+ pstatstg->type = 0;
+ pstatstg->cbSize.HighPart = 0;
+ pstatstg->cbSize.LowPart = m_pData->cb;
+ pstatstg->mtime.dwLowDateTime = 0;
+ pstatstg->mtime.dwHighDateTime = 0;
+ pstatstg->ctime.dwLowDateTime = 0;
+ pstatstg->ctime.dwHighDateTime = 0;
+ pstatstg->atime.dwLowDateTime = 0;
+ pstatstg->atime.dwHighDateTime = 0;
+ pstatstg->grfMode = 0;
+ pstatstg->grfLocksSupported = 0;
+ pstatstg->clsid = CLSID_NULL;
+ pstatstg->grfStateBits = 0;
+#ifdef CAIROLE_DOWNLEVEL
+ pstatstg->reserved = 0;
+#else
+ pstatstg->dwStgFmt = 0;
+#endif
+
+ return S_OK;
+}
+
+
+// Create CMemBytes.
+//
+CMemBytes * CMemBytes::Create(HANDLE hMem)
+{
+ CMemBytes * pCMemBytes;
+ struct MEMBYTES * pData;
+
+ pData = (MEMBYTES *) GlobalLock(hMem);
+ if (pData == NULL)
+ return NULL;
+
+ pCMemBytes = new CMemBytes;
+
+ if (pCMemBytes == NULL)
+ {
+ GlobalUnlock(hMem);
+ return NULL;
+ }
+
+ // Initialize CMemBytes
+ //
+ pCMemBytes->m_dwSig = LOCKBYTE_SIG;
+ pCMemBytes->m_hMem = hMem;
+ (pCMemBytes->m_pData = pData)->cRef++;
+ pCMemBytes->m_refs = 1;
+
+ return pCMemBytes;
+}
+
+
+
+STDAPI_(LPLOCKBYTES) CreateMemLockBytes(DWORD cb, LPHANDLE phMem)
+{
+ HANDLE h;
+ LPLOCKBYTES plb = NULL;
+
+ if (phMem)
+ *phMem = NULL;
+
+ h = GlobalAlloc (GMEM_DDESHARE | GMEM_MOVEABLE, cb);
+ if (NULL==h)
+ return NULL;
+
+ if (CreateILockBytesOnHGlobal (h, phMem==NULL, &plb) != S_OK)
+ return NULL;
+
+ if (phMem)
+ GetHGlobalFromILockBytes (plb, phMem);
+
+ return plb;
+}
+
+
+
+
+// Create CMemBytes on top of the specified hMem.
+// Return pointer to the stream if done, NULL if error.
+//
+STDAPI_(LPLOCKBYTES) CloneMemLockbytes(HANDLE hMem)
+{
+ return CMemBytes::Create(hMem); // Create the lockbytes
+}
+
+
+// CMemStm object's IMarshal implementation
+//
+
+STDMETHODIMP CMarshalMemStm::QueryInterface(REFIID iidInterface,
+ void * * ppvObj)
+{
+ SCODE error = S_OK;
+ *ppvObj = NULL;
+
+ // Two interfaces supported: IUnknown, IMarshal
+
+ if (IsEqualIID(iidInterface,IID_IMarshal) ||
+ IsEqualIID(iidInterface,IID_IUnknown))
+ {
+ m_refs++; // A pointer to this object is returned
+ *ppvObj = this;
+ }
+ else
+ { // Not accessible or unsupported interface
+ *ppvObj = NULL;
+ error = E_NOINTERFACE;
+ }
+
+ return error;
+}
+
+
+STDMETHODIMP_(ULONG) CMarshalMemStm::AddRef(void)
+{
+ return ++m_refs;
+}
+
+STDMETHODIMP_(ULONG) CMarshalMemStm::Release(void)
+{
+ if (--m_refs != 0) // Still used by others
+ return m_refs;
+
+ if (m_pMemStm)
+ m_pMemStm->Release();
+
+ delete this; // Free storage
+ return 0;
+}
+
+
+// Returns the clsid of the object that created this CMarshalMemStm.
+//
+STDMETHODIMP CMarshalMemStm::GetUnmarshalClass(REFIID riid, LPVOID pv,
+ DWORD dwDestContext, LPVOID pvDestContext, DWORD mshlflags, CLSID * pCid)
+{
+ *pCid = m_clsid;
+ return S_OK;
+}
+
+
+STDMETHODIMP CMarshalMemStm::GetMarshalSizeMax(REFIID riid, LPVOID pv,
+ DWORD dwDestContext, LPVOID pvDestContext, DWORD mshlflags, DWORD * pSize)
+{
+ *pSize = sizeof(m_pMemStm->m_hMem);
+ return S_OK;
+}
+
+
+STDMETHODIMP CMarshalMemStm::MarshalInterface(IStream * pStm,
+ REFIID riid, void * pv,
+ DWORD dwDestContext, LPVOID pvDestContext, DWORD mshlflags)
+{
+ if (m_pMemStm == NULL)
+ return E_FAIL;
+
+ if ((!IsEqualIID(riid,IID_IStream) &&
+ !IsEqualIID(riid,IID_IUnknown)) || pv != m_pMemStm)
+ return E_INVALIDARG;
+
+ // increase ref count on hglobal (ReleaseMarshalData has -- to match)
+ SCODE error;
+ error = pStm->Write(&m_pMemStm->m_hMem,sizeof(m_pMemStm->m_hMem), NULL);
+ if (error == S_OK)
+ m_pMemStm->m_pData->cRef++;
+
+ return error;
+}
+
+
+STDMETHODIMP CMarshalMemStm::UnmarshalInterface(IStream * pStm,
+ REFIID riid, void * * ppv)
+{
+ SCODE error;
+ HANDLE hMem;
+
+ *ppv = NULL;
+
+ if (!IsEqualIID(riid,IID_IStream) && !IsEqualIID(riid,IID_IUnknown))
+ return E_INVALIDARG;
+
+ error = pStm->Read(&hMem,sizeof(hMem),NULL);
+ if (error != S_OK)
+ return error;
+
+ if (m_pMemStm != NULL)
+ {
+ if (hMem != m_pMemStm->m_hMem)
+ return E_FAIL;
+ }
+ else
+ {
+ m_pMemStm = (CMemStm *) CloneMemStm(hMem);
+ if (m_pMemStm == NULL)
+ return E_OUTOFMEMORY;
+ }
+
+ m_pMemStm->AddRef();
+ *ppv = (LPVOID) m_pMemStm;
+ return S_OK;
+}
+
+
+STDMETHODIMP CMarshalMemStm::ReleaseMarshalData(IStream * pStm)
+{
+ // reduce ref count on hglobal (matches that done in MarshalInterface)
+ SCODE error;
+ MEMSTM * pData;
+ HANDLE hMem;
+
+ error = pStm->Read(&hMem,sizeof(hMem),NULL);
+ if (error != S_OK)
+ return error;
+
+ pData = (MEMSTM *) GlobalLock(hMem);
+ if (pData == NULL)
+ return E_FAIL;
+
+ if (--pData->cRef == 0)
+ {
+ GlobalUnlock(hMem);
+ GlobalFree(hMem);
+ } else
+ // still used by one or more CMemStm in one or more processes
+ GlobalUnlock(hMem);
+
+ return S_OK;
+}
+
+
+STDMETHODIMP CMarshalMemStm::DisconnectObject(DWORD dwReserved)
+{
+ return S_OK;
+}
+
+
+CMarshalMemStm * CMarshalMemStm::Create(CMemStm * pMemStm)
+{
+ CMarshalMemStm * pMMS = new CMarshalMemStm;
+
+ if (pMMS == NULL)
+ return NULL;
+
+ if (pMemStm != NULL)
+ {
+ pMMS->m_pMemStm = pMemStm;
+ pMMS->m_pMemStm->AddRef();
+ }
+
+ pMMS->m_clsid = CLSID_StdMemStm;
+ pMMS->m_refs = 1;
+
+ return pMMS;
+}
+
+
+STDAPI_(IUnknown *) CMemStmUnMarshal(void)
+{
+ return CMarshalMemStm::Create(NULL);
+}
+
+
+
+// CMemBytes object's IMarshal implementation
+//
+
+STDMETHODIMP CMarshalMemBytes::QueryInterface(REFIID iidInterface,
+ void * * ppvObj)
+{
+ SCODE error = S_OK;
+ *ppvObj = NULL;
+
+ // Two interfaces supported: IUnknown, IMarshal
+
+ if (IsEqualIID(iidInterface,IID_IMarshal) ||
+ IsEqualIID(iidInterface,IID_IUnknown))
+ {
+ m_refs++; // A pointer to this object is returned
+ *ppvObj = this;
+ }
+ else
+ { // Not accessible or unsupported interface
+ *ppvObj = NULL;
+ error = E_NOINTERFACE;
+ }
+
+ return error;
+}
+
+
+STDMETHODIMP_(ULONG) CMarshalMemBytes::AddRef(void)
+{
+ return ++m_refs;
+}
+
+STDMETHODIMP_(ULONG) CMarshalMemBytes::Release(void)
+{
+ if (--m_refs != 0) // Still used by others
+ return m_refs;
+
+ if (m_pMemBytes != NULL)
+ m_pMemBytes->Release();
+
+ delete this; // Free storage
+ return 0;
+}
+
+
+// Returns the clsid of the object that created this CMarshalMemBytes.
+//
+STDMETHODIMP CMarshalMemBytes::GetUnmarshalClass(REFIID riid, LPVOID pv,
+ DWORD dwDestContext, LPVOID pvDestContext, DWORD mshlflags, CLSID * pCid)
+{
+ *pCid = m_clsid;
+ return S_OK;
+}
+
+
+STDMETHODIMP CMarshalMemBytes::GetMarshalSizeMax(REFIID riid, LPVOID pv,
+ DWORD dwDestContext, LPVOID pvDestContext, DWORD mshlflags, DWORD * pSize)
+{
+ *pSize = sizeof(m_pMemBytes->m_hMem);
+ return S_OK;
+}
+
+
+STDMETHODIMP CMarshalMemBytes::MarshalInterface(IStream * pStm,
+ REFIID riid, void * pv,
+ DWORD dwDestContext, LPVOID pvDestContext, DWORD mshlflags)
+{
+ if (m_pMemBytes == NULL)
+ return E_FAIL;
+
+ if ((!IsEqualIID(riid,IID_ILockBytes) &&
+ !IsEqualIID(riid,IID_IUnknown)) || pv != m_pMemBytes)
+ return E_INVALIDARG;
+
+ // increase ref count on hglobal (ReleaseMarshalData has -- to match)
+ SCODE error;
+ error = pStm->Write(&m_pMemBytes->m_hMem,sizeof(m_pMemBytes->m_hMem),NULL);
+ if (error == S_OK)
+ m_pMemBytes->m_pData->cRef++;
+
+ return error;
+}
+
+
+STDMETHODIMP CMarshalMemBytes::UnmarshalInterface(IStream * pStm,
+ REFIID riid, void * * ppv)
+{
+ HANDLE hMem;
+
+ *ppv = NULL;
+
+ if (!IsEqualIID(riid,IID_ILockBytes) && !IsEqualIID(riid,IID_IUnknown))
+ return E_INVALIDARG;
+
+ SCODE error = pStm->Read(&hMem,sizeof(hMem),NULL);
+ if (error != S_OK)
+ return error;
+
+ if (m_pMemBytes != NULL)
+ {
+ if (hMem != m_pMemBytes->m_hMem)
+ return E_FAIL;
+ }
+ else
+ {
+ m_pMemBytes = (CMemBytes *) CloneMemLockbytes(hMem);
+ if (m_pMemBytes == NULL)
+ return E_OUTOFMEMORY;
+ }
+
+ m_pMemBytes->AddRef();
+ *ppv = (LPVOID) m_pMemBytes;
+ return S_OK;
+}
+
+
+STDMETHODIMP CMarshalMemBytes::ReleaseMarshalData(IStream * pStm)
+{
+ // reduce ref count on hglobal (matches that done in MarshalInterface)
+ MEMBYTES *pData;
+ HANDLE hMem;
+
+ SCODE error = pStm->Read(&hMem,sizeof(hMem),NULL);
+ if (error != S_OK)
+ return error;
+
+ pData = (MEMBYTES *) GlobalLock(hMem);
+ if (pData == NULL)
+ return E_FAIL;
+
+ if (--pData->cRef == 0)
+ {
+ GlobalUnlock(hMem);
+ GlobalFree(hMem);
+ }
+ else
+ {
+ // still used by one or more CMemStm in one or more processes
+ GlobalUnlock(hMem);
+ }
+
+ return S_OK;
+}
+
+
+STDMETHODIMP CMarshalMemBytes::DisconnectObject(DWORD dwReserved)
+{
+ return S_OK;
+}
+
+
+CMarshalMemBytes *CMarshalMemBytes::Create(CMemBytes *pMemBytes)
+{
+ CMarshalMemBytes *pMMB = new CMarshalMemBytes;
+
+ if (pMMB == NULL)
+ return NULL;
+
+ if (pMemBytes != NULL)
+ {
+ pMMB->m_pMemBytes = pMemBytes;
+ pMMB->m_pMemBytes->AddRef();
+ }
+
+ pMMB->m_clsid = CLSID_StdMemBytes;
+ pMMB->m_refs = 1;
+
+ return pMMB;
+}
+
+
+STDAPI_(IUnknown *) CMemBytesUnMarshal(void)
+{
+ return CMarshalMemBytes::Create(NULL);
+}
diff --git a/private/oleutest/balls/common/memstm.h b/private/oleutest/balls/common/memstm.h
new file mode 100644
index 000000000..02e5db504
--- /dev/null
+++ b/private/oleutest/balls/common/memstm.h
@@ -0,0 +1,226 @@
+#if !defined( _MEMSTM_H_ )
+#define _MEMSTM_H_
+
+class CMarshalMemStm;
+class CMarshalMemBytes;
+
+// function prototypes
+STDAPI_(LPSTREAM) CreateMemStm(DWORD cb, LPHANDLE phMem);
+STDAPI_(LPLOCKBYTES) CreateMemLockBytes(DWORD cb, LPHANDLE phMem);
+
+
+// CMemStm is a stream implementation on top of global shared memory MEMSTM
+//
+// CMemStm
+// +---------+
+// + pvtf + Shared memory
+// +---------+ +--------------+
+// + m_pMem +-->|cb |
+// +---------+ |cRef |
+// |hGlobal |--->+--------------+
+// +--------------+ | Actual Data |
+// CMemStm MEMSTM +--------------+
+//
+struct MEMSTM
+{
+ DWORD cb; // Size of buf[]
+ DWORD cRef; // See below
+ BYTE buf[4]; // The data
+};
+
+// cRef counts all CMemStm pointers to this MEMSTM plus the number of times
+// a hMem handle to MEMSTM had been returned
+
+
+
+class CMemStm : public IStream
+{
+public:
+ CMemStm() { m_hMem = NULL; m_pData = NULL; m_pos = 0; m_refs = 0; }
+ ~CMemStm() {}
+
+ STDMETHOD(QueryInterface) (REFIID iidInterface, void * * ppvObj);
+ STDMETHOD_(ULONG,AddRef) (void);
+ STDMETHOD_(ULONG,Release) (void);
+
+
+ STDMETHOD(Read) (VOID HUGEP* pv, ULONG cb, ULONG *pcbRead);
+ STDMETHOD(Write) (VOID const HUGEP* pv, ULONG cb, ULONG *pcbWritten);
+ STDMETHOD(Seek) (LARGE_INTEGER dlibMove,
+ DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition);
+ STDMETHOD(SetSize) (ULARGE_INTEGER cb);
+ STDMETHOD(CopyTo) (IStream *pstm, ULARGE_INTEGER cb,
+ ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *pcbWritten);
+ STDMETHOD(Commit) (DWORD grfCommitFlags);
+ STDMETHOD(Revert) (void);
+ STDMETHOD(LockRegion) (ULARGE_INTEGER libOffset, ULARGE_INTEGER cb,
+ DWORD dwLockType);
+ STDMETHOD(UnlockRegion) (ULARGE_INTEGER libOffset, ULARGE_INTEGER cb,
+ DWORD dwLockType);
+ STDMETHOD(Stat) (STATSTG *pstatstg, DWORD statflag);
+ STDMETHOD(Clone)(IStream **ppstm);
+
+ static CMemStm *Create(HANDLE hMem);
+
+private:
+ ULONG m_refs; // Number of references to this CmemStm
+ ULONG m_pos; // Seek pointer for Read/Write
+ HANDLE m_hMem; // Memory Handle passed on creation
+ MEMSTM * m_pData; // Pointer to that memroy
+
+ friend class CMarshalMemStm;
+};
+
+
+
+
+// CMemBytes is an ILockBytes implementation on top of global shared
+// memory MEMBYTES
+//
+// CMemBytes
+// +---------+
+// + pvtf + Shared memory
+// +---------+ +--------------+
+// + m_pData +-->| cb |
+// +---------+ | cRef |
+// | hGlobal |--->+-------------+
+// +--------------+ | Actual data |
+// CMemBytes MEMBYTES +-------------+
+//
+struct MEMBYTES // Bookeeping info in shared memory
+{
+ DWORD cRef; // See below
+ DWORD cb; // Size of hGlobal
+ HANDLE hGlobal; // The data
+ BOOL fDeleteOnRelease;
+};
+
+#define LOCKBYTE_SIG (0x0046574A)
+
+// cRef counts all CMemBytes pointers to this MEMBYTES.
+// It and fDeleteOnRelease control the GlobalFreeing of the hGlobal.
+
+
+
+class CMemBytes : public ILockBytes
+{
+public:
+ CMemBytes() {m_hMem = NULL; m_pData = NULL; m_refs = 0;}
+ ~CMemBytes() {}
+
+ STDMETHOD(QueryInterface) (REFIID iidInterface, void **ppvObj);
+ STDMETHOD_(ULONG,AddRef) (void);
+ STDMETHOD_(ULONG,Release) (void);
+
+
+ STDMETHOD(ReadAt) (ULARGE_INTEGER ulOffset, VOID HUGEP *pv, ULONG cb,
+ ULONG *pcbRead);
+ STDMETHOD(WriteAt) (ULARGE_INTEGER ulOffset, VOID const HUGEP *pv,
+ ULONG cb, ULONG *pcbWritten);
+ STDMETHOD(Flush) (void);
+ STDMETHOD(SetSize) (ULARGE_INTEGER cb);
+ STDMETHOD(LockRegion) (ULARGE_INTEGER libOffset, ULARGE_INTEGER cb,
+ DWORD dwLockType);
+ STDMETHOD(UnlockRegion) (ULARGE_INTEGER libOffset, ULARGE_INTEGER cb,
+ DWORD dwLockType);
+ STDMETHOD(Stat) (STATSTG *pstatstg, DWORD statflag);
+
+ static CMemBytes *Create(HANDLE hMem);
+
+private:
+ DWORD m_dwSig; // Signature indicating this is our
+ // implementation of ILockBytes: LOCKBYTE_SIG
+ ULONG m_refs; // Normal reference count
+ HANDLE m_hMem; // Handle for bookeeping info (MEMBYTES)
+ MEMBYTES * m_pData; // Pointer to that memroy
+
+// friend GetHGlobalFromILockBytes(LPLOCKBYTES, HGLOBAL *);
+ friend class CMarshalMemBytes;
+};
+
+
+// CMarshalMemStm can Marshal, Unmarshal CMemStm. It is impletented as
+// a seperate object accessible from CMemStm, CMemBytes: QueryIntreface of
+// IMarshal on CMemStm's IStream will return an IMarshal pointer to
+// CMarshalMemStm, but QueryInterface of IStream on that IMarshal will
+// fail.
+//
+// Also QueryInterface of IUnknown on IMarshal will not return the same value
+// As QueryInterface of IUnkown on the original IStream.
+//
+class CMarshalMemStm : public IMarshal
+{
+public:
+ CMarshalMemStm() {m_pMemStm = NULL; m_refs = 0; }
+ ~CMarshalMemStm() {}
+
+ STDMETHOD(QueryInterface) (REFIID riid, LPVOID * ppvObj);
+ STDMETHOD_(ULONG,AddRef) (void);
+ STDMETHOD_(ULONG,Release) (void);
+
+ STDMETHOD(GetUnmarshalClass)(THIS_ REFIID riid, LPVOID pv,
+ DWORD dwDestContext, LPVOID pvDestContext,
+ DWORD mshlflags, LPCLSID pCid);
+ STDMETHOD(GetMarshalSizeMax)(THIS_ REFIID riid, LPVOID pv,
+ DWORD dwDestContext, LPVOID pvDestContext,
+ DWORD mshlflags, LPDWORD pSize);
+ STDMETHOD(MarshalInterface)(THIS_ IStream * pStm, REFIID riid,
+ LPVOID pv, DWORD dwDestContext, LPVOID pvDestContext,
+ DWORD mshlflags);
+ STDMETHOD(UnmarshalInterface)(THIS_ IStream * pStm, REFIID riid,
+ LPVOID * ppv);
+ STDMETHOD(ReleaseMarshalData)(THIS_ IStream * pStm);
+ STDMETHOD(DisconnectObject)(THIS_ DWORD dwReserved);
+
+ static CMarshalMemStm * Create(CMemStm *pMemStm);
+
+private:
+ ULONG m_refs; // Number of references to this CmemStm
+ CMemStm * m_pMemStm; // Pointer to object [Un]Marshalled
+ CLSID m_clsid; // Class of object pointed by pUnk
+};
+
+
+// CMarshalMemBytes can Marshal, Unmarshal CMemBytes. It is impletented as
+// a seperate object accessible from CMemBytes, CMemBytes: QueryIntreface of
+// IMarshal on CMemBytes's ILocBytes will return an IMarshal pointer to
+// CMarshalMemBytes, but QueryInterface of ILockBytes on that IMarshal will
+// fail.
+//
+// Also QueryInterface of IUnknown on IMarshal will not return the same value
+// as QueryInterface of IUnknown on the original ILockBytes.
+//
+class CMarshalMemBytes : public IMarshal
+{
+public:
+ CMarshalMemBytes() {m_pMemBytes = NULL; m_refs = 0;}
+ ~CMarshalMemBytes() {}
+
+ STDMETHOD(QueryInterface) (REFIID riid, LPVOID * ppvObj);
+ STDMETHOD_(ULONG,AddRef) (void);
+ STDMETHOD_(ULONG,Release) (void);
+
+ STDMETHOD(GetUnmarshalClass)(THIS_ REFIID riid, LPVOID pv,
+ DWORD dwDestContext, LPVOID pvDestContext,
+ DWORD mshlflags, LPCLSID pCid);
+ STDMETHOD(GetMarshalSizeMax)(THIS_ REFIID riid, LPVOID pv,
+ DWORD dwDestContext, LPVOID pvDestContext,
+ DWORD mshlflags, LPDWORD pSize);
+ STDMETHOD(MarshalInterface)(THIS_ IStream * pStm, REFIID riid,
+ LPVOID pv, DWORD dwDestContext, LPVOID pvDestContext,
+ DWORD mshlflags);
+ STDMETHOD(UnmarshalInterface)(THIS_ IStream * pStm, REFIID riid,
+ LPVOID * ppv);
+ STDMETHOD(ReleaseMarshalData)(THIS_ IStream * pStm);
+ STDMETHOD(DisconnectObject)(THIS_ DWORD dwReserved);
+
+ static CMarshalMemBytes* Create(CMemBytes *pMemBytes);
+
+private:
+ ULONG m_refs; // Number of references to this CMemBytes
+ CMemBytes *m_pMemBytes; // Pointer to object [Un]Marshalled
+ CLSID m_clsid; // Class of object pointed by pUnk
+};
+
+
+#endif // _MEMSTM_H_
diff --git a/private/oleutest/balls/common/mixedcf.cxx b/private/oleutest/balls/common/mixedcf.cxx
new file mode 100644
index 000000000..23c89b30e
--- /dev/null
+++ b/private/oleutest/balls/common/mixedcf.cxx
@@ -0,0 +1,152 @@
+//+-------------------------------------------------------------------
+//
+// File: mixedcf.cxx
+//
+// Contents: class factory object implementation for implementing
+// multiple classes in the same factory code.
+//
+// Classes: CMixedClassFactory
+//
+// History: 23-Nov-92 Rickhi Created
+//
+//--------------------------------------------------------------------
+#include <pch.cxx>
+#pragma hdrstop
+#include <mixedcf.hxx> // class definiton
+#include <cqi.hxx> // CQI
+#include <cballs.hxx> // CBallCtrlUnk
+#include <ccubes.hxx> // CCubes
+#include <cloop.hxx> // CLoop
+
+#if 0 // These are defined in the header files, but left here for reference.
+const GUID CLSID_QI =
+ {0x00000140,0x0000,0x0008,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}};
+
+const GUID CLSID_QIHANDLER =
+ {0x00000141,0x0000,0x0008,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}};
+
+const GUID CLSID_Balls =
+ {0x0000013a,0x0001,0x0008,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}};
+
+const GUID CLSID_Loop =
+ {0x0000013c,0x0001,0x0008,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}};
+#endif
+
+const GUID CLSID_Cubes =
+ {0x0000013b,0x0001,0x0008,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}};
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CMixedClassFactory::CMixedClassFactory, public
+//
+// History: 23-Nov-92 Rickhi Created
+//
+//--------------------------------------------------------------------
+CMixedClassFactory::CMixedClassFactory(REFCLSID rclsid) : _clsid(rclsid)
+{
+ ENLIST_TRACKING(CMixedClassFactory);
+}
+
+//+-------------------------------------------------------------------
+//
+// Member: CMixedClassFactory::~CMixedClassFactory, public
+//
+// History: 23-Nov-92 Rickhi Created
+//
+//--------------------------------------------------------------------
+CMixedClassFactory::~CMixedClassFactory(void)
+{
+ // automatic actions do the rest of the work
+}
+
+//+-------------------------------------------------------------------
+//
+// Member: CMixedClassFactory::QueryInterface, public
+//
+// Algorithm: if the interface is not one implemented by us,
+// pass the request to the proxy manager
+//
+// History: 23-Nov-92 Rickhi Created
+//
+//--------------------------------------------------------------------
+STDMETHODIMP CMixedClassFactory::QueryInterface(REFIID riid, void **ppUnk)
+{
+ if (IsEqualIID(riid, IID_IUnknown) ||
+ IsEqualIID(riid, IID_IClassFactory))
+ {
+ *ppUnk = (void *)(IClassFactory *) this;
+ AddRef();
+ return S_OK;
+ }
+
+ *ppUnk = NULL;
+ return E_NOINTERFACE;
+}
+
+//+-------------------------------------------------------------------
+//
+// Member: CMixedClassFactory::CreateInstance, public
+//
+// Synopsis: create a new object with the same class
+//
+// History: 23-Nov-92 Rickhi Created
+//
+//--------------------------------------------------------------------
+STDMETHODIMP CMixedClassFactory::CreateInstance(IUnknown *punkOuter,
+ REFIID riid,
+ void **ppunkObject)
+{
+ HRESULT hr = E_OUTOFMEMORY;
+
+ *ppunkObject = NULL; // in case of failure
+
+ // create a new object.
+ IUnknown *pUnk = NULL;
+
+ if (IsEqualCLSID(_clsid, CLSID_QI) ||
+ IsEqualCLSID(_clsid, CLSID_QIHANDLER))
+ {
+ pUnk = (IUnknown *) new CQI(_clsid);
+ }
+ else if (IsEqualCLSID(_clsid, CLSID_Balls))
+ {
+ pUnk = (IUnknown *) new CBallCtrlUnk(NULL);
+ }
+ else if (IsEqualCLSID(_clsid, CLSID_Cubes))
+ {
+ pUnk = (IUnknown *) new CCube();
+ }
+ else if (IsEqualCLSID(_clsid, CLSID_Loop))
+ {
+ pUnk = (IUnknown *) new CLoop();
+ }
+
+ if (pUnk)
+ {
+ // get the interface the caller wants to use
+ hr = pUnk->QueryInterface(riid, ppunkObject);
+ pUnk->Release();
+ }
+
+ return hr;
+}
+
+//+-------------------------------------------------------------------
+//
+// Member: CMixedClassFactory::LockServer, public
+//
+// Synopsis: create a new object with the same class
+//
+// History: 23-Nov-92 Rickhi Created
+//
+//--------------------------------------------------------------------
+STDMETHODIMP CMixedClassFactory::LockServer(BOOL fLock)
+{
+ if (fLock)
+ GlobalRefs(TRUE);
+ else
+ GlobalRefs(FALSE);
+
+ return S_OK;
+}
diff --git a/private/oleutest/balls/common/mixedcf.hxx b/private/oleutest/balls/common/mixedcf.hxx
new file mode 100644
index 000000000..bdbb036a7
--- /dev/null
+++ b/private/oleutest/balls/common/mixedcf.hxx
@@ -0,0 +1,53 @@
+//+-------------------------------------------------------------------
+//
+// File: mixedcf.hxx
+//
+// Contents: class factory object implementation for implementing
+// multiple classes in the same factory code.
+//
+// Classes: CMixedClassFactory
+//
+// History: 23-Nov-92 Rickhi Created
+//
+//--------------------------------------------------------------------
+#ifndef __CMIXEDCLASSFACTORY__
+#define __CMIXEDCLASSFACTORY__
+
+#include <win4p.hxx>
+#include <otrack.hxx> // object tracking
+
+//+-------------------------------------------------------------------
+//
+// Class: CMixedClassFactory
+//
+// Purpose: test class factory object implementation
+//
+// History: 23-Nov-92 Rickhi Created
+//
+//--------------------------------------------------------------------
+class CMixedClassFactory : INHERIT_TRACKING,
+ public IClassFactory
+{
+public:
+ // Constructor & Destructor
+ CMixedClassFactory(REFCLSID rclsid);
+
+ // IUnknown methods
+ STDMETHOD(QueryInterface)(REFIID riid, void **ppUnk);
+ DECLARE_STD_REFCOUNTING;
+
+
+ // IClassFactory methods
+ STDMETHOD(CreateInstance)(IUnknown *punkOuter,
+ REFIID riid,
+ void **ppunkObject);
+
+ STDMETHOD(LockServer)(BOOL fLock);
+
+private:
+ ~CMixedClassFactory(void);
+
+ CLSID _clsid;
+};
+
+#endif // __CMIXEDCLASSFACTORY__
diff --git a/private/oleutest/balls/common/oleinit.hxx b/private/oleutest/balls/common/oleinit.hxx
new file mode 100644
index 000000000..6a77c8200
--- /dev/null
+++ b/private/oleutest/balls/common/oleinit.hxx
@@ -0,0 +1,54 @@
+#ifndef __OLEINIT_HXX__
+#define __OLEINIT_HXX__
+
+
+#include <stdio.h>
+
+class COleInit
+{
+public:
+ COleInit(HRESULT *phr);
+
+ ~COleInit(void);
+private:
+
+ // No private data
+};
+
+inline COleInit::COleInit(HRESULT *phr)
+{
+ // Initialize the OLE libraries
+#ifdef THREADING_SUPPORT
+ // Look up the thread mode from the win.ini file.
+ DWORD dwThreadMode;
+ TCHAR buffer[80];
+
+ int len = GetProfileString( TEXT("OleSrv"),
+ TEXT("ThreadMode"),
+ TEXT("MultiThreaded"),
+ buffer, sizeof(buffer) );
+
+ if (lstrcmp(buffer, TEXT("SingleThreaded")) == 0)
+ dwThreadMode = COINIT_SINGLETHREADED;
+ else
+ dwThreadMode = COINIT_MULTITHREADED;
+
+ // Initialize the OLE libraries
+ *phr = OleInitializeEx(NULL, dwThreadMode);
+#else
+ *phr = OleInitialize(NULL);
+#endif
+
+ if (FAILED(*phr))
+ {
+ printf ("Failed OleInitialize\n");
+ }
+}
+
+inline COleInit::~COleInit(void)
+{
+ // Do the clean up
+ OleUninitialize();
+}
+
+#endif // __OLEINIT_HXX__
diff --git a/private/oleutest/balls/common/oleobj.cxx b/private/oleutest/balls/common/oleobj.cxx
new file mode 100644
index 000000000..3326e39de
--- /dev/null
+++ b/private/oleutest/balls/common/oleobj.cxx
@@ -0,0 +1,631 @@
+//+-------------------------------------------------------------------
+// File: ioleobj.cxx
+//
+// Contents: IOleObject methods of COleObject class.
+//
+// Classes: COleObject - IOleObject implementation
+//
+// History: 7-Dec-92 DeanE Created
+//---------------------------------------------------------------------
+#pragma optimize("",off)
+
+#include <pch.cxx>
+#pragma hdrstop
+#include <embed.hxx>
+#include <oleobj.hxx>
+
+
+//+-------------------------------------------------------------------
+// Member: COleObject::COleObject()
+//
+// Synopsis: The constructor for COleObject.
+//
+// Arguments: None
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+COleObject::COleObject(CTestEmbed *pteObject)
+{
+ _cRef = 1;
+ _pOAHolder = NULL;
+ _pocs = NULL;
+ _pteObject = pteObject;
+ _pmkContainer = NULL;
+}
+
+
+//+-------------------------------------------------------------------
+// Member: COleObject::~COleObject()
+//
+// Synopsis: The destructor for COleObject.
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+COleObject::~COleObject()
+{
+ // _cRef should be 1
+ if (1 != _cRef)
+ {
+ // BUGBUG - Log error - someone hasn't released
+ }
+
+ if (_pocs != NULL)
+ {
+ _pocs->Release();
+ }
+
+ if (_pmkContainer != NULL)
+ {
+ _pmkContainer->Release();
+ }
+
+}
+
+
+//+-------------------------------------------------------------------
+// Method: COleObject::QueryInterface
+//
+// Synopsis: Forward this to the object we're associated with
+//
+// Parameters: [iid] - Interface ID to return.
+// [ppv] - Pointer to pointer to object.
+//
+// Returns: S_OK if iid is supported, or E_NOINTERFACE if not.
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP COleObject::QueryInterface(REFIID iid, void FAR * FAR *ppv)
+{
+ return(_pteObject->QueryInterface(iid, ppv));
+}
+
+
+//+-------------------------------------------------------------------
+// Method: COleObject::AddRef
+//
+// Synopsis: Forward this to the object we're associated with
+//
+// Returns: New reference count.
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP_(ULONG) COleObject::AddRef(void)
+{
+ ++_cRef;
+ return(_pteObject->AddRef());
+}
+
+
+//+-------------------------------------------------------------------
+// Method: COleObject::Release
+//
+// Synopsis: Forward this to the object we're associated with
+//
+// Returns: New reference count.
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP_(ULONG) COleObject::Release(void)
+{
+ --_cRef;
+ return(_pteObject->Release());
+}
+
+
+//+-------------------------------------------------------------------
+// Method: COleObject::SetClientSite
+//
+// Synopsis: Save the IOleClientSite pointer passed - it's this
+// object's client site object.
+//
+// Parameters: [pClientSite] - Pointer to the new client site object.
+//
+// Returns: S_OK
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP COleObject::SetClientSite(LPOLECLIENTSITE pClientSite)
+{
+ if (_pocs != NULL)
+ {
+ _pocs->Release();
+ }
+
+ _pocs = pClientSite;
+
+ if (pClientSite)
+ {
+ _pocs->AddRef();
+ }
+
+ return(S_OK);
+}
+
+
+//+-------------------------------------------------------------------
+// Method: COleObject::GetClientSite
+//
+// Synopsis: Return this objects current client site - NULL indicates
+// it hasn't been set yet.
+//
+// Parameters: [ppClientSite] - Save current client site pointer here.
+//
+// Returns: S_OK
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP COleObject::GetClientSite(LPOLECLIENTSITE FAR *ppClientSite)
+{
+ *ppClientSite = _pocs;
+ _pocs->AddRef();
+ return(S_OK);
+}
+
+
+//+-------------------------------------------------------------------
+// Method: COleObject::SetHostNames
+//
+// Synopsis: See spec 2.00.09 p99. Returns names the caller can use
+// to display our object name (in window titles and such).
+//
+// Parameters: [szContainerApp] - Name of container application.
+// [szContainerObj] - Name of this object.
+//
+// Returns: S_OK
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP COleObject::SetHostNames(
+ LPCOLESTR szContainerApp,
+ LPCOLESTR szContainerObj)
+{
+ szContainerApp = OLESTR("Test Server");
+ szContainerObj = OLESTR("Test Server:Test Object");
+ return(S_OK);
+}
+
+
+//+-------------------------------------------------------------------
+// Method: COleObject::Close
+//
+// Synopsis: See spec 2.00.09 p104. Short story is: if fMerelyHide,
+// turn off the UI of this object, else return to the
+// "loaded" state, which for us means to shut down (since we
+// don't do any caching).
+//
+// Parameters: [dwSaveOption] - ???
+//
+// Returns: S_OK
+//
+// History: 7-Dec-92 DeanE Created
+//
+// Notes: BUGBUG - what if we have multiple instances? Do we
+// return the server app to the loaded state or do we
+// return this object to the loaded state?
+//--------------------------------------------------------------------
+STDMETHODIMP COleObject::Close(DWORD dwSaveOption)
+{
+ // BUGBUG - NYI
+ return(S_OK);
+}
+
+
+//+-------------------------------------------------------------------
+// Method: COleObject::SetMoniker
+//
+// Synopsis: See spec 2.00.09 p99. The moniker for this object
+// (or it's container) has been changed to that passed
+// in. Take appropriate actions (de-register old object
+// and register new, inform contained objects, etc).
+//
+// Parameters: [dwWhichMoniker] - Moniker type being sent.
+// [pmk] - The new moniker.
+//
+// Returns: S_OK
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP COleObject::SetMoniker(DWORD dwWhichMoniker, LPMONIKER pmk)
+{
+ if (_pmkContainer)
+ {
+ _pmkContainer->Release();
+
+ }
+
+ _pmkContainer = pmk;
+
+ pmk->AddRef();
+
+ // Set moniker in container
+ IOleObject *pobj;
+
+ HRESULT hresult = _pocs->QueryInterface(IID_IOleObject, (void **) &pobj);
+
+ pobj->SetMoniker(dwWhichMoniker, pmk);
+
+ pobj->Release();
+
+ return S_OK;
+}
+
+
+//+-------------------------------------------------------------------
+// Method: COleObject::GetMoniker
+//
+// Synopsis: See spec 2.00.09 p100. Return either this objects
+// container moniker, this objects relative moniker, or
+// this objects full moniker.
+//
+// Parameters: [dwAssign] - Condition to get moniker.
+// [dwWhichMoniker] - Kind of moniker being requested.
+// [ppmk] - Return moniker here.
+//
+// Returns: S_OK
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP COleObject::GetMoniker(
+ DWORD dwAssign,
+ DWORD dwWhichMoniker,
+ LPMONIKER FAR *ppmk)
+{
+ *ppmk = _pmkContainer;
+ _pmkContainer->AddRef();
+ return S_OK;
+}
+
+
+//+-------------------------------------------------------------------
+// Method: COleObject::InitFromData
+//
+// Synopsis: See spec 2.00.09 p100. Initialize this object from
+// the format passed in.
+//
+// Parameters: [pDataObject] - IDataObject providing data.
+// [fCreation] - TRUE if this is the initial creation.
+// [dwReserved] - Ignored.
+//
+// Returns: S_OK if we attempt to initialize, S_FALSE if we don't
+// want to.
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP COleObject::InitFromData(
+ LPDATAOBJECT pDataObject,
+ BOOL fCreation,
+ DWORD dwReserved)
+{
+ // BUGBUG - NYI
+ return(S_FALSE);
+}
+
+
+//+-------------------------------------------------------------------
+// Method: COleObject::GetClipboardData
+//
+// Synopsis: See spec 2.00.09 p101. Return clipboard object that would
+// be created if Edit/Copy were done to this item.
+//
+// Parameters: [dwReserved] - Ignored.
+// [ppDataObject] - IDataObject return locale.
+//
+// Returns: S_OK or ???
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP COleObject::GetClipboardData(
+ DWORD dwReserved,
+ LPDATAOBJECT FAR *ppDataObject)
+{
+ // BUGBUG - NYI
+ *ppDataObject = NULL;
+ return(S_OK);
+}
+
+
+//+-------------------------------------------------------------------
+// Method: COleObject::DoVerb
+//
+// Synopsis: See spec 2.00.09 p101. Execute the verb passed in.
+//
+// Parameters: [iVerb] - Verb being requested.
+// [pMsg] - Message that triggered the request.
+// [pActiveSite] - IOleClientSite for this object.
+// [lReserved] - Ignored.
+//
+// Returns: S_OK, or other ones specified but not defined yet...
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP COleObject::DoVerb(
+ LONG iVerb,
+ LPMSG pMsg,
+ LPOLECLIENTSITE pActiveSite,
+ LONG lReserved,
+ HWND hwndParent,
+ LPCRECT lprcPosRect)
+{
+ // HWND hwndObj;
+
+ if (OLEIVERB_SHOW == iVerb)
+ {
+ // BUGBUG - NYI
+ // Display the object (we're not in-place yet)
+ // PostMessage(g_hwndMain, WM_REPORT, MB_SHOWVERB, 0);
+ // PostMessage(0xFFFF, WM_REPORT, MB_SHOWVERB, 0);
+ // MessageBox(g_hwndMain, L"Received OLEIVERB_SHOW", L"OLE Server", MB_ICONINFORMATION | MB_OK);
+
+ // Get hwndObj
+ //_pteObject->GetWindow(&hwndObj);
+ //MessageBox(hwndObj, L"Received OLEIVERB_SHOW", L"OLE Server", MB_ICONINFORMATION | MB_OK);
+ }
+ else
+ {
+ // Return alternate error code?
+ }
+
+ return(S_OK);
+}
+
+
+//+-------------------------------------------------------------------
+// Method: COleObject::EnumVerbs
+//
+// Synopsis: See spec 2.00.09 p103. Enumerate all the verbs available
+// on this object in increasing numerical order.
+//
+// Parameters: [ppenmOleVerb] - Enumeration object return locale.
+//
+// Returns: S_OK or ???
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP COleObject::EnumVerbs(IEnumOLEVERB FAR* FAR *ppenmOleVerb)
+{
+ // BUGBUG - NYI
+ *ppenmOleVerb = NULL;
+ return(S_OK);
+}
+
+
+//+-------------------------------------------------------------------
+// Method: COleObject::Update
+//
+// Synopsis: See spec 2.00.09 p105. Ensure any data or view caches
+// maintained inside the object are up to date.
+//
+// Parameters: None
+//
+// Returns: S_OK
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP COleObject::Update()
+{
+ // We don't use any caches, so we don't have to do anything
+ return(S_OK);
+}
+
+
+//+-------------------------------------------------------------------
+// Method: COleObject::IsUpToDate
+//
+// Synopsis: See spec 2.00.09 p105. Check to see if this object is
+// up to date - including embedded children, etc.
+//
+// Parameters: None
+//
+// Returns: S_OK, S_FALSE, or ???
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP COleObject::IsUpToDate()
+{
+ // We should always be up to date as we don't have any caches
+ // or children or links
+ return(S_OK);
+}
+
+
+//+-------------------------------------------------------------------
+// Method: COleObject::GetUserClassID
+//
+// Synopsis: I have little idea what this does. It's not in the
+// spec 2.00.09.
+//
+// Parameters: [dwFormOfType] -
+// [pszUserType] -
+//
+// Returns: S_OK?
+//
+// History: 16-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP COleObject::GetUserClassID(
+ CLSID FAR *pClsid)
+{
+ // BUGBUG - NYI
+ return(E_FAIL);
+}
+
+
+//+-------------------------------------------------------------------
+// Method: COleObject::GetUserType
+//
+// Synopsis: I have little idea what this does. It's not in the
+// spec 2.00.09.
+//
+// Parameters: [dwFormOfType] -
+// [pszUserType] -
+//
+// Returns: S_OK?
+//
+// History: 16-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP COleObject::GetUserType(
+ DWORD dwFormOfType,
+ LPOLESTR FAR *pszUserType)
+{
+ // BUGBUG - NYI
+ return(E_FAIL);
+}
+
+
+//+-------------------------------------------------------------------
+// Method: COleObject::SetExtent
+//
+// Synopsis: See spec 2.00.09 p106. Set the rectangular extent of
+// this object. Container will call us with the size
+// it will give us; we must fit accordingly.
+//
+// Parameters: [dwDrawAspect] - DVASPECT specified for this object.
+// [lpsizel] - Extent structure.
+//
+// Returns: S_OK
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP COleObject::SetExtent(DWORD dwDrawAspect, LPSIZEL lpsizel)
+{
+ // BUGBUG - NYI
+ return(S_OK);
+}
+
+
+//+-------------------------------------------------------------------
+// Method: COleObject::GetExtent
+//
+// Synopsis: See spec 2.00.09 p106. Size of the object given in the
+// the last SetExtent call is returned. If SetExtent has
+// not been called, the natural size of the object is
+// returned.
+//
+// Parameters: [dwDrawAspect] - DVASPECT specified for this object.
+// [lpsizel] - Extent structure to set.
+//
+// Returns: S_OK
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP COleObject::GetExtent(DWORD dwDrawAspect, LPSIZEL lpsizel)
+{
+ // BUGBUG - NYI
+ return(S_OK);
+}
+
+
+//+-------------------------------------------------------------------
+// Method: COleObject::Advise
+//
+// Synopsis: See spec 2.00.09 p121. Set up an advisory connection
+// between this object and an advisory sink; when certain
+// events happen (birthdays?) this sink should be informed
+// by this object. Use the OleAdviseHolder object as a
+// helper (see p122).
+//
+// Parameters: [pAdvSink] - Sink that should be informed of changes.
+// [pdwConnection] - Pass advisory token returned so our
+// caller can shut down the link.
+//
+// Returns: S_OK
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP COleObject::Advise(
+ IAdviseSink FAR *pAdvSink,
+ DWORD FAR *pdwConnection)
+{
+// if (NULL == _pOAHolder)
+// {
+// if (S_OK != CreateOleAdviseHolder(&_pOAHolder))
+// {
+// return(E_OUTOFMEMORY);
+// }
+// }
+//
+// return(_pOAHolder->Advise(pAdvSink, pdwConnection));
+ *pdwConnection = 0;
+ return S_OK;
+}
+
+
+//+-------------------------------------------------------------------
+// Method: COleObject::Unadvise
+//
+// Synopsis: See spec 2.00.09 p121. Tear down an advisory connection
+// set up previously.
+//
+// Parameters: [dwConnection] - Connection established earlier.
+//
+// Returns: S_OK or ???
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP COleObject::Unadvise(DWORD dwConnection)
+{
+ if (NULL == _pOAHolder)
+ {
+ // No one is registered - see ellipswt.cpp for this
+ return(E_INVALIDARG);
+ }
+
+ return(_pOAHolder->Unadvise(dwConnection));
+}
+
+
+//+-------------------------------------------------------------------
+// Method: COleObject::EnumAdvise
+//
+// Synopsis: See spec 2.00.09 p122. Enumerate the advisory connections
+// currently attached to this object.
+//
+// Parameters: [ppenmAdvise] - Enumeration object to return.
+//
+// Returns: S_OK
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP COleObject::EnumAdvise(LPENUMSTATDATA FAR *ppenmAdvise)
+{
+ if (NULL == _pOAHolder)
+ {
+ return(E_FAIL);
+ }
+ return(_pOAHolder->EnumAdvise(ppenmAdvise));
+}
+
+
+//+-------------------------------------------------------------------
+// Method: COleObject::GetMiscStatus
+//
+// Synopsis: I have little idea what this does. It's not in the
+// spec 2.00.09.
+//
+// Returns: S_OK?
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP COleObject::GetMiscStatus(
+ DWORD dwAspect,
+ DWORD FAR *pdwStatus)
+{
+ // BUGBUG - NYI
+ return(E_FAIL);
+}
+
+
+//+-------------------------------------------------------------------
+// Method: COleObject::SetColorScheme
+//
+// Synopsis: I have little idea what this does. It's not in the
+// spec 2.00.09.
+//
+// Returns: S_OK?
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP COleObject::SetColorScheme(LPLOGPALETTE lpLogpal)
+{
+ // BUGBUG - NYI
+ return(S_OK);
+}
diff --git a/private/oleutest/balls/common/oleobj.hxx b/private/oleutest/balls/common/oleobj.hxx
new file mode 100644
index 000000000..fad27688f
--- /dev/null
+++ b/private/oleutest/balls/common/oleobj.hxx
@@ -0,0 +1,105 @@
+//+-------------------------------------------------------------------
+//
+// File: oleobj.hxx
+//
+// Contents: COleObject declarations
+//
+// History: 24-Nov-92 DeanE Created
+//
+//---------------------------------------------------------------------
+
+#ifndef __OLEOBJ_HXX__
+#define __OLEOBJ_HXX__
+
+
+//+-------------------------------------------------------------------
+// Class: COleObject
+//
+// Synopsis: COleObject implements the IOleObject interface for OLE
+// objects within the server. There will be one instantiation
+// per OLE object.
+//
+// Methods: QueryInterface IUnknown
+// AddRef IUnknown
+// Release IUnknown
+// SetClientSite IOleObject
+// GetClientSite IOleObject
+// SetHostNames IOleObject
+// Close IOleObject
+// SetMoniker IOleObject
+// GetMoniker IOleObject
+// InitFromData IOleObject
+// GetClipboardData IOleObject
+// DoVerb IOleObject
+// EnumVerbs IOleObject
+// Update IOleObject
+// IsUpToDate IOleObject
+// GetUserType IOleObject
+// SetExtent IOleObject
+// GetExtent IOleObject
+// Advise IOleObject
+// Unadvise IOleObject
+// EnumAdvise IOleObject
+// GetMiscStatus IOleObject
+// SetColorScheme IOleObject
+//
+// History: 17-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+class FAR COleObject : public IOleObject
+{
+public:
+// Constructor/Destructor
+ COleObject(CTestEmbed *pteObject);
+ ~COleObject();
+
+// IUnknown
+ STDMETHODIMP QueryInterface(REFIID iid, void FAR * FAR *ppv);
+ STDMETHODIMP_(ULONG) AddRef (void);
+ STDMETHODIMP_(ULONG) Release (void);
+
+// IOleObject
+ STDMETHODIMP SetClientSite (LPOLECLIENTSITE pClientSite);
+ STDMETHODIMP GetClientSite (LPOLECLIENTSITE FAR *ppClientSite);
+ STDMETHODIMP SetHostNames (LPCOLESTR szContainerApp, LPCOLESTR szContainerObj);
+ STDMETHODIMP Close (DWORD dwSaveOption);
+ STDMETHODIMP SetMoniker (DWORD dwWhichMoniker, LPMONIKER pmk);
+ STDMETHODIMP GetMoniker (DWORD dwAssign,
+ DWORD dwWhichMoniker,
+ LPMONIKER FAR *ppmk);
+ STDMETHODIMP InitFromData (LPDATAOBJECT pDataObject,
+ BOOL fCreation,
+ DWORD dwReserved);
+ STDMETHODIMP GetClipboardData(
+ DWORD dwReserved,
+ LPDATAOBJECT FAR *ppDataObject);
+ STDMETHODIMP DoVerb (LONG iVerb,
+ LPMSG pMsg,
+ LPOLECLIENTSITE pActiveSite,
+ LONG lReserved,
+ HWND hwndParent,
+ LPCRECT lprcPosRect);
+ STDMETHODIMP EnumVerbs (IEnumOLEVERB FAR* FAR* ppenmOleVerb);
+ STDMETHODIMP Update (void);
+ STDMETHODIMP IsUpToDate (void);
+ STDMETHODIMP GetUserClassID(CLSID FAR* pClsid);
+ STDMETHODIMP GetUserType (DWORD dwFormOfType, LPOLESTR FAR *pszUserType);
+ STDMETHODIMP SetExtent (DWORD dwDrawAspect, LPSIZEL lpsizel);
+ STDMETHODIMP GetExtent (DWORD dwDrawAspect, LPSIZEL lpsizel);
+ STDMETHODIMP Advise (IAdviseSink FAR *pAdvSink,
+ DWORD FAR *pdwConnection);
+ STDMETHODIMP Unadvise (DWORD dwConnection);
+ STDMETHODIMP EnumAdvise (LPENUMSTATDATA FAR *ppenmAdvise);
+ STDMETHODIMP GetMiscStatus (DWORD dwAspect, DWORD FAR *pdwStatus);
+ STDMETHODIMP SetColorScheme(LPLOGPALETTE lpLogpal);
+
+private:
+ ULONG _cRef; // Reference count
+ IOleAdviseHolder FAR *_pOAHolder; // Advise Holder
+ IOleClientSite FAR *_pocs; // This objects client site
+ CTestEmbed *_pteObject; // Object we're associated with
+ IMoniker * _pmkContainer;
+};
+
+
+
+#endif // __OLEOBJ_HXX__
diff --git a/private/oleutest/balls/common/otrack.hxx b/private/oleutest/balls/common/otrack.hxx
new file mode 100644
index 000000000..341c1eeab
--- /dev/null
+++ b/private/oleutest/balls/common/otrack.hxx
@@ -0,0 +1,85 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) 1992, Microsoft Corporation.
+//
+// File: otrack.hxx
+//
+// Contents: This file defines facilities for a standard implementation
+// of reference-counted objects, incorporating mechanisms for
+// tracking the usage history of the objects.
+//
+// Classes: ObjectTracker
+//
+// History: 6-Apr-92 MikeSe Created
+//
+//----------------------------------------------------------------------------
+
+#ifndef __OTRACK_HXX__
+#define __OTRACK_HXX__
+
+#include <windows.h>
+
+//+-------------------------------------------------------------------------
+//
+// Class: ObjectTracker (otr)
+//
+// Purpose: Provides basis for tracking (OLE) objects (aka interface handles)
+//
+// History: 6-Apr-92 MikeSe Created
+//
+// Notes: Access to this class is only indirect, through the macros
+// defined later.
+//
+//--------------------------------------------------------------------------
+
+class ObjectTracker
+{
+protected:
+ ObjectTracker();
+
+ ULONG _cReferences;
+};
+
+//+-------------------------------------------------------------------------
+//
+// The following macros encapsulate use of the above
+//
+// INHERIT_TRACKING:
+//
+// For any class which implements a Cairo interface, add this macro
+// in the class declaration, eg:
+//
+// class CMyFoo: INHERIT_TRACKING, IFoo
+//
+// Do not repeat this in any subclass. If both INHERIT_UNWIND and
+// INHERIT_TRACKING are used, the former should appear first.
+
+# define INHERIT_TRACKING protected ObjectTracker
+
+inline ObjectTracker::ObjectTracker():_cReferences(1) {};
+
+# define DECLARE_STD_REFCOUNTING \
+ STDMETHOD_(ULONG, AddRef) () \
+ { \
+ InterlockedIncrement((long*)&_cReferences); \
+ return _cReferences; \
+ }; \
+ STDMETHOD_(ULONG, Release) () \
+ { \
+ if ( InterlockedDecrement((long*)&_cReferences) == 0 ) \
+ { \
+ delete this; \
+ return 0; \
+ } \
+ else \
+ return _cReferences; \
+ };
+
+# define ENLIST_TRACKING(cls)
+
+# define DUMP_TRACKING_INFO()
+
+# define TRACK_CLASS(fTrack, cls)
+
+#endif // of ifndef __OTRACK_HXX__
diff --git a/private/oleutest/balls/common/pch.cxx b/private/oleutest/balls/common/pch.cxx
new file mode 100644
index 000000000..88a695d56
--- /dev/null
+++ b/private/oleutest/balls/common/pch.cxx
@@ -0,0 +1,22 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1991 - 1992.
+//
+// File: PCH.CXX
+//
+// Contents: Precompiled header
+//
+// History: 04-Feb-94 Rickhi Created
+//
+//--------------------------------------------------------------------------
+#pragma warning(disable:4101) // Local variable not used
+
+#include <common.h>
+#include <debnot.h>
+#include <math.h>
+#include <smartp.hxx>
+#include <safepnt.hxx>
+#include <sem.hxx>
+
+#pragma hdrstop
diff --git a/private/oleutest/balls/common/persist.cxx b/private/oleutest/balls/common/persist.cxx
new file mode 100644
index 000000000..ee5deb8a8
--- /dev/null
+++ b/private/oleutest/balls/common/persist.cxx
@@ -0,0 +1,252 @@
+//+-------------------------------------------------------------------
+// File: ipersist.cxx
+//
+// Contents: IPersist and IPersistStorage methods of CPersistStorage class.
+//
+// Classes: CPersistStorage - IPersist, IPersistStorage implementations
+//
+// History: 7-Dec-92 DeanE Created
+//---------------------------------------------------------------------
+
+#include <pch.cxx>
+#pragma hdrstop
+#pragma optimize("",off)
+#include <persist.hxx>
+
+
+//+-------------------------------------------------------------------
+// Member: CPersistStorage::CPersistStorage()
+//
+// Synopsis: The constructor for CPersistStorage.
+//
+// Arguments: None
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+CPersistStorage::CPersistStorage(CTestEmbed *pteObject)
+{
+ _cRef = 1;
+ _pteObject = pteObject;
+ _fDirty = FALSE;
+}
+
+
+//+-------------------------------------------------------------------
+// Member: CPersistStorage::~CPersistStorage()
+//
+// Synopsis: The destructor for CPersistStorage.
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+CPersistStorage::~CPersistStorage()
+{
+ // _cRef should be 1
+ if (1 != _cRef)
+ {
+ // BUGBUG - Log error, someone hasn't released
+ }
+ return;
+}
+
+
+//+-------------------------------------------------------------------
+// Method: CPersistStorage::QueryInterface
+//
+// Synopsis: Forward this to the object we're associated with
+//
+// Parameters: [iid] - Interface ID to return.
+// [ppv] - Pointer to pointer to object.
+//
+// Returns: S_OK if iid is supported, or E_NOINTERFACE if not.
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP CPersistStorage::QueryInterface(REFIID iid, void FAR * FAR *ppv)
+{
+ return(_pteObject->QueryInterface(iid, ppv));
+}
+
+
+//+-------------------------------------------------------------------
+// Method: CPersistStorage::AddRef
+//
+// Synopsis: Forward this to the object we're associated with
+//
+// Returns: New reference count.
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP_(ULONG) CPersistStorage::AddRef(void)
+{
+ ++_cRef;
+ return(_pteObject->AddRef());
+}
+
+
+//+-------------------------------------------------------------------
+// Method: CPersistStorage::Release
+//
+// Synopsis: Forward this to the object we're associated with
+//
+// Returns: New reference count.
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP_(ULONG) CPersistStorage::Release(void)
+{
+ --_cRef;
+ return(_pteObject->Release());
+}
+
+
+//+-------------------------------------------------------------------
+// Method: CPersistStorage::GetClassId
+//
+// Synopsis: See spec 2.00.09 p197. Answer the Class ID of this
+// object.
+//
+// Parameters: [pClassId] -
+//
+// Returns: S_OK
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP CPersistStorage::GetClassID(LPCLSID pClassId)
+{
+ if (NULL != pClassId)
+ {
+ *pClassId = CLSID_TestEmbed;
+ }
+ return(S_OK);
+}
+
+
+//+-------------------------------------------------------------------
+// Method: CPersistStorage::IsDirty
+//
+// Synopsis: See spec 2.00.09 p200. Return S_OK if the object needs
+// to be saved in order to avoid data loss, or S_FALSE
+// if not.
+//
+// Parameters: None
+//
+// Returns: S_OK or S_FALSE
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP CPersistStorage::IsDirty()
+{
+ // BUGBUG - NYI
+ // Because we are NYI, just return S_FALSE
+ return(S_FALSE);
+}
+
+
+//+-------------------------------------------------------------------
+// Method: CPersistStorage::InitNew
+//
+// Synopsis: See spec 2.00.09 p197. This method provides a way
+// for a container to provide persistent storage to this
+// object. Call AddRef on the pStg passed if we do save
+// it.
+//
+// Parameters: [pStg] - IStorage instance this object can use.
+//
+// Returns: S_OK
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP CPersistStorage::InitNew(LPSTORAGE pStg)
+{
+ // BUGBUG - NYI
+ return(S_OK);
+}
+
+
+//+-------------------------------------------------------------------
+// Method: CPersistStorage::Load
+//
+// Synopsis: See spec 2.00.09 p200. Called by handler to put this
+// object into the running state. Object should use the
+// pStg passed to "initialize" itself. We can hold onto
+// this pStg, but when ::Save is called, this can be
+// a different IStorage.
+//
+// Parameters: [pStg] - IStorage to initialize object from.
+//
+// Returns: S_OK?
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP CPersistStorage::Load(LPSTORAGE pStg)
+{
+ // BUGBUG - NYI
+ // Initialize the object here, though, just as if we had obtained
+ // data from an IStorage
+ return(S_OK);
+}
+
+
+//+-------------------------------------------------------------------
+// Method: CPersistStorage::Save
+//
+// Synopsis: See spec 2.00.09 p197. Save the data in the IStorage
+// passed. Ignore flags for now.
+//
+// Parameters: [pStgSave] - Save data in here.
+// [fSameAsLoad] - Indicates this object is the same one
+// that was initially started.
+// [fRemember] - Only matters if fSameAsLoad is FALSE.
+//
+// Returns: STG_E_MEDIUMFULL - why???
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP CPersistStorage::Save(
+ LPSTORAGE pStgSave,
+ BOOL fSameAsLoad)
+{
+ // BUGBUG - NYI
+ return(STG_E_MEDIUMFULL);
+}
+
+
+//+-------------------------------------------------------------------
+// Method: CPersistStorage::SaveCompleted
+//
+// Synopsis: See spec 2.00.09 p198. Used only in certain circumstances.
+//
+// Parameters: [pStgSaved] -
+//
+// Returns: S_OK
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP CPersistStorage::SaveCompleted(LPSTORAGE pStgSaved)
+{
+ // BUGBUG - NYI
+ // We don't have to worry about this unless we allow a "Save As"
+ // operation
+ return(S_OK);
+}
+
+
+
+//+-------------------------------------------------------------------
+// Method: CPersistStorage::HandsOffStorage
+//
+// Synopsis: See spec 2.00.09 p198. Used only in certain circumstances.
+//
+// Parameters: [pStgSaved] -
+//
+// Returns: S_OK
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP CPersistStorage::HandsOffStorage(void)
+{
+ // BUGBUG - NYI
+ // We don't have to worry about this unless we allow a "Save As"
+ // operation
+ return(S_OK);
+}
diff --git a/private/oleutest/balls/common/persist.hxx b/private/oleutest/balls/common/persist.hxx
new file mode 100644
index 000000000..7a626d501
--- /dev/null
+++ b/private/oleutest/balls/common/persist.hxx
@@ -0,0 +1,65 @@
+//+-------------------------------------------------------------------
+//
+// File: persist.hxx
+//
+// Contents: CPersistStorage declaration
+//
+// History: 24-Nov-92 DeanE Created
+//
+//---------------------------------------------------------------------
+
+#ifndef __PERSIST_HXX__
+#define __PERSIST_HXX__
+
+#include <embed.hxx>
+
+//+-------------------------------------------------------------------
+// Class: CPersistStorage
+//
+// Synopsis: Test class CPersistStorage
+//
+// Methods: QueryInterface IUnknown
+// AddRef IUnknown
+// Release IUnknown
+// GetClassId IPersist
+// IsDirty IPersistStorage
+// InitNew IPersistStorage
+// Load IPersistStorage
+// Save IPersistStorage
+// SaveCompleted IPersistStorage
+//
+// History: 24-Nov-92 DeanE Created
+//--------------------------------------------------------------------
+
+class FAR CPersistStorage : public IPersistStorage
+{
+public:
+// Constructor/Destructor
+ CPersistStorage(CTestEmbed *pteObject);
+ ~CPersistStorage();
+
+// IUnknown - Everyone inherits from this
+ STDMETHODIMP QueryInterface(REFIID iid, void FAR * FAR *ppv);
+ STDMETHODIMP_(ULONG) AddRef (void);
+ STDMETHODIMP_(ULONG) Release (void);
+
+// IPersist - IPersistStorage inherits from this
+ STDMETHODIMP GetClassID (LPCLSID pClassId);
+
+// IPersistStorage
+ STDMETHODIMP IsDirty (void);
+ STDMETHODIMP InitNew (LPSTORAGE pStg);
+ STDMETHODIMP Load (LPSTORAGE pStg);
+ STDMETHODIMP Save (LPSTORAGE pStgSave,
+ BOOL fSameAsLoad);
+ STDMETHODIMP SaveCompleted (LPSTORAGE pStgSaved);
+ STDMETHODIMP HandsOffStorage (void);
+
+private:
+ ULONG _cRef; // Reference count
+ CTestEmbed *_pteObject; // Object we're associated with
+ BOOL _fDirty; // TRUE if object is dirty
+};
+
+
+#endif // __PERSIST_HXX__
diff --git a/private/oleutest/balls/common/qicf.cxx b/private/oleutest/balls/common/qicf.cxx
new file mode 100644
index 000000000..c29de9807
--- /dev/null
+++ b/private/oleutest/balls/common/qicf.cxx
@@ -0,0 +1,123 @@
+//+-------------------------------------------------------------------
+//
+// File: qicf.cxx
+//
+// Contents: test class factory object implementation
+//
+// Classes: CQIClassFactory
+//
+// Functions:
+//
+// History: 23-Nov-92 Rickhi Created
+//
+//--------------------------------------------------------------------
+
+#include <pch.cxx>
+#pragma hdrstop
+#include <qicf.hxx> // class definiton
+#include <cqi.hxx> // CQI defines
+
+
+const GUID CLSID_QI =
+ {0x00000140,0x0000,0x0008,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}};
+
+const GUID CLSID_QIHANDLER =
+ {0x00000141,0x0000,0x0008,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}};
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CQIClassFactory::CQIClassFactory, public
+//
+// History: 23-Nov-92 Rickhi Created
+//
+//--------------------------------------------------------------------
+CQIClassFactory::CQIClassFactory(REFCLSID rclsid) : _clsid(rclsid)
+{
+ ENLIST_TRACKING(CQIClassFactory);
+}
+
+//+-------------------------------------------------------------------
+//
+// Member: CQIClassFactory::~CQIClassFactory, public
+//
+// History: 23-Nov-92 Rickhi Created
+//
+//--------------------------------------------------------------------
+CQIClassFactory::~CQIClassFactory(void)
+{
+ // automatic actions do the rest of the work
+}
+
+//+-------------------------------------------------------------------
+//
+// Member: CQIClassFactory::QueryInterface, public
+//
+// Algorithm: if the interface is not one implemented by us,
+// pass the request to the proxy manager
+//
+// History: 23-Nov-92 Rickhi Created
+//
+//--------------------------------------------------------------------
+STDMETHODIMP CQIClassFactory::QueryInterface(REFIID riid, void **ppUnk)
+{
+ if (IsEqualIID(riid, IID_IUnknown) ||
+ IsEqualIID(riid, IID_IClassFactory))
+ {
+ *ppUnk = (void *)(IClassFactory *) this;
+ AddRef();
+ return S_OK;
+ }
+
+ *ppUnk = NULL;
+ return E_NOINTERFACE;
+}
+
+//+-------------------------------------------------------------------
+//
+// Member: CQIClassFactory::CreateInstance, public
+//
+// Synopsis: create a new object with the same class
+//
+// History: 23-Nov-92 Rickhi Created
+//
+//--------------------------------------------------------------------
+STDMETHODIMP CQIClassFactory::CreateInstance(IUnknown *punkOuter,
+ REFIID riid,
+ void **ppunkObject)
+{
+ SCODE sc = E_OUTOFMEMORY;
+
+ *ppunkObject = NULL; // in case of failure
+
+ // create a new object.
+ IUnknown *pQI = new CQI(_clsid);
+
+ if (pQI)
+ {
+ // get the interface the caller wants to use
+ sc = pQI->QueryInterface(riid, ppunkObject);
+ pQI->Release();
+ }
+
+ return sc;
+}
+
+//+-------------------------------------------------------------------
+//
+// Member: CQIClassFactory::LockServer, public
+//
+// Synopsis: create a new object with the same class
+//
+// History: 23-Nov-92 Rickhi Created
+//
+//--------------------------------------------------------------------
+STDMETHODIMP CQIClassFactory::LockServer(BOOL fLock)
+{
+ if (fLock)
+ GlobalRefs(TRUE);
+ else
+ GlobalRefs(FALSE);
+
+ return S_OK;
+}
diff --git a/private/oleutest/balls/common/qicf.hxx b/private/oleutest/balls/common/qicf.hxx
new file mode 100644
index 000000000..8f63c5455
--- /dev/null
+++ b/private/oleutest/balls/common/qicf.hxx
@@ -0,0 +1,55 @@
+//+-------------------------------------------------------------------
+//
+// File: qicf.hxx
+//
+// Contents: test class factory object implementation
+//
+// Classes: CQIClassFactory
+//
+// Functions: None
+//
+// History: 23-Nov-92 Rickhi Created
+//
+//--------------------------------------------------------------------
+#ifndef __CQICLASSFACTORY__
+#define __CQICLASSFACTORY__
+
+#include <win4p.hxx>
+#include <otrack.hxx> // object tracking
+#include <cqi.hxx> // class code
+
+//+-------------------------------------------------------------------
+//
+// Class: CQIClassFactory
+//
+// Purpose: test class factory object implementation
+//
+// History: 23-Nov-92 Rickhi Created
+//
+//--------------------------------------------------------------------
+class CQIClassFactory : INHERIT_TRACKING,
+ public IClassFactory
+{
+public:
+ // Constructor & Destructor
+ CQIClassFactory(REFCLSID rclsid);
+
+ // IUnknown methods
+ STDMETHOD(QueryInterface)(REFIID riid, void **ppUnk);
+ DECLARE_STD_REFCOUNTING;
+
+
+ // IClassFactory methods
+ STDMETHOD(CreateInstance)(IUnknown *punkOuter,
+ REFIID riid,
+ void **ppunkObject);
+
+ STDMETHOD(LockServer)(BOOL fLock);
+
+private:
+ ~CQIClassFactory(void);
+
+ CLSID _clsid;
+};
+
+#endif // __CQICLASSFACTORY__
diff --git a/private/oleutest/balls/common/regmain.cxx b/private/oleutest/balls/common/regmain.cxx
new file mode 100644
index 000000000..026ecd392
--- /dev/null
+++ b/private/oleutest/balls/common/regmain.cxx
@@ -0,0 +1,203 @@
+//+------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1993.
+//
+// File: regmain.cxx
+//
+// Contents: registration of developer regression tests and benchmrk
+// tests.
+//
+// Functions: RegistrySetup
+//
+// History: 23-May-96 Rickhi Created
+//
+//--------------------------------------------------------------------------
+#include <pch.cxx>
+#include <regmain.hxx>
+
+#define REGISTRY_ENTRY_LEN 256
+
+typedef struct
+{
+ const char *key;
+ const char *value;
+} RegistryKeyValue;
+
+const RegistryKeyValue REG_CONST_KEY[] =
+{
+ ".bm1", "CLSID\\{99999999-0000-0008-C000-000000000052}",
+ ".bm2", "CLSID\\{99999999-0000-0008-C000-000000000051}",
+
+ "CLSID\\{20730701-0001-0008-C000-000000000046}", "OleTestClass",
+ "CLSID\\{20730711-0001-0008-C000-000000000046}", "OleTestClass1",
+ "CLSID\\{20730712-0001-0008-C000-000000000046}", "OleTestClass2",
+ "CLSID\\{20730713-0001-0008-C000-000000000046}", "OleTestClass3",
+ "CLSID\\{20730714-0001-0008-C000-000000000046}", "OleTestClass4",
+ "CLSID\\{20730715-0001-0008-C000-000000000046}", "OleTestClass5",
+ "CLSID\\{20730716-0001-0008-C000-000000000046}", "OleTestClass6",
+ "CLSID\\{20730717-0001-0008-C000-000000000046}", "OleTestClass7",
+ "CLSID\\{20730718-0001-0008-C000-000000000046}", "OleTestClass8",
+
+ "CLSID\\{00000138-0001-0008-C000-000000000046}", "CPrxyBalls",
+ "Interface\\{00000138-0001-0008-C000-000000000046}", "IBalls",
+ "Interface\\{00000139-0001-0008-C000-000000000046}", "ICube",
+ "Interface\\{00000136-0001-0008-C000-000000000046}", "ILoops",
+ "Interface\\{00000137-0001-0008-C000-000000000046}", "IRpcTest",
+
+ "Interface\\{00000138-0001-0008-C000-000000000046}\\ProxyStubClsid32", "{00000138-0001-0008-C000-000000000046}",
+ "Interface\\{00000139-0001-0008-C000-000000000046}\\ProxyStubClsid32", "{00000138-0001-0008-C000-000000000046}",
+ "Interface\\{00000136-0001-0008-C000-000000000046}\\ProxyStubClsid32", "{00000138-0001-0008-C000-000000000046}",
+ "Interface\\{00000137-0001-0008-C000-000000000046}\\ProxyStubClsid32", "{00000138-0001-0008-C000-000000000046}",
+ "CLSID\\{0000013a-0001-0008-C000-000000000046}\\ProgID", "ProgID60",
+ "CLSID\\{0000013a-0001-0008-C000-000000000046}", "CBallsClassFactory",
+ "CLSID\\{0000013b-0001-0008-C000-000000000046}", "CCubesClassFactory",
+ "CLSID\\{0000013c-0001-0008-C000-000000000046}", "CLoopClassFactory",
+ "CLSID\\{0000013d-0001-0008-C000-000000000046}", "CRpcTestClassFactory",
+ "CLSID\\{0000013e-0001-0008-C000-000000000046}", "CHandCraftedProxy",
+ "CLSID\\{00000140-0000-0008-C000-000000000046}", "CQueryInterface",
+ "CLSID\\{00000141-0000-0008-C000-000000000046}", "CQueryInterfaceHandler",
+
+ ".ut4", "ProgID50",
+ ".ut5", "ProgID51",
+ ".ut6", "ProgID52",
+ ".ut7", "ProgID53",
+ ".ut8", "ProgID54",
+ ".ut9", "ProgID55",
+ ".bls", "ProgID60",
+
+ "CLSID\\{99999999-0000-0008-C000-000000000050}", "SDI",
+ "CLSID\\{99999999-0000-0008-C000-000000000051}", "MDI",
+ "CLSID\\{99999999-0000-0008-C000-000000000052}", "InprocNoRegister",
+ "CLSID\\{99999999-0000-0008-C000-000000000053}", "InprocRegister",
+ "CLSID\\{99999999-0000-0008-C000-000000000054}", "InprocRegister",
+ "CLSID\\{99999999-0000-0008-C000-000000000054}\\TreatAs", "{99999999-0000-0008-C000-000000000050}",
+ "CLSID\\{99999999-0000-0008-C000-000000000055}", "MDI",
+ "CLSID\\{99999999-0000-0008-C000-000000000055}\\ActivateAtBits", "Y",
+
+ "ProgID50", "objact sdi",
+ "ProgID50\\CLSID", "{99999999-0000-0008-C000-000000000050}",
+ "ProgID51", "objact mdi",
+ "ProgID51\\CLSID", "{99999999-0000-0008-C000-000000000051}",
+ "ProgID52", "objact dll",
+ "ProgID52\\CLSID", "{99999999-0000-0008-C000-000000000052}",
+ "ProgID53", "objact dll reg",
+ "ProgID53\\CLSID", "{99999999-0000-0008-C000-000000000053}",
+ "ProgID54", "objact dll reg",
+ "ProgID54\\CLSID", "{99999999-0000-0008-C000-000000000054}",
+ "ProgID55", "remote activation",
+ "ProgID55\\CLSID", "{99999999-0000-0008-C000-000000000055}",
+ "ProgID60", "CLSIDFromProgID test",
+ "ProgID60\\CLSID", "{0000013a-0001-0008-C000-000000000046}",
+
+ // Indicates end of list.
+ "", ""
+};
+
+const RegistryKeyValue REG_EXE_KEY[] =
+{
+ "CLSID\\{20730701-0001-0008-C000-000000000046}\\InprocServer32", "oletest.dll",
+ "CLSID\\{20730711-0001-0008-C000-000000000046}\\InprocServer32", "oletest.dll",
+ "CLSID\\{20730712-0001-0008-C000-000000000046}\\InprocServer32", "oletest.dll",
+ "CLSID\\{20730713-0001-0008-C000-000000000046}\\InprocServer32", "oletest.dll",
+ "CLSID\\{20730714-0001-0008-C000-000000000046}\\InprocServer32", "oletest.dll",
+ "CLSID\\{20730715-0001-0008-C000-000000000046}\\InprocServer32", "oletest.dll",
+ "CLSID\\{20730716-0001-0008-C000-000000000046}\\InprocServer32", "oletest.dll",
+ "CLSID\\{20730717-0001-0008-C000-000000000046}\\InprocServer32", "oletest.dll",
+ "CLSID\\{20730718-0001-0008-C000-000000000046}\\InprocServer32", "oletest.dll",
+
+ "CLSID\\{20730712-0001-0008-C000-000000000046}\\LocalServer32", "bmtstsvr.exe",
+ "CLSID\\{20730701-0001-0008-C000-000000000046}\\LocalServer32", "bmtstsvr.exe",
+
+ "CLSID\\{0000013a-0001-0008-C000-000000000046}\\LocalServer32", "ballsrv.exe",
+ "CLSID\\{00000138-0001-0008-C000-000000000046}\\InprocServer32", "iballs.dll",
+ "CLSID\\{0000013b-0001-0008-C000-000000000046}\\LocalServer32", "cubesrv.exe",
+ "CLSID\\{0000013c-0001-0008-C000-000000000046}\\LocalServer32", "loopsrv.exe",
+ "CLSID\\{0000013d-0001-0008-C000-000000000046}\\LocalServer32", "rpctst.exe",
+ "CLSID\\{0000013e-0001-0008-C000-000000000046}\\InprocServer32", "myproxy.dll",
+ "CLSID\\{00000140-0000-0008-C000-000000000046}\\LocalServer32", "qisrv.exe",
+ "CLSID\\{00000140-0000-0008-C000-000000000046}\\InprocServer32", "qisrv.dll",
+ "CLSID\\{00000141-0000-0008-C000-000000000046}\\LocalServer32", "qisrv.exe",
+ "CLSID\\{00000141-0000-0008-C000-000000000046}\\InprocHandler32", "ole32.dll",
+
+
+ "CLSID\\{99999999-0000-0008-C000-000000000050}\\LocalServer32", "sdi.exe",
+ "CLSID\\{99999999-0000-0008-C000-000000000051}\\LocalServer32", "mdi.exe",
+ "CLSID\\{99999999-0000-0008-C000-000000000052}\\InprocServer32", "dlltest.dll",
+ "CLSID\\{99999999-0000-0008-C000-000000000053}\\InprocServer32", "dlltest.dll",
+ "CLSID\\{99999999-0000-0008-C000-000000000055}\\LocalServer32", "db.exe",
+
+ // Indicates end of list.
+ "", ""
+};
+
+
+//+-------------------------------------------------------------------
+//
+// Function: RegistrySetup
+//
+// Synopsis: write the registry entries for this program
+//
+// Note: This function uses all Ascii characters and character
+// arithmatic because it has to run on NT and Chicago.
+//
+// History: 16 Dec 94 AlexMit Created
+//
+//--------------------------------------------------------------------
+BOOL RegistrySetup(char *pszAppName)
+{
+ char value[REGISTRY_ENTRY_LEN];
+ LONG value_size;
+ LONG result;
+ char directory[MAX_PATH];
+ char *appname;
+ BOOL success = FALSE;
+
+ // Write constant entries.
+ for (int i = 0; REG_CONST_KEY[i].key[0] != '\0'; i++)
+ {
+ result = RegSetValueA(
+ HKEY_CLASSES_ROOT,
+ REG_CONST_KEY[i].key,
+ REG_SZ,
+ REG_CONST_KEY[i].value,
+ strlen(REG_CONST_KEY[i].value) );
+
+ if (result != ERROR_SUCCESS)
+ goto cleanup;
+ }
+
+ // Compute the path to the application.
+ result = GetFullPathNameA(pszAppName, sizeof(directory), directory, &appname);
+ if (result == 0)
+ goto cleanup;
+
+ // Add the path to all the dll and exe entries.
+ for (i = 0; REG_EXE_KEY[i].key[0] != '\0'; i++)
+ {
+ // Verify that the path will fit in the buffer and compute the path
+ // to the next executable.
+ if (strlen(REG_EXE_KEY[i].value) >=
+ (ULONG)(MAX_PATH - (appname - directory)))
+ goto cleanup;
+
+ strcpy(appname, REG_EXE_KEY[i].value);
+
+ // Write the next entry.
+ result = RegSetValueA(
+ HKEY_CLASSES_ROOT,
+ REG_EXE_KEY[i].key,
+ REG_SZ,
+ directory,
+ strlen(directory));
+
+ if (result != ERROR_SUCCESS)
+ goto cleanup;
+ }
+
+ success = TRUE;
+
+cleanup:
+ return success;
+}
+
diff --git a/private/oleutest/balls/common/regmain.hxx b/private/oleutest/balls/common/regmain.hxx
new file mode 100644
index 000000000..890ee4f39
--- /dev/null
+++ b/private/oleutest/balls/common/regmain.hxx
@@ -0,0 +1,18 @@
+//+------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1993.
+//
+// File: regmain.cxx
+//
+// Contents: registration of developer regression tests and benchmrk
+// tests.
+//
+// Functions: RegistrySetup
+//
+// History: 23-May-96 Rickhi Created
+//
+//--------------------------------------------------------------------------
+
+BOOL RegistrySetup(char *pszAppName);
+
diff --git a/private/oleutest/balls/common/rpccf.cxx b/private/oleutest/balls/common/rpccf.cxx
new file mode 100644
index 000000000..a726ec225
--- /dev/null
+++ b/private/oleutest/balls/common/rpccf.cxx
@@ -0,0 +1,140 @@
+//+-------------------------------------------------------------------
+//
+// File: rpccf.cxx
+//
+// Contents: rpc test class factory object implementation
+//
+// Classes: CRpcTestClassFactory
+//
+// History: 23-Nov-92 Rickhi Created
+//
+//--------------------------------------------------------------------
+
+#include <pch.cxx>
+#pragma hdrstop
+#include <rpccf.hxx> // class definiton
+#include <crpc.hxx> // CRpcTests defines
+
+
+const GUID CLSID_RpcTest =
+ {0x0000013d,0x0001,0x0008,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}};
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CRpcTestClassFactory::CRpcTestClassFactory, public
+//
+// Algorithm:
+//
+// History: 23-Nov-92 Rickhi Created
+//
+//--------------------------------------------------------------------
+
+CRpcTestClassFactory::CRpcTestClassFactory(void)
+{
+ ENLIST_TRACKING(CRpcTestClassFactory);
+}
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CRpcTestClassFactory::~CRpcTestClassFactory, public
+//
+// Algorithm:
+//
+// History: 23-Nov-92 Rickhi Created
+//
+//--------------------------------------------------------------------
+
+CRpcTestClassFactory::~CRpcTestClassFactory(void)
+{
+ // automatic actions do the rest of the work
+}
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CRpcTestClassFactory::QueryInterface, public
+//
+// Algorithm: if the interface is not one implemented by us,
+// pass the request to the proxy manager
+//
+// History: 23-Nov-92 Rickhi Created
+//
+//--------------------------------------------------------------------
+
+STDMETHODIMP CRpcTestClassFactory::QueryInterface(REFIID riid, void **ppUnk)
+{
+ SCODE sc = S_OK;
+
+ if (IsEqualIID(riid, IID_IUnknown) ||
+ IsEqualIID(riid, IID_IClassFactory))
+ {
+ *ppUnk = (void *)(IClassFactory *) this;
+ AddRef();
+ }
+ else
+ {
+ *ppUnk = NULL;
+ sc = E_NOINTERFACE;
+ }
+ return sc;
+}
+
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CRpcTestClassFactory::CreateInstance, public
+//
+// Synopsis: create a new object with the same class
+//
+// History: 23-Nov-92 Rickhi Created
+//
+//--------------------------------------------------------------------
+
+STDMETHODIMP CRpcTestClassFactory::CreateInstance(IUnknown *punkOuter,
+ REFIID riid,
+ void **ppunkObject)
+{
+ SCODE sc = E_OUTOFMEMORY;
+
+ *ppunkObject = NULL; // in case of failure
+
+ // create a ball object.
+ IUnknown *punk = (IUnknown *) new CRpcTest();
+
+ if (punk)
+ {
+ // get the interface the caller wants to use
+ sc = punk->QueryInterface(riid, ppunkObject);
+
+ // release our hold on the ball, since the QI got a hold for
+ // the client.
+ punk->Release();
+ }
+
+ return sc;
+}
+
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CRpcTestClassFactory::LockServer, public
+//
+// Synopsis: create a new object with the same class
+//
+// History: 23-Nov-92 Rickhi Created
+//
+//--------------------------------------------------------------------
+
+STDMETHODIMP CRpcTestClassFactory::LockServer(BOOL fLock)
+{
+ if (fLock)
+ GlobalRefs(TRUE);
+ else
+ GlobalRefs(FALSE);
+
+ return S_OK;
+}
diff --git a/private/oleutest/balls/common/rpccf.hxx b/private/oleutest/balls/common/rpccf.hxx
new file mode 100644
index 000000000..624fe8fca
--- /dev/null
+++ b/private/oleutest/balls/common/rpccf.hxx
@@ -0,0 +1,61 @@
+//+-------------------------------------------------------------------
+//
+// File: rpccf.hxx
+//
+// Contents: rpctest class factory object implementation
+//
+// Classes: CRpcTestClassFactory
+//
+// Functions: None
+//
+// History: 23-Nov-92 Rickhi Created
+//
+//--------------------------------------------------------------------
+
+#ifndef __CRPCTESTCLASSFACTORY__
+#define __CRPCTESTCLASSFACTORY__
+
+#include <win4p.hxx>
+#include <otrack.hxx> // object tracking
+
+extern "C" const GUID CLSID_RpcTest;
+
+//+-------------------------------------------------------------------
+//
+// Class: CRpcTestClassFactory
+//
+// Purpose: test class factory object implementation
+//
+// Interface:
+//
+// History: 23-Nov-92 Rickhi Created
+//
+// Notes:
+//
+//--------------------------------------------------------------------
+
+class CRpcTestClassFactory : INHERIT_TRACKING,
+ public IClassFactory
+{
+public:
+ // Constructor & Destructor
+ CRpcTestClassFactory(void);
+
+ // IUnknown methods
+ STDMETHOD(QueryInterface)(REFIID riid, void **ppUnk);
+ DECLARE_STD_REFCOUNTING;
+
+ // IClassFactory methods
+ STDMETHOD(CreateInstance)(IUnknown *punkOuter,
+ REFIID riid,
+ void **ppunkObject);
+
+ STDMETHOD(LockServer)(BOOL fLock);
+
+private:
+ ~CRpcTestClassFactory(void);
+
+};
+
+
+#endif // __CRPCTESTCLASSFACTORY__
diff --git a/private/oleutest/balls/common/rpctcf.cxx b/private/oleutest/balls/common/rpctcf.cxx
new file mode 100644
index 000000000..406522514
--- /dev/null
+++ b/private/oleutest/balls/common/rpctcf.cxx
@@ -0,0 +1,136 @@
+//+-------------------------------------------------------------------
+//
+// File: rpccf.cxx
+//
+// Contents: rpc test class factory object implementation
+//
+// Classes: CRpcTestClassFactory
+//
+// History: 23-Nov-92 Rickhi Created
+//
+//--------------------------------------------------------------------
+
+#include <pch.cxx>
+#pragma hdrstop
+#include <rpctcf.hxx> // class definiton
+#include <crpctyp.hxx> // CRpcTests defines
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CRpcTypesClassFactory::CRpcTypesClassFactory, public
+//
+// Algorithm:
+//
+// History: 23-Nov-92 Rickhi Created
+//
+//--------------------------------------------------------------------
+
+CRpcTypesClassFactory::CRpcTypesClassFactory(void)
+{
+ ENLIST_TRACKING(CRpcTypesClassFactory);
+}
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CRpcTypesClassFactory::~CRpcTypesClassFactory, public
+//
+// Algorithm:
+//
+// History: 23-Nov-92 Rickhi Created
+//
+//--------------------------------------------------------------------
+
+CRpcTypesClassFactory::~CRpcTypesClassFactory(void)
+{
+ // automatic actions do the rest of the work
+}
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CRpcTypesClassFactory::QueryInterface, public
+//
+// Algorithm: if the interface is not one implemented by us,
+// pass the request to the proxy manager
+//
+// History: 23-Nov-92 Rickhi Created
+//
+//--------------------------------------------------------------------
+
+STDMETHODIMP CRpcTypesClassFactory::QueryInterface(REFIID riid, void **ppUnk)
+{
+ SCODE sc = S_OK;
+
+ if (IsEqualIID(riid, IID_IUnknown) ||
+ IsEqualIID(riid, IID_IClassFactory))
+ {
+ *ppUnk = (void *)(IClassFactory *) this;
+ AddRef();
+ }
+ else
+ {
+ *ppUnk = NULL;
+ sc = E_NOINTERFACE;
+ }
+ return sc;
+}
+
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CRpcTypesClassFactory::CreateInstance, public
+//
+// Synopsis: create a new object with the same class
+//
+// History: 23-Nov-92 Rickhi Created
+//
+//--------------------------------------------------------------------
+
+STDMETHODIMP CRpcTypesClassFactory::CreateInstance(IUnknown *punkOuter,
+ REFIID riid,
+ void **ppunkObject)
+{
+ SCODE sc = E_OUTOFMEMORY;
+
+ *ppunkObject = NULL; // in case of failure
+
+ // create a ball object.
+ IUnknown *punk = (IUnknown *) new CRpcTypes();
+
+ if (punk)
+ {
+ // get the interface the caller wants to use
+ sc = punk->QueryInterface(riid, ppunkObject);
+
+ // release our hold on the ball, since the QI got a hold for
+ // the client.
+ punk->Release();
+ }
+
+ return sc;
+}
+
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CRpcTypesClassFactory::LockServer, public
+//
+// Synopsis: create a new object with the same class
+//
+// History: 23-Nov-92 Rickhi Created
+//
+//--------------------------------------------------------------------
+
+STDMETHODIMP CRpcTypesClassFactory::LockServer(BOOL fLock)
+{
+ if (fLock)
+ GlobalRefs(TRUE);
+ else
+ GlobalRefs(FALSE);
+
+ return S_OK;
+}
diff --git a/private/oleutest/balls/common/rpctcf.hxx b/private/oleutest/balls/common/rpctcf.hxx
new file mode 100644
index 000000000..3adc78876
--- /dev/null
+++ b/private/oleutest/balls/common/rpctcf.hxx
@@ -0,0 +1,61 @@
+//+-------------------------------------------------------------------
+//
+// File: rpccf.hxx
+//
+// Contents: rpctest class factory object implementation
+//
+// Classes: CRpcTestClassFactory
+//
+// Functions: None
+//
+// History: 23-Nov-92 Rickhi Created
+//
+//--------------------------------------------------------------------
+
+#ifndef __CRPCTYPESCLASSFACTORY__
+#define __CRPCTYPESCLASSFACTORY__
+
+#include <win4p.hxx>
+#include <otrack.hxx> // object tracking
+
+extern "C" const GUID CLSID_RpcTypes;
+
+//+-------------------------------------------------------------------
+//
+// Class: CRpcTypesClassFactory
+//
+// Purpose: test class factory object implementation
+//
+// Interface:
+//
+// History: 23-Nov-92 Rickhi Created
+//
+// Notes:
+//
+//--------------------------------------------------------------------
+
+class CRpcTypesClassFactory : INHERIT_TRACKING,
+ public IClassFactory
+{
+public:
+ // Constructor & Destructor
+ CRpcTypesClassFactory(void);
+
+ // IUnknown methods
+ STDMETHOD(QueryInterface)(REFIID riid, void **ppUnk);
+ DECLARE_STD_REFCOUNTING;
+
+ // IClassFactory methods
+ STDMETHOD(CreateInstance)(IUnknown *punkOuter,
+ REFIID riid,
+ void **ppunkObject);
+
+ STDMETHOD(LockServer)(BOOL fLock);
+
+private:
+ ~CRpcTypesClassFactory(void);
+
+};
+
+
+#endif // __CRPCTYPESCLASSFACTORY__
diff --git a/private/oleutest/balls/common/smartp.hxx b/private/oleutest/balls/common/smartp.hxx
new file mode 100644
index 000000000..3490ec0b7
--- /dev/null
+++ b/private/oleutest/balls/common/smartp.hxx
@@ -0,0 +1,75 @@
+//+---------------------------------------------------------------------------
+//
+// Copyright (C) 1992, Microsoft Corporation.
+//
+// File: smartp.hxx
+//
+// Contents: Class and associated macros for generic smart pointer
+// capability.
+//
+// Classes: XIUnknown
+// XMem
+//
+// History: 30-Mar-92 MikeSe Created
+// 6-Oct-92 MikeSe Added XMem and related macros.
+//
+// Notes: All of the interesting stuff from here is now in safepnt.hxx
+// which should be used in preference. The following correspondences
+// exist between the macros defined here and those in safepnt,
+// should you wish to convert to avoid the (deliberately) annoying
+// warning:
+//
+// DefineSmartItfP(class) == SAFE_INTERFACE_PTR(Xclass,class)
+// DefineSmartMemP(class,NO_ARROW) == SAFE_MEMALLOC_MEMPTR(Xclass,class)
+// DefineSmartMemP(class,DEFINE_ARROW) == SAFE_MEMALLOC_PTR(Xclass,class)
+//
+//----------------------------------------------------------------------------
+
+#ifndef __SMARTP_HXX__
+#define __SMARTP_HXX__
+
+// #include <types.hxx>
+#include <safepnt.hxx>
+
+//+-------------------------------------------------------------------------
+//
+// Macro: DefineSmartItfP
+//
+// Purpose: Macro to define smart pointer to an IUnknown derivative.
+//
+// Notes: The smart pointer so defined has a fixed name consisting of
+// X (for eXception-safe) prefixed to the name of the pointed-to
+// class. If you want to choose the name, you should use the
+// SAFE_INTERFACE_PTR macro in safepnt.hxx.
+//
+//--------------------------------------------------------------------------
+
+#define DefineSmartItfP(cls) SAFE_INTERFACE_PTR(X##cls,cls)
+
+DefineSmartItfP(IUnknown)
+
+// For backwards compatibility
+#define DefineSmartP(cls) DefineSmartItfP(cls)
+
+//+-------------------------------------------------------------------------
+//
+// Macro: DefineSmartMemP
+//
+// Purpose: Macro to define smart pointer to any MemAlloc'ed structure
+//
+// Notes: This macro is used to define a smart pointer to any structure
+// allocated using MemAlloc. Invocation is as follows:
+//
+// DefineSmartMemP(SWCStringArray,arrow_spec)
+//
+// where arrow_spec is DEFINE_ARROW if the pointed-to type
+// supports a member-of (->) operator, and NO_ARROW if
+// it does not. (EG: use NO_ARROW for WCString).
+//
+//--------------------------------------------------------------------------
+
+#define _MEM_DEFINE_ARROW(cls) SAFE_MEMALLOC_PTR(X##cls,cls)
+#define _MEM_NO_ARROW(cls) SAFE_MEMALLOC_MEMPTR(X##cls,cls)
+#define DefineSmartMemP(cls,arrow) _MEM_##arrow(cls)
+
+#endif // of ifndef __SMARTP_HXX__
diff --git a/private/oleutest/balls/common/srvmain.cxx b/private/oleutest/balls/common/srvmain.cxx
new file mode 100644
index 000000000..4d4ab96a7
--- /dev/null
+++ b/private/oleutest/balls/common/srvmain.cxx
@@ -0,0 +1,352 @@
+//+-------------------------------------------------------------------
+//
+// File: srvmain.cxx
+//
+// Contents: Server entry points.
+//
+// Classes: none
+//
+// History: 23-Nov-92 Rickhi Created
+//
+//--------------------------------------------------------------------
+#include <pch.cxx>
+#pragma hdrstop
+
+extern "C"
+{
+#include "wterm.h"
+#include <memory.h>
+#include <stdio.h>
+}
+
+// globals
+LONG g_Usage = 0;
+DWORD gTlsIndex = TlsAlloc();
+
+
+//+-------------------------------------------------------------------
+//
+// typedef: SCLASSDATA - class data stored in TLS.
+//
+//+-------------------------------------------------------------------
+typedef struct tagSCLASSDATA
+{
+ ULONG cClasses;
+ SCLASSINFO *pClsInfo;
+} SCLASSDATA;
+
+//+-------------------------------------------------------------------
+//
+// Function: RememberClasses
+//
+// Synopsis: Stores the class info for this thread in TLS.
+//
+// History: 21-Nov-92 SarahJ Created
+//
+//--------------------------------------------------------------------
+HRESULT RememberClasses(SCLASSINFO *pClsInfo, ULONG cClasses)
+{
+ SCLASSDATA *pClsData = (SCLASSDATA *) new BYTE[sizeof(SCLASSDATA)];
+
+ if (pClsData)
+ {
+ pClsData->cClasses = cClasses;
+ pClsData->pClsInfo = pClsInfo;
+ TlsSetValue(gTlsIndex, pClsData);
+ return S_OK;
+ }
+
+ return E_OUTOFMEMORY;
+}
+
+//+-------------------------------------------------------------------
+//
+// Function: RecallClasses
+//
+// Synopsis: retrieves the class info for this thread from TLS.
+//
+// History: 21-Nov-92 SarahJ Created
+//
+//--------------------------------------------------------------------
+void RecallClasses(SCLASSINFO **ppClsInfo, ULONG *pcClasses)
+{
+ SCLASSDATA *pClsData = (SCLASSDATA *) TlsGetValue(gTlsIndex);
+
+ if (pClsData)
+ {
+ *pcClasses = pClsData->cClasses;
+ *ppClsInfo = pClsData->pClsInfo;
+ }
+ else
+ {
+ *pcClasses = 0;
+ *ppClsInfo = NULL;
+ }
+}
+
+//+-------------------------------------------------------------------
+//
+// Function: ForgetClasses
+//
+// Synopsis: removes the class info for this thread from TLS.
+//
+// History: 21-Nov-92 SarahJ Created
+//
+//--------------------------------------------------------------------
+void ForgetClasses()
+{
+ SCLASSDATA *pClsData = (SCLASSDATA *) TlsGetValue(gTlsIndex);
+
+ if (pClsData)
+ {
+ delete pClsData;
+ TlsSetValue(gTlsIndex, NULL);
+ }
+}
+
+//+-------------------------------------------------------------------
+//
+// Function: RegisterAllClasses
+//
+// Synopsis: loops, registering each class specified by the server.
+//
+// History: 21-Nov-92 SarahJ Created
+//
+//--------------------------------------------------------------------
+void RegisterAllClasses(SCLASSINFO *pClsInfo, ULONG cClasses)
+{
+ // store the class info in TLS so we can get it back later
+ // in GlobalRefs.
+
+ if (FAILED(RememberClasses(pClsInfo, cClasses)))
+ return;
+
+ HRESULT hr;
+
+ for (ULONG i=0; i<cClasses; i++, pClsInfo++)
+ {
+ // register the CF. Note that we do this AFTER creating the
+ // window, so that if we get a Release very quickly we have
+ // a valid window handle to send a message to.
+ hr = CoRegisterClassObject(pClsInfo->clsid,
+ pClsInfo->pCF,
+ pClsInfo->dwCtx,
+ pClsInfo->dwClsReg,
+ &pClsInfo->dwReg);
+
+ if (FAILED(hr))
+ {
+ Display(TEXT("ERROR: failed CoRegisterClassObject %x\n"), hr);
+ }
+ }
+
+ if (FAILED(hr))
+ {
+ Display(TEXT("ERROR: failed CoResumeClassObjects %x\n"), hr);
+ }
+}
+
+//+-------------------------------------------------------------------
+//
+// Function: RevokeAllClasses
+//
+// Synopsis: loops, revoking each class specified by the server.
+//
+// History: 21-Nov-92 SarahJ Created
+//
+//--------------------------------------------------------------------
+void RevokeAllClasses()
+{
+ // first, get the class information from TLS
+ SCLASSINFO *pClsInfo;
+ ULONG cClasses;
+
+ RecallClasses(&pClsInfo, &cClasses);
+
+ // now revoke each of the registered classes
+ for (ULONG i=0; i<cClasses; i++, pClsInfo++)
+ {
+ if (pClsInfo->dwReg != 0)
+ {
+ ULONG ulRef = CoRevokeClassObject(pClsInfo->dwReg);
+ Display(TEXT("Revoked ClassObject\n"));
+ pClsInfo->dwReg = 0;
+ }
+ }
+}
+
+//+-------------------------------------------------------------------
+//
+// Function: ReleaseAllClasses
+//
+// Synopsis: loops, releasing each class factory object.
+//
+// History: 21-Nov-92 SarahJ Created
+//
+//--------------------------------------------------------------------
+void ReleaseAllClasses()
+{
+ // first, get the class information from TLS
+ SCLASSINFO *pClsInfo;
+ ULONG cClasses;
+
+ RecallClasses(&pClsInfo, &cClasses);
+
+ // now release each of the class factories
+ for (ULONG i=0; i<cClasses; i++, pClsInfo++)
+ {
+ ULONG ulRef = pClsInfo->pCF->Release();
+ Display(TEXT("CF RefCnt = %x\n"), ulRef);
+ }
+
+ // now remove the class information from TLS
+ ForgetClasses();
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: GlobalRefs
+//
+// Synopsis: keeps track of global reference couting. Revokes all the
+// classes when the global count reaches 0.
+//
+// History: 06-Aug-92 Ricksa Created
+//
+//--------------------------------------------------------------------------
+void GlobalRefs(BOOL fAddRef)
+{
+ if (fAddRef)
+ {
+ g_Usage = CoAddRefServerProcess();
+ Display(TEXT("Object Count: %ld\n"), g_Usage);
+ }
+ else
+ {
+ if (0 == (g_Usage = CoReleaseServerProcess()))
+ {
+ // No more objects so we can quit
+ Display(TEXT("Object Server Exiting\n"));
+ PostMessage((HWND)g_hMain, WM_TERM_WND, 0, 0);
+ }
+ }
+}
+
+//+-------------------------------------------------------------------
+//
+// Function: SrvMain
+//
+// Synopsis: Special entry point for registing just 1 class.
+//
+// History: 21-Nov-92 SarahJ Created
+//
+//--------------------------------------------------------------------
+int SrvMain(
+ HANDLE hInstance,
+ REFCLSID rclsid,
+ DWORD dwClsReg,
+ TCHAR *pszAppName,
+ IClassFactory *pCF)
+{
+ SCLASSINFO clsinfo;
+ clsinfo.clsid = rclsid;
+ clsinfo.dwCtx = CLSCTX_LOCAL_SERVER,
+ clsinfo.dwClsReg = dwClsReg;
+ clsinfo.pCF = pCF;
+ clsinfo.dwReg = 0;
+
+ STHREADINFO ThrdInfo;
+ ThrdInfo.hEventRun = CreateEvent(NULL, FALSE, FALSE, NULL);
+ ThrdInfo.hEventDone = CreateEvent(NULL, FALSE, FALSE, NULL);
+ ThrdInfo.hInstance = (HINSTANCE)hInstance;
+ ThrdInfo.dwTid = GetCurrentThreadId();
+ ThrdInfo.pszWindow = pszAppName;
+ ThrdInfo.dwFlags = SRVF_THREADMODEL_UNKNOWN;
+ ThrdInfo.cClasses = 1;
+ ThrdInfo.pClsInfo = &clsinfo;
+
+ return SrvMain2(&ThrdInfo);
+}
+
+//+-------------------------------------------------------------------
+//
+// Function: SrvMain2
+//
+// Synopsis: Main entry point for registering classes, entering modal
+// loop, and cleaning up on exit.
+//
+// History: 21-Nov-92 SarahJ Created
+//
+//--------------------------------------------------------------------
+int SrvMain2(STHREADINFO *pThrdInfo)
+{
+ MakeTheWindow(pThrdInfo->hInstance, pThrdInfo->pszWindow);
+
+ // Initialize the OLE libraries
+ DWORD dwThreadMode = COINIT_APARTMENTTHREADED;
+
+ if (pThrdInfo->dwFlags & SRVF_THREADMODEL_UNKNOWN)
+ {
+ // Look up the thread mode from the win.ini file.
+ TCHAR buffer[80];
+ int len;
+
+ len = GetProfileString( TEXT("OleSrv"),
+ TEXT("ThreadMode"),
+ TEXT("MultiThreaded"),
+ buffer,
+ sizeof(buffer) );
+
+ if (lstrcmp(buffer, TEXT("ApartmentThreaded")) != 0)
+ dwThreadMode = COINIT_MULTITHREADED;
+ }
+ else if (pThrdInfo->dwFlags & SRVF_THREADMODEL_MULTI)
+ {
+ dwThreadMode = COINIT_MULTITHREADED;
+ }
+
+
+ HRESULT hr = CoInitializeEx(NULL, dwThreadMode);
+
+ if (SUCCEEDED(hr))
+ {
+ // registe all the classes
+ RegisterAllClasses(pThrdInfo->pClsInfo, pThrdInfo->cClasses);
+ }
+ else
+ {
+ Display(TEXT("ERROR: failed OleInitialize %x\n"), hr);
+ }
+
+ if (pThrdInfo->dwFlags & SRVF_REGISTER_RESUME)
+ {
+ hr = CoResumeClassObjects();
+ }
+
+ // notify the main thread we are running now
+ SetEvent(pThrdInfo->hEventRun);
+
+
+ // Message processing loop
+ MSG msg;
+ while (GetMessage (&msg, NULL, 0, 0))
+ {
+ TranslateMessage (&msg);
+ DispatchMessage (&msg);
+ }
+
+
+ // revoke the classes again incase we missed any (eg. no instances
+ // were created, the user just closed the app).
+ RevokeAllClasses();
+
+ // release the classes
+ ReleaseAllClasses();
+
+ // Tell OLE we are going away.
+ CoUninitialize();
+
+ // notify the main thread that we are done
+ SetEvent(pThrdInfo->hEventDone);
+
+ return (msg.wParam); /* Returns the value from PostQuitMessage */
+}
diff --git a/private/oleutest/balls/common/srvmain.hxx b/private/oleutest/balls/common/srvmain.hxx
new file mode 100644
index 000000000..fd45be2ee
--- /dev/null
+++ b/private/oleutest/balls/common/srvmain.hxx
@@ -0,0 +1,97 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1991 - 1992.
+//
+// File: srvmain.hxx
+//
+// Contents: headers shared by COM server implementations
+//
+// History: 04-Feb-94 Rickhi Created
+//
+//--------------------------------------------------------------------------
+#ifndef _SRVMAIN_HXX_
+#define _SRVMAIN_HXX_
+
+//+-------------------------------------------------------------------
+//
+// Struct: SCLASSINFO
+//
+// Synopsis: structure used to register class factories. an array of these
+// is passed to SrvMain2 which registers them, enters a message
+// pump, then revokes and releases them on exit.
+//
+//+-------------------------------------------------------------------
+typedef struct tagSCLASSINFO
+{
+ CLSID clsid; // class to register
+ DWORD dwClsReg; // registration parameter
+ DWORD dwCtx; // class context (single/multiple use)
+ IClassFactory *pCF; // class factory object
+ DWORD dwReg; // reg key from CoRegisterClassObject
+} SCLASSINFO;
+
+
+
+// flag values for dwFlags parameter in STHREADINFO (see below)
+typedef enum tagSRVFLAGS
+{
+ SRVF_THREADMODEL_UNKNOWN = 0x0,
+ SRVF_THREADMODEL_APARTMENT = 0x1,
+ SRVF_THREADMODEL_MULTI = 0x2,
+ SRVF_REGISTER_RESUME = 0x4 // call CoResumeClassObjects
+} SRVFLAGS;
+
+//+-------------------------------------------------------------------
+//
+// Struct: STHREADINFO
+//
+// Synopsis: Used to pass execution parameters to threads.
+//
+//+-------------------------------------------------------------------
+typedef struct tagSTHREADINFO
+{
+ HANDLE hEventRun; // thread is done initializing
+ HANDLE hEventDone; // thread is done cleaning up
+ HINSTANCE hInstance;
+ DWORD dwTid; // server thread id
+ TCHAR *pszWindow; // window name
+ DWORD dwFlags; // see SRVFLAGS above
+ ULONG cClasses; // number of classes in SCLASSINFO list
+ SCLASSINFO *pClsInfo; // class registration info list
+} STHREADINFO;
+
+
+
+extern "C" const GUID IID_IStdIdentity;
+extern void Display(TCHAR *pszFmt, ...);
+extern void GlobalRefs(BOOL fAdd);
+
+
+//+-------------------------------------------------------------------
+//
+// Function: SrvMain2
+//
+// Synopsis: Main entry point for a thread.
+//
+//+-------------------------------------------------------------------
+int SrvMain2(STHREADINFO *pThrdInfo);
+
+
+//+-------------------------------------------------------------------
+//
+// Function: SrvMain
+//
+// Synopsis: Alternative entry point for a thread, just packages
+// the parameters and calls SrvMain2.
+//
+//+-------------------------------------------------------------------
+extern int SrvMain(
+ HANDLE hInstance,
+ REFCLSID rclsid,
+ DWORD dwClsRegParm,
+ TCHAR *pwszAppName,
+ IClassFactory *pCF);
+
+
+#endif // _SRVMAIN_HXX_
diff --git a/private/oleutest/balls/common/stream.cxx b/private/oleutest/balls/common/stream.cxx
new file mode 100644
index 000000000..d5c4681bf
--- /dev/null
+++ b/private/oleutest/balls/common/stream.cxx
@@ -0,0 +1,320 @@
+//+-------------------------------------------------------------------
+//
+// File: stream.cxx
+//
+// Contents: Stream interface on flat File.
+//
+// Classes: CStreamOnFile
+//
+// Macros: DEFINE_INTERFACE_XMIT_ROUTINES
+//
+// History: 08-08-95 Rickhi Created
+//
+//--------------------------------------------------------------------
+#include <pch.cxx>
+#pragma hdrstop
+#include <stream.hxx>
+
+
+CStreamOnFile::CStreamOnFile(const TCHAR *pwszFileName, SCODE &sc, BOOL fRead) :
+ _clRefs(1),
+ _hFile(NULL),
+ _lOffset(0),
+ _cSize(0),
+ _cbData(0),
+ _fRead(fRead)
+{
+ _pbData = new BYTE[2048]; // should be big enough
+ if (!_pbData)
+ {
+ sc = E_OUTOFMEMORY;
+ return;
+ }
+
+ _cbData = 2048;
+
+ // open the file.
+ DWORD fdwCreate;
+ if (_fRead)
+ fdwCreate = OPEN_EXISTING; // open existing, fail if not found.
+ else
+ fdwCreate = CREATE_ALWAYS; // overwrite existing if present
+
+
+ _hFile = CreateFile(pwszFileName,
+ GENERIC_READ | GENERIC_WRITE, // fdwAccess
+ FILE_SHARE_READ | FILE_SHARE_WRITE, // fdwShareMode
+ NULL, // lpsaSecurity
+ fdwCreate, // creation options
+ FILE_ATTRIBUTE_NORMAL, // attributes & flags
+ NULL // hTemplateFile
+ );
+
+ if (_hFile == INVALID_HANDLE_VALUE)
+ {
+ sc = HRESULT_FROM_WIN32(GetLastError());
+ return;
+ }
+
+ // read the file into the memory block
+ DWORD cbRead = 0;
+ if (_fRead && ! ReadFile(_hFile,
+ _pbData,
+ _cbData,
+ &cbRead,
+ NULL))
+ {
+ sc = HRESULT_FROM_WIN32(GetLastError());
+ return;
+ }
+
+ if (_fRead)
+ {
+ _cSize = _cbData;
+ }
+
+ sc = S_OK;
+}
+
+CStreamOnFile::~CStreamOnFile(void)
+{
+ if (_hFile)
+ {
+ if (!_fRead)
+ {
+ // write the data to the file
+ DWORD cbWritten = 0;
+ if (!WriteFile(_hFile,
+ _pbData,
+ _cbData,
+ &cbWritten,
+ NULL))
+ {
+ SCODE sc = HRESULT_FROM_WIN32(GetLastError());
+ }
+ }
+
+ CloseHandle(_hFile);
+ }
+}
+
+
+
+STDMETHODIMP CStreamOnFile::QueryInterface(
+ REFIID iidInterface,
+ void FAR* FAR* ppvObj)
+{
+ HRESULT hresult = S_OK;
+
+ // We only support IUnknown and IStream
+ if (IsEqualIID(iidInterface, IID_IUnknown) ||
+ IsEqualIID(iidInterface, IID_IStream))
+ {
+ *ppvObj = this;
+ AddRef();
+ }
+ else
+ {
+ *ppvObj = NULL;
+ hresult = E_NOINTERFACE;
+ }
+
+ return hresult;
+}
+
+STDMETHODIMP_(ULONG) CStreamOnFile::AddRef(void)
+{
+ InterlockedIncrement(&_clRefs);
+ return _clRefs;
+}
+
+STDMETHODIMP_(ULONG) CStreamOnFile::Release(void)
+{
+ if (InterlockedDecrement(&_clRefs) == 0)
+ {
+ delete this;
+ return 0;
+ }
+
+ return _clRefs;
+}
+
+STDMETHODIMP CStreamOnFile::Read(
+ VOID HUGEP* pv,
+ ULONG cb,
+ ULONG FAR* pcbRead)
+{
+ HRESULT hresult = S_OK;
+
+ if (pcbRead)
+ {
+ *pcbRead = 0L;
+ }
+
+ if (cb + _lOffset > _cSize)
+ {
+ cb = _cSize - _lOffset;
+ hresult = STG_E_READFAULT;
+ }
+
+ memcpy(pv, _pbData + _lOffset, (size_t) cb);
+ _lOffset += cb;
+
+ if (pcbRead != NULL)
+ {
+ *pcbRead = cb;
+ }
+
+ return hresult;
+}
+
+STDMETHODIMP CStreamOnFile::Write(
+ VOID const HUGEP* pv,
+ ULONG cbToWrite,
+ ULONG FAR* pcbWritten)
+{
+ HRESULT hresult = S_OK;
+
+ if (pcbWritten)
+ {
+ *pcbWritten = 0L;
+ }
+
+ if (cbToWrite + _lOffset > _cbData)
+ {
+ return E_OUTOFMEMORY;
+ }
+
+ // copy in the new data
+ memcpy(_pbData + _lOffset, pv, (size_t) cbToWrite);
+ _lOffset += cbToWrite;
+
+ if (pcbWritten != NULL)
+ {
+ *pcbWritten = cbToWrite;
+ }
+
+ // We assume maxium size of buffer is the size to send on the network.
+ if (_cSize < _lOffset)
+ {
+ _cSize = _lOffset;
+ }
+
+ return hresult;
+}
+
+
+
+STDMETHODIMP CStreamOnFile::Seek(
+ LARGE_INTEGER dlibMoveIN,
+ DWORD dwOrigin,
+ ULARGE_INTEGER FAR* plibNewPosition)
+{
+ HRESULT hresult = S_OK;
+
+ LONG dlibMove = dlibMoveIN.LowPart;
+ ULONG cbNewPos = dlibMove;
+
+ switch(dwOrigin)
+ {
+ case STREAM_SEEK_SET:
+
+ if (dlibMove >= 0)
+ {
+ _lOffset = dlibMove;
+ }
+ else
+ {
+ hresult = STG_E_SEEKERROR;
+ }
+ break;
+
+ case STREAM_SEEK_CUR:
+
+ if (!(dlibMove < 0 && ((ULONG) -dlibMove > _lOffset)))
+ {
+ _lOffset += (ULONG) dlibMove;
+ }
+ else
+ {
+ hresult = STG_E_SEEKERROR;
+ }
+ break;
+
+ case STREAM_SEEK_END:
+
+ if (!(dlibMove < 0 && ((ULONG) -dlibMove) > _cbData))
+ {
+ _lOffset = _cbData + dlibMove;
+ }
+ else
+ {
+ hresult = STG_E_SEEKERROR;
+ }
+ break;
+
+ default:
+
+ hresult = STG_E_SEEKERROR;
+ }
+
+ if (plibNewPosition != NULL)
+ {
+ ULISet32(*plibNewPosition, _lOffset);
+ }
+
+ return hresult;
+}
+
+STDMETHODIMP CStreamOnFile::SetSize(ULARGE_INTEGER cb)
+{
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP CStreamOnFile::CopyTo(
+ IStream FAR* pstm,
+ ULARGE_INTEGER cb,
+ ULARGE_INTEGER FAR* pcbRead,
+ ULARGE_INTEGER FAR* pcbWritten)
+{
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP CStreamOnFile::Commit(DWORD grfCommitFlags)
+{
+ return NOERROR;
+}
+
+STDMETHODIMP CStreamOnFile::Revert(void)
+{
+ return NOERROR;
+}
+
+STDMETHODIMP CStreamOnFile::LockRegion(
+ ULARGE_INTEGER libOffset,
+ ULARGE_INTEGER cb,
+ DWORD dwLockType)
+{
+ return STG_E_INVALIDFUNCTION;
+}
+
+STDMETHODIMP CStreamOnFile::UnlockRegion(
+ ULARGE_INTEGER libOffset,
+ ULARGE_INTEGER cb,
+ DWORD dwLockType)
+{
+ return STG_E_INVALIDFUNCTION;
+}
+
+STDMETHODIMP CStreamOnFile::Stat(
+ STATSTG FAR* pstatstg,
+ DWORD statflag)
+{
+ memset(pstatstg, 0, sizeof(STATSTG));
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP CStreamOnFile::Clone(IStream FAR * FAR *ppstm)
+{
+ return E_NOTIMPL;
+}
diff --git a/private/oleutest/balls/common/stream.hxx b/private/oleutest/balls/common/stream.hxx
new file mode 100644
index 000000000..af947a26b
--- /dev/null
+++ b/private/oleutest/balls/common/stream.hxx
@@ -0,0 +1,97 @@
+//+-------------------------------------------------------------------
+//
+// File: stream.hxx
+//
+// Contents: Stream class on a file.
+//
+// Classes: CStreamOnFile
+//
+// History: 08-08-95 Rickhi Created
+//
+//--------------------------------------------------------------------
+#ifndef __STREAMONFILE_HXX__
+#define __STREAMONFILE_HXX__
+
+
+//+-------------------------------------------------------------------
+//
+// Class: CStreamOnFile
+//
+// Purpose: Stream wrapper for a flat file.
+//
+// History: 30-Jan-93 Ricksa Created
+//
+//--------------------------------------------------------------------
+class CStreamOnFile : public IStream
+{
+public:
+ CStreamOnFile(const TCHAR *pwszFileName, SCODE &sc, BOOL fRead);
+
+ ~CStreamOnFile(void);
+
+ STDMETHOD(QueryInterface)(
+ REFIID iidInterface,
+ void FAR* FAR* ppvObj);
+
+ STDMETHOD_(ULONG,AddRef)(void);
+
+ STDMETHOD_(ULONG,Release)(void);
+
+ STDMETHOD(Read)(
+ VOID HUGEP* pv,
+ ULONG cb,
+ ULONG FAR* pcbRead);
+
+ STDMETHOD(Write)(
+ VOID const HUGEP* pv,
+ ULONG cb,
+ ULONG FAR* pcbWritten);
+
+ STDMETHOD(Seek)(
+ LARGE_INTEGER dlibMove,
+ DWORD dwOrigin,
+ ULARGE_INTEGER FAR* plibNewPosition);
+
+ STDMETHOD(SetSize) (ULARGE_INTEGER cb);
+
+ STDMETHOD(CopyTo)(
+ IStream FAR* pstm,
+ ULARGE_INTEGER cb,
+ ULARGE_INTEGER FAR* pcbRead,
+ ULARGE_INTEGER FAR* pcbWritten);
+
+ STDMETHOD(Commit)(DWORD grfCommitFlags);
+
+ STDMETHOD(Revert)(void);
+
+ STDMETHOD(LockRegion)(
+ ULARGE_INTEGER libOffset,
+ ULARGE_INTEGER cb,
+ DWORD dwLockType);
+
+ STDMETHOD(UnlockRegion)(
+ ULARGE_INTEGER libOffset,
+ ULARGE_INTEGER cb,
+ DWORD dwLockType);
+
+ STDMETHOD(Stat)(
+ STATSTG FAR* pstatstg,
+ DWORD statflag);
+
+ STDMETHOD(Clone)(IStream FAR * FAR *ppstm);
+
+private:
+
+ LONG _clRefs; // reference count
+ HANDLE _hFile; // file handle
+ BOOL _fRead; // read or write side
+
+ ULONG _lOffset; // current seek ptr
+ ULONG _cSize; // number of bytes written
+
+ ULONG _cbData; // size of data
+ BYTE *_pbData; // ptr to data
+
+};
+
+#endif // _STREAMONFILE_HXX__
diff --git a/private/oleutest/balls/common/tstmain.cxx b/private/oleutest/balls/common/tstmain.cxx
new file mode 100644
index 000000000..a7fc2febb
--- /dev/null
+++ b/private/oleutest/balls/common/tstmain.cxx
@@ -0,0 +1,178 @@
+//+------------------------------------------------------------------
+//
+// File: tmain.cxx
+//
+// Contents: entry point common for all test drivers.
+//
+//--------------------------------------------------------------------
+#include <pch.cxx>
+#include <tstmain.hxx>
+#include <regmain.hxx>
+
+BOOL fQuiet = 0; // turn tracing on/off
+DWORD gInitFlag; // current COINT flag used on main thread.
+
+DWORD dwInitFlag[2] = {COINIT_APARTMENTTHREADED,
+ COINIT_MULTITHREADED};
+
+LPSTR pszInitFlag[2] = {"ApartmentThreaded",
+ "MultiThreaded"};
+
+
+// global statistics counters
+LONG gCountAttempts = 0; // # of tests attempted
+LONG gCountPassed = 0; // # of tests passed
+LONG gCountFailed = 0; // # of tests failed
+
+void InitStatistics();
+void PrintStatistics();
+
+//+-------------------------------------------------------------------
+//
+// Function: DriverMain
+//
+// Synopsis: Entry point to EXE
+//
+// Returns: TRUE
+//
+// History: 21-Nov-92 Rickhi Created
+//
+// Parses parameters, sets the threading model, initializes OLE,
+// runs the test, Uninitializes OLE, reports PASSED/FAILED.
+//
+//--------------------------------------------------------------------
+int _cdecl DriverMain(int argc, char **argv, char *pszTestName, LPFNTEST pfnTest)
+{
+ char *pszAppName = *argv;
+
+ // default to running both single-thread and multi-thread
+ int iStart = 0;
+ int iEnd = 2;
+
+
+ // process the command line args
+ if (argc > 1)
+ {
+ for (int i=argc; i>0; i--, argv++)
+ {
+ if (!_strnicmp(*argv, "-r", 2))
+ {
+ // register class information
+ RegistrySetup(pszAppName);
+ return 0;
+ }
+ else if (!_strnicmp(*argv, "-q", 2))
+ {
+ // quiet output
+ fQuiet = TRUE;
+ }
+ else if (!_strnicmp(*argv, "-s", 2))
+ {
+ // just run single-threaded
+ iStart = 0;
+ iEnd = 1;
+ }
+ else if (!_strnicmp(*argv, "-m", 2))
+ {
+ // just run multi-threaded
+ iStart = 1;
+ iEnd = 2;
+ }
+ }
+ }
+
+
+ // run the tests.
+ for (int i=iStart; i<iEnd; i++)
+ {
+ InitStatistics();
+
+ WriteProfileStringA("OleSrv",
+ "ThreadMode",
+ pszInitFlag[i]);
+
+ printf ("Starting %s Test with %s threading model\n",
+ pszTestName, pszInitFlag[i]);
+
+ gInitFlag = dwInitFlag[i];
+ SCODE sc = CoInitializeEx(NULL, gInitFlag);
+
+ if (sc != S_OK)
+ {
+ printf("CoInitializeEx Failed with %lx\n", sc);
+ DebugBreak();
+ return 1;
+ }
+
+ BOOL fRslt = (pfnTest)();
+
+ PrintStatistics();
+
+ if (fRslt)
+ printf("%s Tests PASSED\n", pszTestName);
+ else
+ printf("%s Tests FAILED\n", pszTestName);
+
+ CoUninitialize();
+ }
+
+ return 0;
+}
+
+//+-------------------------------------------------------------------
+//
+// Function: TestResult
+//
+// Synopsis: prints test results
+//
+// History: 21-Nov-92 Rickhi Created
+//
+//--------------------------------------------------------------------
+BOOL TestResult(BOOL RetVal, LPSTR pszTestName)
+{
+ gCountAttempts++;
+
+ if (RetVal == TRUE)
+ {
+ printf ("PASSED: %s\n", pszTestName);
+ gCountPassed++;
+ }
+ else
+ {
+ printf ("FAILED: %s\n", pszTestName);
+ gCountFailed++;
+ }
+
+ return RetVal;
+}
+
+//+-------------------------------------------------------------------
+//
+// Function: InitStatistics
+//
+// Synopsis: Initializes run statistics
+//
+// History: 21-Nov-92 Rickhi Created
+//
+//--------------------------------------------------------------------
+void InitStatistics()
+{
+ gCountAttempts = 0;
+ gCountPassed = 0;
+ gCountFailed = 0;
+}
+
+//+-------------------------------------------------------------------
+//
+// Function: PrintStatistics
+//
+// Synopsis: Prints run statistics
+//
+// History: 21-Nov-92 Rickhi Created
+//
+//--------------------------------------------------------------------
+void PrintStatistics()
+{
+ printf("\nTEST STATISTICS -- Attempted:%d Passed:%d Failed:%d\n\n",
+ gCountAttempts, gCountPassed, gCountFailed);
+}
diff --git a/private/oleutest/balls/common/tstmain.hxx b/private/oleutest/balls/common/tstmain.hxx
new file mode 100644
index 000000000..302a85fea
--- /dev/null
+++ b/private/oleutest/balls/common/tstmain.hxx
@@ -0,0 +1,49 @@
+//+------------------------------------------------------------------
+//
+// File: tmain.hxx
+//
+// Contents: common include file for all test drivers.
+//
+//--------------------------------------------------------------------
+#include <windows.h>
+#include <ole2.h>
+#include <stdio.h>
+
+extern BOOL fQuiet; // turn tracing on/off
+extern DWORD gInitFlag; // current COINT flag used on main thread.
+
+// definition of ptr to test subroutine
+typedef BOOL (* LPFNTEST)(void);
+
+// driver entry point
+int _cdecl DriverMain(int argc, char **argv,
+ char *pszTestName,
+ LPFNTEST pfnTest);
+
+BOOL TestResult(BOOL RetVal, LPSTR pszTestName);
+
+
+// macros
+#define TEST_FAILED_EXIT(x, y) \
+ if (x) \
+ { \
+ printf("ERROR: ");\
+ printf(y); \
+ RetVal = FALSE; \
+ goto Cleanup; \
+ }
+
+#define TEST_FAILED(x, y) \
+ if (x) \
+ { \
+ printf("ERROR: ");\
+ printf(y); \
+ RetVal = FALSE; \
+ }
+
+#define OUTPUT(x) if (!fQuiet) printf(x);
+
+// global statistics
+extern LONG gCountAttempts;
+extern LONG gCountPassed;
+extern LONG gCountFailed;
diff --git a/private/oleutest/balls/common/win4p.hxx b/private/oleutest/balls/common/win4p.hxx
new file mode 100644
index 000000000..49a56c473
--- /dev/null
+++ b/private/oleutest/balls/common/win4p.hxx
@@ -0,0 +1,3 @@
+
+#include <windows.h>
+#include <ole2.h>
diff --git a/private/oleutest/balls/common/wterm.c b/private/oleutest/balls/common/wterm.c
new file mode 100644
index 000000000..359f98f36
--- /dev/null
+++ b/private/oleutest/balls/common/wterm.c
@@ -0,0 +1,1027 @@
+/****************************************************************************
+
+ PROGRAM: wterm.c
+
+ PURPOSE: Implementation of TermWClass Windows
+
+ FUNCTIONS:
+
+
+ COMMENTS:
+
+
+****************************************************************************/
+
+#include "windows.h"
+#include "stdlib.h"
+#include "memory.h"
+#include "wterm.h"
+
+#define MAX_ROWS 24
+#define MAX_COLS 80
+
+typedef struct WData
+{
+ // Function to execute for processing a menu
+ MFUNCP pMenuProc;
+
+ // Function to execute for processing a single character
+ CFUNCP pCharProc;
+
+ // Function to execute when window is closed (terminated)
+ TFUNCP pCloseProc;
+
+ // Pass on callback
+ void *pvCallBackData;
+
+ BOOL fGotFocus;
+
+ BOOL fCaretHidden;
+
+ // Rows on the screen
+ int cRows;
+
+ // Columns on the screen
+ int cCols;
+
+ // Row at top of screen
+ int iTopRow;
+
+ // Row at bottom of the screen
+ int iBottomRow;
+
+ // First Column on screen
+ int iFirstCol;
+
+ // Column at bottom of the screen
+ int iBottomCol;
+
+ // Row for next character
+ int iNextRow;
+
+ // Row for next column
+ int iNextCol;
+
+ // Width of character
+ int cxChar;
+
+ // Height of character
+ int cyChar;
+
+ // Memory image of screen this is treated as a circular buffer
+ TCHAR aImage[MAX_ROWS] [MAX_COLS];
+
+ // First row in circular screen buffer
+ int iBufferTop;
+} WData;
+
+static HANDLE hInst = 0;
+TCHAR BlankLine[80];
+
+static int
+row_diff(
+ int row1,
+ int row2)
+{
+ return (row2 > row1)
+ ? MAX_ROWS - (row2 - row1)
+ : row1 - row2;
+}
+
+static void
+set_vscroll_pos(
+ HWND hwnd,
+ WData *pwdata)
+{
+ if (pwdata->cRows != 0)
+ {
+ // Save a few indirections by caching cRows
+ register int cRows = pwdata->cRows;
+
+ // calculate distance bottom of screen from top of data buffer
+ register int top_from_row = row_diff(pwdata->iBottomRow,
+ pwdata->iBufferTop);
+
+ // Output position of scroll bar
+ int new_pos = 0;
+
+ if (top_from_row >= cRows)
+ {
+ // Calculate number of screens to display entire buffer
+ int screens_for_data = MAX_ROWS / cRows
+ + ((MAX_ROWS % cRows != 0) ? 1 : 0);
+
+ // Figure out which screen the row falls in
+ int screen_loc = top_from_row / cRows
+ + ((top_from_row % cRows != 0) ? 1 : 0);
+
+ // If the screen is in the last one set box to max
+ new_pos = (screen_loc == screens_for_data)
+ ? MAX_ROWS : screen_loc * cRows;
+ }
+
+ SetScrollPos(hwnd, SB_VERT, new_pos, TRUE);
+ }
+}
+
+static int
+calc_row(
+ register int row,
+ WData *pwdata)
+{
+ register int top = pwdata->iTopRow;
+ static int boopa = 0;
+
+ if (top > row)
+ boopa++;
+
+ return (row >= top) ? row - top : (MAX_ROWS - (top - row));
+}
+
+static void
+display_text(
+ HWND hwnd,
+ int row,
+ int col,
+ LPTSTR text,
+ int text_len,
+ WData *pWData)
+{
+ // Get the DC to display the text
+ HDC hdc = GetDC(hwnd);
+
+ // Select Font
+ SelectObject(hdc, GetStockObject(SYSTEM_FIXED_FONT));
+
+ // Hide caret while we are printing
+ HideCaret(hwnd);
+
+ // Update the screen
+ TextOut(hdc, (col - pWData->iFirstCol) * pWData->cxChar,
+ calc_row(row, pWData) * pWData->cyChar, text, text_len);
+
+ // Done with DC
+ ReleaseDC(hwnd, hdc);
+
+ // Put the caret back now that we are done
+ ShowCaret(hwnd);
+}
+
+static void
+display_char(
+ HWND hwnd,
+ TCHAR char_to_display,
+ WData *pWData)
+{
+ // Update image buffer
+ pWData->aImage[pWData->iNextRow][pWData->iNextCol] = char_to_display;
+
+ display_text(hwnd, pWData->iNextRow, pWData->iNextCol,
+ &char_to_display, 1, pWData);
+}
+
+static void
+do_backspace(
+ HWND hwnd,
+ WData *pWData)
+{
+ // Point to the previous character in the line
+ if (--pWData->iNextCol < 0)
+ {
+ // Can't backspace beyond the current line
+ pWData->iNextCol = 0;
+ return;
+ }
+
+ display_char(hwnd, ' ', pWData);
+
+ // Null character for repaint
+ pWData->aImage[pWData->iNextRow][pWData->iNextCol] = '\0';
+}
+
+static int
+inc_row(
+ int row,
+ int increment)
+{
+ row += increment;
+
+ if (row >= MAX_ROWS)
+ {
+ row -= MAX_ROWS;
+ }
+ else if (row < 0)
+ {
+ row += MAX_ROWS;
+ }
+
+ return row;
+}
+
+void
+inc_next_row(
+ HWND hwnd,
+ WData *pWData)
+{
+ if (pWData->iNextRow == pWData->iBottomRow)
+ {
+ // Line is at bottom -- scroll the client area one row
+ ScrollWindow(hwnd, 0, -pWData->cyChar, NULL, NULL);
+
+ // Increment the top & bottom of the screen
+ pWData->iTopRow = inc_row(pWData->iTopRow, 1);
+ pWData->iBottomRow = inc_row(pWData->iBottomRow, 1);
+ }
+
+ // Increment the row
+ pWData->iNextRow = inc_row(pWData->iNextRow, 1);
+
+ if (pWData->iNextRow == pWData->iBufferTop)
+ {
+ // Have to reset circular buffer to next
+ pWData->iBufferTop = inc_row(pWData->iBufferTop, 1);
+
+ // Reset line to nulls for repaint
+ memset(&pWData->aImage[pWData->iNextRow][0], '\0', MAX_COLS);
+ }
+
+ pWData->iNextCol = 0;
+}
+
+static void
+do_cr(
+ HWND hwnd,
+ WData *pWData)
+{
+ // Set position to next row
+ inc_next_row(hwnd, pWData);
+ pWData->iNextCol = 0;
+
+ // Make sure next character is null for repaint of line
+ pWData->aImage[pWData->iNextRow][pWData->iNextCol] = '\0';
+
+ // Update the vertical scroll bar's position
+ set_vscroll_pos(hwnd, pWData);
+}
+
+static void
+do_char(
+ HWND hwnd,
+ WPARAM wParam,
+ WData *pWData)
+{
+ display_char(hwnd, (TCHAR) wParam, pWData);
+
+ // Point to the next character in the line
+ if (++pWData->iNextCol > MAX_COLS)
+ {
+ // Handle switch to next line
+ inc_next_row(hwnd, pWData);
+ }
+}
+
+static void
+do_tab(
+ HWND hwnd,
+ WData *pWData)
+{
+ int c = pWData->iNextCol % 8;
+
+ if ((pWData->iNextCol + c) <= MAX_COLS)
+ {
+ for ( ; c; c--)
+ {
+ do_char(hwnd, ' ', pWData);
+ }
+ }
+ else
+ {
+ do_cr(hwnd, pWData);
+ }
+}
+
+static void
+EchoChar(
+ HWND hwnd,
+ WORD cRepeats,
+ WPARAM wParam,
+ WData *pWData)
+{
+ for ( ; cRepeats; cRepeats--)
+ {
+ switch (wParam)
+ {
+ // Backspace
+ case '\b':
+ do_backspace(hwnd, pWData);
+ break;
+
+ // Carriage return
+ case '\n':
+ case '\r':
+ do_cr(hwnd, pWData);
+ break;
+
+ // Tab
+ case '\t':
+ do_tab(hwnd, pWData);
+ break;
+
+ // Regular characters
+ default:
+ do_char(hwnd, wParam, pWData);
+ }
+ }
+
+ // The row is guaranteed to be on the screen because we will
+ // scroll on a CR. However, the next column for input may be
+ // beyond the window we are working in.
+ if (pWData->iNextCol > pWData->iBottomCol)
+ {
+ // We are out of the window so scroll the window one
+ // column to the right.
+ SendMessage(hwnd, WM_HSCROLL, SB_LINEDOWN, 0L);
+ }
+ else if (pWData->iNextCol < pWData->iFirstCol)
+ {
+ // We are out of the window so repaint the window using
+ // iNextCol as the first column for the screen.
+ pWData->iFirstCol = pWData->iNextCol;
+ pWData->iBottomCol = pWData->iFirstCol + pWData->cCols - 1;
+
+ // Reset scroll bar
+ SetScrollPos(hwnd, SB_HORZ, pWData->iFirstCol, TRUE);
+
+ // Tell window to update itself.
+ InvalidateRect(hwnd, NULL, TRUE);
+ UpdateWindow(hwnd);
+ }
+ else
+ {
+ // Reset Caret's position
+ SetCaretPos((pWData->iNextCol - pWData->iFirstCol) * pWData->cxChar,
+ calc_row(pWData->iNextRow, pWData) * pWData->cyChar);
+ }
+}
+
+/****************************************************************************
+
+ FUNCTION: WmCreate(HWND)
+
+ PURPOSE: Initializes control structures for a TermWClass Window
+
+ MESSAGES:
+ WM_CREATE
+
+ COMMENTS:
+
+ This prepares a window for processing character based
+ I/O. In particular it does stuff like calculate the
+ size of the window needed.
+
+****************************************************************************/
+static void
+WmCreate(
+ HWND hwnd,
+ CREATESTRUCT *pInit)
+{
+ WData *pData = (WData *) (pInit->lpCreateParams);
+ HDC hdc = GetDC(hwnd);
+ TEXTMETRIC tm;
+
+ // Store pointer to window data
+ SetWindowLong(hwnd, 0, (LONG) pData);
+
+ // Set font to system fixed font
+ SelectObject(hdc, GetStockObject(SYSTEM_FIXED_FONT));
+
+ // Calculate size of a character
+ GetTextMetrics(hdc, &tm);
+ pData->cxChar = tm.tmAveCharWidth;
+ pData->cyChar = tm.tmHeight;
+ ReleaseDC(hwnd, hdc);
+
+ // Set up vertical scroll bars
+ SetScrollRange(hwnd, SB_VERT, 0, MAX_ROWS, TRUE);
+ SetScrollPos(hwnd, SB_VERT, 0, TRUE);
+
+ // Set up horizontal scroll bars
+ SetScrollRange(hwnd, SB_HORZ, 0, MAX_COLS, TRUE);
+ SetScrollPos(hwnd, SB_HORZ, 0, TRUE);
+}
+
+/****************************************************************************
+
+ FUNCTION: WmSize(HWND, WORD, LONG)
+
+ PURPOSE: Processes a size message
+
+ MESSAGES:
+
+ COMMENTS:
+
+****************************************************************************/
+static void
+WmSize(
+ HWND hwnd,
+ WPARAM wParam,
+ LONG lParam,
+ WData *pwdata)
+{
+ // Get the new size of the window
+ int cxClient;
+ int cyClient;
+ int cRowChange = pwdata->cRows;
+ RECT rect;
+
+ // Get size of client area
+ GetClientRect(hwnd, &rect);
+
+ // Calculate size of client area
+ cxClient = rect.right - rect.left;
+ cyClient = rect.bottom - rect.top;
+
+ // Calculate size of area in rows
+ pwdata->cCols = cxClient / pwdata->cxChar;
+ pwdata->cRows = min(MAX_ROWS, cyClient / pwdata->cyChar);
+ pwdata->iBottomCol = min(pwdata->iFirstCol + pwdata->cCols, MAX_COLS);
+ cRowChange = pwdata->cRows - cRowChange;
+
+ // Keep input line toward bottom of screen
+ if (cRowChange < 0)
+ {
+ // Screen has shrunk in size.
+ if (pwdata->iNextRow != pwdata->iTopRow)
+ {
+ // Has input row moved out of screen?
+ if (row_diff(pwdata->iNextRow, pwdata->iTopRow) >= pwdata->cRows)
+ {
+ // Yes -- Calculate top new top that puts input line on
+ // the bottom.
+ pwdata->iTopRow =
+ inc_row(pwdata->iNextRow, 1 - pwdata->cRows);
+ }
+ }
+ }
+ else
+ {
+ // Screen has gotten bigger -- Display more text if possible
+ if (pwdata->iTopRow != pwdata->iBufferTop)
+ {
+ pwdata->iTopRow = inc_row(pwdata->iTopRow,
+ -(min(row_diff(pwdata->iTopRow, pwdata->iBufferTop),
+ cRowChange)));
+ }
+ }
+
+ // Calculate new bottom
+ pwdata->iBottomRow = inc_row(pwdata->iTopRow, pwdata->cRows - 1);
+
+ InvalidateRect(hwnd, NULL, TRUE);
+ UpdateWindow(hwnd);
+}
+
+static void
+WmSetFocus(
+ HWND hwnd,
+ WData *pwdata)
+{
+ // save indirections
+ register int cxchar = pwdata->cxChar;
+ register int cychar = pwdata->cyChar;
+ pwdata->fGotFocus = TRUE;
+ CreateCaret(hwnd, NULL, cxchar, cychar);
+
+ if (!pwdata->fCaretHidden)
+ {
+ SetCaretPos(pwdata->iNextCol * cxchar,
+ calc_row(pwdata->iNextRow, pwdata) * cychar);
+ }
+
+ ShowCaret(hwnd);
+}
+
+static void
+WmKillFocus(
+ HWND hwnd,
+ WData *pwdata)
+{
+ pwdata->fGotFocus = FALSE;
+
+ if (!pwdata->fCaretHidden)
+ {
+ HideCaret(hwnd);
+ }
+
+ DestroyCaret();
+}
+
+static void
+WmVscroll(
+ HWND hwnd,
+ WPARAM wParam,
+ LONG lParam,
+ WData *pwdata)
+{
+ int cVscrollInc = 0;
+ register int top_diff = row_diff(pwdata->iTopRow, pwdata->iBufferTop);
+ register int bottom_diff = MAX_ROWS - (top_diff + pwdata->cRows);
+
+ switch(wParam)
+ {
+ case SB_TOP:
+
+ if (top_diff != 0)
+ {
+ cVscrollInc = -top_diff;
+ }
+
+ break;
+
+ case SB_BOTTOM:
+
+ if (bottom_diff != 0)
+ {
+ cVscrollInc = bottom_diff;
+ }
+
+ break;
+
+ case SB_LINEUP:
+
+ if (top_diff != 0)
+ {
+ cVscrollInc = -1;
+ }
+
+ break;
+
+ case SB_LINEDOWN:
+
+ if (bottom_diff != 0)
+ {
+ cVscrollInc = 1;
+ }
+
+ break;
+
+ case SB_PAGEUP:
+
+ if (top_diff != 0)
+ {
+ cVscrollInc = - ((top_diff > pwdata->cRows)
+ ? pwdata->cRows : top_diff);
+ }
+
+ break;
+
+ case SB_PAGEDOWN:
+
+ if (bottom_diff != 0)
+ {
+ cVscrollInc = (bottom_diff > pwdata->cRows)
+ ? pwdata->cRows : bottom_diff;
+ }
+
+ break;
+
+ case SB_THUMBTRACK:
+
+ if (LOWORD(lParam) != 0)
+ {
+ cVscrollInc = LOWORD(lParam)
+ - row_diff(pwdata->iTopRow, pwdata->iBufferTop);
+ }
+ }
+
+ // Cacluate new top row
+ if (cVscrollInc != 0)
+ {
+ // Calculate new top and bottom
+ pwdata->iTopRow = inc_row(pwdata->iTopRow, cVscrollInc);
+ pwdata->iBottomRow = inc_row(pwdata->iTopRow, pwdata->cRows);
+
+ // Scroll window
+ ScrollWindow(hwnd, 0, pwdata->cyChar * cVscrollInc, NULL, NULL);
+
+ // Reset scroll bar
+ set_vscroll_pos(hwnd, pwdata);
+
+ // Tell window to update itself.
+ InvalidateRect(hwnd, NULL, TRUE);
+ UpdateWindow(hwnd);
+ }
+}
+
+static void
+WmHscroll(
+ HWND hwnd,
+ WPARAM wParam,
+ LONG lParam,
+ WData *pwdata)
+{
+ register int cHscrollInc = 0;
+
+ switch(wParam)
+ {
+ case SB_LINEUP:
+
+ cHscrollInc = -1;
+ break;
+
+ case SB_LINEDOWN:
+
+ cHscrollInc = 1;
+ break;
+
+ case SB_PAGEUP:
+
+ cHscrollInc = -8;
+ break;
+
+ case SB_PAGEDOWN:
+
+ cHscrollInc = 8;
+ break;
+
+ case SB_THUMBTRACK:
+
+ if (LOWORD(lParam) != 0)
+ {
+ cHscrollInc = LOWORD(lParam) - pwdata->iFirstCol;
+ }
+ }
+
+ if (cHscrollInc != 0)
+ {
+ // Cacluate new first column
+ register int NormalizedScrollInc = cHscrollInc + pwdata->iFirstCol;
+
+ if (NormalizedScrollInc < 0)
+ {
+ cHscrollInc = -pwdata->iFirstCol;
+ }
+ else if (NormalizedScrollInc > MAX_COLS - pwdata->cCols)
+ {
+ cHscrollInc = (MAX_COLS - pwdata->cCols) - pwdata->iFirstCol;
+ }
+
+ pwdata->iFirstCol += cHscrollInc;
+ pwdata->iBottomCol = pwdata->iFirstCol + pwdata->cCols - 1;
+
+ // Scroll window
+ ScrollWindow(hwnd, -(pwdata->cxChar * cHscrollInc), 0, NULL, NULL);
+
+ // Reset scroll bar
+ SetScrollPos(hwnd, SB_HORZ, pwdata->iFirstCol, TRUE);
+
+ // Tell window to update itself.
+ InvalidateRect(hwnd, NULL, TRUE);
+ UpdateWindow(hwnd);
+ }
+}
+
+static void
+WmPaint(
+ HWND hwnd,
+ WData *pwdata)
+{
+ PAINTSTRUCT ps;
+ HDC hdc = BeginPaint(hwnd, &ps);
+ register int row = pwdata->iTopRow;
+ register int col = pwdata->iFirstCol;
+ int bottom_row = pwdata->iBottomRow;
+ int cxChar = pwdata->cxChar;
+ int cyChar = pwdata->cyChar;
+ int y;
+
+ // Select System Font
+ SelectObject(hdc, GetStockObject(SYSTEM_FIXED_FONT));
+
+ while (TRUE)
+ {
+ int len = lstrlen(&pwdata->aImage[row][col]);
+
+ if (len != 0)
+ {
+ y = calc_row(row, pwdata) * cyChar;
+ TextOut(hdc, 0, y, &pwdata->aImage[row][col], len);
+ }
+
+ if (row == bottom_row)
+ {
+ break;
+ }
+
+ row = inc_row(row, 1);
+ }
+
+ if (pwdata->fGotFocus)
+ {
+ if ((pwdata->iNextCol >= pwdata->iFirstCol)
+ && (row_diff(pwdata->iNextRow, pwdata->iTopRow) < pwdata->cRows))
+ {
+ if (pwdata->fCaretHidden)
+ {
+ pwdata->fCaretHidden = FALSE;
+ ShowCaret(hwnd);
+ }
+
+ SetCaretPos(
+ (pwdata->iNextCol - pwdata->iFirstCol) * pwdata->cxChar,
+ calc_row(pwdata->iNextRow, pwdata) * pwdata->cyChar);
+ }
+ else
+ {
+ if (!pwdata->fCaretHidden)
+ {
+ pwdata->fCaretHidden = TRUE;
+ HideCaret(hwnd);
+ }
+ }
+ }
+
+ EndPaint(hwnd, &ps);
+}
+
+
+
+
+
+//
+// FUNCTION: WmPrintLine
+//
+// PURPOSE: Print a line on the screen.
+//
+// Note: this is a user message not an intrinsic Window's message.
+//
+void
+WmPrintLine(
+ HWND hwnd,
+ WPARAM wParam,
+ LONG lParam,
+ WData *pTermData)
+{
+ TCHAR *pBuf = (TCHAR *) lParam;
+
+ // MessageBox(hwnd, L"WmPrintLine", L"Debug", MB_OK);
+
+ // DebugBreak();
+
+ while (wParam--)
+ {
+ // Is character a lf?
+ if (*pBuf == '\n')
+ {
+ // Convert to cr since that is what this window uses
+ *pBuf = '\r';
+ }
+
+ // Write the character to the window
+ EchoChar(hwnd, 1, *pBuf++, pTermData);
+ }
+
+}
+
+//
+// FUNCTION: WmPutc
+//
+// PURPOSE: Print a single character on the screen
+//
+// Note: this is a user message not an intrinsic Window's message.
+//
+void
+WmPutc(
+ HWND hwnd,
+ WPARAM wParam,
+ WData *pTermData)
+{
+ // Is character a lf?
+ if (wParam == '\n')
+ {
+ // Convert to cr since that is what this window uses
+ wParam = '\r';
+ }
+
+ // Write the character to the window
+ EchoChar(hwnd, 1, wParam, pTermData);
+}
+
+
+/****************************************************************************
+
+ FUNCTION: TermWndProc(HWND, unsigned, WORD, LONG)
+
+ PURPOSE: Processes messages
+
+ MESSAGES:
+
+ COMMENTS:
+
+****************************************************************************/
+
+long TermWndProc(
+ HWND hWnd,
+ UINT message,
+ WPARAM wParam,
+ LPARAM lParam)
+{
+ WData *pTerm = (WData *) GetWindowLong(hWnd, 0);
+
+ switch (message)
+ {
+ case WM_CREATE:
+ WmCreate(hWnd, (CREATESTRUCT *) lParam);
+ break;
+
+ case WM_COMMAND:
+ case WM_SYSCOMMAND:
+ // Call procedure that processes the menus
+ return (*(pTerm->pMenuProc))(hWnd, message, wParam, lParam,
+ pTerm->pvCallBackData);
+
+ case WM_SIZE:
+ WmSize(hWnd, wParam, lParam, pTerm);
+ break;
+
+ case WM_SETFOCUS:
+ WmSetFocus(hWnd, pTerm);
+ break;
+
+ case WM_KILLFOCUS:
+ WmKillFocus(hWnd, pTerm);
+ break;
+
+ case WM_VSCROLL:
+ WmVscroll(hWnd, wParam, lParam, pTerm);
+ break;
+
+ case WM_HSCROLL:
+ WmHscroll(hWnd, wParam, lParam, pTerm);
+ break;
+
+ case WM_CHAR:
+ // Character message echo and put in buffer
+ return (*(pTerm->pCharProc))(hWnd, message, wParam, lParam,
+ pTerm->pvCallBackData);
+
+ case WM_PAINT:
+ WmPaint(hWnd, pTerm);
+ break;
+
+ case WM_CLOSE:
+ DestroyWindow(hWnd);
+ break;
+
+ case WM_NCDESTROY:
+ // Call close notification procedure
+ return (*(pTerm->pCloseProc))(hWnd, message, wParam, lParam,
+ pTerm->pvCallBackData);
+
+ case WM_PRINT_LINE:
+ WmPrintLine(hWnd, wParam, lParam, pTerm);
+ break;
+
+ case WM_PUTC:
+ WmPutc(hWnd, wParam, pTerm);
+ break;
+
+ case WM_DESTROY:
+ PostQuitMessage(0);
+ break;
+
+ case WM_TERM_WND:
+ DestroyWindow(hWnd);
+ break;
+
+ default: /* Passes it on if unproccessed */
+ return (DefWindowProc(hWnd, message, wParam, lParam));
+ }
+
+ return 0;
+}
+
+
+/****************************************************************************
+
+ FUNCTION: TermRegisterClass(HANDLE)
+
+ PURPOSE: Register a class for a terminal window
+
+ COMMENTS:
+
+
+****************************************************************************/
+
+BOOL TermRegisterClass(
+ HANDLE hInstance,
+ LPTSTR MenuName,
+ LPTSTR ClassName,
+ LPTSTR Icon)
+{
+ WNDCLASS wc;
+ BOOL retVal;
+
+ // Make sure blank line is blank
+ memset(BlankLine, ' ', 80);
+
+ /* Fill in window class structure with parameters that describe the */
+ /* main window. */
+
+ wc.style = 0;
+ wc.lpfnWndProc = TermWndProc;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = sizeof(WData *);
+ wc.hInstance = hInstance;
+ wc.hIcon = LoadIcon(NULL, Icon);
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wc.hbrBackground = GetStockObject(WHITE_BRUSH);
+ wc.lpszMenuName = MenuName;
+ wc.lpszClassName = ClassName;
+
+ /* Register the window class and return success/failure code. */
+ if (retVal = RegisterClass(&wc))
+ {
+ // Class got registered -- so finish set up
+ hInst = hInstance;
+ }
+
+ return retVal;
+}
+
+
+/****************************************************************************
+
+ FUNCTION: TermCreateWindow(LPTSTR, LPTSTR, HMENU, void *, void *, int)
+
+ PURPOSE: Create a window of a previously registered window class
+
+ COMMENTS:
+
+
+****************************************************************************/
+
+BOOL
+TermCreateWindow(
+ LPTSTR lpClassName,
+ LPTSTR lpWindowName,
+ HMENU hMenu,
+ MFUNCP MenuProc,
+ CFUNCP CharProc,
+ TFUNCP CloseProc,
+ int nCmdShow,
+ HWND *phNewWindow,
+ void *pvCallBackData)
+{
+ HWND hWnd; // Main window handle.
+ WData *pTermData;
+
+ // Allocate control structure for the window
+ if ((pTermData = malloc(sizeof(WData))) == NULL)
+ {
+ return FALSE;
+ }
+
+ // Set entire structure to nulls
+ memset((TCHAR *) pTermData, '\0', sizeof(WData));
+
+ // Initialize function pointers
+ pTermData->pMenuProc = MenuProc;
+ pTermData->pCharProc = CharProc;
+ pTermData->pCloseProc = CloseProc;
+
+ // Initialize callback data
+ pTermData->pvCallBackData = pvCallBackData;
+
+ // Create a main window for this application instance.
+ hWnd = CreateWindow(
+ lpClassName,
+ lpWindowName,
+ WS_OVERLAPPEDWINDOW,
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ NULL,
+ hMenu,
+ hInst,
+ (LPTSTR) pTermData
+ );
+
+ // If window could not be created, return "failure"
+
+ if (!hWnd)
+ {
+ free(pTermData);
+ return FALSE;
+ }
+
+ SetFocus(hWnd);
+
+ // Make the window visible; update its client area; and return "success"
+
+ ShowWindow(hWnd, nCmdShow);
+ UpdateWindow(hWnd);
+ *phNewWindow = hWnd;
+ return (TRUE);
+}
diff --git a/private/oleutest/balls/common/wterm.h b/private/oleutest/balls/common/wterm.h
new file mode 100644
index 000000000..5e8aa15c3
--- /dev/null
+++ b/private/oleutest/balls/common/wterm.h
@@ -0,0 +1,56 @@
+#ifndef __WTERM__
+#define __WTERM__
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+// Message to print a line on the window
+#define WM_PRINT_LINE (WM_USER + 1)
+
+// Message to print a character on the window
+#define WM_PUTC (WM_USER + 2)
+
+// Message used to terminate this window
+#define WM_TERM_WND (WM_USER + 3)
+
+//
+// Typedefs for call back functions for the window
+//
+typedef long (*MFUNCP)(HWND, UINT, WPARAM, LPARAM, void *);
+typedef long (*CFUNCP)(HWND, UINT, WPARAM, LPARAM, void *);
+typedef long (*TFUNCP)(HWND, UINT, WPARAM, LPARAM, void *);
+
+// Register the terminal window class
+BOOL TermRegisterClass(
+ HANDLE hInstance,
+ LPTSTR MenuName,
+ LPTSTR ClassName,
+ LPTSTR ICON);
+
+// Create a window for the terminal
+BOOL
+TermCreateWindow(
+ LPTSTR lpClassName,
+ LPTSTR lpWindowName,
+ HMENU hMenu,
+ MFUNCP MenuProc,
+ CFUNCP CharProc,
+ TFUNCP CloseProc,
+ int nCmdShow,
+ HWND *phNewWindow,
+ void *pvCallBackData);
+
+// make the window for the server
+void
+MakeTheWindow(
+ HANDLE hInstance,
+ TCHAR *pwszAppName);
+
+extern HWND g_hMain;
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // __WTERM__
diff --git a/private/oleutest/balls/common/wterm2.cxx b/private/oleutest/balls/common/wterm2.cxx
new file mode 100644
index 000000000..2ed1526c0
--- /dev/null
+++ b/private/oleutest/balls/common/wterm2.cxx
@@ -0,0 +1,186 @@
+//+-------------------------------------------------------------------
+//
+// File: wterm2.cxx
+//
+// Contents: Shared Windows Procedures
+//
+// Classes: none
+//
+// History: 23-Nov-92 Rickhi Created
+//
+//--------------------------------------------------------------------
+#include <pch.cxx>
+#pragma hdrstop
+
+extern "C"
+{
+#include "wterm.h"
+#include <memory.h>
+#include <stdio.h>
+}
+
+// function prototypes
+long ProcessMenu(HWND hWindow, UINT uiMessage, WPARAM wParam, LPARAM lParam,
+ void *);
+long ProcessChar(HWND hWindow, UINT uiMessage, WPARAM wParam, LPARAM lParam,
+ void *);
+long ProcessClose(
+ HWND hWindow,
+ UINT uiMessage,
+ WPARAM wParam,
+ LPARAM lParam,
+ void *pvCallBackData);
+
+#define IDM_DEBUG 0x100
+
+// global variables.
+
+HWND g_hMain;
+#if DBG==1
+BOOL g_fDisplay = 1;
+#else
+BOOL g_fDisplay = 0;
+#endif
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: Display
+//
+// Synopsis: prints a message on the window
+//
+// History: 06-Aug-92 Ricksa Created
+//
+//--------------------------------------------------------------------------
+void Display(TCHAR *pszFmt, ...)
+{
+ // since it takes a long time to display these messages and we dont
+ // want to skew benchmarks, displaying the messages is optional.
+ // the messages are usefull for debugging.
+
+ if (!g_fDisplay)
+ return;
+
+ va_list marker;
+ TCHAR szBuffer[256];
+
+ va_start(marker, pszFmt);
+
+#ifdef UNICODE
+ int iLen = vswprintf(szBuffer, pszFmt, marker);
+#else
+ int iLen = vsprintf(szBuffer, pszFmt, marker);
+#endif
+
+ va_end(marker);
+
+ // Display the message on terminal window
+ SendMessage(g_hMain, WM_PRINT_LINE, iLen, (LONG) szBuffer);
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: ProcessMenu
+//
+// Synopsis: Gets called when a WM_COMMAND message received.
+//
+// Arguments: [hWindow] - handle for the window
+// [uiMessage] - message id
+// [wParam] - word parameter
+// [lParam] - long parameter
+//
+// Returns: DefWindowProc result
+//
+// History: 06-Aug-92 Ricksa Created
+//
+//--------------------------------------------------------------------------
+long ProcessMenu(HWND hWindow, UINT uiMessage, WPARAM wParam, LPARAM lParam,
+ void *)
+{
+ return (DefWindowProc(hWindow, uiMessage, wParam, lParam));
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: ProcessChar
+//
+// Synopsis: Gets called when a WM_CHAR message received.
+//
+// Arguments: [hWindow] - handle for the window
+// [uiMessage] - message id
+// [wParam] - word parameter
+// [lParam] - long parameter
+//
+// Returns: DefWindowProc result
+//
+// History: 06-Aug-92 Ricksa Created
+//
+//--------------------------------------------------------------------------
+long ProcessChar(HWND hWindow, UINT uiMessage, WPARAM wParam, LPARAM lParam,
+ void *)
+{
+ return (DefWindowProc(hWindow, uiMessage, wParam, lParam));
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: ProcessClose
+//
+// Synopsis: Gets called when a NC_DESTROY message received.
+//
+// Arguments: [hWindow] - handle for the window
+// [uiMessage] - message id
+// [wParam] - word parameter
+// [lParam] - long parameter
+//
+// Returns: DefWindowProc result
+//
+// History: 06-Aug-92 Ricksa Created
+//
+//--------------------------------------------------------------------------
+long ProcessClose(
+ HWND hWindow,
+ UINT uiMessage,
+ WPARAM wParam,
+ LPARAM lParam,
+ void *pvCallBackData)
+{
+ // Take default action with message
+ return (DefWindowProc(hWindow, uiMessage, wParam, lParam));
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: MakeTheWindow
+//
+// Synopsis: Creates the terminal window.
+//
+// Arguments: [hInstance] -
+// [pwszAppName] - app name to display
+//
+// History: 06-Aug-92 Ricksa Created
+//
+//--------------------------------------------------------------------------
+void MakeTheWindow(HANDLE hInstance, TCHAR *pwszAppName)
+{
+ // Register the window class
+ TermRegisterClass(hInstance, (LPTSTR) pwszAppName,
+ (LPTSTR) pwszAppName, (LPTSTR) (1));
+
+ // Create the server window
+ TermCreateWindow(
+ (LPTSTR) pwszAppName,
+ (LPTSTR) pwszAppName,
+ NULL,
+ ProcessMenu,
+ ProcessChar,
+ ProcessClose,
+ SW_SHOWMINIMIZED,
+ (HWND *)&g_hMain,
+ NULL);
+
+ // Add debug option to system menu
+ HMENU hmenu = GetSystemMenu(g_hMain, FALSE);
+ AppendMenu(hmenu, MF_SEPARATOR, 0, NULL);
+ AppendMenu(hmenu, MF_STRING | MF_ENABLED, IDM_DEBUG, TEXT("Debug"));
+}
diff --git a/private/oleutest/balls/copyall.bat b/private/oleutest/balls/copyall.bat
new file mode 100644
index 000000000..f479aa2c2
--- /dev/null
+++ b/private/oleutest/balls/copyall.bat
@@ -0,0 +1,22 @@
+rem set SRCROOT%=\\rickhi1\c$
+set SRC=%1\nt\private\oleutest
+set DST=%2
+set PLATFORM=%3
+
+for %%f in (tmarshal dllhost) do copy %SRC%\balls\client\%%f\daytona\obj\%PLATFORM%\*.exe %DST%
+
+for %%f in (balls loops qi cubes mdi mixed rpctst) do copy %SRC%\balls\srv\%%f\daytona\obj\%PLATFORM%\*.exe %DST%
+
+for %%f in (qi dlltest) do copy %SRC%\balls\dll\%%f\daytona\obj\%PLATFORM%\*.dll %DST%
+
+copy %SRC%\balls\oleprx32\proxy\daytona\obj\%PLATFORM%\*.dll %DST%
+
+
+copy %SRC%\perform\driver\daytona\obj\%PLATFORM%\*.exe %DST%
+copy %SRC%\perform\rawrpc\daytona\obj\%PLATFORM%\*.exe %DST%
+copy %SRC%\perform\cairole\svr\daytona\obj\%PLATFORM%\*.exe %DST%
+copy %SRC%\perform\cairole\dll\daytona\obj\%PLATFORM%\*.dll %DST%
+
+copy %SRC%\perform\driver\*.ini %DST%
+copy %SRC%\balls\client\tmarshal\*.ini %DST%
+
diff --git a/private/oleutest/balls/daytona.inc b/private/oleutest/balls/daytona.inc
new file mode 100644
index 000000000..0b89a2b90
--- /dev/null
+++ b/private/oleutest/balls/daytona.inc
@@ -0,0 +1,30 @@
+# This is the global include file for the daytona version of CairOLE.
+# It is included by all project sources files.
+
+C_DEFINES= \
+ $(C_DEFINES) \
+ -DFLAT \
+ -DWIN32=100 \
+ -D_NT1X_=100 \
+ -DUNICODE \
+ -D_UNICODE \
+ -DINC_OLE2 \
+ -DNOEXCEPTIONS \
+ -DCAIROLE_DOWNLEVEL \
+ $(TRACELOG)
+
+
+BLDCRT= 1
+
+# For the Daytona build, we do not want statically linked compiler runtimes,
+# so leave this commented out.
+#
+# USE_LIBCMT= 1
+
+
+USE_CRTDLL=1
+
+
+OLEDIR= $(BASEDIR)\private\ole32
+OLEUTESTDIR= $(BASEDIR)\private\oleutest
+OLEBALLSDIR= $(BASEDIR)\private\oleutest\balls
diff --git a/private/oleutest/balls/dirs b/private/oleutest/balls/dirs
new file mode 100644
index 000000000..913a5f375
--- /dev/null
+++ b/private/oleutest/balls/dirs
@@ -0,0 +1,41 @@
+!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= \
+ idl \
+ oleprx32 \
+ common \
+ srv \
+ dll \
+ client
+
+#
+# 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=
diff --git a/private/oleutest/balls/dll/cairo.inc b/private/oleutest/balls/dll/cairo.inc
new file mode 100644
index 000000000..97f7a6014
--- /dev/null
+++ b/private/oleutest/balls/dll/cairo.inc
@@ -0,0 +1,53 @@
+!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.
+
+!ENDIF
+
+DLLENTRY= _DllMainCRTStartup
+
+DLLBASE=@$(BASEDIR)\PUBLIC\SDK\LIB\coffbase.txt,usermode
+
+
+!include ..\..\..\daytona.inc
+
+INCLUDES= ..\;..\..\..\..\..\cinc;..\..\..\oleprx32\proxy;..\..\..\common
+
+UMTYPE= windows
+UMAPPL=
+UMTEST=
+
+LINKLIBS= \
+ ..\..\..\oleprx32\uuid\daytona\obj\*\uuid.lib \
+ ..\..\..\common\daytona\obj\*\servers.lib \
+ $(BASEDIR)\private\ole32\com\port\daytona\obj\*\port.lib \
+ $(BASEDIR)\private\ole32\common\daytona\obj\*\common.lib \
+ $(BASEDIR)\public\sdk\lib\*\uuid.lib \
+ $(BASEDIR)\public\sdk\lib\*\ole32.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
+
+!IF $(386)
+NTTARGETFILE0=$(DLLDEF:*=i386)
+!ENDIF
+
+!IF $(MIPS)
+NTTARGETFILE0=$(DLLDEF:*=mips)
+!ENDIF
+
+!IF $(ALPHA)
+NTTARGETFILE0=$(DLLDEF:*=alpha)
+!ENDIF
diff --git a/private/oleutest/balls/dll/chicago.inc b/private/oleutest/balls/dll/chicago.inc
new file mode 100644
index 000000000..896ac4b92
--- /dev/null
+++ b/private/oleutest/balls/dll/chicago.inc
@@ -0,0 +1,64 @@
+!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:
+
+ David Plummer (davepl) 19-Mar-94
+
+ Modifed by via awk to include global project include file
+ and to wrap precompiled header line within a conditional
+ that can be set in this include file.
+
+ Donna Liu (DonnaLi) 19-Dec-1993
+
+!ENDIF
+
+DLLENTRY= _DllMainCRTStartup
+
+DLLBASE=@$(BASEDIR)\PUBLIC\SDK\LIB\coffbase.txt,usermode
+
+
+!include ..\..\..\chicago.inc
+
+INCLUDES= ;..;$(OLEBALLSDIR)\common;
+INCLUDES= $(INCLUDES);$(OLEUTESTDIR)\balls\oleprx32\chicago
+
+UMTYPE= windows
+UMAPPL=
+UMTEST=
+
+LINKLIBS= \
+ ..\..\..\oleprx32\uuid\chicago\obj\*\uuid.lib \
+ ..\..\..\common\chicago\obj\*\servers.lib \
+ $(BASEDIR)\private\ole32\common\chicago\obj\*\common.lib \
+ $(BASEDIR)\public\sdk\lib\*\uuid.lib \
+ $(BASEDIR)\public\sdk\lib\*\ole32.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
+
+!IF $(386)
+NTTARGETFILE0=$(DLLDEF:*=i386)
+!ENDIF
+
+!IF $(MIPS)
+NTTARGETFILE0=$(DLLDEF:*=mips)
+!ENDIF
+
+!IF $(ALPHA)
+NTTARGETFILE0=$(DLLDEF:*=alpha)
+!ENDIF
diff --git a/private/oleutest/balls/dll/daytona.inc b/private/oleutest/balls/dll/daytona.inc
new file mode 100644
index 000000000..9532c0de4
--- /dev/null
+++ b/private/oleutest/balls/dll/daytona.inc
@@ -0,0 +1,64 @@
+!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:
+
+ David Plummer (davepl) 19-Mar-94
+
+ Modifed by via awk to include global project include file
+ and to wrap precompiled header line within a conditional
+ that can be set in this include file.
+
+ Donna Liu (DonnaLi) 19-Dec-1993
+
+!ENDIF
+
+DLLENTRY= _DllMainCRTStartup
+
+DLLBASE=@$(BASEDIR)\PUBLIC\SDK\LIB\coffbase.txt,usermode
+
+
+!include ..\..\..\daytona.inc
+
+INCLUDES= ;..;$(OLEBALLSDIR)\common;
+INCLUDES= $(INCLUDES);$(OLEUTESTDIR)\balls\oleprx32\daytona
+
+UMTYPE= windows
+UMAPPL=
+UMTEST=
+
+LINKLIBS= \
+ ..\..\..\oleprx32\uuid\daytona\obj\*\uuid.lib \
+ ..\..\..\common\daytona\obj\*\servers.lib \
+ $(BASEDIR)\private\ole32\common\daytona\obj\*\common.lib \
+ $(BASEDIR)\public\sdk\lib\*\uuid.lib \
+ $(BASEDIR)\public\sdk\lib\*\ole32.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
+
+!IF $(386)
+NTTARGETFILE0=$(DLLDEF:*=i386)
+!ENDIF
+
+!IF $(MIPS)
+NTTARGETFILE0=$(DLLDEF:*=mips)
+!ENDIF
+
+!IF $(ALPHA)
+NTTARGETFILE0=$(DLLDEF:*=alpha)
+!ENDIF
diff --git a/private/oleutest/balls/dll/dirs b/private/oleutest/balls/dll/dirs
new file mode 100644
index 000000000..d24330610
--- /dev/null
+++ b/private/oleutest/balls/dll/dirs
@@ -0,0 +1,38 @@
+!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= \
+ oleimpl \
+ dlltest \
+ qi
+
+#
+# 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=
diff --git a/private/oleutest/balls/dll/dlltest/daytona/dlltest.src b/private/oleutest/balls/dll/dlltest/daytona/dlltest.src
new file mode 100644
index 000000000..08dff9047
--- /dev/null
+++ b/private/oleutest/balls/dll/dlltest/daytona/dlltest.src
@@ -0,0 +1,48 @@
+#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 dlltest
+
+DESCRIPTION 'Microsoft (R) OLE 2.0 Proxy DLL 1.00'
+
+EXPORTS
+#if defined(i386)
+
+ _DllGetClassObject@12 @1
+ DllGetClassObject=_DllGetClassObject@12
+ _DllCanUnloadNow@0 @2
+ DllCanUnloadNow=_DllCanUnloadNow@0
+
+#elif defined(_MIPS_)
+
+ DllGetClassObject @1
+ DllCanUnloadNow @2
+
+#endif // i386 - MIPS
+
+#endif // FLAT
diff --git a/private/oleutest/balls/dll/dlltest/daytona/makefile b/private/oleutest/balls/dll/dlltest/daytona/makefile
new file mode 100644
index 000000000..1d3728d41
--- /dev/null
+++ b/private/oleutest/balls/dll/dlltest/daytona/makefile
@@ -0,0 +1,10 @@
+############################################################################
+#
+# Copyright (C) 1992, Microsoft Corporation.
+#
+# All rights reserved.
+#
+############################################################################
+
+!include $(NTMAKEENV)\makefile.def
+
diff --git a/private/oleutest/balls/dll/dlltest/daytona/makefile.inc b/private/oleutest/balls/dll/dlltest/daytona/makefile.inc
new file mode 100644
index 000000000..d0428f8b6
--- /dev/null
+++ b/private/oleutest/balls/dll/dlltest/daytona/makefile.inc
@@ -0,0 +1 @@
+obj\i386\dlltest.def: dlltest.src
diff --git a/private/oleutest/balls/dll/dlltest/daytona/sources b/private/oleutest/balls/dll/dlltest/daytona/sources
new file mode 100644
index 000000000..f69f723eb
--- /dev/null
+++ b/private/oleutest/balls/dll/dlltest/daytona/sources
@@ -0,0 +1,59 @@
+!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.
+
+!ENDIF
+
+#
+# The following includes a global include file defined at the
+# base of the project for all components
+#
+
+!include ..\..\daytona.inc
+
+#
+# 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= dlltest
+
+#
+# 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= DYNLINK
+
+DLLDEF= obj\*\dlltest.def
+
+
+INCLUDES= $(INCLUDES)
+C_DEFINES= $(C_DEFINES)
+
+
+SOURCES= \
+ ..\dlltest.cxx
+
+UMTYPE= windows
+UMAPPL=
+UMTEST=
diff --git a/private/oleutest/balls/dll/dlltest/dirs b/private/oleutest/balls/dll/dlltest/dirs
new file mode 100644
index 000000000..1d0b9edbb
--- /dev/null
+++ b/private/oleutest/balls/dll/dlltest/dirs
@@ -0,0 +1,38 @@
+!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/balls/dll/dlltest/dlltest.cxx b/private/oleutest/balls/dll/dlltest/dlltest.cxx
new file mode 100644
index 000000000..d5dede76b
--- /dev/null
+++ b/private/oleutest/balls/dll/dlltest/dlltest.cxx
@@ -0,0 +1,124 @@
+//+-------------------------------------------------------------------
+//
+// File: dlltest.cxx
+//
+// Contents: This file contins the DLL entry points
+// LibMain
+// DllGetClassObject (Bindings key func)
+// CAdvBndCF (class factory)
+// CAdvBnd (actual class implementation)
+//
+// Classes: CAdvBndCF, CAdvBnd
+//
+//
+// History: 30-Nov-92 SarahJ Created
+//
+//---------------------------------------------------------------------
+
+#include <windows.h>
+#include <ole2.h>
+// #include <debnot.h>
+#include <sem.hxx>
+#include <actcf.hxx>
+
+
+static GUID CLSID_TestNoRegister =
+ {0x99999999,0x0000,0x0008,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x52}};
+
+static GUID CLSID_TestRegister =
+ {0x99999999,0x0000,0x0008,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x53}};
+
+// The class objects can be totally static in a DLL
+CActClassFactory clsfactNoRegister(CLSID_TestNoRegister, FALSE);
+CActClassFactory clsfactRegister(CLSID_TestRegister, FALSE);
+
+CMutexSem mxsUnloadTest;
+
+BOOL fUnload = FALSE;
+
+DWORD dwRegistration;
+
+ULONG gUsage = 0;
+
+
+extern "C" BOOL WINAPI DllMain (HANDLE hDll,
+ DWORD dwReason,
+ LPVOID pvReserved)
+{
+ return TRUE;
+}
+
+
+
+void GlobalRefs(BOOL fAddRef)
+{
+ if (fAddRef)
+ {
+ gUsage++;
+ }
+ else
+ {
+ gUsage--;
+ }
+}
+
+
+STDAPI DllCanUnloadNow(void)
+{
+ CLock clk(mxsUnloadTest);
+
+ if (gUsage == 0)
+ {
+ fUnload = TRUE;
+
+ if (dwRegistration != 0)
+ {
+ HRESULT hr = CoRevokeClassObject(dwRegistration);
+
+ Win4Assert(SUCCEEDED(hr) && "CoRevokeClassObject failed!!");
+ }
+ }
+
+ return (gUsage == 0);
+}
+
+STDAPI DllGetClassObject(REFCLSID clsid, REFIID iid, void FAR* FAR* ppv)
+{
+ CLock clk(mxsUnloadTest);
+
+ if (fUnload)
+ {
+ return E_UNEXPECTED;
+ }
+
+ if (IsEqualCLSID(clsid, CLSID_TestNoRegister))
+ {
+ clsfactNoRegister.AddRef();
+ *ppv = &clsfactNoRegister;
+ }
+ else if (IsEqualCLSID(clsid, CLSID_TestRegister))
+ {
+ clsfactNoRegister.AddRef();
+ *ppv = &clsfactNoRegister;
+
+ if (dwRegistration == 0)
+ {
+ // Register the class
+ HRESULT hr = CoRegisterClassObject(CLSID_TestRegister,
+ &clsfactRegister, CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE,
+ &dwRegistration);
+
+ Win4Assert(SUCCEEDED(hr) && "CoRegisterClassObject failed!!");
+
+ // Decrement the global reference count since the registration
+ // bumped the reference count because it does an addref
+ gUsage--;
+ }
+ }
+ else
+ {
+ return E_UNEXPECTED;
+ }
+
+ return S_OK;
+}
diff --git a/private/oleutest/balls/dll/dlltest/dlltest.def b/private/oleutest/balls/dll/dlltest/dlltest.def
new file mode 100644
index 000000000..4991a6e6b
--- /dev/null
+++ b/private/oleutest/balls/dll/dlltest/dlltest.def
@@ -0,0 +1,38 @@
+#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 dlltest
+
+DESCRIPTION 'Microsoft (R) OLE 2.0 Proxy DLL 1.00'
+
+EXPORTS
+
+ DllGetClassObject
+ DllCanUnloadNow
+
+#endif // FLAT
diff --git a/private/oleutest/balls/dll/oleimpl/daytona/makefile b/private/oleutest/balls/dll/oleimpl/daytona/makefile
new file mode 100644
index 000000000..1d3728d41
--- /dev/null
+++ b/private/oleutest/balls/dll/oleimpl/daytona/makefile
@@ -0,0 +1,10 @@
+############################################################################
+#
+# Copyright (C) 1992, Microsoft Corporation.
+#
+# All rights reserved.
+#
+############################################################################
+
+!include $(NTMAKEENV)\makefile.def
+
diff --git a/private/oleutest/balls/dll/oleimpl/daytona/makefile.inc b/private/oleutest/balls/dll/oleimpl/daytona/makefile.inc
new file mode 100644
index 000000000..071024ed2
--- /dev/null
+++ b/private/oleutest/balls/dll/oleimpl/daytona/makefile.inc
@@ -0,0 +1 @@
+obj\i386\oleimpl.def: oleimpl.src
diff --git a/private/oleutest/balls/dll/oleimpl/daytona/oleimpl.src b/private/oleutest/balls/dll/oleimpl/daytona/oleimpl.src
new file mode 100644
index 000000000..944533676
--- /dev/null
+++ b/private/oleutest/balls/dll/oleimpl/daytona/oleimpl.src
@@ -0,0 +1,48 @@
+#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 oleimpl
+
+DESCRIPTION 'Microsoft (R) OLE 2.0 Proxy DLL 1.00'
+
+EXPORTS
+#if defined(i386)
+
+ _DllGetClassObject@12 @1
+ DllGetClassObject=_DllGetClassObject@12
+ _DllCanUnloadNow@0 @2
+ DllCanUnloadNow=_DllCanUnloadNow@0
+
+#elif defined(_MIPS_)
+
+ DllGetClassObject @1
+ DllCanUnloadNow @2
+
+#endif // i386 - MIPS
+
+#endif // FLAT
diff --git a/private/oleutest/balls/dll/oleimpl/daytona/sources b/private/oleutest/balls/dll/oleimpl/daytona/sources
new file mode 100644
index 000000000..8cb955dc2
--- /dev/null
+++ b/private/oleutest/balls/dll/oleimpl/daytona/sources
@@ -0,0 +1,55 @@
+!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.
+
+!ENDIF
+
+#
+# The following includes a global include file defined at the
+# base of the project for all components
+#
+
+!include ..\..\daytona.inc
+
+#
+# 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= oleimpl
+
+#
+# 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= DYNLINK
+
+DLLDEF= obj\*\oleimpl.def
+
+INCLUDES= $(INCLUDES)
+C_DEFINES= $(C_DEFINES)
+
+
+
+SOURCES= \
+ ..\oleimpl.cxx
diff --git a/private/oleutest/balls/dll/oleimpl/dirs b/private/oleutest/balls/dll/oleimpl/dirs
new file mode 100644
index 000000000..1d0b9edbb
--- /dev/null
+++ b/private/oleutest/balls/dll/oleimpl/dirs
@@ -0,0 +1,38 @@
+!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/balls/dll/oleimpl/oleimpl.cxx b/private/oleutest/balls/dll/oleimpl/oleimpl.cxx
new file mode 100644
index 000000000..82cbf5d76
--- /dev/null
+++ b/private/oleutest/balls/dll/oleimpl/oleimpl.cxx
@@ -0,0 +1,98 @@
+//+-------------------------------------------------------------------
+//
+// File: oleimpl.cxx
+//
+// Contents: This file contins the DLL entry points
+// LibMain
+// DllGetClassObject (Bindings key func)
+// CBasicBndCF (class factory)
+// CBasicBnd (actual class implementation)
+//
+// Classes: CBasicBndCF, CBasicBnd
+//
+//
+// History: 30-Nov-92 SarahJ Created
+//
+//---------------------------------------------------------------------
+
+#include <windows.h>
+#include <ole2.h>
+#include <bscbnd.hxx>
+
+
+extern ULONG g_UseCount;
+
+CBasicBndCF *g_pcf = NULL;
+
+
+//+-------------------------------------------------------------------
+//
+// Function: LibMain
+//
+// Synopsis: Entry point to DLL - does little else
+//
+// Arguments:
+//
+// Returns: TRUE
+//
+// History: 21-Nov-92 SarahJ Created
+//
+//--------------------------------------------------------------------
+
+extern "C" BOOL WINAPI DLLMain (HANDLE hDll,
+ DWORD dwReason,
+ LPVOID pvReserved)
+{
+ return TRUE;
+}
+
+
+//+-------------------------------------------------------------------
+//
+// Function: DllGetClassObject
+//
+// Synopsis: Called by client (from within BindToObject et al)
+// interface requested should be IUnknown or IClassFactory -
+// Creates ClassFactory object and returns pointer to it
+//
+// Arguments: REFCLSID clsid - class id
+// REFIID iid - interface id
+// void FAR* FAR* ppv- pointer to class factory interface
+//
+// Returns: TRUE
+//
+// History: 21-Nov-92 SarahJ Created
+//
+//--------------------------------------------------------------------
+
+
+STDAPI DllGetClassObject(REFCLSID clsid, REFIID iid, void FAR* FAR* ppv)
+{
+ if (!IsEqualIID(iid, IID_IUnknown) && !IsEqualIID(iid, IID_IClassFactory))
+ {
+ return E_NOINTERFACE;
+ }
+
+ if (IsEqualCLSID(clsid, CLSID_BasicBnd))
+ {
+ if (g_pcf)
+ {
+ *ppv = g_pcf;
+ g_pcf->AddRef();
+ }
+ else
+ {
+ *ppv = new CBasicBndCF();
+ }
+
+ return (*ppv != NULL) ? S_OK : E_FAIL;
+ }
+
+ return E_FAIL;
+}
+
+
+STDAPI DllCanUnloadNow(void)
+{
+ return (g_UseCount == 0) ? S_OK : S_FALSE;
+}
diff --git a/private/oleutest/balls/dll/oleimpl/oleimpl.def b/private/oleutest/balls/dll/oleimpl/oleimpl.def
new file mode 100644
index 000000000..cc6d563a6
--- /dev/null
+++ b/private/oleutest/balls/dll/oleimpl/oleimpl.def
@@ -0,0 +1,38 @@
+#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 oleimpl
+
+DESCRIPTION 'Microsoft (R) OLE 2.0 Proxy DLL 1.00'
+
+EXPORTS
+
+ DllGetClassObject
+ DllCanUnloadNow
+
+#endif // FLAT
diff --git a/private/oleutest/balls/dll/qi/daytona/makefile b/private/oleutest/balls/dll/qi/daytona/makefile
new file mode 100644
index 000000000..1d3728d41
--- /dev/null
+++ b/private/oleutest/balls/dll/qi/daytona/makefile
@@ -0,0 +1,10 @@
+############################################################################
+#
+# Copyright (C) 1992, Microsoft Corporation.
+#
+# All rights reserved.
+#
+############################################################################
+
+!include $(NTMAKEENV)\makefile.def
+
diff --git a/private/oleutest/balls/dll/qi/daytona/makefile.inc b/private/oleutest/balls/dll/qi/daytona/makefile.inc
new file mode 100644
index 000000000..d79611892
--- /dev/null
+++ b/private/oleutest/balls/dll/qi/daytona/makefile.inc
@@ -0,0 +1 @@
+obj\i386\qisrv.def: qisrv.src
diff --git a/private/oleutest/balls/dll/qi/daytona/qisrv.src b/private/oleutest/balls/dll/qi/daytona/qisrv.src
new file mode 100644
index 000000000..9596e5b89
--- /dev/null
+++ b/private/oleutest/balls/dll/qi/daytona/qisrv.src
@@ -0,0 +1,48 @@
+#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 qisrv
+
+DESCRIPTION 'Microsoft (R) OLE 2.0 Proxy DLL 1.00'
+
+EXPORTS
+#if defined(i386)
+
+ _DllGetClassObject@12 @1
+ DllGetClassObject=_DllGetClassObject@12
+ _DllCanUnloadNow@0 @2
+ DllCanUnloadNow=_DllCanUnloadNow@0
+
+#elif defined(_MIPS_)
+
+ DllGetClassObject @1
+ DllCanUnloadNow @2
+
+#endif // i386 - MIPS
+
+#endif // FLAT
diff --git a/private/oleutest/balls/dll/qi/daytona/sources b/private/oleutest/balls/dll/qi/daytona/sources
new file mode 100644
index 000000000..868e0b05c
--- /dev/null
+++ b/private/oleutest/balls/dll/qi/daytona/sources
@@ -0,0 +1,55 @@
+!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.
+
+!ENDIF
+
+#
+# The following includes a global include file defined at the
+# base of the project for all components
+#
+
+!include ..\..\daytona.inc
+
+#
+# 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= qisrv
+
+#
+# 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= DYNLINK
+
+DLLDEF= obj\*\qisrv.def
+
+INLCUDES= $(INCLUDES)
+C_DEFINES= $(C_DEFINES)
+
+
+
+SOURCES= \
+ ..\qisrv.cxx
diff --git a/private/oleutest/balls/dll/qi/dirs b/private/oleutest/balls/dll/qi/dirs
new file mode 100644
index 000000000..1d0b9edbb
--- /dev/null
+++ b/private/oleutest/balls/dll/qi/dirs
@@ -0,0 +1,38 @@
+!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/balls/dll/qi/qisrv.cxx b/private/oleutest/balls/dll/qi/qisrv.cxx
new file mode 100644
index 000000000..4265e17d6
--- /dev/null
+++ b/private/oleutest/balls/dll/qi/qisrv.cxx
@@ -0,0 +1,55 @@
+//+-------------------------------------------------------------------
+//
+// File: qisrv.cxx
+//
+// Contents: This file contins the DLL entry points
+// DllGetClassObject
+// DllCanUnloadNow
+//
+// History: 30-Nov-92 Rickhi Created
+//
+//---------------------------------------------------------------------
+#include <common.h>
+#include <qicf.hxx>
+
+ULONG gUsage = 0;
+
+
+extern "C" BOOL WINAPI DllMain (HANDLE hDll,
+ DWORD dwReason,
+ LPVOID pvReserved)
+{
+ return TRUE;
+}
+
+void GlobalRefs(BOOL fAddRef)
+{
+ if (fAddRef)
+ {
+ gUsage++;
+ }
+ else
+ {
+ gUsage--;
+ }
+}
+
+STDAPI DllCanUnloadNow(void)
+{
+ return (gUsage == 0);
+}
+
+STDAPI DllGetClassObject(REFCLSID clsid, REFIID iid, void FAR* FAR* ppv)
+{
+ if (IsEqualCLSID(clsid, CLSID_QI) ||
+ IsEqualCLSID(clsid, CLSID_QIHANDLER))
+ {
+ *ppv = (void *)(IClassFactory *) new CQIClassFactory(clsid);
+ }
+ else
+ {
+ return E_UNEXPECTED;
+ }
+
+ return S_OK;
+}
diff --git a/private/oleutest/balls/dll/qi/qisrv.def b/private/oleutest/balls/dll/qi/qisrv.def
new file mode 100644
index 000000000..8561b5659
--- /dev/null
+++ b/private/oleutest/balls/dll/qi/qisrv.def
@@ -0,0 +1,38 @@
+#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 qisrv
+
+DESCRIPTION 'Microsoft (R) OLE 2.0 Proxy DLL 1.00'
+
+EXPORTS
+
+ DllGetClassObject
+ DllCanUnloadNow
+
+#endif // FLAT
diff --git a/private/oleutest/balls/dll/rpctst/daytona/makefile b/private/oleutest/balls/dll/rpctst/daytona/makefile
new file mode 100644
index 000000000..1d3728d41
--- /dev/null
+++ b/private/oleutest/balls/dll/rpctst/daytona/makefile
@@ -0,0 +1,10 @@
+############################################################################
+#
+# Copyright (C) 1992, Microsoft Corporation.
+#
+# All rights reserved.
+#
+############################################################################
+
+!include $(NTMAKEENV)\makefile.def
+
diff --git a/private/oleutest/balls/dll/rpctst/daytona/makefile.inc b/private/oleutest/balls/dll/rpctst/daytona/makefile.inc
new file mode 100644
index 000000000..7652697e3
--- /dev/null
+++ b/private/oleutest/balls/dll/rpctst/daytona/makefile.inc
@@ -0,0 +1 @@
+obj\i386\rpcsrv.def: rpcsrv.src
diff --git a/private/oleutest/balls/dll/rpctst/daytona/rpcsrv.src b/private/oleutest/balls/dll/rpctst/daytona/rpcsrv.src
new file mode 100644
index 000000000..fa7cc5015
--- /dev/null
+++ b/private/oleutest/balls/dll/rpctst/daytona/rpcsrv.src
@@ -0,0 +1,48 @@
+#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 rpcsrv
+
+DESCRIPTION 'Microsoft (R) OLE 2.0 Proxy DLL 1.00'
+
+EXPORTS
+#if defined(i386)
+
+ _DllGetClassObject@12 @1
+ DllGetClassObject=_DllGetClassObject@12
+ _DllCanUnloadNow@0 @2
+ DllCanUnloadNow=_DllCanUnloadNow@0
+
+#elif defined(_MIPS_)
+
+ DllGetClassObject @1
+ DllCanUnloadNow @2
+
+#endif // i386 - MIPS
+
+#endif // FLAT
diff --git a/private/oleutest/balls/dll/rpctst/daytona/sources b/private/oleutest/balls/dll/rpctst/daytona/sources
new file mode 100644
index 000000000..5ffa25353
--- /dev/null
+++ b/private/oleutest/balls/dll/rpctst/daytona/sources
@@ -0,0 +1,68 @@
+!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:
+
+ David Plummer (davepl) 19-Mar-94
+
+ Modifed by via awk to include global project include file
+ and to wrap precompiled header line within a conditional
+ that can be set in this include file.
+
+ Donna Liu (DonnaLi) 19-Dec-1993
+
+!ENDIF
+
+MAJORCOMP = cairole
+MINORCOMP = com
+
+#
+# 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= rpcsrv
+
+#
+# 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= DYNLINK
+
+DLLDEF= obj\*\rpcsrv.def
+
+#
+# The following includes a global include file defined at the
+# base of the project for all components
+#
+
+!include ..\..\daytona.inc
+
+C_DEFINES= \
+ $(C_DEFINES)
+
+
+SOURCES= \
+ ..\rpcsrv.cxx
diff --git a/private/oleutest/balls/dll/rpctst/dirs b/private/oleutest/balls/dll/rpctst/dirs
new file mode 100644
index 000000000..1d0b9edbb
--- /dev/null
+++ b/private/oleutest/balls/dll/rpctst/dirs
@@ -0,0 +1,38 @@
+!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/balls/dll/rpctst/rpcsrv.cxx b/private/oleutest/balls/dll/rpctst/rpcsrv.cxx
new file mode 100644
index 000000000..bcd0486dd
--- /dev/null
+++ b/private/oleutest/balls/dll/rpctst/rpcsrv.cxx
@@ -0,0 +1,63 @@
+//+-------------------------------------------------------------------
+//
+// File: rpcsrv.cxx
+//
+// Contents: This file contins the DLL entry points
+// DllGetClassObject
+// DllCanUnloadNow
+//
+// Classes:
+//
+// History: 30-Nov-92 Rickhi Created
+//
+//---------------------------------------------------------------------
+
+#include <windows.h>
+#include <ole2.h>
+#include <rpccf.hxx>
+
+
+ULONG gUsage = 0;
+
+
+extern "C" BOOL WINAPI DllMain(HANDLE hDll,
+ DWORD dwReason,
+ LPVOID pvReserved)
+{
+ return TRUE;
+}
+
+
+void GlobalRefs(BOOL fAddRef)
+{
+ if (fAddRef)
+ {
+ gUsage++;
+ }
+ else
+ {
+ gUsage--;
+ }
+}
+
+
+STDAPI DllCanUnloadNow(void)
+{
+ return (gUsage == 0);
+}
+
+
+
+STDAPI DllGetClassObject(REFCLSID clsid, REFIID iid, void FAR* FAR* ppv)
+{
+ if (IsEqualCLSID(clsid, CLSID_RpcTest))
+ {
+ *ppv = (void *)(IClassFactory *) new CRpcTestClassFactory();
+ }
+ else
+ {
+ return E_UNEXPECTED;
+ }
+
+ return S_OK;
+}
diff --git a/private/oleutest/balls/dll/rpctst/rpcsrv.def b/private/oleutest/balls/dll/rpctst/rpcsrv.def
new file mode 100644
index 000000000..c11b43fb8
--- /dev/null
+++ b/private/oleutest/balls/dll/rpctst/rpcsrv.def
@@ -0,0 +1,38 @@
+#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 qisrv
+
+DESCRIPTION 'Microsoft (R) OLE 2.0 Proxy DLL 1.00'
+
+EXPORTS
+
+ DllGetClassObject
+ DllGetClassObject
+
+#endif // FLAT
diff --git a/private/oleutest/balls/idl/iballs.idl b/private/oleutest/balls/idl/iballs.idl
new file mode 100644
index 000000000..e9825742c
--- /dev/null
+++ b/private/oleutest/balls/idl/iballs.idl
@@ -0,0 +1,47 @@
+//[ IBalls_itf
+//+-------------------------------------------------------------------
+//
+// Interface: IBalls (ib)
+//
+// Purpose: Interface for manipulating balls
+//
+// History: 23-Nov-92 Rickhi Created
+//
+// Notes:
+//
+//--------------------------------------------------------------------
+
+[ object,
+ uuid(00000138-0001-0008-C000-000000000046),
+ pointer_default(unique) ]
+
+interface IBalls : IUnknown
+{
+ import "unknwn.idl";
+ import "icube.idl";
+
+ HRESULT MoveBall(
+ [in] ULONG xPos,
+ [in] ULONG yPos);
+
+ HRESULT GetBallPos(
+ [out] ULONG *xPos,
+ [out] ULONG *yPos);
+
+ HRESULT IsOverLapped(
+ [in] [unique] IBalls *pIFDb);
+
+ HRESULT IsContainedIn(
+ [in] [unique] ICube *pIFDc);
+
+ HRESULT Clone(
+ [out] IBalls **ppIFDb);
+
+ HRESULT Echo(
+ [in] [unique] IUnknown *pIFDIn,
+ [out] IUnknown **ppIFDOut);
+
+}
+
+//]
+
diff --git a/private/oleutest/balls/idl/ibtest.idl b/private/oleutest/balls/idl/ibtest.idl
new file mode 100644
index 000000000..a5d5d576c
--- /dev/null
+++ b/private/oleutest/balls/idl/ibtest.idl
@@ -0,0 +1,32 @@
+//[ IBindTest_itf
+//+-------------------------------------------------------------------
+//
+// Interface: IBindTest (ib)
+//
+// Purpose: Interface for manipulating balls
+//
+// History: 23-Nov-92 Rickhi Created
+//
+// Notes:
+//
+//--------------------------------------------------------------------
+
+[ object,
+ uuid(00000138-0002-0008-C000-000000000046),
+ pointer_default(unique) ]
+
+interface IBindTest : IUnknown
+{
+ import "unknwn.idl";
+
+ SCODE Bind(
+ [in, string] LPWSTR pwszPath,
+ [in] REFIID riid,
+ [out, iid_is(riid)] IUnknown **ppv);
+
+ SCODE TestBindEcho(
+ [in, string] LPWSTR pwszDataIn,
+ [out, string] LPWSTR *ppwszDataOut);
+}
+
+//]
diff --git a/private/oleutest/balls/idl/icube.idl b/private/oleutest/balls/idl/icube.idl
new file mode 100644
index 000000000..c8a160cb9
--- /dev/null
+++ b/private/oleutest/balls/idl/icube.idl
@@ -0,0 +1,46 @@
+//[ ICube_itf
+//+-------------------------------------------------------------------
+//
+// Interface: ICube (ib)
+//
+// Purpose: Interface for manipulating cubes
+//
+// History: 23-Nov-92 Rickhi Created
+//
+// Notes:
+//
+//--------------------------------------------------------------------
+
+[ object,
+ uuid(00000139-0001-0008-c000-000000000046),
+ pointer_default(unique) ]
+
+interface ICube : IUnknown
+{
+ import "unknwn.idl";
+ import "iballs.idl";
+
+ HRESULT MoveCube(
+ [in] ULONG xPos,
+ [in] ULONG yPos);
+
+ HRESULT GetCubePos(
+ [out] ULONG *xPos,
+ [out] ULONG *yPos);
+
+ HRESULT Contains(
+ [in] [unique] IBalls *pIFDb);
+
+ HRESULT SimpleCall(
+ [in] DWORD pidCaller,
+ [in] DWORD tidCaller,
+ [in] GUID lidCaller);
+
+ HRESULT PrepForInputSyncCall(
+ [in] IUnknown *pUnkIn);
+
+ [input_sync]
+ HRESULT InputSyncCall(void);
+}
+
+//]
diff --git a/private/oleutest/balls/idl/iloop.idl b/private/oleutest/balls/idl/iloop.idl
new file mode 100644
index 000000000..007ae0908
--- /dev/null
+++ b/private/oleutest/balls/idl/iloop.idl
@@ -0,0 +1,29 @@
+//[ ILoop_itf
+//+-------------------------------------------------------------------
+//
+// Interface: ILoop (ib)
+//
+// Purpose: Interface for testing Rpc Looping
+//
+// History: 23-Nov-92 Rickhi Created
+//
+// Notes:
+//
+//--------------------------------------------------------------------
+
+[ object,
+ uuid(00000136-0001-0008-C000-000000000046),
+ pointer_default(unique) ]
+
+interface ILoop : IUnknown
+{
+ import "unknwn.idl";
+
+ HRESULT Init([in] ILoop *pRemoteLoop);
+
+ HRESULT Uninit(void);
+
+ HRESULT Loop([in] ULONG ulLoopCount);
+}
+
+//]
diff --git a/private/oleutest/balls/idl/makefile b/private/oleutest/balls/idl/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/oleutest/balls/idl/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/balls/idl/pch.cxx b/private/oleutest/balls/idl/pch.cxx
new file mode 100644
index 000000000..7dad5c005
--- /dev/null
+++ b/private/oleutest/balls/idl/pch.cxx
@@ -0,0 +1,24 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1991 - 1992.
+//
+// File: PCH.CXX
+//
+// Contents: Precompiled header
+//
+// History: 12-Jul-93 ShannonC Created
+//
+//--------------------------------------------------------------------------
+#pragma warning(disable:4101) // Local variable not used
+
+#include <windows.h>
+#include <basetyps.h>
+#include <varnt.h>
+#include <wtypes.h>
+#include <shtyps.h>
+#include <oletyp.h>
+#include <stdrpc.hxx>
+#include <idltyps.h>
+
+#pragma hdrstop
diff --git a/private/oleutest/balls/idl/prxydll.def b/private/oleutest/balls/idl/prxydll.def
new file mode 100644
index 000000000..9a7bb260a
--- /dev/null
+++ b/private/oleutest/balls/idl/prxydll.def
@@ -0,0 +1,47 @@
+#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 IBALLS
+
+DESCRIPTION 'Microsoft (R) OLE 2.0 Proxy/Stub DLL 1.00'
+
+EXPORTS
+
+#if defined(i386)
+
+ DllGetClassObject=DllGetClassObject@12 @1
+ DllCanUnloadNow=DllCanUnloadNow@0 @2
+
+#elif defined(_MIPS_)
+
+ DllGetClassObject @1
+ DllCanUnloadNow @2
+
+#endif // i386 - MIPS
+
+#endif // FLAT
diff --git a/private/oleutest/balls/idl/rawrpc.idl b/private/oleutest/balls/idl/rawrpc.idl
new file mode 100644
index 000000000..d41e75c25
--- /dev/null
+++ b/private/oleutest/balls/idl/rawrpc.idl
@@ -0,0 +1,59 @@
+//[ IRawRpc_itf
+//+-------------------------------------------------------------------
+//
+// Interface: IRawRpc
+//
+// Purpose: Interface for testing Rpc calls via Raw Rpc interfaces
+//
+// History: 23-Nov-92 Rickhi Created
+//
+// Notes:
+//
+//--------------------------------------------------------------------
+
+[ uuid(00000145-0001-0008-C000-000000000046),
+ pointer_default(unique) ]
+
+interface IRawRpc
+{
+ import "wtypes.idl";
+
+ // tells server process to exit.
+ SCODE Quit([in] handle_t hRpc);
+
+ // test passing void parameters
+ SCODE Void([in] handle_t hRpc);
+ SCODE VoidRC([in] handle_t hRpc);
+
+ // test passing void ptr parameters ie byte arrays
+ SCODE VoidPtrIn([in] handle_t hRpc,
+ [in] ULONG cb,
+ [in, size_is(cb)] BYTE *pv);
+
+ SCODE VoidPtrOut([in] handle_t hRpc,
+ [in] ULONG cb,
+ [out] ULONG *pcb,
+ [out, size_is(cb), length_is(*pcb)] BYTE *pv);
+
+ // test passing dword parameters
+ SCODE DwordIn([in] handle_t hRpc, [in] DWORD dw);
+ SCODE DwordOut([in] handle_t hRpc, [out] DWORD *pdw);
+ SCODE DwordInOut([in] handle_t hRpc, [in,out] DWORD *pdw);
+
+ // test passing LARGE_INTEGER parameters
+ SCODE LiIn([in] handle_t hRpc, [in] LARGE_INTEGER li);
+ SCODE LiOut([in] handle_t hRpc, [out] LARGE_INTEGER *pli);
+ SCODE ULiIn([in] handle_t hRpc, [in] ULARGE_INTEGER uli);
+ SCODE ULiOut([in] handle_t hRpc, [out] ULARGE_INTEGER *puli);
+
+ // test passing string parameters
+ SCODE StringIn([in] handle_t hRpc, [in,string] LPWSTR pwsz);
+ SCODE StringOut([in] handle_t hRpc, [out,string] LPWSTR *ppwsz);
+ SCODE StringInOut([in] handle_t hRpc, [in,out,string] LPWSTR pwsz);
+
+ // test passing GUID parameters
+ SCODE GuidIn([in] handle_t hRpc, [in] GUID guid);
+ SCODE GuidOut([in] handle_t hRpc, [out] GUID *pguid);
+}
+
+//]
diff --git a/private/oleutest/balls/idl/rpctst.idl b/private/oleutest/balls/idl/rpctst.idl
new file mode 100644
index 000000000..4c9e5e265
--- /dev/null
+++ b/private/oleutest/balls/idl/rpctst.idl
@@ -0,0 +1,66 @@
+//[ IRpcTest_itf
+//+-------------------------------------------------------------------
+//
+// Interface: IRpcTest (ib)
+//
+// Purpose: Interface for testing Rpc calls via Ole style interfaces
+//
+// History: 23-Nov-92 Rickhi Created
+//
+// Notes:
+//
+//--------------------------------------------------------------------
+
+[ object,
+ uuid(00000137-0001-0008-C000-000000000046),
+ pointer_default(unique) ]
+
+interface IRpcTest : IUnknown
+{
+ import "unknwn.idl";
+
+ // test passing void parameters
+ SCODE Void(void);
+ SCODE VoidRC(void);
+
+ // test passing void ptr parameters ie byte arrays
+ SCODE VoidPtrIn([in] ULONG cb, [in, size_is(cb)] BYTE *pv);
+ SCODE VoidPtrOut([in] ULONG cb, [out] ULONG *pcb,
+ [out, size_is(cb), length_is(*pcb)] BYTE *pv);
+
+ // test passing dword parameters
+ SCODE DwordIn([in] DWORD dw);
+ SCODE DwordOut([out] DWORD *pdw);
+ SCODE DwordInOut([in,out] DWORD *pdw);
+
+ // test passing LARGE_INTEGER parameters
+ SCODE LiIn([in] LARGE_INTEGER li);
+ SCODE LiOut([out] LARGE_INTEGER *pli);
+ SCODE ULiIn([in] ULARGE_INTEGER uli);
+ SCODE ULiOut([out] ULARGE_INTEGER *puli);
+
+ // test passing string parameters
+ SCODE StringIn([in,string] LPWSTR pwsz);
+ SCODE StringOut([out,string] LPWSTR *ppwsz);
+ SCODE StringInOut([in,out,string] LPWSTR pwsz);
+
+ // test passing GUID parameters
+ SCODE GuidIn([in] GUID guid);
+ SCODE GuidOut([out] GUID *pguid);
+
+ // test passing interface parameters
+ SCODE IUnknownIn([in] IUnknown *punk);
+ SCODE IUnknownOut([out] IUnknown **ppunk);
+
+ // these versions retain the interface ptr
+ SCODE IUnknownInKeep([in] IUnknown *punk);
+ SCODE IUnknownInRelease(void);
+
+ SCODE IUnknownOutKeep([out] IUnknown **ppunk);
+
+ // these versions test asking for a non-IUnknown interface
+ SCODE InterfaceIn([in] REFIID riid, [in, iid_is(riid)] IUnknown *punk);
+ SCODE InterfaceOut([in] REFIID riid, [out,iid_is(riid)] IUnknown **ppunk);
+}
+
+//]
diff --git a/private/oleutest/balls/idl/rpctyp.idl b/private/oleutest/balls/idl/rpctyp.idl
new file mode 100644
index 000000000..2265008fa
--- /dev/null
+++ b/private/oleutest/balls/idl/rpctyp.idl
@@ -0,0 +1,95 @@
+//[ IRpcTypes_itf
+//+-------------------------------------------------------------------
+//
+// Interface: IRpcTypes
+//
+// Purpose: Interface for testing Rpc calls via Ole style interfaces
+//
+// History: 23-Nov-92 Rickhi Created
+//
+// Notes:
+//
+//--------------------------------------------------------------------
+
+[ object,
+ uuid(00000135-0001-0008-C000-000000000046),
+ pointer_default(unique) ]
+
+interface IRpcTypes : IUnknown
+{
+ import "unknwn.idl";
+ import "estatd.idl";
+
+
+ // methods to test GUID parameter passing
+
+ SCODE GuidsIn([in] REFCLSID rclsid,
+ [in] CLSID clsid,
+ [in] REFIID riid,
+ [in] IID iid,
+ [in] GUID guid);
+
+ SCODE GuidsOut([out] CLSID *pclsid,
+ [out] IID *piid,
+ [out] GUID *pguid);
+
+
+ // methods to test DWORD / LARGE_INTEGER parameter passing
+
+ SCODE DwordIn([in] DWORD dw,
+ [in] ULONG ul,
+ [in] LONG lg,
+ [in] LARGE_INTEGER li,
+ [in] ULARGE_INTEGER uli);
+
+ SCODE DwordOut([out] DWORD *pdw,
+ [out] ULONG *pul,
+ [out] LONG *plg,
+ [out] LARGE_INTEGER *pli,
+ [out] ULARGE_INTEGER *puli);
+
+
+ // methods to test Windows structures parameter passing
+
+ SCODE WindowsIn([in] POINTL pointl,
+ [in] SIZEL sizel,
+ [in] RECTL rectl,
+ [in] FILETIME filetime,
+ [in] PALETTEENTRY paletentry,
+ [in] LOGPALETTE *plogpalet);
+
+ SCODE WindowsOut([out] POINTL *ppointl,
+ [out] SIZEL *psizel,
+ [out] RECTL *prectl,
+ [out] FILETIME *pfiletime,
+ [out] PALETTEENTRY *ppaletentry,
+ [out] LOGPALETTE **pplogpalet);
+
+
+ // methods to test OLE2.0 data/presentation structures parameter passing
+
+ SCODE OleDataIn([in] STATDATA statdata,
+ [in] STATSTG statstg,
+ [in] STGMEDIUM stgmedium,
+ [in] FORMATETC formatetc,
+ [in] DVTARGETDEVICE *pdvtargetdevice);
+
+ SCODE OleDataOut([out] STATDATA *pstatdata,
+ [out] STATSTG *pstatstg,
+ [out] STGMEDIUM *pstgmedium,
+ [out] FORMATETC *pformatetc,
+ [out] DVTARGETDEVICE **ppdvtargetdevice);
+
+
+ // methods to test void pointer parameter passing - mimics stream i/o
+
+ SCODE VoidPtrIn([in] ULONG cb,
+ [in, size_is(cb)] void *pv);
+
+ SCODE VoidPtrOut([out, size_is(cb), length_is(*pcb)] void *pv,
+ [in] ULONG cb,
+ [out] ULONG *pcb);
+
+}
+
+//]
diff --git a/private/oleutest/balls/idl/sources b/private/oleutest/balls/idl/sources
new file mode 100644
index 000000000..e71219326
--- /dev/null
+++ b/private/oleutest/balls/idl/sources
@@ -0,0 +1,30 @@
+!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:
+
+ Terry Rusell
+
+!ENDIF
+
+!include ..\types.inc
+
+SOURCES= \
+ iballs.idl \
+ ibtest.idl \
+ icube.idl \
+ iloop.idl \
+ rpctst.idl
diff --git a/private/oleutest/balls/idl/stdrpc.hxx b/private/oleutest/balls/idl/stdrpc.hxx
new file mode 100644
index 000000000..920d94511
--- /dev/null
+++ b/private/oleutest/balls/idl/stdrpc.hxx
@@ -0,0 +1,240 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: stdrpc.hxx
+//
+// Contents: Private header file for building interface proxies and stubs.
+//
+// Classes: CStdPSFactoryBuffer
+// CStubBase
+// CProxyBase
+// CStdProxyBuffer
+// CStreamOnMessage
+//
+// Functions: RpcInitMessage
+// RpcGetBuffer
+// RpcSendReceive
+// RpcFreeBuffer
+// RpcGetMarshalSizeMax
+// RpcMarshalInterface
+// RpcUnmarshalInterface
+// RpcClientErrorHandler
+// RpcServerErrorHandler
+//
+// History: 4-Jul-93 ShannonC Created
+// 3-Aug-93 ShannonC Changes for NT511 and IDispatch support.
+// 20-Oct-93 ShannonC Changed to new IRpcChannelBuffer interface.
+//
+//--------------------------------------------------------------------------
+#ifndef __STDRPC_HXX__
+#define __STDRPC_HXX__
+
+#define _OLE2ANAC_H_
+#include <stdclass.hxx>
+#include "rpcferr.h"
+
+#pragma warning(4:4355)
+//+-------------------------------------------------------------------------
+//
+// Class: CStdPSFactoryBuffer
+//
+// Synopsis: Standard implementation of a proxy/stub factory. Proxy/stub factory
+// implementations should inherit this class and implement the
+// method.
+//
+// Derivation: IPSFactoryBuffer
+//
+// Notes: By deriving a class from this base class, you automatically
+// acquire implementations of DllGetClassObject and DllCanUnloadNow.
+//
+//--------------------------------------------------------------------------
+class CStdPSFactoryBuffer : public IPSFactoryBuffer, public CStdFactory
+{
+public:
+
+ CStdPSFactoryBuffer(REFCLSID rcls);
+
+ //
+ // IUnknown methods
+ //
+
+ STDMETHOD(QueryInterface) ( REFIID riid, void** ppv );
+ STDMETHOD_(ULONG,AddRef) ( void );
+ STDMETHOD_(ULONG,Release) ( void );
+
+ //
+ // IPSFactoryBuffer methods must be provided in subclass.
+ //
+
+};
+
+#pragma warning(default:4355)
+
+//+-------------------------------------------------------------------------
+//
+// Class: CStubIUnknown
+//
+// Synopsis: Standard implementation of an RpcStubBuffer
+//
+// Derivation: IRpcStubBuffer
+//
+// Notes: The constructor calls DllAddRef, and the destructor calls
+// DllRelease. This updates the DLL reference count used by
+// DllCanUnloadNow.
+//
+//--------------------------------------------------------------------------
+
+class CStubIUnknown : public IRpcStubBuffer
+{
+public:
+ CStubIUnknown(REFIID riid);
+ ~CStubIUnknown();
+ virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppv);
+ virtual ULONG STDMETHODCALLTYPE AddRef();
+ virtual ULONG STDMETHODCALLTYPE Release();
+ virtual HRESULT STDMETHODCALLTYPE Connect(IUnknown *punkServer);
+ virtual void STDMETHODCALLTYPE Disconnect(void);
+ virtual IRpcStubBuffer *STDMETHODCALLTYPE IsIIDSupported(REFIID riid);
+ virtual ULONG STDMETHODCALLTYPE CountRefs(void);
+ virtual HRESULT STDMETHODCALLTYPE DebugServerQueryInterface(void **ppv);
+ virtual void STDMETHODCALLTYPE DebugServerRelease(void *pv);
+
+ void *_pInterface;
+ IID _iid;
+
+private:
+ ULONG _cRefs;
+ IUnknown *_punk;
+};
+
+//+-------------------------------------------------------------------------
+//
+// Class: CProxyIUnknown.
+//
+// Synopsis: Base class for interface proxy.
+//
+// Notes: The interface proxy is used by a CStdProxyBuffer.
+// We store the _iid so we can support dispinterfaces.
+//
+//--------------------------------------------------------------------------
+class CProxyIUnknown
+{
+public:
+ CProxyIUnknown(IUnknown *punkOuter, REFIID riid);
+ ~CProxyIUnknown();
+
+ virtual HRESULT STDMETHODCALLTYPE QueryInterface
+ (
+ REFIID riid,
+ void **ppvObject
+ );
+
+ virtual ULONG STDMETHODCALLTYPE AddRef
+ (
+ void
+ );
+
+ virtual ULONG STDMETHODCALLTYPE Release
+ (
+ void
+ );
+
+ IUnknown *_punkOuter;
+ IID _iid;
+ IRpcChannelBuffer *_pRpcChannel;
+ CProxyIUnknown *_pNext;
+};
+
+//+-------------------------------------------------------------------------
+//
+// Class: CStdProxyBuffer
+//
+// Synopsis: Standard implementation of an RpcProxyBuffer.
+//
+// Derivation: IRpcProxyBuffer
+//
+// Notes: The constructor calls DllAddRef, and the destructor calls
+// DllRelease. This updates the DLL reference count used by
+// DllCanUnloadNow.
+//
+// The _pProxy data member points to an interface proxy.
+// The interface proxy provides the public interface seen by the
+// client application.
+//
+//--------------------------------------------------------------------------
+class CStdProxyBuffer : public IRpcProxyBuffer
+{
+public:
+ CStdProxyBuffer(CProxyIUnknown *pProxy);
+ ~CStdProxyBuffer();
+ virtual ULONG STDMETHODCALLTYPE AddRef();
+ virtual ULONG STDMETHODCALLTYPE Release();
+ virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppv);
+ virtual HRESULT STDMETHODCALLTYPE Connect(IRpcChannelBuffer *pChannel);
+ virtual void STDMETHODCALLTYPE Disconnect();
+
+private:
+ ULONG _cRefs;
+ CProxyIUnknown *_pProxy;
+};
+
+typedef struct tagMIDLMESSAGE : tagRPCOLEMESSAGE
+{
+ IRpcChannelBuffer *pRpcChannel;
+ void *packet;
+ DWORD dwExceptionCode;
+} MIDLMESSAGE;
+
+void STDAPICALLTYPE RpcInitMessage(MIDLMESSAGE *pMessage, IRpcChannelBuffer *pRpcChannel);
+void STDAPICALLTYPE RpcGetBuffer(MIDLMESSAGE *pMessage, REFIID riid);
+void STDAPICALLTYPE RpcSendReceive(MIDLMESSAGE *pMessage);
+void STDAPICALLTYPE RpcFreeBuffer(MIDLMESSAGE *pMessage);
+void STDAPICALLTYPE RpcGetMarshalSizeMax(RPC_MESSAGE *pMessage, REFIID riid, IUnknown *punk);
+void STDAPICALLTYPE RpcMarshalInterface(RPC_MESSAGE *pMessage, REFIID riid, void *pv);
+void STDAPICALLTYPE RpcUnmarshalInterface(RPC_MESSAGE *pMessage, REFIID riid, void **ppv);
+void STDAPICALLTYPE RpcClientErrorHandler(MIDLMESSAGE *pMessage, DWORD dwException, HRESULT *phResult, error_status_t *pCommStatus, error_status_t *pFaultStatus);
+void STDAPICALLTYPE RpcCheckHRESULT(HRESULT hr);
+HRESULT STDAPICALLTYPE RpcServerErrorHandler(MIDLMESSAGE *pMessage, DWORD dwException);
+
+class CStreamOnMessage : public IStream
+{
+
+ public:
+ STDMETHOD (QueryInterface) ( THIS_ REFIID riid, LPVOID FAR* ppvObj);
+ STDMETHOD_(ULONG,AddRef) ( THIS );
+ STDMETHOD_(ULONG,Release) ( THIS );
+ STDMETHOD (Read) (THIS_ VOID HUGEP *pv,
+ ULONG cb, ULONG *pcbRead) ;
+ STDMETHOD (Write) (THIS_ VOID const HUGEP *pv,
+ ULONG cb,
+ ULONG *pcbWritten) ;
+ STDMETHOD (Seek) (THIS_ LARGE_INTEGER dlibMove,
+ DWORD dwOrigin,
+ ULARGE_INTEGER *plibNewPosition) ;
+ STDMETHOD (SetSize) (THIS_ ULARGE_INTEGER libNewSize) ;
+ STDMETHOD (CopyTo) (THIS_ IStream *pstm,
+ ULARGE_INTEGER cb,
+ ULARGE_INTEGER *pcbRead,
+ ULARGE_INTEGER *pcbWritten) ;
+ STDMETHOD (Commit) (THIS_ DWORD grfCommitFlags) ;
+ STDMETHOD (Revert) (THIS) ;
+ STDMETHOD (LockRegion) (THIS_ ULARGE_INTEGER libOffset,
+ ULARGE_INTEGER cb,
+ DWORD dwLockType) ;
+ STDMETHOD (UnlockRegion) (THIS_ ULARGE_INTEGER libOffset,
+ ULARGE_INTEGER cb,
+ DWORD dwLockType) ;
+ STDMETHOD (Stat) (THIS_ STATSTG *pstatstg, DWORD grfStatFlag) ;
+ STDMETHOD (Clone) (THIS_ IStream * *ppstm) ;
+
+ CStreamOnMessage( MIDLMESSAGE *pMessage);
+ ~CStreamOnMessage();
+
+ unsigned char *actual_buffer;
+ MIDLMESSAGE *message;
+ ULONG ref_count;
+};
+
+#endif //__STDRPC_HXX__
diff --git a/private/oleutest/balls/idl/unknwn.idl b/private/oleutest/balls/idl/unknwn.idl
new file mode 100644
index 000000000..bacfecd0c
--- /dev/null
+++ b/private/oleutest/balls/idl/unknwn.idl
@@ -0,0 +1,33 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: unknwn.idl
+//
+// Contents: IUnknown interface definition
+//
+// History: 06-08-93 ShannonC Updated to OLE 2 release
+//
+//--------------------------------------------------------------------------
+[
+ local,
+ object,
+ uuid(00000000-0000-0000-C000-000000000046),
+ pointer_default(unique)
+]
+
+interface IUnknown
+{
+ import "wtypes.idl";
+
+ typedef [unique] IUnknown *LPUNKNOWN;
+
+ HRESULT QueryInterface(
+ [in] REFIID riid,
+ [out] void **ppvObject);
+
+ ULONG AddRef();
+
+ ULONG Release();
+}
diff --git a/private/oleutest/balls/idl/wtypes.idl b/private/oleutest/balls/idl/wtypes.idl
new file mode 100644
index 000000000..b15bc47f4
--- /dev/null
+++ b/private/oleutest/balls/idl/wtypes.idl
@@ -0,0 +1,741 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: $(COMMON)\types\wtypes.idl
+//
+// Contents: This interface definition contains typedefs for remotable
+// data types. Most of these data types come from compobj.h.
+//
+// History: 07-Apr-93 ShannonC Added header
+// 09-Sep-93 ShannonC Fixed memory leak in _free_xmit
+// 02-May-94 BruceMa Added spec'd but unimplemeted constant
+//
+//--------------------------------------------------------------------------
+
+[ uuid(D3980A60-910C-1068-9341-00DD010F2F1C),
+ version(0.1), pointer_default(unique) ]
+
+interface IWinTypes
+{
+
+// BUGBUG, make sure and verify this before putting in the build.
+// TerryRu 04/16/94
+
+//cpp_quote("#include <basetyps.h>")
+
+cpp_quote("#pragma warning(disable:4200)")
+typedef struct tagRemHGLOBAL
+{
+ long fNullHGlobal;
+ unsigned long cbData;
+ [size_is(cbData)] byte data[];
+} RemHGLOBAL;
+cpp_quote("#pragma warning(default:4200)")
+
+cpp_quote("#pragma warning(disable:4200)")
+typedef struct tagRemHMETAFILEPICT
+{
+ long mm;
+ long xExt;
+ long yExt;
+ unsigned long cbData;
+ [size_is(cbData)] byte data[];
+} RemHMETAFILEPICT;
+cpp_quote("#pragma warning(default:4200)")
+
+typedef [transmit_as(RemHMETAFILEPICT)] void * HMETAFILEPICT;
+
+cpp_quote("#pragma warning(disable:4200)")
+typedef struct tagRemHENHMETAFILE
+{
+ unsigned long cbData;
+ [size_is(cbData)] byte data[];
+} RemHENHMETAFILE;
+cpp_quote("#pragma warning(default:4200)")
+
+cpp_quote("#pragma warning(disable:4200)")
+typedef struct tagRemHBITMAP
+{
+ unsigned long cbData;
+ [size_is(cbData)] byte data[];
+} RemHBITMAP;
+cpp_quote("#pragma warning(default:4200)")
+
+cpp_quote("#pragma warning(disable:4200)")
+typedef struct tagRemBRUSH
+{
+ unsigned long cbData;
+ [size_is(cbData)] byte data[];
+} RemHBRUSH;
+cpp_quote("#pragma warning(default:4200)")
+
+
+cpp_quote("#ifndef WIN32 // The following code is for Win16 only")
+cpp_quote("#ifndef WINAPI // If not included with 3.1 headers... ")
+
+cpp_quote("#define FAR _far")
+cpp_quote("#define PASCAL _pascal")
+cpp_quote("#define CDECL _cdecl")
+
+cpp_quote("#define VOID void")
+cpp_quote("#define WINAPI FAR PASCAL")
+cpp_quote("#define CALLBACK FAR PASCAL")
+
+
+
+cpp_quote("#ifndef FALSE")
+cpp_quote("#define FALSE 0")
+cpp_quote("#define TRUE 1")
+cpp_quote("#endif // !FALSE")
+
+cpp_quote("#ifndef _BYTE_DEFINED")
+cpp_quote("#define _BYTE_DEFINED")
+typedef unsigned char BYTE;
+cpp_quote("#endif // !_BYTE_DEFINED")
+
+cpp_quote("#ifndef _WORD_DEFINED")
+cpp_quote("#define _WORD_DEFINED")
+typedef unsigned short WORD;
+cpp_quote("#endif // !_WORD_DEFINED")
+
+typedef [transmit_as(unsigned long)] unsigned int UINT;
+typedef [transmit_as(long)] int INT;
+typedef long BOOL;
+
+cpp_quote("#ifndef _LONG_DEFINED")
+cpp_quote("#define _LONG_DEFINED")
+typedef long LONG;
+cpp_quote("#endif // !_LONG_DEFINED")
+
+cpp_quote("#ifndef _WPARAM_DEFINED")
+cpp_quote("#define _WPARAM_DEFINED")
+typedef UINT WPARAM;
+cpp_quote("#endif // _WPARAM_DEFINED")
+
+cpp_quote("#ifndef _DWORD_DEFINED")
+cpp_quote("#define _DWORD_DEFINED")
+typedef unsigned long DWORD;
+cpp_quote("#endif // !_DWORD_DEFINED")
+
+cpp_quote("#ifndef _LPARAM_DEFINED")
+cpp_quote("#define _LPARAM_DEFINED")
+typedef LONG LPARAM;//BUGBUG: this should be a discriminated union.
+cpp_quote("#endif // !_LPARAM_DEFINED")
+
+cpp_quote("#ifndef _LRESULT_DEFINED")
+cpp_quote("#define _LRESULT_DEFINED")
+typedef LONG LRESULT;
+cpp_quote("#endif // !_LRESULT_DEFINED")
+
+typedef [transmit_as(long)] void *HANDLE;
+
+#define DECLARE_HANDLE(name) typedef [transmit_as(long)] void * name
+
+DECLARE_HANDLE(HMODULE);
+DECLARE_HANDLE(HINSTANCE);
+DECLARE_HANDLE(HICON);
+DECLARE_HANDLE(HFONT);
+typedef [transmit_as(RemHGLOBAL)] void * HGLOBAL;
+typedef HGLOBAL HLOCAL;
+typedef [transmit_as(RemHBITMAP)] void * HBITMAP;
+typedef [transmit_as(RemHBRUSH)] void * HBRUSH;
+typedef [transmit_as(RemHENHMETAFILE)] void * HENHMETAFILE;
+DECLARE_HANDLE(HDC);
+DECLARE_HANDLE(HRGN);
+DECLARE_HANDLE(HWND);
+DECLARE_HANDLE(HMENU);
+DECLARE_HANDLE(HACCEL);
+DECLARE_HANDLE(HTASK);
+DECLARE_HANDLE(HKEY);
+
+DECLARE_HANDLE(HDESK);
+/* DECLARE_HANDLE(HENHMETAFILE); */
+DECLARE_HANDLE(HMF);
+DECLARE_HANDLE(HEMF);
+DECLARE_HANDLE(HMETAFILE);
+DECLARE_HANDLE(HPALETTE);
+DECLARE_HANDLE(HPEN);
+DECLARE_HANDLE(HRSRC);
+DECLARE_HANDLE(HSTR);
+DECLARE_HANDLE(HWINSTA);
+DECLARE_HANDLE(HKL);
+DECLARE_HANDLE(HGDIOBJ);
+
+typedef HANDLE HDWP;
+
+cpp_quote("#ifndef _HFILE_DEFINED")
+cpp_quote("#define _HFILE_DEFINED")
+typedef INT HFILE; /* Polymorphic with C runtime file handle type */
+cpp_quote("#endif // !_HFILE_DEFINED")
+
+
+cpp_quote("#ifndef _HCURSOR_DEFINED")
+cpp_quote("#define _HCURSOR_DEFINED")
+typedef HICON HCURSOR; /* HICONs & HCURSORs are polymorphic */
+cpp_quote("#endif // !_HCURSOR_DEFINED")
+
+
+
+cpp_quote("#ifndef _LPWORD_DEFINED")
+cpp_quote("#define _LPWORD_DEFINED")
+typedef WORD *LPWORD;
+cpp_quote("#endif // !_LPWORD_DEFINED")
+
+
+cpp_quote("#ifndef _LPDWORD_DEFINED")
+cpp_quote("#define _LPDWORD_DEFINED")
+typedef DWORD *LPDWORD;
+cpp_quote("#endif // !_LPDWORD_DEFINED")
+
+
+// LPSTR is a base type of TDL
+#if !defined(__MKTYPLIB__)
+typedef [string] char *LPSTR;
+#endif
+
+typedef [string] const char *LPCSTR;
+
+
+cpp_quote("#ifndef _WCHAR_DEFINED")
+cpp_quote("#define _WCHAR_DEFINED")
+typedef wchar_t WCHAR;
+typedef WCHAR TCHAR;
+cpp_quote("#endif // !_WCHAR_DEFINED")
+
+// LPWSTR is a TDL base type
+#if !defined(__MKTYPLIB__)
+typedef [string] WCHAR *LPWSTR;
+#endif
+
+
+typedef [string] TCHAR *LPTSTR;
+
+typedef [string] const WCHAR *LPCWSTR;
+typedef [string] const TCHAR *LPCTSTR;
+
+
+typedef struct tagPALETTEENTRY {
+ BYTE peRed;
+ BYTE peGreen;
+ BYTE peBlue;
+ BYTE peFlags;
+} PALETTEENTRY, *PPALETTEENTRY, *LPPALETTEENTRY;
+
+// Logical Palette
+cpp_quote("#if 0")
+
+ typedef struct tagLOGPALETTE {
+ WORD palVersion;
+ WORD palNumEntries;
+ [size_is(palNumEntries)] PALETTEENTRY palPalEntry[];
+ } LOGPALETTE, *PLOGPALETTE, *LPLOGPALETTE;
+
+cpp_quote("#else")
+cpp_quote("typedef struct tagLOGPALETTE {")
+cpp_quote(" WORD palVersion;")
+cpp_quote(" WORD palNumEntries;")
+cpp_quote(" PALETTEENTRY palPalEntry[1];")
+cpp_quote("} LOGPALETTE, *PLOGPALETTE, *LPLOGPALETTE;")
+cpp_quote("#endif")
+
+cpp_quote("#ifndef _COLORREF_DEFINED")
+cpp_quote("#define _COLORREF_DEFINED")
+typedef DWORD COLORREF;
+cpp_quote("#endif // !_COLORREF_DEFINED")
+
+cpp_quote("#ifndef _LPCOLORREF_DEFINED")
+cpp_quote("#define _LPCOLORREF_DEFINED")
+typedef DWORD *LPCOLORREF;
+cpp_quote("#endif // !_LPCOLORREF_DEFINED")
+
+
+typedef HANDLE *LPHANDLE;
+
+//typedefs for remotable types from wingdi.h
+
+typedef struct _RECTL
+{
+ LONG left;
+ LONG top;
+ LONG right;
+ LONG bottom;
+} RECTL, *PRECTL, *LPRECTL;
+
+
+typedef struct tagPOINT
+{
+ LONG x;
+ LONG y;
+} POINT, *PPOINT, *LPPOINT;
+
+typedef struct _POINTL
+{
+ LONG x;
+ LONG y;
+} POINTL, *PPOINTL;
+
+
+
+cpp_quote("#ifndef WIN16")
+typedef struct tagSIZE
+{
+ LONG cx;
+ LONG cy;
+} SIZE, *PSIZE, *LPSIZE;
+cpp_quote("#else // WIN16")
+cpp_quote("typedef struct tagSIZE")
+cpp_quote("{")
+cpp_quote(" INT cx;")
+cpp_quote(" INT cy;")
+cpp_quote("} SIZE, *PSIZE, *LPSIZE;")
+cpp_quote("#endif // WIN16")
+
+
+// Message structure
+
+typedef struct tagMSG {
+ HWND hwnd;
+ UINT message;
+ WPARAM wParam;
+ LPARAM lParam;
+ DWORD time;
+ POINT pt;
+} MSG, *PMSG, *NPMSG, *LPMSG;
+
+
+
+typedef struct tagSIZEL
+{
+ LONG cx;
+ LONG cy;
+} SIZEL, *PSIZEL, *LPSIZEL;
+
+
+cpp_quote("#endif //WINAPI")
+cpp_quote("#endif //!WIN32")
+
+
+//
+// BUGBUG: review for chicago
+//
+
+
+cpp_quote("#if defined(WIN32) && !defined(OLE2ANSI)")
+
+typedef WCHAR OLECHAR;
+typedef [string] OLECHAR *LPOLESTR;
+typedef [string] const OLECHAR *LPCOLESTR;
+cpp_quote("#define OLESTR(str) L##str")
+
+cpp_quote("#else")
+
+cpp_quote("typedef char OLECHAR;")
+cpp_quote("typedef LPSTR LPOLESTR;")
+cpp_quote("typedef LPCSTR LPCOLESTR;")
+cpp_quote("#define OLESTR(str) str")
+
+cpp_quote("#endif")
+
+
+
+typedef const RECTL *LPCRECTL;
+
+
+// This block contains types that are normally defined by the nt sdk in WINDEF.H
+// but we need them here for definitions that follow in this file. If WINDEF.H
+// hasn't been included then we need to define them now so that WTYPES.H
+// will compile.
+cpp_quote("#ifndef _WINDEF_")
+typedef void * PVOID, *LPVOID;
+typedef struct tagRECT
+{
+ LONG left;
+ LONG top;
+ LONG right;
+ LONG bottom;
+} RECT, *PRECT, *LPRECT;
+cpp_quote("#endif //_WINDEF_")
+
+
+
+
+
+
+
+typedef unsigned char UCHAR;
+typedef short SHORT;
+typedef unsigned short USHORT;
+typedef DWORD ULONG;
+
+cpp_quote("#if !defined(_WINNT_) && !defined (_NTDEF_)")
+typedef struct _LARGE_INTEGER {
+ DWORD LowPart;
+ LONG HighPart;
+} LARGE_INTEGER, *PLARGE_INTEGER;
+
+typedef struct _ULARGE_INTEGER {
+ DWORD LowPart;
+ DWORD HighPart;
+} ULARGE_INTEGER, *PULARGE_INTEGER;
+cpp_quote("#endif // !defined(_WINNT_) && !defined (_NTDEF_)")
+
+
+cpp_quote("#ifndef _WINBASE_")
+
+cpp_quote("#ifndef _FILETIME_")
+cpp_quote("#define _FILETIME_")
+typedef struct _FILETIME
+{
+ DWORD dwLowDateTime;
+ DWORD dwHighDateTime;
+} FILETIME, *PFILETIME, *LPFILETIME;
+cpp_quote("#endif // !_FILETIME")
+
+cpp_quote("#ifndef _SYSTEMTIME_")
+cpp_quote("#define _SYSTEMTIME_")
+typedef struct _SYSTEMTIME {
+ WORD wYear;
+ WORD wMonth;
+ WORD wDayOfWeek;
+ WORD wDay;
+ WORD wHour;
+ WORD wMinute;
+ WORD wSecond;
+ WORD wMilliseconds;
+} SYSTEMTIME, *PSYSTEMTIME, *LPSYSTEMTIME;
+cpp_quote("#endif // !_SYSTEMTIME")
+
+cpp_quote("#ifndef _SECURITY_ATTRIBUTES_")
+cpp_quote("#define _SECURITY_ATTRIBUTES_")
+typedef struct _SECURITY_ATTRIBUTES {
+ DWORD nLength;
+ [size_is(nLength)] LPVOID lpSecurityDescriptor;
+ BOOL bInheritHandle;
+} SECURITY_ATTRIBUTES, *PSECURITY_ATTRIBUTES, *LPSECURITY_ATTRIBUTES;
+cpp_quote("#endif // !_SECURITY_ATTRIBUTES_")
+
+cpp_quote("#ifndef SECURITY_DESCRIPTOR_REVISION")
+
+typedef USHORT SECURITY_DESCRIPTOR_CONTROL, *PSECURITY_DESCRIPTOR_CONTROL;
+
+typedef PVOID PSID; // winnt
+
+typedef struct _ACL {
+ UCHAR AclRevision;
+ UCHAR Sbz1;
+ USHORT AclSize;
+ USHORT AceCount;
+ USHORT Sbz2;
+} ACL;
+typedef ACL *PACL;
+
+typedef struct _SECURITY_DESCRIPTOR {
+ UCHAR Revision;
+ UCHAR Sbz1;
+ SECURITY_DESCRIPTOR_CONTROL Control;
+ PSID Owner;
+ PSID Group;
+ PACL Sacl;
+ PACL Dacl;
+} SECURITY_DESCRIPTOR, *PISECURITY_DESCRIPTOR;
+
+cpp_quote("#endif // !SECURITY_DESCRIPTOR_REVISION")
+
+cpp_quote("#endif //_WINBASE_")
+
+
+//
+// SCODE, HRESULT
+//
+//
+// Status values are 32 bit values layed out as follows:
+//
+// 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
+// 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+// +-+-----------------------------+-------------------------------+
+// |S| Facility | Code |
+// +-+-----------------------------+-------------------------------+
+//
+// where
+//
+// S - is the severity code
+//
+// 0 - Success
+// 1 - Error
+//
+//
+// Facility - is the facility code
+//
+// Code - is the facility's status code
+//
+// SCODE and HRESULT are mktyplib base types.
+//
+#ifndef __MKTYPLIB__
+typedef LONG SCODE;
+typedef LONG HRESULT;
+#endif // !__MKTYPLIB__
+
+typedef SCODE *PSCODE;
+
+
+cpp_quote("#ifndef GUID_DEFINED")
+cpp_quote("#define GUID_DEFINED")
+typedef struct _GUID
+{
+ DWORD Data1;
+ WORD Data2;
+ WORD Data3;
+ BYTE Data4[8];
+} GUID;
+cpp_quote("#endif // !GUID_DEFINED")
+
+cpp_quote("#if !defined( __LPGUID_DEFINED__ )")
+cpp_quote("#define __LPGUID_DEFINED__")
+typedef GUID *LPGUID;
+cpp_quote("#endif // !__LPGUID_DEFINED__")
+
+cpp_quote("#ifndef __OBJECTID_DEFINED")
+cpp_quote("#define __OBJECTID_DEFINED")
+cpp_quote("#define _OBJECTID_DEFINED")
+typedef struct _OBJECTID // NOTE!! Order of structure members is important for OFS
+{ // enumeration.
+ GUID Lineage; // Unique for objects copied from same original and copies of.
+ unsigned long Uniquifier; // Random, to provide uniqueness within small set with same
+} OBJECTID; // lineage id.
+cpp_quote("#endif // !_OBJECTID_DEFINED")
+
+
+
+
+cpp_quote("#if !defined( __IID_DEFINED__ )")
+cpp_quote("#define __IID_DEFINED__")
+
+// Interface ID are just a kind of GUID
+typedef GUID IID;
+typedef IID *LPIID;
+cpp_quote("#define IID_NULL GUID_NULL")
+cpp_quote("#define IsEqualIID(riid1, riid2) IsEqualGUID(riid1, riid2)")
+
+// Class ID are just a kind of GUID
+typedef GUID CLSID;
+typedef CLSID *LPCLSID;
+cpp_quote("#define CLSID_NULL GUID_NULL")
+cpp_quote("#define IsEqualCLSID(rclsid1, rclsid2) IsEqualGUID(rclsid1, rclsid2)")
+
+#ifndef __MKTYPLIB__
+
+//The following typedefs are used internally by MIDL.
+cpp_quote("#if 0")
+#if defined(__midl)
+ /* MIDL 2.0 definitions */
+ typedef GUID *REFGUID;
+ typedef IID *REFIID;
+ typedef CLSID *REFCLSID;
+#else
+ /* MIDL 1.1 definitions */
+ typedef GUID REFGUID;
+ typedef IID REFIID;
+ typedef CLSID REFCLSID;
+#endif
+cpp_quote("#endif // 0")
+
+cpp_quote("#if defined(__cplusplus)")
+
+cpp_quote("#ifndef _REFGUID_DEFINED")
+cpp_quote("#define _REFGUID_DEFINED")
+cpp_quote("#define REFGUID const GUID &")
+cpp_quote("#endif // !_REFGUID_DEFINED")
+
+cpp_quote("#ifndef _REFIID_DEFINED")
+cpp_quote("#define _REFIID_DEFINED")
+cpp_quote("#define REFIID const IID &")
+cpp_quote("#endif // !_REFIID_DEFINED")
+
+cpp_quote("#ifndef _REFCLSID_DEFINED")
+cpp_quote("#define _REFCLSID_DEFINED")
+cpp_quote("#define REFCLSID const CLSID &")
+cpp_quote("#endif // !_REFCLSID_DEFINED")
+
+
+cpp_quote("#else // !__cplusplus")
+
+cpp_quote("#ifndef _REFGUID_DEFINED")
+cpp_quote("#define _REFGUID_DEFINED")
+cpp_quote("#define REFGUID const GUID * const")
+cpp_quote("#endif // !_REFGUID_DEFINED")
+
+cpp_quote("#ifndef _REFIID_DEFINED")
+cpp_quote("#define _REFIID_DEFINED")
+cpp_quote("#define REFIID const IID * const")
+cpp_quote("#endif // !_REFIID_DEFINED")
+
+
+cpp_quote("#ifndef _REFCLSID_DEFINED")
+cpp_quote("#define _REFCLSID_DEFINED")
+cpp_quote("#define REFCLSID const CLSID * const")
+cpp_quote("#endif // !_REFCLSID_DEFINED")
+
+cpp_quote("#endif // !__cplusplus")
+
+
+#else // __MKTYPLIB__
+
+typedef GUID const *REFGUID;
+typedef IID const *REFIID;
+typedef CLSID const *REFCLSID;
+
+#endif // _MKTYPLIB__
+
+cpp_quote("#endif // !__IID_DEFINED__")
+
+ /************************* Misc types ***********************************/
+
+ // Common typdefs used in API paramaters, gleamed from compobj.h
+
+ // memory context values; passed to CoGetMalloc
+ typedef enum tagMEMCTX
+ {
+ MEMCTX_TASK = 1, // task (private) memory
+ MEMCTX_SHARED = 2, // shared memory (between processes)
+ MEMCTX_MACSYSTEM = 3, // on the mac, the system heap
+ // these are mostly for internal use...
+ MEMCTX_UNKNOWN = -1, // unknown context (when asked about it)
+ MEMCTX_SAME = -2, // same context (as some other pointer)
+ } MEMCTX;
+
+
+// For IRunningObjectTable::Register
+cpp_quote("#ifndef _ROTFLAGS_DEFINED")
+cpp_quote("#define _ROTFLAGS_DEFINED")
+cpp_quote("#define ROTFLAGS_REGISTRATIONKEEPSALIVE 1")
+cpp_quote("#endif // !_ROTFLAGS_DEFINED")
+
+
+
+ // class context: used to determine what scope and kind of class object to use
+ // NOTE: this is a bitwise enum
+ typedef enum tagCLSCTX
+ {
+ CLSCTX_INPROC_SERVER = 1, // server dll (runs in same process as caller)
+ CLSCTX_INPROC_HANDLER = 2, // handler dll (runs in same process as caller)
+ CLSCTX_LOCAL_SERVER = 4, // server exe (runs on same machine; diff proc)
+ CLSCTX_INPROC_SERVER16 = 8 // 16-bit server dll (runs in same process as caller)
+ } CLSCTX;
+
+
+ // marshaling flags; passed to CoMarshalInterface
+ typedef enum tagMSHLFLAGS
+ {
+ MSHLFLAGS_NORMAL = 0, // normal marshaling via proxy/stub
+ MSHLFLAGS_TABLESTRONG = 1, // keep object alive; must explicitly release
+ MSHLFLAGS_TABLEWEAK = 2 // doesn't hold object alive; still must release
+ } MSHLFLAGS;
+
+ // marshal context: determines the destination context of the marshal operation
+ typedef enum tagMSHCTX
+ {
+ MSHCTX_LOCAL = 0, // unmarshal context is local (eg.shared memory)
+ MSHCTX_NOSHAREDMEM = 1, // unmarshal context has no shared memory access
+ MSHCTX_DIFFERENTMACHINE = 2,// unmarshal context is on a different machine
+ } MSHCTX;
+
+
+
+
+ //
+ // Common typedefs for paramaters used in data view API's, gleamed
+ // from dvobj.h
+ //
+
+ // Data/View aspect; specifies the desired aspect of the object when
+ // drawing or getting data.
+ typedef enum tagDVASPECT
+ {
+ DVASPECT_CONTENT = 1,
+ DVASPECT_THUMBNAIL = 2,
+ DVASPECT_ICON = 4,
+ DVASPECT_DOCPRINT = 8
+ } DVASPECT;
+
+ /****** Storage types *************************************************/
+
+
+ /* Storage commit types */
+ typedef enum tagSTGC
+ {
+ STGC_DEFAULT = 0,
+ STGC_OVERWRITE = 1,
+ STGC_ONLYIFCURRENT = 2,
+ STGC_DANGEROUSLYCOMMITMERELYTODISKCACHE = 4
+ } STGC;
+
+
+
+ typedef enum tagSTGMOVE
+ {
+ STGMOVE_MOVE = 0,
+ STGMOVE_COPY = 1
+ } STGMOVE;
+
+ typedef enum tagSTATFLAG
+ {
+ STATFLAG_DEFAULT = 0,
+ STATFLAG_NONAME = 1
+ } STATFLAG;
+
+ typedef enum tagSTGFMT
+ {
+ STGFMT_DOCUMENT = 0,
+ STGFMT_DIRECTORY = 1,
+ STGFMT_CATALOG = 2,
+ STGFMT_FILE = 3
+
+ } STGFMT;
+
+
+
+
+typedef [context_handle] void *HCONTEXT;
+
+/****** Critical Section Wrappers ***********************************/
+
+
+/* if not already picked up from olenls.h */
+cpp_quote("#ifndef _LCID_DEFINED")
+cpp_quote("#define _LCID_DEFINED")
+typedef DWORD LCID;
+cpp_quote("#endif // !_LCID_DEFINED")
+
+
+
+typedef const RECT *LPCRECT;
+
+
+cpp_quote("void __RPC_API HGLOBAL_to_xmit (HGLOBAL __RPC_FAR *, RemHGLOBAL __RPC_FAR * __RPC_FAR *);")
+cpp_quote("void __RPC_API HGLOBAL_from_xmit (RemHGLOBAL __RPC_FAR *, HGLOBAL __RPC_FAR *);")
+cpp_quote("void __RPC_API HGLOBAL_free_inst (HGLOBAL __RPC_FAR *);")
+cpp_quote("void __RPC_API HGLOBAL_free_xmit (RemHGLOBAL __RPC_FAR *);")
+
+cpp_quote("void __RPC_API HBITMAP_to_xmit (HBITMAP __RPC_FAR *, RemHBITMAP __RPC_FAR * __RPC_FAR *);")
+cpp_quote("void __RPC_API HBITMAP_from_xmit (RemHBITMAP __RPC_FAR *, HBITMAP __RPC_FAR *);")
+cpp_quote("void __RPC_API HBITMAP_free_inst (HBITMAP __RPC_FAR *);")
+cpp_quote("void __RPC_API HBITMAP_free_xmit (RemHBITMAP __RPC_FAR *);")
+
+cpp_quote("void __RPC_API HBRUSH_to_xmit (HBRUSH __RPC_FAR *, RemHBRUSH __RPC_FAR * __RPC_FAR *);")
+cpp_quote("void __RPC_API HBRUSH_from_xmit (RemHBRUSH __RPC_FAR *, HBRUSH __RPC_FAR *);")
+cpp_quote("void __RPC_API HBRUSH_free_inst (HBRUSH __RPC_FAR *);")
+cpp_quote("void __RPC_API HBRUSH_free_xmit (RemHBRUSH __RPC_FAR *);")
+
+cpp_quote("void __RPC_API HMETAFILEPICT_to_xmit (HMETAFILEPICT __RPC_FAR *, RemHMETAFILEPICT __RPC_FAR * __RPC_FAR *);")
+cpp_quote("void __RPC_API HMETAFILEPICT_from_xmit (RemHMETAFILEPICT __RPC_FAR *, HMETAFILEPICT __RPC_FAR *);")
+cpp_quote("void __RPC_API HMETAFILEPICT_free_inst (HMETAFILEPICT __RPC_FAR *);")
+cpp_quote("void __RPC_API HMETAFILEPICT_free_xmit (RemHMETAFILEPICT __RPC_FAR *);")
+
+cpp_quote("void __RPC_API HENHMETAFILE_to_xmit (HENHMETAFILE __RPC_FAR *, RemHENHMETAFILE __RPC_FAR * __RPC_FAR *);")
+cpp_quote("void __RPC_API HENHMETAFILE_from_xmit (RemHENHMETAFILE __RPC_FAR *, HENHMETAFILE __RPC_FAR *);")
+cpp_quote("void __RPC_API HENHMETAFILE_free_inst (HENHMETAFILE __RPC_FAR *);")
+cpp_quote("void __RPC_API HENHMETAFILE_free_xmit (RemHENHMETAFILE __RPC_FAR *);")
+
+}
diff --git a/private/oleutest/balls/licfiles.sed b/private/oleutest/balls/licfiles.sed
new file mode 100644
index 000000000..58c56ed7e
--- /dev/null
+++ b/private/oleutest/balls/licfiles.sed
@@ -0,0 +1,6 @@
+s/\.[lL][iI][bB]/\.lic/
+/\.lic/!d
+s/ *$//g
+s/ *$//g
+s/\(.*\)lic$/copy \1lic/
+s/\(.*\)lic$/\1lic 1>nul 2>nul/
diff --git a/private/oleutest/balls/makefil0 b/private/oleutest/balls/makefil0
new file mode 100644
index 000000000..3a5a9ea4a
--- /dev/null
+++ b/private/oleutest/balls/makefil0
@@ -0,0 +1,16 @@
+!include $(NTMAKEENV)\makefile.plt
+!include dirs
+
+DIR=$(DIRS) $(OPTIONAL_DIRS)
+DIRS=$(DIRS:oleprx32=oleprx32\daytona)
+
+all:
+!IF "$(BUILDMSG)" != ""
+ @ech ; $(BUILDMSG) ;
+!ENDIF
+
+clean: cleansrc all
+
+cleansrc:
+ for %%i in ($(DIRS)) do cd %i & nmake -nologo BUILDMSG= clean & cd $(MAKEDIR)
+
diff --git a/private/oleutest/balls/makefile.inc b/private/oleutest/balls/makefile.inc
new file mode 100644
index 000000000..8f0a3b721
--- /dev/null
+++ b/private/oleutest/balls/makefile.inc
@@ -0,0 +1,2801 @@
+############################################################################
+#
+# Microsoft Windows
+# Copyright (C) Microsoft Corporation, 1991 - 1992.
+#
+# File: makefile.inc
+#
+# Contents: Main project makefile
+#
+# History:
+#
+#
+############################################################################
+
+
+#** Make include file
+#
+# Definitions for compiler
+#
+# GCFLAGS - additional flags for the C compiler, intended only
+# to be used for global changes. DONT EVER PUT THIS
+# IN A MAKEFILE.
+# GAFLAGS - Same as GCFLAGS, but for the assembler.
+#
+#
+# -------------------- Build Type Control ------------------------------------
+#
+# The "build type" determines what kind of internal checking is done.
+# Turning on checking allows for catching more internal
+# consistency errors, but slows the system down.
+#
+# Mechanically, one changes the build type the makefile is set for by
+# editing the makefile to comment in or out the OBFLAGS line of interest.
+# (Separate entry points cannot easily be used for this, this is a failing
+# of make. That's why you have to edit the makefile.)
+#
+#
+
+############################################################################
+#
+# Default target is "all"
+#
+
+default: all
+
+
+############################################################################
+#
+# Suffixes for inference rules
+#
+
+.SUFFIXES:
+.SUFFIXES: .idl .tdl .tlb .dll .h .inc .exe .obj .lst .cod .cxx .cpp
+.SUFFIXES: .c .s .lrf .lnk .map .sym .rc .lib .def .res .dgn .rtf .y .mc
+.SUFFIXES: .i .ico .bmp .dlg .cur .cx2 .c2 .rc2 .hxx .pas .for .cbl .bas
+
+##################################################
+# TGTDIR, OBJDIR selection
+#
+# Each build type stores obj files and built binaries in a different
+# directory below the source or distribution tree. Current directory
+# naming convention is:
+#
+# TGTDIR=OBJ<p><o><b>
+# OBJDIR=OBJ<p><o><b>
+#
+# <p>: i = i386
+# m = MIPS
+# a = ALPHA
+# 2 = i286
+#
+# <o>: d = DOS
+# 1 = NT 1.x
+# n = NT 2.0 (Cairo)
+# o = OS/2
+# w = Win16 (used when targeting Win32s)
+#
+# <b>: r = Retail
+# d = Debug
+# p = Profile (Retail with debug info)
+# <Nothing> = Release
+#
+# TGTEXT/RDEXT selection for MULTIDEPEND != ""
+# Each build type stores depend.mk files with a different last character
+# in the extension, as in "mk?". Current extension convention is:
+# <1>: NT 2.0 x86
+# <3>: Chicago
+# <5>: NT 2.0 MIPS
+# <7>: NT 2.0 Alpha
+# <9>: Win 3.1
+# <a>: Dos 5.0
+# <c>: OS/2 1.x
+# <e>: NTKERNEL x86
+# <g>: NTKERNEL MIPS
+# <h>: NTKERNEL Alpha
+# <j>: Win32s
+# <k>: NT 1.x x86
+# <l>: NT 1.x MIPS
+# <m>: NT 1.x Alpha
+#
+# As you can see the scheme gets a bit cumbersome, so if you define
+# MULTIDEPEND == MERGED then similar systems use the same letter, so:
+# <1>: NT 2.0 all
+# <3>: NT 1.x all, Chicago, Win32s
+# <9>: Win 3.1
+# <a>: Dos 5.0
+# <c>: OS/2 1.x
+# <e>: NTKERNEL all
+
+OBJDIR=
+TGTDIR=
+TGTEXT=
+RDEXT=
+
+# set BUILDTYPE based on NTDEBUG setting
+# bugbug need to base on settings in makefile.def
+#
+
+
+
+!if "$(NTDEBUG)" == "retail"
+BUILDTYPE=RELEASE
+!else
+!if "$(NTDEBUG)" == "ntsdnodbg"
+BUILDTYPE=RELEASE
+!else
+BUILDTYPE=DEBUG
+!endif
+!endif
+
+
+!ifndef _NTROOT
+_NTROOT=\nt
+!endif
+
+!ifndef BASEDIR
+BASEDIR=$(_NTDRIVE)$(_NTROOT)
+!endif
+
+!if "$(OPSYS)"==""
+OPSYS=NT
+!endif
+
+
+
+!if "$(PROCESSOR_ARCHITECTURE)" == "x86"
+PLAT = i
+PLATFORM=I386
+!elseif "$(PROCESSOR_ARCHITECTURE)" == "MIPS"
+PLAT = m
+PLATFORM=MIPS
+!elseif "$(PROCESSOR_ARCHITECTURE)" == "ALPHA"
+PLAT = a
+PLATFORM=ALPHA
+!else
+!error Unknown PROCESSOR_ARCHITECTURE setting "$(PROCESSOR_ARCHITECTURE)"
+!endif
+
+!if "$(BUILDTYPE)" == "DEBUG"
+BLDT = d
+!elseif "$(BUILDTYPE)" == "RETAIL"
+BLDT = r
+!elseif "$(BUILDTYPE)" == "PROFILE"
+BLDT = p
+!elseif "$(BUILDTYPE)" == "RELEASE"
+BLDT =
+!else
+!error Unknown BUILDTYPE setting "$(BUILDTYPE)"
+!endif
+
+# DavidBak hack
+!if "$(PERFSNAP)" == "1"
+BLDT = p
+!endif
+
+!if "$(OPSYS)" == "NT" || "$(OPSYS)" == "NTKERNEL"
+OPST = n
+!elseif "$(OPSYS)" == "DOS"
+OPST = d
+!elseif "$(OPSYS)" == "DOS5"
+OPST = 5
+!elseif "$(OPSYS)" == "OS2"
+OPST = o
+!elseif "$(OPSYS)" == "WIN16"
+OPST = w
+!elseif "$(OPSYS)" == "NT1X"
+OPST = 1
+!else
+!error Unknown OPSYS setting "$(OPSYS)"
+!endif
+
+
+
+OBJDIR = OBJ\$(PLATFORM)
+TGTDIR = OBJ\$(PLATFORM)
+
+
+
+!if "$(MULTIDEPEND)" == "MERGED"
+! if "$(OPSYS)" == "NT"
+DEXT = 1
+! endif
+!else # !MERGED
+! if "$(OPSYS)" == "NT"
+PLATDIR=DAYTONA
+! if "$(PROCESSOR_ARCHITECTURE)" == "x86"
+DEXT = 1
+! elseif "$(PROCESSOR_ARCHITECTURE)" == "MIPS"
+DEXT = 5
+! elseif "$(PROCESSOR_ARCHITECTURE)" == "ALPHA"
+DEXT = 7
+! endif
+! elseif "$(OPSYS)" == "NTKERNEL"
+! if "$(PROCESSOR_ARCHITECTURE)" == "x86"
+DEXT = e
+! elseif "$(PROCESSOR_ARCHITECTURE)" == "MIPS"
+DEXT = g
+! elseif "$(PROCESSOR_ARCHITECTURE)" == "ALPHA"
+DEXT = h
+! endif
+! elseif "$(OPSYS)" == "DOS" && "$(PROCESSOR_ARCHITECTURE)" == "i286"
+DEXT = 9
+! elseif "$(OPSYS)" == "DOS5"
+DEXT = a
+! elseif "$(OPSYS)" == "OS2"
+DEXT = c
+! elseif "$(OPSYS)" == "NT1X"
+PLATDIR=DAYTONA
+! if "$(PROCESSOR_ARCHITECTURE)" == "x86"
+DEXT = k
+! elseif "$(PROCESSOR_ARCHITECTURE)" == "MIPS"
+DEXT = l
+! elseif "$(PROCESSOR_ARCHITECTURE)" == "ALPHA"
+DEXT = m
+! endif
+! elseif "$(PROCESSOR_ARCHITECTURE)" == "x86" && "$(OPSYS)" == "WIN16"
+DEXT = j
+! elseif "$(PROCESSOR_ARCHITECTURE)" == "x86" && "$(OPSYS)" == "DOS"
+DEXT = 3
+! endif
+!endif
+
+#bugbug, what about chicago platform
+
+RDEXT = $(DEXT)
+TGTEXT = $(DEXT)
+
+####################################################################################
+#
+#
+# Binplace rules, copied from $(PUBLIC)\oak\bin\makefile.def
+#
+#
+
+RELEASE_BIN=
+
+!IFDEF NTDBGFILES
+! IF "$(PROCESSOR_ARCHITECTURE)" == "x86"
+BINPLACE_FLAGS=-s $(_NT386TREE)\Symbols
+! ELSE
+! IF "$(PROCESSOR_ARCHITECTURE)" == "MIPS"
+BINPLACE_FLAGS=-s $(_NTMIPSTREE)\Symbols
+! ELSE
+! IF "$(PROCESSOR_ARCHITECTURE)" == "ALPHA"
+BINPLACE_FLAGS=-s $(_NTALPHATREE)\Symbols
+! ENDIF
+! ENDIF
+! ENDIF
+!ELSE
+BINPLACE_FLAGS=
+!ENDIF
+
+
+# The xxxTREE macros are set in the razzle cmd window.
+# for cairo builds cairoxxxxxx macros will be set.
+
+
+!ifdef CAIRO_PRODUCT
+!ifdef _CAIROMIPSTREE
+_NTMIPSTREE=$(_CAIROMIPSTREE)
+!endif
+
+!ifdef _CAIRO386TREE
+_NT386TREE=$(_CAIRO386TREE)
+!endif
+
+!ifdef _CAIROALPHATREE
+_NTALPHATREE=$(_CAIROALPHATREE)
+!endif
+!endif
+
+
+!ifdef _NTMIPSTREE
+RELEASE_BIN=TRUE
+!endif
+
+!ifdef _NT386TREE
+RELEASE_BIN=TRUE
+!endif
+
+!ifdef _NTALPHATREE
+RELEASE_BIN=TRUE
+!endif
+
+
+
+!ifndef BUILDDETAIL
+BUILDDETAIL = quiet
+!endif
+
+!if "$(BUILDDETAIL)" == "FULL" || "$(BUILDDETAIL)" == "full"
+COMPLOGO =
+COMPRESP = KEEP
+LINKLOGO =
+LINKRESP = KEEP
+!endif
+
+!if "$(BUILDDETAIL)" == "KEEPCOMP" || "$(BUILDDETAIL)" == "keepcomp"
+COMPLOGO =
+COMPRESP = KEEP
+LINKLOGO = -nologo
+LINKRESP = NOKEEP
+!endif
+
+!if "$(BUILDDETAIL)" == "KEEPLINK" || "$(BUILDDETAIL)" == "keeplink"
+COMPLOGO = -nologo
+COMPRESP = NOKEEP
+LINKLOGO =
+LINKRESP = KEEP
+!endif
+
+!if "$(BUILDDETAIL)" == "QUIET" || "$(BUILDDETAIL)" == "quiet"
+COMPLOGO = -nologo
+COMPRESP = NOKEEP
+LINKLOGO = -nologo
+LINKRESP = NOKEEP
+!endif
+
+!if "$(NOLOGOS)" != ""
+COMPLOGO = -nologo
+LINKLOGO = -nologo
+!endif
+
+######################################################################
+# Destination for messages
+
+!ifdef NOTIME
+TIMESTR=
+ATSTR=
+!else
+TIMESTR=/H:M:S
+ATSTR=at
+!endif
+
+!ifndef OUTPUT
+! ifdef BUILDQUIET
+OUTPUT= >nul
+! else
+OUTPUT=
+! endif
+!endif
+
+#
+# DOS doesn't let us redirect stderr output, so we use the following define
+# to unify our output.
+#
+
+!if "$(HOST)" != "DOS"
+OUTNUL= 1>nul 2>nul
+!else
+OUTNUL=
+!endif
+
+!ifndef OUTFIX
+OUTFIX = $(OUTNUL)
+!endif
+
+
+######################################################################
+#
+# Set location to locate tools
+
+# Empty toolpath so it can be used to check for invalid host type
+TOOLPATH=
+SDKTOOLPATH=
+
+!if "$(HOST)" == ""
+HOST = NT
+!endif
+
+HOSTBIN = .
+
+
+######################################################################
+#
+# Set location to copy include files
+
+HCOPY= ..\oleprx32\daytona
+LIBCP=
+SEDHCOPY= ..\oleprx32\daytona
+#LIBCP= $(BASEDIR)\public\sdk\lib\cairo\$(PLATFORM)
+#SEDHCOPY= $(_NTDRIVE)\$(_NTROOT)\\public\\sdk\\inc\\cairo
+
+
+
+######################################################################
+#
+# Misc tool defines
+
+AWK= awk.exe
+CAT= cat.exe
+CHMODE= chmode.exe
+CLASSGEN= classgen
+CMP= fcom.exe
+COFF= link32
+COPY= copy /v
+CP= $(COPY)
+CTCOPY= xcopy /v /i
+CVPACK= cvpack.exe
+DEL= del
+CVTRES= cvtres.exe
+DOCGEN= docgen.exe
+ECH= ech.exe
+ECHOTIME= echotime
+FLEX= flex.exe
+GENLRF= genlrf.exe
+GENORD= genord.exe
+IN= $(SLMTOOLS)\in.exe
+INCLUDES= includes.exe
+MAPSYM= mapsym.exe
+MC= mc.exe
+MIDL= midl
+MKHEADER= mkheader
+MKTMPLAT= mktmplat
+MKTYPLIB= mktyplib
+MUNGE= munge.exe
+OUT= out.exe
+RC= rc
+REGTLB= regtlb.exe
+SED= sed.exe
+SIFTTOOL= sifttool.exe
+SORT= sort.exe
+SPLITSYM= splitsym.exe
+TOUCH= touch.exe
+UNIQ= uniq.exe
+UNREGTLB= unregtlb.exe
+YACC= yacc.exe
+
+
+IMPORTNT = $(BASEDIR)\public\sdk
+
+
+
+
+TYPESDIR = $(BASEDIR)\private\oleutest\balls
+SCRIPTS = $(BASEDIR)\private\oleutest\balls
+
+CAIROINC = $(BASEDIR)\private\cinc
+
+BASEINC =$(TYPESDIR)\idl
+
+PROXYINC =$(TYPESDIR)\oleprx32\$(PLATDIR)
+
+############################################################################
+#
+# Object files and resource files
+#
+
+CXX_OBJS=$(CXXFILES:.cxx=.obj)
+CXX_OBJS=$(CXX_OBJS) $(CPPFILES:.cpp=.obj)
+C_OBJS=$(CFILES:.c=.obj)
+RESFILES = $(RCFILES:.rc=.res)
+TYPELIBS = $(TDLFILES:.tdl=.tlb)
+MKHDR_H_FILES = $(TDLFILES:.tdl=.h)
+MKHDR_C_FILES = $(TDLFILES:.tdl=.c)
+MIDL_INCS=$(IDLFILES:.idl=.h)
+MIDL_PROXYS=$(IDLFILES:.idl=.h)
+
+# Hack alert:
+#
+# We want to use $(OBJDIR) in the replacement string, like this:
+#
+# CXX_OBJS = $(CXX_OBJS:.\=$(OBJDIR)\)
+#
+# Unfortunately, nmake wants no part of it. As a workaround, we test for
+# each known value of $(OBJDIR) and perform the individual substitution
+# for each.
+
+!if "$(MKHEADER_OUT_DIR)"==""
+MKHEADER_OUT_DIR=$(TYPESDIR)\oleprx32\$(PLATDIR)\
+!endif
+
+
+
+!if "$(MIDL_OUT_DIR)"==""
+MIDL_PROXYS=$(MIDL_PROXYS:.\=..\oleprx32\daytona\)
+MIDL_INCS=$(MIDL_INCS:.\=..\oleprx32\daytona\)
+MKHDR_H_FILES=$(MKHDR_H_FILES:.\=..\oleprx32\daytona\)
+MKHDR_C_FILES=$(MKHDR_C_FILES:.\=..\oleprx32\daytona\)
+MIDL_HDR_OUT_DIR=..\oleprx32\daytona
+!else
+MIDL_INCS=$(MIDL_INCS:.\=..\oleprx32\daytona\)
+MIDL_HDR_OUT_DIR=..\oleprx32\daytona
+!endif
+
+
+!if "$(MIDL_OUT_DIR)"==""
+MIDL_OUT_DIR=..\oleprx32\$(PLATDIR)
+MIDL_HDR_OUT_DIR=..\oleprx32\daytona
+!endif
+
+
+!if "$(OBJDIR)" == "OBJ\I386"
+CXX_OBJS = $(CXX_OBJS:.\=.\OBJ\I386\)
+C_OBJS = $(C_OBJS:.\=.\OBJ\I386\)
+RESFILES = $(RESFILES:.\=OBJ\I386\)
+TYPELIBS = $(TYPELIBS:.\=.\OBJ\i386\)
+
+! elseif "$(OBJDIR)" == "OBJ\MIPS"
+CXX_OBJS = $(CXX_OBJS:.\=.\OBJ\MIPS\)
+C_OBJS = $(C_OBJS:.\=.\OBJ\MIPS\)
+RESFILES = $(RESFILES:.\=OBJ\MIPS\)
+TYPELIBS = $(TYPELIBS:.\=.\OBJ\MIPS\)
+
+! elseif "$(OBJDIR)" == "OBJ\ALPHA"
+CXX_OBJS = $(CXX_OBJS:.\=.\OBJ\ALPHA\)
+C_OBJS = $(C_OBJS:.\=.\OBJ\ALPHA\)
+RESFILES = $(RESFILES:.\=OBJ\ALPHA\)
+TYPELIBS = $(TYPELIBS:.\=.\OBJ\ALPHA\)
+
+! else
+! error Unknown object directory: $(OBJDIR)
+
+!endif # $(OBJDIR)
+
+
+############################################################################
+# Rules for generating .h, and .rc files from .mc files.
+#
+#
+#
+#
+
+# bugbug, what about chicago builds?
+# bugbug, maybe we should use other variable besides
+# MIDL_OUT_DIR to determine which directory to generate
+# message flies in.
+
+
+!if "$(MESSAGE_FILES)" != ""
+
+MCRESOURCE=$(MESSAGE_FILES:.mc=.rc)
+
+MESSAGE_H_FILES=$(MESSAGE_FILES:.mc=.h)
+
+
+
+!if "$(PLATDIR)" == "DAYTONA"
+MESSAGE_H_FILES=$(MESSAGE_H_FILES:.\=..\..\..\..\public\sdk\inc\)
+MC_OUT_DIR=..\..\..\..\public\sdk\inc
+!endif
+
+
+
+!if "$(OBJDIR)" == "OBJ\I386"
+MCRESOURCE = $(MCRESOURCE:.\=.\OBJ\I386\)
+!elseif "$(OBJDIR)"== "OBJ\MIPS"
+MCRESOURCE = $(MCRESOURCE:.\=.\OBJ\MIPS\)
+!elseif "$(OBJDIR)"== "OBJ\ALPHA"
+MCRESOURCE = $(MCRESOURCE:.\=.\OBJ\ALPHA\)
+!else
+!error Uknown object directory : $(OBJDIR)
+!endif
+
+MCBIN= $(OBJDIR)\msg00001.bin
+
+all: $(MESSAGE_H_FILES)
+
+.mc{$(MC_OUT_DIR)}.h:
+ @echo Building $< $(OUTPUT)
+ @-md $(OBJDIR) $(OUTNUL)
+ $(MC) $(MCFLAGS) $< -h $(HCOPY) $(OUTPUT)
+!if "$(OPSYS)"=="NT1X" && "$(NORELEASE_CHICAGO)"==""
+ @-md $(HCOPY)\chicago $(OUTNUL)
+ @echo Build_Status Releasing $(@B).h files to $(HCOPY)\chicago
+ $(COPY) $(HCOPY)\$(@B).h $(HCOPY)\chicago $(OUTNUL)
+!endif
+
+
+clean: cleancomp
+ -$(DEL) $(MESSAGE_H_FILES:.mc=.h) $(MCRESOURCE) $(MCBIN) $(OUTNUL)
+
+
+!endif
+
+
+############################################################################
+#
+# Rules for generating .tlb, .hxx and .cxx files from .tdl files
+# These should be before any target rules, to force code
+# generation before compiling.
+#
+
+!if "$(TDLFILES)" != ""
+
+all: $(TYPELIBS)
+
+.tdl{$(OBJDIR)}.tlb:
+ @-md $(OBJDIR) $(OUTNUL)
+ $(MKTYPLIB) $(MKTYPLIBFLAGS) $(CINC) $(TLBDIRS) -tlb$@ $<
+ $(MKHEADER) $(MKHEADERFLAGS) -o $(HCOPY)\$(@B).h -u $(MKHEADER_OUT_DIR)\$(@B).c -x $(@)
+ $(REGTLB) $@
+
+$(TDLFILES): $(IDLFILES)
+
+DEPENDFILES = $(TYPELIBS) $(MKHDR_H_FILES) $(MKHDR_C_FILES) $(DEPENDFILES)
+
+
+TYPELIBS = $(TYPELIBS:.\=)
+
+
+CLEANFILES = $(CLEANFILES) $(TYPELIBS) $(MKHDR_H_FILES) $(MKHDR_C_FILES)
+
+!endif
+
+
+
+############################################################################
+#
+# Generate .h and .c files from .idl files
+# 1
+
+# NOTE: this rule should appear before any target rules, to force
+# idl-to-h translation to happen first.
+
+!if "$(IDLFILES)" != ""
+
+all: $(MIDL_INCS)
+
+clean: cleanidl
+
+#
+# Due to command line limitations (yes, even NT has them), we write a script
+# to delete the idl output files.
+#
+
+cleanidl:
+ @type << | $(SED) -f << > idlclean.bat
+$(MIDL_INCS:.h=.h
+)
+$(MIDL_PROXYS:.h=_?.c
+)
+$(MIDL_PROXYS:.h=_?.cxx
+)
+$(MIDL_PROXYS:.h=_?.h
+)
+$(MIDL_PROXYS:.h=_?.hxx
+)
+<<NOKEEP
+1i\
+\@echo off \
+\@echo Build_Status Deleting MIDL output files...
+/\./!d
+s/^/del /g
+s/$$/ $(OUTNUL)/g
+<<NOKEEP
+ @-idlclean.bat
+ @-$(DEL) idlclean.bat $(OUTNUL)
+
+
+DEPENDFILES = $(DEPENDFILES) $(MIDL_INCS)
+
+!endif # IDLFILES
+
+
+##################################################################
+#
+# Rules to build the composite .h file from midl generated files #
+#
+#
+
+!if "$(ITFS_BASE)" != "" && "$(ITFS_DIR)" != ""
+ITFS_H = $(ITFS_BASE).h
+
+all: $(ITFS_DIR)\$(ITFS_H)
+
+
+$(ITFS_DIR)\$(ITFS_H): $(MIDL_INCS) $(ITFS_BASE).x $(ITFS_BASE).y
+ @echo Build_Status Building $(ITFS_DIR)\$(ITFS_H) ...
+ @del $(ITFS_DIR)\$(ITFS_H) $(OUTNUL)
+#
+# Add the file header and base #includes.
+#
+
+ @type $(ITFS_BASE).x >> $(ITFS_DIR)\$(ITFS_H)
+ @echo @echo off > copyall.cmd
+ @echo cd $(ITFS_DIR)\ >> copyall.cmd
+ @type << | $(SED) -f << >> copyall.cmd
+$(BASE_HFILES: =
+)
+<<NOKEEP
+/\./!d
+s/\.\\//g
+s/^/\@sed -e \"\/^\#include\/d\" -e \"\/\\\/\\\/ File\\\:\/d" /g
+s/$$/ \>\> $(ITFS_H)/g
+<<NOKEEP
+ @echo cd $(MAKEDIR) >> copyall.cmd
+ @copyall.cmd
+ @del copyall.cmd
+#
+# Copy the initial forward declarations from all the derived h files.
+#
+ @type << >> $(ITFS_DIR)\$(ITFS_H)
+
+// Forward declarations for typedefs in this file
+<<NOKEEP
+ @type << > $(ITFS_DIR)\forward.sed
+/\/\* Forward Declarations \*\// {
+N
+s/\/\* Forward Declarations \*\/\ntypedef/xtypedef/
+}
+/xtypedef/!d
+s/xtypedef/typedef/
+<<NOKEEP
+
+ @echo @echo off > forward.cmd
+ @echo cd $(ITFS_DIR) >> forward.cmd
+ @type << | $(SED) -f << >> forward.cmd
+$(DERIVED_HFILES: =
+)
+<<NOKEEP
+/\./!d
+s/\.\\//g
+s/^/\@sed -f forward.sed /g
+s/$$/ \>\> $(ITFS_H)/g
+<<NOKEEP
+ @echo cd $(MAKEDIR) >> forward.cmd
+ @forward.cmd
+ @del forward.cmd
+ @del $(ITFS_DIR)\forward.sed $(OUTNUL)
+#
+# Copy the derived h files in. Strip off any #includes along the way.
+#
+
+ @echo @echo off > copyall.cmd
+ @echo cd $(ITFS_DIR)\ >> copyall.cmd
+ @type << | $(SED) -f << >> copyall.cmd
+$(DERIVED_HFILES: =
+)
+<<NOKEEP
+/\./!d
+s/\.\\//g
+s/^/\@sed -e \"\/^\#include\/d\" -e \"\/\\\/\\\/ File\\\:\/d" /g
+s/$$/ \>\> $(ITFS_H)/g
+<<NOKEEP
+ @echo cd $(MAKEDIR) >> copyall.cmd
+ @copyall.cmd
+ @del copyall.cmd
+#
+# Append API prototypes to the end of the file
+#
+ @type $(ITFS_BASE).y >> $(ITFS_DIR)\$(ITFS_H)
+#
+# Finally, close the file #ifdef
+#
+
+ @type << >> $(ITFS_DIR)\$(ITFS_H)
+#ifndef RC_INVOKED
+#pragma pack()
+#endif // RC_INVOKED
+#endif // __$(ITFS_BASE)_H__
+<<NOKEEP
+
+!if "$(OPSYS)"=="NT1X" && "$(NORELEASE_CHICAGO)" == ""
+ @echo "Releaseing composite .h file for Chicago" $(OUTPUT)
+ $(COPY) $(ITFS_DIR)\$(ITFS_BASE).h $(HCOPY)\chicago
+!endif
+!endif # ITFS_BASE
+
+
+##################################################################
+#
+# Rules to build the composite .h file from mc generated files #
+#
+#
+
+!if "$(MCERRS_BASE)" != "" && "$(MCERRS_DIR)" != ""
+MCERRS_H = $(MCERRS_BASE).h
+
+all: $(MCERRS_DIR)\$(MCERRS_H)
+
+
+$(MCERRS_DIR)\$(MCERRS_H): $(MESSAGE_FILES)
+ @echo Build_Status Building $(MCERRS_DIR)\$(MCERRS_H) ...
+ @del $(MCERRS_DIR)\$(MCERRS_H) $(OUTNUL)
+#
+# Add the file header and base #includes.
+#
+
+
+ @echo @echo off > copyall.cmd
+ @echo cd $(MCERRS_DIR)\ >> copyall.cmd
+ @type << | $(SED) -f << >> copyall.cmd
+$(MESSAGE_FILES:.mc=.h
+)
+<<NOKEEP
+/\./!d
+s/\.\\//g
+s/^/\@sed -e \"\/\\\/\\\/ File\\\:\/d" /g
+s/$$/ \>\> $(MCERRS_H)/g
+<<NOKEEP
+ @echo cd $(MAKEDIR) >> copyall.cmd
+ @copyall.cmd
+ @del copyall.cmd
+
+!if "$(OPSYS)"=="NT1X" && "$(NORELEASE_CHICAGO)" == ""
+ @echo "Releaseing composite .h file for Chicago" $(OUTPUT)
+ $(COPY) $(MCERRS_DIR)\$(MCERRS_BASE).h $(HCOPY)\chicago
+!endif
+
+cleancomp:
+ @del $(MCERRS_DIR)\$(MCERRS_H)
+
+!endif
+
+
+############################################################################
+#
+# Determine target type (DLL, EXE, or LIB)
+#
+
+!ifdef TARGET
+
+TARGET = $(TARGET:.\=)
+
+CLEANTARGET= $(CLEANTARGET) $(TGTDIR)\$(TARGET)
+
+#
+# Is it a DLL?
+#
+
+TARGETBASE=$(TARGET:.dll=)
+! if "$(TARGETBASE)" != "$(TARGET)"
+all: $(YACCFILES:.y=.h) $(TGTDIR)\$(TARGET) copy
+TARGETTYPE=dll
+DLLFILES= $(DLLFILES) $(TGTDIR)\$(TARGET)
+! else
+
+#
+# Is it an EXE?
+#
+
+TARGETBASE=$(TARGET:.exe=)
+! if "$(TARGETBASE)" != "$(TARGET)"
+all: $(YACCFILES:.y=.h) $(TGTDIR)\$(TARGET) copy
+TARGETTYPE=exe
+EXEFILES= $(EXEFILES) $(TGTDIR)\$(TARGET)
+! else
+
+#
+# Is it a LIB?
+#
+
+TARGETBASE=$(TARGET:.lib=)
+! if "$(TARGETBASE)" != "$(TARGET)"
+all: $(YACCFILES:.y=.h) $(OBJDIR)\$(TARGET) copy
+TARGETTYPE=lib
+! if "$(DEFFILE)" == ""
+NO_IMPLIB= TRUE
+! endif
+! else
+
+#
+# This is a special target used when we have files to RELEASE
+# but nothing to actually build.
+#
+
+! if "$(TARGET)" == "RELEASE"
+all:
+! else
+
+#
+# We don't know what it is.
+#
+
+! error Unrecognized target type: $(TARGET)
+! endif # !RELEASE
+! endif # !.lib
+! endif # !.exe
+! endif # !.dll
+!endif # TARGET
+#
+# If no name was given for a DEF file, make one up.
+#
+
+DEFEXT = f
+
+!ifndef DEFBASE
+DEFBASE = $(TARGETBASE)
+!endif
+
+!ifndef DEFFILE
+DEFFILE=$(DEFBASE).def
+!endif
+
+!if "$(NO_IMPLIB)" == ""
+DEFFILELIB = $(OBJDIR)\$(DEFBASE).lib
+DEFFILEEXP = $(OBJDIR)\$(DEFBASE).exp
+!endif
+
+
+
+
+
+######################################################################
+# Make sure INCLUDE and LIB are null.
+
+INCLUDE=
+LIB=
+
+######################################################################
+# Independent definitions for C compiler, LINK
+
+CFLAGS= $(CFLAGS) -D_WINDOWS -ZB64
+
+# The 16 bit OLE DOCFILE libraries do not want UNICODE defined.
+
+!ifndef NO_UNICODE
+! if "$(OPSYS)" == "NT" || "$(OPSYS)" == "NT1X" || "$(OPSYS)" == "NTKERNEL"
+CFLAGS = $(CFLAGS) -DUNICODE -D_UNICODE
+! endif
+!endif
+
+CINC= -I. $(CINC)
+
+CINC= $(CINC) -I$(TYPESDIR)\oleprx32\$(PLATDIR)
+CINC= $(CINC) -I$(CAIROINC) -I$(BASEINC)
+
+
+
+
+######################################################################
+# Debug/Retail definitions
+#
+# These are hardware independant debug/retail flags
+#
+
+
+# NOTE: NT kernel include files require that DBG be defined.
+!if "$(BUILDTYPE)" == "DEBUG"
+CDEBUGFLAGS = $(CDEBUGFLAGS) -DDBG=1 -DDEVL=1
+!elseif "$(BUILDTYPE)" == "RETAIL"
+CDEBUGFLAGS = $(CDEBUGFLAGS) -DDBG=0 -DDEVL=1
+!else
+CDEBUGFLAGS = $(CDEBUGFLAGS) -DDBG=0 -DDEVL=0
+!endif
+
+CFLAGS = $(CFLAGS) $(CDEBUGFLAGS)
+
+
+######################################################################
+#
+# Generic Definitions
+#
+
+COMMON_LIBS = $(BASEDIR)\public\sdk\lib\$(PLATFORM)
+
+CAIROLIB = $(COMMON_LIBS)\commnot.lib\
+ $(COMMON_LIBS)\compob32.lib\
+ $(COMMON_LIBS)\storag32.lib\
+ $(COMMON_LIBS)\propset.lib\
+ $(COMMON_LIBS)\ole232.lib\
+ $(COMMON_LIBS)\lnktrack.lib\
+ $(TYPESDIR)\oleprx32\$(PLATDIR)\$(OBJDIR)\uuid.lib\
+ $(COMMON_LIBS)\change.lib\
+ $(COMMON_LIBS)\events.lib\
+ $(COMMON_LIBS)\dsys.lib \
+ $(IMPORTNT)\lib\$(PLATFORM)\ntdll.lib
+
+
+######################################################################
+#
+# Win32 (NT 1.x/NT 2.0/Chicago/Win32s) Definitions
+#
+
+!if "$(PROCESSOR_ARCHITECTURE)" == "x86" || \
+ "$(PROCESSOR_ARCHITECTURE)" == "MIPS" || \
+ "$(PROCESSOR_ARCHITECTURE)" == "ALPHA"
+! if "$(PROCESSOR_ARCHITECTURE)" == "x86"
+
+#--------------------------------------
+# X86 Specific Flags
+#--------------------------------------
+
+CC= cl386
+BUILD_EXE_COMPFLAG= cl386
+BUILD_EXE_PROCTYPE=i386
+
+CPLATFORM= -Di386=1 -D_X86_=1
+
+CFLAGS = $(CFLAGS) -G4f -Zl -Bbb1
+
+# Chicago doesn't have Unicode API's
+! if "$(OPSYS)" == "DOS" || "$(OPSYS)" == "WIN16"
+CFLAGS = $(CFLAGS) -UUNICODE -U_UNICODE
+! endif
+
+!if "$(CALLCONV)" == ""
+! ifndef 386_STDCALL
+386_STDCALL = TRUE
+! endif
+
+! if "$(386_STDCALL)" == "TRUE"
+CFLAGS = $(CFLAGS) -Gz
+! else
+CFLAGS = $(CFLAGS) -Gd
+! endif
+!else
+CFLAGS = $(CFLAGS) $(CALLCONV)
+!endif
+
+#
+# Disable FPO for now. If/when we determine if the debuggers can handle
+# it, and the CriticalSection code isn't dependent on the stack frame, and
+# the Stack walk-back code is updated, we should turn it back on...
+#
+
+! ifndef OPTFLAGS
+! if "$(BUILDTYPE)" == "DEBUG" || "$(BUILDTYPE)" == "RETAIL"
+OPTFLAGS = -Ogit -Oy-
+! elseif "$(BUILDTYPE)" == "RELEASE" || "$(BUILDTYPE)" == "PROFILE"
+OPTFLAGS = -Owx -Oy- -Ob1
+! endif
+! endif
+
+# Make sure intrinsics are always on.
+
+OPTFLAGS = $(OPTFLAGS) -Oi
+
+
+
+# Hack to workaround cvpack types limit when building ole2prxy.dll in
+# common\types. s/b revisted once the linker and cvpack are one.
+# BryanT 8/10/93
+
+!if "$(NO_DEBUG)" == "1"
+NTDEBUGTYPE = ntsd
+!else
+NTDEBUGTYPE = windbg
+!endif
+
+DLLENTRY = @12
+DRIVERENTRY = @8
+
+#
+# (To be moved to NT section when the MIPS linker understands this flag)
+#
+
+LFLAGS = $(LFLAGS) -merge:.CRT=.data
+
+#
+# The CUDA Linker requires this if there is no entrypoint (resource only DLL)
+#
+
+! ifdef NOEXPORTS
+DLLSTARTUP= -NOENTRY
+! endif
+
+LFLAGS = $(LFLAGS) -NODEFAULTLIB -OPT:REF -RELEASE
+
+OBJFILES = $(OBJFILES) $(X86_OBJFILES)
+
+! elseif "$(PROCESSOR_ARCHITECTURE)" == "MIPS"
+
+#--------------------------------------
+# MIPS Specific Flags
+#--------------------------------------
+
+CC= mcl
+BUILD_EXE_COMPFLAG= ClMips
+BUILD_EXE_PROCTYPE=mips
+
+CPLATFORM= -DMIPS=1 -D_MIPS_=1 -DR4000=1
+
+CFLAGS = $(CFLAGS) -QmipsOb2000 -QmipsG2
+
+! ifndef OPTFLAGS
+! if "$(BUILDTYPE)" == "DEBUG" || "$(BUILDTYPE)" == "RETAIL"
+OPTFLAGS = -Oglt
+! elseif "$(BUILDTYPE)" == "RELEASE" || "$(BUILDTYPE)" == "PROFILE"
+OPTFLAGS = -Owx -Ob1
+! endif
+! endif
+
+DLLENTRY =
+DRIVERENTRY =
+
+! if "$(TARGETTYPE)" == "exe"
+LFLAGS = $(LFLAGS) -GPSIZE:32
+! endif
+
+!ifdef NEW_LINKER
+
+! ifdef NOEXPORTS
+DLLSTARTUP= -NOENTRY
+! endif
+
+LFLAGS = $(LFLAGS) -NODEFAULTLIB -OPT:REF -RELEASE
+
+! if "$(NO_DEBUG)" == "1"
+NTDEBUGTYPE = ntsd
+! else
+NTDEBUGTYPE = windbg
+! endif
+
+!else
+
+#
+# The MIPS Linker doesn't use a special switch to disable the entrypoint.
+#
+
+! ifdef NOEXPORTS
+DLLSTARTUP=
+! endif
+
+LFLAGS = $(LFLAGS) -IGNORE:505
+
+#
+# The MIPS Linker doesn't understand the nologo switch... Disable it for now.
+#
+
+LINKLOGO =
+
+!endif
+
+# BUGBUG: For GPSIZE to really be useful, the compiler switches should include
+# -Gt32 and we should add libm.lib to the LIBS macros. However, I'm
+# pretty sure Steve (shanson) and Sundeep haven't implemented the
+# necessary code for it to work with DLL's... So for now, we just add
+# if to the exe link flags in case some library we link with was built
+# with -Gt... BryanT 6/20/93
+
+
+OBJFILES = $(OBJFILES) $(MIPS_OBJFILES)
+
+! elseif "$(PROCESSOR_ARCHITECTURE)" == "ALPHA"
+
+#--------------------------------------
+# ALPHA Specific Flags
+#--------------------------------------
+
+CC= claxp
+BUILD_EXE_COMPFLAG= ClAlpha
+BUILD_EXE_PROCTYPE=alpha
+
+CPLATFORM= -DALPHA=1 -D_ALPHA_=1 -DJENSEN
+
+! ifndef OPTFLAGS
+! if "$(BUILDTYPE)" == "DEBUG" || "$(BUILDTYPE)" == "RETAIL"
+OPTFLAGS = -Oglt
+! elseif "$(BUILDTYPE)" == "RELEASE" || "$(BUILDTYPE)" == "PROFILE"
+OPTFLAGS = -Owx -Ob1
+! endif
+! endif
+
+DLLENTRY =
+DRIVERENTRY =
+
+#
+# The ALPHA Linker doesn't use a special switch to disable the entrypoint.
+#
+
+! ifdef NOEXPORTS
+DLLSTARTUP=
+! endif
+
+LFLAGS = $(LFLAGS) -IGNORE:505
+
+#
+# The ALPHA Linker doesn't understand the nologo switch... Disable it for now.
+#
+
+LINKLOGO =
+
+
+
+OBJFILES = $(OBJFILES) $(ALPHA_OBJFILES)
+
+! endif # PROCESSOR_ARCHITECTURE == x86 / MIPS / ALPHA
+
+#--------------------------------------
+# NT/Chicago(DOS) Specific Flags
+#--------------------------------------
+
+CPLATFORM = $(CPLATFORM) -DFLAT
+
+CFLAGS = $(CFLAGS) -Zp8 -Ze -Gys -W3 -FI$(BASEDIR)\private\cinc\warning.h
+
+!if "$(OPSYS)" == "NT" || "$(OPSYS)" == "NTKERNEL"
+CFLAGS = $(CFLAGS) -DCAIROLE_BUILD
+!endif
+
+# WIN32 == 50 -> Win32s
+# WIN32 == 100 -> NT version 1.0
+# WIN32 == 200 -> Chicago version 1.0
+# WIN32 == 300 -> Cairo (NT version 2.0)
+
+!if "$(OPSYS)" == "WIN16"
+CPLATFORM = $(CPLATFORM) -DWIN32=50 -D_WIN32S_=50
+!elseif "$(OPSYS)" == "NT1X"
+CPLATFORM = $(CPLATFORM) -DWIN32=100 -D_NT1X_=100
+!elseif "$(OPSYS)" == "DOS"
+CPLATFORM = $(CPLATFORM) -DWIN32=200 -D_CHICAGO_=200
+!elseif "$(OPSYS)" == "NT" || "$(OPSYS)" == "NTKERNEL"
+CPLATFORM = $(CPLATFORM) -DWIN32=300 -D_CAIRO_=300
+!else
+!error Unknown OPSYS: $(OPSYS)
+!endif
+
+!ifdef PERFSNAP
+CFLAGS = $(CFLAGS) -DPERFSNAP=1
+!endif
+
+!ifdef NO_OLE
+INCLUDES_FLAGS = $(INCLUDES_FLAGS) -nole2.h
+CFLAGS = $(CFLAGS) -DNOOLETYPES
+!else
+CFLAGS = $(CFLAGS) -DINC_OLE2
+!endif
+
+IDLFLAGS = $(IDLFLAGS) -Zp8
+
+NO_SPLITSYM = TRUE # Reenable when commnot understands .dbg files
+
+IMAGE_TYPE_COFF = TRUE
+
+
+! if "$(BUILDTYPE)" == "RELEASE"
+DBGFLAGS =
+! else
+DBGFLAGS = -Z7
+! endif
+
+! if "$(NO_STRICT)" == ""
+CFLAGS = $(CFLAGS) -DSTRICT
+! else
+CFLAGS = $(CFLAGS) -DNO_STRICT
+! endif
+
+CFLAGS = $(CFLAGS) $(OPTFLAGS) $(DBGFLAGS) $(CPLATFORM)
+
+! if "$(TARGETTYPE)" != "sys" && !defined(USE_STDCRT)
+USE_CRTDLL=TRUE
+! endif
+
+! ifdef USE_CRTDLL
+CFLAGS= $(CFLAGS) -D_MT -D_DLL
+MTHREAD= 1
+! else
+! if "$(TARGETTYPE)" == "dll" || "$(MTHREAD)" == "1"
+CFLAGS= $(CFLAGS) -D_MT
+! endif
+! endif
+
+WILDCARDOBJ = $(RTLIBDIR)\setargv.obj
+
+! ifdef WILDCARDS
+OBJFILES = $(OBJFILES) $(WILDCARDOBJ)
+! endif
+
+AFLAGS= $(AFLAGS) -Ml -W2 -Zi -t
+
+CRTINC= $(OSINC)\crt
+
+
+RTLIBDIR= $(OSLIBDIR)
+
+! if "$(OPSYS)" == "NT" || "$(OPSYS)" == "NTKERNEL"
+RTLIBST= $(RTLIBDIR)\cairost.lib $(RTLIBDIR)\libc.lib
+RTLIBMT= $(RTLIBDIR)\cairomt.lib $(RTLIBDIR)\libcmt.lib
+RTLIBCRTDLL= $(RTLIBDIR)\crtdll.lib
+RTLIBSYS= $(RTLIBDIR)\cairoker.lib $(RTLIBDIR)\libcnt.lib
+! else
+RTLIBST= $(RTLIBDIR)\libc.lib
+RTLIBMT= $(RTLIBDIR)\libcmt.lib
+RTLIBSYS= $(RTLIBDIR)\libcnt.lib
+RTLIBCRTDLL= $(RTLIBDIR)\crtdll.lib
+! endif
+
+RTLIBEXE= $(RTLIBST)
+RTLIBEXEQ=
+RTLIBEXEFP=
+RTLIBEXEFPMT=
+
+! ifdef USE_CRTDLL
+RTLIBEXEMT= $(RTLIBCRTDLL)
+RTLIBDLL= $(RTLIBCRTDLL)
+! else
+RTLIBEXEMT= $(RTLIBMT)
+RTLIBDLL= $(RTLIBMT)
+! endif
+
+
+RPCLIBDIR= $(OSLIBDIR)
+
+RPCNDRLIB= $(RPCLIBDIR)\RpcNdr.lib
+RPCRTLIB= $(RPCLIBDIR)\RpcRt4.lib
+RPCLIBS= $(RPCRTLIB) $(RPCLIBDIR)\ntdll.lib
+
+! if "$(SUBSYSTEMVER)" == ""
+SUBSYSTEMVER = 3.10
+! endif
+
+! if "$(NO_WINMAIN)" == ""
+EXESTARTUP= -ENTRY:WinMainCRTStartup
+SUBSYSTEM= WINDOWS,$(SUBSYSTEMVER)
+! else
+EXESTARTUP= -ENTRY:mainCRTStartup
+! if "$(SUBSYSTEM)" == ""
+SUBSYSTEM= CONSOLE,$(SUBSYSTEMVER)
+! else # Make sure the subsystem version is set
+! if "$(SUBSYSTEM)" == "$(SUBSYSTEM:,=x)"
+SUBSYSTEM= $(SUBSYSTEM),$(SUBSYSTEMVER)
+! endif
+! endif # allows override of subsystem
+! endif
+
+#
+# For a perfsnap build, we use a modified version of dllentr2.obj
+#
+
+!if "$(PERFSNAP)" == "1"
+STARTUPFILE=dllpsnap.obj
+!else
+STARTUPFILE=dllentr2.obj
+!endif
+
+#
+# BugBug, what do we do about the DllEntryPoint for Daytona builds?
+# now we jus link with dllentr2.obj.
+
+! ifndef NOEXPORTS
+! ifdef USE_CRTDLL
+! if "$(OPSYS)" == "NT" || "$(OPSYS)" == "NTKERNEL"
+DLLSTARTUP= -ENTRY:DllEntryPoint$(DLLENTRY)
+! else
+DLLSTARTUP= -ENTRY:DllEntryPoint$(DLLENTRY)
+! endif
+! else
+DLLSTARTUP= -ENTRY:DllEntryPoint$(DLLENTRY)
+! endif
+! endif
+
+SYSSTARTUP= -ENTRY:DriverEntry$(DRIVERENTRY)
+
+!ifdef USE_OLE_MC
+MCFLAGS= -r $(OBJDIR) -o
+!else
+MCFLAGS= -r $(OBJDIR)
+!endif
+
+RCFLAGS= $(RCFLAGS) -r $(CDEBUGFLAGS) $(CPLATFORM) $(CINC) -fo
+RCEXEFLAGS= $(RCEXEFLAGS)
+
+LINK= $(COFF) -link $(LINKLOGO)
+LIBUTIL= $(COFF) -lib $(LINKLOGO)
+
+LFLAGS= $(LFLAGS) \
+ -MACHINE:$(PLATFORM) \
+ -MAP:$(OBJDIR)\$(TARGETBASE).map \
+!if "$(OPSYS)" == "NT" || "$(OPSYS)" == "NTKERNEL"
+ -VERSION:2.0 \
+!else
+ -VERSION:1.0 \
+!endif
+ -SECTION:.rsrc,r \
+ -SECTION:.guids,r
+
+! if "$(BUILDTYPE)" == "RELEASE"
+LFLAGS= $(LFLAGS) -DEBUG:none
+! else
+! if "$(TARGETTYPE)" == "sys"
+! if "$(PROCESSOR_ARCHITECTURE)" == "x86"
+LFLAGS= $(LFLAGS) -DEBUG:notmapped,full -DEBUGTYPE:both,fixup
+NTDEBUGTYPE=windbg
+! else
+LFLAGS= $(LFLAGS) -DEBUG:notmapped,full -DEBUGTYPE:coff
+NTDEBUGTYPE=ntsd
+! endif
+! else
+! if "$(NTDEBUGTYPE)" == "windbg"
+! if "$(PROCESSOR_ARCHITECTURE)" == "x86"
+LFLAGS= $(LFLAGS) -DEBUG:mapped,full -DEBUGTYPE:both,fixup
+! else
+LFLAGS= $(LFLAGS) -DEBUG:mapped,full -DEBUGTYPE:both
+! endif
+! else
+LFLAGS= $(LFLAGS) -DEBUG:mapped,full -DEBUGTYPE:coff
+! endif
+! endif
+! endif
+
+LFLAGSEXE= $(LFLAGS) -ALIGN:0x1000 -SUBSYSTEM:$(SUBSYSTEM)
+LFLAGSDLL= $(LFLAGS) -DLL -ALIGN:0x1000 -SUBSYSTEM:$(SUBSYSTEM)
+LFLAGSSYS= $(LFLAGS) -DLL:system -ALIGN:0x200
+
+# Chicago and Win32s need relocations
+!if "$(OPSYS)" != "DOS" && "$(OPSYS)" != "WIN16"
+LFLAGSEXE= $(LFLAGSEXE) -FIXED
+!endif
+
+LIBFLAGS= -MACHINE:$(PLATFORM) -DEBUGTYPE:BOTH
+
+! ifndef IMAGEBASE
+! if "$(TARGETTYPE)" == "sys"
+IMAGEBASE = 0x10000
+! elseif "$(TARGETTYPE)" == "dll" || "$(TARGETTYPE)" == "cpl"
+! ifdef COFFBASE
+IMAGEBASE= @$(TYPESDIR)\coffbase.txt,$(COFFBASE)
+! else
+! if "$(RELEASE)" != ""
+!error *** BUILD ERROR - Cannot set RELEASE w/o a COFFBASE setting ***
+! endif
+! endif
+! else
+IMAGEBASE= @$(TYPESDIR)\coffbase.txt,usermode
+! endif
+! endif
+
+IMAGEBASE= -BASE:$(IMAGEBASE)
+
+SPLITSYMFLAGS= -v
+
+!endif # $(PROCESSOR_ARCHITECTURE) == x86/MIPS/ALPHA
+
+
+
+##################################################
+# OS dependent Definitions for C compiler
+#
+# These are definitions which will change for each flavor of Win32
+# supported (NT, DOS)
+#
+
+!if "$(PROCESSOR_ARCHITECTURE)" == "x86" || "$(PROCESSOR_ARCHITECTURE)" == "MIPS" || "$(PROCESSOR_ARCHITECTURE)" == "ALPHA"
+
+!if "$(OPSYS)" == "NT" || "$(OPSYS)" == "NT1X"
+OSLIBDIR= $(IMPORTNT)\lib\$(PLATFORM)
+OSINC= $(IMPORTNT)\inc
+
+
+!if "$(OPSYS)" == "NT"
+CAIROOSINC=$(IMPORTNT)\inc
+!elseif "$(OPSYS)" == "NT1X"
+CAIROOSINC=$(IMPORTNT)\inc
+!endif
+
+RPCINC= $(IMPORTNT)\inc
+
+!else
+!error Unknown OPSYS: $(OPSYS)
+!endif
+
+OSLIBEXE= $(OSLIBDIR)\gdi32.lib $(OSLIBDIR)\kernel32.lib \
+ $(OSLIBDIR)\user32.lib $(OSLIBDIR)\advapi32.lib
+
+
+
+OSLIBEXE= $(OSLIBEXE) $(EXTRAOSLIBS)
+
+! if "$(PROFILE)" == "TRUE"
+OSLIBEXE= $(OSLIBEXE) $(OSLIBDIR)\cap.lib
+! endif # "$(PROFILE)" == "TRUE"
+
+
+
+OSLIBDLL= $(OSLIBEXE)
+OSLIBSYS= $(OSLIBDIR)\ntoskrnl.lib $(OSLIBDIR)\hal.lib $(EXTRAOSLIBS)
+
+! if "$(IDLBASE)" != ""
+OSLIBEXE= $(OSLIBEXE) $(RPCNDRLIB)
+OSLIBDLL= $(OSLIBDLL) $(RPCNDRLIB)
+! endif
+
+
+
+!endif # PROCESSOR_ARCHITECTURE == x86/MIPS/ALPHA
+
+CINC= $(CINC) -I$(CRTINC) -I$(CAIROOSINC) -I$(OSINC) -I$(RPCINC)
+
+####################################################################
+#
+# Defines for the SDK Tools.
+#
+
+MKHEADERFLAGS = $(MKHEADERFLAGS)
+MKTYPLIBFLAGS = $(MKTYPLIBFLAGS) -cpp_cmd $(CC)
+MKTMPLATFLAGS = $(MKTMPLATFLAGS)
+
+# update TLBDIRS to point to the location of the master winole
+# type library. Currently this is in $(BASEINC)\$(OBJDIR)
+TLBDIRS = $(TLBDIRS) -L$(BASEINC)\$(OBJDIR)
+
+######################################################################
+#
+# Generic rules to build OBJs from C, and CXX files.
+#
+
+CLOBJ= $(CC) $(CFLAGS) $(OCFLAGS) $(CINC) $(GCFLAGS) -c
+
+
+ALLCFLAGS = $(CFLAGS) $(OCFLAGS) $(GCFLAGS) -c
+
+
+IDLMIDLFLAGS = $(MIDLFLAGS) $(IDLFLAGS)
+
+
+#####################################################################
+#
+# Rules for generating precompiled headers
+#
+# BUGBUG: This business with adding a dummy function to the end of the pch
+# is necessitated by the compiler not doing it for us. By doing
+# it, we force the linker to add the module to the library. We
+# also create a .lic (Link Include) file that will follow the library
+# around and force the module to be linked in to the final image
+# so cvpack can find the types data. 4-14-93 BryanT
+#
+# Define NEW_PCH_BUILD to eliminate this problem. Instead of generating
+# a dummy function and the .lic file, we use -Yl on the compile line with
+# the name of the target. This causes the compiler to add a special
+# symbol to the pch file. Not turned on for the full build because
+# Centaur doesn't support it yet. 9-24-93 BryanT
+#
+
+!if "$(PCHDIR)" == ""
+PCHDIR = $(MAKEDIR)
+!endif
+
+CINC = -I$(PCHDIR) $(CINC)
+
+PCH_SECRET_NAME = __@@_PchDebugInfoLibrary
+
+DUMFUNC = $(PCH_SECRET_NAME)_$(TARGETBASE)_$(TARGETTYPE)
+! if "$(PROCESSOR_ARCHITECTURE)" == "x86"
+DUMINCLUDE = -INCLUDE:_$(DUMFUNC)
+! else
+DUMINCLUDE = -INCLUDE:$(DUMFUNC)
+! endif
+PCHOBJDIR = $(PCHDIR)\$(OBJDIR)
+
+# --------------------------- PXXFILE Support ------------------------
+
+#bugbug
+#work around for precompiled header problem.
+!if "$(NTNOPCH)"!=""
+PXXFILE=
+!endif
+
+!if "$(PXXFILE)" != ""
+
+PXXFILE = $(PXXFILE:.\=)
+PXXSOURCE = $(PCHDIR)\$(PXXFILE)
+PXXHEADER = $(PCHOBJDIR)\$(PXXFILE:.cxx=.pxh)
+PRECOMPXXOBJ = $(PCHOBJDIR)\$(PXXFILE:.cxx=.obj)
+PXXLIC = $(PCHOBJDIR)\$(PXXFILE:.cxx=.lxp)
+PCH_CXX_OPT = -Yu -Fp$(PXXHEADER)
+!if "$(PROCESSOR_ARCHITECTURE)" == "MIPS" || "$(PROCESSOR_ARCHITECTURE)" == "x86" || "$(PROCESSOR_ARCHITECTURE)" == "ALPHA"
+PCH_CXX_NAME = -Yl$(TARGETBASE)_$(TARGETTYPE)
+!else
+PCH_CXX_NAME =
+!endif
+
+! ifndef NEW_PCH_BUILD
+$(PXXHEADER) $(PXXLIC): $(PXXSOURCE)
+! if "$(PCHDIR)" == "$(MAKEDIR)"
+ @-md $(OBJDIR) $(OUTNUL)
+ $(CC) $(COMPLOGO) @<<$(OBJDIR)\$(PXXFILE:.cxx=.rsp)
+$(ALLCFLAGS: =
+)
+$(CINC: =
+)
+-Yc
+$(PCH_CXX_NAME)
+-Fp$(PXXHEADER)
+-Fo$(PRECOMPXXOBJ)
+-Tp$(PXXSOURCE)
+<<$(COMPRESP)
+ @echo $(DUMINCLUDE) > $(PXXLIC)
+! else
+ @-cd $(PCHDIR)
+ @-$(MAKE) -$(MAKEFLAGS)
+ @-cd $(MAKEDIR)
+! endif
+! else # NEW_PCH_BUILD
+
+$(PXXHEADER): $(PXXSOURCE)
+! if "$(PCHDIR)" == "$(MAKEDIR)"
+ @-md $(OBJDIR) $(OUTNUL)
+ $(CC) $(COMPLOGO) @<<$(OBJDIR)\$(PXXFILE:.cxx=.rsp)
+$(ALLCFLAGS: =
+)
+$(CINC: =
+)
+-Yc
+$(PCH_CXX_NAME)
+-Fp$(PXXHEADER)
+-Fo$(PRECOMPXXOBJ)
+-Tp$(PXXSOURCE)
+<<$(COMPRESP)
+! else
+ @-cd $(PCHDIR)
+ @-$(MAKE) -$(MAKEFLAGS)
+ @-cd $(MAKEDIR)
+! endif
+! endif # NEW_PCH_BUILD
+!else # PXXFILE == ""
+
+PCH_CXX_OPT =
+PRECOMPXXOBJ =
+
+!endif
+
+# ---------------------------- PFILE Support -------------------------
+
+!if "$(PFILE)" != ""
+
+PFILE = $(PFILE:.\=)
+PSOURCE = $(PCHDIR)\$(PFILE)
+PHEADER = $(PCHOBJDIR)\$(PFILE:.c=.ph)
+PRECOMPOBJ = $(PCHOBJDIR)\$(PFILE:.c=.obj)
+PLIC = $(PCHOBJDIR)\$(PFILE:.c=.lp)
+PCH_C_OPT = -Yu -Fp$(PHEADER)
+!if "$(PROCESSOR_ARCHITECTURE)" == "MIPS" || "$(PROCESSOR_ARCHITECTURE)" == "x86" || "$(PROCESSOR_ARCHITECTURE)" == "ALPHA"
+PCH_C_NAME = -Yl$(TARGETBASE)_$(TARGETTYPE)
+!else
+PCH_C_NAME =
+!endif
+
+! ifndef NEW_PCH_BUILD
+$(PHEADER) $(PLIC): $(PSOURCE)
+ @-md $(OBJDIR) $(OUTNUL)
+ $(CC) $(COMPLOGO) @<<$(OBJDIR)\$(PFILE:.c=.rsp)
+$(ALLCFLAGS: =
+)
+$(CINC: =
+)
+-Yc
+$(PCH_C_NAME)
+-Fp$(PHEADER)
+-Fo$(PRECOMPOBJ)
+-Tc$(PSOURCE)
+<<$(COMPRESP)
+ @echo $(DUMINCLUDE) > $(PLIC)
+
+! else # NEW_PCH_BUILD
+
+$(PHEADER): $(PSOURCE)
+ @-md $(OBJDIR) $(OUTNUL)
+ $(CC) $(COMPLOGO) @<<$(OBJDIR)\$(PFILE:.c=.rsp)
+$(ALLCFLAGS: =
+)
+$(CINC: =
+)
+-Yc
+$(PCH_C_NAME)
+-Fp$(PHEADER)
+-Fo$(PRECOMPOBJ)
+-Tc$(PSOURCE)
+<<$(COMPRESP)
+! endif # NEW_PCH_BUILD
+!else # PFILE == ""
+
+PCH_C_OPT =
+PRECOMPOBJ =
+
+!endif
+
+!ifndef NEW_PCH_BUILD
+# ----------------------- Library .LIC Support ------------------------
+
+!if "$(TARGETTYPE)" == "lib" && ("$(PXXFILE)" != "" || "$(PFILE)" != "")
+
+$(TGTDIR)\$(TARGET): $(TGTDIR)\$(TARGETBASE).lic
+
+$(TGTDIR)\$(TARGETBASE).lic: $(PXXLIC) $(PLIC)
+ @-md $(OBJDIR) $(OUTNUL)
+ @-$(DEL) $@ $(OUTNUL)
+ @for %i in ($**) do @type %i >> $@
+
+!endif
+
+!endif # NEW_PCH_BUILD
+
+
+#####################################################################
+#
+# Rules for c files
+#
+
+.c{$(OBJDIR)}.obj:
+ @echo $< --^> $@ $(OUTPUT)
+ @-md $(OBJDIR) $(OUTNUL)
+ @echo $(BUILD_EXE_COMPFLAG) $< $(CC) $(COMPLOGO) @$*.rsp
+ @$(CC) $(COMPLOGO) @<<$*.rsp
+$(ALLCFLAGS: =
+)
+$(CINC: =
+)
+$(PCH_C_OPT: =
+)
+-Fo$(MAKEDIR)\$*.obj
+$(MAKEDIR)\$<
+<<$(COMPRESP)
+!ifdef SIFTBUILD
+ $(SIFTTOOL) $(SIFTFLAGS) $*.obj
+!endif
+
+
+.c{$(OBJDIR)}.lst:
+ @echo $< --^> $@ $(OUTPUT)
+ @-md $(OBJDIR) $(OUTNUL)
+ @echo $(BUILD_EXE_COMPFLAG) $< $(CC) $(COMPLOGO) -Fc$*.lst @$*.rsp
+ @$(CC) $(COMPLOGO) -Fc$*.lst @<<$*.rsp
+$(ALLCFLAGS: =
+)
+$(CINC: =
+)
+$(PCH_C_OPT: =
+)
+-Fo$(MAKEDIR)\$*.obj
+$(MAKEDIR)\$<
+<<$(COMPRESP)
+
+
+#####################################################################
+#
+# Rules for cxx files
+#
+
+
+!if "$(PROCESSOR_ARCHITECTURE)" == "x86"
+
+CFFLAGS = +L +m7 +H63
+!elseif "$(PROCESSOR_ARCHITECTURE)" == "MIPS"
+
+CFFLAGS = +L +m7 +H63 +E$(IMPORTNT)\h\sdk\mipsxcpt.tab +M
+!elseif "$(PROCESSOR_ARCHITECTURE)" == "ALPHA"
+
+CFFLAGS = +L +m7 +H63 +E$(IMPORTNT)\h\sdk\alphxcpt.tab +M
+!endif
+
+.cxx{$(OBJDIR)}.obj:
+ @echo $< --^> $@ $(OUTPUT)
+ @-md $(OBJDIR) $(OUTNUL)
+ @echo $(BUILD_EXE_COMPFLAG) $< $(CC) $(COMPLOGO) @$*.rsp
+ @$(CC) $(COMPLOGO) @<<$*.rsp
+$(ALLCFLAGS: =
+)
+$(CINC: =
+)
+$(PCH_CXX_OPT: =
+)
+-Fo$(MAKEDIR)\$*.obj
+-Tp$(MAKEDIR)\$<
+<<$(COMPRESP)
+!ifdef SIFTBUILD
+ $(SIFTTOOL) $(SIFTFLAGS) $*.obj
+!endif
+
+.cxx{$(OBJDIR)}.lst:
+ @echo $< --^> $@ $(OUTPUT)
+ @-md $(OBJDIR) $(OUTNUL)
+ @echo $(BUILD_EXE_COMPFLAG) $< $(CC) $(COMPLOGO) -Fc$*.lst @$*.rsp
+ @$(CC) $(COMPLOGO) -Fc$*.lst @<<$*.rsp
+$(ALLCFLAGS: =
+)
+$(CINC: =
+)
+$(PCH_CXX_OPT: =
+)
+-Fo$*.obj
+-Tp$(MAKEDIR)\$<
+<<$(COMPRESP)
+
+
+.cpp{$(OBJDIR)}.obj:
+ @echo $< --^> $@ $(OUTPUT)
+ @-md $(OBJDIR) $(OUTNUL)
+ @echo $(BUILD_EXE_COMPFLAG) $< $(CC) $(COMPLOGO) @$*.rsp
+ @$(CC) $(COMPLOGO) @<<$*.rsp
+$(ALLCFLAGS: =
+)
+$(CINC: =
+)
+$(PCH_CXX_OPT: =
+)
+-Fo$(MAKEDIR)\$*.obj
+-Tp$(MAKEDIR)\$<
+<<$(COMPRESP)
+!ifdef SIFTBUILD
+ $(SIFTTOOL) $(SIFTFLAGS) $*.obj
+!endif
+
+.cpp{$(OBJDIR)}.lst:
+ @echo $< --^> $@ $(OUTPUT)
+ @-md $(OBJDIR) $(OUTNUL)
+ @echo $(BUILD_EXE_COMPFLAG) $< $(CC) $(COMPLOGO) -Fc$*.lst @$*.rsp
+ @$(CC) $(COMPLOGO) -Fc$*.lst @<<$*.rsp
+$(ALLCFLAGS: =
+)
+$(CINC: =
+)
+$(PCH_CXX_OPT: =
+)
+-Fo$*.obj
+-Tp$(MAKEDIR)\$<
+<<$(COMPRESP)
+
+
+
+
+############################################################################
+#
+# Build a Version resource (NT only) for every image in the build.
+#
+# The user has the choice of either defining their own version resource
+# script or letting the build make one for them on the fly. If the user
+# defines their own, set VERSION_RC in filelist.mk to point to a valid .rc
+# file (with the same format as $(VERSION_RC), below) and don't add that
+# file to the RCFILES macro in filelist.mk. If the user does not define
+# VERSION_RC, build a default file by using TARGET_DESCRIPTION and
+# (optionally) TARGET_INTERNAL_NAME to the internal name (By default, the
+# target name minus the extension).
+#
+
+!ifdef IMAGE_TYPE_COFF
+! if "$(OPSYS)" != "DOS" # BUGBUG: Chicago seems to fail on version resources BryanT 9/28/93
+! if "$(TARGETTYPE)" != "lib" && "$(TARGET)" != "RELEASE" && "$(TARGET)" != ""
+! if "$(VERSION_RC)" == ""
+VERSION_RC = $(OBJDIR)\$(TARGETBASE).rc1
+
+! ifndef TARGET_DESCRIPTION
+! if "$(RELEASE)" != ""
+!error *** BUILD ERROR - TARGET_DESCRIPTION not set. Aborting. ***
+! endif
+! endif
+
+! if "$(TARGET_INTERNAL_NAME)" == ""
+TARGET_INTERNAL_NAME = "$(TARGETBASE)"
+! endif
+
+# Set the major file type to one of DRV, APP, DLL, STATIC LIB, or UNKNOWN.
+
+! if "$(TARGETTYPE)" == "dll"
+VFT_TYPE = VFT_DLL
+! elseif "$(TARGETTYPE)" == "exe"
+VFT_TYPE = VFT_APP
+! elseif "$(TARGETTYPE)" == "lib"
+VFT_TYPE = VFT_STATIC_LIB
+! else
+VFT_TYPE = VFT_UNKNOWN
+! endif # if "$(TARGETTYPE)" == "sys"
+
+# The Minor file type distinguishes the type of driver. All DRV's in Cairo
+# are currently SYSTEM drivers.
+
+! if "$(TARGETTYPE)" == "sys"
+VFT_TYPE2 = VFT2_DRV_SYSTEM
+! else
+VFT_TYPE2 = VFT2_UNKNOWN
+! endif
+
+all: $(VERSION_RC)
+
+$(VERSION_RC): $(TYPESDIR)\makefile.inc
+ @-md $(OBJDIR) $(OUTNUL)
+ type << > $@
+#include <windows.h>
+#include <ntverp.h>
+#define VER_FILETYPE $(VFT_TYPE)
+#define VER_FILESUBTYPE $(VFT_TYPE2)
+#define VER_FILEDESCRIPTION_STR $(TARGET_DESCRIPTION)
+#define VER_INTERNALNAME_STR $(TARGET_INTERNAL_NAME)
+#include <common.ver>
+<<NOKEEP
+
+! endif # if "$(VERSION_RC)" == ""
+
+RCFILES = $(VERSION_RC) $(RCFILES)
+
+!else # TARGETTYPE != lib && TARGET != RELEASE
+
+VERSION_RC =
+
+! endif # TARGETTYPE != lib && TARGET != RELEASE
+!endif # OPSYS == DOS BUGBUG: Chicago
+!endif # IMAGE_TYPE_COFF
+
+
+
+######################################################################
+#
+# Rule to build RES from RC file.
+#
+# Note: we mess with PATH because RC is not real clever about
+# finding RCPP (it's sub-component EXE). It looks along PATH,
+# so we limit PATH here in order to guarantee that RCPATH is
+# in PATH, and also to avoid invoking a non-compatible RCPP that
+# might just be in the user's private toolset.
+#
+# In the case of an NT build, COFF can't handle more than one
+# resource obj. So, we build a single .rc2 file that #include's
+# all the component RCFILES.
+#
+
+!ifdef IMAGE_TYPE_COFF
+! if "$(RCFILES)" != ""
+
+$(OBJDIR)\$(TARGETBASE).rc2: $(RCFILES)
+ @echo $(RCFILES) --^> $@ $(OUTPUT)
+ type << | $(SED) -f $(SCRIPTS)\rcfiles.sed > $@
+$(RCFILES: =
+)
+<<NOKEEP
+
+$(OBJDIR)\$(TARGETBASE).res: $(OBJDIR)\$(TARGETBASE).rc2
+
+{$(OBJDIR)}.rc2{$(OBJDIR)}.res:
+ @echo $< --^> $@ $(OUTPUT)
+ @-md $(OBJDIR) $(OUTNUL)
+ $(RC) $(ORCFLAGS) -I$(OBJDIR) $(RCFLAGS) $(MAKEDIR)\$(<R).tmp $(MAKEDIR)\$<
+ $(CVTRES) -$(PLATFORM) -o $*.res $(MAKEDIR)\$(<R).tmp
+! endif
+
+!else
+
+.rc{$(OBJDIR)}.res:
+ @echo $< --^> $@ $(OUTPUT)
+ @-md $(OBJDIR) $(OUTNUL)
+ @set oldpath=%%PATH%%
+ @set path=$(RCPATH)
+ $(RC) $(ORCFLAGS) $(RCFLAGS) $*.res $(MAKEDIR)\$<
+ @set path=%%oldpath%%
+ @set oldpath=
+
+!endif
+
+
+######################################################################
+#
+# Rule for building .lib files from .lrf files
+
+.lrf{$(OBJDIR)}.lib:
+ @echo $< --^> $@ $(OUTPUT)
+ @-md $(OBJDIR) $(OUTNUL)
+ -$(DEL) $*.lib $(OUTNUL)
+ @echo lib32 -out:@$< $(BUILD_EXE_PROCTYPE)
+ @$(LIBUTIL) $(LIBFLAGS) @$<
+
+.lrf.lib:
+ @echo $< --^> $@ $(OUTPUT)
+ @-md $(OBJDIR) $(OUTNUL)
+ if exist $*.lib $(DEL) $*.lib $(OUTNUL)
+ @echo lib32 -out:@$< $(BUILD_EXE_PROCTYPE)
+ $(LIBUTIL) $(LIBFLAGS) @$*.lrf
+
+
+
+
+##################################################
+#
+# Rules for generating .h and .c files from .idl files
+#
+
+
+##
+## IDLUSE == none --> generate header file only
+##
+
+
+.idl{$(MIDL_HDR_OUT_DIR)}.h:
+ @echo $< --^> $@ $(OUTPUT)
+!ifdef IMAGE_TYPE_COFF
+ $(MIDL) @<<$*.rsp $<
+$(IDLMIDLFLAGS)
+$(CINC)
+-no_format_opt
+-no_warn
+-char unsigned
+-mode c_port
+-proxy $(MIDL_OUT_DIR)\$(@B)_p.c
+-iid $(MIDL_OUT_DIR)\$(@B)_i.c
+-header $(MIDL_HDR_OUT_DIR)\$(@B).h
+-caux $(MIDL_OUT_DIR)\$(@B)_x.c
+-saux $(MIDL_OUT_DIR)\$(@B)_y.c
+-cpp_cmd
+$(CC)
+-cpp_opt "$(COMPLOGO) -DMIDL_PASS $(CPLATFORM) $(OCFLAGS) $(CINC) -E -Tc"
+<<$(COMPRESP)
+!else
+ $(MIDL) $(CINC) -char unsigned -mode c_port -header $@ -cpp_cmd $(CC) -cpp_opt "$(COMPLOGO) @<<$*.rsp -Tc" $<
+-DMIDL_PASS
+-D$(PLATFORM)
+$(OCFLAGS)
+$(CINC)
+-D$(PLATFORM)=1
+-E
+<<$(COMPRESP)
+!if "$(OPSYS)"=="NT1X" && "$(NORELEASE_CHICAGO)"==""
+ @echo Build_Status Releasing Midl generated $(@B).h files to $(HCOPY)\chicago
+ copy $(MIDL_HDR)OUT_DIR)\$(@B).h $(HCOPY)\chicago
+!endif
+!endif
+
+#-proxy $(MIDL_OUT_DIR)\$(@B)_p.c
+
+##################################################
+# Provide some includes prefixes
+
+INCLUDES_PREFIX= -L$$(OBJDIR) -S$$(OBJDIR)
+
+INCLUDES_ROOTS= $(INCLUDES_ROOTS) \
+ -P$$(BASEDIR)=$(BASEDIR)
+
+
+
+
+OBJS=$(CXX_OBJS) \
+ $(C_OBJS) \
+ $(PRECOMPOBJ) \
+ $(PRECOMPXXOBJ) \
+ $(OBJFILES)
+
+
+
+############################################################################
+#
+# Build a Link Include file.
+# Basically, every library we call that has a precompiled header needs
+# to have that header obj forced into the final image. The .lic file built
+# with the pch provides that for us. We just make a simple one with
+# NODEFAULTLIB and append any others we can find. BryanT 4/14/93
+#
+
+!ifdef IMAGE_TYPE_COFF
+! ifndef NEW_PCH_BUILD
+TARGETLICS = $(TGTDIR)\$(TARGETBASE).tlc
+
+$(TARGETLICS): $(OBJS) $(LIBS)
+ @-md $(TGTDIR) $(OUTNUL)
+ @echo -NODEFAULTLIB > KTx14J.lic
+ @echo @echo off > $*.cmd
+ @$(SED) -f $(SCRIPTS)\licfiles.sed << >> $*.cmd
+$(LIBS: =
+)
+$(OBJS: =
+)
+<<NOKEEP
+ @-$*.cmd
+ @-$(DEL) $@ $(OUTNUL)
+ @for %%i in (*.lic) do @type %i >> $@
+ @-$(DEL) *.lic $(OUTNUL)
+! else
+
+TARGETLICS =
+
+! endif # NEW_PCH_BUILD
+
+!else
+
+TARGETLICS =
+
+!endif
+
+############################################################################
+#
+# HACK for NT COFF limitation of only 1 .res obj per image.
+#
+# We force a single resfile name and handle generating it with the
+# .rc->.rc2->,res rules.
+#
+
+!ifdef IMAGE_TYPE_COFF
+! if "$(RCFILES)" != ""
+
+RESFILES = $(OBJDIR)\$(TARGETBASE).res
+
+! endif
+!endif
+
+
+############################################################################
+#
+# Build a DLL or CPL (Control Panel Applet)
+#
+
+#BUGBUG BuildDLL
+
+!if "$(TARGETTYPE)" == "dll"
+
+! ifdef NOEXPORTS
+DLLDEF=
+! else
+DLLDEF= $(DEFFILEEXP)
+! endif
+DLLOBJS= $(OBJS)
+! ifdef SIFTBUILD
+DLLOBJS = $(DLLOBJS) $(SIFTOBJ)
+! endif # SIFTBUILD
+DLLLIBS= $(LIBS) $(OSLIBDLL) $(RTLIBDLL)
+DLLRES= $(RESFILES)
+
+! ifndef NEW_PCH_BUILD
+TLRSPFILE = @$(TARGETLICS)
+! else
+TLRSPFILE =
+! endif
+
+#
+# Link the DLL.
+#
+
+$(TGTDIR)\$(TARGET): $(DLLOBJS) $(DLLLIBS) $(DLLRES) $(DLLDEF) $(TYPESDIR)\coffbase.txt $(TARGETLICS)
+ @$(ECHOTIME) Linking $@ $(ATSTR) $(TIMESTR)... $(OUTPUT)
+ @-md $(TGTDIR) $(OUTNUL)
+! ifdef IMAGE_TYPE_COFF
+ @echo link32 -out:$@ $(BUILD_EXE_PROCTYPE)
+ @$(LINK) @<<$*.lnk $(TLRSPFILE)
+$(DLLDEF)
+$(LFLAGSDLL: =
+)
+$(DLLSTARTUP)
+-OUT:$@
+$(IMAGEBASE)
+$(DLLOBJS: =
+)
+$(DLLRES)
+$(DLLLIBS: =
+)
+<<$(LINKRESP)
+! ifndef NO_SPLITSYM
+ $(SPLITSYM) $(SPLITSYMFLAGS) $@
+! endif
+!if "$(RELEASE_BIN)" != ""
+ binplace $(BINPLACE_FLAGS) $@
+!endif
+!if "$(NO_RELEASE_IMPORT_LIB)" == "" && "$(LIBCP)" != ""
+ $(COPY) $*.lib $(LIBCP)
+!endif
+
+
+
+
+
+CLEANTARGET= $(CLEANTARGET)\
+ $(OBJDIR)\$(TARGETBASE).lib\
+ $(OBJDIR)\$(TARGETBASE).exp
+
+! else # IMAGE_TYPE_COFF
+ @echo link32 -out:$*.dll $(BUILD_EXE_PROCTYPE)
+ @$(LINK) @<<$*.lnk
+$(LFLAGSDLL) $(DLLSTARTUP) $(DLLOBJS: = +^
+)
+$*.dll
+$*.map
+$(DLLLIBS: = +^
+)
+$(DLLDEF)
+<<$(LINKRESP)
+ if exist $(DLLRES) $(RC) $(RCEXEFLAGS) -fe $*.dll $(DLLRES) $*.dll
+ $(MAPSYM) $(MAPSYMFLAGS) $*.map
+
+#
+# Generate the import library.
+#
+
+all: $(OBJDIR)\$(TARGETBASE).lib
+
+$(OBJDIR)\$(TARGETBASE).lib: $(DLLDEF:.\=)
+
+CLEANTARGET= $(CLEANTARGET) $(OBJDIR)\$(TARGETBASE).lib
+
+! endif # IMAGE_TYPE_COFF
+
+!endif # Build DLL
+
+
+############################################################################
+#
+# Build a LIB
+#
+
+!if "$(TARGETTYPE)" == "lib"
+
+$(OBJDIR)\$(TARGETBASE).lib: $(OBJS) $(LIBS)
+ @$(ECHOTIME) Building $@ $(ATSTR) $(TIMESTR)... $(OUTPUT)
+ @-md $(OBJDIR) $(OUTNUL)
+ -$(DEL) $@ $(OUTNUL)
+! ifdef IMAGE_TYPE_COFF
+ @echo lib32 -out:$@ $(BUILD_EXE_PROCTYPE)
+ @$(LIBUTIL) @<<$*.lnb
+$(LIBFLAGS: =
+)
+$(OBJS: =
+)
+$(LIBS: =
+)
+-OUT:$@
+<<$(LINKRESP)
+
+! else # IMAGE_TYPE_COFF
+ @echo lib32 -out:$@ $(BUILD_EXE_PROCTYPE)
+ @$(LIBUTIL) $(LIBFLAGS) @<<$*.lnb
+$(OBJDIR)\$(TARGET)
+y
+$(OBJS: = &^
+)&
+$(LIBS: = &^
+)&
+
+$*.lls
+<<$(LINKRESP)
+
+! endif # IMAGE_TYPE_COFF
+
+!endif # Build LIB
+
+
+############################################################################
+#
+# Build an EXE
+#
+
+!if "$(TARGETTYPE)" == "exe"
+! ifdef IMAGE_TYPE_COFF
+EXEDEF=
+! else
+! if "$(DEFFILE)" == ""
+EXEDEF=
+! else
+EXEDEF= $(DEFFILEEXP)
+! endif
+! endif
+EXELIBS= $(LIBS)\
+! if "$(MTHREAD)" == "1"
+ $(RTLIBEXEMT)\
+! else
+ $(RTLIBEXE)\
+! endif
+ $(OSLIBEXE)
+
+EXEOBJS= $(OBJS)
+
+!ifdef SIFTBUILD
+EXEOBJS = $(EXEOBJS) $(SIFTOBJ)
+!endif # SIFTBUILD
+
+EXERES= $(RESFILES)
+
+#
+# Link the EXE.
+#
+
+
+
+! ifndef NEW_PCH_BUILD
+TLRSPFILE = @$(TARGETLICS)
+! else
+TLRSPFILE =
+! endif
+
+#
+# Need WINSTUB.EXE to build WIN16 targets -- "DOS" "i286"
+#
+
+WINSTUB=$(RCPATH)\winstub.exe
+
+$(TGTDIR)\$(TARGET): $(EXEOBJS) $(EXELIBS) $(EXERES) $(EXEDEF) $(TARGETLICS)
+!if "$(OPSYS)" == "DOS" && "$(PROCESSOR_ARCHITECTURE)" == "i286"
+ $(COPY) $(WINSTUB) .
+!endif
+ @$(ECHOTIME) Linking $@ $(ATSTR) $(TIMESTR)... $(OUTPUT)
+ @-md $(TGTDIR) $(OUTNUL)
+! ifdef IMAGE_TYPE_COFF
+ @echo link32 -out:$@ $(BUILD_EXE_PROCTYPE)
+ @$(LINK) @<<$*.lnk $(TLRSPFILE)
+$(LFLAGSEXE: =
+)
+$(EXESTARTUP)
+$(EXEOBJS: =
+)
+$(EXELIBS: =
+)
+$(EXERES)
+-OUT:$@
+$(IMAGEBASE)
+! if "$(NTDEBUGTYPE)" == "windbg" && "$(PROCESSOR_ARCHITECTURE)" == "x86"
+-nopack
+! endif
+<<$(LINKRESP)
+! if "$(NTDEBUGTYPE)" == "windbg" && "$(PROCESSOR_ARCHITECTURE)" == "x86"
+ $(CVPACK) -nologo $@
+! endif
+! ifndef NO_SPLITSYM
+ $(SPLITSYM) $(SPLITSYMFLAGS) $@
+! endif
+! else # IMAGE_TYPE_COFF
+ @echo link32 -out:$*.exe $(BUILD_EXE_PROCTYPE)
+ @$(LINK) @<<$*.lnk
+$(LFLAGSEXE) $(EXESTARTUP) +
+$(EXEOBJS: = +^
+)
+$*.exe
+$*.map
+$(EXELIBS: = +^
+)
+$(EXEDEF)
+<<$(LINKRESP)
+!if "$(OPSYS)" == "DOS" && "$(PROCESSOR_ARCHITECTURE)" == "i286"
+ if exist $(EXERES) $(RC) $(RCEXEFLAGS) -fe $*.exe $(EXERES) $*.exe
+ -$(DEL) winstub.exe
+!else
+ if exist $(EXERES) $(RC) $(RCEXEFLAGS) -fo $*.exe $(EXERES) $*.exe
+!endif
+ $(MAPSYM) $(MAPSYMFLAGS) $*.map
+! endif # IMAGE_TYPE_COFF
+
+!endif # Build EXE
+
+
+
+######################################################################
+# IMPLIB files (unlike their real lib counterparts)
+# live in the source directory, not in a version
+# specific subdirectory
+
+!if "$(NO_IMPLIB)" == ""
+! ifdef IMAGE_TYPE_COFF
+
+$(DEFFILEEXP) $(DEFFILELIB): $(DEFFILE)
+ @echo $(DEFFILE) --^> $@ $(OUTPUT)
+ @-md $(OBJDIR) $(OUTNUL)
+ $(CC) $(COMPLOGO) @<<$*.rsp 1>$*.def
+$(CPLATFORM)
+$(CDEBUGFLAGS)
+$(CINC: =
+)
+-EP
+-Tc $**
+<<$(COMPRESP)
+ $(LIBUTIL) @<<$*.lsp
+$(LIBFLAGS)
+-OUT:$(DEFFILELIB)
+-DEF:$*.def
+<<$(LINKRESP)
+
+.def{$(OBJDIR)}.lib:
+ @echo $< --^> $@ $(OUTPUT)
+ @-md $(OBJDIR) $(OUTNUL)
+ $(CC) $(COMPLOGO) @<<$*.rsp 1>$(OBJDIR)\$<
+$(CPLATFORM)
+$(CDEBUGFLAGS)
+$(CINC: =
+)
+-EP
+-Tc $<
+<<$(COMPRESP)
+ $(LIBUTIL) @<<$*.lsp
+$(LIBFLAGS)
+-OUT:$@
+-DEF:$(OBJDIR)\$<
+<<$(LINKRESP)
+
+! else # IMAGE_TYPE_COFF
+
+IMPFLAGS=-nologo -noignorecase
+
+.def.lib:
+ @echo $< --^> $@ $(OUTPUT)
+ $(IMPLIB) $(IMPFLAGS) $@ $<
+
+$(DEFFILEEXP): $(DEFFILE)
+ @echo $(DEFFILE) --^> $@ $(OUTPUT)
+ @-md $(OBJDIR) $(OUTNUL)
+ $(CC) $(COMPLOGO) @<<$*.rsp 1>$(DEFFILEEXP)
+$(ALLCFLAGS: =
+)
+$(CINC: =
+)
+-EP
+-Tc $**
+<<$(COMPRESP)
+
+$(DEFFILELIB): $(DEFFILEEXP)
+ @echo $(DEFFILEEXP) --^> $@ $(OUTPUT)
+ $(IMPLIB) $(IMPFLAGS) $(DEFFILELIB) $(DEFFILEEXP)
+
+! endif # IMAGE_TYPE_COFF
+!endif # NO_IMPLIB
+
+
+
+############################################################################
+#
+# Cleanup
+#
+
+!if defined(TARGET) || defined(CLEANTARGET)
+
+clean: cleanobj
+
+cleanobj:
+! if "$(HOST)" == "NT"
+ -$(DEL) /q $(OBJDIR) $(OUTNUL)
+! else
+ -echo y | $(DEL) $(OBJDIR) $(OUTNUL)
+! endif
+ -rmdir $(OBJDIR) $(OUTNUL)
+
+cleantarget:
+! if "$(HOST)" == "NT"
+ -$(DEL) /q $(CLEANTARGET) $(OUTNUL)
+! else
+ -echo y | $(DEL) $(CLEANTARGET) $(OUTNUL)
+! endif
+
+!endif
+
+!ifdef CLEANFILES
+
+clean: cleanclean
+
+cleanclean:
+ -$(DEL) $(CLEANFILES) $(OUTNUL)
+
+!endif
+
+!ifdef LIBCOPY
+! if "$(TARGETTYPE)" == "lib" || "$(TARGETTYPE)" == "dll"
+
+clean: cleanlibcopy
+
+cleanlibcopy:
+ -$(DEL) $(LIBCOPY)\$(TARGETBASE).lib $(OUTNUL)
+ -$(DEL) $(LIBCOPY)\$(TARGETBASE).lic $(OUTNUL)
+!if "$(OPSYS)"=="NT1X" && "$(NORELEASE_CHICAGO)" == ""
+ -$(DEL) $(CHICAGOLIBCOPY)\$(TARGETBASE).lib $(OUTNUL)
+ -$(DEL) $(CHICAGOLIBCOPY)\$(TARGETBASE).lic $(OUTNUL)
+!endif
+
+! endif
+!endif
+
+!ifdef DLLCOPY
+! if "$(TARGETTYPE)" == "dll"
+
+clean: cleandllcopy
+
+cleandllcopy:
+ -$(DEL) $(DLLCOPY)\$(TARGETBASE).dll $(OUTNUL)
+ -$(DEL) $(DLLCOPY)\$(TARGETBASE).dbg $(OUTNUL)
+! endif
+!endif
+
+!ifdef EXECOPY
+! if "$(TARGETTYPE)" == "exe"
+
+clean: cleanexecopy
+
+cleanexecopy:
+ -$(DEL) $(EXECOPY)\$(TARGETBASE).exe $(OUTNUL)
+ -$(DEL) $(EXECOPY)\$(TARGETBASE).dbg $(OUTNUL)
+! endif
+!endif
+
+!if "$(TLBCOPY)" != ""
+
+clean: cleantlbcopy
+
+cleantlbcopy:
+ @echo WARNING - Can't clean Type Library copies in $(TLBCOPY).
+
+!endif
+
+
+############################################################################
+#
+# Copy targets to other directories.
+#
+copy:
+
+!ifdef LIBCOPY
+
+! if "$(TARGETTYPE)" == "dll" || "$(TARGETTYPE)" == "lib"
+
+copy: $(LIBCOPY)\$(TARGETBASE).lib
+
+$(LIBCOPY)\$(TARGETBASE).lib: $(OBJDIR)\$(TARGETBASE).lib
+ @echo Copying $(TARGETBASE).lib to $(LIBCOPY)... $(OUTPUT)
+ @-md $(LIBCOPY) $(OUTNUL)
+ @-$(CHMODE) -r $(LIBCOPY)\$(TARGETBASE).lib $(OUTNUL)
+ @-$(CHMODE) -r $(LIBCOPY)\$(TARGETBASE).lic $(OUTNUL)
+ $(COPY) $(OBJDIR)\$(TARGETBASE).lib $(LIBCOPY)\$(TARGETBASE).lib
+ @-$(COPY) $(OBJDIR)\$(TARGETBASE).lic $(LIBCOPY)\$(TARGETBASE).lic $(OUTNUL)
+!if "$(OPSYS)" == "NT1X" && "$(NORELEASE_CHICAGO)" == ""
+ @echo Releasing $(TARGETBASE).lib for Chicago... $(OUTPUT)
+ @-md $(CHICAGOLIBCOPY) $(OUTNUL)
+ @-$(CHMODE) -r $(CHICAGOLIBCOPY)$(TARGETBASE).lib $(OUTNUL)
+ @-$(CHMODE) -r $(CHICAGOLIBCOPY)$(TARGETBASE).lic $(OUTNUL)
+ $(COPY) $(OBJDIR)\$(TARGETBASE).lib $(CHICAGOLIBCOPY)\$(TARGETBASE).lib
+ @-$(COPY) $(OBJDIR)\$(TARGETBASE).lic $(CHICAGOLIBCOPY)\$(TARGETBASE).lic $(OUTNUL)
+!endif
+
+! endif # dll or lib
+
+!endif # LIBCOPY
+
+
+!ifdef DLLCOPY
+
+! if "$(TARGETTYPE)" == "dll"
+
+copy: $(DLLCOPY)\$(TARGETBASE).dll
+
+$(DLLCOPY)\$(TARGETBASE).dll: $(TGTDIR)\$(TARGETBASE).dll
+ @echo Copying $(TARGETBASE).dll to $(DLLCOPY)... $(OUTPUT)
+ @-md $(DLLCOPY) $(OUTNUL)
+ @-$(CHMODE) -r $(DLLCOPY)\$(TARGETBASE).dll $(OUTNUL)
+ @-$(CHMODE) -r $(DLLCOPY)\$(TARGETBASE).dbg $(OUTNUL)
+ $(COPY) $(TGTDIR)\$(TARGETBASE).dll $(DLLCOPY)\$(TARGETBASE).dll
+ @-$(COPY) $(TGTDIR)\$(TARGETBASE).dbg $(DLLCOPY)\$(TARGETBASE).dbg $(OUTNUL)
+! endif # dll
+
+!endif # DLLCOPY
+
+
+!ifdef EXECOPY
+
+! if "$(TARGETTYPE)" == "exe"
+
+copy: $(EXECOPY)\$(TARGETBASE).exe
+
+$(EXECOPY)\$(TARGETBASE).exe: $(TGTDIR)\$(TARGETBASE).exe
+ @echo Copying $(TARGETBASE).exe to $(EXECOPY)... $(OUTPUT)
+ @-md $(EXECOPY) $(OUTNUL)
+ @-$(CHMODE) -r $(EXECOPY)\$(TARGETBASE).exe $(OUTNUL)
+ @-$(CHMODE) -r $(EXECOPY)\$(TARGETBASE).dbg $(OUTNUL)
+ $(COPY) $(TGTDIR)\$(TARGETBASE).exe $(EXECOPY)\$(TARGETBASE).exe
+ @-$(COPY) $(TGTDIR)\$(TARGETBASE).dbg $(EXECOPY)\$(TARGETBASE).dbg $(OUTNUL)
+
+! endif # exe
+
+!endif # EXECOPY
+
+!if "$(TLBCOPY)" != "" && "$(TYPELIBS)" != ""
+
+copy: copytlbfiles
+
+copytlbfiles: $(TYPELIBS)
+ @echo Build_Status Copying Type Libraries to "$(TLBCOPY)"... $(OUTPUT)
+ @-md $(TLBCOPY) $(OUTNUL)
+ !$(COPY) $** $(TLBCOPY)
+ !$(UNREGTLB) $**
+ !$(REGTLB) $(TLBCOPY)\$(**F)
+
+!else
+
+copytlbfiles:
+
+
+!endif
+
+############################################################################
+#
+# Generate external header file
+#
+
+!ifdef HFILES
+
+all: $(TARGETBASE).h
+
+clean: cleanh
+
+cleanh:
+ -$(DEL) $(TARGETBASE).h $(OUTNUL)
+
+$(TARGETBASE).h: $(HFILES)
+ @echo Generating $(TARGETBASE).h $(OUTPUT)
+ $(SED) -f $(SCRIPTS)\public.sed $(HFILES) >$(TMP)\$(TARGETBASE).h
+ -$(CMP) -s $(TMP)\$(TARGETBASE).h $@ 2>nul || $(COPY) $(TMP)\$(TARGETBASE).h $@
+ -$(DEL) $(TMP)\$(TARGETBASE).h $(OUTNUL)
+
+DEPENDFILES = $(DEPENDFILES) $(TARGETBASE).h
+
+!endif
+
+
+############################################################################
+#
+# Resource files dependencies
+#
+
+!if "$(RESFILES)" != ""
+$(RESFILES): $(RCFILES) $(RCOBJECTS)
+!endif
+
+
+############################################################################
+#
+# Dependencies
+#
+
+!if "$(DEPENDSRC)" == "" && \
+ "$(CXXFILES)" == "" && \
+ "$(CPPFILES)" == "" && \
+ "$(CFILES)" == "" && \
+ "$(IDLFILES)" == "" && \
+ "$(TDLFILES)" == ""
+
+
+depend:
+
+!else
+
+! if "$(DEPENDSRC)" == "" && \
+ "$(CXXFILES)" == "" && \
+ "$(CPPFILES)" == "" && \
+ "$(CFILES)" == ""
+DEPENDSRC=
+! else
+DEPENDSRC=$(DEPENDSRC) $(CXXFILES) $(CPPFILES) $(CFILES)
+! endif
+
+
+depend: dependfile
+
+!ifdef MULTIDEPEND
+DEPENDFILE=depend.mk$(RDEXT)
+NEWDEPENDFILE=depend.ne$(RDEXT)
+!else
+DEPENDFILE=depend.mk
+NEWDEPENDFILE=depend.new
+!endif
+
+OBJPATTERN=$(OBJDIR:\=\\)
+
+
+#########################################################################
+#
+# Here's where the dependencies are actually generated. We break up
+# the CINC, INCLUDES_ROOTS, and src macros to put one command on each
+# to ensure no one line is over 1024 bytes in length. The includes
+# tool reads in 1k bytes and get's confused if any one line is split.
+#
+
+INCLUDES_FLAGS = $(INCLUDES_FLAGS) -nntos.h -nzwapi.h -dos
+
+!if "$(OPSYS)"=="NT1X"
+INCLUDES_FLAGS =$(INCLUDES_FLAGS) -nole2.h
+!endif
+
+dependfile: $(DEPENDFILES)
+ $(ECHOTIME) # ; # Built automatically ; # ; >$(NEWDEPENDFILE)
+!if "$(DEPENDSRC)" != ""
+#
+# Source file dependencies
+#
+ $(ECHOTIME) # ; # Source files ; # ; >>$(NEWDEPENDFILE)
+ $(INCLUDES) @<< >>$(NEWDEPENDFILE)
+-e
+$(INCLUDES_FLAGS)
+$(INCLUDES_PREFIX)
+$(CINC:-I=
+-I)
+$(INCLUDES_ROOTS:-P=
+-P)
+$(DEPENDSRC:.\=
+.\)
+<<NOKEEP
+!endif # DEPENDSRC
+
+#
+# MIDL dependencies
+#
+
+!if "$(IDLFILES)" != ""
+ $(ECHOTIME) # ; # MIDL Source files ; # ; >>$(NEWDEPENDFILE)
+ $(INCLUDES) @<<idl.tmp >>$(NEWDEPENDFILE)
+-e
+$(INCLUDES_FLAGS)
+$(CINC:-I=
+-I)
+$(INCLUDES_ROOTS:-P=
+-P)
+-sh
+-S$$(MIDL_HDR_OUT_DIR)
+$(IDLFILES:.\=
+.\)
+<<NOKEEP
+!endif # IDLFILES
+
+!if "$(TDLFILES)" != ""
+ $(ECHOTIME) # ; # MkTypeLib Source files ; # ; >>$(NEWDEPENDFILE)
+ $(INCLUDES) @<<tdl.tmp >>$(NEWDEPENDFILE)
+-e
+$(INCLUDES_FLAGS)
+$(CINC:-I=
+-I)
+$(INCLUDES_ROOTS:-P=
+-P)
+-stlb
+-S$$(OBJDIR)
+$(TDLFILES:.\=
+.\)
+<<NOKEEP
+
+!endif # IDLFILES
+
+
+#
+# C++ PCH dependencies
+#
+
+!if "$(PXXFILE)" != ""
+ $(ECHOTIME) # ; # Precompiled C++ header ; # ; ; !ifdef PXXFILE >>$(NEWDEPENDFILE)
+# if exist $(PXXSOURCE) $(INCLUDES) @<< >>$(NEWDEPENDFILE)
+ if exist $(PXXSOURCE) $(INCLUDES) $(INCLUDES_FLAGS) -e -S$$(PCHDIR)\$$(OBJDIR) \
+ -L$$(PCHDIR)\$$(OBJDIR) -spxh $(CINC:-I=-I) $(INCLUDES_ROOTS:-P=-P)\
+ $(PXXSOURCE) >>$(NEWDEPENDFILE)
+#$(INCLUDES_FLAGS)
+#-e
+#-S$$(PCHDIR)\$$(OBJDIR)
+#-L$$(PCHDIR)\$$(OBJDIR)
+#-spxh
+#$(CINC:-I=
+#-I)
+#$(INCLUDES_ROOTS:-P=
+#-P)
+#$(PXXSOURCE)
+#<<NOKEEP
+ $(SED) "s/$(OBJPATTERN)\(.*\)/$$(OBJDIR)\1 : \
+$$(PCHDIR)\\$$(OBJDIR)\\$(PXXFILE:.cxx=.pxh)/" << >>$(NEWDEPENDFILE)
+$(CXX_OBJS: =^
+)
+<<NOKEEP
+ $(ECHOTIME) !endif # PXXFILE ; ;>>$(NEWDEPENDFILE)
+!endif
+
+#
+# C PCH dependencies
+#
+
+!if "$(PFILE)" != ""
+ $(ECHOTIME) # ; # Precompiled C header ; # ; ; !ifdef PFILE >>$(NEWDEPENDFILE)
+ if exist $(PSOURCE) $(INCLUDES) @<< >>$(NEWDEPENDFILE)
+-e
+$(INCLUDES_FLAGS)
+-S$$(PCHDIR)\$$(OBJDIR)
+-L$$(PCHDIR)\$$(OBJDIR)
+-sph
+$(CINC:-I=
+-I)
+$(INCLUDES_ROOTS:-P=
+-P)
+$(PSOURCE)
+<<NOKEEP
+ $(ECHOTIME) $(C_OBJS:.obj =.obj ; )| \
+ $(SED) "s/$(OBJPATTERN)/$$(OBJDIR)/" | \
+ $(SED) "s/\.obj/.obj : $$(PCHDIR)\\$$(OBJDIR)\\$(PFILE:.c=.ph)/" >>$(NEWDEPENDFILE)
+ $(ECHOTIME) !endif # PFILE ; ;>>$(NEWDEPENDFILE)
+!endif
+ @$(CMP) -s $(NEWDEPENDFILE) $(DEPENDFILE) $(OUTNUL) || \
+ $(COPY) $(NEWDEPENDFILE) $(DEPENDFILE) $(OUTNUL) || \
+ (out -f -! $(DEPENDFILE) && $(ECHOTIME) $(DEPENDFILE) checked out... & $(COPY) $(NEWDEPENDFILE) $(DEPENDFILE) $(OUTNUL))
+ $(DEL) $(NEWDEPENDFILE) $(OUTNUL)
+
+!endif # DEPENDSRC
+
+############################################################################
+#
+# Special Rules for Building NT-like parts of the tree. For instance,
+# OFS. Defining RELEASE=NT causes the build to be performed 2 times for
+# this part of the tree. Once with the current BUILDTYPE, once with the
+# opposite one. In either case, we release under the current build in
+# either a CHECK\NT\... tree (for DEBUG BUILDTYPE) or FREE\NT\... tree
+# (for RETAIL BUILDTYPE).
+#
+
+!if ("$(RELEASE)" == "NT" && "$(BUILD_BOTH)" != "FALSE") || "$(BUILD_BOTH)" == "TRUE"
+
+! if "$(BUILDTYPE)" == "DEBUG"
+SECONDBUILDTYPE = RETAIL
+! else
+SECONDBUILDTYPE = DEBUG
+! endif
+
+all tree clean:
+ @$(MAKE) -$(MAKEFLAGS) -L BUILDTYPE=$(SECONDBUILDTYPE) RELEASETREE=$(TGTDIR:OBJ=) BUILD_BOTH=FALSE $@
+
+!endif # RELEASE = NT
diff --git a/private/oleutest/balls/myproxy/daytona.inc b/private/oleutest/balls/myproxy/daytona.inc
new file mode 100644
index 000000000..d3fbaaf23
--- /dev/null
+++ b/private/oleutest/balls/myproxy/daytona.inc
@@ -0,0 +1,64 @@
+!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:
+
+ David Plummer (davepl) 19-Mar-94
+
+ Modifed by via awk to include global project include file
+ and to wrap precompiled header line within a conditional
+ that can be set in this include file.
+
+ Donna Liu (DonnaLi) 19-Dec-1993
+
+!ENDIF
+
+DLLENTRY= _DllMainCRTStartup
+
+DLLBASE=@$(BASEDIR)\PUBLIC\SDK\LIB\coffbase.txt,usermode
+
+
+!include ..\..\daytona.inc
+
+INCLUDES= ;..;$(OLEBALLSDIR)\common;
+INCLUDES= $(INCLUDES);$(OLEUTESTDIR)\balls\oleprx32\daytona
+
+UMTYPE= windows
+UMAPPL=
+UMTEST=
+
+LINKLIBS= \
+ ..\..\oleprx32\uuid\daytona\obj\*\uuid.lib \
+ ..\..\common\daytona\obj\*\servers.lib \
+ $(OLEDIR)\common\daytona\obj\*\common.lib \
+ $(BASEDIR)\public\sdk\lib\*\uuid.lib \
+ $(BASEDIR)\public\sdk\lib\*\ole32.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
+
+!IF $(386)
+NTTARGETFILE0=$(DLLDEF:*=i386)
+!ENDIF
+
+!IF $(MIPS)
+NTTARGETFILE0=$(DLLDEF:*=mips)
+!ENDIF
+
+!IF $(ALPHA)
+NTTARGETFILE0=$(DLLDEF:*=alpha)
+!ENDIF
diff --git a/private/oleutest/balls/myproxy/daytona/makefile b/private/oleutest/balls/myproxy/daytona/makefile
new file mode 100644
index 000000000..1d3728d41
--- /dev/null
+++ b/private/oleutest/balls/myproxy/daytona/makefile
@@ -0,0 +1,10 @@
+############################################################################
+#
+# Copyright (C) 1992, Microsoft Corporation.
+#
+# All rights reserved.
+#
+############################################################################
+
+!include $(NTMAKEENV)\makefile.def
+
diff --git a/private/oleutest/balls/myproxy/daytona/makefile.inc b/private/oleutest/balls/myproxy/daytona/makefile.inc
new file mode 100644
index 000000000..d79611892
--- /dev/null
+++ b/private/oleutest/balls/myproxy/daytona/makefile.inc
@@ -0,0 +1 @@
+obj\i386\qisrv.def: qisrv.src
diff --git a/private/oleutest/balls/myproxy/daytona/myproxy.src b/private/oleutest/balls/myproxy/daytona/myproxy.src
new file mode 100644
index 000000000..9596e5b89
--- /dev/null
+++ b/private/oleutest/balls/myproxy/daytona/myproxy.src
@@ -0,0 +1,48 @@
+#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 qisrv
+
+DESCRIPTION 'Microsoft (R) OLE 2.0 Proxy DLL 1.00'
+
+EXPORTS
+#if defined(i386)
+
+ _DllGetClassObject@12 @1
+ DllGetClassObject=_DllGetClassObject@12
+ _DllCanUnloadNow@0 @2
+ DllCanUnloadNow=_DllCanUnloadNow@0
+
+#elif defined(_MIPS_)
+
+ DllGetClassObject @1
+ DllCanUnloadNow @2
+
+#endif // i386 - MIPS
+
+#endif // FLAT
diff --git a/private/oleutest/balls/myproxy/daytona/sources b/private/oleutest/balls/myproxy/daytona/sources
new file mode 100644
index 000000000..d946b8aee
--- /dev/null
+++ b/private/oleutest/balls/myproxy/daytona/sources
@@ -0,0 +1,56 @@
+!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.
+
+!ENDIF
+
+#
+# The following includes a global include file defined at the
+# base of the project for all components
+#
+
+
+!include ..\daytona.inc
+
+#
+# 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= myproxy
+
+#
+# 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= DYNLINK
+
+DLLDEF= obj\*\myproxy.def
+
+INCLUDES= $(INCLUDES)
+C_DEFINES= $(C_DEFINES)
+
+
+
+SOURCES= \
+ ..\myproxy.cxx
diff --git a/private/oleutest/balls/myproxy/dirs b/private/oleutest/balls/myproxy/dirs
new file mode 100644
index 000000000..4d3d49b1f
--- /dev/null
+++ b/private/oleutest/balls/myproxy/dirs
@@ -0,0 +1,38 @@
+!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= \
+ cairo \
+ chicago \
+ daytona
diff --git a/private/oleutest/balls/myproxy/myproxy.cxx b/private/oleutest/balls/myproxy/myproxy.cxx
new file mode 100644
index 000000000..7a480f635
--- /dev/null
+++ b/private/oleutest/balls/myproxy/myproxy.cxx
@@ -0,0 +1,1092 @@
+//---------------------------------------------------------------------------
+//
+// File: myproxy.cxx
+//
+// Purpose: Sample implementation of wrappers to allow simultaneous
+// hand-crafted and MILD-generated stubs.
+//
+// History: 12-11-95 Rickhi Created
+//
+//---------------------------------------------------------------------------
+#include <ole2.h>
+#include <stddef.h> // offsetof
+#include <icube.h> // custom interface ICube, IID_ICube
+
+
+// flag set in rpcFlags field of RPCOLEMESSAGE if the call is from a
+// non-NDR client.
+#define RPCFLG_NON_NDR 0x80000000UL
+
+
+DEFINE_OLEGUID(IID_INonNDRStub, 0x0000013DL, 0, 0);
+DEFINE_OLEGUID(CLSID_MyProxy, 0x0000013EL, 0, 0);
+
+// IID that the proxy querys the channel for to see if the server
+// has an NDR or NON NDR stub.
+const GUID IID_INonNDRStub =
+ {0x0000013d,0x0000,0x0000,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}};
+
+// class id of my custom proxy dll
+const GUID CLSID_MyProxy =
+ {0x0000013e,0x0001,0x0008,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}};
+
+// class id of the MIDL generated proxy dll
+const GUID CLSID_CubeProxy =
+ {0x00000138,0x0001,0x0008,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}};
+
+
+
+#define GETPPARENT(pmemb, struc, membname) (\
+ (struc FAR *)(((char FAR *)(pmemb))-offsetof(struc, membname)))
+
+
+//---------------------------------------------------------------------------
+//
+// Class: CPSFactory
+//
+// Purpose: ProxyStub Class Factory
+//
+// Notes: fill in the CreateProxy and CreateStub methods for
+// other custom interfaces supported by this DLL.
+//
+//---------------------------------------------------------------------------
+class CPSFactory : public IPSFactoryBuffer
+{
+public:
+ // no ctor or dtor needed. DllGetClassObject returns a static
+ // instance of this class.
+
+ STDMETHOD(QueryInterface)(REFIID riid, void **ppv);
+ STDMETHOD_(ULONG, AddRef)(void);
+ STDMETHOD_(ULONG, Release)(void);
+
+ STDMETHOD(CreateProxy)(IUnknown *pUnkOuter, REFIID riid,
+ IRpcProxyBuffer **ppProxy, void **ppv);
+
+ STDMETHOD(CreateStub)(REFIID riid, IUnknown *pUnkObj,
+ IRpcStubBuffer **ppStub);
+};
+
+//---------------------------------------------------------------------------
+//
+// Class: CStubWrapper
+//
+// Purpose: Wrapper object for stubs.
+//
+// Notes: This class can wrap any stub object regardless of
+// the interface the stub is for.
+//
+//---------------------------------------------------------------------------
+class CStubWrapper : public IRpcStubBuffer
+{
+public:
+ CStubWrapper(IUnknown *pUnkObj, REFIID riid);
+
+ STDMETHOD(QueryInterface)(REFIID riid, void **ppv);
+ STDMETHOD_(ULONG, AddRef)(void);
+ STDMETHOD_(ULONG, Release)(void);
+
+ STDMETHOD(Connect)(IUnknown *pUnkObj);
+ STDMETHOD_(void, Disconnect)(void);
+ STDMETHOD(Invoke)(RPCOLEMESSAGE *pMsg, IRpcChannelBuffer *pChnl);
+ STDMETHOD_(IRpcStubBuffer *, IsIIDSupported)(REFIID riid);
+ STDMETHOD_(ULONG, CountRefs)(void);
+ STDMETHOD(DebugServerQueryInterface)(void **ppv);
+ STDMETHOD_(void, DebugServerRelease)(void *pv);
+
+private:
+ ~CStubWrapper(void);
+
+ ULONG _cRefs;
+ IUnknown * _pUnkObj;
+ IRpcStubBuffer *_pHCStub;
+ IRpcStubBuffer *_pMIDLStub;
+ IID _iid;
+};
+
+//---------------------------------------------------------------------------
+//
+// Class: CCubesStub
+//
+// Purpose: Hand-Crafted stub object for interface ICube.
+//
+// Notes: Replace this with your exisitng 32bit hand-crafted stubs.
+//
+//---------------------------------------------------------------------------
+class CCubesStub : public IRpcStubBuffer
+{
+public:
+ CCubesStub(IUnknown *pUnkObj);
+
+ STDMETHOD(QueryInterface)(REFIID riid, void **ppv);
+ STDMETHOD_(ULONG, AddRef)(void);
+ STDMETHOD_(ULONG, Release)(void);
+
+ STDMETHOD(Connect)(IUnknown *pUnkObj);
+ STDMETHOD_(void, Disconnect)(void);
+ STDMETHOD(Invoke)(RPCOLEMESSAGE *pMsg, IRpcChannelBuffer *pChnl);
+ STDMETHOD_(IRpcStubBuffer *, IsIIDSupported)(REFIID riid);
+ STDMETHOD_(ULONG, CountRefs)(void);
+ STDMETHOD(DebugServerQueryInterface)(void **ppv);
+ STDMETHOD_(void, DebugServerRelease)(void *pv);
+
+private:
+ ~CCubesStub(void);
+
+ ULONG _cRefs;
+ IUnknown * _pUnkObj;
+};
+
+//---------------------------------------------------------------------------
+//
+// Class: CInternalUnk
+//
+// Purpose: Internal proxy class that implements IRpcProxyBuffer
+//
+// Notes: This could use some work. Perhaps dont make it an internal
+// class, but derive the other proxy classes from it, allowing
+// common code.
+//
+//---------------------------------------------------------------------------
+#define DECLARE_INTERNAL_PROXY() \
+ class CInternalUnk : public IRpcProxyBuffer \
+ { \
+ public: \
+ STDMETHOD(QueryInterface)(REFIID riid, void **ppvObj); \
+ STDMETHOD_(ULONG,AddRef)(void) ; \
+ STDMETHOD_(ULONG,Release)(void); \
+ STDMETHOD(Connect)(IRpcChannelBuffer *pChnl); \
+ STDMETHOD_(void, Disconnect)(void); \
+ }; \
+ friend CInternalUnk; \
+ CInternalUnk _InternalUnk;
+
+
+//---------------------------------------------------------------------------
+//
+// Class: CProxyWrapper
+//
+// Purpose: Wrapper object for itnerface proxies.
+//
+// Notes: the routines in this class simply delegate to the
+// real proxy or the internal proxy unknown, or to the
+// controlling unknown.
+//
+//---------------------------------------------------------------------------
+class CProxyWrapper : public ICube
+{
+public:
+ CProxyWrapper(IUnknown *pUnkOuter, IRpcProxyBuffer **ppProxy);
+
+ STDMETHOD(QueryInterface)(REFIID riid, void **ppv);
+ STDMETHOD_(ULONG, AddRef)(void);
+ STDMETHOD_(ULONG, Release)(void);
+
+ // interface specific routines below here
+ STDMETHOD(MoveCube)(ULONG xPos, ULONG yPos);
+ STDMETHOD(GetCubePos)(ULONG *pxPos, ULONG *pyPos);
+ STDMETHOD(Contains)(IBalls *pIFDb);
+ STDMETHOD(SimpleCall)(DWORD pidCaller,
+ DWORD tidCaller,
+ GUID lidCaller);
+
+ DECLARE_INTERNAL_PROXY()
+
+private:
+ ~CProxyWrapper(void);
+
+ ULONG _cRefs;
+ IUnknown *_pUnkOuter;
+ IRpcProxyBuffer *_pRealProxy;
+ ICube *_pRealIf;
+};
+
+//---------------------------------------------------------------------------
+//
+// Class: CCubesProxy
+//
+// Purpose: Hand-Crafted proxy object for ICube interface.
+//
+//---------------------------------------------------------------------------
+class CCubesProxy : public ICube
+{
+public:
+ CCubesProxy(IUnknown *pUnkOuter, IRpcProxyBuffer **ppProxy);
+
+ STDMETHOD(QueryInterface)(REFIID riid, void **ppv);
+ STDMETHOD_(ULONG, AddRef)(void);
+ STDMETHOD_(ULONG, Release)(void);
+
+ // interface specific routines below here
+ STDMETHOD(MoveCube)(ULONG xPos, ULONG yPos);
+ STDMETHOD(GetCubePos)(ULONG *pxPos, ULONG *pyPos);
+ STDMETHOD(Contains)(IBalls *pIFDb);
+ STDMETHOD(SimpleCall)(DWORD pidCaller,
+ DWORD tidCaller,
+ GUID lidCaller);
+
+
+ DECLARE_INTERNAL_PROXY()
+
+private:
+ ~CCubesProxy(void);
+
+ ULONG _cRefs;
+ IUnknown *_pUnkOuter;
+ IRpcChannelBuffer *_pChnl;
+};
+
+
+//---------------------------------------------------------------------------
+//
+// Function: DllMain
+//
+// Purpose: Entry point for the Proxy/Stub Dll
+//
+//---------------------------------------------------------------------------
+extern "C" BOOL WINAPI DllMain(HANDLE hDll, DWORD dwReason, void *pvReserved)
+{
+ return TRUE;
+}
+
+//---------------------------------------------------------------------------
+//
+// Function: DllGetClassObject
+//
+// Purpose: Entry point to return proxy/stub class factory
+//
+//---------------------------------------------------------------------------
+
+// static instance of the class factory
+CPSFactory gPSFactory;
+
+STDAPI DllGetClassObject(REFCLSID clsid, REFIID iid, void **ppv)
+{
+ if (IsEqualCLSID(clsid, CLSID_MyProxy))
+ {
+ *ppv = (void *)(IClassFactory *)&gPSFactory;
+ return S_OK;
+ }
+
+ return E_UNEXPECTED;
+}
+
+//---------------------------------------------------------------------------
+//
+// Function: DllCanUnloadNow
+//
+// Purpose: Entry point to determine if DLL is unloadable.
+//
+//---------------------------------------------------------------------------
+STDAPI DllCanUnloadNow(void)
+{
+ return FALSE;
+}
+
+//---------------------------------------------------------------------------
+//
+// Function: GetMIDLPSFactory
+//
+// Purpose: Function for getting the MIDL generated PSFactoryBuffer
+// for the test interface.
+//
+//---------------------------------------------------------------------------
+HRESULT GetMIDLPSFactory(REFIID riid, IPSFactoryBuffer **ppIPSF)
+{
+ *ppIPSF = NULL;
+
+ // load the dll and get the PS class object
+
+ return CoGetClassObject(CLSID_CubeProxy,
+ CLSCTX_INPROC_SERVER, // | CLSCTX_PS_DLL,
+ NULL,
+ IID_IPSFactoryBuffer,
+ (void **)ppIPSF);
+}
+
+//---------------------------------------------------------------------------
+//
+// Function: CreateMIDLProxy
+//
+// Purpose: Function for creating the MIDL generated proxy
+// for the test interface.
+//
+//---------------------------------------------------------------------------
+IUnknown *CreateMIDLProxy(REFIID riid,
+ IUnknown *pUnkOuter,
+ IRpcProxyBuffer **ppProxy)
+{
+ IUnknown *pRealIf = NULL;
+ IPSFactoryBuffer *pPSFactory = NULL;
+
+ HRESULT hr = GetMIDLPSFactory(riid, &pPSFactory);
+ if (SUCCEEDED(hr))
+ {
+ hr = pPSFactory->CreateProxy(pUnkOuter,riid,ppProxy,(void **)&pRealIf);
+ pPSFactory->Release();
+ }
+
+ return pRealIf;
+}
+
+//---------------------------------------------------------------------------
+//
+// Function: CreateMIDLStub
+//
+// Purpose: Function for creating the MIDL generated stub
+// for the test interface.
+//
+//---------------------------------------------------------------------------
+IRpcStubBuffer *CreateMIDLStub(REFIID riid,
+ IUnknown *pUnkOuter)
+{
+ IRpcStubBuffer *pStub = NULL;
+ IPSFactoryBuffer *pPSFactory = NULL;
+
+ HRESULT hr = GetMIDLPSFactory(riid, &pPSFactory);
+ if (SUCCEEDED(hr))
+ {
+ hr = pPSFactory->CreateStub(riid, pUnkOuter, &pStub);
+ pPSFactory->Release();
+ }
+
+ return pStub;
+}
+
+
+//---------------------------------------------------------------------------
+//
+// Implement: CPSFactory
+//
+// Purpose: ProxyStub Class Factory
+//
+// Notes: just fill in the CreateProxy and CreateStub methods for
+// your other custom interfaces.
+//
+//---------------------------------------------------------------------------
+HRESULT CPSFactory::QueryInterface(REFIID riid, void **ppv)
+{
+ if (IsEqualIID(riid, IID_IPSFactoryBuffer) ||
+ IsEqualIID(riid, IID_IUnknown))
+ {
+ *ppv = (IPSFactoryBuffer *)this;
+ // static object, dont need refcnt
+ return S_OK;
+ }
+
+ *ppv = NULL;
+ return E_NOINTERFACE;
+}
+
+ULONG CPSFactory::AddRef(void)
+{
+ // static object, dont need refcnt
+ return 1;
+}
+
+ULONG CPSFactory::Release(void)
+{
+ // static object, dont need refcnt
+ return 1;
+}
+
+HRESULT CPSFactory::CreateProxy(IUnknown *pUnkOuter, REFIID riid,
+ IRpcProxyBuffer **ppProxy, void **ppv)
+{
+ // check for supported interfaces
+ if (IsEqualIID(riid, IID_ICube))
+ {
+ CProxyWrapper *pProxy = new CProxyWrapper(pUnkOuter, ppProxy);
+
+ if (pProxy)
+ {
+ *ppv = (void *)(ICube *) pProxy;
+ ((IUnknown *)(*ppv))->AddRef(); // AddRef the returned interface
+ return S_OK;
+ }
+ }
+
+ *ppProxy = NULL;
+ *ppv = NULL;
+ return E_NOINTERFACE;
+}
+
+HRESULT CPSFactory::CreateStub(REFIID riid, IUnknown *pUnkObj, IRpcStubBuffer **ppStub)
+{
+ // check for supported interfaces
+ if (IsEqualIID(riid, IID_ICube))
+ {
+ CStubWrapper *pStub = new CStubWrapper(pUnkObj, riid);
+
+ if (pStub)
+ {
+ *ppStub = (IRpcStubBuffer *) pStub;
+ return S_OK;
+ }
+ }
+
+ *ppStub = NULL;
+ return E_NOINTERFACE;
+}
+
+
+//---------------------------------------------------------------------------
+//
+// Implement: CStubWrapper
+//
+// Purpose: Wrapper object for stubs.
+//
+// Notes: This same class can wrap any stub object regardless of
+// the interface the stub is for.
+//
+//---------------------------------------------------------------------------
+CStubWrapper::CStubWrapper(IUnknown *pUnkObj, REFIID riid) :
+ _cRefs(1),
+ _pUnkObj(pUnkObj),
+ _pHCStub(NULL),
+ _pMIDLStub(NULL),
+ _iid(riid)
+{
+ _pUnkObj->AddRef();
+}
+
+CStubWrapper::~CStubWrapper(void)
+{
+ Disconnect();
+}
+
+HRESULT CStubWrapper::QueryInterface(REFIID riid, void **ppv)
+{
+ if (IsEqualIID(riid, IID_IRpcStubBuffer) ||
+ IsEqualIID(riid, IID_IUnknown))
+ {
+ *ppv = (IRpcStubBuffer *)this;
+ AddRef();
+ return S_OK;
+ }
+
+ *ppv = NULL;
+ return E_NOINTERFACE;
+}
+
+ULONG CStubWrapper::AddRef(void)
+{
+ InterlockedIncrement((LONG *)&_cRefs);
+ return _cRefs;
+}
+
+ULONG CStubWrapper::Release(void)
+{
+ ULONG cRefs = _cRefs-1;
+ if (InterlockedDecrement((LONG *)&_cRefs) == 0)
+ {
+ delete this;
+ return 0;
+ }
+
+ return cRefs;
+}
+
+HRESULT CStubWrapper::Connect(IUnknown *pUnkObj)
+{
+ if (_pUnkObj)
+ {
+ // already connected, disconnect
+ Disconnect();
+ }
+
+ // get the requested interface and hold it.
+ HRESULT hr = pUnkObj->QueryInterface(_iid, (void **)&_pUnkObj);
+ if (FAILED(hr))
+ {
+ // make sure our ptr is NULL else we might think we're connected
+ _pUnkObj = NULL;
+ }
+
+ return hr;
+}
+
+void CStubWrapper::Disconnect()
+{
+ if (_pHCStub)
+ {
+ _pHCStub->Disconnect();
+ _pHCStub->Release();
+ _pHCStub = NULL;
+ }
+
+ if (_pMIDLStub)
+ {
+ _pMIDLStub->Disconnect();
+ _pMIDLStub->Release();
+ _pMIDLStub = NULL;
+ }
+
+ if (_pUnkObj)
+ {
+ _pUnkObj->Release();
+ _pUnkObj = NULL;
+ }
+}
+
+HRESULT CStubWrapper::Invoke(RPCOLEMESSAGE *pMsg, IRpcChannelBuffer *pChnl)
+{
+ if (pMsg->rpcFlags & RPCFLG_NON_NDR)
+ {
+ // call is not NDR format, so use the hand-crafted stub.
+ // create the stub if it does not exist yet.
+
+ if (_pHCStub == NULL)
+ {
+ if ((_pHCStub = new CCubesStub(_pUnkObj)) == NULL)
+ return E_OUTOFMEMORY;
+ }
+
+ return _pHCStub->Invoke(pMsg, pChnl);
+ }
+
+ // call is NDR format, so use the MIDL generated stub.
+ // create the stub if it does not exist yet.
+
+ if (_pMIDLStub == NULL)
+ {
+ _pMIDLStub = CreateMIDLStub(IID_ICube, _pUnkObj);
+ if (_pMIDLStub == NULL)
+ return E_OUTOFMEMORY;
+ }
+
+ return _pMIDLStub->Invoke(pMsg, pChnl);
+}
+
+IRpcStubBuffer *CStubWrapper::IsIIDSupported(REFIID riid)
+{
+ if (IsEqualIID(riid, _iid))
+ {
+ AddRef();
+ return (IRpcStubBuffer *)this;
+ }
+
+ return NULL;
+}
+
+ULONG CStubWrapper::CountRefs()
+{
+ ULONG cRefs = (_pUnkObj) ? 1 : 0;
+
+ if (_pHCStub)
+ cRefs += _pHCStub->CountRefs();
+
+ if (_pMIDLStub)
+ cRefs += _pMIDLStub->CountRefs();
+
+ return cRefs;
+}
+
+HRESULT CStubWrapper::DebugServerQueryInterface(void **ppv)
+{
+ *ppv = (void *)_pUnkObj;
+ return S_OK;
+}
+
+void CStubWrapper::DebugServerRelease(void *pv)
+{
+ return;
+}
+
+
+//---------------------------------------------------------------------------
+//
+// Implement: CProxyWrapper
+//
+// Purpose: Wrapper object for itnerface proxies.
+//
+// Notes: the top several routines are the same for all proxies
+// but you must change the interface specific routines for
+// each new interface.
+//
+//---------------------------------------------------------------------------
+CProxyWrapper::CProxyWrapper(IUnknown *pUnkOuter, IRpcProxyBuffer **ppProxy) :
+ _cRefs(1),
+ _pUnkOuter(pUnkOuter), // don't AddRef
+ _pRealProxy(NULL)
+{
+ *ppProxy = (IRpcProxyBuffer *)&_InternalUnk;
+}
+
+CProxyWrapper::~CProxyWrapper(void)
+{
+ if (_pRealProxy)
+ {
+ _InternalUnk.Disconnect();
+ }
+}
+
+HRESULT CProxyWrapper::CInternalUnk::QueryInterface(REFIID riid, void **ppv)
+{
+ CProxyWrapper *pProxy = GETPPARENT(this, CProxyWrapper, _InternalUnk);
+
+ if (IsEqualIID(riid, IID_IRpcProxyBuffer) ||
+ IsEqualIID(riid, IID_IUnknown))
+ {
+ pProxy->AddRef();
+ *ppv = (IRpcProxyBuffer *)this;
+ return S_OK;
+ }
+ else if (IsEqualIID(riid, IID_ICube))
+ {
+ *ppv = (ICube *)pProxy;
+ AddRef();
+ return S_OK;
+ }
+
+ *ppv = NULL;
+ return E_NOINTERFACE;
+}
+
+ULONG CProxyWrapper::CInternalUnk::AddRef(void)
+{
+ CProxyWrapper *pProxy = GETPPARENT(this, CProxyWrapper, _InternalUnk);
+
+ InterlockedIncrement((LONG *)&pProxy->_cRefs);
+ return pProxy->_cRefs;
+}
+
+ULONG CProxyWrapper::CInternalUnk::Release(void)
+{
+ CProxyWrapper *pProxy = GETPPARENT(this, CProxyWrapper, _InternalUnk);
+
+ ULONG cRefs = pProxy->_cRefs-1;
+ if (InterlockedDecrement((LONG *)&pProxy->_cRefs) == 0)
+ {
+ delete this;
+ return 0;
+ }
+
+ return cRefs;
+}
+
+HRESULT CProxyWrapper::CInternalUnk::Connect(IRpcChannelBuffer *pChnl)
+{
+ CProxyWrapper *pProxy = GETPPARENT(this, CProxyWrapper, _InternalUnk);
+
+ void *pv;
+ HRESULT hr = pChnl->QueryInterface(IID_INonNDRStub, &pv);
+ if (SUCCEEDED(hr))
+ {
+ ((IUnknown *)pv)->Release();
+
+ // create the hand-crafted proxy
+ pProxy->_pRealIf = new CCubesProxy(pProxy->_pUnkOuter,
+ &pProxy->_pRealProxy);
+ }
+ else
+ {
+ // create the MIDL generated proxy
+ pProxy->_pRealIf = (ICube *) CreateMIDLProxy(IID_ICube,
+ pProxy->_pUnkOuter,
+ &pProxy->_pRealProxy);
+
+ }
+
+ if (pProxy->_pRealIf == NULL)
+ return E_OUTOFMEMORY;
+
+ // since the proxy AddRef'd the punkOuter, we need to release it.
+ pProxy->_pUnkOuter->Release();
+
+ // connect the proxy
+ hr = pProxy->_pRealProxy->Connect(pChnl);
+ if (FAILED(hr))
+ {
+ pProxy->_pRealProxy->Release();
+ pProxy->_pRealProxy = NULL;
+ }
+
+ return hr;
+}
+
+void CProxyWrapper::CInternalUnk::Disconnect(void)
+{
+ CProxyWrapper *pProxy = GETPPARENT(this, CProxyWrapper, _InternalUnk);
+
+ if (pProxy->_pRealProxy)
+ {
+ pProxy->_pRealProxy->Disconnect();
+ pProxy->_pRealProxy->Release();
+ pProxy->_pRealProxy = NULL;
+ }
+}
+
+//---------------------------------------------------------------------------
+//
+// ICube specific proxy wrapper code below here.
+//
+//---------------------------------------------------------------------------
+HRESULT CProxyWrapper::QueryInterface(REFIID riid, void **ppv)
+{
+ return _pUnkOuter->QueryInterface(riid, ppv);
+}
+
+ULONG CProxyWrapper::AddRef(void)
+{
+ return _pUnkOuter->AddRef();
+}
+
+ULONG CProxyWrapper::Release(void)
+{
+ return _pUnkOuter->Release();
+}
+
+HRESULT CProxyWrapper::MoveCube(ULONG xPos, ULONG yPos)
+{
+ if (_pRealProxy)
+ {
+ return _pRealIf->MoveCube(xPos, yPos);
+ }
+
+ return CO_E_OBJNOTCONNECTED;
+}
+
+HRESULT CProxyWrapper::GetCubePos(ULONG *pxPos, ULONG *pyPos)
+{
+ if (_pRealProxy)
+ {
+ return _pRealIf->GetCubePos(pxPos, pyPos);
+ }
+
+ *pxPos = 0;
+ *pyPos = 0;
+ return CO_E_OBJNOTCONNECTED;
+}
+
+HRESULT CProxyWrapper::Contains(IBalls *pIFDb)
+{
+ if (_pRealProxy)
+ {
+ return _pRealIf->Contains(pIFDb);
+ }
+
+ return CO_E_OBJNOTCONNECTED;
+}
+
+
+HRESULT CProxyWrapper::SimpleCall(
+ DWORD pidCaller,
+ DWORD tidCaller,
+ GUID lidCaller)
+{
+ return CO_E_OBJNOTCONNECTED;
+}
+
+//---------------------------------------------------------------------------
+//
+// Implement: CCubesProxy
+//
+// Purpose: Hand-Crafted proxy object for interface ICube.
+//
+// Notes: Replace this with your exisitng 32bit hand-crafted proxies.
+//
+//---------------------------------------------------------------------------
+CCubesProxy::CCubesProxy(IUnknown *pUnkOuter, IRpcProxyBuffer **ppProxy) :
+ _pUnkOuter(pUnkOuter),
+ _pChnl(NULL)
+{
+ _pUnkOuter->AddRef();
+ *ppProxy = (IRpcProxyBuffer *)&_InternalUnk;
+}
+
+CCubesProxy::~CCubesProxy(void)
+{
+ _InternalUnk.Disconnect();
+}
+
+HRESULT CCubesProxy::CInternalUnk::QueryInterface(REFIID riid, void **ppv)
+{
+ if (IsEqualIID(riid, IID_IRpcProxyBuffer) ||
+ IsEqualIID(riid, IID_IUnknown))
+ {
+ CCubesProxy *pProxy = GETPPARENT(this, CCubesProxy, _InternalUnk);
+ pProxy->AddRef();
+
+ *ppv = (IRpcProxyBuffer *)this;
+ return S_OK;
+ }
+
+ *ppv = NULL;
+ return E_NOINTERFACE;
+}
+
+ULONG CCubesProxy::CInternalUnk::AddRef(void)
+{
+ CCubesProxy *pProxy = GETPPARENT(this, CCubesProxy, _InternalUnk);
+
+ InterlockedIncrement((LONG *)&pProxy->_cRefs);
+ return pProxy->_cRefs;
+}
+
+ULONG CCubesProxy::CInternalUnk::Release(void)
+{
+ CCubesProxy *pProxy = GETPPARENT(this, CCubesProxy, _InternalUnk);
+
+ ULONG cRefs = pProxy->_cRefs-1;
+ if (InterlockedDecrement((LONG *)&pProxy->_cRefs) == 0)
+ {
+ delete this;
+ return 0;
+ }
+
+ return cRefs;
+}
+
+HRESULT CCubesProxy::CInternalUnk::Connect(IRpcChannelBuffer *pChnl)
+{
+ Disconnect(); // make sure we are disconnected
+
+ CCubesProxy *pProxy = GETPPARENT(this, CCubesProxy, _InternalUnk);
+
+ pProxy->_pChnl = pChnl; // keep the channel ptr
+ pChnl->AddRef();
+ return S_OK;
+}
+
+void CCubesProxy::CInternalUnk::Disconnect(void)
+{
+ CCubesProxy *pProxy = GETPPARENT(this, CCubesProxy, _InternalUnk);
+
+ if (pProxy->_pChnl)
+ {
+ pProxy->_pChnl->Release();
+ pProxy->_pChnl = NULL;
+ }
+}
+
+//---------------------------------------------------------------------------
+//
+// ICubes Proxy Implementation
+//
+//---------------------------------------------------------------------------
+HRESULT CCubesProxy::QueryInterface(REFIID riid, void **ppv)
+{
+ return _pUnkOuter->QueryInterface(riid, ppv);
+}
+
+ULONG CCubesProxy::AddRef(void)
+{
+ return _pUnkOuter->AddRef();
+}
+
+ULONG CCubesProxy::Release(void)
+{
+ return _pUnkOuter->Release();
+}
+
+HRESULT CCubesProxy::MoveCube(ULONG xPos, ULONG yPos)
+{
+ // set up the message and get the buffer
+ RPCOLEMESSAGE msg;
+ memset(&msg, 0, sizeof(msg));
+ msg.iMethod = 3;
+ msg.dataRepresentation = NDR_LOCAL_DATA_REPRESENTATION;
+ msg.cbBuffer = 16;
+
+ HRESULT hrFromServer;
+ HRESULT hr = _pChnl->GetBuffer(&msg, IID_ICube);
+
+ if (SUCCEEDED(hr))
+ {
+ // Marshal the parameters. The string "myproxy" followed by
+ // xPos and yPos values.
+
+ char *pBuf = (char *)msg.Buffer;
+ strcpy((char *)pBuf, "myproxy");
+
+ pBuf += 8;
+ DWORD *dwp = (DWORD *)pBuf;
+ *dwp = xPos;
+ pBuf += 4;
+ dwp = (DWORD *)pBuf;
+ *dwp = yPos;
+
+ // Send the message and get the reply
+ ULONG ulStatus = 0;
+ hr = _pChnl->SendReceive(&msg, &ulStatus);
+
+ if (SUCCEEDED(hr))
+ {
+ // unmarshal the results
+ hrFromServer = (DWORD)(msg.Buffer);
+ }
+
+ // FreeBuffer
+ hr = _pChnl->FreeBuffer(&msg);
+ }
+
+ return hr;
+}
+
+HRESULT CCubesProxy::GetCubePos(ULONG *pxPos, ULONG *pyPos)
+{
+ *pxPos = 0;
+ *pyPos = 0;
+ return E_NOTIMPL;
+}
+
+HRESULT CCubesProxy::Contains(IBalls *pIFDb)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT CCubesProxy::SimpleCall(
+ DWORD pidCaller,
+ DWORD tidCaller,
+ GUID lidCaller)
+{
+ return E_NOTIMPL;
+}
+
+
+//---------------------------------------------------------------------------
+//
+// Implement: CCubesStub
+//
+// Purpose: Hand-Crafted stub object for interface ICube.
+//
+// Notes: Replace this with your exisitng 32bit hand-crafted stubs.
+//
+//---------------------------------------------------------------------------
+
+CCubesStub::CCubesStub(IUnknown *pUnkObj) :
+ _cRefs(1),
+ _pUnkObj(pUnkObj)
+{
+ _pUnkObj->AddRef();
+}
+
+CCubesStub::~CCubesStub(void)
+{
+ Disconnect();
+}
+
+HRESULT CCubesStub::QueryInterface(REFIID riid, void **ppv)
+{
+ if (IsEqualIID(riid, IID_IRpcStubBuffer) ||
+ IsEqualIID(riid, IID_IUnknown))
+ {
+ *ppv = (IRpcStubBuffer *)this;
+ }
+ else
+ {
+ *ppv = NULL;
+ return E_NOINTERFACE;
+ }
+
+ AddRef();
+ return S_OK;
+}
+
+ULONG CCubesStub::AddRef(void)
+{
+ InterlockedIncrement((LONG *)&_cRefs);
+ return _cRefs;
+}
+
+ULONG CCubesStub::Release(void)
+{
+ ULONG cRefs = _cRefs-1;
+ if (InterlockedDecrement((LONG *)&_cRefs) == 0)
+ {
+ delete this;
+ return 0;
+ }
+
+ return cRefs;
+}
+
+HRESULT CCubesStub::Connect(IUnknown *pUnkObj)
+{
+ if (_pUnkObj)
+ {
+ // already connected, disconnect
+ Disconnect();
+ }
+
+ // get the requested interface and hold it.
+ HRESULT hr = pUnkObj->QueryInterface(IID_ICube, (void **)&_pUnkObj);
+ if (FAILED(hr))
+ {
+ _pUnkObj = NULL;
+ }
+
+ return hr;
+}
+
+void CCubesStub::Disconnect()
+{
+ if (_pUnkObj)
+ {
+ _pUnkObj->Release();
+ _pUnkObj = NULL;
+ }
+}
+
+HRESULT CCubesStub::Invoke(RPCOLEMESSAGE *pMsg, IRpcChannelBuffer *pChnl)
+{
+ // Check the method number.
+ if (pMsg->iMethod !=3 || pMsg->cbBuffer != 16)
+ return E_INVALIDARG;
+
+ // unmarshal the parameters
+ char *pBuf = (char *)pMsg->Buffer;
+ pBuf += 8;
+ DWORD *dwp = (DWORD *)pBuf;
+ ULONG xPos = *dwp;
+
+ pBuf += 4;
+ dwp = (DWORD *)pBuf;
+ ULONG yPos = *dwp;
+
+ // call the real object
+ HRESULT hrFromServer = ((ICube *)_pUnkObj)->MoveCube(xPos, yPos);
+
+ // get a new buffer
+ pMsg->cbBuffer = 4;
+ HRESULT hr = pChnl->GetBuffer(pMsg, IID_ICube);
+
+ if (SUCCEEDED(hr))
+ {
+ // marshal the return values
+ pBuf = (char *)pMsg->Buffer;
+ dwp = (DWORD *)pBuf;
+ *dwp = hrFromServer;
+ }
+
+ return hr;
+}
+
+IRpcStubBuffer *CCubesStub::IsIIDSupported(REFIID riid)
+{
+ if (IsEqualIID(riid, IID_ICube))
+ {
+ AddRef();
+ return (IRpcStubBuffer *)this;
+ }
+
+ return NULL;
+}
+
+ULONG CCubesStub::CountRefs()
+{
+ // only keep one reference
+ return 1;
+}
+
+HRESULT CCubesStub::DebugServerQueryInterface(void **ppv)
+{
+ *ppv = (void *)_pUnkObj;
+ return S_OK;
+}
+
+void CCubesStub::DebugServerRelease(void *pv)
+{
+ return;
+}
diff --git a/private/oleutest/balls/myproxy/myproxy.def b/private/oleutest/balls/myproxy/myproxy.def
new file mode 100644
index 000000000..53a8bd51f
--- /dev/null
+++ b/private/oleutest/balls/myproxy/myproxy.def
@@ -0,0 +1,38 @@
+#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 myproxy
+
+DESCRIPTION 'Microsoft (R) OLE 2.0 Proxy DLL 1.00'
+
+EXPORTS
+
+ DllGetClassObject
+ DllCanUnloadNow
+
+#endif // FLAT
diff --git a/private/oleutest/balls/oleprx32/dirs b/private/oleutest/balls/oleprx32/dirs
new file mode 100644
index 000000000..e32223799
--- /dev/null
+++ b/private/oleutest/balls/oleprx32/dirs
@@ -0,0 +1,21 @@
+!if 0
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: dirs
+//
+// Contents: dirs files for NT types project.
+//
+//
+// Functions:
+//
+// History: 12-20-93 terryru Created
+//
+//----------------------------------------------------------------------------
+
+!endif
+
+DIRS= uuid proxy
+
diff --git a/private/oleutest/balls/oleprx32/proxy/daytona/makefile b/private/oleutest/balls/oleprx32/proxy/daytona/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/oleutest/balls/oleprx32/proxy/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/balls/oleprx32/proxy/daytona/sources b/private/oleutest/balls/oleprx32/proxy/daytona/sources
new file mode 100644
index 000000000..463f81828
--- /dev/null
+++ b/private/oleutest/balls/oleprx32/proxy/daytona/sources
@@ -0,0 +1,59 @@
+
+NO_CAIRO_LIBS=1
+
+MAJORCOMP=iballs
+MINORCOMP=proxy
+TARGETNAME=iballs
+
+DLLDEF=obj\*\iballs.def
+
+#
+# Add this to the coffbase.txt file
+#
+DLLBASE=0x1b500000
+
+#
+# We don't want the .lib file in sdk\lib. Binplace.exe will put the DLL in
+# the release tree.
+#
+TARGETPATH=obj
+TARGETTYPE=DYNLINK
+
+TARGETLIBS= \
+ $(BASEDIR)\public\sdk\lib\*\gdi32p.lib \
+ $(BASEDIR)\public\sdk\lib\*\ntdll.lib \
+ $(BASEDIR)\public\sdk\lib\*\ole32.lib \
+ $(BASEDIR)\public\sdk\lib\*\kernel32.lib \
+ $(BASEDIR)\public\sdk\lib\*\RpcRt4.lib
+
+
+LINKLIBS= \
+ ..\..\uuid\daytona\obj\*\uuid.lib \
+ $(BASEDIR)\public\sdk\lib\*\uuid.lib
+
+INCLUDES=..\..\..\..\ole32\ih
+INCLUDES=$(INCLUDES);$(BASEDIR)\private\cinc
+
+CONDITIONAL_INCLUDES=
+
+
+SYNCHRONIZE_BLOCK=1
+SYNCHRONIZE_DRAIN=1
+
+!include ..\..\..\daytona.inc
+
+C_DEFINES = $(C_DEFINES)
+
+LINKER_FLAGS = /MERGE:.text=.orpc
+
+# All the files listed below ending in _p.c are generated by MIDL
+
+SOURCES= \
+ ..\transmit.cxx \
+ ..\dlldata.c \
+ ..\iballs_p.c \
+ ..\icube_p.c \
+ ..\ibtest_p.c \
+ ..\iloop_p.c \
+ ..\rpctst_p.c
+
diff --git a/private/oleutest/balls/oleprx32/proxy/dirs b/private/oleutest/balls/oleprx32/proxy/dirs
new file mode 100644
index 000000000..8f1bf9100
--- /dev/null
+++ b/private/oleutest/balls/oleprx32/proxy/dirs
@@ -0,0 +1,24 @@
+!if 0
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: dirs
+//
+// Contents: dirs files for NT types project.
+//
+//
+// Functions:
+//
+// History: 12-20-93 terryru Created
+//
+//----------------------------------------------------------------------------
+
+!endif
+
+DIRS=
+OPTIONAL_DIRS= \
+ daytona \
+ \
+
diff --git a/private/oleutest/balls/oleprx32/proxy/iballs.def b/private/oleutest/balls/oleprx32/proxy/iballs.def
new file mode 100644
index 000000000..ccd27694d
--- /dev/null
+++ b/private/oleutest/balls/oleprx32/proxy/iballs.def
@@ -0,0 +1,38 @@
+#if 0
+
+ Microsoft Windows
+ Copyright (C) Microsoft Corporation, 1992 - 1994.
+ 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 IBALLS
+
+DESCRIPTION 'Microsoft (R) OLE 2.0 Proxy/Stub DLL 1.00'
+
+EXPORTS
+
+ DllGetClassObject PRIVATE
+ DllCanUnloadNow PRIVATE
+#if 0
+ IPersist_GetClassID_Proxy
+ IPersist_GetClassID_Stub
+#endif
diff --git a/private/oleutest/balls/oleprx32/proxy/stdrpc.hxx b/private/oleutest/balls/oleprx32/proxy/stdrpc.hxx
new file mode 100644
index 000000000..83524a570
--- /dev/null
+++ b/private/oleutest/balls/oleprx32/proxy/stdrpc.hxx
@@ -0,0 +1,66 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: stdrpc.hxx
+//
+// Contents: Private header file for building interface proxies and stubs.
+//
+// Classes: CStreamOnMessage
+//
+// Functions:
+//
+// History: 4-Jul-93 ShannonC Created
+// 3-Aug-93 ShannonC Changes for NT511 and IDispatch support.
+// 10-Oct-93 ShannonC Changed to new IRpcChannelBuffer interface.
+// 22-Sep-94 MikeSe Moved from CINC and simplified.
+//
+//--------------------------------------------------------------------------
+#ifndef __STDRPC_HXX__
+#define __STDRPC_HXX__
+
+#define _OLE2ANAC_H_
+#include <windows.h>
+
+class CStreamOnMessage : public IStream
+{
+
+ public:
+ virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, LPVOID FAR* ppvObj);
+ virtual ULONG STDMETHODCALLTYPE AddRef();
+ virtual ULONG STDMETHODCALLTYPE Release();
+ virtual HRESULT STDMETHODCALLTYPE Read(VOID HUGEP *pv, ULONG cb, ULONG *pcbRead);
+ virtual HRESULT STDMETHODCALLTYPE Write(VOID const HUGEP *pv,
+ ULONG cb,
+ ULONG *pcbWritten) ;
+ virtual HRESULT STDMETHODCALLTYPE Seek(LARGE_INTEGER dlibMove,
+ DWORD dwOrigin,
+ ULARGE_INTEGER *plibNewPosition) ;
+ virtual HRESULT STDMETHODCALLTYPE SetSize(ULARGE_INTEGER libNewSize) ;
+ virtual HRESULT STDMETHODCALLTYPE CopyTo(IStream *pstm,
+ ULARGE_INTEGER cb,
+ ULARGE_INTEGER *pcbRead,
+ ULARGE_INTEGER *pcbWritten) ;
+ virtual HRESULT STDMETHODCALLTYPE Commit(DWORD grfCommitFlags) ;
+ virtual HRESULT STDMETHODCALLTYPE Revert();
+ virtual HRESULT STDMETHODCALLTYPE LockRegion(ULARGE_INTEGER libOffset,
+ ULARGE_INTEGER cb,
+ DWORD dwLockType) ;
+ virtual HRESULT STDMETHODCALLTYPE UnlockRegion(ULARGE_INTEGER libOffset,
+ ULARGE_INTEGER cb,
+ DWORD dwLockType) ;
+ virtual HRESULT STDMETHODCALLTYPE Stat(STATSTG *pstatstg, DWORD grfStatFlag) ;
+ virtual HRESULT STDMETHODCALLTYPE Clone(IStream * *ppstm) ;
+
+ CStreamOnMessage(unsigned char **ppMessageBuffer);
+ CStreamOnMessage(unsigned char **ppMessageBuffer, unsigned long cbMax);
+
+ unsigned char *pStartOfStream;
+ unsigned char **ppBuffer;
+ unsigned long cbMaxStreamLength;
+ ULONG ref_count;
+};
+
+#endif //__STDRPC_HXX__
+
diff --git a/private/oleutest/balls/oleprx32/proxy/transmit.cxx b/private/oleutest/balls/oleprx32/proxy/transmit.cxx
new file mode 100644
index 000000000..c776a13ff
--- /dev/null
+++ b/private/oleutest/balls/oleprx32/proxy/transmit.cxx
@@ -0,0 +1,3295 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: transmit.cxx
+//
+// Contents: Support for Windows/OLE data types for oleprx32.dll.
+// Used to be transmit_as routines, now user_marshal routines.
+//
+// Functions: HGLOBAL_UserSize
+// HGLOBAL_UserMarshal
+// HGLOBAL_UserUnmarshal
+// HGLOBAL_UserFree
+// HMETAFILEPICT_UserSize
+// HMETAFILEPICT_UserMarshal
+// HMETAFILEPICT_UserUnmarshal
+// HMETAFILEPICT_UserFree
+// HENHMETAFILE_UserSize
+// HENHMETAFILE_UserMarshal
+// HENHMETAFILE_UserUnmarshal
+// HENHMETAFILE_UserFree
+// HBITMAP_UserSize
+// HBITMAP_UserMarshal
+// HBITMAP_UserUnmarshal
+// HBITMAP_UserFree
+// HBRUSH_UserSize
+// HBRUSH_UserMarshal
+// HBRUSH_UserUnmarshal
+// HBRUSH_UserFree
+// STGMEDIUM_UserSize
+// STGMEDIUM_UserMarshal
+// STGMEDIUM_UserUnmarshal
+// STGMEDIUM_UserFree
+// HACCEL_UserSize
+// HACCEL_UserMarshal
+// HACCEL_UserUnmarshal
+// HACCEL_UserFree
+// HWND_UserSize
+// HWND_UserMarshal
+// HWND_UserUnmarshal
+// HWND_UserFree
+// HMENU_UserSize
+// HMENU_UserMarshal
+// HMENU_UserUnmarshal
+// HMENU_UserFree
+//
+// History: 24-Aug-93 ShannonC Created
+// 24-Nov-93 ShannonC Added HGLOBAL
+// 14-May-94 DavePl Added HENHMETAFILE
+// 18-May-94 ShannonC Added HACCEL, UINT, WPARAM
+// 19-May-94 DavePl Added HENHMETAFILE to STGMEDIUM code
+// May-95 Ryszardk Wrote all the _User* routines
+//
+//--------------------------------------------------------------------------
+#include "stdrpc.hxx"
+#pragma hdrstop
+
+#include <oleauto.h>
+#include <objbase.h>
+#include "transmit.h"
+#include <rpcwdt.h>
+
+
+WINOLEAPI_(void) ReleaseStgMedium(LPSTGMEDIUM pStgMed);
+
+#pragma code_seg(".orpc")
+
+EXTERN_C const CLSID CLSID_MyPSFactoryBuffer = {0x6f11fe5c,0x2fc5,0x101b,{0x9e,0x45,0x00,0x00,0x0b,0x65,0xc7,0xef}};
+
+
+
+//+-------------------------------------------------------------------------
+//
+// class: CPunkForRelease
+//
+// purpose: special IUnknown for remoted STGMEDIUMs
+//
+// history: 02-Mar-94 Rickhi Created
+//
+// notes: This class is used to do the cleanup correctly when certain
+// types of storages are passed between processes or machines
+// in Nt and Chicago.
+//
+// On NT, GLOBAL, GDI, and BITMAP handles cannot be passed between
+// processes, so we actually copy the whole data and create a
+// new handle in the receiving process. However, STGMEDIUMs have
+// this weird behaviour where if PunkForRelease is non-NULL then
+// the sender is responsible for cleanup, not the receiver. Since
+// we create a new handle in the receiver, we would leak handles
+// if we didnt do some special processing. So, we do the
+// following...
+//
+// During STGMEDIUM_UserUnmarshal, if there is a pUnkForRelease
+// replace it with a CPunkForRelease. When Release is called
+// on the CPunkForRelease, do the necessary cleanup work,
+// then call the real PunkForRelease.
+//
+//+-------------------------------------------------------------------------
+
+class CPunkForRelease : public IUnknown
+{
+public:
+ CPunkForRelease( STGMEDIUM *pStgMed, ulong fTopLayerOnly);
+
+ // IUnknown Methods
+ STDMETHOD(QueryInterface)(REFIID riid, void **ppunk);
+ STDMETHOD_(ULONG, AddRef)(void);
+ STDMETHOD_(ULONG, Release)(void);
+
+private:
+ ~CPunkForRelease(void);
+
+ ULONG _cRefs; // reference count
+ ULONG _fTopLayerMFP:1; // optimisation flag for Chicago
+ STGMEDIUM _stgmed; // storage medium
+ IUnknown * _pUnkForRelease; // real pUnkForRelease
+};
+
+
+inline CPunkForRelease::CPunkForRelease(
+ STGMEDIUM * pStgMed,
+ ulong fTopLayerMFPict
+ ) :
+ _cRefs(1),
+ _fTopLayerMFP( fTopLayerMFPict),
+ _stgmed(*pStgMed)
+{
+ // NOTE: we assume the caller has verified pStgMed is not NULL,
+ // and the pUnkForRelease is non-null, otherwise there is no
+ // point in constructing this object. The tymed must also be
+ // one of the special ones.
+
+ UserNdrAssert(pStgMed);
+ UserNdrAssert(pStgMed->tymed == TYMED_HGLOBAL ||
+ pStgMed->tymed == TYMED_GDI ||
+ pStgMed->tymed == TYMED_MFPICT ||
+ pStgMed->tymed == TYMED_ENHMF);
+
+ _pUnkForRelease = pStgMed->pUnkForRelease;
+}
+
+
+inline CPunkForRelease::~CPunkForRelease()
+{
+ // since we really have our own copies of these handles' data, just
+ // pretend like the callee is responsible for the release, and
+ // recurse into ReleaseStgMedium to do the cleanup.
+
+ _stgmed.pUnkForRelease = NULL;
+
+ // There is this weird optimized case of Chicago MFPICT when we have two
+ // layers with a HENHMETAFILE handle inside. Top layer is an HGLOBAL.
+
+ if ( _fTopLayerMFP )
+ GlobalFree( _stgmed.hGlobal );
+ else
+ ReleaseStgMedium( &_stgmed );
+
+ // release the callers punk
+ _pUnkForRelease->Release();
+}
+
+STDMETHODIMP_(ULONG) CPunkForRelease::AddRef(void)
+{
+ InterlockedIncrement((LONG *)&_cRefs);
+ return _cRefs;
+}
+
+STDMETHODIMP_(ULONG) CPunkForRelease::Release(void)
+{
+ long Ref = _cRefs - 1;
+
+ UserNdrAssert( _cRefs );
+
+ if (InterlockedDecrement((LONG *)&_cRefs) == 0)
+ {
+ // null out the vtable.
+ long * p = (long *)this;
+ *p = 0;
+
+ delete this;
+ return 0;
+ }
+ else
+ return Ref;
+}
+
+STDMETHODIMP CPunkForRelease::QueryInterface(REFIID riid, void **ppv)
+{
+ if (IsEqualIID(riid, IID_IUnknown))
+ {
+ *ppv = (void *)(IUnknown *) this;
+ AddRef();
+ return S_OK;
+ }
+ else
+ {
+ *ppv = NULL;
+ return E_NOINTERFACE;
+ }
+}
+
+
+// These methods are needed as the object is used for interface marshaling.
+
+/***************************************************************************/
+STDMETHODIMP_(ULONG) CStreamOnMessage::AddRef( THIS )
+{
+ return ref_count += 1;
+}
+
+/***************************************************************************/
+STDMETHODIMP CStreamOnMessage::Clone(THIS_ IStream * *ppstm)
+{
+ return ResultFromScode(E_NOTIMPL);
+}
+
+/***************************************************************************/
+STDMETHODIMP CStreamOnMessage::Commit(THIS_ DWORD grfCommitFlags)
+{
+ return ResultFromScode(E_NOTIMPL);
+}
+
+/***************************************************************************/
+STDMETHODIMP CStreamOnMessage::CopyTo(THIS_ IStream *pstm,
+ ULARGE_INTEGER cb,
+ ULARGE_INTEGER *pcbRead,
+ ULARGE_INTEGER *pcbWritten)
+{
+ return ResultFromScode(E_NOTIMPL);
+}
+
+/***************************************************************************/
+CStreamOnMessage::CStreamOnMessage(unsigned char **ppMessageBuffer)
+ : ref_count(1), ppBuffer(ppMessageBuffer), cbMaxStreamLength(0xFFFFFFFF)
+{
+ pStartOfStream = *ppMessageBuffer;
+}
+
+/***************************************************************************/
+STDMETHODIMP CStreamOnMessage::LockRegion(THIS_ ULARGE_INTEGER libOffset,
+ ULARGE_INTEGER cb,
+ DWORD dwLockType)
+{
+ return ResultFromScode(E_NOTIMPL);
+}
+
+/***************************************************************************/
+STDMETHODIMP CStreamOnMessage::QueryInterface( REFIID riid, LPVOID FAR* ppvObj)
+{
+ if (IsEqualIID(riid, IID_IUnknown))
+ {
+ *ppvObj = (IUnknown *) this;
+ ref_count += 1;
+ return ResultFromScode(S_OK);
+ }
+ else if (IsEqualIID(riid, IID_IStream))
+ {
+ *ppvObj = (IStream *) this;
+ ref_count += 1;
+ return ResultFromScode(S_OK);
+ }
+ else
+ return ResultFromScode(E_NOINTERFACE);
+}
+
+/***************************************************************************/
+STDMETHODIMP CStreamOnMessage::Read(THIS_ VOID HUGEP *pv,
+ ULONG cb, ULONG *pcbRead)
+{
+ memcpy( pv, *ppBuffer, cb );
+ *ppBuffer += cb;
+ if (pcbRead != NULL)
+ *pcbRead = cb;
+ return ResultFromScode(S_OK);
+}
+
+/***************************************************************************/
+STDMETHODIMP_(ULONG) CStreamOnMessage::Release( THIS )
+{
+ ref_count -= 1;
+ if (ref_count == 0)
+ {
+ delete this;
+ return 0;
+ }
+ else
+ return ref_count;
+
+}
+
+/***************************************************************************/
+STDMETHODIMP CStreamOnMessage::Revert(THIS)
+{
+ return ResultFromScode(E_NOTIMPL);
+}
+
+/***************************************************************************/
+STDMETHODIMP CStreamOnMessage::Seek(THIS_ LARGE_INTEGER dlibMove,
+ DWORD dwOrigin,
+ ULARGE_INTEGER *plibNewPosition)
+{
+ ULONG pos;
+
+ // Verify that the offset isn't out of range.
+ if (dlibMove.HighPart != 0)
+ return ResultFromScode( E_FAIL );
+
+ // Determine the new seek pointer.
+ switch (dwOrigin)
+ {
+ case STREAM_SEEK_SET:
+ pos = dlibMove.LowPart;
+ break;
+
+ case STREAM_SEEK_CUR:
+ /* Must use signed math here. */
+ pos = *ppBuffer - pStartOfStream;
+ if ((long) dlibMove.LowPart < 0 &&
+ pos < (unsigned long) - (long) dlibMove.LowPart)
+ return ResultFromScode( E_FAIL );
+ pos += (long) dlibMove.LowPart;
+ break;
+
+ case STREAM_SEEK_END:
+ return ResultFromScode(E_NOTIMPL);
+ break;
+
+ default:
+ return ResultFromScode( E_FAIL );
+ }
+
+ // Set the seek pointer.
+ *ppBuffer = pStartOfStream + pos;
+ if (plibNewPosition != NULL)
+ {
+ plibNewPosition->LowPart = pos;
+ plibNewPosition->HighPart = 0;
+ }
+ return ResultFromScode(S_OK);
+}
+
+/***************************************************************************/
+STDMETHODIMP CStreamOnMessage::SetSize(THIS_ ULARGE_INTEGER libNewSize)
+{
+ return ResultFromScode(E_NOTIMPL);
+}
+
+/***************************************************************************/
+STDMETHODIMP CStreamOnMessage::Stat(THIS_ STATSTG *pstatstg, DWORD grfStatFlag)
+{
+ return ResultFromScode(E_NOTIMPL);
+}
+
+/***************************************************************************/
+STDMETHODIMP CStreamOnMessage::UnlockRegion(THIS_ ULARGE_INTEGER libOffset,
+ ULARGE_INTEGER cb,
+ DWORD dwLockType)
+{
+ return ResultFromScode(E_NOTIMPL);
+}
+
+/***************************************************************************/
+STDMETHODIMP CStreamOnMessage::Write(THIS_ VOID const HUGEP *pv,
+ ULONG cb,
+ ULONG *pcbWritten)
+{
+ // Write the data.
+ memcpy( *ppBuffer, pv, cb );
+ if (pcbWritten != NULL)
+ *pcbWritten = cb;
+ *ppBuffer += cb;
+ return ResultFromScode(S_OK);
+}
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: SNB_UserSize
+//
+// Synopsis: Sizes an SNB.
+//
+// Derivation: An array of strings in one block of memory.
+//
+// history: June-95 Ryszardk Created, based on SNB_*_xmit.
+//
+//--------------------------------------------------------------------------
+
+unsigned long __RPC_USER
+SNB_UserSize (
+ unsigned long * pFlags,
+ unsigned long Offset,
+ SNB * pSnb )
+{
+ if ( ! pSnb )
+ return Offset;
+
+ // calculate the number of strings and characters (with their terminators)
+
+ ULONG ulCntStr = 0;
+ ULONG ulCntChar = 0;
+
+ if (pSnb && *pSnb)
+ {
+ SNB snb = *pSnb;
+
+ WCHAR *psz = *snb;
+ while (psz)
+ {
+ ulCntChar += wcslen(psz) + 1;
+ ulCntStr++;
+ snb++;
+ psz = *snb;
+ }
+ }
+
+ // The wire size is: conf size, 2 fields and the wchars.
+
+ LENGTH_ALIGN( Offset, 3 );
+
+ return ( Offset + 3 * sizeof(long) + ulCntChar * sizeof( WCHAR ) );
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: SNB_UserMarshall
+//
+// Synopsis: Marshalls an SNB into the RPC buffer.
+//
+// Derivation: An array of strings in one block of memory.
+//
+// history: June-95 Ryszardk Created, based on SNB_*_xmit.
+//
+//--------------------------------------------------------------------------
+
+unsigned char __RPC_FAR * __RPC_USER
+SNB_UserMarshal (
+ unsigned long * pFlags,
+ unsigned char * pBuffer,
+ SNB * pSnb )
+{
+ UserNdrDebugOut((UNDR_FORCE, "SNB_UserMarshal\n"));
+
+ if ( ! pSnb )
+ return pBuffer;
+
+ // calculate the number of strings and characters (with their terminators)
+
+ ULONG ulCntStr = 0;
+ ULONG ulCntChar = 0;
+
+ if (pSnb && *pSnb)
+ {
+ SNB snb = *pSnb;
+
+ WCHAR *psz = *snb;
+ while (psz)
+ {
+ ulCntChar += wcslen(psz) + 1;
+ ulCntStr++;
+ snb++;
+ psz = *snb;
+ }
+ }
+
+ // conformant size
+
+ ALIGN( pBuffer, 3 );
+ *( PULONG_LV_CAST pBuffer)++ = ulCntChar;
+
+ // fields
+
+ *( PULONG_LV_CAST pBuffer)++ = ulCntStr;
+ *( PULONG_LV_CAST pBuffer)++ = ulCntChar;
+
+ // actual strings only
+
+ if ( pSnb && *pSnb )
+ {
+ // There is a NULL string pointer to mark the end of the pointer array.
+ // However, the strings don't have to follow tightly.
+ // Hence, we have to copy one string at a time.
+
+ SNB snb = *pSnb;
+ WCHAR *pszSrc;
+
+ while (pszSrc = *snb++)
+ {
+ ULONG ulCopyLen = (wcslen(pszSrc) + 1) * sizeof(WCHAR);
+
+ WdtpMemoryCopy( pBuffer, pszSrc, ulCopyLen );
+ pBuffer += ulCopyLen;
+ }
+ }
+
+ return pBuffer;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: SNB_UserUnmarshall
+//
+// Synopsis: Unmarshalls an SNB from the RPC buffer.
+//
+// Derivation: An array of strings in one block of memory.
+//
+// history: June-95 Ryszardk Created, based on SNB_*_xmit.
+//
+//--------------------------------------------------------------------------
+
+unsigned char __RPC_FAR * __RPC_USER
+SNB_UserUnmarshal (
+ unsigned long * pFlags,
+ unsigned char * pBuffer,
+ SNB * pSnb )
+{
+ UserNdrDebugOut((UNDR_FORCE, "SNB_UserUnmarshal\n"));
+
+ ALIGN( pBuffer, 3 );
+
+ // conf size
+
+ unsigned long ulCntChar = *( PULONG_LV_CAST pBuffer)++;
+
+ // fields
+
+ unsigned long ulCntStr = *( PULONG_LV_CAST pBuffer)++;
+ pBuffer += sizeof(long);
+
+ // no reusage of pSNB.
+
+ if ( *pSnb )
+ WdtpFree( pFlags, *pSnb );
+
+ if ( ulCntStr == 0 )
+ {
+ *pSnb = NULL;
+ return pBuffer;
+ }
+
+ // construct the SNB.
+
+ SNB Snb = (SNB) WdtpAllocate( pFlags,
+ ( (ulCntStr + 1) * sizeof(WCHAR *) +
+ ulCntChar * sizeof(WCHAR)) );
+
+ *pSnb = Snb;
+
+ if (Snb)
+ {
+ // create the pointer array within the SNB.
+
+ WCHAR *pszSrc = (WCHAR *) pBuffer;
+ WCHAR *pszTgt = (WCHAR *) (Snb + ulCntStr + 1); // right behind array
+
+ for (ULONG i = ulCntStr; i > 0; i--)
+ {
+ *Snb++ = pszTgt;
+
+ ULONG ulLen = wcslen(pszSrc) + 1;
+ pszSrc += ulLen;
+ pszTgt += ulLen;
+ }
+
+ *Snb++ = NULL;
+
+ // Copy the actual strings.
+ // We can do a block copy here as we packed them tight in the buffer.
+ // Snb points right behind the lastarray of pointers within the SNB.
+
+ WdtpMemoryCopy( Snb, pBuffer, ulCntChar * sizeof(WCHAR) );
+ pBuffer += ulCntChar * sizeof(WCHAR);
+ }
+
+ return pBuffer;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: SNB_UserFree
+//
+// Synopsis: Frees an SNB.
+//
+// Derivation: An array of strings in one block of memory.
+//
+// history: June-95 Ryszardk Created, based on SNB_*_xmit.
+//
+//--------------------------------------------------------------------------
+
+void __RPC_USER
+SNB_UserFree(
+ unsigned long * pFlags,
+ SNB * pSnb )
+{
+ if ( pSnb && *pSnb )
+ WdtpFree( pFlags, *pSnb );
+}
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: WdtpVoidStar_UserSize
+//
+// Synopsis: Sizes a remotable void star as ulong.
+//
+// history: June-95 Ryszardk Created.
+//
+//--------------------------------------------------------------------------
+
+unsigned long __RPC_USER
+WdtpVoidStar_UserSize (
+ unsigned long * pFlags,
+ unsigned long Offset,
+ unsigned long * pVoid )
+{
+ if ( !pVoid )
+ return Offset;
+
+ LENGTH_ALIGN( Offset, 3 );
+
+ return( Offset + 4 ) ;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: WdtpVoidStar_UserMarshall
+//
+// Synopsis: Marshalls a remotable void star as ulong.
+//
+// history: June-95 Ryszardk Created.
+//
+//--------------------------------------------------------------------------
+
+unsigned char __RPC_FAR * __RPC_USER
+WdtpVoidStar_UserMarshal (
+ unsigned long * pFlags,
+ unsigned char * pBuffer,
+ unsigned long * pVoid )
+{
+ if ( !pVoid )
+ return pBuffer;
+
+ ALIGN( pBuffer, 3 );
+
+ *( PULONG_LV_CAST pBuffer)++ = *pVoid;
+
+ return( pBuffer );
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: WdtpVoidStaer_UserUnmarshall
+//
+// Synopsis: Unmarshalls a remotable void star as ulong.
+//
+// history: June-95 Ryszardk Created.
+//
+//--------------------------------------------------------------------------
+
+unsigned char __RPC_FAR * __RPC_USER
+WdtpVoidStar_UserUnmarshal (
+ unsigned long * pFlags,
+ unsigned char * pBuffer,
+ unsigned long * pVoid )
+{
+ ALIGN( pBuffer, 3 );
+
+ *pVoid= *( PULONG_LV_CAST pBuffer)++;
+
+ return( pBuffer );
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: WdtpVoidStar_UserFree
+//
+//--------------------------------------------------------------------------
+
+void __RPC_USER
+WdtpVoidStar_UserFree(
+ unsigned long * pFlags,
+ unsigned long * pVoid )
+{
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: HWND_UserSize
+//
+// Synopsis: Sizes an HWND handle.
+//
+//--------------------------------------------------------------------------
+
+unsigned long __RPC_USER
+HWND_UserSize (
+ unsigned long * pFlags,
+ unsigned long Offset,
+ HWND * pH )
+{
+ return WdtpVoidStar_UserSize( pFlags, Offset, (ulong*)pH );
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: HWND_UserMarshall
+//
+// Synopsis: Marshalls an HWND handle into the RPC buffer.
+//
+//--------------------------------------------------------------------------
+
+unsigned char __RPC_FAR * __RPC_USER
+HWND_UserMarshal (
+ unsigned long * pFlags,
+ unsigned char * pBuffer,
+ HWND * pH )
+{
+ return WdtpVoidStar_UserMarshal( pFlags, pBuffer, (ulong*)pH );
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: HWND_UserUnmarshall
+//
+// Synopsis: Unmarshalls an HWND handle from the RPC buffer.
+//
+//--------------------------------------------------------------------------
+
+unsigned char __RPC_FAR * __RPC_USER
+HWND_UserUnmarshal (
+ unsigned long * pFlags,
+ unsigned char * pBuffer,
+ HWND * pH )
+{
+ return WdtpVoidStar_UserUnmarshal( pFlags, pBuffer, (ulong*)pH );
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: HWND_UserFree
+//
+// Synopsis: Shouldn't be called.
+//
+//--------------------------------------------------------------------------
+
+void __RPC_USER
+HWND_UserFree(
+ unsigned long * pFlags,
+ HWND * pH )
+{
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: HMENU_UserSize
+//
+// Synopsis: Sizes an HMENU handle.
+//
+//--------------------------------------------------------------------------
+
+unsigned long __RPC_USER
+HMENU_UserSize (
+ unsigned long * pFlags,
+ unsigned long Offset,
+ HMENU * pH )
+{
+ return WdtpVoidStar_UserSize( pFlags, Offset, (ulong*)pH );
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: HMENU_UserMarshall
+//
+// Synopsis: Marshalls an HMENU handle into the RPC buffer.
+//
+//--------------------------------------------------------------------------
+
+unsigned char __RPC_FAR * __RPC_USER
+HMENU_UserMarshal (
+ unsigned long * pFlags,
+ unsigned char * pBuffer,
+ HMENU * pH )
+{
+ return WdtpVoidStar_UserMarshal( pFlags, pBuffer, (ulong*)pH );
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: HMENU_UserUnmarshall
+//
+// Synopsis: Unmarshalls an HMENU handle from the RPC buffer.
+//
+//--------------------------------------------------------------------------
+
+unsigned char __RPC_FAR * __RPC_USER
+HMENU_UserUnmarshal (
+ unsigned long * pFlags,
+ unsigned char * pBuffer,
+ HMENU * pH )
+{
+ return WdtpVoidStar_UserUnmarshal( pFlags, pBuffer, (ulong*)pH );
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: HMENU_UserFree
+//
+// Synopsis: Free an HMENU.
+//
+//--------------------------------------------------------------------------
+
+void __RPC_USER
+HMENU_UserFree(
+ unsigned long * pFlags,
+ HMENU * pH )
+{
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: HACCEL_UserSize
+//
+// Synopsis: Sizes an HACCEL handle.
+//
+//--------------------------------------------------------------------------
+
+unsigned long __RPC_USER
+HACCEL_UserSize (
+ unsigned long * pFlags,
+ unsigned long Offset,
+ HACCEL * pH )
+{
+ return WdtpVoidStar_UserSize( pFlags, Offset, (ulong*)pH );
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: HACCEL_UserMarshall
+//
+// Synopsis: Marshalls an HACCEL handle into the RPC buffer.
+//
+//--------------------------------------------------------------------------
+
+unsigned char __RPC_FAR * __RPC_USER
+HACCEL_UserMarshal (
+ unsigned long * pFlags,
+ unsigned char * pBuffer,
+ HACCEL * pH )
+{
+ return WdtpVoidStar_UserMarshal( pFlags, pBuffer, (ulong*)pH );
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: HACCEL_UserUnmarshall
+//
+// Synopsis: Unmarshalls an HACCEL handle from the RPC buffer.
+//
+//--------------------------------------------------------------------------
+
+unsigned char __RPC_FAR * __RPC_USER
+HACCEL_UserUnmarshal (
+ unsigned long * pFlags,
+ unsigned char * pBuffer,
+ HACCEL * pH )
+{
+ return WdtpVoidStar_UserUnmarshal( pFlags, pBuffer, (ulong*)pH );
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: HACCEL_UserFree
+//
+// Synopsis: Free an HACCEL.
+//
+//--------------------------------------------------------------------------
+
+void __RPC_USER
+HACCEL_UserFree(
+ unsigned long * pFlags,
+ HACCEL * pH )
+{
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: HBRUSH_UserSize
+//
+// Synopsis: Sizes an HBRUSH handle.
+//
+//--------------------------------------------------------------------------
+
+unsigned long __RPC_USER
+HBRUSH_UserSize (
+ unsigned long * pFlags,
+ unsigned long Offset,
+ HBRUSH * pH )
+{
+ return WdtpVoidStar_UserSize( pFlags, Offset, (ulong*)pH );
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: HBRUSH_UserMarshall
+//
+// Synopsis: Marshalls an HBRUSH handle into the RPC buffer.
+//
+//--------------------------------------------------------------------------
+
+unsigned char __RPC_FAR * __RPC_USER
+HBRUSH_UserMarshal (
+ unsigned long * pFlags,
+ unsigned char * pBuffer,
+ HBRUSH * pH )
+{
+ return WdtpVoidStar_UserMarshal( pFlags, pBuffer, (ulong*)pH );
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: HBRUSH_UserUnmarshall
+//
+// Synopsis: Unmarshalls an HBRUSH handle from the RPC buffer.
+//
+//--------------------------------------------------------------------------
+
+unsigned char __RPC_FAR * __RPC_USER
+HBRUSH_UserUnmarshal (
+ unsigned long * pFlags,
+ unsigned char * pBuffer,
+ HBRUSH * pH )
+{
+ return WdtpVoidStar_UserUnmarshal( pFlags, pBuffer, (ulong*)pH );
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: HBRUSH_UserFree
+//
+// Synopsis: Free an HBRUSH.
+//
+//--------------------------------------------------------------------------
+
+void __RPC_USER
+HBRUSH_UserFree(
+ unsigned long * pFlags,
+ HBRUSH * pH )
+{
+}
+
+
+// #########################################################################
+//
+// HGLOBAL.
+// See transmit.h for explanation of strict data/handle passing.
+//
+// #########################################################################
+
+//+-------------------------------------------------------------------------
+//
+// Function: HGLOBAL_UserSize
+//
+// Synopsis: Get the wire size the HGLOBAL handle and data.
+//
+// Derivation: Conformant struct with a flag field:
+// align + 12 + data size.
+//
+// history: May-95 Ryszardk Created.
+//
+//--------------------------------------------------------------------------
+
+unsigned long __RPC_USER
+HGLOBAL_UserSize (
+ unsigned long * pFlags,
+ unsigned long Offset,
+ HGLOBAL * pGlobal)
+{
+ if ( !pGlobal )
+ return Offset;
+
+ // userHGLOBAL: the encapsulated union.
+ // Discriminant and then handle or pointer from the union arm.
+
+ LENGTH_ALIGN( Offset, 3 );
+
+ Offset += sizeof(long) + sizeof(void*);
+
+ if ( ! *pGlobal )
+ return Offset;
+
+ if ( HGLOBAL_DATA_PASSING(*pFlags) )
+ {
+ unsigned long ulDataSize = GlobalSize( *pGlobal );
+
+ Offset += 3 * sizeof(long) + ulDataSize;
+ }
+
+ return( Offset );
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: HGLOBAL_UserMarshall
+//
+// Synopsis: Marshalls an HGLOBAL object into the RPC buffer.
+//
+// Derivation: Conformant struct with a flag field:
+// align, size, null flag, size, data (bytes, if any)
+//
+// history: May-95 Ryszardk Created.
+//
+//--------------------------------------------------------------------------
+
+unsigned char __RPC_FAR * __RPC_USER
+HGLOBAL_UserMarshal (
+ unsigned long * pFlags,
+ unsigned char * pBuffer,
+ HGLOBAL * pGlobal)
+{
+ if ( !pGlobal )
+ return pBuffer;
+
+ // We marshal a null handle, too.
+
+ UserNdrDebugOut((UNDR_OUT4, "HGLOBAL_UserMarshal\n"));
+
+ ALIGN( pBuffer, 3 );
+
+ // Discriminant of the encapsulated union and union arm.
+
+ if ( HGLOBAL_DATA_PASSING(*pFlags) )
+ {
+ unsigned long ulDataSize;
+
+ // userHGLOBAL
+
+ *( PULONG_LV_CAST pBuffer)++ = WDT_DATA_MARKER;
+ *( PULONG_LV_CAST pBuffer)++ = (ulong) *pGlobal;
+
+ if ( ! *pGlobal )
+ return pBuffer;
+
+ // FLAGGED_BYTE_BLOB
+
+ ulDataSize = GlobalSize( *pGlobal );
+
+ *( PULONG_LV_CAST pBuffer)++ = ulDataSize;
+
+ // Handle is the non-null flag
+
+ *( PULONG_LV_CAST pBuffer)++ = (ulong)*pGlobal;
+ *( PULONG_LV_CAST pBuffer)++ = ulDataSize;
+
+ if( ulDataSize )
+ {
+ void * pData = GlobalLock( *pGlobal);
+ memcpy( pBuffer, pData, ulDataSize );
+ GlobalUnlock( *pGlobal);
+ }
+
+ pBuffer += ulDataSize;
+ }
+ else
+ {
+ // Sending a handle.
+
+ *( PULONG_LV_CAST pBuffer)++ = WDT_HANDLE_MARKER;
+ *( PULONG_LV_CAST pBuffer)++ = (ulong) *pGlobal;
+ }
+
+ return( pBuffer );
+}
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: WdtpGlobalUnmarshal
+//
+// Synopsis: Unmarshalls an HGLOBAL object from the RPC buffer.
+//
+// Derivation: Conformant struct with a flag field:
+// align, size, null flag, size, data (bytes, if any)
+//
+// Note: Reallocation is forbidden when the hglobal is part of
+// an [in,out] STGMEDIUM in IDataObject::GetDataHere.
+// This affects only data passing with old handles being
+// non null.
+//
+// history: May-95 Ryszardk Created.
+//
+//--------------------------------------------------------------------------
+
+unsigned char __RPC_FAR * __RPC_USER
+WdtpGlobalUnmarshal (
+ unsigned long * pFlags,
+ unsigned char * pBuffer,
+ HGLOBAL * pGlobal,
+ BOOL fCanReallocate )
+{
+ unsigned long ulDataSize, fHandle, UnionDisc;
+ HGLOBAL hGlobal;
+
+ ALIGN( pBuffer, 3 );
+
+ UnionDisc = *( PULONG_LV_CAST pBuffer)++;
+ hGlobal = (HGLOBAL) *( PULONG_LV_CAST pBuffer)++;
+
+ if ( IS_DATA_MARKER( UnionDisc) )
+ {
+ if ( ! hGlobal )
+ {
+ if ( *pGlobal )
+ GlobalFree( *pGlobal );
+ *pGlobal = NULL;
+ return pBuffer;
+ }
+
+ // There is a handle data on wire.
+
+ ulDataSize = *( PULONG_LV_CAST pBuffer)++;
+ // fhandle and data size again.
+ pBuffer += 8;
+
+ if ( *pGlobal )
+ {
+ // Check for reallocation
+
+ if ( GlobalSize( *pGlobal ) == ulDataSize )
+ hGlobal = *pGlobal;
+ else
+ {
+ if ( fCanReallocate )
+ {
+ // hGlobal = GlobalReAlloc( *pGlobal, ulDataSize, GMEM_MOVEABLE );
+
+ GlobalFree( *pGlobal );
+ hGlobal = GlobalAlloc( GMEM_MOVEABLE, ulDataSize );
+ }
+ else
+ {
+ if ( GlobalSize(*pGlobal) < ulDataSize )
+ RpcRaiseException( STG_E_MEDIUMFULL );
+ else
+ hGlobal = *pGlobal;
+ }
+ }
+ }
+ else
+ {
+ // allocate a new block
+
+ hGlobal = GlobalAlloc( GMEM_MOVEABLE, ulDataSize );
+ }
+
+ if ( hGlobal == NULL )
+ RpcRaiseException(E_OUTOFMEMORY);
+ else
+ {
+ void * pData = GlobalLock( hGlobal);
+ memcpy( pData, pBuffer, ulDataSize );
+ pBuffer += ulDataSize;
+ GlobalUnlock( hGlobal);
+ }
+ }
+ else
+ {
+ // Sending a handle only.
+ // Reallocation problem doesn't apply to handle passing.
+
+ if ( *pGlobal != hGlobal && *pGlobal )
+ GlobalFree( *pGlobal );
+ }
+
+ *pGlobal = hGlobal;
+
+ return( pBuffer );
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: HGLOBAL_UserUnmarshall
+//
+// Synopsis: Unmarshalls an HGLOBAL object from the RPC buffer.
+//
+// Derivation: Conformant struct with a flag field:
+// align, size, null flag, size, data (bytes, if any)
+//
+// history: May-95 Ryszardk Created.
+//
+//--------------------------------------------------------------------------
+
+unsigned char __RPC_FAR * __RPC_USER
+HGLOBAL_UserUnmarshal (
+ unsigned long * pFlags,
+ unsigned char * pBuffer,
+ HGLOBAL * pGlobal)
+{
+ return( WdtpGlobalUnmarshal( pFlags,
+ pBuffer,
+ pGlobal,
+ TRUE ) ); // reallocation possible
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: HGLOBAL_UserFree
+//
+// Synopsis: Free an HGLOBAL.
+//
+// history: May-95 Ryszardk Created.
+//
+//--------------------------------------------------------------------------
+
+void __RPC_USER
+HGLOBAL_UserFree(
+ unsigned long * pFlags,
+ HGLOBAL * pGlobal)
+{
+ if( pGlobal && *pGlobal )
+ {
+ if ( HGLOBAL_DATA_PASSING(*pFlags) )
+ GlobalFree( *pGlobal);
+ }
+}
+
+
+// #########################################################################
+//
+// HMETAFILEPICT
+// See transmit.h for explanation of strict vs. lax data/handle passing.
+//
+// #########################################################################
+
+//+-------------------------------------------------------------------------
+//
+// Function: HMETAFILEPICT_UserSize
+//
+// Synopsis: Get the wire size the HMETAFILEPICT handle and data.
+//
+// Derivation: Union of a long and the meta file pict handle.
+// Then struct with top layer (and a hmetafile handle).
+// The the representation of the metafile.
+//
+// history: May-95 Ryszardk Created.
+//
+//--------------------------------------------------------------------------
+
+unsigned long __RPC_USER
+HMETAFILEPICT_UserSize (
+ unsigned long * pFlags,
+ unsigned long Offset,
+ HMETAFILEPICT * pHMetaFilePict )
+{
+ if ( !pHMetaFilePict )
+ return Offset;
+
+ LENGTH_ALIGN( Offset, 3 );
+
+ // Discriminant of the encapsulated union and the union arm.
+
+ Offset += 8;
+
+ if ( ! *pHMetaFilePict )
+ return Offset;
+
+ if ( HGLOBAL_HANDLE_PASSING(*pFlags) )
+ return Offset;
+
+ // Now, this is a two layer object with HGLOBAL on top.
+ // Upper layer - hglobal part - needs to be sent as data.
+
+ METAFILEPICT *
+ pMFP = (METAFILEPICT*) GlobalLock( *(HANDLE *)pHMetaFilePict );
+
+ if ( pMFP == NULL )
+ RpcRaiseException( E_OUTOFMEMORY );
+
+ // Upper layer: 3 long fields + handle
+
+ Offset += 3 * sizeof(long) + sizeof(void*);
+
+ // The lower part is a metafile handle.
+
+ if ( HGLOBAL_DATA_PASSING( *pFlags) )
+ {
+ ulong ulDataSize = GetMetaFileBitsEx( pMFP->hMF, 0 , NULL );
+
+ Offset += 12 + ulDataSize;
+ }
+
+ GlobalUnlock( *(HANDLE *)pHMetaFilePict );
+
+ return( Offset ) ;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: HMETAFILEPICT_UserMarshal
+//
+// Synopsis: Marshalls an HMETAFILEPICT object into the RPC buffer.
+//
+// history: May-95 Ryszardk Created.
+//
+//--------------------------------------------------------------------------
+
+unsigned char __RPC_FAR * __RPC_USER
+HMETAFILEPICT_UserMarshal (
+ unsigned long * pFlags,
+ unsigned char * pBuffer,
+ HMETAFILEPICT * pHMetaFilePict )
+{
+ if ( !pHMetaFilePict )
+ return pBuffer;
+
+ UserNdrDebugOut((UNDR_OUT4, "HMETAFILEPICT_UserMarshal\n"));
+
+ ALIGN( pBuffer, 3 );
+
+ if ( HGLOBAL_HANDLE_PASSING(*pFlags) )
+ {
+ // Sending only the top level global handle.
+
+ *( PULONG_LV_CAST pBuffer)++ = WDT_HANDLE_MARKER;
+ *( PULONG_LV_CAST pBuffer)++ = (ulong)*(HANDLE*)pHMetaFilePict;
+
+ return pBuffer;
+ }
+
+ // userHMETAFILEPICT
+ // We need to send the data from the top (hglobal) layer.
+
+ *( PULONG_LV_CAST pBuffer)++ = WDT_DATA_MARKER;
+ *( PULONG_LV_CAST pBuffer)++ = (ulong)*pHMetaFilePict;
+
+ if ( ! *pHMetaFilePict )
+ return pBuffer;
+
+ // remoteHMETAFILEPICT
+
+ METAFILEPICT * pMFP = (METAFILEPICT*) GlobalLock(
+ *(HANDLE *)pHMetaFilePict );
+ if ( pMFP == NULL )
+ RpcRaiseException( E_OUTOFMEMORY );
+
+ *( PULONG_LV_CAST pBuffer)++ = pMFP->mm;
+ *( PULONG_LV_CAST pBuffer)++ = pMFP->xExt;
+ *( PULONG_LV_CAST pBuffer)++ = pMFP->yExt;
+ *( PULONG_LV_CAST pBuffer)++ = (ulong) pMFP->hMF;
+
+ // See if the HMETAFILE needs to be sent as data, too.
+
+ if ( pMFP->hMF && HGLOBAL_DATA_PASSING(*pFlags) )
+ {
+ ulong ulDataSize = GetMetaFileBitsEx( pMFP->hMF, 0 , NULL );
+
+ // conformant size then the size field
+
+ *( PULONG_LV_CAST pBuffer)++ = ulDataSize;
+ *( PULONG_LV_CAST pBuffer)++ = ulDataSize;
+
+ GetMetaFileBitsEx( pMFP->hMF, ulDataSize , pBuffer );
+
+ pBuffer += ulDataSize;
+ }
+
+ GlobalUnlock( *(HANDLE *)pHMetaFilePict );
+
+ return( pBuffer );
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: HMETAFILEPICT_UserUnmarshal
+//
+// Synopsis: Unmarshalls an HMETAFILEPICT object from the RPC buffer.
+//
+// history: May-95 Ryszardk Created.
+//
+//--------------------------------------------------------------------------
+
+unsigned char __RPC_FAR * __RPC_USER
+HMETAFILEPICT_UserUnmarshal (
+ unsigned long * pFlags,
+ unsigned char * pBufferStart,
+ HMETAFILEPICT * pHMetaFilePict )
+{
+ unsigned long ulDataSize, fHandle;
+ unsigned char * pBuffer;
+ HMETAFILEPICT hMetaFilePict;
+
+ UserNdrDebugOut((UNDR_OUT4, "HMETAFILEPICT_UserUnmarshal\n"));
+
+ pBuffer = pBufferStart;
+ ALIGN( pBuffer, 3 );
+
+ unsigned long UnionDisc = *( PULONG_LV_CAST pBuffer)++;
+ hMetaFilePict = (HMETAFILEPICT) *( PULONG_LV_CAST pBuffer)++;
+
+ if ( IS_DATA_MARKER( UnionDisc) && hMetaFilePict )
+ {
+ HGLOBAL hGlobal = GlobalAlloc( GMEM_MOVEABLE, sizeof(METAFILEPICT) );
+ hMetaFilePict = (HMETAFILEPICT) hGlobal;
+
+ if ( hMetaFilePict == NULL )
+ RpcRaiseException( E_OUTOFMEMORY );
+
+ METAFILEPICT * pMFP = (METAFILEPICT*) GlobalLock(
+ (HANDLE) hMetaFilePict );
+ if ( pMFP == NULL )
+ RpcRaiseException( E_OUTOFMEMORY );
+
+ pMFP->mm = *( PULONG_LV_CAST pBuffer)++;
+ pMFP->xExt = *( PULONG_LV_CAST pBuffer)++;
+ pMFP->yExt = *( PULONG_LV_CAST pBuffer)++;
+ pMFP->hMF = (HMETAFILE) *( PULONG_LV_CAST pBuffer)++;
+
+ if ( pMFP->hMF && HGLOBAL_DATA_PASSING(*pFlags) )
+ {
+ // conformant size then the size field
+
+ ulong ulDataSize = *( PULONG_LV_CAST pBuffer)++;
+ pBuffer += 4;
+
+ pMFP->hMF = SetMetaFileBitsEx( ulDataSize, (uchar*)pBuffer );
+
+ pBuffer += ulDataSize;
+ }
+
+ GlobalUnlock( (HANDLE) hMetaFilePict );
+ }
+
+ // no reusage, just release the previous one.
+
+ if ( *pHMetaFilePict )
+ {
+ // This may happen on the client only and doesn't depend on
+ // how the other one was passed.
+
+ METAFILEPICT *
+ pMFP = (METAFILEPICT*) GlobalLock( *(HANDLE *)pHMetaFilePict );
+
+ if ( pMFP == NULL )
+ RpcRaiseException( E_OUTOFMEMORY );
+
+ if ( pMFP->hMF )
+ DeleteMetaFile( pMFP->hMF );
+
+ GlobalUnlock( *pHMetaFilePict );
+ GlobalFree( *pHMetaFilePict );
+ }
+
+ *pHMetaFilePict = hMetaFilePict;
+
+ return( pBuffer );
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: HMETAFILEPICT_UserFree
+//
+// Synopsis: Free an HMETAFILEPICT.
+//
+// history: May-95 Ryszardk Created.
+//
+//--------------------------------------------------------------------------
+
+void __RPC_USER
+HMETAFILEPICT_UserFree(
+ unsigned long * pFlags,
+ HMETAFILEPICT * pHMetaFilePict )
+{
+ UserNdrDebugOut((UNDR_FORCE, "HMETAFILEPICT_UserFree\n"));
+
+ if( pHMetaFilePict && *pHMetaFilePict )
+ {
+ if ( HGLOBAL_HANDLE_PASSING(*pFlags) )
+ return;
+
+ // Need to free the upper hglobal part.
+
+ METAFILEPICT *
+ pMFP = (METAFILEPICT*) GlobalLock( *(HANDLE *)pHMetaFilePict );
+
+ if ( pMFP == NULL )
+ RpcRaiseException( E_OUTOFMEMORY );
+
+ // See if we need to free the hglobal, too.
+
+ if ( pMFP->hMF && HGLOBAL_DATA_PASSING(*pFlags) )
+ DeleteMetaFile( pMFP->hMF );
+
+ GlobalUnlock( *pHMetaFilePict );
+ GlobalFree( *pHMetaFilePict );
+ }
+}
+
+
+
+// #########################################################################
+//
+// HENHMETAFILE
+// See transmit.h for explanation of lax data/handle passing.
+//
+// #########################################################################
+
+//+-------------------------------------------------------------------------
+//
+// Function: HENHMETAFILE_UserSize
+//
+// Synopsis: Get the wire size the HENHMETAFILE handle and data.
+//
+// Derivation: Union of a long and the meta file handle and then struct.
+//
+// history: May-95 Ryszardk Created.
+//
+//--------------------------------------------------------------------------
+
+unsigned long __RPC_USER
+HENHMETAFILE_UserSize (
+ unsigned long * pFlags,
+ unsigned long Offset,
+ HENHMETAFILE * pHEnhMetafile )
+{
+ if ( !pHEnhMetafile )
+ return Offset;
+
+ LENGTH_ALIGN( Offset, 3 );
+
+ // The encapsulated union.
+ // Discriminant and then handle or pointer from the union arm.
+
+ Offset += sizeof(long) + sizeof(void*);
+
+ if ( ! *pHEnhMetafile )
+ return Offset;
+
+ if ( GDI_DATA_PASSING(*pFlags) )
+ {
+ // Pointee of the union arm for the remote case.
+ // Byte blob : conformant size, size field, data
+
+ Offset += 2 * sizeof(long);
+
+ ulong ulDataSize = GetEnhMetaFileBits( *pHEnhMetafile, 0, NULL );
+ Offset += ulDataSize;
+ }
+
+ return( Offset );
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: HENHMETAFILE_UserMarshall
+//
+// Synopsis: Marshalls an HENHMETAFILE object into the RPC buffer.
+//
+// history: May-95 Ryszardk Created.
+//
+//--------------------------------------------------------------------------
+
+unsigned char __RPC_FAR * __RPC_USER
+HENHMETAFILE_UserMarshal (
+ unsigned long * pFlags,
+ unsigned char * pBuffer,
+ HENHMETAFILE * pHEnhMetafile )
+{
+ if ( !pHEnhMetafile )
+ return pBuffer;
+
+ UserNdrDebugOut((UNDR_OUT4, "HENHMETAFILE_UserMarshal\n"));
+
+ ALIGN( pBuffer, 3 );
+
+ // Discriminant of the encapsulated union and union arm.
+
+ if ( GDI_DATA_PASSING(*pFlags) )
+ {
+ // userHENHMETAFILE
+
+ *( PULONG_LV_CAST pBuffer)++ = WDT_DATA_MARKER;
+ *( PULONG_LV_CAST pBuffer)++ = (ulong) *pHEnhMetafile;
+
+ if ( !*pHEnhMetafile )
+ return pBuffer;
+
+ // BYTE_BLOB: conformant size, size field, data
+
+ ulong ulDataSize = GetEnhMetaFileBits( *pHEnhMetafile, 0, NULL );
+
+ *( PULONG_LV_CAST pBuffer)++ = ulDataSize;
+ *( PULONG_LV_CAST pBuffer)++ = ulDataSize;
+
+ if ( 0 == GetEnhMetaFileBits( *pHEnhMetafile,
+ ulDataSize,
+ (uchar*)pBuffer ) )
+ RpcRaiseException( HRESULT_FROM_WIN32(GetLastError()));
+
+ pBuffer += ulDataSize;
+ }
+ else
+ {
+ // Sending a handle.
+
+ *( PULONG_LV_CAST pBuffer)++ = WDT_HANDLE_MARKER;
+ *( PULONG_LV_CAST pBuffer)++ = (ulong) *(HANDLE *)pHEnhMetafile;
+ }
+
+ return( pBuffer );
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: HENHMETAFILE_UserUnmarshall
+//
+// Synopsis: Unmarshalls an HENHMETAFILE object from the RPC buffer.
+//
+// history: May-95 Ryszardk Created.
+//
+//--------------------------------------------------------------------------
+
+unsigned char __RPC_FAR * __RPC_USER
+HENHMETAFILE_UserUnmarshal (
+ unsigned long * pFlags,
+ unsigned char * pBuffer,
+ HENHMETAFILE * pHEnhMetafile )
+{
+ HENHMETAFILE hEnhMetafile;
+
+ UserNdrDebugOut((UNDR_OUT4, "HENHMETAFILE_UserUnmarshal\n"));
+
+ ALIGN( pBuffer, 3 );
+
+ unsigned long UnionDisc = *( PULONG_LV_CAST pBuffer)++;
+ hEnhMetafile = (HENHMETAFILE) *( PULONG_LV_CAST pBuffer)++;
+
+ if ( IS_DATA_MARKER( UnionDisc) )
+ {
+ if ( hEnhMetafile )
+ {
+ // Byte blob : conformant size, size field, data
+
+ ulong ulDataSize = *(ulong*)pBuffer;
+ pBuffer += 8;
+ hEnhMetafile = SetEnhMetaFileBits( ulDataSize, (uchar*) pBuffer );
+ pBuffer += ulDataSize;
+ }
+ }
+
+ // No reusage of the old object.
+
+ if (*pHEnhMetafile)
+ DeleteEnhMetaFile( *pHEnhMetafile );
+
+ *pHEnhMetafile = hEnhMetafile;
+
+ return( pBuffer );
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: HENHMETAFILE_UserFree
+//
+// Synopsis: Free an HENHMETAFILE.
+//
+// history: May-95 Ryszardk Created.
+//
+//--------------------------------------------------------------------------
+
+void __RPC_USER
+HENHMETAFILE_UserFree(
+ unsigned long * pFlags,
+ HENHMETAFILE * pHEnhMetafile )
+{
+ UserNdrDebugOut((UNDR_FORCE, "HENHMETAFILE_UserFree\n"));
+
+ if( pHEnhMetafile && *pHEnhMetafile )
+ {
+ if ( GDI_DATA_PASSING(*pFlags) )
+ {
+ DeleteEnhMetaFile( *pHEnhMetafile );
+ }
+ }
+}
+
+
+// #########################################################################
+//
+// HBITMAP
+// See transmit.h for explanation of lax data/handle passing.
+//
+// #########################################################################
+
+//+-------------------------------------------------------------------------
+//
+// Function: HBITMAP_UserSize
+//
+// Synopsis: Get the wire size the HBITMAP handle and data.
+//
+// Derivation: Union of a long and the bitmap handle and then struct.
+//
+// history: May-95 Ryszardk Created.
+//
+//--------------------------------------------------------------------------
+
+unsigned long __RPC_USER
+HBITMAP_UserSize (
+ unsigned long * pFlags,
+ unsigned long Offset,
+ HBITMAP * pHBitmap )
+{
+ if ( !pHBitmap )
+ return Offset;
+
+ BITMAP bm;
+ HBITMAP hBitmap = *pHBitmap;
+
+ LENGTH_ALIGN( Offset, 3 );
+
+ // The encapsulated union.
+ // Discriminant and then handle or pointer from the union arm.
+
+ Offset += sizeof(long) + sizeof(void*);
+
+ if ( ! *pHBitmap )
+ return Offset;
+
+ if ( GDI_DATA_PASSING(*pFlags) )
+ {
+ // Pointee of the union arm for the remote case.
+ // Conformat size, 6 fields, size, conf array.
+
+ Offset += 4 + 4 * sizeof(LONG) + 2 * sizeof(WORD) + 4;
+
+ // Get information about the bitmap
+
+ #if defined(_CHICAGO_)
+ if (FALSE == GetObjectA(hBitmap, sizeof(BITMAP), &bm))
+ #else
+ if (FALSE == GetObject(hBitmap, sizeof(BITMAP), &bm))
+ #endif
+ {
+ RpcRaiseException(HRESULT_FROM_WIN32(GetLastError()));
+ }
+
+ ULONG ulDataSize = bm.bmPlanes * bm.bmHeight * bm.bmWidthBytes;
+
+ Offset += ulDataSize;
+ }
+
+ return( Offset ) ;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: HBITMAP_UserMarshall
+//
+// Synopsis: Marshalls an HBITMAP object into the RPC buffer.
+//
+// history: May-95 Ryszardk Created.
+//
+//--------------------------------------------------------------------------
+
+unsigned char __RPC_FAR * __RPC_USER
+HBITMAP_UserMarshal (
+ unsigned long * pFlags,
+ unsigned char * pBuffer,
+ HBITMAP * pHBitmap )
+{
+ if ( !pHBitmap )
+ return pBuffer;
+
+ UserNdrDebugOut((UNDR_OUT4, "HBITMAP_UserMarshal\n"));
+
+ ALIGN( pBuffer, 3 );
+
+ // Discriminant of the encapsulated union and union arm.
+
+ if ( GDI_DATA_PASSING(*pFlags) )
+ {
+ // userHBITMAP
+
+ *( PULONG_LV_CAST pBuffer)++ = WDT_DATA_MARKER;
+ *( PULONG_LV_CAST pBuffer)++ = (ulong) *pHBitmap;
+
+ if ( ! *pHBitmap )
+ return pBuffer;
+
+ // Get information about the bitmap
+
+ BITMAP bm;
+ HBITMAP hBitmap = *pHBitmap;
+
+ #if defined(_CHICAGO_)
+ if (FALSE == GetObjectA(hBitmap, sizeof(BITMAP), &bm))
+ #else
+ if (FALSE == GetObject(hBitmap, sizeof(BITMAP), &bm))
+ #endif
+ {
+ RpcRaiseException(HRESULT_FROM_WIN32(GetLastError()));
+ }
+
+ DWORD dwCount = bm.bmPlanes * bm.bmHeight * bm.bmWidthBytes;
+
+ *( PULONG_LV_CAST pBuffer)++ = dwCount;
+
+ // Get the bm structure fields.
+
+ ulong ulBmSize = 4 * sizeof(LONG) + 2 * sizeof( WORD );
+
+ memcpy( pBuffer, (void *) &bm, ulBmSize );
+ pBuffer += ulBmSize;
+
+ // Get the raw bits.
+
+ if (0 == GetBitmapBits( hBitmap, dwCount, pBuffer ) )
+ {
+ RpcRaiseException(HRESULT_FROM_WIN32(GetLastError()));
+ }
+ pBuffer += dwCount;
+ }
+ else
+ {
+ // Sending a handle.
+
+ *( PULONG_LV_CAST pBuffer)++ = WDT_HANDLE_MARKER;
+ *( PULONG_LV_CAST pBuffer)++ = (ulong) *(HANDLE *)pHBitmap;
+ }
+
+ return( pBuffer );
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: HBITMAP_UserUnmarshall
+//
+// Synopsis: Unmarshalls an HBITMAP object from the RPC buffer.
+//
+// history: May-95 Ryszardk Created.
+//
+//--------------------------------------------------------------------------
+
+unsigned char __RPC_FAR * __RPC_USER
+HBITMAP_UserUnmarshal (
+ unsigned long * pFlags,
+ unsigned char * pBuffer,
+ HBITMAP * pHBitmap )
+{
+ HBITMAP hBitmap;
+
+ UserNdrDebugOut((UNDR_OUT4, "HBITMAP_UserUnmarshal\n"));
+
+ ALIGN( pBuffer, 3 );
+
+ unsigned long UnionDisc = *( PULONG_LV_CAST pBuffer)++;
+ hBitmap = (HBITMAP) *( PULONG_LV_CAST pBuffer)++;
+
+ if ( IS_DATA_MARKER( UnionDisc) )
+ {
+ if ( hBitmap )
+ {
+ DWORD dwCount = *( PULONG_LV_CAST pBuffer)++;
+ BITMAP * pBm = (BITMAP *) pBuffer;
+
+ ulong ulBmSize = 4 * sizeof(LONG) + 2 * sizeof( WORD );
+
+ pBuffer += ulBmSize;
+
+ // Create a bitmap based on the BITMAP structure and the raw bits in
+ // the transmission buffer
+
+ hBitmap = CreateBitmap( pBm->bmWidth,
+ pBm->bmHeight,
+ pBm->bmPlanes,
+ pBm->bmBitsPixel,
+ pBuffer );
+
+ pBuffer += dwCount;
+ }
+ }
+
+ // A new bitmap handle is ready, destroy the old one, if needed.
+
+ if ( *pHBitmap )
+ DeleteObject( *pHBitmap );
+
+ *pHBitmap = hBitmap;
+
+ return( pBuffer );
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: HBITMAP_UserFree
+//
+// Synopsis: Free an HBITMAP.
+//
+// history: May-95 Ryszardk Created.
+//
+//--------------------------------------------------------------------------
+
+void __RPC_USER
+HBITMAP_UserFree(
+ unsigned long * pFlags,
+ HBITMAP * pHBitmap )
+{
+ UserNdrDebugOut((UNDR_OUT4, "HBITMAP_UserFree\n"));
+
+ if( pHBitmap && *pHBitmap )
+ {
+ if ( GDI_DATA_PASSING(*pFlags) )
+ {
+ DeleteObject( *pHBitmap );
+ }
+ }
+}
+
+
+// #########################################################################
+//
+// HPALETTE
+// See transmit.h for explanation of lax data/handle passing.
+//
+// #########################################################################
+
+//+-------------------------------------------------------------------------
+//
+// Function: HPALETTE_UserSize
+//
+// Synopsis: Get the wire size the HPALETTE handle and data.
+//
+// Derivation: Union of a long and the hpalette handle.
+// Then the struct represents hpalette.
+//
+// history: May-95 Ryszardk Created.
+//
+//--------------------------------------------------------------------------
+
+unsigned long __RPC_USER
+HPALETTE_UserSize (
+ unsigned long * pFlags,
+ unsigned long Offset,
+ HPALETTE * pHPalette )
+{
+ if ( !pHPalette )
+ return Offset;
+
+ BITMAP bm;
+
+ LENGTH_ALIGN( Offset, 3 );
+
+ // The encapsulated union.
+ // Discriminant and then handle or pointer from the union arm.
+
+ Offset += sizeof(long) + sizeof(void*);
+
+ if ( ! *pHPalette )
+ return Offset;
+
+ if ( GDI_DATA_PASSING(*pFlags) )
+ {
+ // Conformat struct with version and size and conf array of entries.
+
+ Offset += sizeof(long) + 2 * sizeof(short);
+
+ // Determine the number of color entries in the palette
+
+ DWORD cEntries = GetPaletteEntries(*pHPalette, 0, 0, NULL);
+
+ Offset += cEntries * sizeof(PALETTEENTRY);
+ }
+
+ return( Offset ) ;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: HPALETTE_UserMarshall
+//
+// Synopsis: Marshalls an HPALETTE object into the RPC buffer.
+//
+// history: May-95 Ryszardk Created.
+//
+//--------------------------------------------------------------------------
+
+unsigned char __RPC_FAR * __RPC_USER
+HPALETTE_UserMarshal (
+ unsigned long * pFlags,
+ unsigned char * pBuffer,
+ HPALETTE * pHPalette )
+{
+ if ( !pHPalette )
+ return pBuffer;
+
+ UserNdrDebugOut((UNDR_OUT4, "HPALETTE_UserMarshal\n"));
+
+ ALIGN( pBuffer, 3 );
+
+ // Discriminant of the encapsulated union and union arm.
+
+ if ( GDI_DATA_PASSING(*pFlags) )
+ {
+ // userHPALETTE
+
+ *( PULONG_LV_CAST pBuffer)++ = WDT_DATA_MARKER;
+ *( PULONG_LV_CAST pBuffer)++ = (ulong) *pHPalette;
+
+ if ( ! *pHPalette )
+ return pBuffer;
+
+ // rpcLOGPALETTE
+ // Logpalette is a conformant struct with a version field,
+ // size filed and conformant array of palentries.
+
+ // Determine the number of color entries in the palette
+
+ DWORD cEntries = GetPaletteEntries(*pHPalette, 0, 0, NULL);
+
+ // Conformant size
+
+ *( PULONG_LV_CAST pBuffer)++ = cEntries;
+
+ // Fields: both are short!
+ // The old code was just setting the version number.
+ // They say it has to be that way.
+
+ *( PUSHORT_LV_CAST pBuffer)++ = (ushort) 0x300;
+ *( PUSHORT_LV_CAST pBuffer)++ = (ushort) cEntries;
+
+ // Entries: each entry is a struct with 4 bytes.
+ // Calculate the resultant data size
+
+ DWORD cbData = cEntries * sizeof(PALETTEENTRY);
+
+ if (cbData)
+ {
+ if (0 == GetPaletteEntries( *pHPalette,
+ 0,
+ cEntries,
+ (PALETTEENTRY *)pBuffer ) )
+ {
+ RpcRaiseException(HRESULT_FROM_WIN32(GetLastError()));
+ }
+ pBuffer += cbData;
+ }
+ }
+ else
+ {
+ // Sending a handle.
+
+ *( PULONG_LV_CAST pBuffer)++ = WDT_HANDLE_MARKER;
+ *( PULONG_LV_CAST pBuffer)++ = (ulong) *(HANDLE *)pHPalette;
+ }
+
+ return( pBuffer );
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: HPALETTE_UserUnmarshall
+//
+// Synopsis: Unmarshalls an HPALETTE object from the RPC buffer.
+//
+// history: May-95 Ryszardk Created.
+//
+//--------------------------------------------------------------------------
+
+unsigned char __RPC_FAR * __RPC_USER
+HPALETTE_UserUnmarshal (
+ unsigned long * pFlags,
+ unsigned char * pBuffer,
+ HPALETTE * pHPalette )
+{
+ HPALETTE hPalette;
+
+ UserNdrDebugOut((UNDR_OUT4, "HPALETTE_UserUnmarshal\n"));
+
+ ALIGN( pBuffer, 3 );
+
+ unsigned long UnionDisc = *( PULONG_LV_CAST pBuffer)++;
+ hPalette = (HPALETTE) *( PULONG_LV_CAST pBuffer)++;
+
+ if ( IS_DATA_MARKER( UnionDisc) )
+ {
+ if ( hPalette )
+ {
+ // Get the conformant size.
+
+ DWORD cEntries = *( PULONG_LV_CAST pBuffer)++;
+ LOGPALETTE * pLogPal;
+
+ // If there are 0 color entries, we need to allocate the LOGPALETTE
+ // structure with the one dummy entry (it's a variably sized struct).
+ // Otherwise, we need to allocate enough space for the extra n-1
+ // entries at the tail of the structure
+
+ if (0 == cEntries)
+ {
+ pLogPal = (LOGPALETTE *) WdtpAllocate( pFlags,
+ sizeof(LOGPALETTE));
+ }
+ else
+ {
+ pLogPal = (LOGPALETTE *)
+ WdtpAllocate( pFlags,
+ sizeof(LOGPALETTE) +
+ (cEntries - 1) * sizeof(PALETTEENTRY));
+ }
+
+ pLogPal->palVersion = *( PUSHORT_LV_CAST pBuffer)++;
+ pLogPal->palNumEntries = *( PUSHORT_LV_CAST pBuffer)++;
+
+ // If there are entries, move them into out LOGPALETTE structure
+
+ if (cEntries)
+ {
+ memcpy( &(pLogPal->palPalEntry[0]),
+ pBuffer,
+ cEntries * sizeof(PALETTEENTRY) );
+ pBuffer += cEntries * sizeof(PALETTEENTRY);
+ }
+
+ // Attempt to create the palette
+
+ hPalette = CreatePalette(pLogPal);
+
+ // Success or failure, we're done with the LOGPALETTE structure
+
+ WdtpFree( pFlags, pLogPal );
+
+ // If the creation failed, raise an exception
+
+ if (NULL == hPalette)
+ {
+ RpcRaiseException(HRESULT_FROM_WIN32(GetLastError()));
+ }
+ }
+ }
+
+ // A new palette is ready, destroy the old one, if needed.
+
+ if ( *pHPalette )
+ DeleteObject( *pHPalette );
+
+ *pHPalette = hPalette;
+
+ return( pBuffer );
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: HPALETTE_UserFree
+//
+// Synopsis: Free an HPALETTE.
+//
+// history: May-95 Ryszardk Created.
+//
+//--------------------------------------------------------------------------
+
+void __RPC_USER
+HPALETTE_UserFree(
+ unsigned long * pFlags,
+ HPALETTE * pHPalette )
+{
+ UserNdrDebugOut((UNDR_OUT4, "HPALETTE_UserFree\n"));
+
+ if( pHPalette && *pHPalette )
+ {
+ if ( GDI_DATA_PASSING(*pFlags) )
+ {
+ DeleteObject( *pHPalette );
+ }
+ }
+}
+
+
+// #########################################################################
+//
+// NON REMOTABLE GDI and other HANDLES
+//
+// #########################################################################
+
+//+-------------------------------------------------------------------------
+//
+// Function: WdtpNonRemotableHandle_UserSize
+//
+// Synopsis: Get the wire size for a non remotable GDI handle.
+//
+// Derivation: Union of a long and nothing.
+// It is union just in case some remoting is needed.
+//
+// history: May-95 Ryszardk Created.
+//
+//--------------------------------------------------------------------------
+
+unsigned long __RPC_USER
+WdtpNonRemotableHandle_UserSize (
+ unsigned long * pFlags,
+ unsigned long Offset,
+ HANDLE * pHandle )
+{
+ if ( !pHandle || *pHandle == NULL )
+ return Offset;
+
+ if ( HGLOBAL_DATA_PASSING(*pFlags) )
+ RpcRaiseException(E_INVALIDARG );
+
+ LENGTH_ALIGN( Offset, 3 );
+
+ // The encapsulated union.
+ // No remote case on any platform.
+
+ return( Offset + 8 ) ;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: WdtpNonRemotableHandle_UserMarshal
+//
+// Synopsis: Marshalls a non-remotable handle into the RPC buffer.
+//
+// history: May-95 Ryszardk Created.
+//
+//--------------------------------------------------------------------------
+
+unsigned char __RPC_FAR * __RPC_USER
+WdtpNonRemotableHandle_UserMarshal (
+ unsigned long * pFlags,
+ unsigned char * pBuffer,
+ HANDLE * pHandle )
+{
+ if ( !pHandle || *pHandle == NULL )
+ return pBuffer;
+
+ ALIGN( pBuffer, 3 );
+
+ // Discriminant of the encapsulated union and union arm.
+
+ if ( HGLOBAL_DATA_PASSING(*pFlags) )
+ {
+ RpcRaiseException(E_INVALIDARG );
+ }
+ else
+ {
+ // Sending a handle.
+
+ *( PULONG_LV_CAST pBuffer)++ = WDT_HANDLE_MARKER;
+ *( PULONG_LV_CAST pBuffer)++ = (ulong) *(HANDLE *)pHandle;
+ }
+
+ return( pBuffer );
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: WdtpNonRemotableHandle_UserUnmarshal
+//
+// Synopsis: Unmarshalls a non-remotable handle from the RPC buffer.
+//
+// history: May-95 Ryszardk Created.
+//
+//--------------------------------------------------------------------------
+
+unsigned char __RPC_FAR * __RPC_USER
+WdtpNonRemotableHandle_UserUnmarshal (
+ unsigned long * pFlags,
+ unsigned char * pBuffer,
+ HANDLE * pHandle )
+{
+ ALIGN( pBuffer, 3 );
+
+ unsigned long UnionDisc = *( PULONG_LV_CAST pBuffer)++;
+
+ if ( IS_DATA_MARKER( UnionDisc) )
+ {
+ RpcRaiseException(E_INVALIDARG );
+ }
+ else
+ {
+ // Sending a handle.
+
+ *pHandle = (HANDLE) *( PULONG_LV_CAST pBuffer)++;
+ }
+
+ return( pBuffer );
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: WdtpNonRemotableHandle_UserFree
+//
+// Synopsis: Nothing to free.
+//
+//--------------------------------------------------------------------------
+
+void __RPC_USER
+WdtpNonRemotableGdiHandle_UserFree(
+ unsigned long * pFlags,
+ HANDLE * pHandle )
+{
+}
+
+
+
+// #########################################################################
+//
+// Interface pointers.
+//
+// #########################################################################
+
+//+-------------------------------------------------------------------------
+//
+// Function: WdtpInterfacePointer_UserSize
+//
+// Synopsis: Get the wire size for an interface pointer.
+//
+// history: May-95 Ryszardk Created.
+//
+//--------------------------------------------------------------------------
+
+unsigned long __RPC_USER
+WdtpInterfacePointer_UserSize (
+ USER_MARSHAL_CB * pContext,
+ unsigned long Flags,
+ unsigned long Offset,
+ IUnknown * pIf,
+ const IID & IId )
+{
+ if ( pIf )
+ {
+ LENGTH_ALIGN( Offset, 3 );
+
+ //Leave space for array bounds and length
+
+ Offset += 2 * sizeof(long);
+
+ HRESULT hr;
+ unsigned long cbSize = 0;
+
+ hr = CoGetMarshalSizeMax( &cbSize,
+ IId,
+ pIf,
+ USER_CALL_CTXT_MASK( Flags ),
+ pContext->pStubMsg->pvDestContext,
+ MSHLFLAGS_NORMAL );
+ if ( FAILED(hr) )
+ RpcRaiseException( hr );
+
+ Offset += cbSize;
+ }
+
+ return( Offset ) ;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: WdtpInterfacePointer_UserMarshal
+//
+// Synopsis: Marshalls an interface pointer.
+//
+// history: May-95 Ryszardk Created.
+//
+//--------------------------------------------------------------------------
+
+unsigned char __RPC_FAR * __RPC_USER
+WdtpInterfacePointer_UserMarshal (
+ USER_MARSHAL_CB * pContext,
+ unsigned long Flags,
+ unsigned char * pBuffer,
+ IUnknown * pIf,
+ const IID & IId )
+{
+ unsigned long * pMaxCount, *pSize;
+ unsigned long cbData = 0;
+
+ UserNdrDebugOut((UNDR_OUT1, "WdtpInterface_PointerMarshal\n"));
+
+ if ( pIf )
+ {
+ // Always marshaled because of the apartment model.
+
+ CStreamOnMessage MemStream( (unsigned char **) &pBuffer );
+
+ ALIGN( pBuffer, 3 );
+
+ pMaxCount = (unsigned long *) pBuffer;
+ pBuffer += 4;
+
+ // Leave space for length
+
+ pSize = (unsigned long *) pBuffer;
+ pBuffer += 4;
+
+ HRESULT hr;
+ unsigned char * pBufferMark = pBuffer;
+
+ hr = CoMarshalInterface( &MemStream,
+ IId,
+ pIf,
+ USER_CALL_CTXT_MASK( Flags ),
+ pContext->pStubMsg->pvDestContext,
+ MSHLFLAGS_NORMAL );
+ if( FAILED(hr) )
+ {
+ RpcRaiseException(hr);
+ }
+
+ // Calculate the size of the data written
+
+ DWORD cbData = pBuffer - pBufferMark;
+
+ // Update the array bounds.
+
+ *pMaxCount = cbData;
+ *pSize = cbData;
+ }
+
+ return( pBuffer );
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: WdtpInterfacePointer_UserUnmarshal
+//
+// Synopsis: Unmarshalls an interface pointer from the RPC buffer.
+//
+// history: May-95 Ryszardk Created.
+//
+//--------------------------------------------------------------------------
+
+unsigned char __RPC_FAR * __RPC_USER
+WdtpInterfacePointer_UserUnmarshal (
+ USER_MARSHAL_CB * pContext,
+ unsigned char * pBuffer,
+ IUnknown ** ppIf,
+ const IID & IId )
+{
+ unsigned long *pMaxCount, *pSize;
+ unsigned long cbData = 0;
+
+ UserNdrDebugOut((UNDR_OUT1, "WdtpInterfacePointerUnmarshal\n"));
+
+ // Always unmarshaled because of the apartment model.
+
+ CStreamOnMessage MemStream((unsigned char **) &pBuffer);
+
+ ALIGN( pBuffer, 3 );
+
+ pMaxCount = (unsigned long *) pBuffer;
+ pBuffer += sizeof(long);
+
+ //Unmarshal count
+ pSize = (unsigned long *) pBuffer;
+ pBuffer += sizeof(long);
+
+ // Release the old pointer after unmarshalling the new one
+ // to prevent object from getting released too early.
+ // Then release the old one only when successful.
+
+ IUnknown * punkTemp = 0;
+
+ HRESULT hr = CoUnmarshalInterface( &MemStream,
+ IId,
+ (void **) &punkTemp );
+ if(FAILED(hr))
+ RpcRaiseException(hr);
+ else
+ {
+ // On the client side, release the [in,out] interface pointer.
+ // The pointer may be different from NULL only on the client side.
+
+ if ( (IId == IID_IStorage || IId == IID_IStream ) && *ppIf )
+ {
+ // This may happen only on the client side.
+
+ // Throw away a new one when coming back to the client !!
+ // This is a pecularity of DocFile custom marshalling:
+ // pointer identity is broken.
+
+ if ( punkTemp )
+ punkTemp->Release();
+
+ // keep the old one
+ }
+ else
+ {
+ // release the old one, keep the new one.
+
+ if ( *ppIf )
+ (*ppIf)->Release();
+ *ppIf = punkTemp;
+ }
+ }
+
+
+ return( pBuffer );
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: WdtpInterfacePointer_UserFree
+//
+// Synopsis: Releases an interface pointer.
+//
+// history: May-95 Ryszardk Created.
+//
+//--------------------------------------------------------------------------
+
+void __RPC_USER
+WdtpInterfacePointer_UserFree(
+ IUnknown * pIf )
+{
+ UserNdrDebugOut((UNDR_OUT1, "WdtpInterfacePointer_UserFree\n"));
+
+ if( pIf )
+ {
+ pIf->Release();
+ }
+}
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: STGMEDIUM_UserSize
+//
+// Synopsis: Sizes a stgmedium pbject for RPC marshalling.
+//
+// history: May-95 Ryszardk Created.
+//
+//--------------------------------------------------------------------------
+
+unsigned long __RPC_USER
+STGMEDIUM_UserSize(
+ unsigned long * pFlags,
+ unsigned long Offset,
+ STGMEDIUM * pStgmed )
+{
+ if ( ! pStgmed )
+ return Offset;
+
+ LENGTH_ALIGN( Offset, 3 );
+
+ if ( pStgmed->tymed == TYMED_NULL )
+ Offset += sizeof(void*) + sizeof(long); // pointer, switch only
+ else
+ Offset += sizeof(void*) + sizeof(long) + sizeof(void*); // same + handle
+
+ // Pointee of the union arm.
+ // Only if the handle/pointer field is non-null.
+
+ if ( pStgmed->hGlobal )
+ {
+ switch( pStgmed->tymed )
+ {
+ case TYMED_NULL:
+ break;
+ case TYMED_MFPICT:
+ Offset = HMETAFILEPICT_UserSize( pFlags,
+ Offset,
+ &pStgmed->hMetaFilePict );
+ break;
+ case TYMED_ENHMF:
+ Offset = HENHMETAFILE_UserSize( pFlags,
+ Offset,
+ &pStgmed->hEnhMetaFile );
+ break;
+ case TYMED_GDI:
+
+ // A GDI object is not necesarrily a BITMAP. Therefore, we handle
+ // those types we know about based on the object type, and reject
+ // those which we do not support.
+
+ // switch for object type.
+
+ Offset += sizeof(long);
+
+ switch( GetObjectType( (HGDIOBJ)pStgmed->hBitmap ) )
+ {
+ case OBJ_BITMAP:
+ Offset = HBITMAP_UserSize( pFlags,
+ Offset,
+ &pStgmed->hBitmap );
+ break;
+
+ case OBJ_PAL:
+ Offset = HPALETTE_UserSize( pFlags,
+ Offset,
+ (HPALETTE *) & pStgmed->hBitmap );
+ break;
+
+ default:
+ RpcRaiseException(DV_E_TYMED);
+ break;
+ }
+ break;
+
+ case TYMED_HGLOBAL:
+ Offset = HGLOBAL_UserSize( pFlags,
+ Offset,
+ &pStgmed->hGlobal );
+ break;
+ case TYMED_FILE:
+ {
+ ulong ulDataSize = wcslen(pStgmed->lpszFileName) + 1;
+ Offset += 3 * sizeof(long); // [string]
+ Offset += ulDataSize * sizeof(wchar_t);
+ }
+ break;
+
+ case TYMED_ISTREAM:
+ case TYMED_ISTORAGE:
+ // Note, that we have to set the local flag for backward
+ // compatibility.
+
+ Offset = WdtpInterfacePointer_UserSize(
+ (USER_MARSHAL_CB *)pFlags,
+ MSHCTX_LOCAL,
+ Offset,
+ pStgmed->pstg,
+ ((pStgmed->tymed == TYMED_ISTREAM) ? IID_IStream
+ : IID_IStorage));
+ break;
+
+ default:
+ break;
+
+ }
+ }
+
+ // pUnkForRelease, if not null.
+
+ if ( pStgmed->pUnkForRelease )
+ Offset = WdtpInterfacePointer_UserSize( (USER_MARSHAL_CB *)pFlags,
+ *pFlags,
+ Offset,
+ pStgmed->pUnkForRelease,
+ IID_IUnknown );
+
+ return( Offset );
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: STGMEDIUM_UserMarshal
+//
+// Synopsis: Marshals a stgmedium pbject for RPC.
+//
+// history: May-95 Ryszardk Created.
+//
+//--------------------------------------------------------------------------
+
+unsigned char __RPC_FAR * __RPC_USER
+STGMEDIUM_UserMarshal(
+ unsigned long * pFlags,
+ unsigned char * pBufferStart,
+ STGMEDIUM * pStgmed )
+{
+ unsigned char * pBuffer;
+ unsigned char * pUnionArmMark;
+
+ if ( ! pStgmed )
+ return pBufferStart;
+
+ UserNdrDebugOut((UNDR_FORCE, "--STGMEDIUM_UserMarshal: %s\n", WdtpGetStgmedName(pStgmed)));
+
+ pBuffer = pBufferStart;
+ ALIGN( pBuffer, 3 );
+
+ // userSTGMEDIUM: if pointer, switch, union arm, .
+
+ *( PULONG_LV_CAST pBuffer)++ = (ulong)pStgmed->pUnkForRelease;
+ *( PULONG_LV_CAST pBuffer)++ = pStgmed->tymed;
+ pUnionArmMark = pBuffer;
+ if ( pStgmed->tymed != TYMED_NULL )
+ {
+ // hGlobal stands for any of these handles.
+
+ *( PULONG_LV_CAST pBuffer)++ = (ulong)pStgmed->hGlobal;
+ }
+
+ // Now the pointee of the union arm.
+ // We need to marshal only if the handle/pointer field is non null.
+ // Otherwise it is already in the buffer.
+
+ if ( pStgmed->hGlobal )
+ {
+ switch( pStgmed->tymed )
+ {
+ case TYMED_NULL:
+ break;
+ case TYMED_MFPICT:
+ pBuffer = HMETAFILEPICT_UserMarshal( pFlags,
+ pBuffer,
+ &pStgmed->hMetaFilePict );
+ break;
+ case TYMED_ENHMF:
+ pBuffer = HENHMETAFILE_UserMarshal( pFlags,
+ pBuffer,
+ &pStgmed->hEnhMetaFile );
+ break;
+ case TYMED_GDI:
+
+ {
+ // A GDI object is not necesarrily a BITMAP. Therefore, we handle
+ // those types we know about based on the object type, and reject
+ // those which we do not support.
+
+ ulong GdiObjectType = GetObjectType( (HGDIOBJ)pStgmed->hBitmap );
+
+ // GDI_OBJECT
+
+ *( PULONG_LV_CAST pBuffer)++ = GdiObjectType;
+
+
+
+ switch( GdiObjectType )
+ {
+ case OBJ_BITMAP:
+ pBuffer = HBITMAP_UserMarshal( pFlags,
+ pBuffer,
+ &pStgmed->hBitmap );
+ break;
+
+ case OBJ_PAL:
+ pBuffer = HPALETTE_UserMarshal( pFlags,
+ pBuffer,
+ (HPALETTE *) & pStgmed->hBitmap );
+ break;
+
+ default:
+ RpcRaiseException(DV_E_TYMED);
+ }
+ }
+ break;
+
+ case TYMED_HGLOBAL:
+ pBuffer = HGLOBAL_UserMarshal( pFlags,
+ pBuffer,
+ & pStgmed->hGlobal );
+ break;
+ case TYMED_FILE:
+ {
+ // We marshal it as a [string].
+
+ ulong Count = (pStgmed->lpszFileName)
+ ? wcslen(pStgmed->lpszFileName) + 1
+ : 0;
+
+ *( PULONG_LV_CAST pBuffer)++ = Count;
+ *( PULONG_LV_CAST pBuffer)++ = 0;
+ *( PULONG_LV_CAST pBuffer)++ = Count;
+ memcpy( pBuffer, pStgmed->lpszFileName, Count * sizeof(wchar_t) );
+ pBuffer += Count * sizeof(wchar_t);
+ }
+ break;
+
+ case TYMED_ISTREAM:
+ case TYMED_ISTORAGE:
+ // Note, that we have to set the local flag for backward compatibility.
+
+ pBuffer = WdtpInterfacePointer_UserMarshal(
+ ((USER_MARSHAL_CB *)pFlags),
+ MSHCTX_LOCAL,
+ pBuffer,
+ pStgmed->pstg,
+ ((pStgmed->tymed == TYMED_ISTREAM) ? IID_IStream
+ : IID_IStorage));
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ // Marker for this pointer is already in the buffer.
+
+ if ( pStgmed->pUnkForRelease )
+ pBuffer = WdtpInterfacePointer_UserMarshal( ((USER_MARSHAL_CB *)pFlags),
+ *pFlags,
+ pBuffer,
+ pStgmed->pUnkForRelease,
+ IID_IUnknown );
+
+ return( pBuffer );
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: STGMEDIUM_UserUnmarshal
+//
+// Synopsis: Unmarshals a stgmedium object for RPC.
+//
+// history: May-95 Ryszardk Created.
+//
+//--------------------------------------------------------------------------
+
+unsigned char __RPC_FAR * __RPC_USER
+STGMEDIUM_UserUnmarshal(
+ unsigned long * pFlags,
+ unsigned char * pBuffer,
+ STGMEDIUM * pStgmed )
+{
+ unsigned long fUnkForRelease;
+ unsigned long Handle = 0;
+
+ // if pointer, switch, union arm.
+
+ ALIGN( pBuffer, 3 );
+
+ // pUnkForRelease pointer marker.
+
+ fUnkForRelease = *( PULONG_LV_CAST pBuffer)++;
+ pStgmed->tymed = *( PULONG_LV_CAST pBuffer)++;
+
+ UserNdrDebugOut((UNDR_FORCE, "--STGMEDIUM_UserUnmarshal: %s\n", WdtpGetStgmedName(pStgmed) ));
+
+ if ( pStgmed->tymed != TYMED_NULL )
+ {
+ // handle or interface pointer (marker) from the buffer
+ Handle = *( PULONG_LV_CAST pBuffer)++;
+ }
+
+ // First pointee
+
+ // Union arm pointee.
+ // We need to unmarshal only if the handle/pointer field was not NULL.
+
+ if ( Handle )
+ {
+ switch( pStgmed->tymed )
+ {
+ case TYMED_NULL:
+ break;
+ case TYMED_MFPICT:
+ pBuffer = HMETAFILEPICT_UserUnmarshal( pFlags,
+ pBuffer,
+ &pStgmed->hMetaFilePict );
+ break;
+ case TYMED_ENHMF:
+ pBuffer = HENHMETAFILE_UserUnmarshal( pFlags,
+ pBuffer,
+ &pStgmed->hEnhMetaFile );
+ break;
+ case TYMED_GDI:
+ {
+ // A GDI object is not necesarrily a BITMAP. Therefore, we handle
+ // those types we know about based on the object type, and reject
+ // those which we do not support.
+
+ DWORD GdiObjectType = *( PULONG_LV_CAST pBuffer)++;
+
+ switch( GdiObjectType )
+ {
+ case OBJ_BITMAP:
+ pBuffer = HBITMAP_UserUnmarshal( pFlags,
+ pBuffer,
+ &pStgmed->hBitmap );
+ break;
+
+ case OBJ_PAL:
+ pBuffer = HPALETTE_UserUnmarshal( pFlags,
+ pBuffer,
+ (HPALETTE *) & pStgmed->hBitmap );
+ break;
+
+ default:
+ RpcRaiseException(DV_E_TYMED);
+ }
+ }
+ break;
+
+ case TYMED_HGLOBAL:
+ // reallocation is forbidden for [in-out] hglobal in STGMEDIUM.
+
+ pBuffer = WdtpGlobalUnmarshal( pFlags,
+ pBuffer,
+ & pStgmed->hGlobal,
+ FALSE ); // realloc flag
+ break;
+
+ case TYMED_FILE:
+ {
+ // We marshal it as a [string].
+
+ ulong Count = *( PULONG_LV_CAST pBuffer)++;
+ pBuffer += 8;
+
+ if ( ! pStgmed->lpszFileName )
+ pStgmed->lpszFileName = (LPOLESTR)
+ WdtpAllocate( pFlags,
+ Count * sizeof(wchar_t) );
+ memcpy( pStgmed->lpszFileName, pBuffer, Count * sizeof(wchar_t) );
+ pBuffer += Count * sizeof(wchar_t);
+ }
+ break;
+
+ case TYMED_ISTREAM:
+ case TYMED_ISTORAGE:
+ // Non null pointer, retrieve the interface pointer
+
+ pBuffer = WdtpInterfacePointer_UserUnmarshal(
+ (USER_MARSHAL_CB *)pFlags,
+ pBuffer,
+ (IUnknown **) &pStgmed->pstm,
+ ((pStgmed->tymed == TYMED_ISTREAM)
+ ? IID_IStream
+ : IID_IStorage));
+ break;
+
+ default:
+ break;
+ }
+ }
+ else
+ {
+ // New handle/pointer field is null, so release the previous one
+ // if it wasn't null.
+
+ if ( pStgmed->hGlobal )
+ {
+ // This should never happen for GetDataHere.
+
+ // Note, that we release the handle field, not the stgmedium itself.
+ // Accordingly, we don't follow punkForRelease.
+
+ UserNdrDebugOut((UNDR_FORCE, "--STGMEDIUM_UserUnmarshal: %s: NULL in, freeing old one\n", WdtpGetStgmedName(pStgmed)));
+
+ STGMEDIUM TmpStg = *pStgmed;
+ TmpStg.pUnkForRelease = NULL;
+
+ if ( pStgmed->tymed == TYMED_HGLOBAL )
+ {
+ // Cannot reallocate.
+ RpcRaiseException(DV_E_TYMED);
+ }
+ else
+ {
+ ReleaseStgMedium( &TmpStg );
+ }
+ }
+
+ pStgmed->hGlobal = 0;
+ }
+
+ if ( fUnkForRelease )
+ {
+ // There is an interface pointer on the wire.
+
+ pBuffer = WdtpInterfacePointer_UserUnmarshal( (USER_MARSHAL_CB *)pFlags,
+ pBuffer,
+ &pStgmed->pUnkForRelease,
+ IID_IUnknown );
+ }
+
+ if ( pStgmed->pUnkForRelease )
+ {
+ // Replace the app's punkForRelease with our custom release
+ // handler for special situations.
+
+ // The special situation is when a handle is remoted with data
+ // and so we have to clean up a side effect of having a data copy
+ // around. UserFree does it properly but we need that for the callee.
+ // When the callee releases a stgmed, it would invoke
+ // ReleaseStgMedium and this API doesn't do anything for handles
+ // when the punkForRelease is not NULL.
+
+ ULONG fHandleWithData = 0;
+ ULONG fTopLevelOnly = 0;
+
+ switch ( pStgmed->tymed )
+ {
+ case TYMED_HGLOBAL:
+ fHandleWithData = HGLOBAL_DATA_PASSING( *pFlags );
+ break;
+
+ case TYMED_ENHMF:
+ case TYMED_GDI:
+ fHandleWithData = GDI_DATA_PASSING( *pFlags );
+ break;
+
+ case TYMED_MFPICT:
+ fHandleWithData = HGLOBAL_DATA_PASSING( *pFlags );
+ fTopLevelOnly = fHandleWithData &&
+ ! GDI_DATA_PASSING( *pFlags );
+ break;
+
+ default:
+ break;
+ }
+
+ if ( fHandleWithData )
+ {
+ IUnknown *
+ punkTmp = (IUnknown *) new CPunkForRelease( pStgmed,
+ fTopLevelOnly );
+ if (!punkTmp)
+ {
+ RpcRaiseException(E_OUTOFMEMORY);
+ }
+
+ pStgmed->pUnkForRelease = punkTmp;
+ }
+ }
+
+ return( pBuffer );
+}
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: STGMEDIUM_UserFree
+//
+// Synopsis: Frees a stgmedium object for RPC.
+//
+// history: May-95 Ryszardk Created.
+//
+// Note: This routine is called from the freeing walk at server
+// or from the SetData *proxy*, when ownership has been passed.
+//
+//--------------------------------------------------------------------------
+
+EXTERN_C
+void NukeHandleAndReleasePunk(
+ STGMEDIUM * pStgmed )
+{
+ pStgmed->hGlobal = NULL;
+ pStgmed->tymed = TYMED_NULL;
+
+ if (pStgmed->pUnkForRelease)
+ {
+ pStgmed->pUnkForRelease->Release();
+ pStgmed->pUnkForRelease = 0;
+ }
+}
+
+void __RPC_USER
+STGMEDIUM_UserFree(
+ unsigned long * pFlags,
+ STGMEDIUM * pStgmed )
+{
+ UserNdrDebugOut((UNDR_FORCE, "--STGMEDIUM_UserFree: %s\n", WdtpGetStgmedName(pStgmed)));
+
+ if( pStgmed )
+ {
+ switch ( pStgmed->tymed )
+ {
+ case TYMED_FILE:
+ WdtpFree( pFlags, pStgmed->lpszFileName);
+ NukeHandleAndReleasePunk( pStgmed );
+ break;
+
+ case TYMED_NULL:
+ case TYMED_ISTREAM:
+ case TYMED_ISTORAGE:
+ ReleaseStgMedium( pStgmed );
+ break;
+
+ case TYMED_GDI:
+ case TYMED_ENHMF:
+
+ if ( GDI_HANDLE_PASSING(*pFlags) )
+ {
+ NukeHandleAndReleasePunk( pStgmed );
+ }
+ else
+ {
+ // Handle w/data: there is a side effect to clean up.
+ // For punk !=0, this will go to our CPunk object.
+
+ ReleaseStgMedium( pStgmed );
+ }
+ break;
+
+ case TYMED_HGLOBAL:
+
+ if ( HGLOBAL_HANDLE_PASSING(*pFlags) )
+ {
+ NukeHandleAndReleasePunk( pStgmed );
+ }
+ else
+ {
+ // Handle w/data: there is a side effect to clean up.
+ // For punk ==0, this will just release the data.
+ // For punk !=0, this will go to our CPunk object,
+ // release the data, and then call the original punk.
+
+ ReleaseStgMedium( pStgmed );
+ }
+ break;
+
+ case TYMED_MFPICT:
+
+ if ( HGLOBAL_HANDLE_PASSING(*pFlags) )
+ {
+ NukeHandleAndReleasePunk( pStgmed );
+ }
+ else if ( GDI_HANDLE_PASSING(*pFlags) )
+ {
+ if ( pStgmed->hGlobal )
+ GlobalFree( pStgmed->hGlobal );
+ NukeHandleAndReleasePunk( pStgmed );
+ }
+ else
+ {
+ // Handle w/data: there is a side effect to clean up.
+ // For punk !=0, this will go to our CPunk object.
+
+ ReleaseStgMedium( pStgmed );
+ }
+ break;
+
+ default:
+ RpcRaiseException( E_INVALIDARG );
+ break;
+ }
+ }
+}
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: FLAG_STGMEDIUM_UserSize
+//
+// Synopsis: Sizes a wrapper for stgmedium.
+//
+// history: May-95 Ryszardk Created.
+//
+//--------------------------------------------------------------------------
+
+unsigned long __RPC_USER
+FLAG_STGMEDIUM_UserSize(
+ unsigned long * pFlags,
+ unsigned long Offset,
+ FLAG_STGMEDIUM* pFlagStgmed )
+{
+ if ( ! pFlagStgmed )
+ return Offset;
+
+ LENGTH_ALIGN( Offset, 3 );
+
+ Offset += sizeof(long);
+ Offset = STGMEDIUM_UserSize( pFlags, Offset, & pFlagStgmed->Stgmed );
+
+ return( Offset );
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: FLAG_STGMEDIUM_UserMarshal
+//
+// Synopsis: Marshals a wrapper for stgmedium. Used in SetData.
+//
+// history: May-95 Ryszardk Created.
+//
+//--------------------------------------------------------------------------
+
+unsigned char __RPC_FAR * __RPC_USER
+FLAG_STGMEDIUM_UserMarshal(
+ unsigned long * pFlags,
+ unsigned char * pBuffer,
+ FLAG_STGMEDIUM* pFlagStgmed )
+{
+ if ( ! pFlagStgmed )
+ return pBuffer;
+
+ ALIGN( pBuffer, 3 );
+
+ // Flags: we need them when freeing in the client call_as routine
+
+ pFlagStgmed->ContextFlags = *pFlags;
+
+ *( PULONG_LV_CAST pBuffer)++ = *pFlags;
+ *( PULONG_LV_CAST pBuffer)++ = pFlagStgmed->fPassOwnership;
+
+ pBuffer = STGMEDIUM_UserMarshal( pFlags,
+ pBuffer,
+ & pFlagStgmed->Stgmed );
+
+ return( pBuffer );
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: FLAG_STGMEDIUM_UserUnmarshal
+//
+// Synopsis: Unmarshals a wrapper for stgmedium.
+//
+// history: May-95 Ryszardk Created.
+//
+//--------------------------------------------------------------------------
+
+unsigned char __RPC_FAR * __RPC_USER
+FLAG_STGMEDIUM_UserUnmarshal(
+ unsigned long * pFlags,
+ unsigned char * pBuffer,
+ FLAG_STGMEDIUM* pFlagStgmed )
+{
+ ALIGN( pBuffer, 3 );
+
+ // Flags and buffer marker
+
+ pFlagStgmed->ContextFlags = *( PULONG_LV_CAST pBuffer)++;
+
+ // We need that in the Proxy, when we call the user free routine.
+
+ pFlagStgmed->fPassOwnership = *( PULONG_LV_CAST pBuffer)++;
+ pFlagStgmed->ContextFlags = *pFlags;
+
+ // We always unmarshal a FLAG_STGMEDIUM object.
+ // The engine will always free the FLAG_STGMEDIUM object later.
+ // Adjustments for passing the ownership are done within SetData_Stub.
+
+ pBuffer = STGMEDIUM_UserUnmarshal( pFlags,
+ pBuffer,
+ & pFlagStgmed->Stgmed );
+ return( pBuffer );
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: FLAG_STGMEDIUM_UserFree
+//
+// Synopsis: Freess a wrapper for stgmedium.
+//
+// history: May-95 Ryszardk Created.
+//
+//--------------------------------------------------------------------------
+
+void __RPC_USER
+FLAG_STGMEDIUM_UserFree(
+ unsigned long * pFlags,
+ FLAG_STGMEDIUM* pFlagsStgmed )
+{
+ if ( ! pFlagsStgmed->fPassOwnership )
+ STGMEDIUM_UserFree( pFlags, & pFlagsStgmed->Stgmed );
+
+ // else the callee is supposed to release the stg medium.
+}
+
+
+#if (DBG==1)
+//+-------------------------------------------------------------------------
+//
+// Function: WdtpGetStgmedName
+//
+// Synopsis: Debug support
+//
+// history: May-95 Ryszardk Created.
+//
+//--------------------------------------------------------------------------
+
+char *
+WdtpGetStgmedName( STGMEDIUM * pStgmed)
+
+{
+ char * Name;
+ if ( pStgmed )
+ {
+ switch (pStgmed->tymed)
+ {
+ case TYMED_NULL:
+ Name = "TYMED_NULL";
+ break;
+ case TYMED_MFPICT:
+ Name = "TYMED_MFPICT";
+ break;
+ case TYMED_ENHMF:
+ Name = "TYMED_ENHMF";
+ break;
+ case TYMED_GDI:
+ Name = "TYMED_GDI";
+ break;
+ case TYMED_HGLOBAL:
+ Name = "TYMED_HGLOBAL";
+ break;
+ case TYMED_FILE:
+ Name = "TYMED_FILE";
+ break;
+ case TYMED_ISTREAM:
+ Name = "TYMED_ISTREAM";
+ break;
+ case TYMED_ISTORAGE:
+ Name = "TYMED_ISTORAGE";
+ break;
+ default:
+ Name = "TYMED invalid";
+ break;
+ }
+ return Name;
+ }
+ else
+ return "STGMED * is null";
+}
+#endif
+
diff --git a/private/oleutest/balls/oleprx32/proxy/transmit.h b/private/oleutest/balls/oleprx32/proxy/transmit.h
new file mode 100644
index 000000000..187c7a6c8
--- /dev/null
+++ b/private/oleutest/balls/oleprx32/proxy/transmit.h
@@ -0,0 +1,145 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1994.
+//
+// File: transmit.h
+//
+// Contents: Function prototypes for STGMEDIUM marshalling.
+//
+// Functions: STGMEDIUM_to_xmit
+// STGMEDIUM_from_xmit
+// STGMEDIUM_free_inst
+//
+// History: May-10-94 ShannonC Created
+// History: May-10-95 Ryszardk wire_marshal changes
+//
+//--------------------------------------------------------------------------
+
+#ifndef __TRANSMIT_H__
+#define __TRANSMIT_H__
+
+#if (DBG==1)
+
+#include <debnot.h>
+
+DECLARE_DEBUG(UserNdr)
+//
+#define UserNdrDebugOut(x)
+#define UserNdrAssert(x)
+#define UserNdrVerify(x)
+
+//#define UNDR_FORCE DEB_FORCE
+#define UNDR_FORCE 0
+#define UNDR_OUT1 0
+#define UNDR_OUT4 0
+
+EXTERN_C char *
+WdtpGetStgmedName( STGMEDIUM * );
+
+#else
+
+#define UserNdrDebugOut(x)
+#define UserNdrAssert(x)
+#define UserNdrVerify(x)
+
+#define UNDR_FORCE 0
+#define UNDR_OUT1 0
+#define UNDR_OUT4 0
+
+#endif
+
+// Shortcut typedefs.
+
+typedef unsigned char uchar;
+typedef unsigned short ushort;
+typedef unsigned long ulong;
+typedef unsigned int uint;
+
+#ifndef TRUE
+#define TRUE (1)
+#define FALSE (0)
+
+typedef unsigned short BOOL;
+#endif
+
+#define ALIGN( pStuff, cAlign ) \
+ pStuff = (unsigned char *)((ulong)((pStuff) + (cAlign)) & ~ (cAlign))
+
+#define LENGTH_ALIGN( Length, cAlign ) \
+ Length = (((Length) + (cAlign)) & ~ (cAlign))
+
+#define PCHAR_LV_CAST *(char __RPC_FAR * __RPC_FAR *)&
+#define PSHORT_LV_CAST *(short __RPC_FAR * __RPC_FAR *)&
+#define PLONG_LV_CAST *(long __RPC_FAR * __RPC_FAR *)&
+#define PHYPER_LV_CAST *(hyper __RPC_FAR * __RPC_FAR *)&
+
+#define PUSHORT_LV_CAST *(unsigned short __RPC_FAR * __RPC_FAR *)&
+#define PULONG_LV_CAST *(unsigned long __RPC_FAR * __RPC_FAR *)&
+
+#define USER_MARSHAL_MARKER 0x72657355
+
+// These are based on flags defined in wtypes.idl comming from the channel
+
+#define INPROC_CALL( Flags) (USER_CALL_CTXT_MASK(Flags) == MSHCTX_INPROC)
+#define REMOTE_CALL( Flags) ((USER_CALL_CTXT_MASK(Flags) == MSHCTX_DIFFERENTMACHINE) \
+ || (USER_CALL_CTXT_MASK(Flags) == MSHCTX_NOSHAREDMEM))
+
+// There is a difference in the scope of handles, Daytona vs. Chicago.
+// The following is an illustration of the notions of strict and lax passing.
+
+// rpc call as defined by the flags above
+
+// Daytona rules
+//I------------I----------------I-----------------------------------I
+//I inproc I same machine I diff. machine (a.k.a "remote" ) I
+//I------------I----------------------------------------------------I
+//| HGLOBL h.p.| HGLOBAL data passing |
+//|------------|----------------------------------------------------|
+//| GDI h.p. | GDI data passing |
+//|------------|----------------------------------------------------|
+
+// Chicago rules
+//I------------I----------------I-----------------------------------I
+//I inproc I same machine I diff. machine (a.k.a "remote" ) I
+//I------------I----------------------------------------------------I
+//| HGLOBL h.p.| HGLOBAL data passing |
+//|-----------------------------------------------------------------|
+//| GDI handle passing | GDI data passing |
+//|-----------------------------|-----------------------------------|
+
+#define HGLOBAL_HANDLE_PASSING( Flags ) INPROC_CALL( Flags)
+#define HGLOBAL_DATA_PASSING( Flags ) (! INPROC_CALL( Flags))
+
+// On Chicago, some handles are valid between processes.
+
+#if defined(_CHICAGO_)
+#define GDI_HANDLE_PASSING( Flags ) (! REMOTE_CALL( Flags ))
+#define GDI_DATA_PASSING( Flags ) REMOTE_CALL( Flags )
+#else
+#define GDI_HANDLE_PASSING( Flags ) HGLOBAL_HANDLE_PASSING( Flags )
+#define GDI_DATA_PASSING( Flags ) HGLOBAL_DATA_PASSING( Flags )
+#endif
+
+#define WDT_DATA_MARKER WDT_REMOTE_CALL
+#define WDT_HANDLE_MARKER WDT_INPROC_CALL
+#define IS_DATA_MARKER( dw ) (WDT_REMOTE_CALL == dw)
+
+#define WdtpMemoryCopy(Destination, Source, Length) \
+ RtlCopyMemory(Destination, Source, Length)
+#define WdtpZeroMemory(Destination, Length) \
+ RtlZeroMemory(Destination, Length)
+
+#define WdtpAllocate(p,size) \
+ ((USER_MARSHAL_CB *)p)->pStubMsg->pfnAllocate( size )
+#define WdtpFree(pf,ptr) \
+ ((USER_MARSHAL_CB *)pf)->pStubMsg->pfnFree( ptr )
+
+EXTERN_C
+void NukeHandleAndReleasePunk(
+ STGMEDIUM * pStgmed );
+
+#endif // __TRANSMIT_H__
+
+
+
diff --git a/private/oleutest/balls/oleprx32/uuid/daytona/makefile b/private/oleutest/balls/oleprx32/uuid/daytona/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/oleutest/balls/oleprx32/uuid/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/balls/oleprx32/uuid/daytona/sources b/private/oleutest/balls/oleprx32/uuid/daytona/sources
new file mode 100644
index 000000000..107bccf3d
--- /dev/null
+++ b/private/oleutest/balls/oleprx32/uuid/daytona/sources
@@ -0,0 +1,25 @@
+#+---------------------------------------------------------------------------
+#
+# Microsoft Windows
+# Copyright (C) Microsoft Corporation, 1992 - 1993.
+#
+# File: sources
+#
+# History: 02-Aug-94 LyleC Created
+#
+#----------------------------------------------------------------------------
+
+MAJORCOMP=oleprx32
+MINORCOMP=uuid
+TARGETNAME=uuid
+
+TARGETPATH=obj
+TARGETTYPE=LIBRARY
+
+# All of the files listed below except cguid_i.c are generated by MIDL
+
+SOURCES= ..\iballs_i.c \
+ ..\icube_i.c \
+ ..\ibtest_i.c \
+ ..\iloop_i.c \
+ ..\rpctst_i.c
diff --git a/private/oleutest/balls/oleprx32/uuid/dirs b/private/oleutest/balls/oleprx32/uuid/dirs
new file mode 100644
index 000000000..8f1bf9100
--- /dev/null
+++ b/private/oleutest/balls/oleprx32/uuid/dirs
@@ -0,0 +1,24 @@
+!if 0
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: dirs
+//
+// Contents: dirs files for NT types project.
+//
+//
+// Functions:
+//
+// History: 12-20-93 terryru Created
+//
+//----------------------------------------------------------------------------
+
+!endif
+
+DIRS=
+OPTIONAL_DIRS= \
+ daytona \
+ \
+
diff --git a/private/oleutest/balls/public.sed b/private/oleutest/balls/public.sed
new file mode 100644
index 000000000..3cf97fd01
--- /dev/null
+++ b/private/oleutest/balls/public.sed
@@ -0,0 +1,13 @@
+s/ This sed script extracts the public sections of header files. //
+/^[ ]*\/[\/\*][ ]*\$PUBLIC/!{
+ d
+}
+:x
+N
+s;.*\n;;
+/^[ ]*\/[\/\*][ ]*\$ENDPUBLIC/!{
+ p
+ b x
+}
+d
+
diff --git a/private/oleutest/balls/rcfiles.sed b/private/oleutest/balls/rcfiles.sed
new file mode 100644
index 000000000..fd54493e3
--- /dev/null
+++ b/private/oleutest/balls/rcfiles.sed
@@ -0,0 +1,36 @@
+# //+-------------------------------------------------------------------------
+# //
+# // Copyright (C) 1993, Microsoft Corporation.
+# //
+# // File: rcfiles.sed
+# //
+# // Contents: Sed script to convert a list of rc files into a header
+# // file that can be compiled with RC. This is to workaround
+# // a "feature" of COFF that only one resource obj can be used
+# // for any one image...
+# //
+# // History: 17-May-93 BryanT Created
+# //
+# // Notes: sed -f rcfiles.sed file.tmp > foo.rc
+# //
+# //--------------------------------------------------------------------------
+#
+# The input file will look like this:
+# .\foo.rc
+#
+# .\version.rc
+#
+#
+# 1. We strip out all the blank lines (lines that don't contain a period)
+# 2. Add #include< to the beginning of each line.
+# 3. Add > to the end of each line.
+#
+# When finished, the file looks like this:
+#
+# #include <.\foo.rc>
+# #include <.\version.rc>
+#
+
+/\./!d
+s/^/\#include\</g
+s/$/\>/g
diff --git a/private/oleutest/balls/srv/balls/ballsrv.cxx b/private/oleutest/balls/srv/balls/ballsrv.cxx
new file mode 100644
index 000000000..9ed5cb132
--- /dev/null
+++ b/private/oleutest/balls/srv/balls/ballsrv.cxx
@@ -0,0 +1,42 @@
+//+-------------------------------------------------------------------
+//
+// File: srvmain.cxx
+//
+// Contents: This file contins the EXE entry points
+// WinMain
+//
+// Classes:
+//
+// History: 30-Nov-92 SarahJ Created
+//
+//---------------------------------------------------------------------
+#include <common.h>
+#include <ballscf.hxx>
+
+
+//+-------------------------------------------------------------------
+//
+// Function: WinMain
+//
+// Synopsis: Entry point to DLL - does little else
+//
+// Arguments:
+//
+// Returns: TRUE
+//
+// History: 21-Nov-92 SarahJ Created
+//
+//--------------------------------------------------------------------
+int WINAPI WinMain(
+ HINSTANCE hInstance,
+ HINSTANCE hPrevInstance,
+ LPSTR lpCmdLine,
+ int nCmdShow)
+{
+ CBallClassFactory *pCF = new CBallClassFactory(NULL);
+
+ int sc = SrvMain(hInstance, CLSID_Balls, REGCLS_MULTIPLEUSE,
+ TEXT("Balls Server"), pCF);
+
+ return sc;
+}
diff --git a/private/oleutest/balls/srv/balls/daytona/makefile b/private/oleutest/balls/srv/balls/daytona/makefile
new file mode 100644
index 000000000..1d3728d41
--- /dev/null
+++ b/private/oleutest/balls/srv/balls/daytona/makefile
@@ -0,0 +1,10 @@
+############################################################################
+#
+# Copyright (C) 1992, Microsoft Corporation.
+#
+# All rights reserved.
+#
+############################################################################
+
+!include $(NTMAKEENV)\makefile.def
+
diff --git a/private/oleutest/balls/srv/balls/daytona/sources b/private/oleutest/balls/srv/balls/daytona/sources
new file mode 100644
index 000000000..b9f495b35
--- /dev/null
+++ b/private/oleutest/balls/srv/balls/daytona/sources
@@ -0,0 +1,54 @@
+!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.
+
+!ENDIF
+
+#
+# The following includes a global include file defined at the
+# base of the project for all components
+#
+
+!include ..\..\daytona.inc
+
+#
+# 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= ballsrv
+
+#
+# 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
+
+
+INLCUDES= $(INCLUDES)
+C_DEFINES= $(C_DEFINES)
+
+
+
+SOURCES= \
+ ..\ballsrv.cxx
diff --git a/private/oleutest/balls/srv/balls/dirs b/private/oleutest/balls/srv/balls/dirs
new file mode 100644
index 000000000..1d0b9edbb
--- /dev/null
+++ b/private/oleutest/balls/srv/balls/dirs
@@ -0,0 +1,38 @@
+!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/balls/srv/cairo.inc b/private/oleutest/balls/srv/cairo.inc
new file mode 100644
index 000000000..50e6cdfa2
--- /dev/null
+++ b/private/oleutest/balls/srv/cairo.inc
@@ -0,0 +1,38 @@
+!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.
+
+
+!ENDIF
+
+!include ..\..\..\cairo.inc
+
+
+UMTYPE= windows
+UMENTRY= winmain
+UMAPPL=
+UMTEST=
+UMLIBS= ..\..\..\oleprx32\uuid\cairo\obj\*\uuid.lib \
+ ..\..\..\common\cairo\obj\*\servers.lib \
+ $(OLEDIR)\com\port\cairo\obj\*\port.lib \
+ $(BASEDIR)\public\sdk\lib\*\uuid.lib \
+ $(BASEDIR)\public\sdk\lib\cairo\*\ole32.lib \
+ $(BASEDIR)\public\sdk\lib\*\rpcndr.lib \
+ $(BASEDIR)\public\sdk\lib\*\rpcrt4.lib \
+ $(BASEDIR)\public\sdk\lib\*\rpcns4.lib \
+ $(BASEDIR)\public\sdk\lib\*\mpr.lib \
+ $(BASEDIR)\public\sdk\lib\*\netapi32.lib \
+ $(BASEDIR)\public\sdk\lib\*\kernel32.lib \
+ $(BASEDIR)\public\sdk\lib\*\user32.lib \
+ $(BASEDIR)\public\sdk\lib\*\advapi32.lib
diff --git a/private/oleutest/balls/srv/chicago.inc b/private/oleutest/balls/srv/chicago.inc
new file mode 100644
index 000000000..66656b8b5
--- /dev/null
+++ b/private/oleutest/balls/srv/chicago.inc
@@ -0,0 +1,51 @@
+!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:
+
+ David Plummer (davepl) 19-Mar-94
+
+ Modifed by via awk to include global project include file
+ and to wrap precompiled header line within a conditional
+ that can be set in this include file.
+
+ Donna Liu (DonnaLi) 19-Dec-1993
+
+!ENDIF
+
+
+!include ..\..\..\chicago.inc
+
+INCLUDES= ;..;$(OLEBALLSDIR)\common;
+INCLUDES= $(INCLUDES);$(OLEUTESTDIR)\balls\oleprx32\chicago
+
+UMTYPE= windows
+UMENTRY= winmain
+UMAPPL=
+UMTEST=
+UMLIBS= ..\..\..\oleprx32\uuid\chicago\obj\*\uuid.lib \
+ ..\..\..\common\chicago\obj\*\servers.lib \
+ $(OLEDIR)\common\chicago\obj\*\common.lib \
+ $(BASEDIR)\public\sdk\lib\*\uuid.lib \
+ $(BASEDIR)\public\sdk\lib\*\ole32.lib \
+ $(BASEDIR)\public\sdk\lib\*\rpcndr.lib \
+ $(BASEDIR)\public\sdk\lib\*\rpcrt4.lib \
+ $(BASEDIR)\public\sdk\lib\*\rpcns4.lib \
+ $(BASEDIR)\public\sdk\lib\*\mpr.lib \
+ $(BASEDIR)\public\sdk\lib\*\netapi32.lib \
+ $(BASEDIR)\public\sdk\lib\*\kernel32.lib \
+ $(BASEDIR)\public\sdk\lib\*\user32.lib \
+ $(BASEDIR)\public\sdk\lib\*\advapi32.lib
diff --git a/private/oleutest/balls/srv/cubes/cubesrv.cxx b/private/oleutest/balls/srv/cubes/cubesrv.cxx
new file mode 100644
index 000000000..9f65da648
--- /dev/null
+++ b/private/oleutest/balls/srv/cubes/cubesrv.cxx
@@ -0,0 +1,41 @@
+//+-------------------------------------------------------------------
+//
+// File: srvmain.cxx
+//
+// Contents: This file contins the EXE entry points
+// WinMain
+//
+// Classes:
+//
+// History: 30-Nov-92 SarahJ Created
+//
+//---------------------------------------------------------------------
+#include <common.h>
+#include <cubescf.hxx>
+
+//+-------------------------------------------------------------------
+//
+// Function: WinMain
+//
+// Synopsis: Entry point to DLL - does little else
+//
+// Arguments:
+//
+// Returns: TRUE
+//
+// History: 21-Nov-92 SarahJ Created
+//
+//--------------------------------------------------------------------
+int WINAPI WinMain(
+ HINSTANCE hInstance,
+ HINSTANCE hPrevInstance,
+ LPSTR lpCmdLine,
+ int nCmdShow)
+{
+ CCubesClassFactory *pCF = new CCubesClassFactory();
+
+ int sc = SrvMain(hInstance, CLSID_Cubes, REGCLS_MULTIPLEUSE,
+ TEXT("Cubes Server"), pCF);
+
+ return sc;
+}
diff --git a/private/oleutest/balls/srv/cubes/daytona/makefile b/private/oleutest/balls/srv/cubes/daytona/makefile
new file mode 100644
index 000000000..1d3728d41
--- /dev/null
+++ b/private/oleutest/balls/srv/cubes/daytona/makefile
@@ -0,0 +1,10 @@
+############################################################################
+#
+# Copyright (C) 1992, Microsoft Corporation.
+#
+# All rights reserved.
+#
+############################################################################
+
+!include $(NTMAKEENV)\makefile.def
+
diff --git a/private/oleutest/balls/srv/cubes/daytona/sources b/private/oleutest/balls/srv/cubes/daytona/sources
new file mode 100644
index 000000000..53d0da37a
--- /dev/null
+++ b/private/oleutest/balls/srv/cubes/daytona/sources
@@ -0,0 +1,54 @@
+!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.
+
+!ENDIF
+
+#
+# The following includes a global include file defined at the
+# base of the project for all components
+#
+
+!include ..\..\daytona.inc
+
+#
+# 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= cubesrv
+
+#
+# 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= $(INCLUDES)
+C_DEFINES= $(C_DEFINES)
+
+
+
+SOURCES= \
+ ..\cubesrv.cxx
diff --git a/private/oleutest/balls/srv/cubes/dirs b/private/oleutest/balls/srv/cubes/dirs
new file mode 100644
index 000000000..1d0b9edbb
--- /dev/null
+++ b/private/oleutest/balls/srv/cubes/dirs
@@ -0,0 +1,38 @@
+!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/balls/srv/daytona.inc b/private/oleutest/balls/srv/daytona.inc
new file mode 100644
index 000000000..55b630a8a
--- /dev/null
+++ b/private/oleutest/balls/srv/daytona.inc
@@ -0,0 +1,51 @@
+!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:
+
+ David Plummer (davepl) 19-Mar-94
+
+ Modifed by via awk to include global project include file
+ and to wrap precompiled header line within a conditional
+ that can be set in this include file.
+
+ Donna Liu (DonnaLi) 19-Dec-1993
+
+!ENDIF
+
+
+!include ..\..\..\daytona.inc
+
+INCLUDES= ;..;$(OLEBALLSDIR)\common;
+INCLUDES= $(INCLUDES);$(OLEUTESTDIR)\balls\oleprx32\daytona
+
+UMTYPE= windows
+UMENTRY= winmain
+UMAPPL=
+UMTEST=
+UMLIBS= ..\..\..\oleprx32\uuid\daytona\obj\*\uuid.lib \
+ ..\..\..\common\daytona\obj\*\servers.lib \
+ $(OLEDIR)\common\daytona\obj\*\common.lib \
+ $(BASEDIR)\public\sdk\lib\*\uuid.lib \
+ $(BASEDIR)\public\sdk\lib\*\ole32.lib \
+ $(BASEDIR)\public\sdk\lib\*\rpcndr.lib \
+ $(BASEDIR)\public\sdk\lib\*\rpcrt4.lib \
+ $(BASEDIR)\public\sdk\lib\*\rpcns4.lib \
+ $(BASEDIR)\public\sdk\lib\*\mpr.lib \
+ $(BASEDIR)\public\sdk\lib\*\netapi32.lib \
+ $(BASEDIR)\public\sdk\lib\*\kernel32.lib \
+ $(BASEDIR)\public\sdk\lib\*\user32.lib \
+ $(BASEDIR)\public\sdk\lib\*\advapi32.lib
diff --git a/private/oleutest/balls/srv/dirs b/private/oleutest/balls/srv/dirs
new file mode 100644
index 000000000..3cee9b246
--- /dev/null
+++ b/private/oleutest/balls/srv/dirs
@@ -0,0 +1,42 @@
+!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= \
+ mixed \
+ balls \
+ cubes \
+ loops \
+ rpctst \
+ qi \
+ mdi
+
+#
+# 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=
diff --git a/private/oleutest/balls/srv/distbind/daytona/makefile b/private/oleutest/balls/srv/distbind/daytona/makefile
new file mode 100644
index 000000000..1d3728d41
--- /dev/null
+++ b/private/oleutest/balls/srv/distbind/daytona/makefile
@@ -0,0 +1,10 @@
+############################################################################
+#
+# Copyright (C) 1992, Microsoft Corporation.
+#
+# All rights reserved.
+#
+############################################################################
+
+!include $(NTMAKEENV)\makefile.def
+
diff --git a/private/oleutest/balls/srv/distbind/daytona/sources b/private/oleutest/balls/srv/distbind/daytona/sources
new file mode 100644
index 000000000..e48ed69d8
--- /dev/null
+++ b/private/oleutest/balls/srv/distbind/daytona/sources
@@ -0,0 +1,53 @@
+!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.
+
+!ENDIF
+
+#
+# The following includes a global include file defined at the
+# base of the project for all components
+#
+
+!include ..\..\daytona.inc
+
+#
+# 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= db
+
+#
+# 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= $(INCLUDES)
+C_DEFINES= $(C_DEFINES)
+
+
+SOURCES= \
+ ..\db.cxx
diff --git a/private/oleutest/balls/srv/distbind/db.cxx b/private/oleutest/balls/srv/distbind/db.cxx
new file mode 100644
index 000000000..08ac63076
--- /dev/null
+++ b/private/oleutest/balls/srv/distbind/db.cxx
@@ -0,0 +1,42 @@
+//+-------------------------------------------------------------------
+//
+// File: mdi.cxx
+//
+// Contents: This file contins the DLL entry points
+// WinMain
+//
+// Classes:
+//
+// History: 30-Nov-92 SarahJ Created
+//
+//---------------------------------------------------------------------
+#include <common.h>
+#include <actcf.hxx>
+
+
+//+-------------------------------------------------------------------
+//
+// Function: WinMain
+//
+// Synopsis: Entry point to DLL - does little else
+//
+// Arguments:
+//
+// Returns: TRUE
+//
+// History: 21-Nov-92 SarahJ Created
+//
+//--------------------------------------------------------------------
+int WINAPI WinMain(
+ HINSTANCE hInstance,
+ HINSTANCE hPrevInstance,
+ LPSTR lpCmdLine,
+ int nCmdShow)
+{
+ CActClassFactory *pCF = new CActClassFactory(CLSID_DistBind ,TRUE);
+
+ int sc = SrvMain(hInstance, CLSID_DistBind, REGCLS_MULTIPLEUSE,
+ TEXT("DistBind Server"), pCF);
+
+ return sc;
+}
diff --git a/private/oleutest/balls/srv/distbind/dirs b/private/oleutest/balls/srv/distbind/dirs
new file mode 100644
index 000000000..1d0b9edbb
--- /dev/null
+++ b/private/oleutest/balls/srv/distbind/dirs
@@ -0,0 +1,38 @@
+!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/balls/srv/loops/daytona/makefile b/private/oleutest/balls/srv/loops/daytona/makefile
new file mode 100644
index 000000000..1d3728d41
--- /dev/null
+++ b/private/oleutest/balls/srv/loops/daytona/makefile
@@ -0,0 +1,10 @@
+############################################################################
+#
+# Copyright (C) 1992, Microsoft Corporation.
+#
+# All rights reserved.
+#
+############################################################################
+
+!include $(NTMAKEENV)\makefile.def
+
diff --git a/private/oleutest/balls/srv/loops/daytona/sources b/private/oleutest/balls/srv/loops/daytona/sources
new file mode 100644
index 000000000..95f205aa3
--- /dev/null
+++ b/private/oleutest/balls/srv/loops/daytona/sources
@@ -0,0 +1,53 @@
+!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.
+
+!ENDIF
+
+#
+# The following includes a global include file defined at the
+# base of the project for all components
+#
+
+!include ..\..\daytona.inc
+
+#
+# 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= loopsrv
+
+#
+# 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= $(INCLUDES)
+C_DEFINES= $(C_DEFINES)
+
+
+SOURCES= \
+ ..\loopsrv.cxx
diff --git a/private/oleutest/balls/srv/loops/dirs b/private/oleutest/balls/srv/loops/dirs
new file mode 100644
index 000000000..1d0b9edbb
--- /dev/null
+++ b/private/oleutest/balls/srv/loops/dirs
@@ -0,0 +1,38 @@
+!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/balls/srv/loops/loopsrv.cxx b/private/oleutest/balls/srv/loops/loopsrv.cxx
new file mode 100644
index 000000000..47f4d46c4
--- /dev/null
+++ b/private/oleutest/balls/srv/loops/loopsrv.cxx
@@ -0,0 +1,41 @@
+//+-------------------------------------------------------------------
+//
+// File: srvmain.cxx
+//
+// Contents: This file contins the EXE entry points
+// WinMain
+//
+// Classes:
+//
+// History: 30-Nov-92 SarahJ Created
+//
+//---------------------------------------------------------------------
+#include <common.h>
+#include <loopscf.hxx>
+
+//+-------------------------------------------------------------------
+//
+// Function: WinMain
+//
+// Synopsis: Entry point to DLL - does little else
+//
+// Arguments:
+//
+// Returns: TRUE
+//
+// History: 21-Nov-92 SarahJ Created
+//
+//--------------------------------------------------------------------
+int WINAPI WinMain(
+ HINSTANCE hInstance,
+ HINSTANCE hPrevInstance,
+ LPSTR lpCmdLine,
+ int nCmdShow)
+{
+ CLoopClassFactory *pCF = new CLoopClassFactory();
+
+ int sc = SrvMain(hInstance, CLSID_Loop, REGCLS_SINGLEUSE,
+ TEXT("Loops Server"), pCF);
+
+ return sc;
+}
diff --git a/private/oleutest/balls/srv/mdi/daytona/makefile b/private/oleutest/balls/srv/mdi/daytona/makefile
new file mode 100644
index 000000000..1d3728d41
--- /dev/null
+++ b/private/oleutest/balls/srv/mdi/daytona/makefile
@@ -0,0 +1,10 @@
+############################################################################
+#
+# Copyright (C) 1992, Microsoft Corporation.
+#
+# All rights reserved.
+#
+############################################################################
+
+!include $(NTMAKEENV)\makefile.def
+
diff --git a/private/oleutest/balls/srv/mdi/daytona/sources b/private/oleutest/balls/srv/mdi/daytona/sources
new file mode 100644
index 000000000..758573d51
--- /dev/null
+++ b/private/oleutest/balls/srv/mdi/daytona/sources
@@ -0,0 +1,53 @@
+!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.
+
+!ENDIF
+
+#
+# The following includes a global include file defined at the
+# base of the project for all components
+#
+
+!include ..\..\daytona.inc
+
+#
+# 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= mdi
+
+#
+# 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= $(INCLUDES)
+C_DEFINES= $(C_DEFINES)
+
+
+SOURCES= \
+ ..\mdi.cxx
diff --git a/private/oleutest/balls/srv/mdi/dirs b/private/oleutest/balls/srv/mdi/dirs
new file mode 100644
index 000000000..1d0b9edbb
--- /dev/null
+++ b/private/oleutest/balls/srv/mdi/dirs
@@ -0,0 +1,38 @@
+!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/balls/srv/mdi/mdi.cxx b/private/oleutest/balls/srv/mdi/mdi.cxx
new file mode 100644
index 000000000..d7ac302e5
--- /dev/null
+++ b/private/oleutest/balls/srv/mdi/mdi.cxx
@@ -0,0 +1,41 @@
+//+-------------------------------------------------------------------
+//
+// File: mdi.cxx
+//
+// Contents: This file contins the DLL entry points
+// WinMain
+//
+// Classes:
+//
+// History: 30-Nov-92 SarahJ Created
+//
+//---------------------------------------------------------------------
+#include <common.h>
+#include <actcf.hxx>
+
+//+-------------------------------------------------------------------
+//
+// Function: WinMain
+//
+// Synopsis: Entry point to DLL - does little else
+//
+// Arguments:
+//
+// Returns: TRUE
+//
+// History: 21-Nov-92 SarahJ Created
+//
+//--------------------------------------------------------------------
+int WINAPI WinMain(
+ HINSTANCE hInstance,
+ HINSTANCE hPrevInstance,
+ LPSTR lpCmdLine,
+ int nCmdShow)
+{
+ CActClassFactory *pCF = new CActClassFactory(CLSID_TestMultipleUse ,TRUE);
+
+ int sc = SrvMain(hInstance, CLSID_TestMultipleUse, REGCLS_MULTIPLEUSE,
+ TEXT("MDI Server"), pCF);
+
+ return sc;
+}
diff --git a/private/oleutest/balls/srv/mixed/daytona/makefile b/private/oleutest/balls/srv/mixed/daytona/makefile
new file mode 100644
index 000000000..1d3728d41
--- /dev/null
+++ b/private/oleutest/balls/srv/mixed/daytona/makefile
@@ -0,0 +1,10 @@
+############################################################################
+#
+# Copyright (C) 1992, Microsoft Corporation.
+#
+# All rights reserved.
+#
+############################################################################
+
+!include $(NTMAKEENV)\makefile.def
+
diff --git a/private/oleutest/balls/srv/mixed/daytona/sources b/private/oleutest/balls/srv/mixed/daytona/sources
new file mode 100644
index 000000000..98f2e04ee
--- /dev/null
+++ b/private/oleutest/balls/srv/mixed/daytona/sources
@@ -0,0 +1,53 @@
+!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.
+
+!ENDIF
+
+#
+# The following includes a global include file defined at the
+# base of the project for all components
+#
+
+!include ..\..\daytona.inc
+
+#
+# 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= mixedsrv
+
+#
+# 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= $(INCLUDES)
+C_DEFINES= $(C_DEFINES)
+
+
+SOURCES= \
+ ..\mixedsrv.cxx
diff --git a/private/oleutest/balls/srv/mixed/dirs b/private/oleutest/balls/srv/mixed/dirs
new file mode 100644
index 000000000..1d0b9edbb
--- /dev/null
+++ b/private/oleutest/balls/srv/mixed/dirs
@@ -0,0 +1,38 @@
+!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/balls/srv/mixed/mixedsrv.cxx b/private/oleutest/balls/srv/mixed/mixedsrv.cxx
new file mode 100644
index 000000000..a12b279f6
--- /dev/null
+++ b/private/oleutest/balls/srv/mixed/mixedsrv.cxx
@@ -0,0 +1,305 @@
+//+-------------------------------------------------------------------
+//
+// File: srvmain.cxx
+//
+// Contents: This file contins the EXE entry points
+//
+// History: 28-Feb-96 Rickhi Created
+//
+//---------------------------------------------------------------------
+#include <common.h>
+#include <mixedcf.hxx>
+
+
+extern "C" const GUID CLSID_QI;
+extern "C" const GUID CLSID_Balls;
+extern "C" const GUID CLSID_Loop;
+extern "C" const GUID CLSID_Cubes;
+
+int WINAPI RegisterSameThread(
+ HINSTANCE hInstance,
+ HINSTANCE hPrevInstance,
+ LPSTR lpCmdLine,
+ int nCmdShow,
+ DWORD dwThreadModel);
+
+int WINAPI RegisterDifferentThreads(
+ HINSTANCE hInstance,
+ HINSTANCE hPrevInstance,
+ LPSTR lpCmdLine,
+ int nCmdShow,
+ DWORD dwThreadModel);
+
+
+void RunServerThread(STHREADINFO *pThrdInfo);
+DWORD _stdcall ServerThread(void *param);
+void WakeupAllThreads();
+
+
+TCHAR *pszWindow[] = { TEXT("QI Server"),
+ TEXT("Balls Server"),
+ TEXT("Cubes Server"),
+ TEXT("Loops Server")};
+
+
+STHREADINFO *gpThrdInfo = NULL;
+ULONG gcThrds = 0;
+BOOL gfWokenUpAllThreads = FALSE;
+
+
+//+-------------------------------------------------------------------
+//
+// Function: MakeClassInfo
+//
+// Synopsis: fills in a SCLASSINFO structure
+//
+// History: 28-Feb-96 Rickhi Created
+//
+//--------------------------------------------------------------------
+HRESULT MakeClassInfo(REFCLSID rclsid, SCLASSINFO *pClsInfo)
+{
+ pClsInfo->clsid = rclsid;
+ pClsInfo->pCF = (IClassFactory *) new CMixedClassFactory(rclsid);
+ pClsInfo->dwCtx = CLSCTX_LOCAL_SERVER;
+ pClsInfo->dwClsReg = REGCLS_MULTIPLEUSE | REGCLS_SUSPENDED;
+ pClsInfo->dwReg = 0;
+
+ return (pClsInfo->pCF != NULL) ? S_OK : E_OUTOFMEMORY;
+}
+
+//+-------------------------------------------------------------------
+//
+// Function: WinMain
+//
+// Synopsis: Entry point. Creates the classinfo and enters the main
+// server loop.
+//
+// History: 28-Feb-96 Rickhi Created
+//
+//--------------------------------------------------------------------
+int WINAPI WinMain(
+ HINSTANCE hInstance,
+ HINSTANCE hPrevInstance,
+ LPSTR lpCmdLine,
+ int nCmdShow)
+{
+ if (lpCmdLine == NULL)
+ {
+ // ShowHelp();
+ return -1;
+ }
+
+ if (!(strncmp(lpCmdLine, "ApartmentSameThread", 19)))
+ {
+ return RegisterSameThread(hInstance, hPrevInstance, lpCmdLine, nCmdShow,
+ SRVF_THREADMODEL_APARTMENT);
+ }
+ else if (!(strncmp(lpCmdLine, "FreeSameThread", 14)))
+ {
+ return RegisterSameThread(hInstance, hPrevInstance, lpCmdLine, nCmdShow,
+ SRVF_THREADMODEL_MULTI);
+ }
+ else if (!(strncmp(lpCmdLine, "ApartmentDifferentThread", 24)))
+ {
+ return RegisterDifferentThreads(hInstance, hPrevInstance, lpCmdLine, nCmdShow,
+ SRVF_THREADMODEL_APARTMENT);
+ }
+ else if (!(strncmp(lpCmdLine, "FreeDifferentThread", 24)))
+ {
+ return RegisterDifferentThreads(hInstance, hPrevInstance, lpCmdLine, nCmdShow,
+ SRVF_THREADMODEL_MULTI);
+
+ }
+
+ return -1;
+}
+
+//+-------------------------------------------------------------------
+//
+// Function: RegisterSameThread
+//
+// Synopsis: Entry point. Creates the classinfo and enters the main
+// server loop.
+//
+// History: 28-Feb-96 Rickhi Created
+//
+//--------------------------------------------------------------------
+int WINAPI RegisterSameThread(
+ HINSTANCE hInstance,
+ HINSTANCE hPrevInstance,
+ LPSTR lpCmdLine,
+ int nCmdShow,
+ DWORD dwThreadModel)
+{
+ SCLASSINFO ClsInfo[4];
+ STHREADINFO ThrdInfo;
+ HRESULT hr[4];
+
+ hr[0] = MakeClassInfo(CLSID_QI, &ClsInfo[0]);
+ hr[1] = MakeClassInfo(CLSID_Balls, &ClsInfo[1]);
+ hr[2] = MakeClassInfo(CLSID_Cubes, &ClsInfo[2]);
+ hr[3] = MakeClassInfo(CLSID_Loop, &ClsInfo[3]);
+
+ ThrdInfo.hEventRun = CreateEvent(NULL, FALSE, FALSE, NULL);
+ ThrdInfo.hEventDone = CreateEvent(NULL, FALSE, FALSE, NULL);
+ ThrdInfo.hInstance = hInstance;
+ ThrdInfo.pszWindow = pszWindow[0];
+ ThrdInfo.dwFlags = dwThreadModel;
+ ThrdInfo.cClasses = 4;
+ ThrdInfo.pClsInfo = &ClsInfo[0];
+
+ // this thread is the one that should call resume.
+ ThrdInfo.dwFlags |= SRVF_REGISTER_RESUME;
+ ThrdInfo.dwTid = GetCurrentThreadId();
+
+ // stuff the thrd pointers and count into globals so we can
+ // wake the threads up whenever 1 single thread exits.
+ gpThrdInfo = &ThrdInfo;
+ gcThrds = 1;
+
+ hr[0] = SrvMain2(&ThrdInfo);
+
+ return hr[0];
+}
+
+
+//+-------------------------------------------------------------------
+//
+// Function: RegisterDifferentThreads
+//
+// Synopsis: Entry point. Creates the classinfo and enters the main
+// server loop.
+//
+// History: 28-Feb-96 Rickhi Created
+//
+//--------------------------------------------------------------------
+int WINAPI RegisterDifferentThreads(
+ HINSTANCE hInstance,
+ HINSTANCE hPrevInstance,
+ LPSTR lpCmdLine,
+ int nCmdShow,
+ DWORD dwThreadModel)
+{
+ SCLASSINFO ClsInfo[4];
+ STHREADINFO ThrdInfo[4];
+ HRESULT hr[4];
+
+ hr[0] = MakeClassInfo(CLSID_QI, &ClsInfo[0]);
+ hr[1] = MakeClassInfo(CLSID_Balls, &ClsInfo[1]);
+ hr[2] = MakeClassInfo(CLSID_Cubes, &ClsInfo[2]);
+ hr[3] = MakeClassInfo(CLSID_Loop, &ClsInfo[3]);
+
+ for (int i=0; i<4; i++)
+ {
+ if (SUCCEEDED(hr[i]))
+ {
+ ThrdInfo[i].hEventRun = CreateEvent(NULL, FALSE, FALSE, NULL);
+ ThrdInfo[i].hEventDone = CreateEvent(NULL, FALSE, FALSE, NULL);
+ ThrdInfo[i].hInstance = hInstance;
+ ThrdInfo[i].pszWindow = pszWindow[i];
+ ThrdInfo[i].dwFlags = dwThreadModel;
+ ThrdInfo[i].cClasses = 1;
+ ThrdInfo[i].pClsInfo = &ClsInfo[i];
+
+ if (i > 0)
+ {
+ // run the thread and wait for it signal it's ready
+ RunServerThread(&ThrdInfo[i]);
+ WaitForSingleObject(ThrdInfo[i].hEventRun, 0xffffffff);
+ CloseHandle(ThrdInfo[i].hEventRun);
+ }
+ }
+ }
+
+ // this thread is the one that should call resume.
+ ThrdInfo[0].dwFlags |= SRVF_REGISTER_RESUME;
+ ThrdInfo[0].dwTid = GetCurrentThreadId();
+
+ // stuff the thrd pointers and count into globals so we can
+ // wake the threads up whenever 1 single thread exits.
+ gpThrdInfo = &ThrdInfo[0];
+ gcThrds = 4;
+
+
+ hr[0] = SrvMain2(&ThrdInfo[0]);
+ WakeupAllThreads();
+
+ for (i=0; i<4; i++)
+ {
+ if (SUCCEEDED(hr[i]))
+ {
+ // wait for other thread to complete before exiting.
+ WaitForSingleObject(ThrdInfo[i].hEventDone, 0xffffffff);
+ CloseHandle(ThrdInfo[i].hEventDone);
+ }
+ }
+
+ return hr[0];
+}
+
+//+-------------------------------------------------------------------
+//
+// Function: WakeupAllThreads
+//
+// Synopsis: Wakes up all the other threads in the process when
+// one thread decides to exit.
+//
+// History: 28-Feb-96 Rickhi Created
+//
+//--------------------------------------------------------------------
+void WakeupAllThreads()
+{
+ if (gfWokenUpAllThreads)
+ return;
+
+ gfWokenUpAllThreads = TRUE;
+ STHREADINFO *pThrdInfo = gpThrdInfo;
+
+ for (ULONG i=0; i<gcThrds; i++, pThrdInfo++)
+ {
+ PostThreadMessage(pThrdInfo->dwTid, WM_QUIT, 0, 0);
+ }
+}
+
+//+-------------------------------------------------------------------
+//
+// Function: ServerThread
+//
+// Synopsis: Thread Entry point. Registers a class and waits for calls
+// on it.
+//
+// History: 28-Feb-96 Rickhi Created
+//
+//--------------------------------------------------------------------
+DWORD _stdcall ServerThread(void *param)
+{
+ STHREADINFO *pThrdInfo = (STHREADINFO *)param;
+
+ HRESULT hr = SrvMain2(pThrdInfo);
+
+ // wake up the other threads.
+ WakeupAllThreads();
+
+ return hr;
+}
+
+//+-------------------------------------------------------------------
+//
+// Function: RunServerThread
+//
+// Synopsis: Spins up a thread to act as a class server.
+//
+// History: 28-Feb-96 Rickhi Created
+//
+//--------------------------------------------------------------------
+void RunServerThread(STHREADINFO *pThrdInfo)
+{
+ HANDLE hThrd = CreateThread(NULL, 0, ServerThread, pThrdInfo,
+ 0, &(pThrdInfo->dwTid));
+ if (hThrd)
+ {
+ CloseHandle(hThrd);
+ }
+
+ return;
+}
diff --git a/private/oleutest/balls/srv/olesrv/daytona/makefile b/private/oleutest/balls/srv/olesrv/daytona/makefile
new file mode 100644
index 000000000..1d3728d41
--- /dev/null
+++ b/private/oleutest/balls/srv/olesrv/daytona/makefile
@@ -0,0 +1,10 @@
+############################################################################
+#
+# Copyright (C) 1992, Microsoft Corporation.
+#
+# All rights reserved.
+#
+############################################################################
+
+!include $(NTMAKEENV)\makefile.def
+
diff --git a/private/oleutest/balls/srv/olesrv/daytona/sources b/private/oleutest/balls/srv/olesrv/daytona/sources
new file mode 100644
index 000000000..e2989dea9
--- /dev/null
+++ b/private/oleutest/balls/srv/olesrv/daytona/sources
@@ -0,0 +1,53 @@
+!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.
+
+!ENDIF
+
+#
+# The following includes a global include file defined at the
+# base of the project for all components
+#
+
+!include ..\..\daytona.inc
+
+#
+# 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= olesrv
+
+#
+# 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= $(INCLUDES)
+C_DEFINES= $(C_DEFINES)
+
+
+SOURCES= \
+ ..\olesrv.cxx
diff --git a/private/oleutest/balls/srv/olesrv/dirs b/private/oleutest/balls/srv/olesrv/dirs
new file mode 100644
index 000000000..1d0b9edbb
--- /dev/null
+++ b/private/oleutest/balls/srv/olesrv/dirs
@@ -0,0 +1,38 @@
+!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/balls/srv/olesrv/olesrv.cxx b/private/oleutest/balls/srv/olesrv/olesrv.cxx
new file mode 100644
index 000000000..42b0372b0
--- /dev/null
+++ b/private/oleutest/balls/srv/olesrv/olesrv.cxx
@@ -0,0 +1,41 @@
+//+-------------------------------------------------------------------
+//
+// File: srvmain.cxx
+//
+// Contents: This file contins the EXE entry points
+// WinMain
+//
+// Classes:
+//
+// History: 30-Nov-92 SarahJ Created
+//
+//---------------------------------------------------------------------
+#include <common.h>
+#include <advbnd.hxx>
+
+//+-------------------------------------------------------------------
+//
+// Function: WinMain
+//
+// Synopsis: Entry point to DLL - does little else
+//
+// Arguments:
+//
+// Returns: TRUE
+//
+// History: 21-Nov-92 SarahJ Created
+//
+//--------------------------------------------------------------------
+int WINAPI WinMain(
+ HINSTANCE hInstance,
+ HINSTANCE hPrevInstance,
+ LPSTR lpCmdLine,
+ int nCmdShow)
+{
+ CAdvBndCF *pCF = new CAdvBndCF();
+
+ int sc = SrvMain(hInstance, CLSID_AdvBnd, REGCLS_MULTIPLEUSE,
+ TEXT("Ole Server"), pCF);
+
+ return sc;
+}
diff --git a/private/oleutest/balls/srv/qi/daytona/makefile b/private/oleutest/balls/srv/qi/daytona/makefile
new file mode 100644
index 000000000..1d3728d41
--- /dev/null
+++ b/private/oleutest/balls/srv/qi/daytona/makefile
@@ -0,0 +1,10 @@
+############################################################################
+#
+# Copyright (C) 1992, Microsoft Corporation.
+#
+# All rights reserved.
+#
+############################################################################
+
+!include $(NTMAKEENV)\makefile.def
+
diff --git a/private/oleutest/balls/srv/qi/daytona/sources b/private/oleutest/balls/srv/qi/daytona/sources
new file mode 100644
index 000000000..129922e2b
--- /dev/null
+++ b/private/oleutest/balls/srv/qi/daytona/sources
@@ -0,0 +1,53 @@
+!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.
+
+!ENDIF
+
+#
+# The following includes a global include file defined at the
+# base of the project for all components
+#
+
+!include ..\..\daytona.inc
+
+#
+# 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= qisrv
+
+#
+# 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= $(INCLUDES)
+C_DEFINES= $(C_DEFINES)
+
+
+SOURCES= \
+ ..\qisrv.cxx
diff --git a/private/oleutest/balls/srv/qi/dirs b/private/oleutest/balls/srv/qi/dirs
new file mode 100644
index 000000000..1d0b9edbb
--- /dev/null
+++ b/private/oleutest/balls/srv/qi/dirs
@@ -0,0 +1,38 @@
+!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/balls/srv/qi/qisrv.cxx b/private/oleutest/balls/srv/qi/qisrv.cxx
new file mode 100644
index 000000000..a94171a2e
--- /dev/null
+++ b/private/oleutest/balls/srv/qi/qisrv.cxx
@@ -0,0 +1,107 @@
+//+-------------------------------------------------------------------
+//
+// File: srvmain.cxx
+//
+// Contents: This file contins the EXE entry points
+//
+// History: 28-Feb-96 Rickhi Created
+//
+//---------------------------------------------------------------------
+#include <common.h>
+#include <mixedcf.hxx>
+
+
+extern "C" const GUID CLSID_QI;
+extern "C" const GUID CLSID_QIHANDLER;
+
+TCHAR *pszWindow[] = { TEXT("QI Server") };
+
+STHREADINFO *gpThrdInfo = NULL;
+ULONG gcThrds = 0;
+
+//+-------------------------------------------------------------------
+//
+// Function: MakeClassInfo
+//
+// Synopsis: fills in a SCLASSINFO structure
+//
+// History: 28-Feb-96 Rickhi Created
+//
+//--------------------------------------------------------------------
+HRESULT MakeClassInfo(REFCLSID rclsid, SCLASSINFO *pClsInfo)
+{
+ pClsInfo->clsid = rclsid;
+ pClsInfo->pCF = (IClassFactory *) new CMixedClassFactory(rclsid);
+ pClsInfo->dwCtx = CLSCTX_LOCAL_SERVER;
+ pClsInfo->dwClsReg = REGCLS_MULTIPLEUSE | REGCLS_SUSPENDED;
+ pClsInfo->dwReg = 0;
+
+ return (pClsInfo->pCF != NULL) ? S_OK : E_OUTOFMEMORY;
+}
+
+//+-------------------------------------------------------------------
+//
+// Function: RegisterSameThread
+//
+// Synopsis: Entry point. Creates the classinfo and enters the main
+// server loop.
+//
+// History: 28-Feb-96 Rickhi Created
+//
+//--------------------------------------------------------------------
+int WINAPI RegisterSameThread(
+ HINSTANCE hInstance,
+ HINSTANCE hPrevInstance,
+ LPSTR lpCmdLine,
+ int nCmdShow,
+ DWORD dwThreadModel)
+{
+ SCLASSINFO ClsInfo[2];
+ STHREADINFO ThrdInfo;
+ HRESULT hr[2];
+
+ hr[0] = MakeClassInfo(CLSID_QI, &ClsInfo[0]);
+ hr[1] = MakeClassInfo(CLSID_QIHANDLER, &ClsInfo[1]);
+
+ ThrdInfo.hEventRun = CreateEvent(NULL, FALSE, FALSE, NULL);
+ ThrdInfo.hEventDone = CreateEvent(NULL, FALSE, FALSE, NULL);
+ ThrdInfo.hInstance = hInstance;
+ ThrdInfo.pszWindow = pszWindow[0];
+ ThrdInfo.dwFlags = dwThreadModel;
+ ThrdInfo.cClasses = 2;
+ ThrdInfo.pClsInfo = &ClsInfo[0];
+
+ // this thread is the one that should call resume.
+ ThrdInfo.dwFlags |= SRVF_REGISTER_RESUME;
+ ThrdInfo.dwTid = GetCurrentThreadId();
+
+ // stuff the thrd pointers and count into globals so we can
+ // wake the threads up whenever 1 single thread exits.
+ gpThrdInfo = &ThrdInfo;
+ gcThrds = 1;
+
+ hr[0] = SrvMain2(&ThrdInfo);
+
+ return hr[0];
+}
+
+//+-------------------------------------------------------------------
+//
+// Function: WinMain
+//
+// Synopsis: Entry point. Creates the classinfo and enters the main
+// server loop.
+//
+// History: 28-Feb-96 Rickhi Created
+//
+//--------------------------------------------------------------------
+int WINAPI WinMain(
+ HINSTANCE hInstance,
+ HINSTANCE hPrevInstance,
+ LPSTR lpCmdLine,
+ int nCmdShow)
+{
+
+ return RegisterSameThread(hInstance, hPrevInstance, lpCmdLine, nCmdShow,
+ SRVF_THREADMODEL_APARTMENT);
+}
diff --git a/private/oleutest/balls/srv/rpctst/daytona/makefile b/private/oleutest/balls/srv/rpctst/daytona/makefile
new file mode 100644
index 000000000..1d3728d41
--- /dev/null
+++ b/private/oleutest/balls/srv/rpctst/daytona/makefile
@@ -0,0 +1,10 @@
+############################################################################
+#
+# Copyright (C) 1992, Microsoft Corporation.
+#
+# All rights reserved.
+#
+############################################################################
+
+!include $(NTMAKEENV)\makefile.def
+
diff --git a/private/oleutest/balls/srv/rpctst/daytona/sources b/private/oleutest/balls/srv/rpctst/daytona/sources
new file mode 100644
index 000000000..24545476c
--- /dev/null
+++ b/private/oleutest/balls/srv/rpctst/daytona/sources
@@ -0,0 +1,54 @@
+!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.
+
+!ENDIF
+
+#
+# The following includes a global include file defined at the
+# base of the project for all components
+#
+
+!include ..\..\daytona.inc
+
+#
+# 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= rpctst
+
+#
+# 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= $(INCLUDES)
+C_DEFINES= $(C_DEFINES)
+
+
+SOURCES= \
+ ..\rpcsrv.cxx
+
diff --git a/private/oleutest/balls/srv/rpctst/dirs b/private/oleutest/balls/srv/rpctst/dirs
new file mode 100644
index 000000000..1d0b9edbb
--- /dev/null
+++ b/private/oleutest/balls/srv/rpctst/dirs
@@ -0,0 +1,38 @@
+!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/balls/srv/rpctst/rpcsrv.cxx b/private/oleutest/balls/srv/rpctst/rpcsrv.cxx
new file mode 100644
index 000000000..001e1ec30
--- /dev/null
+++ b/private/oleutest/balls/srv/rpctst/rpcsrv.cxx
@@ -0,0 +1,103 @@
+//+-------------------------------------------------------------------
+//
+// File: srvmain.cxx
+//
+// Contents: This file contins the EXE entry points
+// WinMain
+//
+// Classes:
+//
+// History: 30-Nov-92 Rickhi Created
+//
+//---------------------------------------------------------------------
+#include <common.h>
+#include <rpccf.hxx>
+#include <stream.hxx>
+#include <rpctst.h> // IID_IRpcTest
+
+extern IUnknown *gpPunk;
+
+//+-------------------------------------------------------------------
+//
+// Function: WinMain
+//
+// Synopsis: Entry point to EXE
+//
+// Arguments:
+//
+// Returns: TRUE
+//
+// History: 21-Nov-92 Rickhi Created
+//
+//--------------------------------------------------------------------
+int WINAPI WinMain(
+ HINSTANCE hInstance,
+ HINSTANCE hPrevInstance,
+ LPSTR lpCmdLine,
+ int nCmdShow)
+{
+ CRpcTestClassFactory *pCF = new CRpcTestClassFactory();
+
+ // create an instance, then marshal that instance TABLE_STRONG
+ // and LONG_FORM into a stream.
+
+ IRpcTest *pUnk = NULL;
+ HRESULT hr = pCF->CreateInstance(NULL, IID_IRpcTest, (void **)&pUnk);
+ if (FAILED(hr))
+ {
+ return hr;
+ }
+
+ hr = E_OUTOFMEMORY;
+ IStream *pStm = (IStream *) new CStreamOnFile(TEXT("c:\\rickrpc.stm"),
+ hr, FALSE);
+
+ if (FAILED(hr))
+ {
+ return hr;
+ }
+
+ DWORD dwThreadMode;
+ TCHAR buffer[80];
+ int len;
+
+ len = GetProfileString( TEXT("OleSrv"),
+ TEXT("ThreadMode"),
+ TEXT("MultiThreaded"),
+ buffer,
+ sizeof(buffer) );
+
+#ifdef THREADING_SUPPORT
+ if (lstrcmp(buffer, TEXT("ApartmentThreaded")) == 0)
+ dwThreadMode = COINIT_APARTMENTTHREADED;
+ else
+ dwThreadMode = COINIT_MULTITHREADED;
+
+ hr = OleInitializeEx(NULL, dwThreadMode);
+#else
+ hr = OleInitialize(NULL);
+#endif
+
+ hr = CoMarshalInterface(pStm, IID_IRpcTest, pUnk, 0, NULL,
+ MSHLFLAGS_TABLESTRONG);
+
+ if (FAILED(hr))
+ {
+ return hr;
+ }
+
+ // close the stream
+ pStm->Release();
+
+ hr = pCF->CreateInstance(NULL, IID_IUnknown, (void **)&gpPunk);
+ if (FAILED(hr))
+ {
+ return hr;
+ }
+
+ int sc = SrvMain(hInstance, CLSID_RpcTest, REGCLS_SINGLEUSE,
+ TEXT("IRpcTest Server"), pCF);
+
+ OleUninitialize();
+ return sc;
+}
diff --git a/private/oleutest/balls/srv/sdi/daytona/makefile b/private/oleutest/balls/srv/sdi/daytona/makefile
new file mode 100644
index 000000000..1d3728d41
--- /dev/null
+++ b/private/oleutest/balls/srv/sdi/daytona/makefile
@@ -0,0 +1,10 @@
+############################################################################
+#
+# Copyright (C) 1992, Microsoft Corporation.
+#
+# All rights reserved.
+#
+############################################################################
+
+!include $(NTMAKEENV)\makefile.def
+
diff --git a/private/oleutest/balls/srv/sdi/daytona/sources b/private/oleutest/balls/srv/sdi/daytona/sources
new file mode 100644
index 000000000..b2b1bf879
--- /dev/null
+++ b/private/oleutest/balls/srv/sdi/daytona/sources
@@ -0,0 +1,53 @@
+!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.
+
+!ENDIF
+
+#
+# The following includes a global include file defined at the
+# base of the project for all components
+#
+
+!include ..\..\daytona.inc
+
+#
+# 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= sdi
+
+#
+# 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= $(INCLUDES)
+C_DEFINES= $(C_DEFINES)
+
+
+SOURCES= \
+ ..\sdi.cxx
diff --git a/private/oleutest/balls/srv/sdi/dirs b/private/oleutest/balls/srv/sdi/dirs
new file mode 100644
index 000000000..1d0b9edbb
--- /dev/null
+++ b/private/oleutest/balls/srv/sdi/dirs
@@ -0,0 +1,38 @@
+!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/balls/srv/sdi/sdi.cxx b/private/oleutest/balls/srv/sdi/sdi.cxx
new file mode 100644
index 000000000..d98fc2951
--- /dev/null
+++ b/private/oleutest/balls/srv/sdi/sdi.cxx
@@ -0,0 +1,41 @@
+//+-------------------------------------------------------------------
+//
+// File: sdi.cxx
+//
+// Contents: This file contins the DLL entry points
+// WinMain
+//
+// Classes:
+//
+// History: 30-Nov-92 SarahJ Created
+//
+//---------------------------------------------------------------------
+#include <common.h>
+#include <actcf.hxx>
+
+//+-------------------------------------------------------------------
+//
+// Function: WinMain
+//
+// Synopsis: Entry point to DLL - does little else
+//
+// Arguments:
+//
+// Returns: TRUE
+//
+// History: 21-Nov-92 SarahJ Created
+//
+//--------------------------------------------------------------------
+int WINAPI WinMain(
+ HINSTANCE hInstance,
+ HINSTANCE hPrevInstance,
+ LPSTR lpCmdLine,
+ int nCmdShow)
+{
+ CActClassFactory *pCF = new CActClassFactory(CLSID_TestSingleUse ,TRUE);
+
+ int sc = SrvMain(hInstance, CLSID_TestSingleUse, REGCLS_SINGLEUSE,
+ TEXT("SDI Server"), pCF);
+
+ return sc;
+}
diff --git a/private/oleutest/balls/srv/testsrv/csrvapp.cxx b/private/oleutest/balls/srv/testsrv/csrvapp.cxx
new file mode 100644
index 000000000..bf3a91189
--- /dev/null
+++ b/private/oleutest/balls/srv/testsrv/csrvapp.cxx
@@ -0,0 +1,289 @@
+//+-------------------------------------------------------------------
+// File: csrvapp.cxx
+//
+// Contents: Implementation of CTestServerApp
+//
+// Classes: CTestServerApp
+//
+// History: 17-Dec-92 DeanE Created
+//---------------------------------------------------------------------
+#pragma optimize("",off)
+#include <common.h>
+#include <csrvapp.hxx>
+#include <except.hxx>
+#include <embed.hxx>
+
+void ProcessCmdLine(LPSTR, BOOL *);
+
+// Used to send a quit message
+extern HWND g_hwndMain;
+
+extern "C" const GUID CLSID_TestEmbed;
+
+
+//+--------------------------------------------------------------
+// Function: CTestServerApp::CTestServerApp
+//
+// Synopsis: Constructor - initialize members
+//
+// Parameters: None
+//
+// Returns: None
+//
+// History: 17-Dec-92 DeanE Created
+//---------------------------------------------------------------
+CTestServerApp::CTestServerApp()
+{
+ _pteClassFactory = NULL;
+ _dwRegId = 0;
+ _fRegistered = FALSE;
+ _fInitialized = FALSE;
+ _fEmbedded = TRUE;
+ _cEmbeddedObjs = 0;
+}
+
+
+//+--------------------------------------------------------------
+// Function: CTestServerApp::~CTestServerApp
+//
+// Synopsis: Insure pointers are free - note this is mainly for
+// error-checking.
+//
+// Parameters: None
+//
+// Returns: None
+//
+// History: 17-Dec-92 DeanE Created
+//---------------------------------------------------------------
+CTestServerApp::~CTestServerApp()
+{
+ delete _pteClassFactory;
+}
+
+
+//+--------------------------------------------------------------
+// Function: CTestServerApp::InitApp
+//
+// Synopsis: Initialize this instance of the app.
+//
+// Parameters: [lpszCmdline] - Command line of the application.
+//
+// Returns: S_OK if everything was initialized, or an error if not.
+//
+// History: 17-Dec-92 DeanE Created
+//
+// Notes: If this does not return, the CloseApp method should
+// still be called for proper cleanup.
+//---------------------------------------------------------------
+SCODE CTestServerApp::InitApp(LPSTR lpszCmdline)
+{
+ SCODE sc;
+
+ // Check OLE version running
+ // BUGBUG - NYI by OLE
+ // Bail out if we are not running with an acceptable version of OLE
+
+ // Process Command Line arguments
+ ProcessCmdLine(lpszCmdline, &_fEmbedded);
+
+ // Initialize OLE
+ // Look up the thread mode from the win.ini file.
+ DWORD thread_mode;
+ TCHAR buffer[80];
+ int len;
+
+ len = GetProfileString( TEXT("TestSrv"),
+ TEXT("ThreadMode"),
+ TEXT("MultiThreaded"),
+ buffer,
+ sizeof(buffer) / sizeof(TCHAR));
+
+ if (lstrcmp(buffer, TEXT("ApartmentThreaded")) == 0)
+ {
+ thread_mode = COINIT_APARTMENTTHREADED;
+ sc = CoInitialize(NULL);
+ }
+ else
+ {
+#ifdef THREADING_SUPPORT
+ thread_mode = COINIT_MULTITHREADED;
+ sc = CoInitializeEx(NULL, thread_mode);
+#else
+ // multi-threading not supported
+ sc = E_INVALIDARG;
+#endif
+ }
+
+ if (S_OK == sc)
+ {
+ _fInitialized = TRUE;
+ }
+ else
+ {
+ return(sc);
+ }
+
+ // Create the applications class factory - note that we have to free
+ // at a later time
+ _pteClassFactory = CTestEmbedCF::Create(this);
+ if (NULL == _pteClassFactory)
+ {
+ return(E_ABORT);
+ }
+
+ // Register the class with OLE
+ sc = CoRegisterClassObject(
+ CLSID_TestEmbed,
+ _pteClassFactory,
+ CLSCTX_LOCAL_SERVER,
+ REGCLS_MULTIPLEUSE,
+ &_dwRegId);
+ if (S_OK == sc)
+ {
+ _fRegistered = TRUE;
+ }
+
+ return(sc);
+}
+
+
+//+--------------------------------------------------------------
+// Function: CTestServerApp::CloseApp
+//
+// Synopsis: Clean up resources this instance of the app is using.
+//
+// Parameters: None
+//
+// Returns: S_OK if everything was cleaned up, or an error if not.
+//
+// History: 17-Dec-92 DeanE Created
+//---------------------------------------------------------------
+SCODE CTestServerApp::CloseApp()
+{
+ // Revoke the class object, if registered
+ if (TRUE == _fRegistered)
+ {
+ CoRevokeClassObject(_dwRegId);
+ }
+
+ // Release this apps class factory, and insure the returned count is 0
+ if (0 == _pteClassFactory->Release())
+ {
+ _pteClassFactory = NULL;
+ }
+ else
+ {
+ // BUGBUG - Log error
+ }
+
+ // Uninitialize OLE only if OleInitialize succeeded
+ if (TRUE == _fInitialized)
+ {
+ CoUninitialize();
+ }
+ return(S_OK);
+}
+
+
+//+--------------------------------------------------------------
+// Function: CTestServerApp::GetEmbeddedFlag
+//
+// Synopsis: Returns TRUE if app was started for an embedded object,
+// FALSE if standalone.
+//
+// Parameters: None
+//
+// Returns: BOOL (_fEmbedded)
+//
+// History: 17-Dec-92 DeanE Created
+//
+// Notes: BUGBUG - This should be an inline method
+//---------------------------------------------------------------
+CTestServerApp::GetEmbeddedFlag()
+{
+ return(_fEmbedded);
+}
+
+
+//+--------------------------------------------------------------
+// Function: CTestServerApp::IncEmbeddedCount
+//
+// Synopsis: Increments the count of embedded objects the server
+// has open.
+//
+// Parameters: None
+//
+// Returns: ULONG (_cEmbeddedObjs)
+//
+// History: 17-Dec-92 DeanE Created
+//
+// Notes: BUGBUG - This should be an inline method
+//---------------------------------------------------------------
+ULONG CTestServerApp::IncEmbeddedCount()
+{
+ return(++_cEmbeddedObjs);
+}
+
+
+//+--------------------------------------------------------------
+// Function: CTestServerApp::DecEmbeddedCount
+//
+// Synopsis: Decrements the count of embedded objects the server
+// has open. If 0 are left and we were running for an
+// embedded object(s), shut down.
+//
+// Parameters: None
+//
+// Returns: ULONG (_cEmbeddedObjs)
+//
+// History: 17-Dec-92 DeanE Created
+//
+// Notes: BUGBUG - This should be an inline method
+//---------------------------------------------------------------
+ULONG CTestServerApp::DecEmbeddedCount()
+{
+ if ((0 == --_cEmbeddedObjs) && _fEmbedded)
+ {
+ SendMessage(g_hwndMain, WM_USER, 0xFFFFFFFF, 0xFFFFFFFF);
+ }
+
+ return(_cEmbeddedObjs);
+}
+
+
+//+--------------------------------------------------------------
+// Function: ProcessCmdline
+//
+// Synopsis: Checks the cmd line parameters, in particular for
+// '/Embedding' or '-Embedding'.
+//
+// Parameters: [lpszCmdLine] - Command line buffer.
+// [pfEmbedded] - Flag should be set to true if we get
+// the '/Embedding' switch.
+//
+// Returns: void
+//
+// History: 25-Nov-92 DeanE Created
+//
+// Notes: Only two valid commandlines for this program:
+// (1) -Embedding when started by OLE or (2) Null
+// string if started from the command line.
+//---------------------------------------------------------------
+void ProcessCmdLine(LPSTR lpszCmdline, BOOL *pfEmbedded)
+{
+ if (lpszCmdline[0] == 0)
+ {
+ *pfEmbedded = FALSE;
+ return;
+ }
+
+ if (strcmp(lpszCmdline, "-Embedding") == 0)
+ {
+ *pfEmbedded = TRUE;
+ return;
+ }
+
+ *pfEmbedded = FALSE;
+
+ return;
+}
diff --git a/private/oleutest/balls/srv/testsrv/daytona/makefile b/private/oleutest/balls/srv/testsrv/daytona/makefile
new file mode 100644
index 000000000..1d3728d41
--- /dev/null
+++ b/private/oleutest/balls/srv/testsrv/daytona/makefile
@@ -0,0 +1,10 @@
+############################################################################
+#
+# Copyright (C) 1992, Microsoft Corporation.
+#
+# All rights reserved.
+#
+############################################################################
+
+!include $(NTMAKEENV)\makefile.def
+
diff --git a/private/oleutest/balls/srv/testsrv/daytona/sources b/private/oleutest/balls/srv/testsrv/daytona/sources
new file mode 100644
index 000000000..f9ec652c4
--- /dev/null
+++ b/private/oleutest/balls/srv/testsrv/daytona/sources
@@ -0,0 +1,54 @@
+!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.
+
+!ENDIF
+
+#
+# The following includes a global include file defined at the
+# base of the project for all components
+#
+
+!include ..\..\daytona.inc
+
+#
+# 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= testsrv
+
+#
+# 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= $(INCLUDES)
+C_DEFINES= $(C_DEFINES)
+
+
+SOURCES= \
+ ..\testsrv.cxx \
+ ..\csrvapp.cxx
diff --git a/private/oleutest/balls/srv/testsrv/dirs b/private/oleutest/balls/srv/testsrv/dirs
new file mode 100644
index 000000000..1d0b9edbb
--- /dev/null
+++ b/private/oleutest/balls/srv/testsrv/dirs
@@ -0,0 +1,38 @@
+!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/balls/srv/testsrv/testsrv.cxx b/private/oleutest/balls/srv/testsrv/testsrv.cxx
new file mode 100644
index 000000000..fa4f509d6
--- /dev/null
+++ b/private/oleutest/balls/srv/testsrv/testsrv.cxx
@@ -0,0 +1,204 @@
+//+-------------------------------------------------------------------
+// File: testsrv.cxx
+//
+// Contents:
+//
+// Classes: CBasicSrvCF - IUnknown IClassFactory
+// CBasicSrv - IUnknown IPersist IPersistFile IParseDisplayName
+//
+// Notes: This code is written based on OLE2.0 code. Therefore
+// all error codes, defines etc are OLE style rather than Cairo
+//
+// History: 24-Nov-92 DeanE Created
+//---------------------------------------------------------------------
+#pragma optimize("",off)
+#include <windows.h>
+#include <ole2.h>
+#include <csrvapp.hxx>
+#include <embed.hxx>
+#include <stdio.h>
+
+// BUGBUG - memory allocation hacks need these so new and delete don't
+// break us
+//
+#include <malloc.h>
+#include <dos.h>
+
+#define IDM_DEBUG 0x100
+
+extern "C" LRESULT FAR PASCAL MainWndProc(HWND, UINT, WPARAM, LPARAM);
+void ReportMessage(HWND, WORD);
+
+// This is global because we're still in $%E#$#K 16-bit world
+HWND g_hwndMain = NULL;
+
+// Note constructor cannot fail
+CTestServerApp tsaMain;
+
+
+//+--------------------------------------------------------------
+// Function: WinMain
+//
+// Synopsis: Initializes application and controls message pump.
+//
+// Returns: Exits with exit code 0 if success, non-zero otherwise
+//
+// History: 25-Nov-92 DeanE Created
+//---------------------------------------------------------------
+int PASCAL WinMain(
+ HINSTANCE hInstance,
+ HINSTANCE hPrevInstance,
+ LPSTR lpszCmdline,
+ int nCmdShow)
+{
+ static TCHAR szAppName[] = TEXT("OleServer");
+ MSG msg;
+ WNDCLASS wndclass;
+
+ if (!hPrevInstance)
+ {
+ wndclass.style = CS_HREDRAW | CS_VREDRAW;
+ wndclass.lpfnWndProc = MainWndProc;
+ wndclass.cbClsExtra = 0;
+ wndclass.cbWndExtra = 0;
+ wndclass.hInstance = hInstance;
+ wndclass.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(125));
+ wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wndclass.hbrBackground = (HBRUSH) GetStockObject(BLACK_BRUSH);
+ wndclass.lpszMenuName = NULL;
+ wndclass.lpszClassName = szAppName;
+
+ if (0==RegisterClass(&wndclass))
+ {
+ // Error! Clean up and exit
+ return(LOG_ABORT);
+ }
+ }
+
+ g_hwndMain = CreateWindow(
+ szAppName,
+ TEXT("OLE Server"),
+ WS_OVERLAPPEDWINDOW | WS_VSCROLL,
+ GetSystemMetrics(SM_CXSCREEN)/12, // Init X pos
+ GetSystemMetrics(SM_CYSCREEN)/12, // Init Y pos
+ GetSystemMetrics(SM_CXSCREEN)*2/3, // width
+ GetSystemMetrics(SM_CYSCREEN)*2/3, // height
+ NULL,
+ NULL,
+ hInstance,
+ NULL);
+
+ if (NULL==g_hwndMain)
+ {
+ // Error! Clean up and exit
+ return(LOG_ABORT);
+ }
+
+ // Add debug option to system menu
+ HMENU hmenu = GetSystemMenu(g_hwndMain, FALSE);
+
+ AppendMenu(hmenu, MF_SEPARATOR, 0, NULL);
+ AppendMenu(hmenu, MF_STRING | MF_ENABLED, IDM_DEBUG, TEXT("Debug"));
+
+
+ // Initialize Application
+ if (S_OK != tsaMain.InitApp(lpszCmdline))
+ {
+ tsaMain.CloseApp();
+ return(LOG_ABORT);
+ }
+
+ if (tsaMain.GetEmbeddedFlag())
+ {
+ // We're running as an embedded app
+ // Don't show the main window unless we're instructed to do so
+ // BUGBUG - In-place editing is NYI
+ ShowWindow(g_hwndMain, SW_SHOWMINIMIZED);
+ }
+ else
+ {
+ // We are not running as an embedded app - show the main window
+ ShowWindow(g_hwndMain, nCmdShow);
+ }
+
+ UpdateWindow(g_hwndMain);
+
+
+ // message loop
+ while (GetMessage(&msg, NULL, 0, 0))
+ {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+
+ // Clean up and exit
+ // BUGBUG - check return code?
+ tsaMain.CloseApp();
+
+ return(0);
+}
+
+
+//+--------------------------------------------------------------
+// Function: MainWndProc
+//
+// Synopsis: Callback for the server window
+//
+// Returns: Varies dependent on message received.
+//
+// History: 25-Nov-92 DeanE Created
+//---------------------------------------------------------------
+extern "C" LRESULT FAR PASCAL MainWndProc(
+ HWND hwnd,
+ UINT wMsg,
+ WPARAM wParam,
+ LPARAM lParam)
+{
+ switch(wMsg)
+ {
+ case WM_DESTROY:
+ PostQuitMessage(0);
+ return(0);
+
+ case WM_USER:
+ DestroyWindow(hwnd);
+ return 0;
+
+ case WM_SYSCOMMAND:
+
+ if (wParam == IDM_DEBUG)
+ {
+ // Request for a debug breakpoint!
+ DebugBreak();
+ }
+
+ default:
+ break;
+ }
+
+ return(DefWindowProc(hwnd, wMsg, wParam, lParam));
+}
+
+
+void ReportMessage(HWND hwnd, WORD wParam)
+{
+ TCHAR szBuffer[MAX_PATH];
+ szBuffer[0] = '\0';
+
+ switch (wParam)
+ {
+ case MB_SHOWVERB:
+ lstrcpy(szBuffer, TEXT("OLEIVERB_SHOW Received"));
+ break;
+
+ case MB_PRIMVERB:
+ lstrcpy(szBuffer, TEXT("OLEIVERB_PRIMARY Received"));
+ break;
+
+ default:
+ lstrcpy(szBuffer, TEXT("Unrecognized ReportMessage code"));
+ break;
+ }
+
+ MessageBox(hwnd, szBuffer, TEXT("OLE Server"), MB_ICONINFORMATION | MB_OK);
+}
diff --git a/private/oleutest/balls/srv/testsrv/testsrv.ico b/private/oleutest/balls/srv/testsrv/testsrv.ico
new file mode 100644
index 000000000..05dac99c1
--- /dev/null
+++ b/private/oleutest/balls/srv/testsrv/testsrv.ico
Binary files differ
diff --git a/private/oleutest/balls/srv/testsrv/testsrv.rc b/private/oleutest/balls/srv/testsrv/testsrv.rc
new file mode 100644
index 000000000..51681d8b2
--- /dev/null
+++ b/private/oleutest/balls/srv/testsrv/testsrv.rc
@@ -0,0 +1,3 @@
+#include <windows.h>
+
+125 ICON testsrv.ico
diff --git a/private/oleutest/balls/stripspc.sed b/private/oleutest/balls/stripspc.sed
new file mode 100644
index 000000000..f0f973968
--- /dev/null
+++ b/private/oleutest/balls/stripspc.sed
@@ -0,0 +1,15 @@
+:noblank
+s/ //
+s/[ ][ ]*$//
+/^$/{
+ p
+:delete
+ N
+ s/\n//
+ s/ //
+ s/[ ][ ]*$//
+ /^$/{
+ b delete
+ }
+ b noblank
+}
diff --git a/private/oleutest/balls/tmarshal.ini b/private/oleutest/balls/tmarshal.ini
new file mode 100644
index 000000000..96432ec29
--- /dev/null
+++ b/private/oleutest/balls/tmarshal.ini
@@ -0,0 +1,92 @@
+;
+; Run All the Marshal Tests
+;
+
+[Marshal Test]
+; these first few are not run due to test bugs
+Aggregate = 0
+CreateRemoteHandler = 0
+StorageDiffMachine = 0
+Rundown = 0
+Async = 0
+
+; all the rest are run
+GetStandardMarshal = 1
+Format = 1
+GetIIDFromMI = 1
+MarshalSizeMax = 1
+LocalInterfaceNormal = 1
+UniqueQIPointer = 1
+LocalInterfaceTableStrong = 1
+LocalInterfaceTableWeak = 1
+UnmarshalGUIDNULL = 1
+UnmarshalDifferentIID = 1
+RemoteInterfaceNormal = 1
+RemoteInterfaceTableStrong = 1
+CustomMarshalNormal = 1
+CustomMarshalTable = 1
+Echo = 1
+MultiQINormal = 1
+MultiQIHandler = 1
+Handler = 1
+Loop = 1
+LockObjectExternal = 1
+DisconnectObject = 1
+ReleaseMarshalData = 1
+MiddleMan = 1
+LocalDiffMachine = 1
+RemoteDiffMachine = 1
+ExpiredOXIDs = 1
+NonNDRProxy = 1
+MarshalStorage = 1
+TIDAndLID = 1
+CrossThread = 1
+NoPing = 1
+PSClsid = 1
+PSClsid2 = 1
+
+
+;
+; Run Selected Marshal Tests
+;
+
+;[Marshal Test]
+Aggregate = 0
+CreateRemoteHandler = 0
+StorageDiffMachine = 0
+Rundown = 0
+Async = 0
+
+GetStandardMarshal = 0
+Format = 0
+GetIIDFromMI = 0
+MarshalSizeMax = 0
+LocalInterfaceNormal = 0
+UniqueQIPointer = 0
+LocalInterfaceTableStrong = 0
+LocalInterfaceTableWeak = 0
+UnmarshalGUIDNULL = 0
+UnmarshalDifferentIID = 0
+RemoteInterfaceNormal = 0
+RemoteInterfaceTableStrong = 0
+CustomMarshalNormal = 0
+CustomMarshalTable = 0
+Echo = 0
+MultiQINormal = 0
+MultiQIHandler = 0
+Handler = 0
+Loop = 0
+LockObjectExternal = 0
+DisconnectObject = 0
+ReleaseMarshalData = 0
+MiddleMan = 0
+LocalDiffMachine = 0
+RemoteDiffMachine = 0
+ExpiredOXIDs = 1
+NonNDRProxy = 0
+MarshalStorage = 0
+TIDAndLID = 0
+CrossThread = 0
+NoPing = 0
+PSClsid = 0
+PSClsid2 = 0
diff --git a/private/oleutest/balls/types.inc b/private/oleutest/balls/types.inc
new file mode 100644
index 000000000..fccef2259
--- /dev/null
+++ b/private/oleutest/balls/types.inc
@@ -0,0 +1,14 @@
+
+MAJORCOMP=cairo
+MINORCOMP=types
+
+PASS0_HEADERDIR = $(BASEDIR)\public\sdk\inc
+PASS0_SOURCEDIR = ..\oleprx32\proxy
+MIDL_UUIDDIR = ..\oleprx32\uuid
+
+C_DEFINES= -DWIN32=300 -D_CAIRO_=300
+
+TARGETPATH=obj
+TARGETTYPE=NOTARGET
+
+SYNCHRONIZE_BLOCK=1
diff --git a/private/oleutest/balls/win.ini b/private/oleutest/balls/win.ini
new file mode 100644
index 000000000..86bb1ae1f
--- /dev/null
+++ b/private/oleutest/balls/win.ini
@@ -0,0 +1,49 @@
+
+;; debug info levels set by default when an app starts up.
+;; a good value for cairole is 0x4ff for debug outs.
+
+[Cairo Infolevels]
+ cairole = 0x03
+ ol = 0x03
+
+
+;; tmarshal test options.
+;; = 1 means run the test
+;; = 0 means dont run the test
+;;
+
+[Marshal Test]
+ LocalInterfaceNormal = 1
+ LocalInterfaceTableStrong = 1
+ LocalInterfaceTableWeak = 1
+ RemoteInterfaceNormal = 1
+ RemoteInterfaceTableStrong = 1
+ RemoteInterfaceTableWeak = 1
+ Echo = 1
+ Loop = 1
+ MiddleMan = 1
+ LockObjectExternal = 1
+ DisconnectObject = 1
+ GetStandardMarshal = 1
+ CreateRemoteHandler = 1
+ CustomMarshalNormal = 1
+ CustomMarshalTable = 1
+ MarshalStorage = 1
+ Aggregate = 0
+ LocalDiffMachine = 0
+ RemoteDiffMachine = 0
+ StorageDiffMachine = 0
+
+
+;; threading modes for the OLE servers
+;; these are used by all OLE servers generated in the com\utest\balls
+;;
+
+[TestSrv]
+ ThreadMode = SingleThreaded
+;; ThreadMode = MultiThreaded
+
+
+[OleSrv]
+ ThreadMode = SingleThreaded
+;; ThreadMode = MultiThreaded
diff --git a/private/oleutest/cachetst/bmpfile.cxx b/private/oleutest/cachetst/bmpfile.cxx
new file mode 100644
index 000000000..94828fa55
--- /dev/null
+++ b/private/oleutest/cachetst/bmpfile.cxx
@@ -0,0 +1,1007 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: bmpfile.cxx
+//
+// Contents: CBitmapFile implementation
+//
+// Classes:
+//
+// Functions:
+//
+// History: 4-23-94 KirtD Created
+//
+//----------------------------------------------------------------------------
+
+#include "headers.hxx"
+#pragma hdrstop
+
+//+---------------------------------------------------------------------------
+//
+// Member: CBitmapFile::CBitmapFile
+//
+// Synopsis: Constructor
+//
+// Arguments: (none)
+//
+// Returns: nothing
+//
+// History: 4-23-94 KirtD Created
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+CBitmapFile::CBitmapFile ()
+{
+ //
+ // Initialize private members
+ //
+
+ //
+ // The name
+ //
+
+ _pszBitmapFile[0] = '\0';
+ _cBitmapFile = 0;
+
+ //
+ // The bitmap information
+ //
+
+ _cbi = 0;
+ _pbi = NULL;
+
+ //
+ // The bits
+ //
+
+ _cbData = 0;
+ _pbData = NULL;
+}
+
+//+---------------------------------------------------------------------------
+//
+// Member: CBitmapFile::~CBitmapFile
+//
+// Synopsis: Destructor
+//
+// Arguments: (none)
+//
+// Returns: nothing
+//
+// History: 4-23-94 KirtD Created
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+CBitmapFile::~CBitmapFile ()
+{
+ //
+ // Delete any possibly allocated things
+ //
+
+ delete _pbi;
+ delete _pbData;
+}
+
+//+---------------------------------------------------------------------------
+//
+// Member: CBitmapFile::LoadBitmapFile
+//
+// Synopsis: loads a bitmap file
+//
+// Arguments: [pszFile] -- the file
+//
+// Returns: HRESULT
+//
+// History: 4-23-94 KirtD Created
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+HRESULT
+CBitmapFile::LoadBitmapFile (LPSTR pszFile)
+{
+ HRESULT hr = ResultFromScode(S_OK);
+ HANDLE hFile = INVALID_HANDLE_VALUE;
+ HANDLE hMap = INVALID_HANDLE_VALUE;
+ DWORD dwFileSizeLow = 0;
+ DWORD dwFileSizeHigh = 0;
+ LPBYTE pbuffer = NULL;
+
+ //
+ // First open the file
+ //
+
+ hFile = CreateFileA(pszFile,
+ GENERIC_READ,
+ FILE_SHARE_READ,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ if (hFile == INVALID_HANDLE_VALUE)
+ {
+ hr = HRESULT_FROM_WIN32(GetLastError());
+ }
+
+ //
+ // Get the size of the file
+ //
+
+ if (SUCCEEDED(hr))
+ {
+ dwFileSizeLow = GetFileSize(hFile, &dwFileSizeHigh);
+ if ((dwFileSizeLow == 0xFFFFFFFF) && (GetLastError() != NO_ERROR))
+ {
+ hr = HRESULT_FROM_WIN32(GetLastError());
+ }
+ else if (dwFileSizeHigh != 0)
+ {
+ //
+ // Bitmap files can't be greater than 4G
+ //
+
+ hr = ResultFromScode(E_FAIL);
+ }
+ }
+
+ //
+ // Create a file mapping object on the file
+ //
+
+ if (SUCCEEDED(hr))
+ {
+ hMap = CreateFileMapping(hFile,
+ NULL,
+ PAGE_READONLY,
+ 0,
+ dwFileSizeLow,
+ NULL);
+
+ if (hMap == INVALID_HANDLE_VALUE)
+ {
+ hr = HRESULT_FROM_WIN32(GetLastError());
+ }
+ }
+
+ //
+ // Now map a view of the file into our address space
+ //
+
+ if (SUCCEEDED(hr))
+ {
+ pbuffer = (LPBYTE)MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0);
+ if (pbuffer == NULL)
+ {
+ hr = HRESULT_FROM_WIN32(GetLastError());
+ }
+ }
+
+ //
+ // Get the bitmap data from the buffer
+ //
+
+ if (SUCCEEDED(hr))
+ {
+ hr = _GetBitmapDataFromBuffer(pbuffer, (ULONG)dwFileSizeLow);
+ }
+
+ //
+ // Record the file name
+ //
+
+ if (SUCCEEDED(hr))
+ {
+ ULONG cFile;
+
+ //
+ // Get the length of the file name
+ //
+
+ cFile = strlen(pszFile);
+
+ //
+ // Check to see that our buffer is big enough and then copy
+ // it. NOTE that I can use sizeof here since the buffer is
+ // in characters which are 1 byte.
+ //
+
+ if (cFile < sizeof(_pszBitmapFile))
+ {
+ strcpy(_pszBitmapFile, pszFile);
+ _cBitmapFile = cFile;
+ }
+ else
+ {
+ hr = ResultFromScode(E_FAIL);
+ }
+ }
+
+ //
+ // Cleanup
+ //
+
+ if (hMap != INVALID_HANDLE_VALUE)
+ {
+ CloseHandle(hMap);
+ }
+
+ if (hFile != INVALID_HANDLE_VALUE)
+ {
+ CloseHandle(hFile);
+ }
+
+ return(hr);
+}
+
+//+---------------------------------------------------------------------------
+//
+// Member: CBitmapFile::GetBitmapFileName
+//
+// Synopsis: gets the file name used to set the bitmap
+//
+// Arguments: [pszFile] -- the file
+// [cChar] -- the length of the buffer in characters
+//
+// Returns: HRESULT
+//
+// History: 4-23-94 KirtD Created
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+HRESULT
+CBitmapFile::GetBitmapFileName (LPSTR pszFile, ULONG cChar) const
+{
+ //
+ // Check the length of the receiving buffer, making sure the buffer size
+ // includes the null terminator
+ //
+
+ if (cChar <= _cBitmapFile)
+ {
+ return(ResultFromScode(E_INVALIDARG));
+ }
+
+ //
+ // Copy the string
+ //
+
+ strcpy(pszFile, _pszBitmapFile);
+
+ return(ResultFromScode(S_OK));
+}
+
+//+---------------------------------------------------------------------------
+//
+// Member: CBitmapFile::GetBitmapFileNameLength
+//
+// Synopsis: returns _cBitmapFile
+//
+// Arguments: (none)
+//
+// Returns: ULONG
+//
+// History: 4-23-94 KirtD Created
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+ULONG
+CBitmapFile::GetBitmapFileNameLength () const
+{
+ return(_cBitmapFile);
+}
+
+//+---------------------------------------------------------------------------
+//
+// Member: CBitmapFile::GetDIBHeight
+//
+// Synopsis: gets the height in pixels of the DIB
+//
+// Arguments: (none)
+//
+// Returns: LONG
+//
+// History: 4-23-94 KirtD Created
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+LONG
+CBitmapFile::GetDIBHeight () const
+{
+ if (_pbi)
+ {
+ return(_pbi->bmiHeader.biHeight);
+ }
+ else
+ {
+ return(0);
+ }
+}
+
+//+---------------------------------------------------------------------------
+//
+// Member: CBitmapFile::GetDIBWidth
+//
+// Synopsis: gets the width in pixels of the DIB
+//
+// Arguments: (none)
+//
+// Returns: LONG
+//
+// History: 4-23-94 KirtD Created
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+LONG
+CBitmapFile::GetDIBWidth () const
+{
+ if (_pbi)
+ {
+ return(_pbi->bmiHeader.biWidth);
+ }
+ else
+ {
+ return(0);
+ }
+}
+
+//+---------------------------------------------------------------------------
+//
+// Member: CBitmapFile::GetLogicalPalette
+//
+// Synopsis: gets the logical palette from the DIB
+//
+// Arguments: [pplogpal] -- logical palette goes here
+//
+// Returns: HRESULT
+//
+// History: 4-23-94 KirtD Created
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+HRESULT
+CBitmapFile::GetLogicalPalette (LPLOGPALETTE *pplogpal) const
+{
+ HRESULT hr = ResultFromScode(S_OK);
+ LOGPALETTE *plogpal = NULL;
+ WORD cPalEntry;
+ LPMALLOC pMalloc = NULL;
+
+ //
+ // First check to see if we have been initialized with a bitmap
+ //
+
+ if (_pbi == NULL)
+ {
+ return(ResultFromScode(E_FAIL));
+ }
+
+ //
+ // Check to see if this bit count allows a palette
+ //
+
+ if (HasPaletteData() == FALSE)
+ {
+ return(ResultFromScode(E_FAIL));
+ }
+
+ //
+ // NOTE: We are about to get the number of palette entries we
+ // need to allocate, we do NOT use biClrUsed since we
+ // know that if this field was set the bitmap would
+ // not have been loaded, see BUGBUG in
+ // _GetBitmapDataFromBuffer notes section. This is
+ // probably a good candidate for an assert.
+ //
+
+ //
+ // Get the palette entries
+ //
+
+ cPalEntry = (WORD) (1 << _pbi->bmiHeader.biBitCount);
+
+ //
+ // Allocate a LOGPALETTE
+ //
+
+ hr = CoGetMalloc(MEMCTX_TASK, &pMalloc);
+ if (SUCCEEDED(hr))
+ {
+ plogpal = (LOGPALETTE *)pMalloc->Alloc(sizeof(LOGPALETTE)+
+ ((cPalEntry-1)*
+ sizeof(PALETTEENTRY)));
+
+ if (plogpal == NULL)
+ {
+ hr = ResultFromScode(E_OUTOFMEMORY);
+ }
+ }
+
+ //
+ // Copy the palette information
+ //
+
+ if (SUCCEEDED(hr))
+ {
+ ULONG cCount;
+
+ plogpal->palVersion = 0x300;
+ plogpal->palNumEntries = cPalEntry;
+
+ for (cCount = 0; cCount < cPalEntry; cCount++)
+ {
+ plogpal->palPalEntry[cCount].peRed = _pbi->bmiColors[cCount].rgbRed;
+ plogpal->palPalEntry[cCount].peGreen = _pbi->bmiColors[cCount].rgbGreen;
+ plogpal->palPalEntry[cCount].peBlue = _pbi->bmiColors[cCount].rgbBlue;
+ plogpal->palPalEntry[cCount].peFlags = PC_NOCOLLAPSE;
+ }
+
+ *pplogpal = plogpal;
+ }
+
+ //
+ // Cleanup
+ //
+
+ if (pMalloc)
+ {
+ pMalloc->Release();
+ }
+
+ return(hr);
+}
+
+//+---------------------------------------------------------------------------
+//
+// Member: CBitmapFile::CreateDIBInHGlobal
+//
+// Synopsis: creates a DIB i.e. info and data in a GlobalAlloc'd buffer
+//
+// Arguments: [phGlobal] -- handle goes here
+//
+// Returns: HRESULT
+//
+// History: 5-06-94 KirtD Created
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+HRESULT
+CBitmapFile::CreateDIBInHGlobal (HGLOBAL *phGlobal) const
+{
+ HRESULT hr = ResultFromScode(S_OK);
+ ULONG cb = 0;
+ LPBYTE pb = NULL;
+ HGLOBAL hGlobal = NULL;
+ ULONG cbPalEntry = 0;
+
+ //
+ // Check to see if we are initialized
+ //
+
+ if (_pbi == NULL)
+ {
+ return(ResultFromScode(E_FAIL));
+ }
+
+ //
+ // The size to allocate for the data must be calculated
+ // from the following ...
+ //
+
+ //
+ // The size of the bitmap info plus the size of the data
+ //
+
+ cb = _cbi + _cbData;
+
+ //
+ // Allocate
+ //
+
+ hGlobal = GlobalAlloc(GHND, cb);
+ if (hGlobal == NULL)
+ {
+ hr = HRESULT_FROM_WIN32(GetLastError());
+ }
+
+ //
+ // Lock the handle
+ //
+
+ if (SUCCEEDED(hr))
+ {
+ pb = (LPBYTE)GlobalLock(hGlobal);
+ if (pb == NULL)
+ {
+ hr = HRESULT_FROM_WIN32(GetLastError());
+ }
+ }
+
+ //
+ // Copy the information
+ //
+
+ if (SUCCEEDED(hr))
+ {
+ //
+ // First the bitmap info
+ //
+
+ memcpy(pb, _pbi, _cbi);
+
+ //
+ // Move pointer but if there is no palette compensate
+ // for the extra RGBQUAD
+ //
+
+ if (_pbi->bmiHeader.biBitCount == BMP_24_BITSPERPIXEL)
+ {
+ pb += (_cbi - sizeof(RGBQUAD));
+ }
+ else
+ {
+ pb += _cbi;
+ }
+
+ //
+ // Now the bits
+ //
+
+ memcpy(pb, _pbData, _cbData);
+ }
+
+ //
+ // Cleanup
+ //
+
+ //
+ // If we locked the handle, unlock it
+ //
+
+ if (pb)
+ {
+ GlobalUnlock(hGlobal);
+ }
+
+ //
+ // If we succeeded, set the out parameter, if we failed and
+ // we had allocated the hGlobal, free it
+ //
+
+ if (SUCCEEDED(hr))
+ {
+ *phGlobal = hGlobal;
+ }
+ else if (hGlobal)
+ {
+ GlobalFree(hGlobal);
+ }
+
+ return(hr);
+}
+
+//+---------------------------------------------------------------------------
+//
+// Member: CBitmapFile::HasPaletteData
+//
+// Synopsis: returns whether or not the dib has palette data
+//
+// Arguments: (none)
+//
+// Returns: BOOL
+//
+// History: 5-16-94 kirtd Created
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+BOOL
+CBitmapFile::HasPaletteData () const
+{
+ //
+ // If we are not initialized return FALSE
+ //
+
+ if (_pbi == NULL)
+ {
+ return(FALSE);
+ }
+
+ //
+ // If we are a 24, 16 or 32 bpp DIB then we do not have
+ // palette data
+ //
+ // BUGBUG: The case where biClrUsed is set is not dealt
+ // with
+ //
+
+ if ((_pbi->bmiHeader.biBitCount == BMP_24_BITSPERPIXEL) ||
+ (_pbi->bmiHeader.biBitCount == BMP_16_BITSPERPIXEL) ||
+ (_pbi->bmiHeader.biBitCount == BMP_32_BITSPERPIXEL))
+ {
+ return(FALSE);
+ }
+
+ //
+ // Otherwise we do have palette data
+ //
+
+ return(TRUE);
+}
+
+//+---------------------------------------------------------------------------
+//
+// Member: CBitmapFile::GetDIBBits
+//
+// Synopsis: gets the bits
+//
+// Arguments: (none)
+//
+// Returns: LPBYTE
+//
+// History: 5-02-94 KirtD Created
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+LPBYTE
+CBitmapFile::GetDIBBits ()
+{
+ return(_pbData);
+}
+
+//+---------------------------------------------------------------------------
+//
+// Member: CBitmapFile::GetBitmapInfo
+//
+// Synopsis: gets the bitmap info pointer
+//
+// Arguments: (none)
+//
+// Returns: LPBITMAPINFO
+//
+// History: 5-14-94 kirtd Created
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+LPBITMAPINFO
+CBitmapFile::GetBitmapInfo ()
+{
+ return(_pbi);
+}
+
+//+---------------------------------------------------------------------------
+//
+// Member: CBitmapFile::_GetBitmapDataFromBuffer
+//
+// Synopsis: gets the bitmap data from the given buffer
+//
+// Arguments: [pbuffer] -- the buffer
+// [cb] -- the buffer size
+//
+// Returns: HRESULT
+//
+// History: 4-23-94 KirtD Created
+//
+// Notes: BUGBUG: If biClrUsed is set the bitmap is not loaded
+//
+//----------------------------------------------------------------------------
+HRESULT
+CBitmapFile::_GetBitmapDataFromBuffer (LPBYTE pbuffer, ULONG cb)
+{
+ HRESULT hr = ResultFromScode(S_OK);
+ BITMAPFILEHEADER bmfh;
+ BITMAPCOREHEADER *pbch;
+ BITMAPINFOHEADER bih;
+ LPBYTE pbStart;
+ ULONG cbi = 0;
+ ULONG cbData;
+ LPBITMAPINFO pbi = NULL;
+ LPBYTE pbData = NULL;
+ DWORD dwSizeOfHeader;
+
+ //
+ // Record the starting position
+ //
+
+ pbStart = pbuffer;
+
+ //
+ // First validate the buffer for size
+ //
+
+ if (cb < sizeof(BITMAPFILEHEADER))
+ {
+ return(ResultFromScode(E_FAIL));
+ }
+
+ //
+ // Now get the bitmap file header
+ //
+
+ memcpy(&bmfh, pbuffer, sizeof(BITMAPFILEHEADER));
+
+ //
+ // Validate the information
+ //
+
+ hr = _ValidateBitmapFileHeader (&bmfh, cb);
+
+ //
+ // Get the next 4 bytes which will represent the size of the
+ // next structure and allow us to determine the type
+ //
+
+ if (SUCCEEDED(hr))
+ {
+ pbuffer += sizeof(BITMAPFILEHEADER);
+ memcpy(&dwSizeOfHeader, pbuffer, sizeof(DWORD));
+
+ if (dwSizeOfHeader == sizeof(BITMAPCOREHEADER))
+ {
+ pbch = (BITMAPCOREHEADER *)pbuffer;
+ memset(&bih, 0, sizeof(BITMAPINFOHEADER));
+
+ bih.biSize = sizeof(BITMAPINFOHEADER);
+ bih.biWidth = pbch->bcWidth;
+ bih.biHeight = pbch->bcHeight;
+ bih.biPlanes = pbch->bcPlanes;
+ bih.biBitCount = pbch->bcBitCount;
+
+ pbuffer += sizeof(BITMAPCOREHEADER);
+ }
+ else if (dwSizeOfHeader == sizeof(BITMAPINFOHEADER))
+ {
+ memcpy(&bih, pbuffer, sizeof(BITMAPINFOHEADER));
+
+ pbuffer += sizeof(BITMAPINFOHEADER);
+ }
+ else
+ {
+ hr = ResultFromScode(E_FAIL);
+ }
+ }
+
+ //
+ // Check if biClrUsed is set since we do not handle that
+ // case at this time
+ //
+
+ if (SUCCEEDED(hr))
+ {
+ if (bih.biClrUsed != 0)
+ {
+ hr = ResultFromScode(E_FAIL);
+ }
+ }
+
+ //
+ // Now we need to calculate the size of the BITMAPINFO we need
+ // to allocate including any palette information
+ //
+
+ if (SUCCEEDED(hr))
+ {
+ //
+ // First the size of the header
+ //
+
+ cbi = sizeof(BITMAPINFOHEADER);
+
+ //
+ // Now the palette
+ //
+
+ if (bih.biBitCount == BMP_24_BITSPERPIXEL)
+ {
+ //
+ // Just add on the 1 RGBQUAD for the structure but
+ // there is no palette
+ //
+
+ cbi += sizeof(RGBQUAD);
+ }
+ else if ((bih.biBitCount == BMP_16_BITSPERPIXEL) ||
+ (bih.biBitCount == BMP_32_BITSPERPIXEL))
+ {
+ //
+ // Add on the 3 DWORD masks which are used to
+ // get the colors out of the data
+ //
+
+ cbi += (3 * sizeof(DWORD));
+ }
+ else
+ {
+ //
+ // Anything else we just use the bit count to calculate
+ // the number of entries
+ //
+
+ cbi += ((1 << bih.biBitCount) * sizeof(RGBQUAD));
+ }
+
+ //
+ // Now allocate the BITMAPINFO
+ //
+
+ pbi = (LPBITMAPINFO) new BYTE [cbi];
+ if (pbi == NULL)
+ {
+ hr = ResultFromScode(E_OUTOFMEMORY);
+ }
+ }
+
+ //
+ // Fill in the BITMAPINFO data structure and get the bits
+ //
+
+ if (SUCCEEDED(hr))
+ {
+ //
+ // First copy the header data
+ //
+
+ memcpy(&(pbi->bmiHeader), &bih, sizeof(BITMAPINFOHEADER));
+
+ //
+ // Now the palette data
+ //
+
+ if (bih.biBitCount == BMP_24_BITSPERPIXEL)
+ {
+ //
+ // No palette data to copy
+ //
+ }
+ else if ((bih.biBitCount == BMP_16_BITSPERPIXEL) ||
+ (bih.biBitCount == BMP_32_BITSPERPIXEL))
+ {
+ //
+ // Copy the 3 DWORD masks
+ //
+
+ memcpy(&(pbi->bmiColors), pbuffer, 3*sizeof(DWORD));
+ }
+ else
+ {
+ //
+ // If we were a BITMAPCOREHEADER type then we have our
+ // palette data in the form of RGBTRIPLEs so we must
+ // explicitly copy each. Otherwise we can just memcpy
+ // the RGBQUADs
+ //
+
+ if (dwSizeOfHeader == sizeof(BITMAPCOREHEADER))
+ {
+ ULONG cPalEntry = (1 << bih.biBitCount);
+ ULONG cCount;
+ RGBTRIPLE *argbt = (RGBTRIPLE *)pbuffer;
+
+ for (cCount = 0; cCount < cPalEntry; cCount++)
+ {
+ pbi->bmiColors[cCount].rgbRed =
+ argbt[cCount].rgbtRed;
+ pbi->bmiColors[cCount].rgbGreen =
+ argbt[cCount].rgbtGreen;
+ pbi->bmiColors[cCount].rgbBlue =
+ argbt[cCount].rgbtBlue;
+
+ pbi->bmiColors[cCount].rgbReserved = 0;
+ }
+ }
+ else
+ {
+ ULONG cbPalette = (1 << bih.biBitCount) * sizeof(RGBQUAD);
+
+ memcpy(&(pbi->bmiColors), pbuffer, cbPalette);
+ }
+ }
+
+ //
+ // Now find out where the bits are
+ //
+
+ pbuffer = pbStart + bmfh.bfOffBits;
+
+ //
+ // Get the size to copy
+ //
+
+ cbData = cb - bmfh.bfOffBits;
+
+ //
+ // Allocate the buffer to hold the bits
+ //
+
+ pbData = new BYTE [cbData];
+ if (pbData == NULL)
+ {
+ hr = ResultFromScode(E_OUTOFMEMORY);
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ memcpy(pbData, pbuffer, cbData);
+ }
+ }
+
+ //
+ // If everything succeeded record the data
+ //
+
+ if (SUCCEEDED(hr))
+ {
+ //
+ // Record the info
+ //
+
+ delete _pbi;
+ _cbi = cbi;
+ _pbi = pbi;
+
+ //
+ // Record the data
+ //
+
+ delete _pbData;
+ _cbData = cbData;
+ _pbData = pbData;
+ }
+ else
+ {
+ //
+ // Cleanup
+ //
+
+ delete pbi;
+ delete pbData;
+ }
+
+ return(hr);
+}
+
+//+---------------------------------------------------------------------------
+//
+// Member: CBitmapFile::_ValidateBitmapFileHeader
+//
+// Synopsis: validates a bitmap file header
+//
+// Arguments: [pbmfh] -- bitmap file header
+// [cbFile] -- bitmap file size
+//
+// Returns: HRESULT
+//
+// History: 4-23-94 KirtD Created
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+HRESULT
+CBitmapFile::_ValidateBitmapFileHeader (BITMAPFILEHEADER *pbmfh, ULONG cbFile)
+{
+ //
+ // Check for the following,
+ //
+ // 1. The bfType member contains 'BM'
+ // 2. The bfOffset member is NOT greater than the size of the file
+ //
+
+ if ((pbmfh->bfType == 0x4d42) && (pbmfh->bfOffBits <= cbFile))
+ {
+ return(ResultFromScode(S_OK));
+ }
+
+ return(ResultFromScode(E_FAIL));
+}
diff --git a/private/oleutest/cachetst/bmpfile.hxx b/private/oleutest/cachetst/bmpfile.hxx
new file mode 100644
index 000000000..915f6270b
--- /dev/null
+++ b/private/oleutest/cachetst/bmpfile.hxx
@@ -0,0 +1,112 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: bmpfile.hxx
+//
+// Contents: CBitmapFile
+//
+// Classes:
+//
+// Functions:
+//
+// History: 4-23-94 KirtD Created
+//
+//----------------------------------------------------------------------------
+#if !defined(__BMPFILE_HXX__)
+#define __BMPFILE_HXX__
+
+//
+// Data structures and definitions
+//
+
+#define BMP_24_BITSPERPIXEL 24
+#define BMP_16_BITSPERPIXEL 16
+#define BMP_32_BITSPERPIXEL 32
+
+typedef BITMAPINFO *LPBITMAPINFO;
+
+//
+// Class definition
+//
+
+class CBitmapFile
+{
+public:
+
+ //
+ // Constructor
+ //
+
+ CBitmapFile ();
+
+ //
+ // Destructor
+ //
+
+ ~CBitmapFile ();
+
+ //
+ // Load and related methods
+ //
+
+ HRESULT LoadBitmapFile (LPSTR pszFile);
+ HRESULT GetBitmapFileName (LPSTR pszFile, ULONG cChar) const;
+ ULONG GetBitmapFileNameLength () const;
+
+ //
+ // Data access methods
+ //
+
+ LONG GetDIBHeight () const;
+ LONG GetDIBWidth () const;
+ HRESULT GetLogicalPalette (LPLOGPALETTE *pplogpal) const;
+ HRESULT CreateDIBInHGlobal (HGLOBAL *phGlobal) const;
+ BOOL HasPaletteData () const;
+
+ //
+ // Member access
+ //
+
+ LPBITMAPINFO GetBitmapInfo ();
+ LPBYTE GetDIBBits ();
+
+private:
+
+ //
+ // Private data
+ //
+
+ //
+ // The file name
+ //
+
+ CHAR _pszBitmapFile[MAX_PATH];
+ ULONG _cBitmapFile;
+
+ //
+ // The bitmap info structure
+ //
+
+ ULONG _cbi;
+ BITMAPINFO *_pbi;
+
+ //
+ // The bits
+ //
+
+ ULONG _cbData;
+ LPBYTE _pbData;
+
+ //
+ // Private methods
+ //
+
+ HRESULT _GetBitmapDataFromBuffer (LPBYTE pbuffer, ULONG cbLow);
+ HRESULT _ValidateBitmapFileHeader (BITMAPFILEHEADER *pbmfh, ULONG cbFile);
+};
+
+#endif
+
+
diff --git a/private/oleutest/cachetst/ctest.hxx b/private/oleutest/cachetst/ctest.hxx
new file mode 100644
index 000000000..be678e0f0
--- /dev/null
+++ b/private/oleutest/cachetst/ctest.hxx
@@ -0,0 +1,138 @@
+//+----------------------------------------------------------------------------
+//
+// File:
+// ctest.hxx
+//
+// Contents:
+// Primary include file for Cache Unit Test
+//
+// Classes:
+// TestInstance - Instance of cache unit test methods
+//
+// History:
+// 04-Sep-94 davepl Created
+//
+//-----------------------------------------------------------------------------
+
+//
+// PROTOTYPES
+//
+
+HRESULT EltIsInArray(STATDATA sdToFind, STATDATA rgStat[], DWORD cCount);
+ULONG __stdcall LaunchTestInstance(void *);
+int ConvHeightInPelsToLHM(HDC, int);
+int ConvWidthInPelsToLHM(HDC, int);
+int mprintf(LPCSTR szFormat, ...);
+int dprintf(LPCSTR szFormat, ...);
+
+//
+// Possible states for the unit test
+//
+
+typedef enum tagTEST_STATE
+{
+ INVALID_STATE,
+ TEST_STARTING,
+ TESTING_ENUMERATOR,
+ SAVE_AND_RELOAD,
+ MULTI_CACHE,
+ DATA_TEST,
+ DRAW_METAFILE_NOW,
+ DRAW_METAFILETILED_NOW,
+ DRAW_DIB_NOW,
+ DRAW_DIBTILED_NOW
+} TEST_STATE;
+
+
+//
+// Class which defines one particular Cache Test object
+//
+
+class TestInstance
+{
+
+private:
+
+ IStorage *m_pStorage;
+ IPersistStorage *m_pPersistStorage;
+ IDataObject *m_pDataObject;
+ IViewObject *m_pViewObject;
+ OLECHAR m_wszStorage[ MAX_PATH ];
+ TEST_STATE m_State;
+
+public:
+ TestInstance();
+ ~TestInstance();
+
+ IOleCache *m_pOleCache;
+ IOleCache2 *m_pOleCache2;
+
+
+ HRESULT CreateAndInit(LPOLESTR lpwszStgName);
+ HRESULT SaveCache();
+ HRESULT LoadCache();
+ HRESULT SaveAndReload();
+
+ HRESULT AddMFCacheNode(DWORD *pdwCon);
+ HRESULT AddEMFCacheNode(DWORD *pdwCon);
+ HRESULT AddDIBCacheNode(DWORD *pdwCon);
+ HRESULT AddBITMAPCacheNode(DWORD *pdwCon);
+ HRESULT UncacheFormat(CLIPFORMAT);
+
+ HRESULT EnumeratorTest();
+ HRESULT MultiCache(DWORD dwCount);
+
+ HRESULT CacheDataTest(char *, char *);
+ HRESULT CompareDIB(HGLOBAL);
+ HRESULT CompareMF(HGLOBAL);
+ HRESULT DrawCacheToMetaFilePict(HGLOBAL *, BOOL);
+ void Draw(HDC);
+ TEST_STATE GetCurrentState();
+ void SetCurrentState(TEST_STATE);
+};
+
+#ifndef DEF_LINDEX
+#define DEF_LINDEX (-1)
+#endif
+
+//
+// I N L I N E U T I L I T Y F U N C T I O N S
+//
+
+
+//+----------------------------------------------------------------------------
+//
+// Member: MassageErrorCode
+//
+// Synopsis: Takes a given HRESULT and converts it to S_OK if
+// [hrExpected] is the error code. If the HRESULT is
+// not S_OK and not Expected, it is left untouched.
+// If it was S_OK, it is changed to E_UNEXPECTED.
+//
+// Arguments: [hrExpected] The acceptable error code
+// [hrIn] The error code in question
+//
+// Returns: HRESULT (not as a success value for this fn)
+//
+// Notes:
+//
+// History: 23-Aug-94 Davepl Created
+//
+//-----------------------------------------------------------------------------
+
+inline HRESULT MassageErrorCode(HRESULT hrExpected, HRESULT hrIn)
+{
+
+ if (hrExpected == hrIn)
+ {
+ return S_OK;
+ }
+ else if (S_OK == hrIn)
+ {
+ return E_UNEXPECTED;
+ }
+ else
+ {
+ return hrIn;
+ }
+}
diff --git a/private/oleutest/cachetst/ctestapp.hxx b/private/oleutest/cachetst/ctestapp.hxx
new file mode 100644
index 000000000..57fb27435
--- /dev/null
+++ b/private/oleutest/cachetst/ctestapp.hxx
@@ -0,0 +1,129 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: ctestapp.hxx
+//
+// Contents: CCacheTestApp
+//
+// Classes:
+//
+// Functions:
+//
+// History: 05-Sep-94 Davepl Created
+//
+//----------------------------------------------------------------------------
+//
+// Definitions
+//
+
+#define CTESTAPPCLASS ("CacheTestAppWindClass")
+#define CTESTAPPTITLE ("OLE Cache Unit Test")
+
+//
+// Application window procedure
+//
+
+extern "C" {
+
+LRESULT FAR PASCAL
+CacheTestAppWndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
+
+}
+
+//
+// Class definition
+//
+
+class CCacheTestApp
+{
+public:
+
+ //
+ // Constructor and initialization routines
+ //
+
+ CCacheTestApp();
+ HRESULT Initialize (HINSTANCE hInst,
+ HINSTANCE hPrevInst,
+ LPSTR lpszCmdLine);
+
+ //
+ // Destructor
+ //
+
+ ~CCacheTestApp();
+
+ //
+ // Member access
+ //
+
+ inline HWND Window();
+ inline HANDLE Mutex();
+
+ //
+ // Unit-Test Thread information
+ //
+
+ HANDLE m_hTest;
+ DWORD m_dwThreadID;
+
+ HMETAFILEPICT m_hMFP;
+ HMETAFILEPICT m_hMFPTILED;
+ HMETAFILEPICT m_hMFPDIB;
+ HMETAFILEPICT m_hMFPDIBTILED;
+
+private:
+
+ HWND m_hWnd;
+ HANDLE m_hMutex;
+
+
+};
+
+//
+// Inline functions
+//
+
+//+---------------------------------------------------------------------------
+//
+// Member: CCacheTestApp::Window
+//
+// Synopsis: returns m_hWnd
+//
+// Arguments: (none)
+//
+// Returns: HWND
+//
+// History: 05-Sep-94 Davepl Created
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+
+inline HWND CCacheTestApp::Window ()
+{
+ return m_hWnd;
+}
+
+//+---------------------------------------------------------------------------
+//
+// Member: CCacheTestApp::Mutex
+//
+// Synopsis: returns m_hMutex
+//
+// Arguments: (none)
+//
+// Returns: HANDLE
+//
+// History: 05-Sep-94 Davepl Created
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+
+inline HANDLE CCacheTestApp::Mutex()
+{
+ return m_hMutex;
+}
diff --git a/private/oleutest/cachetst/davedbg.cpp b/private/oleutest/cachetst/davedbg.cpp
new file mode 100644
index 000000000..7a37c5c64
--- /dev/null
+++ b/private/oleutest/cachetst/davedbg.cpp
@@ -0,0 +1,473 @@
+//+----------------------------------------------------------------------------
+//
+// File: DAVEDBG.CPP
+//
+// Synopsis: TraceLog class for debugging
+//
+// Arguments:
+//
+// History: 23-Aug-94 Davepl Created
+//
+//-----------------------------------------------------------------------------
+
+#include "headers.hxx"
+#pragma hdrstop
+
+GROUPSET LEGroups = GS_CACHE; // Groups to display
+VERBOSITY LEVerbosity = VB_MAXIMUM; // Verbosity level to display at
+
+
+//+----------------------------------------------------------------------------
+//
+// Member: dprintf
+//
+// Synopsis: Dumps a printf style string to the debugger.
+//
+// Arguments: [szFormat] THIS pointer of caller
+// [...] Arguments
+//
+// Notes:
+//
+// History: 05-Sep-94 Davepl Created
+//
+//-----------------------------------------------------------------------------
+
+int dprintf(LPCSTR szFormat, ...)
+{
+ char szBuffer[MAX_BUF];
+
+ va_list vaList;
+ va_start(vaList, szFormat);
+
+ int retval = vsprintf(szBuffer, szFormat, vaList);
+
+ OutputDebugStringA(szBuffer);
+
+ va_end (vaList);
+ return retval;
+}
+
+//+----------------------------------------------------------------------------
+//
+// Member: mprintf
+//
+// Synopsis: Dumps a printf style string to a message box.
+//
+// Arguments: [szFormat] THIS pointer of caller
+// [...] Arguments
+//
+// Notes:
+//
+// History: 05-Sep-94 Davepl Created
+//
+//-----------------------------------------------------------------------------
+
+int mprintf(LPCSTR szFormat, ...)
+{
+ char szBuffer[MAX_BUF];
+
+ va_list vaList;
+ va_start(vaList, szFormat);
+
+ int retval = vsprintf(szBuffer, szFormat, vaList);
+
+ extern CCacheTestApp ctest;
+
+ MessageBox(ctest.Window(),
+ szBuffer,
+ "CACHE UNIT TEST INFO",
+ MB_ICONINFORMATION | MB_APPLMODAL | MB_OK);
+
+ va_end (vaList);
+ return retval;
+}
+
+//+----------------------------------------------------------------------------
+//
+// Member: TraceLog::TraceLog
+//
+// Synopsis: Records the THIS ptr and function name of the caller,
+// and determines whether or not the caller meets the
+// group and verbosity criteria for debug output
+//
+// Arguments: [pvThat] THIS pointer of caller
+// [pszFuntion] name of caller
+// [gsGroups] groups to which caller belongs
+// [vbVerbosity] verbosity level need to display debug
+// info for this function
+//
+// Notes:
+//
+// History: 23-Aug-94 Davepl Created
+//
+//-----------------------------------------------------------------------------
+
+TraceLog::TraceLog (void * pvThat,
+ char * pszFunction,
+ GROUPSET gsGroups,
+ VERBOSITY vbVerbosity)
+{
+ //
+ // Determine whether or not the trace logging should be displayed
+ // for this function. Iff it is, we need to track some information
+ // about the function (ie: this ptr, func name)
+ //
+ // In order to be displayed, the function must belong to a group
+ // which has been set in the group display mask, and the function
+ // must be in an equal or lesser verbosity class.
+ //
+
+ if ( (gsGroups & LEGroups) && (LEVerbosity >= vbVerbosity) )
+ {
+ m_fShouldDisplay = TRUE;
+ m_pvThat = pvThat;
+ strncpy(m_pszFunction, pszFunction, MAX_BUF - 1);
+ }
+ else
+ {
+ m_fShouldDisplay = FALSE;
+ }
+}
+
+//+----------------------------------------------------------------------------
+//
+// Member: TraceLog::OnEntry()
+//
+// Synopsis: Default entry output, which simply displays the _IN
+// trace with the function name and THIS pointer
+//
+// Returns: HRESULT
+//
+// Notes:
+//
+// History: 23-Aug-94 Davepl Created
+//
+//-----------------------------------------------------------------------------
+
+void TraceLog::OnEntry()
+{
+ if (m_fShouldDisplay)
+ {
+ dprintf("[%p] _IN %s\n", m_pvThat, m_pszFunction);
+ }
+}
+
+//+----------------------------------------------------------------------------
+//
+// Member: TraceLog::OnEntry
+//
+// Synopsis: Displays standard entry debug info, plus a printf
+// style trailer string as supplied by the caller
+//
+// Arguments: [pszFormat ...] printf style output string
+//
+// Returns: void
+//
+// Notes:
+//
+// History: 23-Aug-94 Davepl Created
+//
+//-----------------------------------------------------------------------------
+
+void TraceLog::OnEntry(char * pszFormat, ...)
+{
+ //
+ // Only display if we have already matched the correct criteria
+ //
+
+ if (m_fShouldDisplay)
+ {
+ char szBuffer[MAX_BUF];
+
+ //
+ // print the standard trace output, then the custom information as
+ // received from the caller
+ //
+
+ dprintf("[%p] _IN %s ", m_pvThat, m_pszFunction);
+
+ va_list vaList;
+ va_start(vaList, pszFormat);
+ vsprintf(szBuffer, pszFormat, vaList);
+ dprintf(szBuffer);
+ va_end(vaList);
+ }
+}
+
+//+----------------------------------------------------------------------------
+//
+// Member: TraceLog::OnExit
+//
+// Synopsis: Sets the debug info that should be displayed when
+// the TraceLog object is destroyed
+//
+// Arguments: [pszFormat ...] printf style custom info
+//
+// Returns: void
+//
+// Notes: Since it would make no sense to pass variables by
+// value into this function (which would snapshot them
+// at the time this was called), variables in the arg
+// list must be passed by REFERENCE
+//
+// History: 23-Aug-94 Davepl Created
+//
+//-----------------------------------------------------------------------------
+
+void TraceLog::OnExit(const char * pszFormat, ...)
+{
+ if (m_fShouldDisplay)
+ {
+ const char * pch; // ptr to walk format string
+ BOOL fBreak; // set when past fmt specifier
+
+ //
+ // Start processing the argument list
+ //
+
+ va_list arg;
+ va_start (arg, pszFormat);
+
+ //
+ // Save the format string for use in the destructor
+ //
+
+ strcpy (m_pszFormat, pszFormat);
+ m_cArgs = 0;
+
+ //
+ // Walk the format string looking for % modifiers
+ //
+
+ for (pch = pszFormat; *pch; pch++)
+ {
+ if (*pch != '%')
+ {
+ continue;
+ }
+
+ // We can stop looking until EOL or end of specifier
+
+ fBreak = FALSE;
+
+ while (!fBreak)
+ {
+ if (!* (++pch)) // Hit EOL
+ {
+ break;
+ }
+
+ switch (*pch)
+ {
+ //
+ // These are all valid format specifiers and
+ // modifers which may be combined to reference
+ // a single argument in the argument list
+ //
+
+ case 'F':
+ case 'l':
+ case 'h':
+ case 'X':
+ case 'x':
+ case 'O':
+ case 'o':
+ case 'd':
+ case 'u':
+ case 'c':
+ case 's':
+
+ break;
+
+ default:
+
+ //
+ // We have hit a character which is not a valid specifier,
+ // so we stop searching in order to pull the argument
+ // which corresponds with it from the arg list
+ //
+ fBreak = TRUE;
+ break;
+ }
+ }
+
+ //
+ // If we have already hit the maximum number of args, we can't do
+ // any more
+ //
+
+ if (m_cArgs == MAX_ARGS)
+ {
+ break;
+ }
+
+ //
+ // Grab the argument as a NULL ptr. We will save it away and figure
+ // out what kind of argument it was when it comes time to display it,
+ // based on the format string
+ //
+
+ m_aPtr[m_cArgs] = va_arg (arg, void *);
+ m_cArgs++;
+
+ if (! *pch)
+ {
+ break;
+ }
+ }
+ }
+}
+
+//+----------------------------------------------------------------------------
+//
+// Member: TraceLog::~TraceLog
+//
+// Synopsis: On destruction, the TraceLog class displays its debug
+// output as set by the OnExit() method.
+//
+// Returns: void
+//
+// Notes:
+//
+// History: 23-Aug-94 Davepl Created
+//
+//-----------------------------------------------------------------------------
+
+TraceLog::~TraceLog()
+{
+ char szTmpFmt[ MAX_BUF ];
+ char szOutStr[ MAX_BUF ];
+ char *pszOut;
+ char *pszszTmpFmt;
+ const char * pszFmt;
+ void *pv;
+ BYTE i = 0;
+ VARTYPE vtVarType;
+ BOOL fBreak;
+
+ pszOut = szOutStr;
+
+ //
+ // Walk the format string looking for format specifiers
+ //
+
+ for (pszFmt = m_pszFormat; *pszFmt; pszFmt++)
+ {
+ if (*pszFmt != '%')
+ {
+ *pszOut++ = *pszFmt;
+ continue;
+ }
+
+ //
+ // Found the start of a specifier. Reset the expected argument type,
+ // then walk to the end of the specifier
+ //
+
+ vtVarType = NO_TYPE;
+ fBreak = FALSE;
+
+ //
+ // Start recording the specifier for a single call to sprintf later
+ //
+
+ for (pszszTmpFmt = szTmpFmt; !fBreak; )
+ {
+ *pszszTmpFmt++ = *pszFmt;
+
+ //
+ // Guard against a terminator that doesn't comlete before EOL
+ //
+
+ if (!* (++pszFmt))
+ {
+ break;
+ }
+
+ //
+ // These are all valid format specifiers. Skip over them and
+ // update the vtVarType. It's end value will be our heuristic
+ // which indicates what type of variable was really intended
+ //
+
+ switch (*pszFmt)
+ {
+ case 'l': vtVarType |= LONG_TYPE; break;
+ case 'h': vtVarType |= SHORT_TYPE; break;
+ case 'X': vtVarType |= INT_TYPE; break;
+ case 'x': vtVarType |= INT_TYPE; break;
+ case 'O': vtVarType |= INT_TYPE; break;
+ case 'o': vtVarType |= INT_TYPE; break;
+ case 'd': vtVarType |= INT_TYPE; break;
+ case 'u': vtVarType |= INT_TYPE; break;
+ case 'c': vtVarType |= CHAR_TYPE; break;
+ case 's': vtVarType |= STRING_TYPE; break;
+ case 'p': vtVarType |= PTR_TYPE; break;
+ default: fBreak = TRUE; break;
+ }
+ }
+
+ // NUL-terminate the end of the temporary format string
+
+ *pszszTmpFmt = 0;
+
+ // Grab the argument pointer which corresponds to this argument
+
+ pv = m_aPtr[ i ];
+ i++;
+
+ //
+ // Using the appropriate cast, spew the argument into our
+ // local output buffer using the original format specifier.
+ //
+
+ if (vtVarType & STRING_TYPE)
+ {
+ sprintf (pszOut, szTmpFmt, (char *)pv);
+ }
+ else if (vtVarType & LONG_TYPE)
+ {
+ sprintf (pszOut, szTmpFmt, *(long *)pv);
+ }
+ else if (vtVarType & SHORT_TYPE)
+ {
+ sprintf (pszOut, szTmpFmt, *(short *)pv);
+ }
+ else if (vtVarType & INT_TYPE)
+ {
+ sprintf (pszOut, szTmpFmt, *(int *)pv);
+ }
+ else if (vtVarType & CHAR_TYPE)
+ {
+ sprintf (pszOut, szTmpFmt, (char)*(char *)pv);
+ }
+ else if (vtVarType & PTR_TYPE)
+ {
+ sprintf (pszOut, szTmpFmt, (void *)pv);
+ }
+ else
+ {
+ *pszOut = 0;
+ }
+
+ // Advance the output buffer pointer to the end of the
+ // current buffer
+
+ pszOut = &pszOut[ strlen(pszOut) ];
+
+ if (! *pszFmt)
+ {
+ break;
+ }
+ }
+
+ // NUL-terminate the buffer
+
+ *pszOut = 0;
+
+ //
+ // Dump the resultant buffer to the output
+ //
+
+ dprintf("[%p] OUT %s %s", m_pvThat, m_pszFunction, szOutStr);
+}
diff --git a/private/oleutest/cachetst/davedbg.h b/private/oleutest/cachetst/davedbg.h
new file mode 100644
index 000000000..7ac74e33d
--- /dev/null
+++ b/private/oleutest/cachetst/davedbg.h
@@ -0,0 +1,74 @@
+//+----------------------------------------------------------------------------
+//
+// File:
+// davedbg.h
+//
+// Contents:
+// A debug trace class
+//
+// Classes:
+// TraceLog
+//
+// History:
+// 04-Sep-94 davepl Created
+//
+//-----------------------------------------------------------------------------
+
+const ULONG MAX_ARGS = 20;
+const ULONG MAX_BUF = 255;
+
+typedef enum tagGROUPSET
+{
+ GS_CACHE = 0x000000001
+} GROUPSET;
+
+typedef enum tagDVARTYPE
+{
+ NO_TYPE = 0x0000,
+ LONG_TYPE = 0x0001,
+ SHORT_TYPE = 0x0002,
+ INT_TYPE = 0x0004,
+ CHAR_TYPE = 0x0008,
+ STRING_TYPE = 0x0010,
+ FLOAT_TYPE = 0x0020,
+ COMMA_TYPE = 0x0040,
+ MSG_TYPE = 0x0080,
+ PTR_TYPE = 0x0100,
+ HEXINT_TYPE = 0x0200
+} DVARTYPE;
+
+inline DVARTYPE operator |= (DVARTYPE & vtORON, const DVARTYPE vtORBY)
+{
+ return (vtORON = (DVARTYPE)((int) vtORON | (int) vtORBY));
+}
+
+typedef enum tagVERBOSITY
+{
+ VB_SILENT = 0x0000,
+ VB_MINIMAL = 0x0001,
+ VB_MODERATE = 0x0002,
+ VB_MAXIMUM = 0x0004
+} VERBOSITY;
+
+class TraceLog
+{
+public:
+
+ TraceLog (void *, char *, GROUPSET, VERBOSITY);
+ ~TraceLog();
+
+ void OnEntry();
+ void OnEntry(char * pszFormat, ...);
+ void OnExit (const char * pszFormat, ...);
+
+
+private:
+
+ char m_pszFormat[ MAX_BUF ];
+ void *m_aPtr[ MAX_ARGS ];
+ BYTE m_cArgs;
+ BOOL m_fShouldDisplay;
+ void *m_pvThat;
+ char m_pszFunction[MAX_BUF];
+};
+
diff --git a/private/oleutest/cachetst/daytona/sources b/private/oleutest/cachetst/daytona/sources
new file mode 100644
index 000000000..14404f1e6
--- /dev/null
+++ b/private/oleutest/cachetst/daytona/sources
@@ -0,0 +1,83 @@
+!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:
+
+ Donna Liu (DonnaLi) 19-Dec-1993
+
+!ENDIF
+
+MAJORCOMP = cairole
+MINORCOMP = com
+
+#
+# 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= cachetst
+
+#
+# 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= ..;..\..\inc;..\..\common;..\..\..\ole32\common\daytona;..\..\..\ole32\ih;..\..\..\cinc
+
+C_DEFINES= \
+ $(C_DEFINES) \
+ -DFLAT \
+ -DWIN32=100 \
+ -D_NT1X_=100 \
+ -DNOEXCEPTIONS \
+ -DCAIROLE_DOWNLEVEL
+
+BLDCRT= 1
+
+SOURCES= \
+ ..\bmpfile.cxx \
+ ..\davedbg.cpp \
+ ..\genenum.cpp \
+ ..\genforc.cpp \
+ ..\main.cpp \
+ ..\multi.cpp \
+ ..\utils.cpp
+
+UMTYPE= windows
+UMENTRY= winmain
+UMAPPL=
+UMTEST=
+UMLIBS= \
+ $(BASEDIR)\public\sdk\lib\*\ole32.lib \
+ $(BASEDIR)\public\sdk\lib\*\comdlg32.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\*\crtdll.lib \
+ $(BASEDIR)\public\sdk\lib\*\uuid.lib
+
+USE_CRTDLL= 1
diff --git a/private/oleutest/cachetst/dirs b/private/oleutest/cachetst/dirs
new file mode 100644
index 000000000..4084985bc
--- /dev/null
+++ b/private/oleutest/cachetst/dirs
@@ -0,0 +1,36 @@
+!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/cachetst/enum.cpp b/private/oleutest/cachetst/enum.cpp
new file mode 100644
index 000000000..6dc858afd
--- /dev/null
+++ b/private/oleutest/cachetst/enum.cpp
@@ -0,0 +1,318 @@
+//+----------------------------------------------------------------------------
+//
+// File:
+// enum.cpp
+//
+// Contents:
+// Enumerator test methods for the cache unit test
+//
+// History:
+//
+// 04-Sep-94 davepl Created
+//
+//-----------------------------------------------------------------------------
+
+#include "headers.hxx"
+#pragma hdrstop
+
+//+----------------------------------------------------------------------------
+//
+// Member: TestInstance::EnumeratorTest
+//
+// Synopsis: Performs various tests on the cache enumerator
+//
+// Arguments: (void)
+//
+// Returns: HRESULT
+//
+// Notes: General sequence of events is as follows:
+//
+// - Add cache nodes for EMF, DIB (and BMP) and MF
+// - Try to add BMP node (expecting failure)
+// - Create a cache enumerator
+// - Run generic enumerator tests on that cache enumerator
+// - Reset the enumerator
+// - Grab the 4 nodes added above in a single Next()
+// - Verify that the correct 4 nodes were returned
+// - Reset the enumerator
+// - Uncache the MF node
+// - Grab the 3 remaining nodes
+// - Verify that the correct 3 nodes were returned
+// - Reset the enumerator
+// - Skip 1 node
+// - Uncache the DIB (and BMP) node
+// - Try to uncache the BMP node (expecting failure)
+// - Try to skip (expecting failure, as BMP node has disappeared midflight)
+// - Uncache the EMF node (cache should now be empty)
+// - Reset and Skip (expecting failure to verify the cache is empty)
+// - Release the enumerator
+//
+// History: 23-Aug-94 Davepl Created
+//
+//-----------------------------------------------------------------------------
+
+HRESULT TestInstance::EnumeratorTest()
+{
+ HRESULT hr;
+ DWORD dwEMFCon, dwBMPCon, dwDIBCon, dwMFCon;
+
+ TraceLog Log(this, "TestInstance::EnumeratorTest", GS_CACHE, VB_MINIMAL);
+ Log.OnEntry ();
+ Log.OnExit (" ( %X )\n", &hr);
+
+ SetCurrentState(TESTING_ENUMERATOR);
+ //
+ // Cache DIB, MF, EMF, and BITMAP nodes
+ //
+
+ hr = AddEMFCacheNode(&dwEMFCon);
+
+ if (S_OK == hr)
+ {
+ hr = AddDIBCacheNode(&dwDIBCon);
+ }
+
+ if (S_OK == hr)
+ {
+ hr = AddMFCacheNode(&dwMFCon);
+ }
+
+ if (S_OK == hr)
+ {
+ hr = AddBITMAPCacheNode(&dwBMPCon);
+
+ //
+ // We expect that caching a Bitmap node when a DIB node has
+ // already been cached should return CACHE_S_SAMECACHE, so
+ // we transform that into S_OK
+ //
+
+ if (CACHE_S_SAMECACHE == hr)
+ {
+ hr = S_OK;
+ }
+ }
+
+ //
+ // Get an enumerator on the cache
+ //
+
+ LPENUMSTATDATA pEsd;
+ if (S_OK == hr)
+ {
+ hr = m_pOleCache->EnumCache(&pEsd);
+ }
+
+ //
+ // Perform generic emnumerator testing
+ //
+
+ if (S_OK == hr)
+ {
+ hr = TestEnumerator((void *) pEsd, sizeof(STATDATA), 4, NULL, NULL,NULL);
+ }
+
+ //
+ // Reset the enumerator before our specific tests
+ //
+
+ if (S_OK == hr)
+ {
+ hr = pEsd->Reset();
+ }
+
+
+ ULONG cFetched; // Count of elements enumd
+ STATDATA rgStat[4]; // Array of STATDATA to enum into
+
+ //
+ // Get an enumeration of the expected 4 nodes, then check to
+ // ensure that all four match (at a basic level) the four
+ // we expect to find
+ //
+
+ if (S_OK == hr)
+ {
+ hr = pEsd->Next(4, rgStat, &cFetched);
+ }
+
+ STATDATA sdEMF, sdMF, sdBMP, sdDIB;
+
+ // These are the STATDATAs we expect to find
+
+ sdEMF.formatetc.cfFormat = CF_ENHMETAFILE;
+ sdEMF.dwConnection = dwEMFCon;
+ sdMF.formatetc.cfFormat = CF_METAFILEPICT;
+ sdMF.dwConnection = dwMFCon;
+ sdDIB.formatetc.cfFormat = CF_BITMAP;
+ sdDIB.dwConnection = dwBMPCon;
+ sdBMP.formatetc.cfFormat = CF_DIB;
+ sdBMP.dwConnection = dwBMPCon;
+
+ //
+ // Verify that each of our STATDATAs came back
+ // from the enumeration
+ //
+
+ if (S_OK == hr)
+ {
+ if (S_FALSE == EltIsInArray(sdDIB, rgStat, 4))
+ {
+ hr = E_FAIL;
+ }
+ else if (S_FALSE == EltIsInArray(sdBMP, rgStat, 4))
+ {
+ hr = E_FAIL;
+ }
+ else if (S_FALSE == EltIsInArray(sdEMF, rgStat, 4))
+ {
+ hr = E_FAIL;
+ }
+ else if (S_FALSE == EltIsInArray(sdMF, rgStat, 4))
+ {
+ hr = E_FAIL;
+ }
+ }
+
+ //
+ // Reset the enumerator
+ //
+
+ if (S_OK == hr)
+ {
+ hr = pEsd->Reset();
+ }
+
+ //
+ // Remove the EMF node, leaving only MF, DIB and Bitmap
+ //
+
+ if (S_OK == hr)
+ {
+ hr = m_pOleCache->Uncache(dwMFCon);
+ }
+
+ //
+ // Get an enumeration of the expected 3 nodes, then check to
+ // ensure that the DIB and Bitmap nodes are there
+ //
+
+ if (S_OK == hr)
+ {
+ hr = pEsd->Next(3, rgStat, &cFetched);
+ }
+
+ //
+ // Verify that each of our STATDATAs came back
+ // from the enumeration.
+ //
+
+ if (S_OK == hr)
+ {
+ if (S_FALSE == EltIsInArray(sdDIB, rgStat, 3))
+ {
+ hr = E_FAIL;
+ }
+ else if (S_FALSE == EltIsInArray(sdBMP, rgStat, 3))
+ {
+ hr = E_FAIL;
+ }
+ else if (S_FALSE == EltIsInArray(sdEMF, rgStat, 3))
+ {
+ hr = E_FAIL;
+ }
+ }
+
+ //
+ // Reset and Skip one node. WARNING: We assume that the EMF
+ // node is the first on to be enum'd. This is NOT valid, but
+ // is based on knowledge of how the cache is implemented, and
+ // is our only way of testing this...
+ //
+
+ if (S_OK == hr)
+ {
+ hr = pEsd->Reset();
+ }
+
+ if (S_OK == hr)
+ {
+ hr = pEsd->Skip(1);
+ }
+
+ //
+ // What we expect at this point: EMF
+ // DIB <---
+ // BMP
+ //
+ //
+ // If we kill the DIB or BMP node, both should disappear, and Next()
+ // must fail (even though we can't assume order, we know that DIB
+ // and BMP are never enum'd out of order, such as DIB-EMF-DIB
+ //
+
+ if (S_OK == hr)
+ {
+ hr = m_pOleCache->Uncache(dwDIBCon);
+ }
+
+ // Since we have uncached the DIB node, the BITMAP node should have
+ // been automatically uncached as well. First we ensure that we are
+ // unable to uncache the BITMAP node...
+
+ if (S_OK == hr)
+ {
+ hr = m_pOleCache->Uncache(dwBMPCon);
+
+ // This _should_ have failed, so adjust the error code
+
+ hr = MassageErrorCode(OLE_E_NOCONNECTION, hr);
+ }
+
+ //
+ // Now try to skip; the next node automatically disappeared,
+ // so it should fail
+ //
+
+ if (S_OK == hr)
+ {
+ hr = pEsd->Skip(1);
+
+ // The above _should_ fail
+
+ hr = MassageErrorCode(S_FALSE, hr);
+ }
+
+ //
+ // The EMF node should be the only one remaining, so uncache it
+ // to ensure that we leave the cache as empty as we found it.
+ //
+
+
+ if (S_OK == hr)
+ {
+ hr = m_pOleCache->Uncache(dwEMFCon);
+ }
+
+ //
+ // Verify that the cache is empty
+ //
+
+ if (S_OK == hr)
+ {
+ hr = pEsd->Reset();
+ if (hr == S_OK)
+ {
+ hr = pEsd->Skip(1);
+ hr = MassageErrorCode(S_FALSE, hr);
+ }
+ }
+
+ //
+ // Release the enumerator
+ //
+
+ pEsd->Release();
+
+ return hr;
+}
diff --git a/private/oleutest/cachetst/genenum.cpp b/private/oleutest/cachetst/genenum.cpp
new file mode 100644
index 000000000..ab3166c77
--- /dev/null
+++ b/private/oleutest/cachetst/genenum.cpp
@@ -0,0 +1,722 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: genenum.cpp
+//
+// Contents: implementation of CEnumeratorTest object
+// This is the object that does all of the testing.
+//
+// Classes:
+//
+// Functions:
+//
+// History: dd-mmm-yy Author Comment
+// 24-May-94 kennethm author
+//
+//--------------------------------------------------------------------------
+
+#include "headers.hxx"
+#pragma hdrstop
+
+//+-------------------------------------------------------------------------
+//
+// Member: CEnumeratorTest::CEnumeratorTest
+//
+// Synopsis: constructor
+//
+// Arguments: none
+//
+// Returns:
+//
+// History: dd-mmm-yy Author Comment
+// 24-May-94 kennethm author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+CEnumeratorTest::CEnumeratorTest()
+{
+ m_pEnumTest = NULL;
+ m_ElementSize = 0;
+ m_ElementCount = -1;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Member: CEnumeratorTest::CEnumeratorTest
+//
+// Synopsis: constructor
+//
+// Arguments: [enumtest] -- The enumerator object to be tested
+// [elementsize] -- The size of one element from next
+// [elementcount] -- The number of elements expected to in
+// the enumerator. 0 if unknown.
+//
+// Returns:
+//
+// History: dd-mmm-yy Author Comment
+// 24-May-94 kennethm author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+CEnumeratorTest::CEnumeratorTest(IGenEnum * enumtest, size_t elementsize, LONG elementcount)
+{
+ m_pEnumTest = enumtest;
+ m_ElementSize = elementsize;
+ m_ElementCount = elementcount;
+}
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: CEnumeratorTest::GetNext
+//
+// Synopsis: Internal Next Implementation. Does some basic checks on the
+// return values.
+//
+// Effects:
+//
+// Arguments: [celt] -- the number of items to fetch
+// [pceltFetched] -- the number of items fetched
+// [phresult] -- the return from next
+//
+// Requires:
+//
+// Returns: True if the basic tests passed, false if they didn't
+// The result of the next call itself is passed in param 3.
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm: Checks:
+// That if s_ok is returned celt and pceltFetched are ==
+// If a verify is provided it is called
+//
+// History: dd-mmm-yy Author Comment
+// 24-May-94 kennethm author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+BOOL CEnumeratorTest::GetNext( ULONG celt,
+ ULONG* pceltFetched,
+ HRESULT* phresult
+ )
+{
+ void* prgelt;
+ ULONG ul;
+ BOOL fRet = TRUE;
+
+ //
+ // Allocate memory for the return elements
+ //
+
+ prgelt = new char[m_ElementSize * celt];
+
+ if (prgelt == NULL)
+ {
+ printf("IEnumX::GetNext out of memory.\r\n");
+
+ return(FALSE);
+ }
+
+ //
+ // Call next
+ //
+
+ *phresult = m_pEnumTest->Next(celt, prgelt, pceltFetched);
+
+ //
+ // If the return result is S_OK make sure the numbers match
+ //
+
+ if (*phresult == S_OK)
+ {
+ if ((pceltFetched) && (celt != *pceltFetched))
+ {
+ printf("IEnumX::Next returned S_OK but celt"
+ " and pceltFetch mismatch.\r\n");
+
+ fRet = FALSE;
+ }
+ }
+
+ //
+ // If false is returned then make sure celt is less than
+ // the number actually fetched
+ //
+
+ if (*phresult == S_FALSE)
+ {
+ if ((pceltFetched) && (celt < *pceltFetched))
+ {
+ printf("IEnumX::Next return S_FALSE but celt is"
+ " less than pceltFetch.\r\n");
+
+ fRet = FALSE;
+ }
+ }
+
+ //
+ // Call verify to make sure the elements are ok.
+ //
+
+ if ((*phresult == S_OK) || (*phresult == S_FALSE))
+ {
+ //
+ // If we got S_FALSE back set celt to the number of elements
+ // returned in pceltFetched. If the user gave NULL for
+ // pceltFetched and we got S_FALSE back then celt can only be
+ // zero.
+ //
+
+ if (*phresult == S_FALSE)
+ {
+ if (pceltFetched)
+ {
+ celt = *pceltFetched;
+ }
+ else
+ {
+ celt = 0;
+ }
+ }
+
+ //
+ // loop through every returned element
+ //
+
+ for (ul=0; ul <= celt ; ul++)
+ {
+ if ((fRet == TRUE) &&
+ (Verify(((char *)prgelt) + (ul * m_ElementSize)) == FALSE))
+ {
+ printf("Data element %d returned by IEnumX::Next is bad.\r\n", ul);
+
+ fRet = FALSE;
+
+ //
+ // we keep looping anyway just to
+ // free up resources.
+ //
+ }
+
+ //
+ // If the user supplied a cleanup function there is additional
+ // memory that needs to be freed
+ //
+ // Math: cast prgelt to char* to it a one byte size and then scale
+ // it by the index * the element size
+ //
+
+ Cleanup(((char *)prgelt) + (ul * m_ElementSize));
+
+ }
+ }
+
+ delete prgelt;
+
+ return fRet;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Method: CEnumeratorTest::TestNext
+//
+// Synopsis: Test the next enumerator methods
+//
+// Effects:
+//
+// Arguments: None.
+//
+// Requires:
+//
+// Returns: HRESULT
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 24-May-94 kennethm author
+//
+// Notes: BUGBUG: This function should really be broken down into
+// smaller function.
+// Also, the return mechanism is unwieldy.
+//
+//--------------------------------------------------------------------------
+
+HRESULT CEnumeratorTest::TestNext(void)
+{
+ ULONG celtFetched;
+ LONG lInternalCount = 0;
+ HRESULT hresult;
+ ULONG i;
+ void* prgelt;
+
+ //
+ // First we want to count the element by doing a next on each one.
+ //
+
+ do {
+ if (!GetNext(1, &celtFetched, &hresult))
+ {
+ return(E_FAIL);
+ }
+ if (hresult == S_OK)
+ {
+ lInternalCount++;
+ }
+
+ } while ( hresult == S_OK );
+
+ //
+ // If the user passed in an amount make sure it matches what we got
+ //
+
+ if ((m_ElementCount != -1) && (lInternalCount != m_ElementCount))
+ {
+ printf("IEnumX: enumerated count and passed count do not match!\r\n");
+
+ return(E_FAIL);
+ }
+ else if (m_ElementCount == -1)
+ {
+ //
+ // If the user didn't pass in the element count let's set it here.
+ //
+
+ m_ElementCount = lInternalCount;
+ }
+
+ hresult = m_pEnumTest->Reset();
+
+ if (hresult != S_OK)
+ {
+ printf("IEnumnX: Reset failed (%lx)\r\n", hresult );
+
+ return(E_FAIL);
+ }
+
+
+ //
+ // Make sure we fail on ...Next(celt>1, ...,NULL)
+ //
+
+ if (GetNext(2, NULL, &hresult))
+ {
+ if (SUCCEEDED(hresult))
+ {
+ printf("IEnumX: celt>1 pceltFetched==NULL returned success\r\n");
+
+ return(E_FAIL);
+ }
+ }
+ else
+ {
+ return(E_FAIL);
+ }
+
+
+ //
+ // This next test will call next getting more each time
+ //
+
+ for (i = 1; i < (ULONG)m_ElementCount; i++)
+ {
+ hresult = m_pEnumTest->Reset();
+
+ if (hresult != S_OK)
+ {
+ printf("IEnumnX: Reset failed (%lx)\r\n", hresult );
+
+ return(E_FAIL);
+ }
+
+ if (!GetNext(i, &celtFetched, &hresult))
+ {
+ return(E_FAIL);
+ }
+
+ if ((hresult != S_OK) || (celtFetched != i))
+ {
+ printf("IEnumX: next/reset test failed!\r\n");
+
+ return(E_FAIL);
+ }
+ }
+
+
+ //
+ // Now get more elements than we were supposed to
+ // This should return S_FALSE with the max number in the number fetched
+ //
+
+ hresult = m_pEnumTest->Reset();
+
+ if (hresult != S_OK)
+ {
+ printf("IEnumX: Reset failed (%lx)\r\n", hresult );
+
+ return(E_FAIL);
+ }
+
+ if (!GetNext(m_ElementCount + 1, &celtFetched, &hresult))
+ {
+ return(E_FAIL);
+ }
+
+ if ((hresult != S_FALSE) || (lInternalCount != m_ElementCount))
+ {
+ printf("IEnumX: next/reset test failed!\r\n");
+
+ return(E_FAIL);
+ }
+
+ //
+ // Now verifyall. We do it here after the object has been worked on a bit
+ // since it is more likely to fail at this point
+ //
+
+ hresult = m_pEnumTest->Reset();
+
+ if (hresult != S_OK)
+ {
+ printf("IEnumX: Reset failed (%lx)\r\n", hresult );
+
+ return(E_FAIL);
+ }
+
+ //
+ // Allocate memory for the return elements
+ //
+
+ prgelt = new char[m_ElementSize * m_ElementCount];
+
+ if (prgelt == NULL)
+ {
+ printf("IEnumX: verifyall new failed\r\n");
+
+ return(E_OUTOFMEMORY);
+ }
+
+ hresult = m_pEnumTest->Next(m_ElementCount, prgelt, &celtFetched);
+
+ if ((hresult != S_OK) || (celtFetched != (ULONG)m_ElementCount))
+ {
+ printf("IEnumX: verifyall test: next failed (%lx)\r\n", hresult );
+ delete prgelt;
+
+ return(E_FAIL);
+ }
+
+ if (VerifyAll(prgelt, m_ElementCount) == FALSE)
+ {
+ printf("IEnumX: verifyall failed (%lx)\r\n", hresult );
+
+ delete prgelt;
+
+ return(E_FAIL);
+ }
+
+ delete prgelt;
+
+ return(S_OK);
+}
+
+//+-------------------------------------------------------------------------
+//
+// Method: CEnumeratorTest::TestSkip
+//
+// Synopsis: This function calls all the tests
+//
+// Effects:
+//
+// Arguments: None
+//
+// Requires:
+//
+// Returns: HRESULT
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 24-May-94 kennethm author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+HRESULT CEnumeratorTest::TestSkip(void)
+{
+ LONG i;
+ HRESULT hresult;
+ ULONG celtFetched;
+
+ //
+ // Make sure we call TestNext to set the element count
+ //
+
+ if (m_ElementCount == -1)
+ {
+ TestNext();
+ }
+
+ //
+ // Call Skip, reset and try to get one element
+ //
+
+ for (i = 0; i < (LONG)m_ElementCount; i++)
+ {
+ hresult = m_pEnumTest->Reset();
+
+ if (hresult != S_OK)
+ {
+ printf("IEnumnX: Reset failed (%lx)\r\n", hresult );
+
+ return(E_FAIL);
+ }
+
+ hresult = m_pEnumTest->Skip(i);
+
+ if (hresult != S_OK)
+ {
+ printf("IEnumnX: Skip failed (%lx)\r\n", hresult );
+
+ return(E_FAIL);
+ }
+
+ //
+ // Now one element to provide some check that the skip worked
+ //
+
+ if (!GetNext(1, &celtFetched, &hresult))
+ {
+ return(E_FAIL);
+ }
+
+ if (hresult != S_OK)
+ {
+ return(E_FAIL);
+ }
+ }
+
+ //
+ // Reset the enumerator before we leave
+ //
+
+ hresult = m_pEnumTest->Reset();
+
+ if (hresult != S_OK)
+ {
+ printf("IEnumnX: Reset failed (%lx)\r\n", hresult );
+ return(E_FAIL);
+ }
+
+ return(S_OK);
+
+}
+
+//+-------------------------------------------------------------------------
+//
+// Method: CEnumeratorTest::TestRelease
+//
+// Synopsis: This function calls all the tests
+//
+// Effects:
+//
+// Arguments: None
+//
+// Requires:
+//
+// Returns: HRESULT
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 24-May-94 kennethm author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+HRESULT CEnumeratorTest::TestRelease(void)
+{
+ return(S_OK);
+}
+
+//+-------------------------------------------------------------------------
+//
+// Method: CEnumeratorTest::TestClone
+//
+// Synopsis: This function calls all the tests
+//
+// Effects:
+//
+// Arguments: None
+//
+// Requires:
+//
+// Returns: HRESULT
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 24-May-94 kennethm author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+HRESULT CEnumeratorTest::TestClone(void)
+{
+ return(S_OK);
+}
+
+//+-------------------------------------------------------------------------
+//
+// Method: CEnumeratorTest::TestAll
+//
+// Synopsis: This function calls all the tests
+//
+// Effects:
+//
+// Arguments: None
+//
+// Requires:
+//
+// Returns: HRESULT
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 24-May-94 kennethm author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+HRESULT CEnumeratorTest::TestAll(void)
+{
+ HRESULT hresult;
+
+ hresult = TestNext();
+
+ if (hresult == S_OK)
+ {
+ hresult = TestSkip();
+ }
+
+ if (hresult == S_OK)
+ {
+ hresult = TestClone();
+ }
+
+ if (hresult == S_OK)
+ {
+ hresult = TestRelease();
+ }
+
+ return(hresult);
+}
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Method: CEnumeratorTest::VerifyAll
+//
+// Synopsis: Verify entire array of returned results.
+//
+// Arguments: None
+//
+// Returns: BOOL
+//
+// Algorithm: Just default to saying everything is ok
+//
+// History: dd-mmm-yy Author Comment
+// 24-May-94 kennethm author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+BOOL CEnumeratorTest::VerifyAll(void *pv, LONG cl)
+{
+ return TRUE;
+}
+
+
+//+-------------------------------------------------------------------------
+//
+// Method: CEnumeratorTest::Verify
+//
+// Synopsis: Verify one element
+//
+// Arguments: None
+//
+// Returns: BOOL
+//
+// Algorithm: Just default to saying everything is ok
+//
+// History: dd-mmm-yy Author Comment
+// 24-May-94 kennethm author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+BOOL CEnumeratorTest::Verify(void *pv)
+{
+ return TRUE;
+}
+
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Method: CEnumeratorTest::Cleanup
+//
+// Synopsis: Default implementation of cleanup
+//
+// Arguments: [pv] - pointer to entry enumerated
+//
+// Algorithm: If there is nothing special to free this implementation
+// can be used.
+//
+// History: dd-mmm-yy Author Comment
+// 24-May-94 kennethm author
+//
+//--------------------------------------------------------------------------
+
+void CEnumeratorTest::Cleanup(void *pv)
+{
+ return;
+}
+
diff --git a/private/oleutest/cachetst/genenum.h b/private/oleutest/cachetst/genenum.h
new file mode 100644
index 000000000..fac82e5ca
--- /dev/null
+++ b/private/oleutest/cachetst/genenum.h
@@ -0,0 +1,134 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: genenum.hxx
+//
+// Contents: Declaration of a generic enum object and test object.
+//
+// Classes: CGenEnumObject
+//
+// Functions:
+//
+// History: dd-mmm-yy Author Comment
+// 23-May-94 kennethm author! author!
+//
+//--------------------------------------------------------------------------
+
+#ifndef _GENENUM_H
+#define _GENENUM_H
+
+#include <windows.h>
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include <ole2.h>
+
+//
+// This macro allows the code to use a different outputstring function.
+//
+
+EXTERN_C HRESULT TestEnumerator(
+ void *penum,
+ size_t ElementSize,
+ LONG ElementCount,
+ BOOL (*verify)(void*),
+ BOOL (*verifyall)(void*,LONG),
+ void (*cleanup)(void*));
+
+//
+// Classes are exposed for C++ clients only
+//
+
+#ifdef __cplusplus
+
+//+-------------------------------------------------------------------------
+//
+// Class: IGenEnum
+//
+// Purpose: generic enumerator
+//
+// Interface: Abstract class
+//
+// History: dd-mmm-yy Author Comment
+// 23-May-94 kennethm author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+class IGenEnum
+{
+public:
+ STDMETHOD(QueryInterface)(REFIID riid, void **ppvObj) = 0;
+ STDMETHOD_(ULONG,AddRef)(void) = 0;
+ STDMETHOD_(ULONG,Release)(void) = 0;
+
+ STDMETHOD(Next) (ULONG celt, void *rgelt,
+ ULONG *pceltFetched) = 0;
+ STDMETHOD(Skip) (ULONG celt) = 0;
+ STDMETHOD(Reset) (void) = 0;
+ STDMETHOD(Clone) (void **ppenum) = 0;
+};
+
+//+-------------------------------------------------------------------------
+//
+// Class: CEnumeratorTest
+//
+// Purpose: enumerator test class
+//
+// Interface:
+//
+// History: dd-mmm-yy Author Comment
+// 23-May-94 kennethm author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+class CEnumeratorTest
+{
+public:
+
+ //
+ // Constructor
+ //
+
+ CEnumeratorTest(IGenEnum * enumtest, size_t elementsize, LONG elementcount);
+
+ //
+ // Test for each enumerator object
+ //
+
+ HRESULT TestAll(void);
+ HRESULT TestNext(void);
+ HRESULT TestSkip(void);
+ HRESULT TestClone(void);
+ HRESULT TestRelease(void);
+
+ //
+ // Verification functions
+ //
+
+ virtual BOOL Verify(void *);
+ virtual BOOL VerifyAll(void*, LONG);
+ virtual void Cleanup(void *);
+
+protected:
+ CEnumeratorTest();
+
+ BOOL GetNext(ULONG celt, ULONG* pceltFetched, HRESULT* phresult);
+
+ IGenEnum * m_pEnumTest;
+ size_t m_ElementSize;
+ LONG m_ElementCount;
+};
+
+#endif
+
+#endif // !_GENENUM_H
+
diff --git a/private/oleutest/cachetst/genforc.cpp b/private/oleutest/cachetst/genforc.cpp
new file mode 100644
index 000000000..ea8a86bcd
--- /dev/null
+++ b/private/oleutest/cachetst/genforc.cpp
@@ -0,0 +1,276 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: genforc.cpp
+//
+// Contents: implementation of CEnumeratorTestForC.
+// This class is a subclass of CEnumeratorTest that calls for less
+// Implementation work than CEnumeratorTest but is less flexible.
+//
+// Classes:
+//
+// Functions:
+//
+// History: dd-mmm-yy Author Comment
+// 24-May-94 kennethm author
+//
+//--------------------------------------------------------------------------
+
+#include "headers.hxx"
+#pragma hdrstop
+
+//+-------------------------------------------------------------------------
+//
+// Member: CEnumeratorTestForC::CEnumeratorTestForC
+//
+// Synopsis: default constructor
+//
+// Arguments:
+//
+// Returns:
+//
+// History: dd-mmm-yy Author Comment
+// 24-May-94 kennethm author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+CEnumeratorTestForC::CEnumeratorTestForC()
+{
+ m_fnVerify = NULL;
+ m_fnVerifyAll = NULL;
+ m_fnCleanup = NULL;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Method: CEnumeratorTestForC::Verify
+//
+// Synopsis: Verify one element.
+//
+// Arguments: None
+//
+// Returns: BOOL
+//
+// Algorithm: call the user provided function or defer to the super-class
+//
+// History: dd-mmm-yy Author Comment
+// 24-May-94 kennethm author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+BOOL CEnumeratorTestForC::Verify(void *pv)
+{
+ if (m_fnVerify)
+ {
+ return(m_fnVerify(pv ));
+ }
+ else
+ {
+ return(CEnumeratorTest::Verify(pv));
+ }
+}
+
+//+-------------------------------------------------------------------------
+//
+// Method: CEnumeratorTestForC::VerifyAll
+//
+// Synopsis: Verify entire array of returned results.
+//
+// Arguments: None
+//
+// Returns: BOOL
+//
+// Algorithm: call the user provided function or defer to the super-class
+//
+// History: dd-mmm-yy Author Comment
+// 24-May-94 kennethm author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+BOOL CEnumeratorTestForC::VerifyAll(void *pv, LONG cl)
+{
+ if (m_fnVerifyAll)
+ {
+ return(m_fnVerifyAll(pv, cl ));
+ }
+ else
+ {
+ return(CEnumeratorTest::VerifyAll(pv, cl));
+ }
+}
+
+//+-------------------------------------------------------------------------
+//
+// Method: CEnumeratorTestForC::CleanUp
+//
+// Synopsis: Default implementation of cleanup
+//
+// Arguments: [pv] - pointer to entry enumerated
+//
+// Algorithm: call the user provided function or do nothing.
+//
+// History: dd-mmm-yy Author Comment
+// 24-May-94 kennethm author
+//
+//--------------------------------------------------------------------------
+
+void CEnumeratorTestForC::Cleanup(void *pv)
+{
+ if (m_fnCleanup)
+ {
+ m_fnCleanup(pv);
+ }
+}
+
+
+//+-------------------------------------------------------------------------
+//
+// Member: CEnumeratorTestForC::Create
+//
+// Synopsis: Static create function.
+//
+// Effects:
+//
+// Arguments: [ppEnumtest] -- TestEnumerator object pointer
+// [penum] -- Enumerator Interface cast to void*
+// [ElementSize] -- Size of elements return from next
+// [ElementCount] -- Numer of elements that should be in the enumeration,
+// -1 if unknown.
+// [verify] -- verifies one element.
+// [verifyall] -- verifies an array correctly contains all elements
+// [cleanup] -- Frees any additional memory from next call.
+// [pPassedDebugLog] -- The debug log object, NULL if none.
+//
+// Requires:
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Derivation:
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 24-May-94 kennethm author
+//
+// Notes: all of the functions passed in are optional and may be NULL.
+//
+//--------------------------------------------------------------------------
+
+HRESULT CEnumeratorTestForC::Create(
+ CEnumeratorTestForC **ppEnumTest,
+ void *penum,
+ size_t ElementSize,
+ LONG ElementCount,
+ BOOL (*verify)(void*),
+ BOOL (*verifyall)(void*,LONG),
+ void (*cleanup)(void*))
+{
+ HRESULT hresult = S_OK;
+ CEnumeratorTestForC *pEnumTest;
+
+ if ((penum == NULL) || (ppEnumTest == NULL))
+ {
+ return(E_INVALIDARG);
+ }
+
+ *ppEnumTest = NULL;
+
+ //
+ // Create the new enumerator object
+ //
+
+ pEnumTest = new CEnumeratorTestForC();
+
+ if (pEnumTest == NULL)
+ {
+ return(E_OUTOFMEMORY);
+ }
+
+ //
+ // Initialize the enumerator and reset it.
+ //
+
+ pEnumTest->m_pEnumTest = (IGenEnum*)penum;
+
+ pEnumTest->m_ElementSize = ElementSize;
+ pEnumTest->m_ElementCount = ElementCount;
+ pEnumTest->m_fnVerify = verify;
+ pEnumTest->m_fnVerifyAll = verifyall;
+ pEnumTest->m_fnCleanup = cleanup;
+
+ hresult = pEnumTest->m_pEnumTest->Reset();
+
+ if (hresult != S_OK)
+ {
+ printf("IEnumnX: Reset failed (%lx)\r\n", hresult );
+
+ delete pEnumTest;
+
+ return(E_FAIL);
+ }
+
+ *ppEnumTest = pEnumTest;
+
+ return(hresult);
+
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: TestEnumerator
+//
+// Synopsis: This is the one stop testing for C programs.
+//
+// Arguments: [pv] - pointer to entry enumerated
+//
+// Algorithm: If there is nothing special to free this implementation
+// can be used.
+//
+// History: dd-mmm-yy Author Comment
+// 24-May-94 kennethm author
+//
+//--------------------------------------------------------------------------
+
+
+HRESULT TestEnumerator(
+ void *penum,
+ size_t ElementSize,
+ LONG ElementCount,
+ BOOL (*verify)(void*),
+ BOOL (*verifyall)(void*,LONG),
+ void (*cleanup)(void*))
+{
+ CEnumeratorTestForC *pEnumTest;
+ HRESULT hresult;
+
+ hresult = CEnumeratorTestForC::Create(
+ &pEnumTest,
+ penum,
+ ElementSize,
+ ElementCount,
+ verify,
+ verifyall,
+ cleanup);
+
+ if (SUCCEEDED(hresult))
+ {
+ hresult = pEnumTest->TestAll();
+ delete pEnumTest;
+ }
+
+ return(hresult);
+}
+
+
diff --git a/private/oleutest/cachetst/genforc.hxx b/private/oleutest/cachetst/genforc.hxx
new file mode 100644
index 000000000..ee8afb491
--- /dev/null
+++ b/private/oleutest/cachetst/genforc.hxx
@@ -0,0 +1,74 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: genforc.hxx
+//
+// Contents: C exposure for the generice enumerator object
+//
+// Classes: CEnumeratorTestForC
+//
+// Functions:
+//
+// History: dd-mmm-yy Author Comment
+// 23-May-94 kennethm author
+//
+//--------------------------------------------------------------------------
+
+#ifndef _GENFORC_HXX
+#define _GENFORC_HXX
+
+#include <windows.h>
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include <ole2.h>
+#include "genenum.h"
+
+//+-------------------------------------------------------------------------
+//
+// Class: CEnumeratorTestForC
+//
+// Purpose: enumerator test class
+//
+// Interface:
+//
+// History: dd-mmm-yy Author Comment
+// 23-May-94 kennethm author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+class CEnumeratorTestForC : public CEnumeratorTest
+{
+public:
+ // static create function
+
+ static HRESULT Create(
+ CEnumeratorTestForC **ppEnumTest,
+ void *penum,
+ size_t ElementSize,
+ LONG ElementCount,
+ BOOL (*verify)(void*),
+ BOOL (*verifyall)(void*,LONG),
+ void (*cleanup)(void*));
+
+private:
+ CEnumeratorTestForC();
+
+ BOOL (*m_fnVerify)(void*);
+ BOOL (*m_fnVerifyAll)(void*,LONG);
+ void (*m_fnCleanup)(void*);
+
+ virtual BOOL Verify(void *);
+ virtual BOOL VerifyAll(void*, LONG);
+ virtual void Cleanup(void *);
+};
+
+#endif // !_GENFORC_HXX
+
diff --git a/private/oleutest/cachetst/headers.hxx b/private/oleutest/cachetst/headers.hxx
new file mode 100644
index 000000000..99aaa0ffb
--- /dev/null
+++ b/private/oleutest/cachetst/headers.hxx
@@ -0,0 +1,27 @@
+// headers.hxx
+
+// Level 4 warnings which need to be disabled to pass the Windows header
+// files (allowing me to use Level 4 on my own code)
+
+#pragma warning(disable: 4514) // removal of unref'd inline function
+#pragma warning(disable: 4201) // nameless union/struct
+#pragma warning(disable: 4100) // unreferenced formal parameters
+#pragma warning(disable: 4699) // use of precompiled header
+#pragma warning(disable: 4204) // non-constant struct intializers
+
+#define INC_OLE2
+#include <windows.h>
+#include <ole2.h>
+#include <assert.h>
+#include <memory.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "davedbg.h"
+#include "genenum.h"
+#include "genforc.hxx"
+#include "ctest.hxx"
+#include "bmpfile.hxx"
+#include "ctestapp.hxx"
+
diff --git a/private/oleutest/cachetst/main.cpp b/private/oleutest/cachetst/main.cpp
new file mode 100644
index 000000000..1fae23fef
--- /dev/null
+++ b/private/oleutest/cachetst/main.cpp
@@ -0,0 +1,1521 @@
+// This is a multi-threaded app with two primary threads. One
+// sits in the message loop, waiting specifically for WM_PAINT
+// messages which are generated by the other thread, on which
+// the actual unit test runs.
+//
+// When the window thread receives an update message, it takes
+// a snapshot of the unit test state (protected by a mutex),
+// and redraws the screen accordingly.
+//
+// When the unit test thread wants a resource to be drawn in
+// the main window, it places the handle to that resource (for
+// example, an HMETAFILEPICT) in the ctest object associated
+// with the window thread, then fires a screen update. In
+// doing so, ownership of the resource is transfered from the
+// unit test thread to the window thread. By using this
+// mechanism, the window thread can draw the resource at its
+// leisure, while the unit test proceeds. The onus is on
+// the window thread to clean up any resources which have
+// been deposited in its care when it exists.
+//
+// If the window thread receives a WM_CLOSE message, it must
+// first check to see that the unit test thread has completed.
+// If not, it spins in a RETRY/CANCEL loop until the unit test
+// thread has completed, or until the user selects CANCEL, at
+// which point execution proceeds, ignoring the WM_CLOSE.
+//
+// "OVER-ENGINEERED, AND BUILT TO STAY THAT WAY" (tm)
+//
+
+
+#include "headers.hxx"
+#pragma hdrstop
+
+CCacheTestApp ctest; // Application instance
+TestInstance inst; // Test instance
+
+//
+// Prototype for the entry-point of the unit test thread
+//
+
+unsigned long __stdcall testmain(void *);
+
+//+---------------------------------------------------------------------------
+//
+// Function: WinMain
+//
+// Synopsis: windows entry point
+//
+// Arguments: [hInst] --
+// [hPrevInst] --
+// [lpszCmdLine] --
+// [nCmdShow] --
+//
+// Returns: int
+//
+// History: 05-Sep-94 davepl Created
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+
+int WINAPI WinMain (HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpszCmdLine, int nCmdShow)
+{
+ MSG message;
+
+ //
+ // Initialize the application
+ //
+
+ if (SUCCEEDED(ctest.Initialize(hInst, hPrevInst, lpszCmdLine)))
+ {
+ //
+ // Show and update the window
+ //
+
+ ShowWindow(ctest.Window(), nCmdShow);
+ UpdateWindow(ctest.Window());
+
+ //
+ // The main message loop
+ //
+
+ while (GetMessage(&message, NULL, NULL, NULL))
+ {
+ TranslateMessage(&message);
+ DispatchMessage(&message);
+ }
+ }
+ else
+ {
+ return(0);
+ }
+
+ return(message.wParam);
+}
+
+//+---------------------------------------------------------------------------
+//
+// Member: CCacheTestApp::CCacheTestApp
+//
+// Synopsis: Constructor
+//
+// Arguments: (none)
+//
+// Returns: nothing
+//
+// History: 05-Sep-94 Davepl Created
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+
+CCacheTestApp::CCacheTestApp ()
+{
+
+}
+
+//+---------------------------------------------------------------------------
+//
+// Member: CCacheTestApp::Initialize
+//
+// Synopsis: initializes the application
+//
+// Arguments: [hInst] -- current instance
+// [hPrevInst] -- previous instance
+// [lpszCmdLine] -- command line parameters
+//
+// Returns: HRESULT
+//
+// History: 05-Sep-94 Davepl Created
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+
+HRESULT CCacheTestApp::Initialize (HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpszCmdLine)
+{
+ HRESULT hr = S_OK;
+
+ //
+ // Register the window class
+ //
+
+ if (hPrevInst == NULL)
+ {
+ WNDCLASS wndclass;
+
+ wndclass.style = 0;
+ wndclass.lpfnWndProc = CacheTestAppWndProc;
+
+ wndclass.cbClsExtra = 0;
+ wndclass.cbWndExtra = 0;
+
+ wndclass.hInstance = hInst;
+ wndclass.hIcon = LoadIcon(hInst, IDI_EXCLAMATION);
+ wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wndclass.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE + 1);
+ wndclass.lpszMenuName = NULL;
+ wndclass.lpszClassName = CTESTAPPCLASS;
+
+ if (RegisterClass(&wndclass) == 0)
+ {
+ hr = HRESULT_FROM_WIN32(GetLastError());
+ }
+ }
+
+ //
+ // Create the mutex
+ //
+
+ m_hMutex = CreateMutex(NULL, FALSE, NULL);
+ if (NULL == m_hMutex)
+ {
+ hr = HRESULT_FROM_WIN32(GetLastError());
+ }
+
+ //
+ // Create the window
+ //
+
+ if (SUCCEEDED(hr))
+ {
+ if ((m_hWnd = CreateWindowEx(0L,
+ CTESTAPPCLASS,
+ CTESTAPPTITLE,
+ WS_OVERLAPPEDWINDOW,
+ CW_USEDEFAULT,
+ 0,
+ CW_USEDEFAULT,
+ 0,
+ NULL,
+ NULL,
+ hInst,
+ NULL)) == NULL)
+ {
+ hr = HRESULT_FROM_WIN32(GetLastError());
+ }
+ }
+
+ return(hr);
+}
+
+//+---------------------------------------------------------------------------
+//
+// Member: CCacheTestApp::~CCacheTestApp
+//
+// Synopsis: Destructor
+//
+// Arguments: (none)
+//
+// Returns: nothing
+//
+// History: 05-Sep-94 Davepl Created
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+
+CCacheTestApp::~CCacheTestApp ()
+{
+
+}
+
+//+---------------------------------------------------------------------------
+//
+// Function: CacheTestAppWndProc
+//
+// Synopsis: window procedure
+//
+// Arguments: [hWnd] -- window
+// [message] -- message id
+// [wParam] -- parameter
+// [lParam] -- parameter
+//
+// Returns: LRESULT
+//
+// History: 05-Sep-94 Davepl Created
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+LRESULT FAR PASCAL CacheTestAppWndProc (HWND hWnd,
+ UINT message,
+ WPARAM wParam,
+ LPARAM lParam)
+{
+ //
+ // Process the messages
+ //
+
+ switch (message)
+ {
+ case WM_CREATE:
+
+ //
+ // The unit test window is opening. Create another thread
+ // on which the unit test itself runs, while this thread
+ // continues to spin, waiting for redraws, close, and so
+ // on...
+ //
+
+ ctest.m_hTest = CreateThread(NULL,
+ 0,
+ testmain,
+ NULL,
+ 0,
+ &ctest.m_dwThreadID);
+
+ if (NULL == ctest.m_hTest)
+ {
+ mprintf("Unable to begin unit test\n");
+ PostQuitMessage(0);
+ }
+
+ break;
+
+
+ case WM_PAINT:
+ {
+ PAINTSTRUCT ps;
+ HDC hDC;
+
+ //
+ // Get the DC for painting
+ //
+
+ hDC = BeginPaint(hWnd, &ps);
+ if (hDC)
+ {
+ //
+ // Draw the metafile
+ //
+
+ inst.Draw(hDC);
+
+ EndPaint(hWnd, &ps);
+ }
+ }
+ break;
+
+ case WM_SIZE:
+
+ //
+ // Invalidate the rectangle
+ //
+
+ InvalidateRect(hWnd, NULL, TRUE);
+ return DefWindowProc(hWnd, message, wParam, lParam);
+ break;
+
+ case WM_CLOSE:
+
+ {
+ //
+ // The user has tried to exit the main program. Before we
+ // can shut down, we must wait until the child thread has
+ // completed. We allow the user to keep retrying on the
+ // thread, or to "cancel" and wait until later. We do not
+ // provide the option of terminating the child thread while
+ // it is still busy.
+ //
+
+ DWORD dwStatus = 0;
+
+ if (FALSE == GetExitCodeThread(ctest.m_hTest, &dwStatus))
+ {
+ mprintf("Could not get thread information!");
+ break;
+ }
+ else
+ {
+ INT response = IDRETRY;
+
+ while (STILL_ACTIVE == dwStatus)
+ {
+ response = MessageBox(ctest.Window(),
+ "The child thread has not yet completed.",
+ "Cannot Shutdown",
+ MB_RETRYCANCEL);
+
+ if (IDCANCEL == response)
+ {
+ break;
+ }
+
+ }
+ }
+
+ //
+ // Destroy the window if the child has gone away
+ //
+
+ if (STILL_ACTIVE != dwStatus)
+ {
+ DestroyWindow(hWnd);
+ }
+
+ break;
+ }
+
+ case WM_DESTROY:
+
+ PostQuitMessage(0);
+ break;
+
+
+ default:
+ return DefWindowProc(hWnd, message, wParam, lParam);
+ }
+
+ return NULL;
+}
+
+//+----------------------------------------------------------------------------
+//
+// Member:
+//
+// Synopsis:
+//
+// Arguments:
+//
+// Returns: HRESULT
+//
+// Notes:
+//
+// History: 23-Aug-94 Davepl Created
+//
+//-----------------------------------------------------------------------------
+
+unsigned long __stdcall testmain(void *)
+{
+ HRESULT hr;
+
+ hr = inst.CreateAndInit( OLESTR("mystg") );
+
+ if (S_OK != hr)
+ {
+ mprintf("Cache Unit Test Failed [CreateAndInit] hr = %x\n", hr);
+ goto exit;
+ }
+
+ hr = inst.EnumeratorTest();
+ if (S_OK != hr)
+ {
+ mprintf("Cache Unit Test Failed [EnumeratorTest] hr = %x\n", hr);
+ goto exit;
+ }
+
+ hr = inst.MultiCache(50);
+ if (S_OK != hr)
+ {
+ mprintf("Cache Unit Test Failed [MultiCache] hr = %x\n", hr);
+ goto exit;
+ }
+
+ hr = inst.CacheDataTest("TIGER.BMP", "TIGERNPH.WMF");
+ if (S_OK != hr)
+ {
+ mprintf("Cache Unit Test Failed [CacheDataTest] hr = %x\n", hr);
+ goto exit;
+ }
+
+exit:
+
+ PostMessage(ctest.Window(), WM_CLOSE, (WPARAM) hr, 0);
+ return (ULONG) hr;
+
+}
+
+
+//+----------------------------------------------------------------------------
+//
+// Member: TestInstance::TestInstance
+//
+// Synopsis: Constructor
+//
+// Arguments:
+//
+// Returns:
+//
+// Notes:
+//
+// History: 23-Aug-94 Davepl Created
+//
+//-----------------------------------------------------------------------------
+
+TestInstance::TestInstance()
+{
+
+ m_pStorage = NULL;
+ m_pPersistStorage = NULL;
+ m_pOleCache = NULL;
+ m_pOleCache2 = NULL;
+ m_pDataObject = NULL;
+ m_pViewObject = NULL;
+ m_State = TEST_STARTING;
+}
+
+TestInstance::~TestInstance()
+{
+ //
+ // Release our interface pointers
+ //
+
+ if (m_pDataObject)
+ {
+ m_pDataObject->Release();
+ }
+
+ if (m_pViewObject)
+ {
+ m_pViewObject->Release();
+ }
+
+ if (m_pPersistStorage)
+ {
+ m_pPersistStorage->Release();
+ }
+
+ if (m_pOleCache2)
+ {
+ m_pOleCache2->Release();
+ }
+
+ if (m_pOleCache)
+ {
+ m_pOleCache->Release();
+ }
+
+ if (m_pStorage)
+ {
+ m_pStorage->Release();
+ }
+}
+
+//+----------------------------------------------------------------------------
+//
+// Member: TestInstance::CreateAndInit
+//
+// Synopsis: Creates a cache and sets up internal interface ptrs
+//
+// Arguments: (none)
+//
+// Returns: HRESULT
+//
+// Notes:
+//
+// History: 23-Aug-94 Davepl Created
+//
+//-----------------------------------------------------------------------------
+
+HRESULT TestInstance::CreateAndInit(LPOLESTR lpwszStgName)
+{
+ HRESULT hr;
+
+ TraceLog Log(this, "TestInstance::CreateAndInit", GS_CACHE, VB_MINIMAL);
+ Log.OnEntry (" ( %p ) \n", lpwszStgName);
+ Log.OnExit (" ( %X ) \n", &hr);
+
+ //
+ // Create the storage on which we will instantiate our cache
+ //
+
+ // BUGBUG use correct strcpy fn
+
+ wcscpy(m_wszStorage, lpwszStgName);
+
+ hr = StgCreateDocfile(lpwszStgName,
+ STGM_DIRECT |
+ STGM_READWRITE |
+ STGM_SHARE_EXCLUSIVE |
+ STGM_CREATE,
+ 0,
+ &m_pStorage);
+
+ //
+ // Create a Data Cache on our IStorage
+ //
+
+ if (S_OK == hr)
+ {
+ hr = CreateDataCache(NULL,
+ CLSID_NULL,
+ IID_IPersistStorage,
+ (void **)&m_pPersistStorage);
+ }
+
+ if (S_OK == hr)
+ {
+ hr = m_pPersistStorage->InitNew(m_pStorage);
+ }
+
+ //
+ // Get an IOleCache interface pointer to the cache
+ //
+
+ if (S_OK == hr)
+ {
+ hr = m_pPersistStorage->QueryInterface(IID_IOleCache,
+ (void **) &m_pOleCache);
+ }
+
+ //
+ // Get an IOleCache2 interface pointer to the cache
+ //
+
+ if (S_OK == hr)
+ {
+ hr = m_pPersistStorage->QueryInterface(IID_IOleCache2,
+ (void **) &m_pOleCache2);
+ }
+
+ //
+ // Get an IViewObject interface pointer to the cache
+ //
+
+ if (S_OK == hr)
+ {
+ hr = m_pPersistStorage->QueryInterface(IID_IViewObject,
+ (void **) &m_pViewObject);
+ }
+
+ //
+ // Get an IDataObject interface pointer to the cache
+ //
+
+ if (S_OK == hr)
+ {
+ hr = m_pPersistStorage->QueryInterface(IID_IDataObject,
+ (void **) &m_pDataObject);
+ }
+
+ return hr;
+}
+
+//+----------------------------------------------------------------------------
+//
+// Member: TestInstance::SaveAndReload
+//
+// Synopsis: Saves the cache to its storage and reloads it
+// right back.
+//
+// Arguments: (none)
+//
+// Returns: HRESULT
+//
+// Notes: Once saved, the behavior of DiscardCache will
+// change, since each node present at the time of
+// save will have a stream from which it can demand
+// load its data.
+//
+// Since each interface pointer is released and
+// reaquired, the pointer values will (likely) change
+// during this call; hence, so _not_ cache the pointers
+// locally around this call.
+//
+// History: 23-Aug-94 Davepl Created
+//
+//-----------------------------------------------------------------------------
+
+HRESULT TestInstance::SaveAndReload()
+{
+ HRESULT hr;
+
+ TraceLog Log(NULL, "TestInstance::SaveAndReload", GS_CACHE, VB_MINIMAL);
+ Log.OnEntry ();
+ Log.OnExit (" ( %X )\n", &hr);
+
+ SetCurrentState(SAVE_AND_RELOAD);
+
+ hr = m_pPersistStorage->Save(m_pStorage, TRUE);
+
+ if (S_OK == hr)
+ {
+ hr = m_pPersistStorage->SaveCompleted(NULL);
+ }
+
+ // Release our hold on the storage and the cache
+
+ if (S_OK == hr)
+ {
+ m_pViewObject->Release();
+ m_pViewObject = NULL;
+ m_pDataObject->Release();
+ m_pDataObject = NULL;
+
+ m_pStorage->Release();
+ m_pStorage = NULL;
+
+ m_pPersistStorage->Release();
+ m_pPersistStorage = NULL;
+
+ m_pOleCache2->Release();
+ m_pOleCache2 = NULL;
+
+ m_pOleCache->Release();
+ m_pOleCache = NULL;
+
+
+ //
+ // Reload the cache and QI to get our interfaces back
+ //
+
+ hr = StgOpenStorage(m_wszStorage,
+ NULL,
+ STGM_DIRECT |
+ STGM_READWRITE |
+ STGM_SHARE_EXCLUSIVE,
+ NULL,
+ 0,
+ &m_pStorage);
+
+ //
+ // Create a Data Cache on our IStorage
+ //
+
+ if (S_OK == hr)
+ {
+ hr = CreateDataCache(NULL,
+ CLSID_NULL,
+ IID_IPersistStorage,
+ (void **)&m_pPersistStorage);
+ }
+
+ if (S_OK == hr)
+ {
+ hr = m_pPersistStorage->Load(m_pStorage);
+ }
+
+ //
+ // Get an IOleCache interface pointer to the cache
+ //
+
+ if (S_OK == hr)
+ {
+ hr = m_pPersistStorage->QueryInterface(IID_IOleCache,
+ (void **) &m_pOleCache);
+ }
+
+ //
+ // Get an IOleCache2 interface pointer to the cache
+ //
+
+ if (S_OK == hr)
+ {
+ hr = m_pPersistStorage->QueryInterface(IID_IOleCache2,
+ (void **) &m_pOleCache2);
+ }
+
+ //
+ // Get an IViewObject interface pointer to the cache
+ //
+
+ if (S_OK == hr)
+ {
+ hr = m_pPersistStorage->QueryInterface(IID_IViewObject,
+ (void **) &m_pViewObject);
+ }
+
+ //
+ // Get an IDataObject interface pointer to the cache
+ //
+
+ if (S_OK == hr)
+ {
+ hr = m_pPersistStorage->QueryInterface(IID_IDataObject,
+ (void **) &m_pDataObject);
+ }
+ }
+
+ return hr;
+}
+
+
+//+----------------------------------------------------------------------------
+//
+// Member: TestInstance::CacheDataTest
+//
+// Synopsis: Checks the cache for data integrity
+//
+// Arguments: lpszBMPFileName - Name of .BMP file to use for test
+// lpszWMFFileName - Name of .WMF file to use for test
+//
+// Returns: HRESULT
+//
+// Notes:
+//
+// History: 04-Sep-94 Davepl Created
+//
+//-----------------------------------------------------------------------------
+
+HRESULT TestInstance::CacheDataTest(char * lpszBMPFileName, char * lpszWMFFileName)
+{
+ HRESULT hr = S_OK;
+
+ TraceLog Log(NULL, "TestInstance::CacheDataTest", GS_CACHE, VB_MINIMAL);
+ Log.OnEntry (" ( BMP=%s, WMF=%s )\n", lpszBMPFileName, lpszWMFFileName);
+ Log.OnExit (" ( %X )\n", &hr);
+
+ SetCurrentState(DATA_TEST);
+
+ CBitmapFile bmpFile;
+ HGLOBAL hDIB = NULL;
+
+ //
+ // Allocate an hglobal to hold our metafilepict structure
+ //
+
+ HGLOBAL hMFPICT = GlobalAlloc(GMEM_FIXED, sizeof(METAFILEPICT));
+ if (NULL == hMFPICT)
+ {
+ hr = HRESULT_FROM_WIN32(GetLastError());
+ }
+ METAFILEPICT * pMFPICT = (METAFILEPICT *) hMFPICT;
+
+ //
+ // Load the bitmap from disk
+ //
+
+ if (S_OK == hr)
+ {
+ hr = bmpFile.LoadBitmapFile(lpszBMPFileName);
+ }
+
+ //
+ // Create a DIB on an HGLOBAL from the bitmap
+ //
+
+ if (S_OK == hr)
+ {
+ hr = bmpFile.CreateDIBInHGlobal(&hDIB);
+ }
+
+ //
+ // Add DIB and MF nodes to the cache
+ //
+
+ DWORD dwDIBCon;
+ DWORD dwMFCon;
+
+ if (S_OK == hr)
+ {
+ hr = AddDIBCacheNode(&dwDIBCon);
+ }
+
+ if (S_OK == hr)
+ {
+ hr = AddMFCacheNode(&dwMFCon);
+ }
+
+ //
+ // Load the metafile from disk, then set up the
+ // METAFILEPICT structure
+ //
+
+ if (S_OK == hr)
+ {
+ pMFPICT->hMF = GetMetaFileA(lpszWMFFileName);
+ if (NULL == pMFPICT->hMF)
+ {
+ hr = HRESULT_FROM_WIN32(GetLastError());
+ }
+ else
+ {
+ //
+ // We deem the metafile to have the same extents
+ // as the the DIB. This is completely arbitrary,
+ // but might aid in tracking down extents problems.
+ // After all, we have to pick _some_ value, so it
+ // might as well be a useful one...
+ //
+
+ pMFPICT->xExt = ConvWidthInPelsToLHM(NULL, bmpFile.GetDIBHeight());
+ pMFPICT->yExt = ConvHeightInPelsToLHM(NULL, bmpFile.GetDIBWidth());
+ pMFPICT->mm = MM_ANISOTROPIC;
+ }
+ }
+
+ //
+ // Place the nodes in the cache. We keep ownership of the handles,
+ // which will force the cache to duplicate it. We can then compare
+ // our original with whatever we later get back from the cache.
+ //
+
+ FORMATETC fetcDIB =
+ {
+ CF_DIB,
+ NULL,
+ DVASPECT_CONTENT,
+ DEF_LINDEX,
+ TYMED_HGLOBAL
+ };
+
+ STGMEDIUM stgmDIB;
+
+ FORMATETC fetcMF =
+ {
+ CF_METAFILEPICT,
+ NULL,
+ DVASPECT_CONTENT,
+ DEF_LINDEX,
+ TYMED_MFPICT
+ };
+
+ STGMEDIUM stgmMF;
+
+
+
+ if (S_OK == hr)
+ {
+ stgmDIB.tymed = TYMED_HGLOBAL;
+ stgmDIB.hGlobal = hDIB;
+
+ hr = m_pOleCache->SetData(&fetcDIB, &stgmDIB, FALSE);
+ }
+
+ if (S_OK == hr)
+ {
+ stgmMF.tymed = TYMED_MFPICT,
+ stgmMF.hMetaFilePict = hMFPICT;
+
+ hr = m_pOleCache->SetData(&fetcMF, &stgmMF, FALSE);
+ }
+
+ //
+ // If we were able to place the data in the cache, check
+ // to make sure whatever is in the cache matches our
+ // original.
+ //
+
+ if (S_OK == hr)
+ {
+ hr = CompareDIB(hDIB);
+
+ if (S_OK == hr)
+ {
+ hr = CompareMF(hMFPICT);
+ }
+ }
+
+ //
+ // Save and Reload the cache to test persistance
+ //
+
+ if (S_OK == hr)
+ {
+ hr = SaveAndReload();
+ }
+
+ if (S_OK == hr)
+ {
+ SetCurrentState(DATA_TEST);
+ }
+
+ //
+ // Compare the data again
+ //
+
+ if (S_OK == hr)
+ {
+ hr = CompareDIB(hDIB);
+
+ if (S_OK == hr)
+ {
+ hr = CompareMF(hMFPICT);
+ }
+ }
+
+ //
+ // Discard the cache.
+ //
+
+ if (S_OK == hr)
+ {
+ hr = m_pOleCache2->DiscardCache(DISCARDCACHE_NOSAVE);
+ }
+
+ //
+ // Now compare again against the current presentations,
+ // which would have to be demand-loaded after the discard.
+ //
+
+ if (S_OK == hr)
+ {
+ hr = CompareDIB(hDIB);
+
+ if (S_OK == hr)
+ {
+ hr = CompareMF(hMFPICT);
+ }
+ }
+
+
+ //
+ // Try to draw the cache's best presentation (which should
+ // be metafile at this point) into a metafile DC which we
+ // will then hand off to the window thread for drawing.
+ //
+
+ if (S_OK == hr)
+ {
+ hr = DrawCacheToMetaFilePict(&ctest.m_hMFP, FALSE);
+
+ if (S_OK == hr)
+ {
+ SetCurrentState(DRAW_METAFILE_NOW);
+ }
+ }
+
+ //
+ // Now draw the metafile tiled 4 times into the display
+ // metafile, and hand it off...
+ //
+
+ if (S_OK == hr)
+ {
+ hr = DrawCacheToMetaFilePict(&ctest.m_hMFPTILED, TRUE);
+
+ if (S_OK == hr)
+ {
+ SetCurrentState(DRAW_METAFILETILED_NOW);
+ }
+ }
+
+ //
+ // Uncache the metafile node, which will leave the DIB node
+ // as the best (and only) node left for drawing
+ //
+
+ if (S_OK == hr)
+ {
+ hr = UncacheFormat(CF_METAFILEPICT);
+ }
+
+ //
+ // Now draw the DIB into a metafile and hand that off
+ // to the window thread for drawing
+ //
+
+ if (S_OK == hr)
+ {
+ hr = DrawCacheToMetaFilePict(&ctest.m_hMFPDIB, FALSE);
+
+ if (S_OK == hr)
+ {
+ SetCurrentState(DRAW_DIB_NOW);
+ }
+ }
+
+ //
+ // Now draw the DIB again, this time tiled into the mf
+ //
+
+ if (S_OK == hr)
+ {
+ hr = DrawCacheToMetaFilePict(&ctest.m_hMFPDIBTILED, TRUE);
+
+ if (S_OK == hr)
+ {
+ SetCurrentState(DRAW_DIBTILED_NOW);
+ }
+ }
+
+ //
+ // Cleanup our local DIB
+ //
+
+ if (hDIB)
+ {
+ GlobalFree(hDIB);
+ }
+
+ //
+ // Cleaup our local metafile
+ //
+
+ if (pMFPICT)
+ {
+ if (pMFPICT->hMF)
+ {
+ if (FALSE == DeleteMetaFile(pMFPICT->hMF))
+ {
+ hr = HRESULT_FROM_WIN32(GetLastError());
+ }
+ }
+
+ GlobalFree(hMFPICT);
+ }
+
+ return hr;
+}
+
+HRESULT TestInstance::CompareDIB(HGLOBAL hDIB)
+{
+ return S_OK;
+}
+
+HRESULT TestInstance::CompareMF(HMETAFILEPICT hMFPICT)
+{
+ return S_OK;
+}
+
+
+//+----------------------------------------------------------------------------
+//
+// Member: TestInstance::DrawCacheToMetaFilePict
+//
+// Synopsis: Draws the cache's current best presentation to
+// a metafile, contained in a metafilepict structure,
+// which is allocated off of the hGlobal pointer passed
+// in by the caller
+//
+// Arguments: [phGlobal] - The ptr to the hglobal to allocate on
+// [fTile] - If true, the pres is tiled into the mf
+//
+// Returns: HRESULT
+//
+// Notes:
+//
+// History: 06-Sep-94 Davepl Created
+//
+//-----------------------------------------------------------------------------
+
+HRESULT TestInstance::DrawCacheToMetaFilePict(HGLOBAL *phGlobal, BOOL fTile)
+{
+ HRESULT hr = S_OK;
+
+ TraceLog Log(NULL, "TestInstance::DrawCacheToMetaFilePict", GS_CACHE, VB_MINIMAL);
+ Log.OnEntry (" ( %p, %d )\n", phGlobal, fTile);
+ Log.OnExit (" ( %X )\n", &hr);
+
+ //
+ // Create a metafile, and have the cache draw its metafile
+ // into _our_ metafile.
+ //
+
+ //
+ // First, set up the METAFILEPICT structure.
+ // Since ANISOTROPIC mode allows arbitrary scaling extents, we
+ // pick 1000 as a nice arbitrary size.
+ //
+ //
+
+ METAFILEPICT *pmfp = NULL;
+ if (S_OK == hr)
+ {
+ *phGlobal = GlobalAlloc(GMEM_FIXED, sizeof(METAFILEPICT));
+ if (NULL == *phGlobal)
+ {
+ hr = HRESULT_FROM_WIN32(GetLastError());
+ }
+ else
+ {
+ pmfp = (METAFILEPICT *) GlobalLock(*phGlobal);
+ if (NULL == pmfp)
+ {
+ GlobalFree(*phGlobal);
+ *phGlobal = NULL;
+ hr = HRESULT_FROM_WIN32(GetLastError());
+ }
+ else
+ {
+ pmfp->xExt = 1000;
+ pmfp->yExt = 1000;
+ pmfp->mm = MM_ANISOTROPIC;
+ }
+ }
+ }
+
+ //
+ // Now create the metafile within the METAFILEPICT structure,
+ // and ask the cache to draw to it.
+ //
+
+ HDC mfdc;
+ if (S_OK == hr)
+ {
+ mfdc = CreateMetaFile(NULL);
+ if (NULL == mfdc)
+ {
+ hr = HRESULT_FROM_WIN32(GetLastError());
+ GlobalUnlock(*phGlobal);
+ GlobalFree(*phGlobal);
+ *phGlobal = NULL;
+ }
+ }
+
+ //
+ // If we are not tiling the metafile, we draw it exactly once,
+ // scaled to fit the entire output metafile
+ //
+
+ if (S_OK == hr && FALSE == fTile)
+ {
+ RECTL rcBounds = {0, 0, 1000, 1000};
+ RECTL rcWBounds = {0, 0, 1000, 1000};
+
+ SetMapMode(mfdc, MM_ANISOTROPIC);
+ SetWindowExtEx(mfdc, 1000, 1000, NULL);
+ SetWindowOrgEx(mfdc, 0, 0, NULL);
+
+ hr = m_pViewObject->Draw(DVASPECT_CONTENT, // Aspect
+ DEF_LINDEX, // LIndex
+ NULL, // pvAspect
+ NULL, // ptd
+ NULL, // hicTargetDev
+ mfdc, // hdc to draw to
+ &rcBounds, // rectange to draw to
+ &rcWBounds, // bounds of our mfdc
+ NULL, // callback fn
+ 0); // continue param
+
+ }
+
+ //
+ // If we are tiling the metafile (which tests the ability of
+ // the cache to offset and scale the presentation to a rect within
+ // a larger metafile rect), we draw it once in each of the four
+ // corners
+ //
+
+ if (S_OK == hr && TRUE == fTile)
+ {
+ RECTL rcBounds;
+ RECTL rcWBounds = {0, 0, 1000, 1000};
+
+ SetMapMode(mfdc, MM_ANISOTROPIC);
+ SetWindowExtEx(mfdc, 1000, 1000, NULL);
+ SetWindowOrgEx(mfdc, 0, 0, NULL);
+
+ for (int a=0; a < 4 && S_OK == hr; a++)
+ {
+ switch(a)
+ {
+ case 0: // Upper left hand tile
+
+ rcBounds.left = 0;
+ rcBounds.top = 0;
+ rcBounds.right = 500;
+ rcBounds.bottom = 500;
+ break;
+
+ case 1: // Upper right hand tile
+
+ rcBounds.left = 500;
+ rcBounds.top = 0;
+ rcBounds.right = 1000;
+ rcBounds.bottom = 500;
+ break;
+
+ case 2: // Lower left hand tile
+
+ rcBounds.left = 0;
+ rcBounds.top = 500;
+ rcBounds.right = 500;
+ rcBounds.bottom = 1000;
+ break;
+
+ case 3: // Lower right hand tile
+
+ rcBounds.left = 500;
+ rcBounds.top = 500;
+ rcBounds.right = 1000;
+ rcBounds.bottom = 1000;
+ break;
+ }
+
+ hr = m_pViewObject->Draw(DVASPECT_CONTENT, // Aspect
+ DEF_LINDEX, // LIndex
+ NULL, // pvAspect
+ NULL, // ptd
+ NULL, // hicTargetDev
+ mfdc, // hdc to draw to
+ &rcBounds, // rectange to draw to
+ &rcWBounds, // bounds of our mfdc
+ NULL, // callback fn
+ 0); // continue param
+ }
+ }
+
+ //
+ // If the draw failed, clean up the metafile DC now
+ //
+
+ if (S_OK != hr)
+ {
+ GlobalUnlock(*phGlobal);
+ GlobalFree(*phGlobal);
+
+ HMETAFILE temp = CloseMetaFile(mfdc);
+ if (temp)
+ {
+ DeleteMetaFile(temp);
+ }
+ }
+
+ //
+ // Finish up the metafile and prepare to return it to the caller
+ //
+
+ if (S_OK == hr)
+ {
+ pmfp->hMF = CloseMetaFile(mfdc);
+
+ if (pmfp->hMF)
+ {
+ GlobalUnlock(*phGlobal);
+ }
+ else
+ {
+ hr = HRESULT_FROM_WIN32(GetLastError());
+ GlobalUnlock(*phGlobal);
+ GlobalFree(*phGlobal);
+ *phGlobal = NULL;
+ }
+ }
+
+ return hr;
+}
+
+//+----------------------------------------------------------------------------
+//
+// Member: TestInstance::GetCurrentState
+//
+// Synopsis: Returns the state of the unit test (for drawing)
+//
+// Arguments: (none)
+//
+// Returns: HRESULT
+//
+// Notes:
+//
+// History: 04-Sep-94 Davepl Created
+//
+//-----------------------------------------------------------------------------
+
+TEST_STATE TestInstance::GetCurrentState()
+{
+ //
+ // In order to avoid race conditions, we have a mutex around the
+ // current state of the unit test (required because this member
+ // function will be running on the window's thread, not the current
+ // test instance thread.)
+ //
+
+ DWORD dwResult = WaitForSingleObject(ctest.Mutex(), INFINITE);
+ if (WAIT_FAILED == dwResult)
+ {
+ return INVALID_STATE;
+ }
+
+ TEST_STATE tsSnapshot = m_State;
+
+ ReleaseMutex(ctest.Mutex());
+
+ return tsSnapshot;
+}
+
+//+----------------------------------------------------------------------------
+//
+// Member: TestInstance::SetCurrentState
+//
+// Synopsis: Sets the current (drawing) state of the unit test
+//
+// Arguments: [state] - the state to set
+//
+// Returns: HRESULT
+//
+// Notes:
+//
+// History: 04-Sep-94 Davepl Created
+//
+//-----------------------------------------------------------------------------
+
+void TestInstance::SetCurrentState(TEST_STATE state)
+{
+ //
+ // In order to avoid race conditions, we have a mutex around the
+ // current state of the unit test (required because this member
+ // function will be running on the window's thread, not the current
+ // test instance thread.)
+ //
+
+ DWORD dwResult = WaitForSingleObject(ctest.Mutex(), INFINITE);
+ if (WAIT_FAILED == dwResult)
+ {
+ return;
+ }
+
+ m_State = state;
+
+ ReleaseMutex(ctest.Mutex());
+
+ //
+ // Invalid the main window so it will redraw itself with the new
+ // state of the test.
+ //
+
+ InvalidateRgn(ctest.Window(), NULL, FALSE);
+ UpdateWindow(ctest.Window());
+
+}
+
+//+----------------------------------------------------------------------------
+//
+// Member: TestInstance::Draw
+//
+// Synopsis: Draws the current state of the unit test
+//
+// Arguments: [hdc] - The DC to draw to
+//
+// Returns: HRESULT
+//
+// Notes: The DC is supplied, but the main window is assumed
+//
+// History: 04-Sep-94 Davepl Created
+//
+//-----------------------------------------------------------------------------
+
+static char szStarting[] = "Test is starting...";
+static char szInvalid[] = "The state of the test has become invalid...";
+static char szEnumerator[] = "Testing the cache enumerator...";
+static char szSaveReload[] = "Saving and reloading the cache and its data...";
+static char szDataTest[] = "Testing data integrity within the cache...";
+static char szMulti[] = "Testing a large number of simultaneous cache nodes...";
+static char szMetafile[] = "MF -> MF";
+static char szMetafileTiled[] = "MF -> MF (Tiled)";
+static char szDib[] = ""; // Dib contains its own title
+
+void TestInstance::Draw(HDC hdc)
+{
+ //
+ // Retrieve the current state of the unit test
+ //
+
+ TEST_STATE tsState = GetCurrentState();
+
+ //
+ // Clear the window
+ //
+
+ RECT rect;
+ if (TRUE == GetClientRect(ctest.Window(), &rect))
+ {
+ FillRect(hdc, &rect, (HBRUSH) GetStockObject(LTGRAY_BRUSH));
+ }
+
+ //
+ // Draw the current state
+ //
+
+ int iBackMode = SetBkMode(hdc, TRANSPARENT);
+
+ switch(tsState)
+ {
+ case TEST_STARTING:
+
+ TextOut(hdc, 10, 10, szStarting, strlen(szStarting));
+ break;
+
+ case TESTING_ENUMERATOR:
+
+ TextOut(hdc, 10, 10, szEnumerator, strlen(szEnumerator));
+ break;
+
+ case SAVE_AND_RELOAD:
+
+ TextOut(hdc, 10, 10, szSaveReload, strlen(szSaveReload));
+ break;
+
+ case DATA_TEST:
+
+ TextOut(hdc, 10, 10, szDataTest, strlen(szDataTest));
+ break;
+
+ case MULTI_CACHE:
+
+ TextOut(hdc, 10, 10, szMulti, strlen(szMulti));
+ break;
+
+ case DRAW_METAFILE_NOW:
+ case DRAW_METAFILETILED_NOW:
+ case DRAW_DIB_NOW:
+ case DRAW_DIBTILED_NOW:
+ {
+ // We know now that we have to draw a metafile, so
+ // determine which of the metafiles we should be drawing,
+ // and set a handle (so we can reuse the draw code) and
+ // the description text appropriately.
+
+ HGLOBAL hMFP;
+ char * szDesc;
+
+ if (DRAW_METAFILE_NOW == tsState)
+ {
+ hMFP = ctest.m_hMFP;
+ szDesc = szMetafile;
+ }
+ else if (DRAW_METAFILETILED_NOW == tsState)
+ {
+ hMFP = ctest.m_hMFPTILED;
+ szDesc = szMetafileTiled;
+ }
+ else if (DRAW_DIB_NOW == tsState)
+ {
+ hMFP = ctest.m_hMFPDIB;
+ szDesc = szDib;
+ }
+ else if (DRAW_DIBTILED_NOW == tsState)
+ {
+ hMFP = ctest.m_hMFPDIBTILED;
+ szDesc = szDib;
+ }
+
+ TextOut(hdc, 10, 10, szDesc, strlen(szDesc));
+
+ //
+ // Now actually draw the metafile to our main window
+ //
+
+ if (hMFP)
+ {
+ METAFILEPICT *pMFP = (METAFILEPICT *) GlobalLock(hMFP);
+ if (NULL == pMFP)
+ {
+ mprintf("Unable to lock metafile handle");
+ break;
+ }
+
+ int save = SaveDC(hdc);
+
+ SetMapMode(hdc, pMFP->mm);
+ SetWindowExtEx(hdc, pMFP->xExt, pMFP->yExt, NULL);
+
+ RECT client;
+ GetClientRect(ctest.Window(), &client);
+
+ SetViewportExtEx(hdc, client.right, client.bottom, NULL);
+ SetWindowOrgEx(hdc, 0, 0, NULL);
+ SetViewportOrgEx(hdc, client.left, client.top, NULL);
+
+ PlayMetaFile(hdc, pMFP->hMF);
+
+ RestoreDC(hdc, save);
+
+ }
+ break;
+ }
+
+ case INVALID_STATE:
+ default:
+
+ TextOut(hdc, 10, 10, szInvalid, strlen(szInvalid));
+ break;
+
+ }
+
+ SetBkMode(hdc, iBackMode);
+
+}
+
diff --git a/private/oleutest/cachetst/multi.cpp b/private/oleutest/cachetst/multi.cpp
new file mode 100644
index 000000000..bb95dcd4b
--- /dev/null
+++ b/private/oleutest/cachetst/multi.cpp
@@ -0,0 +1,287 @@
+//+----------------------------------------------------------------------------
+//
+// File:
+// multi.cpp
+//
+// Contents:
+// Cache node test which creates multiple nodes, then performs
+// various data tests on them.
+//
+// History:
+//
+// 04-Sep-94 davepl Created
+//
+//-----------------------------------------------------------------------------
+
+#include "headers.hxx"
+#pragma hdrstop
+
+//+----------------------------------------------------------------------------
+//
+// Member: TestInstance::MultiCache
+//
+// Synopsis: Caches N unique nodes, where N is large (>100). Saves
+// the cache, then reloads it to compare.
+//
+// Arguments: [dwCount] Number of new nodes to cache
+//
+// Returns: HRESULT
+//
+// Notes:
+//
+// History: 24-Aug-94 Davepl Created
+//
+//-----------------------------------------------------------------------------
+
+HRESULT TestInstance::MultiCache(DWORD dwCount)
+{
+ HRESULT hr;
+
+ DWORD iCFGEN = 0,
+ iNODES = 0,
+ iSDATA = 0;
+
+ TraceLog Log(NULL, "TestInstance::MultiCache", GS_CACHE, VB_MINIMAL);
+ Log.OnEntry (" ( %d )\n", dwCount);
+ Log.OnExit (" ( %X )\n", &hr);
+
+ //
+ // A temporary buffer for creating text clipformat names
+ //
+
+ char szFormatName[ MAX_BUF ];
+
+ //
+ // An array of UINTs to hold our private clipformats, and an
+ // array of DWORDS to hold the connection IDs
+ //
+
+ CLIPFORMAT *acfArray = (CLIPFORMAT *) malloc(dwCount * sizeof(CLIPFORMAT));
+ if (NULL == acfArray)
+ {
+ return E_OUTOFMEMORY;
+ }
+
+ DWORD *adwConnections = (DWORD *) malloc(dwCount * sizeof(DWORD));
+ if (NULL == adwConnections)
+ {
+ free(acfArray);
+ return E_OUTOFMEMORY;
+ }
+
+ //
+ // Generate N private clipformats
+ //
+
+ for (iCFGEN=0; iCFGEN < dwCount; iCFGEN++)
+ {
+ sprintf(szFormatName, "LocalFormat%d", iCFGEN);
+
+ acfArray[iCFGEN] = (WORD) RegisterClipboardFormat(szFormatName);
+ if (0 == acfArray[iCFGEN])
+ {
+ free(acfArray);
+ return HRESULT_FROM_WIN32(GetLastError());
+ }
+ }
+
+ //
+ // Cache N nodes based on those formats
+ //
+
+ FORMATETC fetc =
+ {
+ 0, // Clipformat
+ NULL, // DVTargetDevice
+ DVASPECT_CONTENT, // Aspect
+ -1, // Index
+ TYMED_HGLOBAL // TYMED
+ };
+
+ STGMEDIUM stgm;
+
+ for (iNODES = 0; iNODES < dwCount; iNODES++)
+ {
+ fetc.cfFormat = acfArray[iNODES];
+ hr = m_pOleCache->Cache(&fetc, ADVF_PRIMEFIRST, &adwConnections[iNODES]);
+
+ // We are expecting the cache to return CACHE_S_FORMATETC_NOTSUPPORTED
+ // for this data, since it cannot draw it.
+
+ hr = MassageErrorCode(CACHE_S_FORMATETC_NOTSUPPORTED, hr);
+
+ if (S_OK != hr)
+ {
+ break;
+ }
+ }
+
+ //
+ // If all went well adding the nodes, proceed to SetData into
+ // each of the nodes with some unique data
+ //
+
+ if (S_OK == hr)
+ {
+ for (iSDATA = 0; iSDATA < dwCount; iSDATA++)
+ {
+ HGLOBAL hTmp = GlobalAlloc(GMEM_MOVEABLE, sizeof(DWORD));
+ if (NULL == hTmp)
+ {
+ break;
+ }
+ DWORD * pdw = (DWORD *) GlobalLock(hTmp);
+ if (NULL == pdw)
+ {
+ GlobalFree(hTmp);
+ break;
+ }
+
+ //
+ // Set the data in the HGLOBAL equal to the clipformat
+ // for this node
+ //
+
+ *pdw = iSDATA;
+
+ GlobalUnlock(hTmp);
+
+ stgm.tymed = TYMED_HGLOBAL;
+ stgm.hGlobal = hTmp;
+ fetc.cfFormat = acfArray[iSDATA];
+
+ hr = m_pOleCache->SetData(&fetc, &stgm, TRUE /* fRelease */);
+
+ if (S_OK != hr)
+ {
+ break;
+ }
+ }
+ }
+
+ //
+ // Save the cache and reload it
+ //
+
+ if (S_OK == hr)
+ {
+ hr = SaveAndReload();
+ }
+
+ //
+ // Just to make things interesting, let's DiscardCache before we
+ // start looking for data. This will force the cache to demand-load
+ // the data as we ask for it. Since we know the cache is not dirty,
+ // there's no value (practical or from a test perspective) in asking
+ // the DiscardCache to save along the way.
+ //
+
+ if (S_OK == hr)
+ {
+ hr = m_pOleCache2->DiscardCache(DISCARDCACHE_NOSAVE);
+ }
+
+ if (S_OK == hr)
+ {
+ for (iSDATA = 0; iSDATA < dwCount; iSDATA++)
+ {
+ //
+ // For each of the cache nodes we added, try to
+ // get the data that was saved in the cache under
+ // that clipformat
+ //
+
+ fetc.cfFormat = acfArray[iSDATA];
+ hr = m_pDataObject->GetData(&fetc, &stgm);
+ if (S_OK != hr)
+ {
+ ReleaseStgMedium(&stgm);
+ break;
+ }
+
+ //
+ // Lock the HGLOBAL and compare what is in the cache
+ // node to what we expect should be there (the index
+ // into our clipboard format table
+ //
+
+ DWORD * pdw = (DWORD *) GlobalLock(stgm.hGlobal);
+ if (NULL == pdw)
+ {
+ hr = E_OUTOFMEMORY;
+ break;
+ }
+
+ if (*pdw != iSDATA)
+ {
+ hr = E_FAIL;
+ GlobalUnlock(stgm.hGlobal);
+ ReleaseStgMedium(&stgm);
+ break;
+ }
+
+ GlobalUnlock(stgm.hGlobal);
+ ReleaseStgMedium(&stgm);
+ }
+ }
+
+ //
+ // We want to remove all of the cache nodes we have added.
+ // Unforunately, there is no easy way to do this; we have to
+ // enumerate over the cache and toss nodes as we find them, even
+ // though we _know_ everything about the nodes. Sigh...
+ //
+
+ //
+ // Get an enumerator on the cache
+ //
+
+ LPENUMSTATDATA pEsd;
+ if (S_OK == hr)
+ {
+ hr = m_pOleCache->EnumCache(&pEsd);
+ }
+
+ //
+ // Since we've got a large number of cache nodes in the cache,
+ // now is a perfect time to run the generic enumerator tests on
+ // the cache.
+ //
+
+ if (S_OK == hr)
+ {
+ hr = TestEnumerator((void *) pEsd, sizeof(STATDATA), iSDATA, NULL, NULL,NULL);
+ }
+
+ //
+ // Reset the enumerator before beginning our UnCache loop.
+ //
+
+ if (S_OK == hr)
+ {
+ hr = pEsd->Reset();
+ }
+
+ if (S_OK == hr)
+ {
+ //
+ // Loop until a failure or until we have removed all of
+ // the nodes that we thought should exist
+ //
+
+ STATDATA stat;
+
+ while (S_OK == hr && iSDATA > 0)
+ {
+ hr = pEsd->Next(1, &stat, NULL);
+
+ if (S_OK == hr)
+ {
+ hr = m_pOleCache->Uncache(stat.dwConnection);
+ iSDATA--;
+ }
+ }
+ }
+
+ return hr;
+}
diff --git a/private/oleutest/cachetst/utils.cpp b/private/oleutest/cachetst/utils.cpp
new file mode 100644
index 000000000..01f8371ea
--- /dev/null
+++ b/private/oleutest/cachetst/utils.cpp
@@ -0,0 +1,315 @@
+#include "headers.hxx"
+#pragma hdrstop
+
+//+----------------------------------------------------------------------------
+//
+// File:
+// utils.cpp
+//
+// Contents:
+// Utility functions for the cache unit test
+//
+// History:
+//
+// 04-Sep-94 davepl Created
+//
+//-----------------------------------------------------------------------------
+
+
+//+----------------------------------------------------------------------------
+//
+// Member: TestInstance::AddXXXCacheNode
+//
+// Synopsis: Adds an empty cache node for various formats
+//
+// Arguments: [inst] -- ptr to test instance
+// [pdwCon] -- ptr to connection ID (out)
+//
+// Returns: HRESULT
+//
+// Notes:
+//
+// History: 23-Aug-94 Davepl Created
+//
+//-----------------------------------------------------------------------------
+
+HRESULT TestInstance::AddMFCacheNode(DWORD *pdwCon)
+{
+ HRESULT hr;
+
+ TraceLog Log(this, "TestInstance::AddMFCacheNode", GS_CACHE, VB_MAXIMUM);
+ Log.OnEntry (" ( %p ) \n", pdwCon);
+ Log.OnExit (" ( %X ) [ %p ]\n", &hr, pdwCon);
+
+ FORMATETC fetcMF =
+ {
+ CF_METAFILEPICT, // Clipformat
+ NULL, // DVTargetDevice
+ DVASPECT_CONTENT, // Aspect
+ -1, // Index
+ TYMED_MFPICT // TYMED
+ };
+
+ //
+ // Cache a METAFILE node
+ //
+
+ hr = m_pOleCache->Cache(&fetcMF, ADVF_PRIMEFIRST, pdwCon);
+ return hr;
+}
+
+HRESULT TestInstance::AddEMFCacheNode(DWORD *pdwCon)
+{
+ HRESULT hr;
+
+ TraceLog Log(this, "TestInstance::AddEMFCacheNode", GS_CACHE, VB_MAXIMUM);
+ Log.OnEntry (" ( %p ) \n", pdwCon);
+ Log.OnExit (" ( %X ) [ %p ]\n", &hr, pdwCon);
+
+ FORMATETC fetcEMF = {
+ CF_ENHMETAFILE, // Clipformat
+ NULL, // DVTargetDevice
+ DVASPECT_CONTENT, // Aspect
+ -1, // Index
+ TYMED_ENHMF // TYMED
+ };
+
+ //
+ // Cache an ENH METAFILE node
+ //
+
+ hr = m_pOleCache->Cache(&fetcEMF, ADVF_PRIMEFIRST, pdwCon);
+ return hr;
+}
+
+HRESULT TestInstance::AddDIBCacheNode(DWORD *pdwCon)
+{
+ HRESULT hr;
+
+ TraceLog Log(this, "TestInstance::AddDIBCacheNode", GS_CACHE, VB_MAXIMUM);
+ Log.OnEntry (" ( %p ) \n", pdwCon);
+ Log.OnExit (" ( %X ) [ %p ]\n", &hr, pdwCon);
+
+
+ FORMATETC fetcDIB = {
+ CF_DIB, // Clipformat
+ NULL, // DVTargetDevice
+ DVASPECT_CONTENT, // Aspect
+ -1, // Index
+ TYMED_HGLOBAL // TYMED
+ };
+
+ //
+ // Cache a DIB node
+ //
+
+ hr = m_pOleCache->Cache(&fetcDIB, ADVF_PRIMEFIRST, pdwCon);
+ return hr;
+
+}
+
+HRESULT TestInstance::AddBITMAPCacheNode(DWORD *pdwCon)
+{
+ HRESULT hr;
+
+ TraceLog Log(this, "TestInstance::AddMFCacheNode", GS_CACHE, VB_MAXIMUM);
+ Log.OnEntry (" ( %p ) \n", pdwCon);
+ Log.OnExit (" ( %X ) [ %p ]\n", &hr, pdwCon);
+
+ FORMATETC fetcBITMAP = {
+ CF_BITMAP, // Clipformat
+ NULL, // DVTargetDevice
+ DVASPECT_CONTENT, // Aspect
+ -1, // Index
+ TYMED_GDI // TYMED
+ };
+
+ //
+ // Cache a BITMAP node
+ //
+
+ hr = m_pOleCache->Cache(&fetcBITMAP, ADVF_PRIMEFIRST, pdwCon);
+ return hr;
+}
+
+//+----------------------------------------------------------------------------
+//
+// Function: EltIsInArray
+//
+// Synopsis: Checks to see if a STATDATA search item is in
+// a STATDATA array. Checks clipformat and connection
+// ID only.
+//
+// Arguments: [sdToFind] STATDATA we are looking for
+// [rgStat] Array of STATDATAs to look in
+// [cCount] Count of STATDATAs in rgStat
+//
+// Returns: S_OK if found, S_FALSE if not
+//
+// Notes:
+//
+// History: 23-Aug-94 Davepl Created
+//
+//-----------------------------------------------------------------------------
+
+
+HRESULT EltIsInArray(STATDATA sdToFind, STATDATA rgStat[], DWORD cCount)
+{
+ HRESULT hr = S_FALSE;
+
+ TraceLog Log(NULL, "EltIsInArray", GS_CACHE, VB_MAXIMUM);
+ Log.OnEntry (" ( %p, %p, %d )\n", &sdToFind, rgStat, cCount);
+ Log.OnExit (" ( %X )\n", &hr);
+
+ for (DWORD a=0; a<cCount; a++)
+ {
+ if (rgStat[a].formatetc.cfFormat == sdToFind.formatetc.cfFormat &&
+ rgStat[a].dwConnection == sdToFind.dwConnection)
+ {
+ hr = S_OK;
+ break;
+ }
+ }
+
+ return hr;
+
+}
+
+//+----------------------------------------------------------------------------
+//
+// Function: ConvWidthInPelsToLHM
+// ConvHeightInPelsToLHM
+//
+// Synopsis: Converts a measurement in pixels to LOGICAL HIMETRICS.
+// If a reference DC is given, it is used, otherwise
+// the screen DC is used as a default.
+//
+// Arguments: [hDC] The reference DC
+// [int] The width or height to convert
+//
+// Returns: S_OK if found, S_FALSE if not
+//
+// History: 06-Aug-94 Davepl Copy/Paste/Cleanup
+//
+//-----------------------------------------------------------------------------
+
+const LONG HIMETRIC_PER_INCH = 2540;
+
+int ConvWidthInPelsToLHM(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 = MulDiv(HIMETRIC_PER_INCH, iWidthInPix, iXppli);
+
+ if (fSystemDC)
+ {
+ ReleaseDC(NULL, hDC);
+ }
+
+ return iWidthInHiMetric;
+}
+
+int ConvHeightInPelsToLHM(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 = MulDiv(HIMETRIC_PER_INCH, iHeightInPix, iYppli);
+
+ if (fSystemDC)
+ {
+ ReleaseDC(NULL, hDC);
+ }
+
+ return iHeightInHiMetric;
+}
+
+//+----------------------------------------------------------------------------
+//
+// Function: TestInstance::UncacheFormat
+//
+// Synopsis: Uncaches the first node found in the cache that
+// matches the format specified.
+//
+// Arguments: [cf] Format to look for
+//
+// Returns: HRESULT
+//
+// Notes: If there are multiple nodes (ie: various apsects) of
+// the same clipformat, only the first one found is
+// removed.
+//
+// History: 23-Aug-94 Davepl Created
+//
+//-----------------------------------------------------------------------------
+
+HRESULT TestInstance::UncacheFormat(CLIPFORMAT cf)
+{
+ HRESULT hr;
+
+ TraceLog Log(NULL, "TestInstance::UncacheFormat", GS_CACHE, VB_MAXIMUM);
+ Log.OnEntry (" ( %d )\n", cf);
+ Log.OnExit (" ( %X )\n", &hr);
+
+ BOOL fFound = FALSE;
+
+ //
+ // Get an enumerator on the cache
+ //
+
+ LPENUMSTATDATA pEsd;
+
+ hr = m_pOleCache->EnumCache(&pEsd);
+
+
+ if (S_OK == hr)
+ {
+ //
+ // Loop until a failure or until we have removed all of
+ // the nodes that we thought should exist
+ //
+
+ STATDATA stat;
+
+ while (S_OK == hr && FALSE == fFound)
+ {
+ hr = pEsd->Next(1, &stat, NULL);
+
+ if (S_OK == hr && stat.formatetc.cfFormat == cf)
+ {
+ hr = m_pOleCache->Uncache(stat.dwConnection);
+ if (S_OK == hr)
+ {
+ fFound = TRUE;
+ }
+ }
+ }
+ }
+
+ return hr;
+}
diff --git a/private/oleutest/cairo.inc b/private/oleutest/cairo.inc
new file mode 100644
index 000000000..9ababba4d
--- /dev/null
+++ b/private/oleutest/cairo.inc
@@ -0,0 +1,26 @@
+# This is the global include file for the cairo version of CairOLE.
+# It is included by all project sources files.
+
+C_DEFINES= \
+ $(C_DEFINES) \
+ -DFLAT \
+ -DWIN32=300 \
+ -D_CAIRO_=300 \
+ -DUNICODE \
+ -D_UNICODE \
+ -DINC_OLE2 \
+ -DNOEXCEPTIONS \
+ -DCAIROLE_DISTRIBUTED \
+ -DMULTI_THREADING \
+ $(TRACELOG)
+
+
+BLDCRT= 1
+
+# For the Cairo build, we do not want statically linked compiler runtimes,
+# so leave this commented out.
+#
+# USE_LIBCMT= 1
+
+
+USE_CRTDLL=1
diff --git a/private/oleutest/cfmex/cdir.cxx b/private/oleutest/cfmex/cdir.cxx
new file mode 100644
index 000000000..250404676
--- /dev/null
+++ b/private/oleutest/cfmex/cdir.cxx
@@ -0,0 +1,418 @@
+
+//+==========================================================================
+//
+// File: CDir.cxx
+//
+// Purpose: Define the CDirectory class.
+//
+// This class is used to represent a directory name.
+// Along with maintaining the name, it can determine
+// the type of FileSystem.
+//
+//+==========================================================================
+
+
+// --------
+// Includes
+// --------
+
+#include <windows.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <wchar.h>
+#include <wtypes.h>
+
+#include "CFMEx.hxx"
+#include "CDir.hxx"
+
+
+//+------------------------------------------------------------------------------
+//
+// Function: CDirectory::Initialize (no arguments)
+//
+// Synopsis: Generate a directory name, using the TEMP environment
+// variable, and use it to initialize this object.
+//
+// Inputs: None.
+//
+// Outputs: TRUE if the function succeeds, FALSE otherwise.
+//
+//+------------------------------------------------------------------------------
+
+BOOL CDirectory::Initialize()
+{
+ // ---------------
+ // Local Variables
+ // ---------------
+
+ // Assume failure for now.
+ BOOL bSuccess = FALSE;
+
+ // The TEMP environment variable.
+ WCHAR wszSystemTempPath[ MAX_PATH + sizeof( L'\0' )];
+
+ // Reset the error code.
+ m_lError = 0L;
+
+ // ----------
+ // Get %TEMP%
+ // ----------
+
+ if( !GetTempPath( MAX_PATH,
+ wszSystemTempPath )
+ )
+ {
+ m_lError = GetLastError();
+ EXIT( L"GetTempPath() failed (%d)" );
+ }
+
+ // ----------------------
+ // Initialize this object
+ // ----------------------
+
+ // Initialize using the temporary path. We must never pass a NULL here,
+ // or we'll cause an infinite recursion.
+
+ if( wszSystemTempPath == NULL )
+ EXIT( L"Invalid temporary path" );
+ bSuccess = Initialize( wszSystemTempPath );
+
+ // ----
+ // Exit
+ // ----
+
+Exit:
+
+ return( bSuccess );
+
+}
+
+//+-----------------------------------------------------------------------
+//
+// Function: CDirectory::Initialize (with an ANSI string)
+//
+// Synopsis: This function converts the ANSI string to a Unicode
+// string, then initializes the object with it.
+//
+// Inputs: A Unicode string.
+//
+// Outputs: TRUE if the function succeeds, FALSE otherwise.
+//
+//+-----------------------------------------------------------------------
+
+BOOL CDirectory::Initialize( LPCSTR szDirectory )
+{
+ // ---------------
+ // Local Variables
+ // ---------------
+
+ // Assume failure.
+ BOOL bSuccess = FALSE;
+
+ // A buffer for the Unicode path
+ WCHAR wszDirectory[ MAX_UNICODE_PATH + sizeof( L'\0' )];
+
+ // -----
+ // Begin
+ // -----
+
+ // Initialize the error code.
+ m_lError = 0L;
+
+
+ // If we were givin a NULL path, use the version of Initialize
+ // that requires no path.
+
+ if( szDirectory == NULL )
+ {
+ bSuccess = Initialize();
+ goto Exit;
+ }
+
+ // Convert the Ansi name to Unicode.
+
+ if( m_lError = (long) AnsiToUnicode( szDirectory,
+ wszDirectory,
+ strlen( szDirectory )
+ )
+ )
+ {
+ EXIT( L"Unable to convert directory to Unicode" );
+ }
+
+ // Initialize using the temporary path. We must never pass a NULL here,
+ // or we'll cause an infinite recursion.
+
+ if( wszDirectory == NULL )
+ EXIT( L"Invalid Directory (internal error)" );
+ bSuccess = Initialize( wszDirectory );
+
+ // ----
+ // Exit
+ // ----
+
+Exit:
+
+ return( bSuccess );
+
+}
+
+
+//+-----------------------------------------------------------------------
+//
+// Function: CDirectory::Initialize (with a Unicode string)
+//
+// Synopsis: This function is the only form of Initialize
+// (there are several variations of the Initialize member)
+// which really initializes the object. It stores the
+// directory name, and determines the type of filesystem
+// on which it resides.
+//
+// Inputs: A Unicode string.
+//
+// Outputs: TRUE if the function succeeds, FALSE otherwise.
+//
+//+-----------------------------------------------------------------------
+
+BOOL CDirectory::Initialize( LPCWSTR wszDirectory )
+{
+
+ // ---------------
+ // Local Variables
+ // ---------------
+
+ // Assume failure.
+ BOOL bSuccess = FALSE;
+
+ // Buffers for the root of the path and for the volume name.
+ WCHAR wszDirectoryRoot[ MAX_PATH + sizeof( L'\0' )];
+ WCHAR wszVolumeName[ MAX_PATH + sizeof( L'\0' )];
+
+ // Parameters to GetVolumeInformation which we won't use.
+ DWORD dwMaxComponentLength = 0L;
+ DWORD dwFileSystemFlags = 0L;
+
+ // -----
+ // Begin
+ // -----
+
+ // Initialize the error code.
+ m_lError = 0L;
+
+ // If we were given a NULL path, use the variation of Initialization()
+ // which does not require one. Note that we will then be called again,
+ // but this time with a path.
+
+ if( wszDirectory == NULL )
+ {
+ bSuccess = Initialize();
+ goto Exit;
+ }
+
+ // Validate the path.
+
+ if( wcslen( wszDirectory ) > MAX_PATH )
+ {
+ m_lError = wcslen( wszDirectory );
+ EXIT( L"Input path is too long (%d)\n" );
+ }
+
+ // Save the path to our member buffer
+
+ wcscpy( m_wszDirectory, wszDirectory );
+
+
+ // ------------------------
+ // Get the file system name
+ // ------------------------
+
+ // Get the root path to the directory.
+
+ wcscpy( wszDirectoryRoot, wszDirectory );
+ MakeRoot( wszDirectoryRoot );
+
+ // Get the volume information, which will include the filesystem name.
+
+ if( !GetVolumeInformation( wszDirectoryRoot, // Root path name.
+ wszVolumeName, // Buffer for volume name
+ MAX_PATH, // Length of the above buffer
+ NULL, // Buffer for serial number
+ // Longest filename length.
+ &dwMaxComponentLength,
+ &dwFileSystemFlags, // Compression, etc.
+ m_wszFileSystemName,// Buffer for the FS name.
+ MAX_PATH ) // Length of above buffer
+ )
+ {
+ m_lError = GetLastError();
+ EXIT( L"GetVolumeInformation() failed" );
+ }
+
+
+ // Determine the file system type from the name.
+
+ if( !wcscmp( m_wszFileSystemName, L"FAT" ))
+ m_FileSystemType = fstFAT;
+
+ else if( !wcscmp( m_wszFileSystemName, L"NTFS" ))
+ m_FileSystemType = fstNTFS;
+
+ else if( !wcscmp( m_wszFileSystemName, L"OFS" ))
+ m_FileSystemType = fstOFS;
+
+ else
+ m_FileSystemType = fstUnknown;
+
+ bSuccess = TRUE;
+
+ // ----
+ // Exit
+ // ----
+
+Exit:
+
+ DisplayErrors( bSuccess, L"CDirectory::Initialize( wszDirectory )" );
+ return( bSuccess );
+
+}
+
+
+
+//
+// GetRootLength
+//
+// This routine was simply copied from private\windows\shell\shelldll\tracker.cxx,
+// and should not be modified here.
+//
+
+unsigned
+CDirectory::GetRootLength(const WCHAR *pwszPath)
+{
+ ULONG cwcRoot = 0;
+ m_lError = 0L;
+
+ if (pwszPath == 0)
+ pwszPath = L"";
+
+ if (*pwszPath == L'\\')
+ {
+ // If the first character is a path separator (backslash), this
+ // must be a UNC drive designator which must be of the form:
+ // <path-separator><path-separator>(<alnum>+)
+ // <path-separator>(<alnum>+)<path-separator>
+ //
+ // This covers drives like these: \\worf\scratch\ and
+ // \\savik\win4dev\.
+ //
+ pwszPath++;
+ cwcRoot++;
+
+ BOOL fMachine = FALSE;
+ BOOL fShare = FALSE;
+
+ if (*pwszPath == L'\\')
+ {
+ cwcRoot++;
+ pwszPath++;
+
+ while (*pwszPath != '\0' && *pwszPath != L'\\')
+ {
+ cwcRoot++;
+ pwszPath++;
+
+ fMachine = TRUE;
+ }
+
+ if (*pwszPath == L'\\')
+ {
+ cwcRoot++;
+ pwszPath++;
+
+ while (*pwszPath != '\0' && *pwszPath != L'\\')
+ {
+ cwcRoot++;
+ pwszPath++;
+
+ fShare = TRUE;
+ }
+
+ // If there weren't any characters in the machine or
+ // share portions of the UNC name, then the drive
+ // designator is bogus.
+ //
+ if (!fMachine || !fShare)
+ {
+ cwcRoot = 0;
+ }
+ }
+ else
+ {
+ cwcRoot = 0;
+ }
+ }
+ else
+ {
+ cwcRoot = 0;
+ }
+ }
+ else
+ if (iswalpha(*pwszPath))
+ {
+ // If the first character is an alphanumeric, we must have
+ // a drive designator of this form:
+ // (<alnum>)+<drive-separator><path-separator>
+ //
+ // This covers drives like these: a:\, c:\, etc
+ //
+
+ pwszPath++;
+ cwcRoot++;
+
+ if (*pwszPath == L':')
+ {
+ cwcRoot++;
+ pwszPath++;
+ }
+ else
+ {
+ cwcRoot = 0;
+ }
+ }
+
+ // If we have counted one or more characters in the root and these
+ // are followed by a component separator, we need to add the separator
+ // to the root length. Otherwise this is not a valid root and we need
+ // to return a length of zero.
+ //
+ if ((cwcRoot > 0) && (*pwszPath == L'\\'))
+ {
+ cwcRoot++;
+ }
+ else
+ {
+ cwcRoot = 0;
+ }
+
+ return (cwcRoot);
+}
+
+//
+// MakeRoot
+//
+// This routine was simply copied from private\windows\shell\shelldll\tracker.cxx,
+// and should not be modified here.
+//
+
+
+VOID
+CDirectory::MakeRoot(WCHAR *pwszPath)
+{
+ unsigned rootlength = GetRootLength(pwszPath);
+ m_lError = 0L;
+
+ if (rootlength)
+ {
+ pwszPath[rootlength] = L'\0';
+ }
+}
+
diff --git a/private/oleutest/cfmex/cdir.hxx b/private/oleutest/cfmex/cdir.hxx
new file mode 100644
index 000000000..7feaf8851
--- /dev/null
+++ b/private/oleutest/cfmex/cdir.hxx
@@ -0,0 +1,161 @@
+
+
+//+-----------------------------------------------------------------------
+//
+// File: CDir.hxx
+//
+// Purpose: Declare the CDirectory class. Objects of this class
+// are used to represent a directory, and provide additional
+// information about it.
+//
+//+-----------------------------------------------------------------------
+
+
+#ifndef _C_DIR_HXX_
+#define _C_DIR_HXX_
+
+// --------
+// Includes
+// --------
+
+#include "CFMEx.hxx"
+
+
+// --------
+// Typedefs
+// --------
+
+// An enumeration of the possible file system types.
+
+typedef enum
+{
+ fstFAT,
+ fstNTFS,
+ fstOFS,
+ fstUnknown
+} enumFileSystemType;
+
+
+// ----------
+// CDirectory
+// ----------
+
+class CDirectory
+{
+
+// Construction/Deconstruction
+
+public:
+
+ CDirectory();
+ ~CDirectory();
+
+// Public Member Functions
+
+public:
+
+ BOOL Initialize(); // Defaulted input
+ BOOL Initialize( LPCWSTR wszDirectory ); // Unicode input
+ BOOL Initialize( LPCSTR szDirectory ); // ANSI input
+
+ enumFileSystemType GetFileSystemType() const;
+ LPCWSTR GetFileSystemName() const;
+ LPCWSTR GetDirectoryName() const;
+
+
+// Private Member Functions
+
+private:
+
+ void DisplayErrors( BOOL bSuccess, LPCWSTR wszFunctionName );
+ VOID MakeRoot(WCHAR *pwszPath);
+ unsigned GetRootLength(const WCHAR *pwszPath);
+
+
+// Member Data
+
+private:
+
+ WCHAR m_wszDirectory[ MAX_UNICODE_PATH + sizeof( L'\0' )];
+ WCHAR m_wszFileSystemName[ MAX_UNICODE_PATH + sizeof( L'\0' )];
+ enumFileSystemType m_FileSystemType;
+
+ WCHAR m_wszErrorMessage[ 200 ];
+ long m_lError;
+
+};
+
+
+// ----------------
+// Inline Functions
+// ----------------
+
+
+// CDirectory::CDirectory
+
+inline CDirectory::CDirectory()
+{
+ wcscpy( m_wszDirectory, L"" );
+ wcscpy( m_wszFileSystemName, L"" );
+ wcscpy( m_wszErrorMessage, L"" );
+ m_lError = 0;
+ m_FileSystemType = fstUnknown;
+
+}
+
+// CDirectory::~CDirectory
+
+inline CDirectory::~CDirectory()
+{
+}
+
+// CDirectory::GetFileSystemType
+
+inline enumFileSystemType CDirectory::GetFileSystemType() const
+{
+ return m_FileSystemType;
+}
+
+// CDirectory::GetFileSystemName
+
+inline LPCWSTR CDirectory::GetFileSystemName() const
+{
+ return m_wszFileSystemName;
+}
+
+// CDirectory::GetDirectoryName
+
+inline LPCWSTR CDirectory::GetDirectoryName() const
+{
+ return m_wszDirectory;
+}
+
+
+// CDirectory::DisplayErrors
+
+inline void CDirectory::DisplayErrors( BOOL bSuccess, LPCWSTR wszFunctionName )
+{
+ if( !bSuccess )
+ {
+ wprintf( L"Error in %s (%08x)\n %s\n",
+ wszFunctionName, m_lError, m_wszErrorMessage );
+ }
+}
+
+
+// ------
+// Macros
+// ------
+
+// Early-exit macro.
+
+#undef EXIT
+#define EXIT( error ) \
+ {\
+ wcscpy( m_wszErrorMessage, ##error );\
+ goto Exit;\
+ }
+
+
+
+#endif // _C_DIR_HXX_
diff --git a/private/oleutest/cfmex/cfmex.cxx b/private/oleutest/cfmex/cfmex.cxx
new file mode 100644
index 000000000..37e8c08ed
--- /dev/null
+++ b/private/oleutest/cfmex/cfmex.cxx
@@ -0,0 +1,449 @@
+
+//+===============================================================
+//
+// File: CFMEx.cxx
+//
+// Purpose: This file provides the main() and global functions
+// for the CreateFileMonikerEx (CFMEx) DRT.
+// This DRT tests the CreateFileMonikerEx API (new to
+// Cairo), as well as related changes to BIND_OPTS
+// (use of the BIND_OPTS2 structure).
+//
+// All moniker activity is performed in the CMoniker
+// object (such as creating a bind context, creating
+// a link source file, moving it, binding it, etc.).
+//
+// The test engine is in the CTest object. When a link
+// source file is moved to test link-tracking, the
+// original and final location of the file may be
+// specified by the user (on the command-line). CTest
+// is aware of the filesystem type (FAT, NTFS, OFS)
+// of these locations, and is aware of how that will
+// effect the results.
+//
+// This file also provides global functions (not associated
+// with an object).
+//
+// Usage: cfmex [-o<Directory>] [-f<Directory>]
+//
+// -o<Directory> specifies the original directory for link sources
+// -f<Directory> specifies the final directory for link sources
+//
+// Examples: cfmex
+// cfmex -oC:\ -fC:\
+//
+//+===============================================================
+
+
+// ----
+// TODO:
+// ----
+//
+// - Replace CRT calls with Win32 calls.
+// - Validate the directory in CDirectory.
+// - Add a flag to CDirectory to indicate "indexed".
+// - Add a flag to CDirectory to indicate local vs remote.
+// - Add a test to verify that the moniker returned from Reduce is
+// not a tracking moniker.
+//
+
+
+// -------------
+// Include Files
+// -------------
+
+
+#define _DCOM_ // Allow DCOM extensions (e.g., CoInitializeEx).
+
+#include <windows.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <wchar.h>
+#include <wtypes.h>
+#include <oaidl.h>
+#include <dsys.h>
+#include <olecairo.h>
+#include "CFMEx.hxx"
+#include "CMoniker.hxx"
+#include "CTest.hxx"
+#include "CDir.hxx"
+
+
+// ------
+// Macros
+// ------
+
+// Early-exit macro: put the error message in a global array,
+// and jump to Exit
+
+WCHAR wszErrorMessage[ 512 ];
+
+#undef EXIT
+#define EXIT( error ) \
+ {\
+ wcscpy( wszErrorMessage, ##error );\
+ goto Exit;\
+ }
+
+
+
+// Run a Test: Display a new paragraph on the screen, run a test,
+// and update stats.
+
+#define RUN_TEST( testID ) \
+ {\
+ nTotalTests++; \
+ wprintf( L"----------------------------------------------\n" ); \
+ wprintf( L"Test %d: ", nTotalTests ); \
+ if( cTest.##testID ) \
+ wprintf( L"Passed\n" ); \
+ else \
+ nTestsFailed++; \
+ }
+
+
+//+---------------------------------------------------------------------------------------
+//
+// Function: DisplayHelp
+//
+// Synopsis: Display a help screen with usage information.
+//
+// Inputs: None.
+//
+// Outputs: None.
+//
+// Effects: None
+//
+//+---------------------------------------------------------------------------------------
+
+
+void DisplayHelp( void )
+{
+
+ wprintf( L"This DRT tests the CreateFileMonikerEx API, and related changes.\n"
+ L"Most of these tests create a link source file, create a moniker\n"
+ L"representing that file, then move the file. You can specify the\n"
+ L"original and/or final locations of the link source, or let those\n"
+ L"locations default to the \%TEMP\% directory\n"
+ L"\n"
+ L"Usage: cfmex [-o<Directory>] [-f<Directory>]\n"
+ L"\n"
+ L"Where: -o<Directory> specifies the original directory for link sources\n"
+ L" -f<Directory> specifies the final directory for link sources\n"
+ L"\n"
+ L"Note: If an original or final directory is specified on the command-\n"
+ L" line, that directory must already exist. If one of these locations\n"
+ L" is not specified, the TEMP environment variable must be defined\n"
+ L" and it must specify an extant directory.\n"
+ L"\n"
+ L"E.g.: cfmex\n"
+ L" cfmex -oC:\\\n"
+ L" cfmex -oE:\\ -fF:\\temp\n"
+ L"\n" );
+ return;
+}
+
+
+
+//+---------------------------------------------------------------------------------------
+//
+// Function: UnicodeToAnsi
+//
+// Synopsis: Convert a Unicode (wide) string to ANSI
+//
+// Inputs: The Unicode String
+// The buffer for the ANSI string
+// The size of the above buffer
+//
+// Outputs: 0 if successful
+// GetLastError() otherwise
+//
+// Effects: None
+//
+//+---------------------------------------------------------------------------------------
+
+DWORD UnicodeToAnsi( const WCHAR * wszUnicode,
+ CHAR * szAnsi,
+ int cbAnsiMax )
+{
+ int cbAnsi = 0;
+
+ // Convert WCS to the MBCS, using the ANSI code page.
+
+ cbAnsi = WideCharToMultiByte( CP_ACP,
+ WC_COMPOSITECHECK | WC_DEFAULTCHAR,
+ wszUnicode,
+ wcslen( wszUnicode ),
+ szAnsi,
+ cbAnsiMax,
+ NULL,
+ NULL );
+ if( !cbAnsi )
+ {
+ // No characters were converted - there was an error.
+ // Note that this will be returned if a null Unicode string is
+ // passed in.
+
+ return( GetLastError() );
+ }
+ else
+ {
+ // Terminate the Ansi string and return.
+
+ szAnsi[ cbAnsi ] = '\0';
+ return( 0L );
+ }
+
+} // UnicodeToAnsi()
+
+
+
+//+---------------------------------------------------------------------------------------
+//
+// Function: AnsiToUnicode
+//
+// Synopsis: Convert an ANSI string to Unicode (i.e. Wide)
+//
+// Inputs: The ANSI String
+// The buffer for the Unicode string
+// The size of the above buffer.
+//
+// Outputs: 0 if successful
+// GetLastError() otherwise
+//
+// Effects: None
+//
+//+---------------------------------------------------------------------------------------
+
+DWORD AnsiToUnicode( const CHAR * szAnsi,
+ WCHAR * wszUnicode,
+ int cbUnicodeMax )
+{
+ int cbUnicode = 0;
+
+ cbUnicode = MultiByteToWideChar( CP_ACP,
+ MB_PRECOMPOSED,
+ szAnsi,
+ strlen( szAnsi ),
+ wszUnicode,
+ cbUnicodeMax );
+
+ if( !cbUnicode )
+ {
+ // If no characters were converted, then there was an error.
+
+ return( GetLastError() );
+ }
+ else
+ {
+ // Terminate the Unicode string and return.
+
+ wszUnicode[ cbUnicode ] = L'\0';
+ return( 0L );
+ }
+
+} // AnsiToUnicode()
+
+
+
+//+---------------------------------------------------------------------------------------
+//
+// Function: main
+//
+// Synopsis: Run the CFMEx DRT. All tests are in the CTest object. These
+// tests are simply called sequentially.
+//
+// Inputs: (argc) the count of arguments
+// (argv) the arguments. See DisplayHelp() for a description.
+//
+// Outputs: 0 if completely successful
+// 1 if help was displayed
+// 2 if a test failed
+//
+// Effects: None
+//
+//+---------------------------------------------------------------------------------------
+
+
+int main( int argc, char** argv )
+{
+
+ // ---------------
+ // Local Variables
+ // ---------------
+
+ // Test statistics.
+
+ int nTotalTests = 0;
+ int nTestsFailed = 0;
+
+ // The original and final directories (in ANSI) of the link source file.
+
+ CHAR* szOriginalDirectory = NULL;
+ CHAR* szFinalDirectory = NULL;
+
+ // Objects representing the original and final directories.
+
+ CDirectory cDirectoryOriginal;
+ CDirectory cDirectoryFinal;
+
+ // The test engine.
+
+ CTest cTest;
+
+ int index = 0;
+
+
+ // --------------
+ // Opening Banner
+ // --------------
+
+ printf( "\n"
+ "*** CreateFileMonikerEx DRT ***\n"
+ "(use \"cfmex -?\" for help)\n"
+ "\n" );
+
+
+ // ------------------------------
+ // Handle command-line parameters
+ // ------------------------------
+
+
+ for( index = 1; index < argc; index++ )
+ {
+ // The first character of an argument should be an "-" or "/"
+ // (they are interchangable).
+
+ if( ( ( argv[index][0] != '-' )
+ &&
+ ( argv[index][0] != '/' )
+ )
+ ||
+ ( strlen( &argv[index][0] ) < 2 ) // Must have more than '-' & an option.
+ )
+ {
+ printf( "Invalid argument ignored: %s\n", argv[ index ] );
+ continue;
+ }
+
+
+ // Switch based on the first character (which defines the option).
+
+ switch( argv[index][1] )
+ {
+ // Help requested
+
+ case '?':
+ DisplayHelp();
+ exit( 1 );
+
+ // An original directory is specified.
+
+ case 'o':
+ case 'O':
+
+ // Verify the specified path length.
+
+ if( strlen( &argv[index][2] ) > MAX_PATH )
+ {
+ printf( "Path is too long, ignored: %s\n", &argv[index][2] );
+ break; // From the switch
+ }
+
+ szOriginalDirectory = &argv[index][2];
+ break; // From the switch
+
+ // A final directory is specified
+
+ case 'f':
+ case 'F':
+
+ if( strlen( &argv[index][2] ) > MAX_PATH )
+ {
+ printf( "Path is too long, ignored: %s\n", &argv[index][2] );
+ break; // From the switch
+ }
+
+ szFinalDirectory = &argv[index][2];
+ break; // From the switch
+
+ // Invalid argument.
+
+ default:
+
+ printf( "Invalid option ignored: \"-%c\"\n", argv[index][1] );
+ break;
+ }
+ }
+
+ // --------------
+ // Initialization
+ // --------------
+
+ // Initialize COM
+
+ CoInitialize( NULL );
+
+
+ // Initialize the CDirectory and CTest objects. If no original/final
+ // directory was specified above, CDirectory will create a default
+ // (based on %TEMP%).
+
+ if( !cDirectoryOriginal.Initialize( szOriginalDirectory ) )
+ EXIT( L"Could not initialize cDirectoryOriginal" );
+
+ if( !cDirectoryFinal.Initialize( szFinalDirectory ) )
+ EXIT( L"Could not initialize cDirectoryFinal" );
+
+ if( !cTest.Initialize( cDirectoryOriginal, cDirectoryFinal ) )
+ EXIT( L"Could not initialize CTest" );
+
+
+ // Show the end result.
+
+ wprintf( L"Link sources will be created in \"%s\" (%s)\n",
+ cDirectoryOriginal.GetDirectoryName(),
+ cDirectoryOriginal.GetFileSystemName() );
+ wprintf( L"and will be moved to \"%s\" (%s)\n",
+ cDirectoryFinal.GetDirectoryName(),
+ cDirectoryFinal.GetFileSystemName() );
+
+
+ // ---------
+ // Run Tests
+ // ---------
+
+ RUN_TEST( GetOversizedBindOpts() );
+ RUN_TEST( GetUndersizedBindOpts() );
+ RUN_TEST( SetOversizedBindOpts() );
+ RUN_TEST( SetUndersizedBindOpts() );
+ RUN_TEST( CreateFileMonikerEx() );
+ RUN_TEST( GetDisplayName() );
+ RUN_TEST( GetTimeOfLastChange() );
+ RUN_TEST( ComposeWith() );
+ RUN_TEST( IPersist() );
+ RUN_TEST( BindToStorage() );
+ RUN_TEST( BindToObject() );
+ RUN_TEST( DeleteLinkSource( 0 )); // Timeout immediately.
+ RUN_TEST( DeleteLinkSource( 200 )); // Timeout in multi-threaded search
+ RUN_TEST( DeleteLinkSource( INFINITE )); // Don't timeout
+
+ // ----
+ // Exit
+ // ----
+
+Exit:
+
+ // Show test results.
+
+ wprintf( L"\n\nTesting complete:\n"
+ L" Total Tests = %d\n"
+ L" Failed = %d\n",
+ nTotalTests, nTestsFailed );
+
+ // Free COM
+
+ CoUninitialize();
+
+ return( nTestsFailed ? 2 : 0 );
+}
diff --git a/private/oleutest/cfmex/cfmex.hxx b/private/oleutest/cfmex/cfmex.hxx
new file mode 100644
index 000000000..5f1f6f488
--- /dev/null
+++ b/private/oleutest/cfmex/cfmex.hxx
@@ -0,0 +1,31 @@
+
+//+==============================================================================
+//
+// File: CFMEx.hxx
+//
+// Purpose: Provide global definitions and function prototypes
+// for the CreateFileMonikerEx DRT.
+//
+//+==============================================================================
+
+#ifndef _CFMEX_HXX_
+#define _CFMEX_HXX_
+
+// The size of a buffer which will hold a path depends on the size
+// of the characters.
+
+#define MAX_ANSI_PATH MAX_PATH
+#define MAX_UNICODE_PATH ( MAX_PATH * sizeof( WCHAR ))
+
+// Function prototypes.
+
+DWORD AnsiToUnicode( const CHAR * szAnsi,
+ WCHAR * wszUnicode,
+ int cbUnicodeMax );
+
+DWORD UnicodeToAnsi( const WCHAR * wszUnicode,
+ CHAR * szAnsi,
+ int cbAnsiMax );
+
+
+#endif // _CFMEX_HXX_
diff --git a/private/oleutest/cfmex/cmoniker.cxx b/private/oleutest/cfmex/cmoniker.cxx
new file mode 100644
index 000000000..7a9c555a7
--- /dev/null
+++ b/private/oleutest/cfmex/cmoniker.cxx
@@ -0,0 +1,1684 @@
+
+//+=======================================================================
+//
+// File: CMoniker.cxx
+//
+// Purpose: Define the CMoniker class.
+//
+// This class provides for all handling of monikers in
+// the CreateFileMonikerEx DRT. Not only does it maintain
+// a file moniker, it also maintains the represented link
+// source file, and a bind context.
+//
+//+=======================================================================
+
+// --------
+// Includes
+// --------
+
+#define _DCOM_ // Allow DCOM extensions (e.g., CoInitializeEx).
+
+#include <windows.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <wchar.h>
+#include <wtypes.h>
+#include <oaidl.h>
+#include <dsys.h>
+#include <olecairo.h>
+#include "CFMEx.hxx"
+#include "CMoniker.hxx"
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: CMoniker::CMoniker
+//
+// Synopsis: Simply initialize all member variables.
+//
+// Inputs: None.
+//
+// Outputs: N/A
+//
+// Effects: Members are defaulted/initialized.
+//
+//+-------------------------------------------------------------------------
+
+
+CMoniker::CMoniker()
+{
+ *m_wszSystemTempPath = L'\0';
+ *m_wszTemporaryStorage = L'\0';
+ m_pIMoniker = NULL;
+ m_pIBindCtx = NULL;
+ m_pIStorage = NULL;
+ *m_wszErrorMessage = L'\0';
+ m_dwTrackFlags = 0L;
+ m_hkeyLinkTracking = NULL;
+ m_hr = 0L;
+ m_bSuppressErrorMessages = FALSE;
+ m_pcDirectoryOriginal = NULL;
+ m_pcDirectoryFinal = NULL;
+
+ return;
+
+} // CMoniker::CMoniker()
+
+
+//+--------------------------------------------------------------------------
+//
+// Function: CMoniker::~CMoniker
+//
+// Synopsis: Release any COM objects.
+//
+// Inputs: N/A
+//
+// Outputs: N/A
+//
+// Effects: All COM objects are released.
+//
+//+--------------------------------------------------------------------------
+
+
+CMoniker::~CMoniker()
+{
+ if( m_pIMoniker )
+ {
+ m_pIMoniker->Release();
+ m_pIMoniker = NULL;
+ }
+
+ if( m_pIBindCtx )
+ {
+ m_pIBindCtx->Release();
+ m_pIBindCtx = NULL;
+ }
+
+ if( m_pIStorage )
+ {
+ m_pIStorage->Release();
+ m_pIStorage = NULL;
+ }
+
+ return;
+
+} // CMoniker::~CMoniker()
+
+
+//+-----------------------------------------------------------------------
+//
+// Function: CMoniker::Initialize
+//
+// Synopsis: Keep pointers to the CDirectory objects passed in.
+//
+// Inputs: A CDirectory object for the original link source file location
+// A CDirectory object for the final location
+//
+// Outputs: TRUE if successful, FALSE otherwise.
+//
+// Effects: The member CDirectory objects are set.
+//
+//+-----------------------------------------------------------------------
+
+
+BOOL CMoniker::Initialize( const CDirectory& cDirectoryOriginal,
+ const CDirectory& cDirectoryFinal )
+{
+ m_hr = S_OK;
+
+ m_pcDirectoryOriginal = &cDirectoryOriginal;
+ m_pcDirectoryFinal = &cDirectoryFinal;
+
+ return( TRUE ); // Success
+
+} // CMoniker::Initialize()
+
+
+//+-----------------------------------------------------------------------------
+//
+// Function: CMoniker::CreateFileMonikerEx
+//
+// Synopsis: Create a tracking file moniker. But before doing so, initialize
+// the Bind Context, and create a link source file.
+//
+// Inputs: Track Flags (from the TRACK_FLAGS defines)
+//
+// Outputs: TRUE if successful, FALSE otherwise.
+//
+// Effects: The member bind context is initialized, and a link
+// source file is created.
+//
+//+-----------------------------------------------------------------------------
+
+
+BOOL CMoniker::CreateFileMonikerEx( DWORD dwTrackFlags )
+{
+
+ // ---------------
+ // Local Variables
+ // ---------------
+
+ // Assume failure
+ BOOL bSuccess = FALSE;
+
+ // -----
+ // Begin
+ // -----
+
+ // Initialize the error code.
+
+ m_hr = S_OK;
+
+ // Free any existing IMoniker.
+
+ if( m_pIMoniker )
+ {
+ m_pIMoniker->Release();
+ m_pIMoniker = NULL;
+ }
+
+ // Initialize the bind context.
+
+ if( !InitializeBindContext() )
+ EXIT( L"Could not initialize the bind context" );
+
+ // Create a root storage for use as a link source.
+
+ if( !CreateTemporaryStorage() )
+ EXIT( L"Could not create temporary Storage" );
+
+ // Create a tracking File Moniker on that root storage.
+
+ m_hr = ::CreateFileMonikerEx( dwTrackFlags, m_wszTemporaryStorage, &m_pIMoniker );
+ EXIT_ON_FAILED( L"Failed CreateFileMonikerEx" );
+
+
+ bSuccess = TRUE;
+
+ // ----
+ // Exit
+ // ----
+
+Exit:
+
+ DisplayErrors( bSuccess, L"CMoniker::CreateFileMonikerEx" );
+ return( bSuccess );
+
+} // CMoniker::CreateFileMonikerEx()
+
+
+//+---------------------------------------------------------------------
+//
+// Function: CMoniker::SaveDeleteLoad
+//
+// Synopsis: This function exercises a moniker's IPersistStream interface.
+// It creates saves the member moniker's persistent state to
+// a stream, deletes the moniker, and then re-creates it
+// using CreateFileMoniker (no Ex, so it's not a tracking
+// file moniker). It then re-loads the original moniker's
+// persistent state.
+//
+// Inputs: None.
+//
+// Outputs: TRUE if successful, FALSE otherwise.
+//
+// Effects: The member moniker is deleted, re-created, and re-loaded.
+//
+//+---------------------------------------------------------------------
+
+
+BOOL CMoniker::SaveDeleteLoad()
+{
+ // ---------------
+ // Local Variables
+ // ---------------
+
+ // Assume failure
+ BOOL bSuccess = FALSE;
+ HRESULT hr = E_FAIL;
+
+ IStream* pStream = NULL;
+ IPersistStream* pIPersistStream = NULL;
+ LARGE_INTEGER li;
+ ULARGE_INTEGER uli;
+
+ // -----
+ // Begin
+ // -----
+
+ // Initialize the error code.
+
+ m_hr = S_OK;
+
+ // Verify that we have a member moniker.
+
+ if( !m_pIMoniker )
+ EXIT( L"Attempt to run SaveDeleteLoad test without an existing file moniker" );
+
+
+ // ------------------------
+ // Save the moniker's state
+ // ------------------------
+
+ // Get the moniker's IPersistStream interface
+
+ m_hr = m_pIMoniker->QueryInterface( IID_IPersistStream, (void **) &pIPersistStream );
+ EXIT_ON_FAILED( L"Failed 1st IMoniker::QueryInterface(IPersistStream)" );
+
+ // Create a stream
+
+ hr = CreateStreamOnHGlobal( NULL, // Auto alloc
+ TRUE, // Delete on release
+ &pStream );
+ EXIT_ON_FAILED( L"Failed CreateStreamOnHGlobal()" );
+
+ // Save the moniker's state to this stream.
+
+ hr = pIPersistStream->Save( pStream, TRUE /* Clear dirty*/ );
+ EXIT_ON_FAILED( L"Failed IPersistStream::Save()" );
+
+ // ------------------
+ // Delete the moniker
+ // ------------------
+
+ // Release all interfaces for the moniker.
+
+ m_pIMoniker->Release();
+ pIPersistStream->Release();
+
+ m_pIMoniker = NULL;
+ pIPersistStream = NULL;
+
+ // --------------------
+ // Create a new moniker
+ // --------------------
+
+ // Create a new moniker, using the non-Ex version of the function.
+
+ m_hr = ::CreateFileMoniker( m_wszTemporaryStorage, &m_pIMoniker );
+ EXIT_ON_FAILED( L"Failed CreateFileMoniker()" );
+
+ // --------------------
+ // Load the new moniker
+ // --------------------
+
+ // Get the IPersisStream interface
+
+ m_hr = m_pIMoniker->QueryInterface( IID_IPersistStream, (void **) &pIPersistStream );
+ EXIT_ON_FAILED( L"Failed 2nd IMoniker::QueryInterface(IPersistStream)" );
+
+ // Re-seek the stream to the beginning.
+
+ li.LowPart = li.HighPart = 0L;
+ hr = pStream->Seek( li, STREAM_SEEK_SET, &uli );
+ EXIT_ON_FAILED( L"Failed IStream::Seek()" );
+ if( uli.LowPart || uli.HighPart ) EXIT( L"Incorrect IStream::Seek()" );
+
+ // Re-load the moniker from the stream.
+
+ m_hr = pIPersistStream->Load( pStream );
+ EXIT_ON_FAILED( L"Failed IPersistStream::Load()" );
+
+
+ bSuccess = TRUE;
+
+ // ----
+ // Exit
+ // ----
+
+Exit:
+
+ // Clean up the stream and the IPersistStream interface.
+
+ if( pStream )
+ pStream->Release;
+
+ if( pIPersistStream )
+ pIPersistStream->Release();
+
+
+ DisplayErrors( bSuccess, L"CMoniker::SaveDeleteLoad()" );
+ return( bSuccess );
+
+} // CMoniker::SaveDeleteLoad()
+
+
+//+------------------------------------------------------------------
+//
+// Function: CMoniker::ComposeWith
+//
+// Synopsis: Compose a tracking moniker with a non-tracking moniker
+// on the right. (The resulting moniker should be tracking,
+// but this is not relevant to this function; that is, whether
+// or not the composed moniker is tracking, this function will
+// succeed.)
+//
+// Inputs: None.
+//
+// Output: TRUE if successful, FALSE otherwise.
+//
+// Effects: The member moniker is deleted, then recreated.
+//
+//+------------------------------------------------------------------
+
+BOOL CMoniker::ComposeWith()
+{
+
+ // ---------------
+ // Local Variables
+ // ---------------
+
+ BOOL bSuccess = FALSE;
+
+ IMoniker* pmkrFirst = NULL;
+ IMoniker* pmkrSecond = NULL;
+ HRESULT hr = E_FAIL;
+
+ WCHAR wszDirectoryName[ MAX_PATH + sizeof( L'\0' ) ];
+ WCHAR* wszFileName = NULL;
+
+ // -----
+ // Begin
+ // -----
+
+ // Initiailize the error code.
+
+ m_hr = S_OK;
+
+ // If we have a moniker already, delete it.
+
+ if( m_pIMoniker )
+ {
+ m_pIMoniker->Release();
+ m_pIMoniker = NULL;
+ }
+
+ // Verify we already have a link source file created.
+
+ if( !wcslen( m_wszTemporaryStorage ) )
+ EXIT( L"Attempt to use ComposeWith without first creating a link source.\n" );
+
+ // -----------------------------------------------
+ // Create a tracking and non-tracking file moniker
+ // -----------------------------------------------
+
+ // Parse the storage's filename into a path and a file ...
+ // for example, "C:\Temp\file.tmp" would become
+ // "C:\Temp" and "file.tmp".
+ //
+ // First, make a copy of the storage's complete path name,
+ // then replace the last '\\' with a '\0', thus creating two
+ // strings.
+
+ wcscpy( wszDirectoryName, m_wszTemporaryStorage );
+ wszFileName = wcsrchr( wszDirectoryName, L'\\' );
+ *wszFileName = L'\0';
+ wszFileName++;
+
+ // Create a tracking file moniker using the directory name.
+
+ m_hr = ::CreateFileMonikerEx( 0L, wszDirectoryName, &pmkrFirst );
+ EXIT_ON_FAILED( L"Failed 1st CreateFileMoniker()" );
+
+ // Create a non-tracking file moniker using the file name.
+
+ m_hr = ::CreateFileMoniker( wszFileName, &pmkrSecond );
+ EXIT_ON_FAILED( L"Failed 2nd CreateFileMoniker()" );
+
+ // -------
+ // Compose
+ // -------
+
+ // Compose the directory name moniker (on the left) with the file name moniker
+ // (on the right). Put the result in the member moniker.
+
+ m_hr = pmkrFirst->ComposeWith( pmkrSecond, TRUE, &m_pIMoniker );
+ EXIT_ON_FAILED( L"Failed IMoniker::ComposeWith" );
+
+
+ bSuccess = TRUE;
+
+ // ----
+ // Exit
+ // ----
+
+Exit:
+
+ // Clean up the intermediary monikers.
+
+ if( pmkrFirst )
+ pmkrFirst->Release();
+
+ if( pmkrSecond )
+ pmkrSecond->Release();
+
+ DisplayErrors( bSuccess, L"CMoniker::ComposeWith()" );
+ return( bSuccess );
+
+} // CMoniker::ComposeWith()
+
+
+//+--------------------------------------------------------------------
+//
+// Function: CMoniker::CreateTemporaryStorage
+//
+// Synopsis: This function creates a Structured Storage
+// in the directory identified by m_cDirectoryOriginal.
+// The name of the file is randomly generated by the system,
+// but begins with "MKR" and has the extension ".tmp".
+//
+// Inputs: None.
+//
+// Output: TRUE if successful, FALSE otherwise.
+//
+// Effects: Stores the Structure Storage's name in
+// m_wszTemporaryStorageName, and releases m_pIStorage if
+// it is currently set.
+//
+//+--------------------------------------------------------------------
+
+
+BOOL CMoniker::CreateTemporaryStorage()
+{
+ // ---------------
+ // Local Variables
+ // ---------------
+
+ BOOL bSuccess = FALSE;
+
+ DWORD dwError = 0L;
+ UINT nError = 0;
+
+
+ // -----
+ // Begin
+ // -----
+
+ m_hr = S_OK;
+
+ // Delete any existing storage.
+
+ if( wcslen( m_wszTemporaryStorage ))
+ {
+ if( !DeleteTemporaryStorage() )
+ EXIT( L"Could not delete the existing temporary storage" );
+ }
+
+ // Generate a temporary filename.
+
+ nError = GetTempFileName( m_pcDirectoryOriginal->GetDirectoryName(),
+ L"MKR", // Prefix string.
+ 0, // Generate random number,
+ m_wszTemporaryStorage );
+ if( nError == 0 )
+ {
+ m_hr = (HRESULT) GetLastError();
+ EXIT( L"Failed GetTempFileName()" );
+ }
+
+ // Create a root Storage.
+
+ m_hr = StgCreateDocfile( m_wszTemporaryStorage,
+ STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_DIRECT,
+ 0L, // Reserved
+ &m_pIStorage );
+ EXIT_ON_FAILED( L"Failed StgCreateDocfile()" );
+
+
+ // Release the storage.
+
+ m_pIStorage->Release();
+ m_pIStorage = NULL;
+
+ bSuccess = TRUE;
+
+ // ----
+ // Exit
+ // ----
+
+Exit:
+
+
+ DisplayErrors( bSuccess, L"CMoniker::CreateTemporaryStorage()" );
+ return( bSuccess );
+
+} // CMoniker::CreateTemporaryStorage()
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: CMoniker::RenameTemporaryStorage
+//
+// Synopsis: Rename the link source file (who's name is in m_wszTemporaryStorage)
+// to the m_cDirectoryFinal directory, with a new name.
+// The current name is "MKR#.tmp" (where "#" is a random number
+// generated by the system), and the new name is "RKM#.tmp" (where
+// "#" is the same random number). (We must rename the base file
+// name, rather than its extension, because otherwise the default
+// link-tracking would fail (it would only score the renamed file
+// a 32 - by matching the file extension the score is 40.)
+//
+// Inputs: None.
+//
+// Output: TRUE if successful, FALSE otherwise.
+//
+// Effects: The link source file is renamed, and it's new name is
+// put into m_wszTemporaryStorage.
+//
+//+-------------------------------------------------------------------------
+
+
+BOOL CMoniker::RenameTemporaryStorage()
+{
+ // ---------------
+ // Local Variables
+ // ---------------
+
+ BOOL bSuccess = FALSE;
+ int nError = 0;
+
+ WCHAR wszNewName[ MAX_PATH + sizeof( L'\0' ) ];
+ WCHAR* wszOldFileName;
+ WCHAR wszNewFileName[ MAX_PATH + sizeof( L'\0' ) ];
+
+ char szOldName[ MAX_PATH + sizeof( L'\0' ) ];
+ char szNewName[ MAX_PATH + sizeof( L'\0' ) ];
+
+
+ // -----
+ // Begin
+ // -----
+
+ m_hr = S_OK;
+
+ // Verify that we already have a link source created.
+
+ if( !wcslen( m_wszTemporaryStorage ))
+ EXIT( L"No temporary storage to rename." );
+
+ // Locate the file name within the complete path.
+ // (E.g., find the "foo.txt" in "C:\TEMP\foot.txt".)
+
+ wszOldFileName = wcsrchr( m_wszTemporaryStorage, L'\\' );
+ if( !wszOldFileName )
+ EXIT( L"Could not extract old file name from temporary storage name\n" );
+ wszOldFileName++; // Get past the '\\'
+
+ // Generate the new file name (change "MKR" to "RKM").
+
+ wcscpy( wszNewFileName, wszOldFileName );
+
+ wszNewFileName[0] = L'R';
+ wszNewFileName[1] = L'K';
+ wszNewFileName[2] = L'M';
+
+ // Generate the complete path spec of the new file.
+
+ wcscpy( wszNewName, m_pcDirectoryFinal->GetDirectoryName() );
+ wcscat( wszNewName, wszNewFileName );
+
+
+ // Convert the new and old file names to ANSI.
+
+ if( m_hr = UnicodeToAnsi( m_wszTemporaryStorage, szOldName, sizeof( szOldName )) )
+ {
+ EXIT( L"Could not convert convert Unicode to Ansi for old name" );
+ }
+
+ if( m_hr = UnicodeToAnsi( wszNewName, szNewName, sizeof( szNewName )) )
+ {
+ EXIT( L"Could not convert convert Unicode to Ansi for new name" );
+ }
+
+
+ // Rename the file.
+
+ nError = rename( szOldName, szNewName );
+ if( nError )
+ {
+ m_hr = (HRESULT) errno;
+ EXIT( L"Failed rename()" );
+ }
+
+ // Record the new name.
+
+ wcscpy( m_wszTemporaryStorage, wszNewName );
+
+
+ bSuccess = TRUE;
+
+ // ----
+ // Exit
+ // ----
+
+Exit:
+
+ DisplayErrors( bSuccess, L"CMoniker::RenameTemporaryStorage()" );
+ return( bSuccess );
+
+} // CMoniker::RenameTemporaryStorage()
+
+
+//+--------------------------------------------------------------------
+//
+// Function: CMoniker::DeleteTemporaryStorage
+//
+// Synopsis: Delete the temporary storage that this object uses
+// as a link source for the moniker. The name of the
+// storage is in m_wszTemporaryStorage.
+//
+// Inputs: None.
+//
+// Output: TRUE if successful, FALSE otherwise.
+//
+// Effects: The link source file is deleted, and m_wszTemporaryStorage
+// is set to a NULL string.
+//
+//+--------------------------------------------------------------------
+
+
+BOOL CMoniker::DeleteTemporaryStorage()
+{
+ // ---------------
+ // Local Variables
+ // ---------------
+
+ BOOL bSuccess = FALSE;
+
+ int nError = 0;
+ CHAR szTemporaryStorage[ MAX_PATH + sizeof( '\0' ) ];
+
+ // -----
+ // Begin
+ // -----
+
+ m_hr = S_OK;
+
+ // Don't do anything if we have no file (don't report an
+ // error either; the caller wants the file deleted, and it's
+ // already not there).
+
+ if( wcslen( m_wszTemporaryStorage ))
+ {
+
+ // Get the file name in ANSI.
+
+ if( m_hr = UnicodeToAnsi( m_wszTemporaryStorage, szTemporaryStorage, sizeof( szTemporaryStorage )))
+ EXIT( L"Could not convert unicode path to ANSI path" );
+
+ // Delete the file.
+
+ nError = unlink( szTemporaryStorage );
+ if( nError )
+ {
+ m_hr = (HRESULT) errno;
+ EXIT( L"Failed unlink()" );
+ }
+
+ // Clear the file name.
+
+ wcscpy( m_wszTemporaryStorage, L"" );
+ }
+
+ bSuccess = TRUE;
+
+ // ----
+ // Exit
+ // ----
+
+Exit:
+
+ DisplayErrors( bSuccess, L"CMoniker::DeleteTemporaryStorage()" );
+ return( bSuccess );
+
+} // CMoniker::DeleteTemporaryStorage()
+
+
+
+
+//+-----------------------------------------------------------------
+//
+// Function: CMoniker::Reduce
+//
+// Synopsis: Perform a IMoniker::Reduce on the member moniker.
+//
+// Inputs: - Number of ticks until the deadline for completion of
+// the operation.
+// - A buffer into which to put the reduced IMoniker*
+// (may be NULL).
+//
+// Output: TRUE if successful, FALSE otherwise.
+//
+// Effects: None.
+//
+//+-----------------------------------------------------------------
+
+
+BOOL CMoniker::Reduce( DWORD dwDelay, IMoniker** ppmkReturn )
+{
+ // ---------------
+ // Local Variables
+ // ---------------
+
+ BOOL bSuccess = FALSE;
+ IMoniker* pmkReduced = NULL;
+ BIND_OPTS2 bind_opts;
+ bind_opts.cbStruct = sizeof( BIND_OPTS2 );
+
+ // -----
+ // Begin
+ // -----
+
+ m_hr = S_OK;
+
+ // ----------
+ // Initialize
+ // ----------
+
+ // Initialize the return buffer, if extant.
+
+ if( ppmkReturn )
+ *ppmkReturn = NULL;
+
+ // Validate our state.
+
+ if( !m_pIMoniker )
+ EXIT( L"No moniker exists to be reduced" );
+
+ // ----------------
+ // Set the deadline
+ // ----------------
+
+ // Get the BIND_OPTS from the bind context.
+
+ m_hr = m_pIBindCtx->GetBindOptions( (LPBIND_OPTS) &bind_opts );
+ EXIT_ON_FAILED( L"Failed IBindCtx::GetBindOptions" );
+
+ // Determine what the tick count of the deadline is.
+
+ if( dwDelay == INFINITE )
+ {
+ bind_opts.dwTickCountDeadline = 0;
+ }
+ else
+ {
+ bind_opts.dwTickCountDeadline = GetTickCount() + dwDelay;
+
+ // Make sure the resulting tick count is not 0 (indicating no
+ // deadline).
+
+ if( bind_opts.dwTickCountDeadline == 0 )
+ bind_opts.dwTickCountDeadline++;
+ }
+
+ // Put the resulting BIND_OPTS back into the bind context.
+
+ m_hr = m_pIBindCtx->SetBindOptions( (LPBIND_OPTS) &bind_opts );
+ EXIT_ON_FAILED( L"Failed IBindCtx::SetBindOptions" );
+
+
+ // ------------------
+ // Reduce the Moniker
+ // ------------------
+
+ m_hr = m_pIMoniker->Reduce( m_pIBindCtx,
+ MKRREDUCE_ALL,
+ NULL,
+ &pmkReduced );
+ EXIT_ON_FAILED( L"Failed IMoniker::Reduce" );
+
+ // Return the reduced moniker to the caller (if so requested).
+
+ if( ppmkReturn )
+ {
+ // Transfer responsibility for the release to the caller.
+ *ppmkReturn = pmkReduced;
+ pmkReduced = NULL;
+ }
+
+ bSuccess = TRUE;
+
+ // ----
+ // Exit
+ // ----
+
+Exit:
+
+ DisplayErrors( bSuccess, L"CMoniker::Reduce()" );
+
+ if( pmkReduced )
+ pmkReduced->Release();
+
+ return( bSuccess );
+
+} // CMoniker::Reduce()
+
+
+
+//+----------------------------------------------------------------------
+//
+// Function: CMoniker::GetDisplayName
+//
+// Synopsis: Get the moniker's display name.
+//
+// Inputs: A Unicode buffer for the display name, and (optionally)
+// a moniker from which to get the display name. If such
+// a moniker is not provided by the caller, then the member
+// moniker is used.
+//
+// The unicode buffer must be long enough for MAX_PATH characters
+// and a terminating NULL.
+//
+// Outputs: TRUE if successful, FALSE otherwise.
+//
+// Effects: None.
+//
+//+----------------------------------------------------------------------
+
+
+BOOL CMoniker::GetDisplayName( WCHAR * wszDisplayName, IMoniker* pmnkCaller )
+{
+ // ---------------
+ // Local Variables
+ // ---------------
+
+ BOOL bSuccess = FALSE;
+
+ WCHAR* wszReturnedDisplayName = NULL;
+ IMoniker* pmnk = NULL;
+
+ // -----
+ // Begin
+ // -----
+
+ m_hr = NOERROR;
+
+ // Determine which moniker to use, the caller-specified one or
+ // the member one.
+
+ if( pmnkCaller != NULL )
+ pmnk = pmnkCaller;
+ else
+ pmnk = m_pIMoniker;
+
+ if( !pmnk )
+ EXIT( L"Attempt to GetDisplayName on NULL moniker" );
+
+ // Get the display name from the moniker.
+
+ m_hr = pmnk->GetDisplayName( m_pIBindCtx,
+ NULL,
+ &wszReturnedDisplayName );
+ EXIT_ON_FAILED( L"Failed IMoniker::GetDisplayName()" );
+
+ if( wcslen( wszReturnedDisplayName ) > MAX_UNICODE_PATH )
+ EXIT( L"IMoniker::GetDisplayName() returned a path which was too long" );
+
+ // Copy the display name into the caller's buffer, and free it.
+
+ wcscpy( wszDisplayName, wszReturnedDisplayName );
+
+
+ bSuccess = TRUE;
+
+ // ----
+ // Exit
+ // ----
+
+Exit:
+
+ if( wszReturnedDisplayName )
+ {
+ CoTaskMemFree( wszReturnedDisplayName );
+ wszReturnedDisplayName = NULL;
+ }
+
+ DisplayErrors( bSuccess, L"CMoniker::GetDisplayName()" );
+ return( bSuccess );
+
+} // CMoniker::GetDisplayName()
+
+
+//+-------------------------------------------------------------
+//
+// Function: CMoniker::InitializeBindContext
+//
+// Synopsis: Create a new bind context, and store it
+// in a member pointer.
+//
+// Inputs: None.
+//
+// Output: TRUE if successful, FALSE otherwise.
+//
+// Effects: Updates m_pIBindCtx.
+//
+//+-------------------------------------------------------------
+
+
+
+BOOL CMoniker::InitializeBindContext( )
+{
+ // ---------------
+ // Local Variables
+ // ---------------
+
+ BOOL bSuccess = FALSE;
+
+ // -----
+ // Begin
+ // -----
+
+ m_hr = S_OK;
+
+ // Release the old bind context if we have one.
+
+ if( m_pIBindCtx )
+ m_pIBindCtx->Release();
+
+ // Create the new bind context.
+
+ m_hr = CreateBindCtx( 0L, &m_pIBindCtx );
+ EXIT_ON_FAILED( L"Failed CreateBindCtx()" );
+
+
+ bSuccess = TRUE;
+
+ // ----
+ // Exit
+ // ----
+
+Exit:
+
+ DisplayErrors( bSuccess, L"CMoniker::InitializeBindContext()" );
+ return( bSuccess );
+
+} // CMoniker::InitializeBindContext()
+
+
+//+----------------------------------------------------------------
+//
+// Function: CMoniker::GetTimeOfLastChange
+//
+// Synopsis: Request the time-of-last-change from our member
+// moniker.
+//
+// Inputs: A buffer into which to put the FILETIME.
+//
+// Output: TRUE if successful, FALSE otherwise.
+//
+// Effects: None.
+//
+//+----------------------------------------------------------------
+
+
+BOOL CMoniker::GetTimeOfLastChange( FILETIME* pft )
+{
+ // ---------------
+ // Local Variables
+ // ---------------
+
+ BOOL bSuccess = FALSE;
+
+ // -----
+ // Begin
+ // -----
+
+ m_hr = S_OK;
+
+ // Validate our state.
+
+ if( !m_pIMoniker )
+ EXIT( L"Cannot GetTimeOfLastChange on a NULL moniker" );
+
+ // Get the time from the moniker.
+
+ m_hr = m_pIMoniker->GetTimeOfLastChange( m_pIBindCtx,
+ NULL,
+ pft );
+ EXIT_ON_FAILED( L"Failed IMoniker::GetTimeOfLastChange()" );
+
+
+ bSuccess = TRUE;
+
+ // ----
+ // Exit
+ // ----
+
+Exit:
+
+ DisplayErrors( bSuccess, L"CMoniker::GetTimeOfLastChange()" );
+ return( bSuccess );
+
+} // CMoniker::GetTimeOfLastChange()
+
+
+
+//+------------------------------------------------------------------------
+//
+// Function: CMoniker::BindToStorage
+//
+// Synopsis: Bind our member moniker to its Structured Storage object.
+//
+// Inputs: None.
+//
+// Outputs: TRUE if successful, FALSE otherwise.
+//
+// Effects: None.
+//
+//+------------------------------------------------------------------------
+
+
+BOOL CMoniker::BindToStorage()
+{
+ // ---------------
+ // Local Variables
+ // ---------------
+
+ BOOL bSuccess = FALSE;
+ BIND_OPTS2 bind_opts;
+ bind_opts.cbStruct = sizeof( BIND_OPTS2 );
+
+ // -----
+ // Begin
+ // -----
+
+ m_hr = S_OK;
+
+ // Validate our state.
+
+ if( !m_pIMoniker )
+ EXIT( L"Cannot GetTimeOfLastChange on a NULL moniker" );
+
+ // Release the IStorage interface if we have one.
+
+ if( m_pIStorage )
+ {
+ m_pIStorage->Release();
+ m_pIStorage = NULL;
+ }
+
+ // Get the bind_opts and set the flags for StgOpenStorage.
+
+ m_hr = m_pIBindCtx->GetBindOptions( (LPBIND_OPTS) &bind_opts );
+ EXIT_ON_FAILED( L"Failed IBindCtx::GetBindOptions" );
+
+ bind_opts.grfMode = STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_DIRECT;
+
+ m_hr = m_pIBindCtx->SetBindOptions( (LPBIND_OPTS) &bind_opts );
+ EXIT_ON_FAILED( L"Failed IBindCtx::SetBindOptions" );
+
+
+ // Bind to the storage.
+
+ m_hr = m_pIMoniker->BindToStorage( m_pIBindCtx,
+ NULL,
+ IID_IStorage,
+ (void **) &m_pIStorage );
+ EXIT_ON_FAILED( L"Failed IMoniker::BindToStorage()" );
+
+
+ bSuccess = TRUE;
+
+ // ----
+ // Exit
+ // ----
+
+Exit:
+
+ // Release the Storage if we got it.
+
+ if( m_pIStorage )
+ {
+ m_pIStorage->Release();
+ m_pIStorage = NULL;
+ }
+
+ DisplayErrors( bSuccess, L"CMoniker::BindToStorage()" );
+ return( bSuccess );
+
+} // CMoniker::BindToStorage()
+
+
+//+-------------------------------------------------------------------
+//
+// Function: CMoniker::BindToObject
+//
+// Synopsis: Bind to our member moniker's object.
+//
+// Inputs: None.
+//
+// Outputs: TRUE if successful, FALSE otherwise.
+//
+// Effects: None.
+//
+// Notes: Since the member moniker represents a storage with no
+// associated server, BindToObject will fail. We will
+// consider it a success if the failure is do to an
+// object-related problem, rather than a Storage-related
+// problem.
+//
+//+-------------------------------------------------------------------
+
+BOOL CMoniker::BindToObject()
+{
+ // ---------------
+ // Local Variables
+ // ---------------
+
+ BOOL bSuccess = FALSE;
+ IUnknown* pUnk = NULL;
+
+ // -----
+ // Begin
+ // -----
+
+ m_hr = S_OK;
+
+ // Validate our state.
+
+ if( !m_pIMoniker )
+ EXIT( L"Cannot bind to an object with a NULL moniker" );
+
+ // Bind to the object.
+
+ m_hr = m_pIMoniker->BindToObject( m_pIBindCtx,
+ NULL,
+ IID_IUnknown,
+ (void **) &pUnk );
+
+ // If the bind succeeded, or failed for a valid reason,
+ // then return Success to the caller.
+
+ if( SUCCEEDED( m_hr )
+ ||
+ ( m_hr = MK_E_INVALIDEXTENSION ) // No handler for ".tmp" files.
+ )
+ {
+ bSuccess = TRUE;
+ }
+ else
+ {
+ EXIT( L"Failed BindToObject" );
+ }
+
+ // ----
+ // Exit
+ // ----
+
+Exit:
+
+ // If we got an IUnknown interface on the Bind, release it.
+
+ if( pUnk )
+ {
+ pUnk->Release();
+ pUnk = NULL;
+ }
+
+ DisplayErrors( bSuccess, L"CMoniker::BindToObject()" );
+ return( bSuccess );
+
+} // CMoniker::BindToObject()
+
+
+//+-------------------------------------------------------------------
+//
+// Function: CMoniker::GetTemporaryStorageTime
+//
+// Synopsis: Get the time from the link source file
+// (identified by m_wszTemporaryStorage).
+//
+// Inputs: A buffer in which to put the FILETIME structure.
+//
+// Outputs: TRUE if successful, FALSE otherwise.
+//
+// Effects: None.
+//
+//+-------------------------------------------------------------------
+
+
+BOOL CMoniker::GetTemporaryStorageTime( FILETIME * pft)
+{
+ // ---------------
+ // Local Variables
+ // ---------------
+
+ BOOL bSuccess = FALSE;
+ HANDLE hFile = NULL;
+
+ // -----
+ // Begin
+ // -----
+
+ m_hr = NOERROR;
+
+ // Get a handle to the file.
+
+ hFile = CreateFile( m_wszTemporaryStorage, // File name
+ GENERIC_READ, // Desired access
+ FILE_SHARE_READ, // Share mode
+ NULL, // Security attributes
+ OPEN_EXISTING, // Creation distribution
+ 0L, // Flags & Attributes
+ NULL ); // hTemplateFile
+ if( hFile == NULL )
+ {
+ m_hr = (HRESULT) GetLastError();
+ EXIT( L"Failed call to CreateFile()" );
+ }
+
+ // Get the time on the file.
+
+ if( !GetFileTime( hFile, // File to check
+ NULL, // Create Time
+ NULL, // Access Time
+ pft ) // Write Time
+ )
+ {
+ m_hr = (HRESULT) GetLastError();
+ EXIT( L"Failed call to GetFileTime()" );
+ }
+
+ bSuccess = TRUE;
+
+ // ----
+ // Exit
+ // ----
+
+Exit:
+
+ // Close the file if we opened it.
+
+ if( hFile )
+ {
+ CloseHandle( hFile );
+ hFile = NULL;
+ }
+
+
+ DisplayErrors( bSuccess, L"CMoniker::GetTemporaryStorageTime()" );
+ return( bSuccess );
+
+} // CMoniker::GetTemporaryStorageTime()
+
+
+//+------------------------------------------------------------------------
+//
+// Function: CMoniker::TouchTemporaryStorage
+//
+// Synopsis: Set the Access time on the link source file.
+//
+// Inputs: None.
+//
+// Output: TRUE if successful, FALSE otherwise.
+//
+// Effects: The link source file (identified by m_wszTemporaryStorage)
+// has its Access time set to the current time.
+//
+//+------------------------------------------------------------------------
+
+
+BOOL CMoniker::TouchTemporaryStorage( )
+{
+ // ---------------
+ // Local Variables
+ // ---------------
+
+ BOOL bSuccess = FALSE;
+ HANDLE hFile = NULL;
+ STATSTG statStorage;
+ FILETIME ftNow;
+
+ // -----
+ // Begin
+ // -----
+
+ m_hr = NOERROR;
+
+ // Open the root Storage.
+
+ m_hr = StgOpenStorage( m_wszTemporaryStorage,
+ NULL,
+ STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_DIRECT,
+ NULL,
+ 0L,
+ &m_pIStorage );
+ EXIT_ON_FAILED( L"Failed StgOpenStorage()" );
+
+ // Get the current time.
+
+ m_hr = CoFileTimeNow( &ftNow );
+ EXIT_ON_FAILED( L"Failed CoFileTimeNow()" );
+
+ // Set the access time
+
+ m_pIStorage->SetElementTimes( NULL, // Set the storage itself
+ NULL, // Create time
+ NULL, // Access time
+ &ftNow );
+ EXIT_ON_FAILED( L"Failed IStorage::SetTimes()" );
+
+
+ bSuccess = TRUE;
+
+ // ----
+ // Exit
+ // ----
+
+Exit:
+
+ // If we got the storage, release it.
+
+ if( m_pIStorage )
+ {
+ m_pIStorage->Release();
+ m_pIStorage = NULL;
+ }
+
+ DisplayErrors( bSuccess, L"CMoniker::TouchTemporaryStorage()" );
+ return( bSuccess );
+
+} // CMoniker::TouchTemporaryStorage()
+
+
+
+#ifdef _FUTURE_
+
+/*
+BOOL CMoniker::OpenLinkTrackingRegistryKey()
+{
+
+ BOOL bSuccess = FALSE;
+ DWORD dwDisposition = 0L;
+ long lResult = 0L;
+
+ m_hr = S_OK;
+
+ lResult = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
+ OLETRACKING_KEY,
+ 0L,
+ KEY_ALL_ACCESS,
+ &m_hkeyLinkTracking
+ );
+
+ if( lResult != ERROR_SUCCESS
+ &&
+ lResult != ERROR_FILE_NOT_FOUND
+ )
+ {
+ m_hr = (HRESULT) lResult;
+ EXIT( L"Failed RegOpenKeyEx()" );
+ }
+
+
+ bSuccess = TRUE;
+
+Exit:
+
+ DisplayErrors( bSuccess, L"CMoniker::OpenLinkTrackingRegistryKey()" );
+ return( bSuccess );
+
+
+} // CMoniker::OpenLinkTrackingRegistryKey()
+
+
+BOOL CMoniker::CreateLinkTrackingRegistryKey()
+{
+
+ BOOL bSuccess = FALSE;
+ HKEY hkey = NULL;
+ DWORD dwDisposition = 0L;
+ long lResult = 0L;
+
+ m_hr = S_OK;
+
+ if( m_hkeyLinkTracking )
+ CloseLinkTrackingRegistryKey();
+
+ lResult = RegCreateKeyEx( HKEY_LOCAL_MACHINE,
+ OLETRACKING_KEY,
+ 0L,
+ NULL,
+ REG_OPTION_NON_VOLATILE,
+ KEY_ALL_ACCESS,
+ NULL,
+ &m_hkeyLinkTracking,
+ &dwDisposition
+ );
+
+ if( lResult != ERROR_SUCCESS )
+ {
+ m_hr = (HRESULT) lResult;
+ EXIT( L"Failed RegCreateKeyEx()" );
+ }
+
+ bSuccess = TRUE;
+
+Exit:
+
+ DisplayErrors( bSuccess, L"CMoniker::CreateLinkTrackingRegistryKey()" );
+ return( bSuccess );
+
+} // CMoniker::CreateLinkTrackingRegistryKey()
+
+
+
+BOOL CMoniker::CloseLinkTrackingRegistryKey()
+{
+ m_hr = S_OK;
+
+ if( m_hkeyLinkTracking )
+ RegCloseKey( m_hkeyLinkTracking );
+
+ m_hkeyLinkTracking = NULL;
+
+ return TRUE;
+
+} // CMoniker::CloseLinkTrackingRegistryKey()
+
+
+
+BOOL CMoniker::SaveRegistryTrackFlags()
+{
+ BOOL bSuccess = FALSE;
+
+ long lResult = 0L;
+ DWORD dwType = 0L;
+ DWORD dwcbData = sizeof( m_dwTrackFlags );
+
+
+ m_hr = S_OK;
+
+ if( !OpenLinkTrackingRegistryKey() )
+ EXIT( L"Could not open the registry" );
+
+ lResult = RegQueryValueEx( m_hkeyLinkTracking,
+ OLETRACKING_FILEMONIKER_VALUE,
+ NULL,
+ &dwType,
+ (LPBYTE) &m_dwTrackFlags,
+ &dwcbData );
+
+ if( lResult != ERROR_SUCCESS )
+ {
+ CloseLinkTrackingRegistryKey();
+
+ if( lResult != ERROR_FILE_NOT_FOUND )
+ {
+ m_hr = (HRESULT) lResult;
+ EXIT( L"Failed RegQueryValueEx()" );
+ }
+ }
+
+
+ bSuccess = TRUE;
+
+Exit:
+
+ DisplayErrors( bSuccess, L"CMoniker::SaveRegistryTrackFlags()" );
+ return( bSuccess );
+
+} // CMoniker::SaveRegistryTrackFlags()
+
+
+
+BOOL CMoniker::DeleteRegistryTrackFlags()
+{
+ BOOL bSuccess = FALSE;
+
+ long lResult = 0L;
+ DWORD dwType = 0L;
+ DWORD dwcbData = sizeof( m_dwTrackFlags );
+
+
+ m_hr = S_OK;
+
+ if( !CreateLinkTrackingRegistryKey() )
+ EXIT( L"Could not open the registry" );
+
+
+ lResult = RegDeleteValue( m_hkeyLinkTracking,
+ OLETRACKING_FILEMONIKER_VALUE );
+
+
+ if( lResult != ERROR_SUCCESS
+ &&
+ lResult != ERROR_FILE_NOT_FOUND
+ )
+ {
+ if( lResult != ERROR_FILE_NOT_FOUND )
+ {
+ m_hr = (HRESULT) lResult;
+ EXIT( L"Failed RegDeleteValue()" );
+ }
+ }
+
+ bSuccess = TRUE;
+
+Exit:
+
+ CloseLinkTrackingRegistryKey();
+
+ DisplayErrors( bSuccess, L"CMoniker::DeleteRegistryTrackFlags()" );
+ return( bSuccess );
+
+} // CMoniker::DeleteRegistryTrackFlags()
+
+
+
+BOOL CMoniker::RestoreRegistryTrackFlags()
+{
+ BOOL bSuccess = FALSE;
+ long lResult = 0L;
+
+
+ m_hr = S_OK;
+
+ // If the registry key doesn't exist, then there's no flags
+ // to restore.
+
+ if( m_hkeyLinkTracking )
+ {
+
+ lResult = RegSetValueEx( m_hkeyLinkTracking,
+ OLETRACKING_FILEMONIKER_VALUE,
+ 0L,
+ REG_DWORD,
+ (LPBYTE) &m_dwTrackFlags,
+ sizeof( m_dwTrackFlags )
+ );
+
+ if( lResult != ERROR_SUCCESS )
+ {
+ m_hr = (HRESULT) lResult;
+ EXIT( L"Failed RegSetValueEx()" );
+ }
+
+ CloseLinkTrackingRegistryKey();
+
+ }
+
+
+ bSuccess = TRUE;
+
+Exit:
+
+ DisplayErrors( bSuccess, L"CMoniker::RestoreRegistryTrackFlags()" );
+ return( bSuccess );
+
+} // CMoniker::RestoreRegistryTrackFlags()
+
+CMoniker::SetTrackFlagsInRegistry( DWORD dwTrackFlags )
+{
+ BOOL bSuccess = FALSE;
+ long lResult = 0L;
+ HKEY hkey = NULL;
+
+
+ m_hr = S_OK;
+
+ if( !CreateLinkTrackingRegistryKey() )
+ EXIT( L"Could not create registry key" );
+
+ lResult = RegSetValueEx( m_hkeyLinkTracking,
+ OLETRACKING_FILEMONIKER_VALUE,
+ 0L,
+ REG_DWORD,
+ (LPBYTE) &dwTrackFlags,
+ sizeof( dwTrackFlags )
+ );
+
+ if( lResult != ERROR_SUCCESS )
+ {
+ m_hr = (HRESULT) lResult;
+ EXIT( L"Failed RegSetValueEx()" );
+ }
+
+
+ bSuccess = TRUE;
+
+Exit:
+
+ DisplayErrors( bSuccess, L"CMoniker::SetTrackFlagsInRegistry()" );
+ return( bSuccess );
+
+} // CMoniker::SetTrackFlagsInRegistry()
+
+
+BOOL CMoniker::CreateFileMoniker()
+{
+
+ BOOL bSuccess = FALSE;
+
+ m_hr = S_OK;
+
+ // Free any existing IMoniker.
+
+ if( m_pIMoniker )
+ {
+ m_pIMoniker->Release();
+ m_pIMoniker = NULL;
+ }
+
+ // Create a root storage.
+
+ if( !CreateTemporaryStorage() )
+ EXIT( L"Could not create a temporary storage" );
+
+ // Create a default File Moniker on that root storage.
+
+ m_hr = ::CreateFileMoniker( m_wszTemporaryStorage, &m_pIMoniker );
+ EXIT_ON_FAILED( L"Failed CreateFileMoniker" );
+
+
+ bSuccess = TRUE;
+
+
+Exit:
+
+ DisplayErrors( bSuccess, L"CMoniker::CreateFileMoniker" );
+ return( bSuccess );
+
+} // CMoniker::CreateFileMoniker()
+*/
+#endif // _FUTURE_
diff --git a/private/oleutest/cfmex/cmoniker.hxx b/private/oleutest/cfmex/cmoniker.hxx
new file mode 100644
index 000000000..7d9e1ada0
--- /dev/null
+++ b/private/oleutest/cfmex/cmoniker.hxx
@@ -0,0 +1,178 @@
+
+
+//+================================================================
+//
+// File: CMoniker.hxx
+//
+// Purpose: This file declares the CMoniker class.
+// This class manages a file moniker.
+//
+//+================================================================
+
+
+#ifndef _C_MONIKER_HXX_
+#define _C_MONIKER_HXX_
+
+
+// --------
+// Includes
+// --------
+
+#include "CDir.hxx"
+
+// --------
+// CMoniker
+// --------
+
+class CMoniker
+{
+
+// (De)Construction
+
+public:
+
+ CMoniker();
+ ~CMoniker();
+
+// Public member routines.
+
+public:
+
+ BOOL GetTemporaryStorageTime( FILETIME *);
+ BOOL Initialize( const CDirectory& cDirectoryOriginal,
+ const CDirectory& cDirectoryFinal );
+ BOOL CreateFileMonikerEx( DWORD dwTrackFlags = 0L );
+ BOOL SaveDeleteLoad();
+ BOOL ComposeWith();
+ BOOL Reduce( DWORD dwDelay, IMoniker** ppmkReduced = NULL );
+ BOOL GetDisplayName( WCHAR * wszDisplayName, IMoniker* pmnkCaller = NULL );
+ BOOL GetTimeOfLastChange( FILETIME *ft );
+ BOOL BindToStorage();
+ BOOL BindToObject();
+
+ BOOL CreateTemporaryStorage();
+ BOOL RenameTemporaryStorage();
+ BOOL DeleteTemporaryStorage();
+
+ const WCHAR * GetTemporaryStorageName() const;
+ IBindCtx* GetBindCtx() const;
+ BOOL TouchTemporaryStorage();
+ HRESULT GetHResult() const;
+ void SuppressErrorMessages( BOOL bSuppress );
+ BOOL InitializeBindContext( );
+
+
+// Private member routines.
+
+private:
+
+ BOOL CreateLinkTrackingRegistryKey();
+ BOOL OpenLinkTrackingRegistryKey();
+ BOOL CloseLinkTrackingRegistryKey();
+ void DisplayErrors( BOOL bSuccess, WCHAR * wszFunctionName ) const;
+
+
+// Private data members
+
+private:
+
+ WCHAR m_wszSystemTempPath[ MAX_PATH + sizeof( L'\0' ) ];
+ WCHAR m_wszTemporaryStorage[ MAX_PATH + sizeof( L'\0' ) ];
+
+ IMoniker* m_pIMoniker;
+ IBindCtx* m_pIBindCtx;
+ IStorage* m_pIStorage;
+
+ WCHAR m_wszErrorMessage[ 100 ];
+ DWORD m_dwTrackFlags;
+ BOOL m_bSuppressErrorMessages;
+
+ const CDirectory* m_pcDirectoryOriginal;
+ const CDirectory* m_pcDirectoryFinal;
+
+ // The following key, along with being a usable handle, is a flag
+ // which indicates if we need to restore the data in the registry.
+
+ HKEY m_hkeyLinkTracking;
+
+
+ // Note that m_hr is used for more than just HRESULTs, sometimes
+ // it is used for other errors as well.
+
+ HRESULT m_hr;
+
+};
+
+
+// --------------
+// Inline Members
+// --------------
+
+#define OUTFILE stdout
+
+// CMoniker::DisplayErrors
+
+inline void CMoniker::DisplayErrors( BOOL bSuccess, WCHAR * wszFunctionName ) const
+{
+ if( !bSuccess
+ &&
+ !m_bSuppressErrorMessages
+ )
+ {
+ fwprintf( OUTFILE, L"Error in %s (%08x)\n %s\n",
+ wszFunctionName, m_hr, m_wszErrorMessage );
+ }
+}
+
+// CMoniker::GetTemporaryStorage
+
+inline const WCHAR * CMoniker::GetTemporaryStorageName() const
+{
+ return m_wszTemporaryStorage;
+}
+
+// CMoniker::GetBindCtx
+
+inline IBindCtx* CMoniker::GetBindCtx() const
+{
+ return( m_pIBindCtx );
+}
+
+// CMoniker::GetHResult
+
+inline HRESULT CMoniker::GetHResult() const
+{
+ return( m_hr );
+}
+
+// CMoniker::SuppressErrorMessages
+
+inline void CMoniker::SuppressErrorMessages( BOOL bSuppress )
+{
+ // Normalize to TRUE or FALSE
+
+ m_bSuppressErrorMessages = bSuppress ? TRUE : FALSE;
+}
+
+
+// ------
+// Macros
+// ------
+
+#define DEFAULT_TRACK_FLAGS ( TRACK_LOCALONLY )
+
+#define EXIT_ON_FAILED( error ) if( FAILED( m_hr )) \
+ {\
+ wcscpy( m_wszErrorMessage, ##error );\
+ goto Exit;\
+ }
+
+#undef EXIT
+#define EXIT( error ) \
+ {\
+ wcscpy( m_wszErrorMessage, ##error );\
+ goto Exit;\
+ }
+
+
+#endif // _C_MONIKER_HXX_
diff --git a/private/oleutest/cfmex/ctest.cxx b/private/oleutest/cfmex/ctest.cxx
new file mode 100644
index 000000000..e2de08c3c
--- /dev/null
+++ b/private/oleutest/cfmex/ctest.cxx
@@ -0,0 +1,1283 @@
+
+
+//+=======================================================================
+//
+// File: CTest.cxx
+//
+// Purpose: Define the CTest class.
+//
+// This class is the test engine for the CreateFileMonikerEx
+// (CFMEx) DRTs. All interactions with monikers are handled
+// through the CMoniker class.
+//
+//+=======================================================================
+
+
+// -------------
+// Include Files
+// -------------
+
+#define _DCOM_ // Allow DCOM extensions (e.g., CoInitializeEx).
+
+#include <windows.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <wchar.h>
+#include <wtypes.h>
+#include <oaidl.h>
+#include <dsys.h>
+#include <olecairo.h>
+#include "CDir.hxx"
+#include "CMoniker.hxx"
+#include "CTest.hxx"
+
+
+//+------------------------------------------------------------------------
+//
+// Function: CTest::CTest
+//
+// Synopsis: Inititialize member variables.
+//
+// Inputs: None.
+//
+// Outputs: N/A
+//
+// Effects: All members are initialized/defaulted.
+//
+//+------------------------------------------------------------------------
+
+
+CTest::CTest( )
+{
+
+ m_lError = 0L;
+ *m_wszErrorMessage = L'\0';
+
+ m_pcDirectoryOriginal = NULL;
+ m_pcDirectoryFinal = NULL;
+
+} // CTest::CTest
+
+//+------------------------------------------------------------------------------
+//
+// Function: CTest::~CTest
+//
+// Synopsis: No action.
+//
+// Inputs: N/A
+//
+// Outputs: N/A
+//
+// Effects: None.
+//
+//+------------------------------------------------------------------------------
+
+
+CTest::~CTest()
+{
+} // CTest::~CTest
+
+
+//+-------------------------------------------------------------------------------
+//
+// Function: CTest::Initialize
+//
+// Synopsis: Inititialize a CTest object.
+//
+// Inputs: CDirectory objects representing the original and final
+// locations of a link source file. The original location
+// is used in CreateTemporaryStorage(), and the final location
+// is used in RenameTemporaryStorage().
+//
+// Outputs: TRUE if successful, FALSE otherwise.
+//
+// Effects: m_cDirectoryOriginal and m_cDirectoryFinal are set.
+//
+//+-------------------------------------------------------------------------------
+
+
+BOOL CTest::Initialize( const CDirectory& cDirectoryOriginal,
+ const CDirectory& cDirectoryFinal
+ )
+{
+ // -----
+ // Begin
+ // -----
+
+ m_pcDirectoryOriginal = &cDirectoryOriginal;
+ m_pcDirectoryFinal = &cDirectoryFinal;
+
+ m_cMoniker.Initialize( cDirectoryOriginal, cDirectoryFinal );
+
+ // ----
+ // Exit
+ // ----
+
+ return TRUE;
+
+} // CTest::Initialize
+
+//+-------------------------------------------------------------------------
+//
+// Function: CTest::CreateFileMonikerEx
+//
+// Synopsis: Verify that CreateFileMonikerEx actually creates a
+// *tracking* file moniker. This is done by creating
+// the file moniker, renaming the link source,
+// Reducing the moniker, and getting the display name
+// of the reduced moniker. Note that this tests
+// both CreateFileMonikerEx and Reduce.
+//
+// Inputs: None.
+//
+// Outputs: TRUE if successful, FALSE otherwise.
+//
+// Effects: None.
+//
+//+-------------------------------------------------------------------------
+
+
+BOOL CTest::CreateFileMonikerEx( )
+{
+ // ---------------
+ // Local Variables
+ // ---------------
+
+ BOOL bSuccess = FALSE;
+
+ WCHAR wszDisplayName[ MAX_PATH + sizeof( L'\0' ) ];
+ IMoniker* pmnkReduced = NULL;
+
+ // -----
+ // Begin
+ // -----
+
+ wprintf( L"CreateFileMonikerEx()\n" );
+ wprintf( L" Create a tracking file moniker (using CreateFileMonikerEx),\n"
+ L" move the represented file, Reduce the moniker, and get\n"
+ L" the display name from the reduced moniker. It should be the\n"
+ L" new file name. This test covers both CreateFileMonikerEx and\n"
+ L" Reduce.\n" );
+
+
+ // Create the tracking file moniker.
+
+ if( !m_cMoniker.CreateFileMonikerEx( ) )
+ EXIT( L"Could not CreateFileMonikerEx" );
+
+ // Rename the link source file.
+
+ if( !m_cMoniker.RenameTemporaryStorage() )
+ EXIT( L"Could not rename the temporary storage file" );
+
+ // Reduce the tracking file moniker
+
+ if( !m_cMoniker.Reduce( INFINITE, &pmnkReduced ))
+ EXIT( L"Could not reduce the moniker" );
+
+ // Use the reduced (non-tracking) file moniker to get the display name.
+
+ if( !m_cMoniker.GetDisplayName( wszDisplayName, pmnkReduced ))
+ EXIT( L"Could not get the display name" );
+
+ // Validate the display name.
+
+ if( _wcsicmp( wszDisplayName, m_cMoniker.GetTemporaryStorageName() ))
+ EXIT( L"Failed" );
+
+
+ bSuccess = TRUE;
+
+ // ----
+ // Exit
+ // ----
+
+Exit:
+
+ m_cMoniker.DeleteTemporaryStorage();
+
+ DisplayErrors( bSuccess, L"CTest::CreateFileMonikerEx()" );
+ return( bSuccess );
+
+} // CTest::CreateFileMonikerEx()
+
+
+//+--------------------------------------------------------------------------
+//
+// Function: CTest::GetDisplayName
+//
+// Synopsis: Create a tracking file moniker, get its display name,
+// rename the link source file, and get the display name again.
+// The value of the second display name will depend on whether
+// or not the original and final link source are within the set
+// of local indexed volumes.
+//
+// Inputs: None.
+//
+// Outputs: TRUE if successful, FALSE otherwise.
+//
+// Effects: None.
+//
+//+--------------------------------------------------------------------------
+
+
+BOOL CTest::GetDisplayName( )
+{
+ // ---------------
+ // Local Variables
+ // ---------------
+
+ BOOL bSuccess = FALSE;
+
+ WCHAR wszFinalDisplayName[ MAX_PATH + sizeof( L'\0' ) ];
+ WCHAR wszOriginalDisplayName[ MAX_PATH + sizeof( L'\0' ) ];
+
+ // -----
+ // Begin
+ // -----
+
+ wprintf( L"GetDisplayName()\n" );
+ wprintf( L" Create a tracking file moniker, move the represented file,\n"
+ L" and perform a GetDisplayName on the moniker. If the original\n"
+ L" and final locations of the source file are within the set of local\n"
+ L" indexed drives, the display name will represent the final file name.\n"
+ L" Otherwise, it will represent the original display name.\n" );
+
+ // Create a tracking file moniker.
+
+ if( !m_cMoniker.CreateFileMonikerEx( ) )
+ EXIT( L"Could not CreateFileMonikerEx" );
+
+ // Get its display name.
+
+ if( !m_cMoniker.GetDisplayName( wszOriginalDisplayName ))
+ EXIT( L"Could not get the original display name" );
+
+ // Rename the link source.
+
+ if( !m_cMoniker.RenameTemporaryStorage() )
+ EXIT( L"Could not rename the temporary storage file" );
+
+ // Get the renamed moniker's display name.
+
+ if( !m_cMoniker.GetDisplayName( wszFinalDisplayName ))
+ EXIT( L"Could not get the final display name" );
+
+ // Was and is the link source on a local, indexed volume?
+
+ if( ( m_pcDirectoryOriginal->GetFileSystemType() == fstOFS )
+ &&
+ ( m_pcDirectoryOriginal->GetFileSystemType() == fstOFS )
+ )
+ {
+ // Yes, so the GetDisplayName should have tracked the rename.
+
+ if( _wcsicmp( wszFinalDisplayName, m_cMoniker.GetTemporaryStorageName() ))
+ EXIT( L"Failed" );
+ }
+ else
+ {
+ // No, so the GetDisplayName should have returned the original name.
+
+ if( _wcsicmp( wszOriginalDisplayName, wszFinalDisplayName ))
+ EXIT( L"Failed" );
+ }
+
+
+ bSuccess = TRUE;
+
+ // ----
+ // Exit
+ // ----
+
+Exit:
+
+ m_cMoniker.DeleteTemporaryStorage();
+
+ DisplayErrors( bSuccess, L"CTest::GetDisplayName()" );
+ return( bSuccess );
+
+} // CTest::GetDisplayName()
+
+
+
+//+--------------------------------------------------------------------------
+//
+// Function: CTest::GetTimeOfLastChange
+//
+// Synopsis: Create a tracking file moniker, rename it, sleep, and
+// touch it. If the original and final link sources are
+// on local, indexed volumes, then a GetDisplayName should
+// return the final link source's time. Otherwise, it should
+// return the original link source's time.
+//
+// Inputs: None.
+//
+// Outputs: TRUE if successful, FALSE otherwise.
+//
+// Effects: None.
+//
+//+--------------------------------------------------------------------------
+
+
+BOOL CTest::GetTimeOfLastChange( )
+{
+ // ---------------
+ // Local Variables
+ // ---------------
+
+ BOOL bSuccess = FALSE;
+
+ FILETIME ftOriginal;
+ FILETIME ftFinal;
+ FILETIME ftMoniker;
+
+ // -----
+ // Begin
+ // -----
+
+ wprintf( L"GetTimeOfLastChange()\n" );
+ wprintf( L" Create a tracking file moniker and move it. Then touch (set the Access\n"
+ L" time) on the link source, and perform a GetTimeOfLastChange on the Moniker.\n"
+ L" If the original and final location of the link source is within the set\n"
+ L" of local indexed volumes, then the time returned from the moniker should\n"
+ L" match that of the post-touch link source. Otherwise it should match the\n"
+ L" link sources original time.\n" );
+
+ // Create a tracking file moniker.
+
+ if( !m_cMoniker.CreateFileMonikerEx( TRACK_LOCALONLY ) )
+ EXIT( L"Could not CreateFileMonikerEx" );
+
+ // Get the link source's current time.
+
+ if( !m_cMoniker.GetTemporaryStorageTime( &ftOriginal ))
+ EXIT( L"Could not get original file time" );
+
+ // Move the link source.
+
+ if( !m_cMoniker.RenameTemporaryStorage() )
+ EXIT( L"Could not rename the temporary storage file" );
+
+ // Delay so that when we touch the final link source, its time
+ // will be noticably different from the original link source's time.
+
+ {
+ wprintf( L" Sleeping to let the time change: " );
+ for( int i = 0; i < 10; i++ ) // Sleep for 5 seconds
+ {
+ wprintf( L"z" );
+ Sleep( 500 ); // 1/2 second
+ }
+ wprintf( L"\n" );
+ }
+
+ // Touch the final link source.
+
+ if( !m_cMoniker.TouchTemporaryStorage())
+ EXIT( L"Could not touch temporary storage" );
+
+ // Get the final link source's time from the file system.
+
+ if( !m_cMoniker.GetTemporaryStorageTime( &ftFinal ))
+ EXIT( L"could not get final file time" );
+
+ // Get the final link source's time from the moniker.
+
+ if( !m_cMoniker.GetTimeOfLastChange( &ftMoniker ))
+ EXIT( L"Could not get the time of last change" );
+
+ // Is the original & final location of the link source file
+ // in the set of local, indexed volumes?
+
+ if( ( m_pcDirectoryOriginal->GetFileSystemType() == fstOFS )
+ &&
+ ( m_pcDirectoryOriginal->GetFileSystemType() == fstOFS )
+ )
+ {
+ // Yes. GetTimeOfLastChange should therefore have found
+ // the time of the final link source file.
+
+ if( memcmp( &ftFinal, &ftMoniker, sizeof( FILETIME ) ))
+ EXIT( L"Failed" );
+ }
+ else
+ {
+ // No. GetTimeOfLastChange should therefore have returned
+ // the time of the original link source file.
+
+ if( memcmp( &ftOriginal, &ftMoniker, sizeof( FILETIME ) ))
+ EXIT( L"Failed" );
+ }
+
+
+ bSuccess = TRUE;
+
+ // ----
+ // Exit
+ // ----
+
+Exit:
+
+ m_cMoniker.DeleteTemporaryStorage();
+
+ DisplayErrors( bSuccess, L"CTest::GetTimeOfLastChange()" );
+ return( bSuccess );
+
+} // CTest::GetTimeOfLastChange()
+
+
+//+--------------------------------------------------------------------
+//
+// Function: CTest::BindToObject
+//
+// Synopsis: Create a tracking file moniker, move the link source,
+// and attempt to bind to it with a BindToObject.
+// Since presumably the temporary file we're using as a link
+// source has no server, this will fail. But any failure
+// downstream of locating the link source file will be
+// ignored.
+//
+// Inputs: None.
+//
+// Output: TRUE if successful, FALSE otherwise.
+//
+// Effects: None.
+//
+//+--------------------------------------------------------------------
+
+
+BOOL CTest::BindToObject( )
+{
+ // ---------------
+ // Local Variables
+ // ---------------
+
+ BOOL bSuccess = FALSE;
+
+ // -----
+ // Begin
+ // -----
+
+ wprintf( L"BindToObject()\n" );
+ wprintf( L" Create a tracking file moniker, moved the represented file,\n"
+ L" and attempt a BindToStorage() (which should succeed).\n" );
+
+ // Create a tracking file moniker.
+
+ if( !m_cMoniker.CreateFileMonikerEx( ) )
+ EXIT( L"Could not CreateFileMonikerEx" );
+
+ // Move the link source file.
+
+ if( !m_cMoniker.RenameTemporaryStorage() )
+ EXIT( L"Could not rename the temporary storage file" );
+
+ // Attempt a bind.
+
+ if( !m_cMoniker.BindToObject( ))
+ EXIT( L"Could not bind to Object" );
+
+
+ bSuccess = TRUE;
+
+ // ----
+ // Exit
+ // ----
+Exit:
+
+ m_cMoniker.DeleteTemporaryStorage();
+
+ DisplayErrors( bSuccess, L"CTest::BindToObject()" );
+ return( bSuccess );
+
+} // CTest::BindToObject()
+
+
+//+-----------------------------------------------------------
+//
+// Function: CTest::IPersist
+//
+// Synopsis: Create a tracking file moniker, move the link
+// source, and perform the CMoniker::SaveDeleteLoad
+// test.
+//
+// Inputs: None.
+//
+// Output: TRUE if successful, FALSE otherwise
+//
+// Effects: None.
+//
+//+-----------------------------------------------------------
+
+
+BOOL CTest::IPersist( )
+{
+ // ---------------
+ // Local Variables
+ // ---------------
+
+ BOOL bSuccess = FALSE;
+
+ // -----
+ // Begin
+ // -----
+
+ wprintf( L"IPersist()\n" );
+ wprintf( L" Create a tracking file moniker (using CreateFileMonikerEx), and\n"
+ L" save it to a Stream. Delete the moniker, create a new one using\n"
+ L" CreateFileMoniker, load it from the Stream, and verify that the resulting\n"
+ L" file moniker is tracking.\n" );
+
+ // Create a tracking file moniker.
+
+ if( !m_cMoniker.CreateFileMonikerEx( ) )
+ EXIT( L"Could not CreateFileMonikerEx" );
+
+ // Rename the link source.
+
+ if( !m_cMoniker.RenameTemporaryStorage() )
+ EXIT( L"Could not rename the temporary storage file" );
+
+ // Save the moniker, deleted, create a new moniker, and reload it.
+
+ if( !m_cMoniker.SaveDeleteLoad( ))
+ EXIT( L"Failed SaveDeleteLoad" );
+
+
+ bSuccess = TRUE;
+
+ // ----
+ // Exit
+ // ----
+
+Exit:
+
+ m_cMoniker.DeleteTemporaryStorage();
+
+ DisplayErrors( bSuccess, L"CTest::IPersist()" );
+ return( bSuccess );
+
+} // CTest::IPersist()
+
+
+//+----------------------------------------------------------------------
+//
+// Function: CTest::ComposeWith
+//
+// Synopsis: Create a tracking file moniker, and use it in the
+// CMoniker::ComposeWith operation.
+//
+// Inputs: None.
+//
+// Output: TRUE if successful, FALSE otherwise.
+//
+// Effects: None.
+//
+//+----------------------------------------------------------------------
+
+BOOL CTest::ComposeWith( )
+{
+ // ---------------
+ // Local Variables
+ // ---------------
+
+ BOOL bSuccess = FALSE;
+
+ IMoniker* pmnkReduced = NULL;
+ WCHAR wszDisplayName[ MAX_PATH + sizeof( L'\0' )];
+
+ // -----
+ // Begin
+ // -----
+
+ m_lError = 0;
+
+ wprintf( L"ComposeWith()\n" );
+ wprintf( L" Create a tracking file moniker, and compose it with a non-tracking\n"
+ L" file moniker on the right. The resulting moniker should be tracking.\n" );
+
+ // Create the tracking file moniker.
+
+ if( !m_cMoniker.CreateFileMonikerEx( ) )
+ EXIT( L"Could not CreateFileMonikerEx" );
+
+ // Perform the ComposeWith operation.
+
+ if( !m_cMoniker.ComposeWith( ))
+ EXIT( L"Failed ComposeWith" );
+
+ // Move the link source file.
+
+ if( !m_cMoniker.RenameTemporaryStorage() )
+ EXIT( L"Could not rename the temporary storage file" );
+
+ // Reduce the composed moniker.
+
+ if( !m_cMoniker.Reduce( INFINITE, &pmnkReduced ))
+ EXIT( L"Could not reduce the moniker" );
+
+ // Get the display name on the reduced moniker.
+
+ if( !m_cMoniker.GetDisplayName( wszDisplayName, pmnkReduced ))
+ EXIT( L"Could not get the display name" );
+
+ // Verify that the name from the moniker is the actual link source
+ // file's new name.
+
+ if( _wcsicmp( wszDisplayName, m_cMoniker.GetTemporaryStorageName() ))
+ EXIT( L"Failed" );
+
+
+ bSuccess = TRUE;
+
+ // ----
+ // Exit
+ // ----
+
+Exit:
+
+ m_cMoniker.DeleteTemporaryStorage();
+
+ DisplayErrors( bSuccess, L"CTest::ComposeWith()" );
+ return( bSuccess );
+
+} // CTest::ComposeWith()
+
+
+//+------------------------------------------------------------------
+//
+// Function: CTest::BindToStorage
+//
+// Synopsis: Create a tracking file moniker, and perform the
+// CMoniker::BindToStorage operation.
+//
+// Inputs: None.
+//
+// Output: TRUE if successful, FALSE otherwise.
+//
+//+------------------------------------------------------------------
+
+
+BOOL CTest::BindToStorage( )
+{
+ // ---------------
+ // Local Variables
+ // ---------------
+
+ BOOL bSuccess = FALSE;
+
+ // -----
+ // Begin
+ // -----
+
+ m_lError = 0;
+
+ wprintf( L"BindToStorage()\n" );
+ wprintf( L" Create a tracking file moniker (using CreateFileMonikerEx),\n"
+ L" move the represented file, Reduce the moniker, and get\n"
+ L" the display name from the reduced moniker. It should be the\n"
+ L" new file name. This test covers both CreateFileMonikerEx and\n"
+ L" Reduce.\n" );
+
+ // Create the tracking file moniker.
+
+ if( !m_cMoniker.CreateFileMonikerEx( ) )
+ EXIT( L"Could not CreateFileMonikerEx" );
+
+ // Move the link source file.
+
+ if( !m_cMoniker.RenameTemporaryStorage() )
+ EXIT( L"Could not rename the temporary storage file" );
+
+ // Bind to the Storage
+
+ if( !m_cMoniker.BindToStorage( ))
+ EXIT( L"Could not bind to Storage" );
+
+
+ bSuccess = TRUE;
+
+ // ----
+ // Exit
+ // ----
+
+Exit:
+
+ m_cMoniker.DeleteTemporaryStorage();
+
+ DisplayErrors( bSuccess, L"CTest::BindToStorage()" );
+ return( bSuccess );
+
+} // CTest::BindToStorage()
+
+
+//+--------------------------------------------------------------------------
+//
+// Function: CTest::DeleteLinkSource
+//
+// Synopsis: Create a tracking file moniker, delete the link source,
+// and attempt a Reduce. The Reduce should not fail, but
+// it should return an HResult of MK_S_REDUCED_TO_SELF.
+//
+// Inputs: Tick count limit on the length of the Reduce operation.
+//
+// Output: TRUE if successful, FALSE otherwise.
+//
+// Effects: None.
+//
+//+--------------------------------------------------------------------------
+
+BOOL CTest::DeleteLinkSource( DWORD dwDelay )
+{
+ // ---------------
+ // Local Variables
+ // ---------------
+
+ BOOL bSuccess = FALSE;
+
+ WCHAR wszTimeout[ 80 ];
+
+ // -----
+ // Begin
+ // -----
+
+ m_lError = 0L;
+
+ // Generate a string which shows what the delay is.
+
+ switch( dwDelay )
+ {
+ case 0:
+ wcscpy( wszTimeout, L"instant timeout" );
+ break;
+
+ case INFINITE:
+ wcscpy( wszTimeout, L"infinite timeout" );
+ break;
+
+ default:
+ wsprintf( wszTimeout, L"%d ms timeout", dwDelay );
+ }
+
+ // Display a header.
+
+ wprintf( L"Delete Link Source (%s)\n",
+ wszTimeout );
+ wprintf( L" Create a tracking file moniker, then delete the link source, and\n"
+ L" attempt a reduce with a %s.\n",
+ wszTimeout );
+
+ // Create a tracking file moniker.
+
+ if( !m_cMoniker.CreateFileMonikerEx( ) )
+ EXIT( L"Could not CreateFileMonikerEx" );
+
+ // Delete the link source file.
+
+ if( !m_cMoniker.DeleteTemporaryStorage() )
+ EXIT( L"Could not delete temporary storage" );
+
+ // Tell CMoniker not to alarm the user with error messages.
+
+ m_cMoniker.SuppressErrorMessages( TRUE );
+
+ // Reduce the moniker, and verify it returns the proper Success code.
+
+ if( !m_cMoniker.Reduce( dwDelay )
+ ||
+ m_cMoniker.GetHResult() != MK_S_REDUCED_TO_SELF
+ )
+ EXIT( L"Failed" );
+
+
+ bSuccess = TRUE;
+
+ // ----
+ // Exit
+ // ----
+
+Exit:
+
+ m_cMoniker.DeleteTemporaryStorage();
+ m_cMoniker.SuppressErrorMessages( FALSE );
+
+ DisplayErrors( bSuccess, L"CTest::DeleteLinkSource()" );
+ return( bSuccess );
+
+} // CTest::DeleteLinkSource()
+
+
+//+------------------------------------------------------------------
+//
+// Function: CTest::GetOversizedBindOpts
+//
+// Synopsis: Test a bind context's ability to return a BIND_OPTS
+// which is larger than expected.
+//
+// First, initialize the default BIND_OPTS in the bind
+// context to 1s. Then, ask for a large BIND_OPTS.
+// The resulting buffer should have 1s up to the size of
+// the normal BIND_OPTS, and 0s for the remainder of the
+// buffer. The length, however, should be that of the large
+// buffer.
+//
+// Inputs: None.
+//
+// Outputs: TRUE if successful, FALSE otherwise.
+//
+// Effects: None.
+//
+//+------------------------------------------------------------------
+
+
+BOOL CTest::GetOversizedBindOpts( )
+{
+ // ---------------
+ // Local Variables
+ // ---------------
+
+ BOOL bSuccess = FALSE;
+
+ BIND_OPTS bind_opts;
+ LPBIND_OPTS pbind_optsLarge = (LPBIND_OPTS) new BYTE[ SIZE_OF_LARGE_BIND_OPTS ];
+ LPBIND_OPTS pbind_optsExpected = (LPBIND_OPTS) new BYTE[ SIZE_OF_LARGE_BIND_OPTS ];
+
+ // -----
+ // Begin
+ // -----
+
+ m_lError = 0L;
+
+ wprintf( L"Get Oversized BindOpts\n" );
+ wprintf( L" Create a buffer which is much larger than a normal BIND_OPTS, and\n"
+ L" use it to request the BIND_OPTS from a bind context. The length\n"
+ L" of the resulting buffer should be the large value, and the extra\n"
+ L" room in the buffer should be all 0s.\n" );
+
+
+ // Validate our 'new' operations.
+
+ if( pbind_optsLarge == NULL )
+ EXIT( L"Could not allocate pbind_optsLarge" );
+ pbind_optsLarge->cbStruct = SIZE_OF_LARGE_BIND_OPTS;
+
+ if( pbind_optsExpected == NULL )
+ EXIT( L"Could not allocate pbind_optsExpected" );
+ pbind_optsExpected->cbStruct = SIZE_OF_LARGE_BIND_OPTS;
+
+
+ // Initialize the bind_opts (normal sized) in the bind context to 1s.
+
+ if( !m_cMoniker.InitializeBindContext() )
+ EXIT( L"Could not initialize the bind context" );
+
+ memset( &bind_opts, 1, sizeof( bind_opts ));
+ bind_opts.cbStruct = sizeof( bind_opts );;
+
+ m_lError = m_cMoniker.GetBindCtx()->SetBindOptions( &bind_opts );
+ if( FAILED( m_lError )) EXIT( L"Could not set original bind options" );
+
+ // Initialize the large bind_opts to 2s, then retrieve the bind_opts into
+ // this structure. This is done to verify that the GetBindOptions below
+ // fills in the entire requested buffer (overwirting all of the 2s).
+
+ memset( pbind_optsLarge, 2, SIZE_OF_LARGE_BIND_OPTS );
+ pbind_optsLarge->cbStruct = SIZE_OF_LARGE_BIND_OPTS;
+
+ m_lError = m_cMoniker.GetBindCtx()->GetBindOptions( pbind_optsLarge );
+ if( FAILED( m_lError )) EXIT( L"Could not get large bind options" );
+
+ // The returned structure should have the large cbStruct, 1s up to
+ // the length of BIND_OPTS, and 0s after that.
+
+ memset( pbind_optsExpected, 0, SIZE_OF_LARGE_BIND_OPTS );
+ memset( pbind_optsExpected, 1, sizeof( bind_opts ));
+ pbind_optsExpected->cbStruct = SIZE_OF_LARGE_BIND_OPTS;
+
+ if( memcmp( pbind_optsLarge, pbind_optsExpected, SIZE_OF_LARGE_BIND_OPTS ))
+ EXIT( L"Failed" );
+
+
+ bSuccess = TRUE;
+
+ // ----
+ // Exit
+ // ----
+
+Exit:
+
+ DisplayErrors( bSuccess, L"CTest::GetOversizedBindOpts()" );
+ return( bSuccess );
+
+} // CTest::GetOversizeBindOpts()
+
+
+
+//+----------------------------------------------------------------
+//
+// Function: CTest::GetUndersizedBindOpts
+//
+// Synopsis: Create a bind context, and initialize the data in its
+// BIND_OPTS to 1s. Create a normal BIND_OPTS-sized buffer,
+// initialize it to 2s, then use it to get a small-sized
+// BIND_OPTS from the bind context. The resulting buffer
+// should have a small length, a small number of 1s,
+// and 2s for the remainder of the buffer.
+//
+// Inputs: None.
+//
+// Outputs: TRUE if successful, FALSE otherwise.
+//
+// Effects: None.
+//
+//+----------------------------------------------------------------
+
+
+
+BOOL CTest::GetUndersizedBindOpts( )
+{
+ // ---------------
+ // Local Variables
+ // ---------------
+
+ BOOL bSuccess = FALSE;
+
+ LPBIND_OPTS pbind_optsSmall = (LPBIND_OPTS) new BYTE[ SIZE_OF_LARGE_BIND_OPTS ];
+ LPBIND_OPTS pbind_optsExpected = (LPBIND_OPTS) new BYTE[ SIZE_OF_LARGE_BIND_OPTS ];
+ BIND_OPTS bind_opts;
+ bind_opts.cbStruct = sizeof( bind_opts );
+
+ // -----
+ // Begin
+ // -----
+
+ m_lError = 0L;
+
+ wprintf( L"Get Undersized BindOpts\n" );
+ wprintf( L" Get the BIND_OPTS from a bind context, but only providing a small\n"
+ L" buffer, and verify that only that portion of the actual BIND_OPTS\n"
+ L" is returned.\n" );
+
+ // Validate our 'new's.
+
+ if( pbind_optsSmall == NULL )
+ EXIT( L"Could not allocate pbind_optsSmall" );
+ pbind_optsSmall->cbStruct = SIZE_OF_SMALL_BIND_OPTS;
+
+ if( pbind_optsExpected == NULL )
+ EXIT( L"Could not allocate pbind_optsExpected" );
+ pbind_optsExpected->cbStruct = SIZE_OF_SMALL_BIND_OPTS;
+
+
+ // Initialize the bind_opts (normal sized) in the bind context to 1s.
+
+ if( !m_cMoniker.InitializeBindContext() )
+ EXIT( L"Could not initialize the bind context" );
+
+ memset( &bind_opts, 1, sizeof( bind_opts ));
+ bind_opts.cbStruct = sizeof( bind_opts );;
+
+ m_lError = m_cMoniker.GetBindCtx()->SetBindOptions( &bind_opts );
+ if( FAILED( m_lError )) EXIT( L"Could not set original bind options" );
+
+
+ // Initialize the small bind_opts to 2s, then retrieve the bind_opts into
+ // this structure.
+
+ memset( pbind_optsSmall, 2, SIZE_OF_LARGE_BIND_OPTS );
+ pbind_optsSmall->cbStruct = SIZE_OF_SMALL_BIND_OPTS;
+
+ m_lError = m_cMoniker.GetBindCtx()->GetBindOptions( pbind_optsSmall );
+ if( FAILED( m_lError )) EXIT( L"Could not get small bind options" );
+
+ // The returned structure should have the small cbStruct, 1s up to
+ // the end of the small buffer, and 2s to the end of the real buffer.
+
+ memset( pbind_optsExpected, 2, SIZE_OF_LARGE_BIND_OPTS );
+ memset( pbind_optsExpected, 1, SIZE_OF_SMALL_BIND_OPTS );
+ pbind_optsExpected->cbStruct = SIZE_OF_SMALL_BIND_OPTS;
+
+ if( memcmp( pbind_optsSmall, pbind_optsExpected, SIZE_OF_LARGE_BIND_OPTS ))
+ EXIT( L"Failed" );
+
+
+ bSuccess = TRUE;
+
+ // ----
+ // Exit
+ // ----
+
+Exit:
+
+ DisplayErrors( bSuccess, L"CTest::GetUndersizedBindOpts()" );
+ return( bSuccess );
+
+} // CTest::GetUndersizedBindOpts()
+
+
+//+----------------------------------------------------------------
+//
+// Function: CTest::SetOversizedBindOpts
+//
+// Synopsis: Create a large BIND_OPTS buffer, set it in
+// a bind context, and verify that it can be read back.
+//
+// Inputs: None.
+//
+// Outputs: TRUE if successful, FALSE otherwise.
+//
+// Effects: None.
+//
+//+----------------------------------------------------------------
+
+BOOL CTest::SetOversizedBindOpts( )
+{
+ // ---------------
+ // Local Variables
+ // ---------------
+
+ BOOL bSuccess = FALSE;
+
+ LPBIND_OPTS pbind_optsLarge = (LPBIND_OPTS) new BYTE[ SIZE_OF_LARGE_BIND_OPTS ];
+ LPBIND_OPTS pbind_optsExpected = (LPBIND_OPTS) new BYTE[ SIZE_OF_LARGE_BIND_OPTS ];
+
+ // -----
+ // Begin
+ // -----
+
+ wprintf( L"Set Oversized BindOpts\n" );
+ wprintf( L" Set a larger-than-usual BIND_OPTS in a bind context, and verify\n"
+ L" that it can be read back in its entirety.\n" );
+
+ // Validate our 'new's.
+
+ if( pbind_optsLarge == NULL )
+ EXIT( L"Could not allocate pbind_optsLarge" );
+ pbind_optsLarge->cbStruct = SIZE_OF_LARGE_BIND_OPTS;
+
+ if( pbind_optsExpected == NULL )
+ EXIT( L"Could not allocate pbind_optsExpected" );
+ pbind_optsExpected->cbStruct = SIZE_OF_LARGE_BIND_OPTS;
+
+ // Initialize the large bind_opts to 1s, then set the large BIND_OPTS
+ // into the bind context.
+
+ if( !m_cMoniker.InitializeBindContext() )
+ EXIT( L"Could not initialize the bind context" );
+
+ memset( pbind_optsLarge, 1, SIZE_OF_LARGE_BIND_OPTS );
+ pbind_optsLarge->cbStruct = SIZE_OF_LARGE_BIND_OPTS;
+
+ m_lError = m_cMoniker.GetBindCtx()->SetBindOptions( pbind_optsLarge );
+ if( FAILED( m_lError )) EXIT( L"Could not set large bind options" );
+
+ // Get the BIND_OPTS back from the bind context, and verify that it's
+ // what we set.
+
+ memset( pbind_optsLarge, 0, SIZE_OF_LARGE_BIND_OPTS );
+ pbind_optsLarge->cbStruct = SIZE_OF_LARGE_BIND_OPTS;
+ m_lError = m_cMoniker.GetBindCtx()->GetBindOptions( pbind_optsLarge );
+
+ memset( pbind_optsExpected, 1, SIZE_OF_LARGE_BIND_OPTS );
+ pbind_optsExpected->cbStruct = SIZE_OF_LARGE_BIND_OPTS;
+
+ if( memcmp( pbind_optsLarge, pbind_optsExpected, SIZE_OF_LARGE_BIND_OPTS ))
+ EXIT( L"Failed" );
+
+
+ bSuccess = TRUE;
+
+ // ----
+ // Exit
+ // ----
+
+Exit:
+
+ DisplayErrors( bSuccess, L"CTest::SetOversizedBindOpts()" );
+ return( bSuccess );
+
+} // CTest::SetOversizeBindOpts()
+
+
+//+------------------------------------------------------------
+//
+// Function: CTest::SetUndersizedBindOpts
+//
+// Synopsis: Create a bind context, and initialize its BIND_OPTS to
+// all 1s. Then, set a small BIND_OPTS in the bind context
+// which is set to 2s. Read back the whold BIND_OPTS, and
+// verify that it has the normal length, 2s at the
+// beginning, and 1s to the end.
+//
+// Inputs: None.
+//
+// Output: TRUE if successful, FALSE otherwise.
+//
+//+------------------------------------------------------------
+
+
+BOOL CTest::SetUndersizedBindOpts( )
+{
+ // ---------------
+ // Local Variables
+ // ---------------
+
+ BOOL bSuccess = FALSE;
+
+ BIND_OPTS bind_opts;
+ BIND_OPTS bind_optsExpected;
+
+ // -----
+ // Begin
+ // -----
+
+ m_lError = 0L;
+
+ wprintf( L"Set Undersized BindOpts\n" );
+ wprintf( L" Initialize a BIND_OPTS in a bind context to 1s, then set a smaller\n"
+ L" BIND_OPTS in it set to 2s. When the buffer is read back, it should\n"
+ L" have 2s up to the small buffer size, followed by 1s.\n" );
+
+ // Initialize the bind context's BIND_OPTS (normal sized) to 1s.
+
+ if( !m_cMoniker.InitializeBindContext() )
+ EXIT( L"Could not initialize the bind context" );
+
+ memset( &bind_opts, 1, sizeof( bind_opts ));
+ bind_opts.cbStruct = sizeof( bind_opts );
+ m_lError = m_cMoniker.GetBindCtx()->SetBindOptions( &bind_opts );
+ if( FAILED( m_lError )) EXIT( L"Could not set initial BIND_OPTS" );
+
+ // Now set a smaller BIND_OPTS. But initialize the local BIND_OPTS to all
+ // 2s, so that we can verify that only part of the buffer is put into the
+ // bind context.
+
+ memset( &bind_opts, 2, sizeof( bind_opts ) );
+ bind_opts.cbStruct = SIZE_OF_SMALL_BIND_OPTS;
+ m_lError = m_cMoniker.GetBindCtx()->SetBindOptions( &bind_opts );
+ if( FAILED( m_lError )) EXIT( L"Could not set small BIND_OPTS" );
+
+ // The resulting BIND_OPTS in the bind context should have 2s up
+ // to SIZE_OF_SMALL_BIND_OPTS, and 1s for the remainder of the buffer.
+
+ bind_opts.cbStruct = sizeof( bind_opts );
+ m_lError = m_cMoniker.GetBindCtx()->GetBindOptions( &bind_opts );
+ if( FAILED( m_lError )) EXIT( L"Could not get BIND_OPTS" );
+
+ memset( &bind_optsExpected, 1, sizeof( bind_opts ));
+ memset( &bind_optsExpected, 2, SIZE_OF_SMALL_BIND_OPTS );
+ bind_optsExpected.cbStruct = sizeof( bind_opts );
+
+ if( memcmp( &bind_opts, &bind_optsExpected, sizeof( bind_opts )))
+ EXIT( L"Failed" );
+
+
+ bSuccess = TRUE;
+
+ // ----
+ // Exit
+ // ----
+
+Exit:
+
+ DisplayErrors( bSuccess, L"CTest::SetUndersizedBindOpts()" );
+ return( bSuccess );
+
+} // CTest::SetUndersizedBindOpts()
+
+
+#ifdef _FUTURE_
+
+BOOL CTest::CFMWithRegistryClear( )
+{
+ BOOL bSuccess = FALSE;
+ WCHAR wszDisplayName[ MAX_PATH + sizeof( L'\0' ) ];
+
+ if( !m_cMoniker.SaveRegistryTrackFlags() )
+ EXIT( L"Could not save the existing track flags in the registry" );
+
+ if( !m_cMoniker.DeleteRegistryTrackFlags() )
+ EXIT( L"Could not delete the existing track flags in the registry" );
+
+ if( !m_cMoniker.CreateFileMoniker() )
+ EXIT( L"Could not CreateFileMoniker" );
+
+ if( !m_cMoniker.RenameTemporaryStorage() )
+ EXIT( L"Could not rename the temporary storage file" );
+
+ if( !m_cMoniker.GetDisplayName( wszDisplayName ))
+ EXIT( L"Could not get the display name" );
+
+ if( !_wcsicmp( wszDisplayName, m_cMoniker.GetTemporaryStorageName() ))
+ EXIT( L"Test failed: A moniker was created using CreateFileMoniker, after\n"
+ L" the Track Flags had been cleared from the Registry.\n"
+ L" The underlying root storage was then renamed.\n"
+ L" But a GetDisplayName then showed the new name, implying\n"
+ L" that the created moniker is using tracking (which it\n"
+ L" should not, because without the Track Flags set there\n"
+ L" should be no tracking).\n" );
+
+
+ bSuccess = TRUE;
+
+Exit:
+
+ m_cMoniker.DeleteTemporaryStorage();
+
+ if( !m_cMoniker.RestoreRegistryTrackFlags() )
+ ERROR_IN_EXIT( L"Could not restore Track Flags in Registry" );
+
+
+ DisplayErrors( bSuccess, L"CTest::CFMWithRegistryClear" );
+ return( bSuccess );
+
+} // CTest::CFMWithRegistryClear
+
+
+
+
+BOOL CTest::CFMWithRegistrySet( )
+{
+ BOOL bSuccess = FALSE;
+ WCHAR wszDisplayName[ MAX_PATH + sizeof( L'\0' ) ];
+
+ if( !m_cMoniker.SaveRegistryTrackFlags() )
+ EXIT( L"Could not save the existing track flags in the registry" );
+
+ if( !m_cMoniker.SetTrackFlagsInRegistry( TRACK_LOCALONLY ) )
+ EXIT( L"Could not set track flags in the registry" );
+
+ if( !m_cMoniker.CreateFileMoniker() )
+ EXIT( L"Could not CreateFileMoniker" );
+
+ if( !m_cMoniker.RenameTemporaryStorage() )
+ EXIT( L"Could not rename the temporary storage file" );
+
+ if( !m_cMoniker.GetDisplayName( wszDisplayName ))
+ EXIT( L"Could not get the display name" );
+
+ if( _wcsicmp( wszDisplayName, m_cMoniker.GetTemporaryStorageName() ))
+ EXIT( L"Test failed: A moniker was created using CreateFileMoniker, after\n"
+ L" setting the TRACK_LOCALONLY flag in the Registry.\n"
+ L" However, after moving the linked file, GetDisplayName\n"
+ L" did not return the new name.\n" );
+
+
+ bSuccess = TRUE;
+
+Exit:
+
+ m_cMoniker.DeleteTemporaryStorage();
+
+ if( !m_cMoniker.RestoreRegistryTrackFlags() )
+ ERROR_IN_EXIT( L"Could not restore Track Flags in Registry" );
+
+
+ DisplayErrors( bSuccess, L"CTest::CFMWithRegistrySet()" );
+ return( bSuccess );
+
+} // CTest::CFMWithRegistrySet
+
+
+#endif // _FUTURE_
diff --git a/private/oleutest/cfmex/ctest.hxx b/private/oleutest/cfmex/ctest.hxx
new file mode 100644
index 000000000..32d1e0012
--- /dev/null
+++ b/private/oleutest/cfmex/ctest.hxx
@@ -0,0 +1,118 @@
+
+
+//+================================================================
+//
+// File: CTest.hxx
+//
+// Purpose: Declare the CTest class.
+//
+// This class is the test engine for the CreateFileMonikerEx
+// API (CFMEx) DRTs.
+//
+//+================================================================
+
+#ifndef _C_TEST_HXX_
+#define _C_TEST_HXX_
+
+// --------
+// Includes
+// --------
+
+#include "CDir.hxx"
+
+// -----
+// CTest
+// -----
+
+class CTest
+{
+
+// (De)Construction
+
+public:
+
+ CTest( );
+ ~CTest();
+
+// Public member routines.
+
+public:
+
+ BOOL Initialize( const CDirectory& cDirectoryOriginal,
+ const CDirectory& cDirectoryFinal );
+ BOOL CreateFileMonikerEx();
+ BOOL BindToStorage();
+ BOOL BindToObject();
+ BOOL IPersist();
+ BOOL ComposeWith();
+ BOOL GetDisplayName();
+ BOOL GetTimeOfLastChange();
+ BOOL DeleteLinkSource( DWORD dwDelay = INFINITE );
+
+ BOOL GetOversizedBindOpts();
+ BOOL GetUndersizedBindOpts();
+ BOOL SetOversizedBindOpts();
+ BOOL SetUndersizedBindOpts();
+
+// Private member routines.
+
+private:
+
+ void DisplayErrors( BOOL bSuccess, WCHAR * wszFunctionName );
+
+// Private member variables.
+
+private:
+
+ CMoniker m_cMoniker;
+ long m_lError;
+ WCHAR m_wszErrorMessage[ 512 ];
+
+ const CDirectory* m_pcDirectoryOriginal;
+ const CDirectory* m_pcDirectoryFinal;
+
+};
+
+
+// --------------
+// Inline Members
+// --------------
+
+#define OUTFILE stdout
+
+inline void CTest::DisplayErrors( BOOL bSuccess, WCHAR * wszFunctionName )
+{
+ if( !bSuccess )
+ fwprintf( OUTFILE, L"Error in %s (%08x)\n %s \n",
+ wszFunctionName, m_lError, m_wszErrorMessage );
+}
+
+
+// ------
+// Macros
+// ------
+
+#undef EXIT
+#define EXIT( error ) \
+ {\
+ wcscpy( m_wszErrorMessage, ##error );\
+ goto Exit;\
+ }
+
+
+#define ERROR_IN_EXIT( error ) \
+ {\
+ wcscpy( m_wszErrorMessage, ##error );\
+ bSuccess = FALSE; \
+ }
+
+
+// -------
+// Defines
+// -------
+
+#define SIZE_OF_LARGE_BIND_OPTS ( 2 * sizeof( BIND_OPTS2 ))
+#define SIZE_OF_SMALL_BIND_OPTS ( 3 * sizeof( DWORD ))
+
+#endif // _C_TEST_HXX_
+
diff --git a/private/oleutest/cfmex/makefile b/private/oleutest/cfmex/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/oleutest/cfmex/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/cfmex/sources b/private/oleutest/cfmex/sources
new file mode 100644
index 000000000..0bfd19e12
--- /dev/null
+++ b/private/oleutest/cfmex/sources
@@ -0,0 +1,35 @@
+!IF 0
+
+Copyright (c) 1995 Microsoft Corporation
+
+!ENDIF
+
+MAJORCOMP= appl
+MINORCOMP= windows
+TARGETNAME= CFMEx
+TARGETPATH= obj
+TARGETTYPE= LIBRARY
+
+
+
+INCLUDES=.
+
+C_DEFINES= \
+ $(C_DEFINES)
+
+
+SOURCES= CDir.cxx CMoniker.cxx CTest.cxx
+
+UMTYPE= console
+UMAPPL= CFMEx
+
+UMLIBS= .\obj\*\CFMEx.lib \
+ $(BASEDIR)\public\sdk\lib\cairo\*\ole32.lib \
+ $(WIN32_LIBS) \
+ $(GUI32_LIBS) \
+ $(BASEDIR)\public\sdk\lib\*\uuid.lib \
+ $(BASEDIR)\public\sdk\lib\i386\oleaut32.lib \
+ $(BASEDIR)\public\sdk\lib\cairo\i386\dsysuuid.lib
+
+
+CAIRO_PRODUCT=1
diff --git a/private/oleutest/channel/app/app.cxx b/private/oleutest/channel/app/app.cxx
new file mode 100644
index 000000000..e7c565a4f
--- /dev/null
+++ b/private/oleutest/channel/app/app.cxx
@@ -0,0 +1,9685 @@
+//--------------------------------------------------------------
+//
+// File: perfcli.cxx
+//
+// Contents: First attempt at getting perfcliing to work
+//
+// This is the client side
+//
+//
+//---------------------------------------------------------------
+
+#include <windows.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <io.h>
+#include <malloc.h>
+
+#include <ole2.h>
+#include "..\idl\itest.h"
+#include <objerror.h>
+#include <dog.h>
+#include <winnt.h> // Security definitions
+
+ /***************************************************************************/
+/* Macros. */
+#define ASSERT( result, message ) \
+if ((result) != 0) \
+{ \
+ printf( "%s: 0x%x\n", (message), result ); \
+ goto cleanup; \
+}
+
+#define ASSERT_EXPR( expr, message ) \
+if (!(expr)) \
+{ \
+ printf( "%s\n", (message) ); \
+ goto cleanup; \
+}
+
+#define ASSERT_THREAD() \
+ if ((ThreadMode == COINIT_SINGLETHREADED || \
+ ThreadMode == COINIT_APARTMENTTHREADED) && \
+ (my_id.process != GetCurrentProcessId() || \
+ my_id.thread != GetCurrentThreadId())) \
+ return RPC_E_WRONG_THREAD;
+
+
+#define MAKE_WIN32( status ) \
+ MAKE_SCODE( SEVERITY_ERROR, FACILITY_WIN32, (status) )
+
+#define MCoCopyProxy (*GCoCopyProxy)
+#define MCoGetCallContext (*GCoGetCallContext)
+#define MCoImpersonateClient (*GCoImpersonateClient)
+#define MCoInitializeSecurity (*GCoInitializeSecurity)
+#define MCoQueryAuthenticationServices (*GCoQueryAuthenticationServices)
+#define MCoQueryClientBlanket (*GCoQueryClientBlanket)
+#define MCoQueryProxyBlanket (*GCoQueryProxyBlanket)
+#define MCoRevertToSelf (*GCoRevertToSelf)
+#define MCoSetProxyBlanket (*GCoSetProxyBlanket)
+#define MCoSwitchCallContext (*GCoSwitchCallContext)
+
+
+ /***************************************************************************/
+/* Definitions. */
+
+#define MAX_CALLS 1000
+#define MAX_THREADS 10
+#define NUM_MARSHAL_LOOP 10
+#define REGISTRY_ENTRY_LEN 256
+#define STATUS_DELAY 2000
+
+const int MAX_NAME = 80;
+const int NUM_CLASS_IDS = 10;
+const int NUM_INTERFACE_IDS = 7;
+
+const char REG_INTERFACE_CLASS[] = "{60000200-76d7-11cf-9af1-0020af6e72f4}";
+const char REG_PROXY_NAME[] = "ITest proxy";
+const char REG_PROXY_DLL[] = "app.exe";
+const char REG_APPID_NAME[] = "Application";
+const char REG_APP_EXE[] = "app.exe";
+const char REG_LOGGED_ON[] = "Interactive User";
+const char REG_CLASS_ID[] = "CLSID\\{60000000-AB0F-101A-B4AE-08002B30612C}";
+const char REG_CLASS_EXE[] = "CLSID\\{60000000-AB0F-101A-B4AE-08002B30612C}\\LocalServer32";
+const char *REG_INTERFACE_NAME[NUM_INTERFACE_IDS] =
+{
+ "ITest",
+ "ITestNoneImp",
+ "ITestConnectImp",
+ "ITestEncryptImp",
+ "ITestNoneId",
+ "ITestConnectId",
+ "ITestEncryptId"
+};
+const char *REG_APP_NAME[NUM_CLASS_IDS] =
+{
+ "Apartment Application with automatic security set to none",
+ "Apartment Application with automatic security set to connect",
+ "Apartment Application with automatic security set to integrity",
+ "Apartment Application with basic security",
+ "Apartment Application with legacy security",
+ "FreeThreaded Application with automatic security set to none",
+ "FreeThreaded Application with automatic security set to connect",
+ "FreeThreaded Application with automatic security set to integrity",
+ "FreeThreaded Application with basic security",
+ "FreeThreaded Application with legacy security",
+};
+const char *REG_APP_OPTIONS[NUM_CLASS_IDS] =
+{
+ " Apartment -auto 1",
+ " Apartment -auto 2",
+ " Apartment -auto 5",
+ " Apartment -basic",
+ " Apartment -legacy",
+ " Multi -auto 1",
+ " Multi -auto 2",
+ " Multi -auto 5",
+ " Multi -basic",
+ " Multi -legacy",
+};
+
+// Private symbols needed for the apartment model.
+#define COINIT_MULTITHREADED 0
+#define COINIT_SINGLETHREADED 1
+#define COINIT_APARTMENTTHREADED 2
+
+typedef enum
+{
+ dirty_s,
+ late_dispatch_s
+} state_en;
+
+typedef enum what_next_en
+{
+ callback_wn,
+ catch_wn,
+ crippled_wn,
+ interrupt_wn,
+ interrupt_marshal_wn,
+ quit_wn,
+ reinitialize_wn,
+ rest_and_die_wn,
+ setup_wn,
+ wait_wn
+} what_next_en;
+
+typedef enum
+{
+ cancel_wt,
+ crash_wt,
+ cstress_wt,
+ hook_wt,
+ load_client_wt,
+ load_server_wt,
+ lots_wt,
+ mmarshal_wt,
+ none_wt,
+ null_wt,
+ one_wt,
+ perf_wt,
+ perfremote_wt,
+ perfrpc_wt,
+ perfsec_wt,
+ post_wt,
+ reject_wt,
+ remote_client_wt,
+ remote_server_wt,
+ ring_wt,
+ rpc_wt,
+ rundown_wt,
+ securerefs_wt,
+ security_wt,
+ send_wt,
+ server_wt,
+ sid_wt,
+ simple_rundown_wt,
+ thread_wt,
+ three_wt,
+ two_wt,
+ uninit_wt,
+ unknown_wt
+} what_test_en;
+
+typedef enum
+{
+ apt_auto_none,
+ apt_auto_connect,
+ apt_auto_integrity,
+ apt_basic,
+ apt_legacy,
+ free_auto_none,
+ free_auto_connect,
+ free_auto_integrity,
+ free_basic,
+ free_legacy
+} class_id_types;
+
+typedef enum
+{
+ auto_sm,
+ basic_sm,
+ legacy_sm
+} security_model;
+
+typedef struct
+{
+ IStream *stream;
+ HANDLE ready;
+} new_apt_params;
+
+typedef struct
+{
+ LONG object_count;
+ what_next_en what_next;
+ BOOL exit_dirty;
+ DWORD sequence;
+} SAptData;
+
+typedef struct
+{
+ unsigned char **buffer;
+ long *buf_size;
+ RPC_STATUS status;
+ ULONG thread;
+} SGetInterface;
+
+typedef HRESULT (*INIT_FN)( void *, ULONG );
+
+typedef void (*SIMPLE_FN)( void * );
+
+typedef HRESULT (*CoInitializeSecurityFn)(
+ SECURITY_DESCRIPTOR *pSecDesc,
+ DWORD cbAuthSvc,
+ SOLE_AUTHENTICATION_SERVICE *asAuthSvc,
+ WCHAR *pPrincName,
+ DWORD dwAuthnLevel,
+ DWORD dwImpLevel,
+ RPC_AUTH_IDENTITY_HANDLE pAuthInfo,
+ DWORD dwCapabilities,
+ void *pReserved );
+typedef HRESULT (*CoQueryAuthenticationServicesFn)( DWORD *pcbAuthSvc,
+ SOLE_AUTHENTICATION_SERVICE **asAuthSvc );
+typedef HRESULT (*CoGetCallContextFn)( REFIID riid, void **ppInterface );
+typedef HRESULT (*CoSwitchCallContextFn)( IUnknown *pNewObject, IUnknown **ppOldObject );
+typedef HRESULT (*CoQueryProxyBlanketFn)(
+ IUnknown *pProxy,
+ DWORD *pwAuthnSvc,
+ DWORD *pAuthzSvc,
+ OLECHAR **pServerPrincName,
+ DWORD *pAuthnLevel,
+ DWORD *pImpLevel,
+ RPC_AUTH_IDENTITY_HANDLE *pAuthInfo,
+ DWORD *pCapabilites );
+typedef HRESULT (*CoSetProxyBlanketFn)(
+ IUnknown *pProxy,
+ DWORD dwAuthnSvc,
+ DWORD dwAuthzSvc,
+ OLECHAR *pServerPrincName,
+ DWORD dwAuthnLevel,
+ DWORD dwImpLevel,
+ RPC_AUTH_IDENTITY_HANDLE *pAuthInfo,
+ DWORD dwCapabilities );
+typedef HRESULT (*CoCopyProxyFn)(
+ IUnknown *pProxy,
+ IUnknown **ppCopy );
+typedef HRESULT (*CoQueryClientBlanketFn)(
+ DWORD *pAuthnSvc,
+ DWORD *pAuthzSvc,
+ OLECHAR **pServerPrincName,
+ DWORD *pAuthnLevel,
+ DWORD *pImpLevel,
+ RPC_AUTHZ_HANDLE *pPrivs,
+ DWORD *pCapabilities );
+typedef HRESULT (*CoImpersonateClientFn)();
+typedef HRESULT (*CoRevertToSelfFn)();
+
+ /***************************************************************************/
+/* Classes */
+
+//+-------------------------------------------------------------------
+//
+// Class: CTestCF
+//
+// Synopsis: Class Factory for CTest
+//
+// Methods: IUnknown - QueryInterface, AddRef, Release
+// IClassFactory - CreateInstance
+//
+//--------------------------------------------------------------------
+
+
+class FAR CTestCF: public IClassFactory
+{
+public:
+
+ // Constructor/Destructor
+ CTestCF();
+ ~CTestCF();
+
+ // IUnknown
+ STDMETHOD (QueryInterface) (REFIID iid, void FAR * FAR * ppv);
+ STDMETHOD_(ULONG,AddRef) ( void );
+ STDMETHOD_(ULONG,Release) ( void );
+
+ // IClassFactory
+ STDMETHODIMP CreateInstance(
+ IUnknown FAR* pUnkOuter,
+ REFIID iidInterface,
+ void FAR* FAR* ppv);
+
+ STDMETHODIMP LockServer(BOOL fLock);
+
+private:
+
+ ULONG ref_count;
+};
+
+//+-------------------------------------------------------------------
+//
+// Class: CAdvise
+//
+// Synopsis: Asynchronous test class
+//
+//--------------------------------------------------------------------
+class CAdvise : public IAdviseSink
+{
+ public:
+ CAdvise();
+ ~CAdvise();
+
+ // IUnknown
+ STDMETHOD (QueryInterface) (REFIID iid, void FAR * FAR * ppv);
+ STDMETHOD_(ULONG,AddRef) ( void );
+ STDMETHOD_(ULONG,Release) ( void );
+
+ // IAdviseSink
+ STDMETHODIMP_(void) OnDataChange( FORMATETC *, STGMEDIUM * );
+ STDMETHODIMP_(void) OnViewChange( DWORD, LONG );
+ STDMETHODIMP_(void) OnRename ( IMoniker * );
+ STDMETHODIMP_(void) OnSave ( void );
+ STDMETHODIMP_(void) OnClose ( void );
+
+ private:
+ ULONG ref_count;
+};
+
+//+----------------------------------------------------------------
+//
+// Class: CHook
+//
+// Purpose: Test channel hooks
+//
+//-----------------------------------------------------------------
+
+class CHook : public IChannelHook
+{
+ public:
+ CHook( REFGUID, DWORD seq );
+
+ STDMETHOD (QueryInterface) ( REFIID riid, LPVOID FAR* ppvObj);
+ STDMETHOD_(ULONG,AddRef) ( void );
+ STDMETHOD_(ULONG,Release) ( void );
+
+ STDMETHOD_(void,ClientGetSize) ( REFGUID, REFIID, ULONG *DataSize );
+ STDMETHOD_(void,ClientFillBuffer)( REFGUID, REFIID, ULONG *DataSize, void *DataBuffer );
+ STDMETHOD_(void,ClientNotify) ( REFGUID, REFIID, ULONG DataSize, void *DataBuffer,
+ DWORD DataRep, HRESULT );
+ STDMETHOD_(void,ServerNotify) ( REFGUID, REFIID, ULONG DataSize, void *DataBuffer,
+ DWORD DataRep );
+ STDMETHOD_(void,ServerGetSize) ( REFGUID, REFIID, HRESULT, ULONG *DataSize );
+ STDMETHOD_(void,ServerFillBuffer)( REFGUID, REFIID, ULONG *DataSize, void *DataBuffer, HRESULT );
+
+ HRESULT check ( DWORD, DWORD, DWORD, DWORD );
+ void check_buf( DWORD size, unsigned char *buf );
+ void fill_buf ( DWORD count, unsigned char *buf );
+ DWORD get_size ( DWORD count );
+
+ private:
+ ULONG ref_count;
+ GUID extent;
+ DWORD sequence;
+ DWORD client_get;
+ DWORD client_fill;
+ DWORD client_notify;
+ DWORD server_get;
+ DWORD server_fill;
+ DWORD server_notify;
+ HRESULT result;
+};
+
+
+//+-------------------------------------------------------------------
+//
+// Class: CTest
+//
+// Synopsis: Test class
+//
+//--------------------------------------------------------------------
+class CTest: public ITest, public IMessageFilter
+{
+public:
+ CTest();
+ ~CTest();
+
+ // IUnknown
+ STDMETHOD (QueryInterface) (REFIID iid, void FAR * FAR * ppv);
+ STDMETHOD_(ULONG,AddRef) ( void );
+ STDMETHOD_(ULONG,Release) ( void );
+
+ // ITest
+ STDMETHOD (align) ( unsigned char x[17] );
+ STDMETHOD (call_canceled) ( long, long, ITest * );
+ STDMETHOD (call_dead) ( void );
+ STDMETHOD (call_me_back) ( ITest *obj );
+ STDMETHOD (call_next) ( void );
+ STDMETHOD (callback) ( void );
+ STDMETHOD (cancel) ( void );
+ STDMETHOD (cancel_now) ( void );
+ STDMETHOD (cancel_pending_call) ( DWORD * );
+ STDMETHOD (cancel_stress) ( ITest *obj );
+ STDMETHOD (catch_at_top) ( BOOL, ITest *, STRING );
+ STDMETHOD (check) ( SAptId );
+ STDMETHOD (check_hook) ( DWORD, DWORD, DWORD, DWORD,
+ DWORD, DWORD, DWORD, DWORD );
+ STDMETHOD (count) ( void );
+ STDMETHOD (crash_out) ( transmit_crash * );
+ STDMETHOD (delegate) ( ITest *, SAptId, HACKSID * );
+ STDMETHOD (exit) ( void );
+ STDMETHOD (forget) ( void );
+ STDMETHOD (get_advise) ( IAdviseSink ** );
+ STDMETHOD (get_data) ( DWORD, unsigned char *, DWORD,
+ unsigned char ** );
+ STDMETHOD (get_id) ( SAptId * );
+ STDMETHOD (get_next) ( ITest **, SAptId * );
+ STDMETHOD (get_next_slowly) ( ITest **, SAptId * );
+ STDMETHOD (get_obj_from_new_apt) ( ITest **, SAptId * );
+ STDMETHOD (get_obj_from_this_apt) ( ITest **, SAptId * );
+ STDMETHOD (get_sid) ( HACKSID ** );
+ STDMETHOD (interface_in) ( ITest * );
+ STDMETHOD (interrupt) ( ITest *, SAptId, BOOL );
+ STDMETHOD (interrupt_marshal) ( ITest *, ITest * );
+ STDMETHOD (make_acl) ( HACKSID * );
+ STDMETHOD (null) ( void );
+ STDMETHOD (out) ( ITest ** );
+ STDMETHOD (pointer) ( DWORD * );
+ STDMETHOD (recurse) ( ITest *, ULONG );
+ STDMETHOD (recurse_disconnect) ( ITest *, ULONG );
+ STDMETHOD (recurse_excp) ( ITest *, ULONG );
+ STDMETHOD (recurse_fatal) ( ITest *, ULONG, ULONG, BOOL );
+ STDMETHOD (recurse_fatal_helper) ( ITest *, ULONG, ULONG, BOOL );
+ STDMETHOD (recurse_interrupt) ( ITest *, ULONG );
+ STDMETHOD (recurse_secure) ( ITest *, ULONG, ULONG, HACKSID * );
+ STDMETHOD (register_hook) ( GUID, DWORD );
+ STDMETHOD (register_message_filter)( BOOL );
+ STDMETHOD (register_rpc) ( WCHAR *, WCHAR ** );
+ STDMETHOD (reinitialize) ( void );
+ STDMETHOD (reject_next) ( void );
+ STDMETHOD (remember) ( ITest *, SAptId );
+ STDMETHOD (rest_and_die) ( void );
+ STDMETHOD (retry_next) ( void );
+ STDMETHOD (ring) ( DWORD );
+ STDMETHOD (secure) ( SAptId, DWORD, DWORD, DWORD, DWORD,
+ STRING, HACKSID *, DWORD * );
+ STDMETHOD (security_performance) ( DWORD *, DWORD *, DWORD *, DWORD * );
+ STDMETHOD (set_state) ( DWORD, DWORD );
+ STDMETHOD (sick) ( ULONG );
+ STDMETHOD (sleep) ( ULONG );
+ STDMETHOD (test) ( ULONG );
+
+ // IMessageFilter
+ STDMETHOD_(DWORD,HandleInComingCall)( DWORD, HTASK, DWORD, LPINTERFACEINFO );
+ STDMETHOD_(DWORD,MessagePending) ( HTASK, DWORD, DWORD );
+ STDMETHOD_(DWORD,RetryRejectedCall) ( HTASK, DWORD, DWORD );
+
+ // Other
+ void assert_unknown();
+
+
+private:
+
+ ULONG ref_count;
+ SAptId my_id;
+ SAptId next_id;
+ ITest *next;
+ BOOL fcancel_next;
+ BOOL freject_next;
+ BOOL fretry_next;
+ BOOL flate_dispatch;
+};
+
+ /***************************************************************************/
+/* Prototypes. */
+DWORD _stdcall apartment_base ( void * );
+void check_for_request ( void );
+HRESULT create_instance ( REFCLSID, ITest **, SAptId * );
+void crippled ( void );
+void decrement_object_count ( void );
+BOOL dirty_thread ( void );
+void do_cancel ( void );
+BOOL do_cancel_helper ( ITest *, SAptId, ITest *, SAptId );
+void do_crash ( void );
+BOOL do_crash_helper ( ITest *, SAptId, ITest *, SAptId );
+void do_cstress ( void );
+void do_hook ( void );
+BOOL do_hook_helper ( BOOL, ITest *, SAptId, ITest * );
+void do_load_client ( void );
+void do_load_server ( void );
+void do_mmarshal ( void );
+void do_null ( void );
+void do_one ( void );
+void do_perf ( void );
+void do_perfremote ( void );
+void do_perfrpc ( void );
+void do_perfsec ( void );
+void do_post ( void );
+void do_reject ( void );
+void do_remote_client ( void );
+void do_remote_server ( void );
+void do_ring ( void );
+void do_rpc ( void );
+void do_rundown ( void );
+BOOL do_rundown1 ( ITest **, SAptId *, DWORD );
+BOOL do_rundown2 ( ITest **, SAptId *, DWORD );
+void do_securerefs ( void );
+BOOL do_securerefs_helper ( ITest ** );
+void do_security ( void );
+BOOL do_security_auto ( void );
+BOOL do_security_call ( ITest *, SAptId, DWORD, DWORD,
+ DWORD, DWORD, SID * );
+BOOL do_security_copy ( ITest *, SAptId );
+BOOL do_security_delegate ( ITest *, SAptId, ITest *, SAptId );
+BOOL do_security_handle ( ITest *, SAptId );
+BOOL do_security_lazy_call ( ITest *, SAptId, DWORD, DWORD,
+ DWORD, DWORD, SID * );
+BOOL do_security_nested ( ITest *, SAptId );
+void do_send ( void );
+void do_sid ( void );
+void do_simple_rundown ( void );
+void do_thread ( void );
+void do_three ( void );
+void do_two ( void );
+void do_uninit ( void );
+DWORD _stdcall do_uninit_helper ( void *param );
+void do_unknown ( void );
+BOOL do_unknown_call ( IUnknown *, DWORD, DWORD, REFIID );
+BOOL do_unknown_helper ( IUnknown *server );
+void *Fixup ( char * );
+WINOLEAPI FixupCoCopyProxy ( IUnknown *, IUnknown ** );
+WINOLEAPI FixupCoGetCallContext ( REFIID, void ** );
+WINOLEAPI FixupCoImpersonateClient ();
+WINOLEAPI FixupCoInitializeSecurity ( SECURITY_DESCRIPTOR *, DWORD, SOLE_AUTHENTICATION_SERVICE *, WCHAR *, DWORD, DWORD, RPC_AUTH_IDENTITY_HANDLE, DWORD, void * );
+WINOLEAPI FixupCoQueryAuthenticationServices ( DWORD *, SOLE_AUTHENTICATION_SERVICE ** );
+WINOLEAPI FixupCoQueryClientBlanket ( DWORD *, DWORD *, OLECHAR **, DWORD *, DWORD *, RPC_AUTHZ_HANDLE *, DWORD * );
+WINOLEAPI FixupCoQueryProxyBlanket ( IUnknown *, DWORD *, DWORD *, OLECHAR **, DWORD *, DWORD *, RPC_AUTH_IDENTITY_HANDLE *, DWORD * );
+WINOLEAPI FixupCoRevertToSelf ();
+WINOLEAPI FixupCoSetProxyBlanket ( IUnknown *, DWORD, DWORD, OLECHAR *, DWORD, DWORD, RPC_AUTH_IDENTITY_HANDLE *, DWORD );
+WINOLEAPI FixupCoSwitchCallContext ( IUnknown *, IUnknown ** );
+DWORD get_sequence ( void );
+void hello ( char * );
+void increment_object_count ( void );
+HRESULT initialize ( void *, ULONG );
+HRESULT initialize_security ( void );
+void interrupt ( void );
+HRESULT new_apartment_test ( ITest **, SAptId *, HANDLE * );
+BOOL parse ( int argc, char *argv[] );
+BOOL registry_setup ( char * );
+void reinitialize ( void );
+void server_loop ( void );
+DWORD _stdcall status_helper ( void * );
+HRESULT switch_thread ( SIMPLE_FN, void * );
+void switch_test ( void );
+void thread_get_interface_buffer( handle_t binding, long *buf_size,
+ unsigned char **buffer, SAptId *id,
+ error_status_t *status );
+DWORD _stdcall thread_helper ( void * );
+void wait_for_message ( void );
+void wake_up_and_smell_the_roses( void );
+void what_next ( what_next_en );
+
+
+ /***************************************************************************/
+/* Externals. */
+const IID ClassIds[NUM_CLASS_IDS] =
+{
+ {0x60000000, 0xAB0F, 0x101A, {0xB4, 0xAE, 0x08, 0x00, 0x2B, 0x30, 0x61, 0x2C}},
+ {0x60000001, 0xAB0F, 0x101A, {0xB4, 0xAE, 0x08, 0x00, 0x2B, 0x30, 0x61, 0x2C}},
+ {0x60000002, 0xAB0F, 0x101A, {0xB4, 0xAE, 0x08, 0x00, 0x2B, 0x30, 0x61, 0x2C}},
+ {0x60000003, 0xAB0F, 0x101A, {0xB4, 0xAE, 0x08, 0x00, 0x2B, 0x30, 0x61, 0x2C}},
+ {0x60000004, 0xAB0F, 0x101A, {0xB4, 0xAE, 0x08, 0x00, 0x2B, 0x30, 0x61, 0x2C}},
+ {0x60000005, 0xAB0F, 0x101A, {0xB4, 0xAE, 0x08, 0x00, 0x2B, 0x30, 0x61, 0x2C}},
+ {0x60000006, 0xAB0F, 0x101A, {0xB4, 0xAE, 0x08, 0x00, 0x2B, 0x30, 0x61, 0x2C}},
+ {0x60000007, 0xAB0F, 0x101A, {0xB4, 0xAE, 0x08, 0x00, 0x2B, 0x30, 0x61, 0x2C}},
+ {0x60000008, 0xAB0F, 0x101A, {0xB4, 0xAE, 0x08, 0x00, 0x2B, 0x30, 0x61, 0x2C}},
+ {0x60000009, 0xAB0F, 0x101A, {0xB4, 0xAE, 0x08, 0x00, 0x2B, 0x30, 0x61, 0x2C}},
+};
+
+/* Globals. */
+BOOL Change = FALSE;
+CTestCF *ClassFactory;
+char Debugger[MAX_PATH+MAX_PATH] = "";
+HANDLE Done;
+CoCopyProxyFn GCoCopyProxy = FixupCoCopyProxy;
+CoGetCallContextFn GCoGetCallContext = FixupCoGetCallContext;
+CoImpersonateClientFn GCoImpersonateClient = FixupCoImpersonateClient;
+CoInitializeSecurityFn GCoInitializeSecurity = FixupCoInitializeSecurity;
+CoQueryAuthenticationServicesFn GCoQueryAuthenticationServices = FixupCoQueryAuthenticationServices;
+CoQueryClientBlanketFn GCoQueryClientBlanket = FixupCoQueryClientBlanket;
+CoQueryProxyBlanketFn GCoQueryProxyBlanket = FixupCoQueryProxyBlanket;
+CoRevertToSelfFn GCoRevertToSelf = FixupCoRevertToSelf;
+CoSetProxyBlanketFn GCoSetProxyBlanket = FixupCoSetProxyBlanket;
+CoSwitchCallContextFn GCoSwitchCallContext = FixupCoSwitchCallContext;
+DWORD GlobalAuthnLevel = RPC_C_AUTHN_LEVEL_NONE;
+SAptId GlobalApt;
+WCHAR *GlobalBinding;
+BOOL GlobalBool;
+long GlobalCalls = 0;
+long GlobalClients = 0;
+LONG GlobalFirst = TRUE;
+CHook *GlobalHook1 = NULL;
+CHook *GlobalHook2 = NULL;
+BOOL GlobalInterruptTest;
+SECURITY_DESCRIPTOR *GlobalSecurityDescriptor = NULL;
+security_model GlobalSecurityModel = auto_sm;
+ITest *GlobalTest = NULL;
+ITest *GlobalTest2 = NULL;
+ULONG GlobalThreadId = 0;
+long GlobalTotal = 0;
+BOOL GlobalWaiting = FALSE;
+DWORD MainThread;
+BOOL Multicall_Test;
+WCHAR Name[MAX_NAME] = L"";
+DWORD NestedCallCount = 0;
+int NumIterations = 1000;
+int NumObjects = 2;
+int NumProcesses = 2;
+int NumRecursion = 2;
+int NumThreads = 2;
+BOOL Popup = FALSE;
+SAptData ProcessAptData;
+SID *ProcessSid;
+HANDLE RawEvent = NULL;
+HRESULT RawResult;
+DWORD Registration;
+const IID *ServerClsid = &ClassIds[apt_auto_none];
+WCHAR TestProtseq[MAX_NAME] = L"ncadg_ip_udp";
+DWORD ThreadMode = COINIT_APARTMENTTHREADED;
+DWORD TlsIndex;
+what_test_en WhatTest;
+BOOL WriteClass = FALSE;
+
+
+ /***************************************************************************/
+STDMETHODIMP_(ULONG) CAdvise::AddRef( THIS )
+{
+ InterlockedIncrement( (long *) &ref_count );
+ return ref_count;
+}
+
+ /***************************************************************************/
+CAdvise::CAdvise()
+{
+ ref_count = 1;
+ increment_object_count();
+}
+
+ /***************************************************************************/
+CAdvise::~CAdvise()
+{
+}
+
+ /***************************************************************************/
+STDMETHODIMP_(void) CAdvise::OnClose( void )
+{
+}
+
+ /***************************************************************************/
+STDMETHODIMP_(void) CAdvise::OnDataChange( FORMATETC *format, STGMEDIUM *stg )
+{
+}
+
+ /***************************************************************************/
+STDMETHODIMP_(void) CAdvise::OnRename( IMoniker *moniker )
+{
+}
+
+ /***************************************************************************/
+STDMETHODIMP_(void) CAdvise::OnSave( void )
+{
+}
+
+ /***************************************************************************/
+STDMETHODIMP_(void) CAdvise::OnViewChange( DWORD aspect, LONG index )
+{
+}
+
+ /***************************************************************************/
+STDMETHODIMP CAdvise::QueryInterface( THIS_ REFIID riid, LPVOID FAR* ppvObj)
+{
+ if (IsEqualIID(riid, IID_IUnknown) ||
+ IsEqualIID(riid, IID_IAdviseSink))
+ {
+ *ppvObj = (IUnknown *) (IAdviseSink *) this;
+ AddRef();
+ return S_OK;
+ }
+ else
+ {
+ *ppvObj = NULL;
+ return E_NOINTERFACE;
+ }
+}
+
+ /***************************************************************************/
+STDMETHODIMP_(ULONG) CAdvise::Release( THIS )
+{
+ if (InterlockedDecrement( (long*) &ref_count ) == 0)
+ {
+ decrement_object_count();
+ delete this;
+ return 0;
+ }
+ else
+ return ref_count;
+}
+
+ /***************************************************************************/
+STDMETHODIMP_(ULONG) CHook::AddRef( THIS )
+{
+ InterlockedIncrement( (long *) &ref_count );
+ return ref_count;
+}
+
+ /***************************************************************************/
+HRESULT CHook::check( DWORD cget, DWORD cnot, DWORD sget, DWORD snot )
+{
+ if (result != S_OK)
+ return result;
+ if (cget != client_get || cnot != client_notify ||
+ sget != server_get || snot != server_notify)
+ return E_INVALIDARG;
+ return S_OK;
+}
+
+ /***************************************************************************/
+void CHook::check_buf( DWORD size, unsigned char *buf )
+{
+ DWORD i;
+
+ if (sequence == 1)
+ {
+ if (size == 1)
+ {
+ if (*buf != 1)
+ goto error;
+ }
+ else if (size == 1000)
+ {
+ for (i = 0; i < size; i++)
+ if (buf[i] != 255)
+ goto error;
+ }
+ else if (size != 0)
+ goto error;
+ }
+ else if (sequence == 2)
+ {
+ for (i = 0; i < size; i++)
+ if (buf[i] != (unsigned char) i)
+ goto error;
+ }
+ else
+ {
+ if (size != 42)
+ goto error;
+ i = 0;
+ while (i < 42)
+ if (buf[i++] != '4' || buf[i++] != '2')
+ goto error;
+ }
+
+ return;
+error:
+ printf( "Hook got bad data.\n" );
+ result = E_UNEXPECTED;
+}
+
+ /***************************************************************************/
+CHook::CHook( REFGUID ext, DWORD seq )
+{
+ extent = ext;
+ sequence = seq;
+ ref_count = 1;
+ client_get = 0;
+ client_fill = 0;
+ client_notify = 0;
+ server_get = 0;
+ server_fill = 0;
+ server_notify = 0;
+ result = S_OK;
+}
+
+ /***************************************************************************/
+STDMETHODIMP_(void) CHook::ClientGetSize( REFGUID ext, REFIID riid,
+ ULONG *size )
+{
+ // Check the parameters.
+ if (extent != ext)
+ {
+ printf( "Hook received the wrong extent.\n" );
+ result = E_FAIL;
+ }
+
+ // Return the correct size for each sequence.
+ client_get += 1;
+ *size = get_size( client_get );
+}
+
+ /***************************************************************************/
+STDMETHODIMP_(void) CHook::ClientFillBuffer( REFGUID ext, REFIID riid,
+ ULONG *max, void *buffer )
+{
+ DWORD size = get_size( client_get );
+
+ // Check the parameters.
+ if (extent != ext)
+ {
+ printf( "Hook received the wrong extent.\n" );
+ result = E_FAIL;
+ }
+ else if (*max < size)
+ {
+ printf( "Hook lost space.\n" );
+ result = E_OUTOFMEMORY;
+ }
+
+ // Fill the buffer.
+ *max = size;
+ client_fill += 1;
+ fill_buf( client_get, (unsigned char *) buffer );
+}
+
+ /***************************************************************************/
+STDMETHODIMP_(void) CHook::ClientNotify( REFGUID ext, REFIID riid,
+ ULONG size, void *buffer,
+ DWORD data_rep, HRESULT result )
+{
+ // Verify the parameters.
+ if (extent != ext)
+ {
+ printf( "Hook received the wrong extent.\n" );
+ result = E_FAIL;
+ }
+
+ // Verify the data.
+ client_notify += 1;
+ if (result == S_OK && buffer != NULL)
+ check_buf( size, (unsigned char *) buffer );
+}
+
+ /***************************************************************************/
+void CHook::fill_buf( DWORD count, unsigned char *buffer )
+{
+ DWORD size = get_size( count );
+ DWORD i;
+
+ if (sequence == 1)
+ {
+ if (size == 1)
+ *buffer = 1;
+ else
+ for (i = 0; i < size; i++)
+ buffer[i] = 255;
+ }
+ else if (sequence == 2)
+ {
+ for (i = 0; i < size; i++)
+ buffer[i] = i;
+ }
+ else
+ {
+ i = 0;
+ while (i < 42)
+ {
+ buffer[i++] = '4';
+ buffer[i++] = '2';
+ }
+ }
+}
+
+ /***************************************************************************/
+DWORD CHook::get_size( DWORD count )
+{
+ DWORD size;
+
+ if (sequence == 1)
+ {
+ size = count % 3;
+ if (size == 2)
+ size = 1000;
+ return size;
+ }
+ else if (sequence == 2)
+ return count;
+ else
+ return 42;
+}
+
+ /***************************************************************************/
+STDMETHODIMP CHook::QueryInterface( THIS_ REFIID riid, LPVOID FAR* ppvObj)
+{
+ if (IsEqualIID(riid, IID_IUnknown) ||
+ IsEqualIID(riid, IID_IChannelHook))
+ {
+ *ppvObj = (IUnknown *) this;
+ AddRef();
+ return S_OK;
+ }
+ else
+ {
+ *ppvObj = NULL;
+ return E_NOINTERFACE;
+ }
+}
+
+ /***************************************************************************/
+STDMETHODIMP_(ULONG) CHook::Release( THIS )
+{
+ if (InterlockedDecrement( (long*) &ref_count ) == 0)
+ {
+ delete this;
+ return 0;
+ }
+ else
+ return ref_count;
+}
+
+ /***************************************************************************/
+STDMETHODIMP_(void) CHook::ServerNotify( REFGUID ext, REFIID riid,
+ ULONG size, void *buffer,
+ DWORD data_rep )
+{
+ // Verify the parameters.
+ if (extent != ext)
+ {
+ printf( "Hook received the wrong extent.\n" );
+ result = E_FAIL;
+ }
+
+ // Verify the data.
+ server_notify += 1;
+ if (result == S_OK && buffer != NULL)
+ check_buf( size, (unsigned char *) buffer );
+}
+
+ /***************************************************************************/
+STDMETHODIMP_(void) CHook::ServerGetSize( REFGUID ext, REFIID riid, HRESULT hr,
+ ULONG *size )
+{
+ // Check the parameters.
+ if (extent != ext)
+ {
+ printf( "Hook received the wrong extent.\n" );
+ result = E_FAIL;
+ }
+
+ // Return the correct size for each sequence.
+ server_get += 1;
+ *size = get_size( server_get );
+}
+
+ /***************************************************************************/
+STDMETHODIMP_(void) CHook::ServerFillBuffer( REFGUID ext, REFIID riid,
+ ULONG *max, void *buffer, HRESULT hr )
+{
+ DWORD size = get_size( server_get );
+
+ // Check the parameters.
+ if (extent != ext)
+ {
+ printf( "Hook received the wrong extent.\n" );
+ result = E_FAIL;
+ }
+ else if (*max < size)
+ {
+ printf( "Hook lost space.\n" );
+ result = E_OUTOFMEMORY;
+ }
+
+ // Fill the buffer.
+ *max = size;
+ server_fill += 1;
+ fill_buf( server_get, (unsigned char *) buffer );
+}
+
+ /***************************************************************************/
+STDMETHODIMP_(ULONG) CTest::AddRef( THIS )
+{
+ assert_unknown();
+ InterlockedIncrement( (long *) &ref_count );
+ return ref_count;
+}
+
+ /***************************************************************************/
+STDMETHODIMP CTest::align( unsigned char x[17] )
+{
+ ASSERT_THREAD();
+ return S_OK;
+}
+
+ /***************************************************************************/
+void CTest::assert_unknown()
+{
+ if ((ThreadMode == COINIT_SINGLETHREADED ||
+ ThreadMode == COINIT_APARTMENTTHREADED) &&
+ (my_id.process != GetCurrentProcessId() ||
+ my_id.thread != GetCurrentThreadId()))
+ {
+ printf( "**************************************************************\n" );
+ printf( "**************************************************************\n" );
+ printf( "* Unknown called on wrong thread. *\n" );
+ printf( "**************************************************************\n" );
+ printf( "**************************************************************\n" );
+ }
+}
+
+ /***************************************************************************/
+STDMETHODIMP CTest::call_canceled( long recurse, long cancel,
+ ITest *callback )
+{
+ HRESULT result = S_OK;
+ DWORD wakeup;
+ DWORD sleep;
+ DWORD reason;
+ MSG msg;
+ ASSERT_THREAD();
+
+ // If the recursion count isn't zero, call back.
+ if (recurse > 0)
+ {
+ result = callback->call_canceled( recurse-1, cancel, this );
+ if (recurse <= cancel)
+ {
+ if (result != RPC_E_CALL_CANCELED &&
+ result != MAKE_WIN32( RPC_S_CALL_CANCELLED ))
+ if (result == S_OK)
+ return E_FAIL;
+ else
+ return result;
+ result = S_OK;
+ }
+ else if (result != S_OK)
+ return result;
+ }
+
+ // If the cancel count is greater then the recursion count, cancel the
+ // object that called me.
+ if (cancel > recurse)
+ {
+ // Give the other object a chance to finish canceling me before I cancel
+ // him.
+ printf( "Waiting 10 seconds before canceling.\n" );
+ Sleep(10000);
+ result = next->cancel();
+
+ // Give the cancel a chance to complete before returning.
+ printf( "Waiting 5 seconds for cancel to complete.\n" );
+ wakeup = GetCurrentTime() + 5000;
+ sleep = 5000;
+ do
+ {
+ reason = MsgWaitForMultipleObjects( 0, NULL, FALSE, sleep, QS_ALLINPUT );
+ sleep = wakeup - GetCurrentTime();
+ if (sleep > 5000)
+ sleep = 0;
+ if (reason != WAIT_TIMEOUT)
+ if (GetMessageA( &msg, NULL, 0, 0 ))
+ {
+ TranslateMessage (&msg);
+ DispatchMessageA (&msg);
+ }
+ } while (sleep != 0);
+ }
+ return result;
+}
+
+ /***************************************************************************/
+STDMETHODIMP CTest::call_dead( void )
+{
+ HRESULT result;
+ ASSERT_THREAD();
+
+ // Call the server, who is dead by now.
+ result = next->check( next_id );
+ next->Release();
+ next = NULL;
+ if (SUCCEEDED(result))
+ return E_FAIL;
+ else
+ return S_OK;
+}
+
+ /***************************************************************************/
+STDMETHODIMP CTest::call_me_back( ITest *test )
+{
+ ASSERT_THREAD();
+
+ // Save the global object and tell the driver loop what to do next.
+ test->AddRef();
+ GlobalTest = test;
+ what_next( callback_wn );
+ wake_up_and_smell_the_roses();
+ return S_OK;
+}
+
+ /***************************************************************************/
+STDMETHODIMP CTest::call_next( void )
+{
+ HRESULT result;
+ ASSERT_THREAD();
+
+ // Call the neighbor.
+ return next->check( next_id );
+}
+
+ /***************************************************************************/
+STDMETHODIMP CTest::callback( void )
+{
+ ASSERT_THREAD();
+ GlobalWaiting = FALSE;
+ return S_OK;
+}
+
+ /***************************************************************************/
+STDMETHODIMP CTest::cancel()
+{
+ HRESULT result;
+ DWORD thread;
+ ASSERT_THREAD();
+
+ // Tell my neighbor to cancel the current call next time he receives a
+ // message on his message queue.
+ result = next->cancel_pending_call( &thread );
+
+ // Put a message on my neighbor's message queue.
+ if (result == S_OK)
+ {
+ if (!PostThreadMessageA( thread, WM_USER, 0, 0 ))
+ return E_FAIL;
+ }
+ return result;
+}
+
+ /***************************************************************************/
+STDMETHODIMP CTest::cancel_now()
+{
+ HRESULT result;
+
+ return next->cancel();
+}
+
+ /***************************************************************************/
+STDMETHODIMP CTest::cancel_pending_call( DWORD *thread )
+{
+ ASSERT_THREAD();
+ fcancel_next = TRUE;
+ *thread = GetCurrentThreadId();
+ return S_OK;
+}
+
+ /***************************************************************************/
+STDMETHODIMP CTest::cancel_stress( ITest *obj )
+{
+ HRESULT result;
+
+ ASSERT_THREAD();
+
+ // If there is an object, ask it to cancel the call to it.
+ if (obj != NULL)
+ result = obj->cancel_now();
+
+ // Otherwise ask my neighbor to cancel the call to him.
+ else
+ // This only works locally.
+ result = next->cancel();
+
+ // Although the call should have been canceled, sometimes it completes
+ // before the cancel does.
+ if (result == S_OK || result == RPC_E_CALL_CANCELED ||
+ result == MAKE_WIN32( RPC_S_CALL_CANCELLED ))
+ return S_OK;
+ else
+ return result;
+}
+
+ /***************************************************************************/
+STDMETHODIMP CTest::catch_at_top( BOOL catchme, ITest *callback, STRING binding )
+{
+ // Save the callback object and the binding.
+ callback->AddRef();
+ GlobalTest = callback;
+ GlobalBinding = binding;
+
+ // If the catch flag is true, tell the top level message loop to catch
+ // exceptions.
+ what_next( catch_wn );
+ wake_up_and_smell_the_roses();
+ return S_OK;
+}
+
+ /***************************************************************************/
+STDMETHODIMP CTest::check( SAptId id )
+{
+ ASSERT_THREAD();
+ if (my_id.process == id.process && my_id.thread == id.thread &&
+ my_id.sequence == id.sequence)
+ return S_OK;
+ else
+ return E_FAIL;
+}
+
+ /***************************************************************************/
+STDMETHODIMP CTest::check_hook( DWORD cg1, DWORD cn1, DWORD sg1, DWORD sn1,
+ DWORD cg2, DWORD cn2, DWORD sg2, DWORD sn2 )
+{
+ HRESULT result;
+ ASSERT_THREAD();
+ result = GlobalHook1->check( cg1, cn1, sg1, sn1 );
+ if (result == S_OK && GlobalHook2 != NULL)
+ result = GlobalHook2->check( cg2, cn2, sg2, sn2 );
+ return result;
+}
+
+ /***************************************************************************/
+STDMETHODIMP CTest::count()
+{
+ InterlockedIncrement( &GlobalCalls );
+ return S_OK;
+}
+
+ /***************************************************************************/
+STDMETHODIMP CTest::crash_out( transmit_crash *x )
+{
+ *x = 0;
+ return S_OK;
+}
+
+ /***************************************************************************/
+CTest::CTest()
+{
+ ref_count = 1;
+ next = NULL;
+ fcancel_next = FALSE;
+ freject_next = FALSE;
+ fretry_next = FALSE;
+ flate_dispatch = FALSE;
+ my_id.sequence = get_sequence();
+ my_id.thread = GetCurrentThreadId();
+ my_id.process = GetCurrentProcessId();
+ increment_object_count();
+}
+
+ /***************************************************************************/
+CTest::~CTest()
+{
+ if (next != NULL)
+ if (!dirty_thread())
+ next->Release();
+}
+
+ /***************************************************************************/
+STDMETHODIMP CTest::delegate( ITest *obj, SAptId id, HACKSID *sid )
+{
+ HRESULT result = S_OK;
+ DWORD ignore;
+
+ ASSERT_THREAD();
+
+ // Impersonate.
+ result = MCoImpersonateClient();
+ ASSERT( result, "Could not impersonate" );
+
+ // Set the security for the next call.
+ result = MCoSetProxyBlanket( obj, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE,
+ NULL, RPC_C_AUTHN_LEVEL_CONNECT,
+ RPC_C_IMP_LEVEL_IMPERSONATE, NULL,
+ EOAC_NONE );
+ ASSERT( result, "Could not set blanket" );
+
+ // Call the final server.
+ result = obj->secure( id, RPC_C_AUTHN_LEVEL_CONNECT,
+ RPC_C_IMP_LEVEL_IMPERSONATE, RPC_C_AUTHN_WINNT,
+ RPC_C_AUTHZ_NONE, NULL, sid, &ignore );
+ ASSERT( result, "Could not make delegate call" );
+
+cleanup:
+ return result;
+}
+
+ /***************************************************************************/
+STDMETHODIMP CTest::exit( void )
+{
+ what_next( quit_wn );
+ wake_up_and_smell_the_roses();
+ ASSERT_THREAD();
+ return S_OK;
+}
+
+ /***************************************************************************/
+STDMETHODIMP CTest::forget( void )
+{
+ ASSERT_THREAD();
+ if (next != NULL)
+ {
+ next->Release();
+ next = NULL;
+ }
+ return S_OK;
+}
+
+ /***************************************************************************/
+STDMETHODIMP CTest::get_advise( IAdviseSink **obj )
+{
+ *obj = NULL;
+ ASSERT_THREAD();
+ *obj = new CAdvise;
+ if (*obj!= NULL)
+ return S_OK;
+ else
+ return E_FAIL;
+}
+
+ /***************************************************************************/
+STDMETHODIMP CTest::get_data( DWORD isize, unsigned char *idata, DWORD osize,
+ unsigned char **odata )
+{
+ *odata = (unsigned char *) CoTaskMemAlloc( 1 );
+ return S_OK;
+}
+
+ /***************************************************************************/
+STDMETHODIMP CTest::get_id( SAptId *id )
+{
+ ASSERT_THREAD();
+ *id = my_id;
+ return S_OK;
+}
+
+ /***************************************************************************/
+STDMETHODIMP CTest::get_next( ITest **obj, SAptId *id )
+{
+ *obj = NULL;
+ ASSERT_THREAD();
+ *id = next_id;
+ *obj = next;
+ if (next != NULL)
+ next->AddRef();
+ return S_OK;
+}
+
+ /***************************************************************************/
+STDMETHODIMP CTest::get_next_slowly( ITest **obj, SAptId *id )
+{
+ *obj = NULL;
+ ASSERT_THREAD();
+ *id = next_id;
+ *obj = next;
+ if (next != NULL)
+ next->AddRef();
+
+ // Start shutting down.
+ exit();
+
+ // Wait a while.
+ SetEvent( RawEvent );
+ Sleep( 5000 );
+ return S_OK;
+}
+
+ /***************************************************************************/
+STDMETHODIMP CTest::get_obj_from_new_apt( ITest **obj, SAptId *id )
+{
+ *obj = NULL;
+ ASSERT_THREAD();
+ return new_apartment_test( obj, id, NULL );
+}
+
+ /***************************************************************************/
+STDMETHODIMP CTest::get_obj_from_this_apt( ITest **obj, SAptId *id )
+{
+ *obj = NULL;
+ ASSERT_THREAD();
+ *obj = new CTest;
+ if (*obj!= NULL)
+ return (*obj)->get_id( id );
+ else
+ return E_FAIL;
+}
+
+ /***************************************************************************/
+STDMETHODIMP CTest::get_sid( HACKSID **sid )
+{
+ // Allocate memory to return the sid.
+ *sid = (HACKSID *) CoTaskMemAlloc( GetLengthSid( ProcessSid ) );
+ if (*sid == NULL)
+ return E_OUTOFMEMORY;
+
+ // Copy it.
+ memcpy( *sid, ProcessSid, GetLengthSid( ProcessSid ) );
+ return S_OK;
+}
+
+ /***************************************************************************/
+STDMETHODIMP_(DWORD) CTest::HandleInComingCall( DWORD type, HTASK task,
+ DWORD tick,
+ LPINTERFACEINFO info )
+{
+ if (freject_next)
+ {
+ freject_next = FALSE;
+ return SERVERCALL_REJECTED;
+ }
+
+ // Accept everything.
+ else
+ return SERVERCALL_ISHANDLED;
+}
+
+ /***************************************************************************/
+STDMETHODIMP CTest::interface_in( ITest *test )
+{
+ return S_OK;
+}
+
+ /***************************************************************************/
+STDMETHODIMP CTest::interrupt( ITest *param, SAptId id, BOOL go )
+{
+ ASSERT_THREAD();
+ GlobalInterruptTest = go;
+ if (go)
+ {
+ GlobalTest = param;
+ GlobalApt = id;
+ GlobalTest->AddRef();
+ what_next( interrupt_wn );
+ wake_up_and_smell_the_roses();
+ }
+ else
+ what_next( wait_wn );
+ return S_OK;
+}
+
+ /***************************************************************************/
+STDMETHODIMP CTest::interrupt_marshal( ITest *obj1, ITest *obj2 )
+{
+ ASSERT_THREAD();
+ GlobalTest = obj1;
+ GlobalTest2 = obj2;
+ GlobalTest->AddRef();
+ GlobalTest2->AddRef();
+ what_next( interrupt_marshal_wn );
+ wake_up_and_smell_the_roses();
+ return S_OK;
+}
+
+ /***************************************************************************/
+STDMETHODIMP CTest::make_acl( HACKSID *allow )
+{
+ BOOL success = FALSE;
+ BOOL call_success = FALSE;
+ PACL pACLNew = NULL;
+ DWORD cbACL = 1024;
+ PRIVILEGE_SET set;
+ DWORD granted_access;
+ BOOL access;
+ DWORD privilege_size;
+ HANDLE token = NULL;
+ HRESULT result = E_FAIL;
+ LUID audit;
+ TOKEN_PRIVILEGES privilege;
+ SID *copy = NULL;
+ DWORD length;
+
+ // Open the process's token.
+ call_success = OpenProcessToken( GetCurrentProcess(),
+ TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
+ &token );
+ result = GetLastError();
+ ASSERT( result, "Could not OpenProcessToken" );
+ ASSERT_EXPR( call_success, "Could not OpenProcessToken." );
+
+ // Lookup the audit privilege.
+ call_success = LookupPrivilegeValue( NULL, SE_AUDIT_NAME, &audit );
+ result = GetLastError();
+ ASSERT( result, "Could not LookupPrivilegeValue" );
+
+ // Enable it.
+ privilege.PrivilegeCount = 1;
+ privilege.Privileges[0].Luid = audit;
+ privilege.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
+ AdjustTokenPrivileges( token, FALSE, &privilege, sizeof(privilege), NULL,
+ NULL );
+ result = GetLastError();
+ ASSERT( result, "Could not AdjustTokenPrivileges" );
+
+ // Copy the SID.
+ length = GetLengthSid( (SID *) allow );
+ copy = (SID *) malloc( length );
+ ASSERT_EXPR( copy != NULL, "Could not allocate memory." );
+ memcpy( copy, allow, length );
+
+ // Initialize a new security descriptor.
+ GlobalSecurityDescriptor = (SECURITY_DESCRIPTOR *) LocalAlloc(LPTR,
+ SECURITY_DESCRIPTOR_MIN_LENGTH);
+ ASSERT_EXPR( GlobalSecurityDescriptor != NULL, "Could not allocate memory for the security descriptor." );
+ call_success = InitializeSecurityDescriptor(GlobalSecurityDescriptor,
+ SECURITY_DESCRIPTOR_REVISION);
+ ASSERT_EXPR( call_success, "InitializeSecurityDescriptor" );
+
+ // Initialize a new ACL.
+ pACLNew = (PACL) LocalAlloc(LPTR, cbACL);
+ ASSERT_EXPR( pACLNew != NULL, "LocalAlloc" );
+ call_success = InitializeAcl(pACLNew, cbACL, ACL_REVISION2);
+ ASSERT_EXPR( call_success, "InitializeAcl" );
+
+ // Allow read but not write access to the file.
+ call_success = AddAccessAllowedAce( pACLNew, ACL_REVISION2, READ_CONTROL,
+ copy );
+ ASSERT_EXPR( call_success, "AddAccessAllowedAce failed." );
+
+ // Add a new ACL to the security descriptor.
+ call_success = SetSecurityDescriptorDacl(GlobalSecurityDescriptor,
+ TRUE, /* fDaclPresent flag */
+ pACLNew,
+ FALSE);
+ result = GetLastError();
+ ASSERT( result, "SetSecurityDescriptorDacl failed" );
+ ASSERT_EXPR( call_success, "SetSecurityDescriptorDacl failed." );
+
+ // Set the group.
+ call_success = SetSecurityDescriptorGroup( GlobalSecurityDescriptor,
+ copy, FALSE );
+ ASSERT_EXPR( call_success, "SetSecurityDescriptorGroup failed." );
+
+ // Set the owner.
+ call_success = SetSecurityDescriptorOwner( GlobalSecurityDescriptor,
+ copy, FALSE );
+ ASSERT_EXPR( call_success, "SetSecurityDescriptorOwner failed." );
+
+ // Check the security descriptor.
+ call_success = IsValidSecurityDescriptor( GlobalSecurityDescriptor );
+ ASSERT_EXPR( call_success, "IsValidSecurityDescriptor failed." );
+
+ success = TRUE;
+cleanup:
+ if (!success)
+ {
+ if(GlobalSecurityDescriptor != NULL)
+ LocalFree((HLOCAL) GlobalSecurityDescriptor);
+ if(pACLNew != NULL)
+ LocalFree((HLOCAL) pACLNew);
+ if (copy != NULL)
+ free( copy );
+ }
+
+ if (token != NULL)
+ CloseHandle( token );
+
+ if (success)
+ return S_OK;
+ else if (result != S_OK)
+ return result;
+ else
+ return E_FAIL;
+}
+
+ /***************************************************************************/
+STDMETHODIMP_(DWORD) CTest::MessagePending( HTASK callee, DWORD tick,
+ DWORD type )
+{
+ if (fcancel_next)
+ {
+ fcancel_next = FALSE;
+ return PENDINGMSG_CANCELCALL;
+ }
+ else
+ return PENDINGMSG_WAITDEFPROCESS;
+}
+
+ /***************************************************************************/
+STDMETHODIMP CTest::QueryInterface( THIS_ REFIID riid, LPVOID FAR* ppvObj)
+{
+ HRESULT result = S_OK;
+ DWORD query_authn_level;
+ BOOL success;
+ char value[REGISTRY_ENTRY_LEN];
+ LONG value_size = sizeof(value);
+ HANDLE token;
+
+ ASSERT_THREAD();
+ *ppvObj = NULL;
+
+ // Return the normal interfaces.
+ if (IsEqualIID(riid, IID_IUnknown) ||
+ IsEqualIID(riid, IID_ITest))
+ {
+ *ppvObj = (IUnknown *) (ITest *) this;
+ AddRef();
+ return S_OK;
+ }
+
+ // Return the message filter.
+ else if (IsEqualIID(riid, IID_IMessageFilter))
+ {
+ *ppvObj = (IUnknown *) (IMessageFilter *) this;
+ AddRef();
+ return S_OK;
+ }
+
+ // Check security and return ITest.
+ else if (IsEqualIID( riid, IID_ITestNoneImp ) ||
+ IsEqualIID( riid, IID_ITestConnectImp ) ||
+ IsEqualIID( riid, IID_ITestEncryptImp ) ||
+ IsEqualIID( riid, IID_ITestNoneId ) ||
+ IsEqualIID( riid, IID_ITestConnectId ) ||
+ IsEqualIID( riid, IID_ITestEncryptId ))
+ {
+ // Get the authentication information.
+ result = MCoQueryClientBlanket( NULL, NULL, NULL, &query_authn_level,
+ NULL, NULL, NULL );
+ // Impersonate.
+ if (SUCCEEDED(result))
+ {
+ result = MCoImpersonateClient();
+ if (query_authn_level != RPC_C_AUTHN_LEVEL_NONE && FAILED(result))
+ return result;
+ }
+
+ // Look at the IID to determine the proper results.
+ if (IsEqualIID( riid, IID_ITestNoneImp ))
+ {
+ // If there is a token, should not be able to read the registry.
+ success = OpenThreadToken( GetCurrentThread(), TOKEN_QUERY, TRUE, &token );
+ if (success)
+ {
+ result = RegQueryValueA( HKEY_CLASSES_ROOT, REG_CLASS_EXE, value, &value_size );
+ if (result != ERROR_SUCCESS)
+ goto exit;
+ }
+ *ppvObj = (ITest *) this;
+ AddRef();
+ result = S_OK;
+ goto exit;
+ }
+ if (IsEqualIID( riid, IID_ITestConnectImp ))
+ {
+ // The query and impersonate should have succeeded.
+ if (FAILED(result)) return result;
+
+ // Should be able to read the registry.
+ if (query_authn_level < RPC_C_AUTHN_LEVEL_CONNECT)
+ {
+ result = E_FAIL;
+ goto exit;
+ }
+ result = RegQueryValueA( HKEY_CLASSES_ROOT, REG_CLASS_EXE, value, &value_size );
+ if (result != ERROR_SUCCESS)
+ goto exit;
+ *ppvObj = (ITest *) this;
+ AddRef();
+ result = S_OK;
+ goto exit;
+ }
+ if (IsEqualIID( riid, IID_ITestEncryptImp ))
+ {
+ // The query and impersonate should have succeeded.
+ if (FAILED(result)) return result;
+
+ // Should be able to read the registry.
+ if (query_authn_level < RPC_C_AUTHN_LEVEL_PKT_PRIVACY)
+ {
+ result = E_FAIL;
+ goto exit;
+ }
+ result = RegQueryValueA( HKEY_CLASSES_ROOT, REG_CLASS_EXE, value, &value_size );
+ if (result != ERROR_SUCCESS)
+ goto exit;
+ *ppvObj = (ITest *) this;
+ AddRef();
+ result = S_OK;
+ goto exit;
+ }
+ if (IsEqualIID( riid, IID_ITestNoneId ))
+ {
+ // If there is a token, should not be able to read the registry.
+ success = OpenThreadToken( GetCurrentThread(), TOKEN_QUERY, TRUE, &token );
+ if (success)
+ {
+ result = RegQueryValueA( HKEY_CLASSES_ROOT, REG_CLASS_EXE, value, &value_size );
+ if (result != ERROR_BAD_IMPERSONATION_LEVEL)
+ {
+ result = E_FAIL;
+ goto exit;
+ }
+ }
+ *ppvObj = (ITest *) this;
+ AddRef();
+ result = S_OK;
+ goto exit;
+ }
+ if (IsEqualIID( riid, IID_ITestConnectId ))
+ {
+ // The query and impersonate should have succeeded.
+ if (FAILED(result)) return result;
+
+ // Should not be able to read the registry.
+ if (query_authn_level < RPC_C_AUTHN_LEVEL_CONNECT)
+ {
+ result = E_FAIL;
+ goto exit;
+ }
+ result = RegQueryValueA( HKEY_CLASSES_ROOT, REG_CLASS_EXE, value, &value_size );
+ if (result != ERROR_BAD_IMPERSONATION_LEVEL)
+ {
+ result = E_FAIL;
+ goto exit;
+ }
+ *ppvObj = (ITest *) this;
+ AddRef();
+ result = S_OK;
+ goto exit;
+ }
+ if (IsEqualIID( riid, IID_ITestEncryptId ))
+ {
+ // The query and impersonate should have succeeded.
+ if (FAILED(result)) return result;
+
+ // Should be able to read the registry.
+ if (query_authn_level < RPC_C_AUTHN_LEVEL_PKT_PRIVACY)
+ {
+ result = E_FAIL;
+ goto exit;
+ }
+ result = RegQueryValueA( HKEY_CLASSES_ROOT, REG_CLASS_EXE, value, &value_size );
+ if (result != ERROR_BAD_IMPERSONATION_LEVEL)
+ {
+ result = E_FAIL;
+ goto exit;
+ }
+ *ppvObj = (ITest *) this;
+ AddRef();
+ result = S_OK;
+ goto exit;
+ }
+exit:
+ CoRevertToSelf();
+ return result;
+ }
+ return E_NOINTERFACE;
+}
+
+ /***************************************************************************/
+STDMETHODIMP CTest::null()
+{
+ return S_OK;
+}
+
+ /***************************************************************************/
+STDMETHODIMP CTest::out( ITest **obj )
+{
+ *obj = this;
+ return S_OK;
+}
+
+ /***************************************************************************/
+STDMETHODIMP CTest::pointer( DWORD *p )
+{
+ ASSERT_THREAD();
+ return S_OK;
+}
+
+ /***************************************************************************/
+STDMETHODIMP CTest::recurse( ITest *callback, ULONG depth )
+{
+ ASSERT_THREAD();
+ if (depth == 0)
+ return S_OK;
+ else
+ return callback->recurse( this, depth-1 );
+}
+
+ /***************************************************************************/
+STDMETHODIMP CTest::recurse_disconnect( ITest *callback, ULONG depth )
+{
+ ASSERT_THREAD();
+
+ HRESULT result;
+
+ if (depth == 0)
+ {
+ result = CoDisconnectObject( (ITest *) this, 0 );
+ return result;
+ }
+ else
+ {
+ result = callback->recurse_disconnect( this, depth-1 );
+ return result;
+ }
+}
+
+ /***************************************************************************/
+STDMETHODIMP CTest::recurse_excp( ITest *callback, ULONG depth )
+{
+ ASSERT_THREAD();
+ if (depth == 0)
+ {
+ RaiseException( E_FAIL, 0, 0, NULL );
+ return E_FAIL;
+ }
+ else
+ return callback->recurse_excp( this, depth-1 );
+}
+
+ /***************************************************************************/
+STDMETHODIMP CTest::recurse_fatal( ITest *callback, ULONG catch_depth,
+ ULONG throw_depth, BOOL cancel )
+{
+ ASSERT_THREAD();
+ if (catch_depth == 0)
+ {
+ __try
+ {
+ return recurse_fatal_helper( callback, catch_depth, throw_depth, cancel );
+ }
+ __except(EXCEPTION_EXECUTE_HANDLER)
+ {
+ printf( "Exception on thread 0x%x\n", GetCurrentThreadId() );
+ what_next( crippled_wn );
+ wake_up_and_smell_the_roses();
+ return S_OK;
+ }
+ }
+ else
+ return recurse_fatal_helper( callback, catch_depth, throw_depth, cancel );
+}
+
+ /***************************************************************************/
+STDMETHODIMP CTest::recurse_fatal_helper( ITest *callback, ULONG catch_depth,
+ ULONG throw_depth, BOOL cancel )
+{
+ volatile void **p = (volatile void **) 0xffffffff;
+
+ if (throw_depth == 0)
+ {
+ // If the cancel flag is set, tell the helper to tell the caller to cancel
+ // the call to this object.
+ if (cancel)
+ next->cancel();
+
+ // Die a horrible death.
+ return (HRESULT) *p;
+ }
+ else
+ return callback->recurse_fatal( this, catch_depth-1, throw_depth-1, cancel );
+}
+
+ /***************************************************************************/
+STDMETHODIMP CTest::recurse_interrupt( ITest *callback, ULONG depth )
+{
+ MSG msg;
+
+ ASSERT_THREAD();
+ if (PeekMessageA( &msg, NULL, 0, 0, PM_REMOVE ))
+ {
+ TranslateMessage (&msg);
+ DispatchMessageA (&msg);
+ }
+
+ if (depth == 0)
+ return S_OK;
+ else
+ return callback->recurse( this, depth-1 );
+}
+
+ /***************************************************************************/
+STDMETHODIMP CTest::recurse_secure( ITest *callback, ULONG depth,
+ ULONG imp_depth, HACKSID *sid )
+{
+ HRESULT result;
+ TOKEN_USER *token_info = NULL;
+ DWORD info_size = 1024;
+ HANDLE token = NULL;
+ PSID me = NULL;
+ ASSERT_THREAD();
+
+ if (depth != 0)
+ {
+ // Set the authentication level to connect.
+ result = MCoSetProxyBlanket( callback, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE,
+ NULL, RPC_C_AUTHN_LEVEL_CONNECT,
+ RPC_C_IMP_LEVEL_IMPERSONATE, NULL,
+ EOAC_NONE );
+ ASSERT( result, "Could not set blanket" );
+ }
+
+ // Impersonate if necessary.
+ if (imp_depth == 0)
+ {
+ result = MCoImpersonateClient();
+ ASSERT( result, "Could not impersonate" );
+ }
+
+ // If not deep enough, continue to recurse.
+ if (depth != 0)
+ {
+ result = callback->recurse_secure( this, depth-1, imp_depth-1,
+ (HACKSID *) ProcessSid );
+ ASSERT( result, "Could not recurse" );
+ }
+
+ // Open the thread's token.
+ if (OpenThreadToken( GetCurrentThread(), TOKEN_QUERY, TRUE, &token ))
+ result = S_OK;
+ else
+ result = GetLastError();
+ if (imp_depth == 0)
+ {
+ ASSERT( result, "Could not open thread token while impersonating" );
+ }
+ else
+ {
+ ASSERT_EXPR( result == NOERROR || result == ERROR_NO_TOKEN, "Could not OpenThreadToken" );
+ }
+
+ // Lookup SID of thread token.
+ token_info = (TOKEN_USER *) malloc( info_size );
+ if (token_info == NULL)
+ {
+ result = E_OUTOFMEMORY;
+ goto cleanup;
+ }
+ if (result == NOERROR)
+ {
+ if (GetTokenInformation( token, TokenUser, token_info, info_size, &info_size ))
+ result = S_OK;
+ else
+ result = GetLastError();
+ ASSERT( result, "Could not GetTokenInformation" );
+ me = token_info->User.Sid;
+ CloseHandle( token );
+ token = NULL;
+
+ // Check the SID in the thread token.
+ if (imp_depth == 0)
+ {
+ if (!EqualSid( me, sid ))
+ {
+ result = E_FAIL;
+ goto cleanup;
+ }
+ }
+ else
+ {
+ if (!EqualSid( me, ProcessSid ))
+ {
+ result = E_FAIL;
+ goto cleanup;
+ }
+ }
+ }
+
+ // Revert.
+ if (imp_depth != 0)
+ {
+ result = MCoRevertToSelf();
+ ASSERT( result, "Could not revert" );
+ }
+
+ // Open the thread's token.
+ if (OpenThreadToken( GetCurrentThread(), TOKEN_QUERY, TRUE, &token ))
+ result = S_OK;
+ else
+ result = GetLastError();
+ if (imp_depth == 0)
+ {
+ ASSERT( result, "Could not open thread token while impersonating" );
+ }
+ else
+ {
+ ASSERT_EXPR( result == NOERROR || result == ERROR_NO_TOKEN, "Could not OpenThreadToken" );
+ }
+
+ // Lookup SID of thread token.
+ if (result == NOERROR)
+ {
+ if (GetTokenInformation( token, TokenUser, token_info, info_size, &info_size ))
+ result = S_OK;
+ else
+ result = GetLastError();
+ ASSERT( result, "Could not GetTokenInformation" );
+ me = token_info->User.Sid;
+ CloseHandle( token );
+ token = NULL;
+
+ // Check the SID in the thread token.
+ if (imp_depth == 0)
+ {
+ if (!EqualSid( me, sid ))
+ {
+ result = E_FAIL;
+ goto cleanup;
+ }
+ }
+ else
+ {
+ if (!EqualSid( me, ProcessSid ))
+ {
+ result = E_FAIL;
+ goto cleanup;
+ }
+ }
+ }
+
+ result = S_OK;
+cleanup:
+ if (token_info != NULL)
+ free(token_info);
+ if (token != NULL)
+ CloseHandle( token );
+ return result;
+}
+
+ /***************************************************************************/
+STDMETHODIMP_(ULONG) CTest::Release( THIS )
+{
+ DWORD status;
+
+ assert_unknown();
+ if (InterlockedDecrement( (long*) &ref_count ) == 0)
+ {
+ decrement_object_count();
+ if (flate_dispatch)
+ {
+ status = WaitForSingleObject( RawEvent, INFINITE );
+ if (status != WAIT_OBJECT_0)
+ printf( "WaitForSingleObject failed.\n" );
+ }
+ delete this;
+ return 0;
+ }
+ else
+ return ref_count;
+}
+
+ /***************************************************************************/
+STDMETHODIMP CTest::register_hook( GUID ext, DWORD seq )
+{
+ CHook *hook;
+ ASSERT_THREAD();
+
+ // Create a new hook.
+ hook = new CHook( ext, seq );
+ if (hook == NULL)
+ return E_OUTOFMEMORY;
+ if (GlobalHook1 == NULL)
+ GlobalHook1 = hook;
+ else
+ GlobalHook2 = hook;
+
+ // Register it.
+ return CoRegisterChannelHook( ext, hook );
+}
+
+ /***************************************************************************/
+STDMETHODIMP CTest::register_message_filter( BOOL reg )
+{
+ ASSERT_THREAD();
+
+ if (reg)
+ return CoRegisterMessageFilter( this, NULL );
+ else
+ return CoRegisterMessageFilter( NULL, NULL );
+}
+
+ /***************************************************************************/
+STDMETHODIMP CTest::register_rpc( WCHAR *protseq, WCHAR **binding )
+{
+ ASSERT_THREAD();
+
+ RPC_STATUS status;
+ RPC_BINDING_VECTOR *bindings;
+ WCHAR *string;
+ DWORD i;
+ WCHAR *binding_protseq;
+ BOOL found;
+
+ *binding = NULL;
+ status = RpcServerUseProtseqEp( protseq, 20, NULL, NULL );
+ if (status != RPC_S_OK)
+ return MAKE_WIN32( status );
+
+ status = RpcServerRegisterIf(xIDog_v0_1_s_ifspec,
+ NULL, // MgrTypeUuid
+ NULL); // MgrEpv; null means use default
+ if (status != RPC_S_OK)
+ return MAKE_WIN32( status );
+
+ status = RpcServerRegisterAuthInfo( L"none", RPC_C_AUTHN_WINNT, 0, 0 );
+ if (status != RPC_S_OK)
+ return MAKE_WIN32( status );
+
+ status = RpcServerListen( 1, 1235, TRUE );
+ if (status != RPC_S_OK && status != RPC_S_ALREADY_LISTENING)
+ return MAKE_WIN32( status );
+
+ // Inquire the string bindings.
+ status = RpcServerInqBindings( &bindings );
+ if (status != RPC_S_OK)
+ return MAKE_WIN32( status );
+ if (bindings->Count == 0)
+ {
+ RpcBindingVectorFree( &bindings );
+ return E_FAIL;
+ }
+
+ // Look for ncalrpc.
+ for (i = 0; i < bindings->Count; i++)
+ {
+
+ // Convert the binding handle to a string binding, copy it, and free it.
+ status = RpcBindingToStringBinding( bindings->BindingH[i], &string );
+ if (status == RPC_S_OK)
+ {
+ // Look up the protseq.
+ status = RpcStringBindingParse( string, NULL, &binding_protseq,
+ NULL, NULL, NULL );
+ if (status == RPC_S_OK)
+ {
+ found = wcscmp( binding_protseq, protseq ) == 0;
+ RpcStringFree( &binding_protseq );
+ if (found)
+ {
+ *binding = (WCHAR *) CoTaskMemAlloc( (wcslen(string)+1) * sizeof(WCHAR) );
+ if (*binding != NULL)
+ wcscpy( *binding, string );
+ else
+ status = RPC_S_OUT_OF_RESOURCES;
+ RpcStringFree( &string );
+ break;
+ }
+ }
+ RpcStringFree( &string );
+ }
+ }
+ if (*binding == NULL)
+ status = E_FAIL;
+
+ // Free the binding vector.
+ RpcBindingVectorFree( &bindings );
+ return status;
+}
+
+ /***************************************************************************/
+STDMETHODIMP CTest::reject_next()
+{
+ freject_next = TRUE;
+ return S_OK;
+}
+
+ /***************************************************************************/
+STDMETHODIMP CTest::reinitialize()
+{
+ ASSERT_THREAD();
+ what_next( reinitialize_wn );
+ wake_up_and_smell_the_roses();
+ return S_OK;
+}
+
+ /***************************************************************************/
+STDMETHODIMP CTest::remember( ITest *neighbor, SAptId id )
+{
+ ASSERT_THREAD();
+
+ // Save this interface pointer.
+ if (next != NULL)
+ next->Release();
+ next_id = id;
+ next = neighbor;
+ next->AddRef();
+ return S_OK;
+}
+
+ /***************************************************************************/
+STDMETHODIMP CTest::rest_and_die()
+{
+ ASSERT_THREAD();
+ what_next( rest_and_die_wn );
+ wake_up_and_smell_the_roses();
+ return S_OK;
+}
+
+ /***************************************************************************/
+STDMETHODIMP CTest::retry_next()
+{
+ fretry_next = TRUE;
+ return S_OK;
+}
+
+ /***************************************************************************/
+STDMETHODIMP_(DWORD) CTest::RetryRejectedCall( HTASK callee, DWORD tick,
+ DWORD reject )
+{
+ if (fretry_next)
+ {
+ fretry_next = FALSE;
+ return 0;
+ }
+
+ // Never retry.
+ else
+ return 0xffffffff;
+}
+
+ /***************************************************************************/
+STDMETHODIMP CTest::ring( DWORD length )
+{
+ DWORD i = 0;
+ ITest *ring;
+ ITest *ring_next;
+ SAptId ring_id;
+ HRESULT result;
+
+ ASSERT_THREAD();
+
+ // Call all the neighbors in the ring.
+ ring = next;
+ ring_id = next_id;
+ next->AddRef();
+ while (ring != this)
+ {
+ result = ring->check( ring_id );
+ if (FAILED(result))
+ {
+ ring->Release();
+ return result;
+ }
+ result = ring->get_next( &ring_next, &ring_id );
+ if (FAILED(result))
+ {
+ ring->Release();
+ return result;
+ }
+ ring->Release();
+ ring = ring_next;
+ i++;
+ }
+
+ // Check to make sure the ring is correct.
+ ring->Release();
+ if (i+1 != length || ring_id.process != my_id.process ||
+ ring_id.thread != my_id.thread || ring_id.sequence != my_id.sequence)
+ return E_FAIL;
+ else
+ return S_OK;
+}
+
+ /***************************************************************************/
+STDMETHODIMP CTest::secure( SAptId id, DWORD authn_level, DWORD imp_level,
+ DWORD authn_svc, DWORD authz_svc,
+ STRING princ_name, HACKSID *caller,
+ DWORD *authn_level_out )
+{
+ HRESULT result = S_OK;
+ DWORD query_authn_level;
+ DWORD query_imp_level;
+ DWORD query_authn_svc;
+ DWORD query_authz_svc;
+ STRING query_princ_name = NULL;
+ TOKEN_USER *token_info = NULL;
+ DWORD info_size = 1024;
+ HANDLE token = NULL;
+ PSID me = NULL;
+
+ *authn_level_out = RPC_C_AUTHN_LEVEL_NONE;
+
+ ASSERT_THREAD();
+ if (my_id.process != id.process || my_id.thread != id.thread ||
+ my_id.sequence != id.sequence)
+ return E_FAIL;
+
+ // Query for the authentication information.
+ result = MCoQueryClientBlanket( &query_authn_svc, &query_authz_svc,
+ &query_princ_name, &query_authn_level,
+ &query_imp_level, NULL, NULL );
+ *authn_level_out = query_authn_level;
+
+ // For unsecure calls, all the other fields should be clear.
+ if (authn_level == RPC_C_AUTHN_LEVEL_NONE)
+ {
+ if (result == S_OK)
+ {
+ if (query_authn_level < authn_level)
+ {
+ result = E_INVALIDARG;
+ goto cleanup;
+ }
+ // The impersonation level can't be determined on the server.
+ // if (query_imp_level != RPC_C_IMP_LEVEL_IMPERSONATE)
+ if (query_imp_level != RPC_C_IMP_LEVEL_ANONYMOUS)
+ {
+ result = E_INVALIDARG;
+ goto cleanup;
+ }
+ if (query_authn_svc != RPC_C_AUTHN_NONE &&
+ query_authn_svc != RPC_C_AUTHN_WINNT)
+ {
+ result = E_INVALIDARG;
+ goto cleanup;
+ }
+ if (query_authz_svc != RPC_C_AUTHZ_NONE)
+ {
+ result = E_INVALIDARG;
+ goto cleanup;
+ }
+ /*
+ if ((princ_name == NULL && query_princ_name != NULL) ||
+ (princ_name != NULL && query_princ_name == NULL))
+ {
+ result = E_INVALIDARG;
+ goto cleanup;
+ }
+ if (princ_name != NULL &&
+ wcscmp(princ_name, query_princ_name) != 0)
+ {
+ result = E_INVALIDARG;
+ goto cleanup;
+ }
+ */
+ }
+ }
+
+ // For secure calls, verify all the authnetication info.
+ else
+ {
+ ASSERT( result, "Could not query client blanket" );
+ if (query_authn_level < authn_level)
+ {
+ result = E_INVALIDARG;
+ goto cleanup;
+ }
+ // The impersonation level can't be determined on the server.
+ //if (query_imp_level != imp_level)
+ if (query_imp_level != RPC_C_IMP_LEVEL_ANONYMOUS)
+ {
+ result = E_INVALIDARG;
+ goto cleanup;
+ }
+ // Sometimes ncalrpc doesn't set the authentication service.
+ if (query_authn_svc != RPC_C_AUTHN_NONE &&
+ query_authn_svc != authn_svc)
+ {
+ result = E_INVALIDARG;
+ goto cleanup;
+ }
+ if (query_authz_svc != authz_svc)
+ {
+ result = E_INVALIDARG;
+ goto cleanup;
+ }
+ /*
+ if ((princ_name == NULL && query_princ_name != NULL) ||
+ (princ_name != NULL && query_princ_name == NULL))
+ {
+ result = E_INVALIDARG;
+ goto cleanup;
+ }
+ if (princ_name != NULL &&
+ wcscmp(princ_name, query_princ_name) != 0)
+ {
+ result = E_INVALIDARG;
+ goto cleanup;
+ }
+ */
+ }
+
+ // Open the thread's token.
+ if (OpenThreadToken( GetCurrentThread(), TOKEN_QUERY, TRUE, &token ))
+ result = S_OK;
+ else
+ result = GetLastError();
+ ASSERT_EXPR( result == NOERROR || result == ERROR_NO_TOKEN, "Could not OpenThreadToken" );
+
+ // Lookup SID of thread token.
+ token_info = (TOKEN_USER *) malloc( info_size );
+ if (token_info == NULL)
+ {
+ result = E_OUTOFMEMORY;
+ goto cleanup;
+ }
+ if (result == NOERROR)
+ {
+ if (GetTokenInformation( token, TokenUser, token_info, info_size, &info_size ))
+ result = S_OK;
+ else
+ result = GetLastError();
+ ASSERT( result, "Could not GetTokenInformation" );
+ me = token_info->User.Sid;
+ CloseHandle( token );
+ token = NULL;
+
+ // The SID on the thread token should equal the process token.
+ if (!EqualSid( me, ProcessSid ))
+ {
+ result = E_FAIL;
+ goto cleanup;
+ }
+ }
+
+ // Impersonate.
+ result = MCoImpersonateClient();
+
+ // For unsecure calls the impersonate should fail.
+ if (authn_level == RPC_C_AUTHN_LEVEL_NONE)
+ {
+ // Currently the impersonate succeeds without setting the thread token.
+/*
+ if (result == S_OK)
+ {
+ result = E_FAIL;
+ goto cleanup;
+ }
+*/
+ result = S_OK;
+ }
+
+ // For secure calls, compare the new thread token sid to the passed
+ // in sid.
+ else
+ {
+ ASSERT( result, "Could not impersonate" );
+
+ // Open the thread's token.
+ if (OpenThreadToken( GetCurrentThread(), TOKEN_QUERY, TRUE, &token ))
+ result = S_OK;
+ else
+ result = GetLastError();
+ ASSERT( result, "Could not OpenThreadToken" );
+
+ // Lookup SID of thread token.
+ if (GetTokenInformation( token, TokenUser, token_info, info_size, &info_size ))
+ result = S_OK;
+ else
+ result = GetLastError();
+ ASSERT( result, "Could not GetTokenInformation" );
+ me = token_info->User.Sid;
+ CloseHandle( token );
+ token = NULL;
+
+ // Compare the impersonate sid to the passed in sid.
+ if (!EqualSid( me, caller ))
+ {
+ result = E_FAIL;
+ goto cleanup;
+ }
+ }
+
+ // Revert.
+ result = MCoRevertToSelf();
+ ASSERT( result, "Could not revert" );
+
+ // Open the thread's token.
+ if (OpenThreadToken( GetCurrentThread(), TOKEN_QUERY, TRUE, &token ))
+ result = S_OK;
+ else
+ result = GetLastError();
+ ASSERT_EXPR( result == NOERROR || result == ERROR_NO_TOKEN, "Could not OpenThreadToken" );
+
+ // Lookup SID of thread token.
+ if (result == NOERROR)
+ {
+ if (GetTokenInformation( token, TokenUser, token_info, info_size, &info_size ))
+ result = S_OK;
+ else
+ result = GetLastError();
+ ASSERT( result, "Could not GetTokenInformation" );
+ me = token_info->User.Sid;
+ CloseHandle( token );
+ token = NULL;
+
+ // The SID on the thread token should equal the process token.
+ if (!EqualSid( me, ProcessSid ))
+ {
+ result = E_FAIL;
+ goto cleanup;
+ }
+ }
+ else
+ result = S_OK;
+
+cleanup:
+ if (token_info != NULL)
+ free(token_info);
+ if (token != NULL)
+ CloseHandle( token );
+ CoTaskMemFree( query_princ_name );
+ return result;
+}
+
+ /***************************************************************************/
+STDMETHODIMP CTest::security_performance( DWORD *get_call, DWORD *query_client,
+ DWORD *impersonate, DWORD *revert )
+{
+ LARGE_INTEGER start;
+ LARGE_INTEGER qget_call;
+ LARGE_INTEGER qquery_client;
+ LARGE_INTEGER qimpersonate;
+ LARGE_INTEGER qrevert;
+ LARGE_INTEGER freq;
+ IServerSecurity *server_sec = NULL;
+ HRESULT result;
+ DWORD authn_svc;
+ DWORD authz_svc;
+ DWORD authn_level;
+ DWORD imp_level;
+ DWORD capabilities;
+ WCHAR *principal = NULL;
+ void *privs;
+
+ // Import the security APIs.
+ GCoGetCallContext = (CoGetCallContextFn) Fixup( "CoGetCallContext" );
+ GCoImpersonateClient = (CoImpersonateClientFn) Fixup( "CoImpersonateClient" );
+ GCoQueryClientBlanket = (CoQueryClientBlanketFn) Fixup( "CoQueryClientBlanket" );
+ GCoRevertToSelf = (CoRevertToSelfFn) Fixup( "CoRevertToSelf" );
+ if (GCoGetCallContext == NULL ||
+ GCoImpersonateClient == NULL ||
+ GCoQueryClientBlanket == NULL ||
+ GCoRevertToSelf == NULL)
+ return E_NOTIMPL;
+
+ // Measure the performance of get call context.
+ QueryPerformanceFrequency( &freq );
+ QueryPerformanceCounter( &start );
+ result = MCoGetCallContext( IID_IServerSecurity, (void **) &server_sec );
+ QueryPerformanceCounter( &qget_call );
+ qget_call.QuadPart = 1000000 * (qget_call.QuadPart - start.QuadPart) / freq.QuadPart;
+ ASSERT( result, "Could not get call context" );
+ server_sec->Release();
+
+ // Measure the performance of query client.
+ QueryPerformanceCounter( &start );
+ result = MCoQueryClientBlanket( &authn_svc, &authz_svc, &principal,
+ &authn_level, &imp_level, &privs, &capabilities );
+ QueryPerformanceCounter( &qquery_client );
+ qquery_client.QuadPart = 1000000 * (qquery_client.QuadPart - start.QuadPart) / freq.QuadPart;
+ ASSERT( result, "Could not query client blanket" );
+ CoTaskMemFree( principal );
+
+ // Measure the performance of impersonate.
+ QueryPerformanceCounter( &start );
+ result = MCoImpersonateClient();
+ QueryPerformanceCounter( &qimpersonate );
+ qimpersonate.QuadPart = 1000000 * (qimpersonate.QuadPart - start.QuadPart) / freq.QuadPart;
+ ASSERT( result, "Could not impersonate" );
+
+ // Measure the performance of revert.
+ QueryPerformanceCounter( &start );
+ result = MCoRevertToSelf();
+ QueryPerformanceCounter( &qrevert );
+ qrevert.QuadPart = 1000000 * (qrevert.QuadPart - start.QuadPart) / freq.QuadPart;
+ ASSERT( result, "Could not revert" );
+
+ // Return the results.
+ *get_call = qget_call.u.LowPart;
+ *query_client = qquery_client.u.LowPart;
+ *impersonate = qimpersonate.u.LowPart;
+ *revert = qrevert.u.LowPart;
+
+cleanup:
+ return result;
+}
+
+ /***************************************************************************/
+STDMETHODIMP CTest::set_state( DWORD state, DWORD priority )
+{
+ BOOL success;
+ ASSERT_THREAD();
+
+ // Save dirty flag per apartment.
+ if (state & dirty_s)
+ if (ThreadMode == COINIT_MULTITHREADED)
+ ProcessAptData.exit_dirty = TRUE;
+ else
+ {
+ SAptData *tls_data = (SAptData *) TlsGetValue( TlsIndex );
+ tls_data->exit_dirty = TRUE;
+ }
+
+ // Save the late dispatch flag per object.
+ if (state & late_dispatch_s)
+ flate_dispatch = TRUE;
+
+ // Set the priority.
+ success = SetThreadPriority( GetCurrentThread(), priority );
+ if (success)
+ return S_OK;
+ else
+ return E_FAIL;
+}
+
+ /***************************************************************************/
+STDMETHODIMP CTest::sick( ULONG val )
+{
+ ASSERT_THREAD();
+ __try
+ {
+ RaiseException( val, 0, 0, NULL );
+ }
+ __except(EXCEPTION_EXECUTE_HANDLER)
+ {
+ }
+ return S_OK;
+}
+
+ /***************************************************************************/
+STDMETHODIMP CTest::sleep( ULONG time )
+{
+ ASSERT_THREAD();
+
+ NestedCallCount += 1;
+ printf( "Sleeping on thread %d for the %d time concurrently.\n",
+ GetCurrentThreadId(), NestedCallCount );
+
+ // For multithreaded mode, verify that this is not the main thread.
+ if (ThreadMode == COINIT_MULTITHREADED)
+ {
+ if (GetCurrentThreadId() == MainThread)
+ {
+ printf( "Sleep called on the main thread in multi threaded mode.\n" );
+ NestedCallCount -= 1;
+ return FALSE;
+ }
+ }
+
+ // For single threaded mode, verify that this is the only call on the
+ // main thread.
+ else
+ {
+ if (GetCurrentThreadId() != MainThread)
+ {
+ printf( "Sleep called on the wrong thread in single threaded mode.\n" );
+ NestedCallCount -= 1;
+ return FALSE;
+ }
+ else if (NestedCallCount != 1)
+ {
+ printf( "Sleep nested call count is %d instead of not 1 in single threaded mode.\n",
+ NestedCallCount );
+ NestedCallCount -= 1;
+ return FALSE;
+ }
+ }
+
+ Sleep( time );
+ NestedCallCount -= 1;
+ return S_OK;
+}
+
+ /***************************************************************************/
+STDMETHODIMP CTest::test( ULONG gronk )
+{
+ IStream *stream = (IStream *) gronk;
+ ITest *server = NULL;
+ HRESULT result;
+
+ // Unmarshal from the stream.
+ result = CoGetInterfaceAndReleaseStream( stream, IID_ITest, (void **) &server );
+ if (result != S_OK)
+ return result;
+
+ // Release the server.
+ server->Release();
+ return S_OK;
+}
+
+ /***************************************************************************/
+STDMETHODIMP_(ULONG) CTestCF::AddRef( THIS )
+{
+ InterlockedIncrement( (long *) &ref_count );
+ return ref_count;
+}
+
+ /***************************************************************************/
+CTestCF::CTestCF()
+{
+ ref_count = 1;
+}
+
+ /***************************************************************************/
+CTestCF::~CTestCF()
+{
+}
+
+ /***************************************************************************/
+STDMETHODIMP CTestCF::CreateInstance(
+ IUnknown FAR* pUnkOuter,
+ REFIID iidInterface,
+ void FAR* FAR* ppv)
+{
+ *ppv = NULL;
+ if (pUnkOuter != NULL)
+ {
+ printf( "Create instance failed, attempted agregation.\n" );
+ return E_FAIL;
+ }
+
+ if (IsEqualIID( iidInterface, IID_ITest ) ||
+ IsEqualIID( iidInterface, IID_IUnknown ))
+ {
+ CTest *Test = new FAR CTest();
+
+ if (Test == NULL)
+ {
+ printf( "Create interface failed, no memory.\n" );
+ return E_OUTOFMEMORY;
+ }
+
+ *ppv = Test;
+ printf( "Created instance.\n" );
+ return S_OK;
+ }
+
+ if (IsEqualIID( iidInterface, IID_IAdviseSink ))
+ {
+ CAdvise *Test = new FAR CAdvise();
+
+ if (Test == NULL)
+ {
+ printf( "Create interface failed, no memory.\n" );
+ return E_OUTOFMEMORY;
+ }
+
+ *ppv = Test;
+ printf( "Created instance.\n" );
+ return S_OK;
+ }
+
+ printf( "Create interface failed, wrong interface.\n" );
+ return E_NOINTERFACE;
+}
+
+ /***************************************************************************/
+STDMETHODIMP CTestCF::LockServer(BOOL fLock)
+{
+ return E_FAIL;
+}
+
+
+ /***************************************************************************/
+STDMETHODIMP CTestCF::QueryInterface( THIS_ REFIID riid, LPVOID FAR* ppvObj)
+{
+ if (IsEqualIID(riid, IID_IUnknown) ||
+ IsEqualIID(riid, IID_IClassFactory))
+ {
+ *ppvObj = (IUnknown *) this;
+ AddRef();
+ return S_OK;
+ }
+
+ *ppvObj = NULL;
+ return E_NOINTERFACE;
+}
+
+ /***************************************************************************/
+STDMETHODIMP_(ULONG) CTestCF::Release( THIS )
+{
+ if (InterlockedDecrement( (long*) &ref_count ) == 0)
+ {
+ delete this;
+ return 0;
+ }
+ else
+ return ref_count;
+}
+
+ /***************************************************************************/
+DWORD _stdcall apartment_base( void *param )
+{
+ new_apt_params *nap = (new_apt_params *) param;
+ CTestCF *factory;
+ ULONG size;
+ HRESULT result;
+ HANDLE memory;
+ BOOL success;
+ SAptData tls_data;
+
+ // In the single threaded mode, stick a pointer to the object count
+ // in TLS.
+ tls_data.object_count = 0;
+ tls_data.what_next = setup_wn;
+ tls_data.exit_dirty = FALSE;
+ tls_data.sequence = 0;
+ TlsSetValue( TlsIndex, &tls_data );
+
+ // Initialize OLE.
+ printf( "Initializing thread 0x%x\n", GetCurrentThreadId() );
+ result = initialize(NULL,ThreadMode);
+ if (SUCCEEDED(result))
+ {
+
+ // Create a class factory.
+ factory = new CTestCF;
+
+ if (factory != NULL)
+ {
+ // Find out how much memory to allocate.
+ result = CoGetMarshalSizeMax( &size, IID_IClassFactory, factory, 0, NULL,
+ MSHLFLAGS_NORMAL );
+
+ if (SUCCEEDED(result))
+ {
+ // Allocate memory.
+ memory = GlobalAlloc( GMEM_FIXED, size );
+
+ if (memory != NULL)
+ {
+ // Create a stream.
+ result = CreateStreamOnHGlobal( memory, TRUE, &nap->stream );
+ if (FAILED(result))
+ {
+ nap->stream = NULL;
+ GlobalFree( memory );
+ }
+
+ // Marshal the class factory.
+ else
+ {
+ result = CoMarshalInterface( nap->stream, IID_IClassFactory,
+ factory, 0, NULL, MSHLFLAGS_NORMAL );
+
+ // Seek back to the start of the stream.
+ if (SUCCEEDED(result))
+ {
+ LARGE_INTEGER pos;
+ LISet32(pos, 0);
+ result = nap->stream->Seek( pos, STREAM_SEEK_SET, NULL );
+ }
+
+ if (FAILED(result))
+ {
+ nap->stream->Release();
+ nap->stream = NULL;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // Pass it back to the creator.
+ success = nap->stream != NULL;
+ SetEvent( nap->ready );
+
+ // Loop till it is time to go away.
+ if (success)
+ server_loop();
+ if (!dirty_thread())
+ {
+ printf( "Uninitializing thread 0x%x\n", GetCurrentThreadId() );
+ CoUninitialize();
+ }
+ else
+ printf( "Did not uninitialize thread 0x%x\n", GetCurrentThreadId() );
+ TlsSetValue( TlsIndex, NULL );
+ return 0;
+}
+
+ /***************************************************************************/
+void callback()
+{
+ HRESULT result;
+
+ // Call the client back.
+ Sleep(1);
+ result = GlobalTest->callback();
+ if (result != S_OK)
+ printf( "Could not callback client: 0x%x\n", result );
+
+ // Release the client.
+ GlobalTest->Release();
+ GlobalTest = NULL;
+}
+
+ /***************************************************************************/
+void check_for_request()
+{
+ MSG msg;
+
+ if (ThreadMode == COINIT_SINGLETHREADED ||
+ ThreadMode == COINIT_APARTMENTTHREADED)
+ {
+ if (PeekMessageA( &msg, NULL, 0, 0, PM_REMOVE ))
+ {
+ TranslateMessage (&msg);
+ DispatchMessageA (&msg);
+ }
+ }
+}
+
+ /***************************************************************************/
+HRESULT create_instance( REFCLSID class_id, ITest **instance, SAptId *id )
+{
+ COSERVERINFO server_machine;
+ MULTI_QI server_instance;
+ WCHAR this_machine[MAX_NAME];
+ DWORD ignore;
+ HRESULT result;
+
+ // Lookup this machine's name.
+ *instance = NULL;
+ ignore = sizeof(this_machine);
+ GetComputerName( this_machine, &ignore );
+
+ // If the server is this machine, just call CoCreateInstance.
+ if (wcscmp(this_machine, Name) == 0)
+ result = CoCreateInstance( class_id, NULL, CLSCTX_LOCAL_SERVER,
+ IID_ITest, (void **) instance );
+
+ // Otherwise call CoCreateInstanceEx.
+ else
+ {
+ server_machine.dwReserved1 = 0;
+ server_machine.pwszName = Name;
+ server_machine.pAuthInfo = 0;
+ server_machine.dwReserved2 = 0;
+ server_instance.pIID = &IID_ITest;
+ server_instance.pItf = NULL;
+ server_instance.hr = S_OK;
+ result = CoCreateInstanceEx( class_id, NULL, CLSCTX_REMOTE_SERVER,
+ &server_machine, 1, &server_instance );
+ *instance = (ITest *) server_instance.pItf;
+ }
+
+ // Get the server's id.
+ if (SUCCEEDED(result) && *instance != NULL)
+ result = (*instance)->get_id( id );
+ return result;
+}
+
+ /***************************************************************************/
+void crippled()
+{
+ HRESULT result;
+ SAptData *mine;
+ SAptId id;
+ RPC_BINDING_HANDLE handle = NULL;
+ RPC_STATUS status;
+ CTest local;
+
+ // Get the apartment specific data.
+ if (ThreadMode == COINIT_MULTITHREADED)
+ mine = &ProcessAptData;
+ else
+ mine = (SAptData *) TlsGetValue( TlsIndex );
+ mine->what_next = quit_wn;
+
+ // Try to make a call out.
+ result = GlobalTest->check( id );
+#if 0
+ if (result != RPC_E_CRIPPLED)
+ {
+ printf( "Expected RPC_E_CRIPPLED making call: 0x%x\n", result );
+ result = E_FAIL;
+ goto cleanup;
+ }
+#endif
+
+ // Try to reinitialize.
+ CoUninitialize();
+ result = initialize(NULL,ThreadMode);
+ if (result != CO_E_INIT_RPC_CHANNEL)
+ {
+ printf( "Expected CO_E_INIT_RPC_CHANNEL reinitializing: 0x%x\n", result );
+ result = E_FAIL;
+ goto cleanup;
+ }
+
+ // Success.
+ result = S_OK;
+cleanup:
+
+ // Make the server loop quit.
+ mine->what_next = quit_wn;
+ mine->object_count = 0;
+
+ // Create a binding handle.
+ status = RpcBindingFromStringBinding( GlobalBinding, &handle );
+ if (status != RPC_S_OK)
+ {
+ printf( "Could not make binding handle form string binding: 0x%x\n" );
+ return;
+ }
+
+ // Make a raw RPC call to report the results.
+ set_status( handle, result, (unsigned long *) &status );
+ if (status != RPC_S_OK)
+ {
+ printf( "Could not make RPC call: 0x%x\n", status );
+ return;
+ }
+ local.set_state( dirty_s, THREAD_PRIORITY_NORMAL );
+}
+
+ /***************************************************************************/
+void decrement_object_count()
+{
+ if (ThreadMode == COINIT_MULTITHREADED)
+ {
+ if (InterlockedDecrement( &ProcessAptData.object_count ) == 0)
+ wake_up_and_smell_the_roses();
+ }
+ else
+ {
+ SAptData *tls_data = (SAptData *) TlsGetValue( TlsIndex );
+ if (tls_data != NULL)
+ tls_data->object_count -= 1;
+ }
+}
+
+ /***************************************************************************/
+BOOL dirty_thread()
+{
+ if (ThreadMode == COINIT_MULTITHREADED)
+ return ProcessAptData.exit_dirty;
+ else
+ {
+ SAptData *tls_data = (SAptData *) TlsGetValue( TlsIndex );
+ return tls_data->exit_dirty;
+ }
+}
+
+ /***************************************************************************/
+void do_cancel()
+{
+ BOOL success = FALSE;
+ ITest *obj1 = NULL;
+ ITest *obj2 = NULL;
+ SAptId id1;
+ SAptId id2;
+ HRESULT result;
+
+ // Initialize OLE.
+ hello( "cancel" );
+ result = initialize(NULL,ThreadMode);
+ ASSERT( result, "Initialize failed" );
+
+ // Create a client.
+ result = CoCreateInstance( *ServerClsid, NULL, CLSCTX_LOCAL_SERVER,
+ IID_ITest, (void **) &obj1 );
+ ASSERT( result, "Could not create instance of test server" );
+ result = obj1->get_id( &id1 );
+ ASSERT( result, "Could not get client id" );
+
+ // Create a client.
+ result = CoCreateInstance( *ServerClsid, NULL, CLSCTX_LOCAL_SERVER,
+ IID_ITest, (void **) &obj2 );
+ ASSERT( result, "Could not create instance of test server" );
+ result = obj2->get_id( &id2 );
+ ASSERT( result, "Could not get client id" );
+
+ // Run test between two remote objects.
+ success = do_cancel_helper( obj1, id1, obj2, id2 );
+ obj1 = NULL;
+ obj2 = NULL;
+ if (!success)
+ goto cleanup;
+ success = FALSE;
+
+ // Create a client.
+ result = CoCreateInstance( *ServerClsid, NULL, CLSCTX_LOCAL_SERVER,
+ IID_ITest, (void **) &obj1 );
+ ASSERT( result, "Could not create instance of test server" );
+ result = obj1->get_id( &id1 );
+ ASSERT( result, "Could not get client id" );
+
+ // Create in process server.
+ result = obj1->get_obj_from_new_apt( &obj2, &id2 );
+ ASSERT( result, "Could not get in process server" );
+
+ // Run test between two local objects.
+ success = do_cancel_helper( obj1, id1, obj2, id2 );
+ obj1 = NULL;
+ obj2 = NULL;
+ if (!success)
+ goto cleanup;
+
+ // Finally, its all over.
+ success = TRUE;
+cleanup:
+ if (obj1 != NULL)
+ obj1->Release();
+ if (obj2 != NULL)
+ obj2->Release();
+ CoUninitialize();
+
+ if (success)
+ printf( "\n\nCancel Test Passed.\n" );
+ else
+ printf( "\n\nCancel Test Failed.\n" );
+}
+
+ /***************************************************************************/
+BOOL do_cancel_helper( ITest *obj1, SAptId id1, ITest *obj2, SAptId id2 )
+{
+ BOOL success = FALSE;
+ HRESULT result;
+ ITest *helper1 = NULL;
+ ITest *helper2 = NULL;
+ SAptId hid1;
+ SAptId hid2;
+
+ // Create first helper.
+ result = obj1->get_obj_from_new_apt( &helper1, &hid1 );
+ ASSERT( result, "Could not get in process server" );
+
+ // Create second helper.
+ result = obj2->get_obj_from_new_apt( &helper2, &hid2 );
+ ASSERT( result, "Could not get in process server" );
+
+ // Register first message filter.
+ result = obj1->register_message_filter( TRUE );
+ ASSERT( result, "Could not register message filter." );
+
+ // Register second message filter.
+ result = obj2->register_message_filter( TRUE );
+ ASSERT( result, "Could not register message filter." );
+
+ // Tell everybody who their neighbor is.
+ result = obj1->remember( helper2, hid2 );
+ ASSERT( result, "Could not remember object" );
+ result = helper2->remember( obj2, id2 );
+ ASSERT( result, "Could not remember object" );
+ result = obj2->remember( helper1, hid1 );
+ ASSERT( result, "Could not remember object" );
+ result = helper1->remember( obj1, id1 );
+ ASSERT( result, "Could not remember object" );
+
+ // Cancel one call.
+ result = obj1->call_canceled( 1, 1, obj2 );
+ ASSERT( result, "Cancel test failed" );
+
+ // Cancel after recursing.
+ result = obj1->call_canceled( 5, 1, obj2 );
+ ASSERT( result, "Cancel after recusing failed" );
+
+ // Make a recursive call and cancel several times.
+ result = obj1->call_canceled( 5, 3, obj2 );
+ ASSERT( result, "Multiple cancel test failed" );
+
+ // Tell everybody to forget their neighbor.
+ result = obj1->forget();
+ ASSERT( result, "Could not forget neighbor" );
+ result = obj2->forget();
+ ASSERT( result, "Could not forget neighbor" );
+ result = helper1->forget();
+ ASSERT( result, "Could not forget neighbor" );
+ result = helper2->forget();
+ ASSERT( result, "Could not forget neighbor" );
+
+ // Release first message filter.
+ result = obj1->register_message_filter( FALSE );
+ ASSERT( result, "Could not deregister message filter." );
+
+ // Release second message filter.
+ result = obj2->register_message_filter( FALSE );
+ ASSERT( result, "Could not deregister message filter." );
+
+ success = TRUE;
+cleanup:
+ if (helper1 != NULL)
+ helper1->Release();
+ if (helper2 != NULL)
+ helper2->Release();
+ if (obj2 != NULL)
+ obj2->Release();
+ if (obj1 != NULL)
+ obj1->Release();
+ return success;
+}
+
+ /***************************************************************************/
+void do_crash()
+{
+ HRESULT result;
+ int i;
+ BOOL success = FALSE;
+ HANDLE helper[MAX_THREADS];
+ DWORD thread_id;
+ DWORD status;
+ ITest *test = NULL;
+ ITest *another = NULL;
+ ITest *local = NULL;
+ SAptId local_id;
+ SAptId test_id;
+ SAptId another_id;
+ unsigned char c[17];
+ WCHAR *binding = NULL;
+/*
+ printf( "This test doesn't run. It tests functionallity that is not checked in.\n" );
+ return;
+*/
+ // Initialize OLE.
+ hello( "crash" );
+ result = initialize(NULL,ThreadMode);
+ ASSERT( result, "Initialize failed" );
+/*
+ result = initialize(NULL,ThreadMode);
+ ASSERT( result, "Recalling Initialize failed" );
+ result = initialize(NULL,xxx);
+ if (result == S_OK)
+ {
+ printf( "Recalling Initialize with wrong thread mode succeeded: %x\n", result );
+ goto cleanup;
+ }
+ CoUninitialize();
+ CoUninitialize();
+*/
+
+ // Create a local object.
+ local = new CTest;
+ ASSERT_EXPR( local != NULL, "Could not create local instance of test server." );
+
+ // Get a test object.
+ result = CoCreateInstance( *ServerClsid, NULL, CLSCTX_LOCAL_SERVER,
+ IID_ITest, (void **) &test );
+ ASSERT( result, "Could not create instance of test server" );
+
+ // Get another test object.
+ result = CoCreateInstance( *ServerClsid, NULL, CLSCTX_LOCAL_SERVER,
+ IID_ITest, (void **) &another );
+ ASSERT( result, "Could not create another instance of test server" );
+ result = another->get_id( &another_id );
+ ASSERT( result, "get_id failed calling second test server" );
+
+ // Let the server throw and exception and catch it before returning.
+ result = test->sick( 95 );
+ ASSERT( result, "Internal server fault was not dealt with correctly." );
+
+ // Throw a non fatal exception on the first call.
+ result = test->recurse_excp( local, 0 );
+ if (result != RPC_E_SERVERFAULT)
+ {
+ printf( "Error with top level exception.\n" );
+ goto cleanup;
+ }
+
+ // Throw a non fatal exception after recursing.
+ result = test->recurse_excp( local, 4 );
+ if (result != RPC_E_SERVERFAULT)
+ {
+ printf( "Error with nested exception.\n" );
+ goto cleanup;
+ }
+
+ // Test alignment of the buffer.
+ result = test->align( c );
+ ASSERT( result, "Alignment call failed" );
+
+ // Test failure marshalling parameters.
+ result = test->pointer( (DWORD *) -1 );
+ if (result != STATUS_ACCESS_VIOLATION)
+ {
+ printf( "Marshalling in parameter failure call failed: 0x%x\n", result );
+ goto cleanup;
+ }
+
+ // Test a recursive call.
+ result = test->recurse( local, 10 );
+ ASSERT( result, "Recursive call failed" );
+
+ // Test multiple threads.
+ Multicall_Test = TRUE;
+ for (i = 0; i < MAX_THREADS; i++)
+ {
+ helper[i] = CreateThread( NULL, 0, thread_helper, test, 0, &thread_id );
+ if (helper[i] == NULL)
+ {
+ printf( "Could not create helper thread number %d.\n", i );
+ goto cleanup;
+ }
+ }
+ result = test->sleep(4000);
+ ASSERT( result, "Multiple call failed on main thread" );
+ status = WaitForMultipleObjects( MAX_THREADS, helper, TRUE, INFINITE );
+ if (status == WAIT_FAILED)
+ {
+ printf( "Could not wait for helper threads to die: 0x%x\n", status );
+ goto cleanup;
+ }
+ if (!Multicall_Test)
+ {
+ printf( "Multiple call failed on helper thread.\n" );
+ goto cleanup;
+ }
+
+ // See if methods can correctly call GetMessage.
+ another->interrupt( test, another_id, TRUE );
+ result = test->recurse_interrupt( local, 10 );
+ ASSERT( result, "Recursive call with interrupts failed" );
+ another->interrupt( test, another_id, FALSE );
+
+ // Kill the server on the first call.
+ printf( "One of the servers may get a popup now. Hit Ok.\n" );
+ result = test->recurse_fatal( local, 0xffffffff, 0, FALSE );
+ ASSERT_EXPR( result != S_OK, "Server still alive after top level exception." );
+ test->Release();
+ test = NULL;
+
+ // Kill the server after nesting.
+ printf( "One of the servers may get a popup now. Hit Ok.\n" );
+ result = another->recurse_fatal( local, 0xffffffff, 4, FALSE );
+ if (result == S_OK)
+ {
+ printf( "Server still alive after nested exception.\n" );
+ goto cleanup;
+ }
+ another->Release();
+ another = NULL;
+/*
+ // Get a test object.
+ result = CoCreateInstance( *ServerClsid, NULL, CLSCTX_LOCAL_SERVER,
+ IID_ITest, (void **) &test );
+ ASSERT( result, "Could not create instance of test server" );
+
+ // Register this process to receive raw RPC.
+ result = local->register_rpc( TestProtseq, &binding );
+ ASSERT( result, "Could not register rpc" );
+
+ // Tell the server to catch the exception at the message loop.
+ result = test->catch_at_top( TRUE, local, binding );
+ ASSERT( result, "Could not tell server to catch exception at top" );
+
+ // Kill the server on the first call.
+ result = test->recurse_fatal( local, 0xffffffff, 0, FALSE );
+ if (result == S_OK)
+ {
+ printf( "Server still alive after exception caught at top.\n" );
+ goto cleanup;
+ }
+ test->Release();
+ test = NULL;
+
+ // Check the raw result.
+ status = WaitForSingleObject( RawEvent, INFINITE );
+ if (status != WAIT_OBJECT_0)
+ {
+ printf( "Could not wait on RawEvent: 0x%x\n", status );
+ goto cleanup;
+ }
+ ASSERT( RawResult, "Problem after exception" );
+
+ // Get a test object.
+ result = CoCreateInstance( *ServerClsid, NULL, CLSCTX_LOCAL_SERVER,
+ IID_ITest, (void **) &test );
+ ASSERT( result, "Could not create instance of test server" );
+
+ // Tell the server to catch the exception at the message loop.
+ result = test->catch_at_top( TRUE, local, binding );
+ ASSERT( result, "Could not tell server to catch exception at top" );
+
+ // Kill the server after nesting.
+ result = test->recurse_fatal( local, 0xffffffff, 6, FALSE );
+ if (result == S_OK)
+ {
+ printf( "Server still alive after exception caught at top.\n" );
+ goto cleanup;
+ }
+ test->Release();
+ test = NULL;
+
+ // Check the raw result.
+ status = WaitForSingleObject( RawEvent, INFINITE );
+ if (status != WAIT_OBJECT_0)
+ {
+ printf( "Could not wait on RawEvent: 0x%x\n", status );
+ goto cleanup;
+ }
+ ASSERT( RawResult, "Problem after exception" );
+
+ // Get a test object.
+ result = CoCreateInstance( *ServerClsid, NULL, CLSCTX_LOCAL_SERVER,
+ IID_ITest, (void **) &test );
+ ASSERT( result, "Could not create instance of test server" );
+
+ // Tell the server not to catch the exception at the message loop.
+ result = test->catch_at_top( FALSE, local, binding );
+ ASSERT( result, "Could not tell server not to catch exception at top" );
+
+ // Tell the server to catch the exception after nesting, nest some more
+ // and then kill it.
+ result = test->recurse_fatal( local, 2, 8, FALSE );
+ ASSERT( result, "Could not gracefully catch exception" );
+ test->Release();
+ test = NULL;
+
+ // Check the raw result.
+ status = WaitForSingleObject( RawEvent, INFINITE );
+ if (status != WAIT_OBJECT_0)
+ {
+ printf( "Could not wait on RawEvent: 0x%x\n", status );
+ goto cleanup;
+ }
+ ASSERT( RawResult, "Problem after exception" );
+
+ // Get a test object.
+ result = CoCreateInstance( *ServerClsid, NULL, CLSCTX_LOCAL_SERVER,
+ IID_ITest, (void **) &test );
+ ASSERT( result, "Could not create instance of test server" );
+
+ // Tell the server not to catch the exception at the message loop.
+ result = test->catch_at_top( FALSE, local, binding );
+ ASSERT( result, "Could not tell server not to catch exception at top" );
+
+ // Get the object ids.
+ result = local->get_id( &local_id );
+ ASSERT( result, "Could not get local id" );
+ result = test->get_id( &test_id );
+ ASSERT( result, "Could not get test id" );
+
+ // Cancel the call to kill the server.
+ success = do_crash_helper( local, local_id, test, test_id);
+ local = NULL;
+ test = NULL;
+ if (!success)
+ goto cleanup;
+ success = FALSE;
+*/
+ // Finally, its all over.
+ success = TRUE;
+cleanup:
+ if (test != NULL)
+ test->Release();
+ if (another != NULL)
+ another->Release();
+ if (local != NULL)
+ local->Release();
+ if (binding != NULL)
+ CoTaskMemFree( binding );
+ CoUninitialize();
+
+ if (success)
+ printf( "\n\nCrash Test Passed.\n" );
+ else
+ printf( "\n\nCrash Test Failed.\n" );
+}
+
+ /***************************************************************************/
+BOOL do_crash_helper( ITest *obj1, SAptId id1, ITest *obj2, SAptId id2 )
+{
+ BOOL success = FALSE;
+ HRESULT result;
+ ITest *helper1 = NULL;
+ SAptId hid1;
+ RPC_STATUS status;
+
+ // Create first helper.
+ result = obj1->get_obj_from_new_apt( &helper1, &hid1 );
+ ASSERT( result, "Could not get in process server" );
+
+ // Register first message filter.
+ result = obj1->register_message_filter( TRUE );
+ ASSERT( result, "Could not register message filter." );
+
+ // Tell everybody who their neighbor is.
+ result = obj2->remember( helper1, hid1 );
+ ASSERT( result, "Could not remember object" );
+ result = helper1->remember( obj1, id1 );
+ ASSERT( result, "Could not remember object" );
+
+ // Tell the server to catch the exception after nesting, nest some more
+ // and then kill it, with cancel.
+ result = obj2->recurse_fatal( obj1, 2, 8, TRUE );
+ if (result == S_OK)
+ ASSERT( result, "Could not gracefully catch exception" );
+ obj2->Release();
+ obj2 = NULL;
+
+ // Check the raw result.
+ status = WaitForSingleObject( RawEvent, INFINITE );
+ if (status != WAIT_OBJECT_0)
+ {
+ printf( "Could not wait on RawEvent: 0x%x\n", status );
+ goto cleanup;
+ }
+ ASSERT( RawResult, "Problem after exception" );
+
+ // Tell everybody to forget their neighbor.
+ result = helper1->forget();
+ ASSERT( result, "Could not forget neighbor" );
+
+ // Release first message filter.
+ result = obj1->register_message_filter( FALSE );
+ ASSERT( result, "Could not deregister message filter." );
+
+ success = TRUE;
+cleanup:
+ if (helper1 != NULL)
+ helper1->Release();
+ if (obj2 != NULL)
+ obj2->Release();
+ if (obj1 != NULL)
+ obj1->Release();
+ return success;
+}
+
+ /***************************************************************************/
+void do_cstress()
+{
+ BOOL success = FALSE;
+ ITest *obj1 = NULL;
+ ITest *obj2 = NULL;
+ ITest *helper = NULL;
+ SAptId id1;
+ SAptId id2;
+ SAptId hid;
+ int i;
+ HRESULT result;
+
+ // Initialize OLE.
+ hello( "cstress" );
+ result = initialize(NULL,ThreadMode);
+ ASSERT( result, "Initialize failed" );
+
+ // Create a client.
+ result = CoCreateInstance( *ServerClsid, NULL, CLSCTX_LOCAL_SERVER,
+ IID_ITest, (void **) &obj1 );
+ ASSERT( result, "Could not create instance of test server" );
+ result = obj1->get_id( &id1 );
+ ASSERT( result, "Could not get client id" );
+
+ // Create helper.
+ result = obj1->get_obj_from_new_apt( &helper, &hid );
+ ASSERT( result, "Could not get in process server" );
+
+ // Create a client.
+ result = CoCreateInstance( *ServerClsid, NULL, CLSCTX_LOCAL_SERVER,
+ IID_ITest, (void **) &obj2 );
+ ASSERT( result, "Could not create instance of test server" );
+ result = obj2->get_id( &hid );
+ ASSERT( result, "Could not get client id" );
+
+ // Register the message filter.
+ result = obj1->register_message_filter( TRUE );
+ ASSERT( result, "Could not register message filter." );
+
+ // Tell everyone to remember their neighbor.
+ result = obj1->remember( helper, hid );
+ ASSERT( result, "Could not remember object" );
+ result = obj2->remember( helper, hid );
+ ASSERT( result, "Could not remember object" );
+ result = helper->remember( obj1, id1 );
+ ASSERT( result, "Could not remember object" );
+
+ // Loop and cancel a lot of calls.
+ for (i = 0; i < NumIterations; i++)
+ {
+ // Cancel remote call.
+ result = obj1->cancel_stress( obj2 );
+ ASSERT( result, "Remote cancel failed" );
+
+ // Cancel local call.
+ result = obj1->cancel_stress( NULL );
+ ASSERT( result, "Local cancel failed" );
+ }
+
+ // Tell everybody to forget their neighbor.
+ result = obj1->forget();
+ ASSERT( result, "Could not forget neighbor" );
+ result = obj2->forget();
+ ASSERT( result, "Could not forget neighbor" );
+ result = helper->forget();
+ ASSERT( result, "Could not forget neighbor" );
+
+ // Release the message filter.
+ result = obj1->register_message_filter( FALSE );
+ ASSERT( result, "Could not register message filter." );
+
+ // Create in process server.
+ result = obj1->get_obj_from_new_apt( &helper, &hid );
+ ASSERT( result, "Could not get in process server" );
+
+ // Finally, its all over.
+ success = TRUE;
+cleanup:
+ if (helper != NULL)
+ helper->Release();
+ if (obj1 != NULL)
+ obj1->Release();
+ if (obj2 != NULL)
+ obj2->Release();
+ CoUninitialize();
+
+ if (success)
+ printf( "\n\nCancel Stress Test Passed.\n" );
+ else
+ printf( "\n\nCancel Stress Test Failed.\n" );
+}
+
+ /***************************************************************************/
+void do_hook()
+{
+ BOOL success = FALSE;
+ ITest *server = NULL;
+ SAptId id;
+ ITest *dead = NULL;
+ ITest *local = NULL;
+ HRESULT result;
+
+ // Initialize OLE.
+ hello( "hook" );
+ result = initialize(NULL,ThreadMode);
+ ASSERT( result, "Initialize failed" );
+
+ // Create a remote server.
+ result = create_instance( *ServerClsid, &dead, &id );
+ ASSERT( result, "Could not create a server" );
+
+ // Tell it to die.
+ result = dead->exit();
+ ASSERT( result, "Could not tell server to die" );
+
+ if (ThreadMode == COINIT_APARTMENTTHREADED)
+ {
+ // Create a local server.
+ result = new_apartment_test( &local, &id, NULL );
+ ASSERT( result, "Could not create local server" );
+
+ // Test hooks in process.
+ success = do_hook_helper( TRUE, local, id, dead );
+ if (!success) goto cleanup;
+ success = FALSE;
+
+ // Release the local server.
+ local->Release();
+ local = NULL;
+ dead->Release();
+ dead = NULL;
+
+ // Uninitialize.
+ CoUninitialize();
+
+ // Reinitialize.
+ result = initialize(NULL,ThreadMode);
+ ASSERT( result, "Initialize failed" );
+
+ // Create a remote server.
+ result = create_instance( *ServerClsid, &dead, &id );
+ ASSERT( result, "Could not create a server" );
+
+ // Tell it to die.
+ result = dead->exit();
+ ASSERT( result, "Could not tell server to die" );
+ }
+
+ // Create a remote server.
+ result = create_instance( *ServerClsid, &server, &id );
+ ASSERT( result, "Could not create a server" );
+
+ // Test remote hooks.
+ success = do_hook_helper( FALSE, server, id, dead );
+ if (!success) goto cleanup;
+ success = FALSE;
+
+ // Finally, its all over.
+ success = TRUE;
+cleanup:
+ if (local != NULL)
+ local->Release();
+ if (server != NULL)
+ server->Release();
+ if (dead != NULL)
+ dead->Release();
+ CoUninitialize();
+
+ if (success)
+ printf( "\n\nHook Test Passed.\n" );
+ else
+ printf( "\n\nHook Test Failed.\n" );
+}
+
+ /***************************************************************************/
+BOOL do_hook_helper( BOOL local, ITest *test, SAptId id, ITest *dead )
+{
+ CHook *hook1 = NULL;
+ CHook *hook2 = NULL;
+ BOOL success = FALSE;
+ UUID extent1;
+ UUID extent2;
+ UUID extent3;
+ HRESULT result;
+ DWORD i;
+ unsigned char *data = NULL;
+
+ // Call the server.
+ result = test->check( id );
+ ASSERT( result, "Could not check server" );
+
+ // Register a hook.
+ result = UuidCreate( &extent1 );
+ ASSERT_EXPR( result == RPC_S_OK || result == RPC_S_UUID_LOCAL_ONLY,
+ "Could not create uuid." );
+ hook1 = new CHook( extent1, 1 );
+ ASSERT_EXPR( hook1 != NULL, "Could not create new hook." );
+ result = CoRegisterChannelHook( extent1, hook1 );
+ ASSERT( result, "Could not register first hook" );
+
+ // Call the server.
+ result = test->check( id );
+ ASSERT( result, "Could not check server" );
+
+ // Register the hook in the server
+ if (!local)
+ {
+ result = test->register_hook( extent1, 1 );
+ ASSERT( result, "Could not register server hook" );
+ }
+
+ // Call the server.
+ result = test->check( id );
+ ASSERT( result, "Could not check server" );
+
+ // Register another hook in the server.
+ result = UuidCreate( &extent3 );
+ ASSERT_EXPR( result == RPC_S_OK || result == RPC_S_UUID_LOCAL_ONLY,
+ "Could not create uuid." );
+ result = test->register_hook( extent3, 3 );
+ ASSERT( result, "Could not register server hook" );
+
+ // Call the server.
+ result = test->check( id );
+ ASSERT( result, "Could not check server" );
+
+ // Register another hook in the client.
+ result = UuidCreate( &extent2 );
+ ASSERT_EXPR( result == RPC_S_OK || result == RPC_S_UUID_LOCAL_ONLY,
+ "Could not create uuid." );
+ hook2 = new CHook( extent2, 2 );
+ ASSERT_EXPR( hook2 != NULL, "Could not create new hook." );
+ result = CoRegisterChannelHook( extent2, hook2 );
+ ASSERT( result, "Could not register first hook" );
+
+ // Call the server several times.
+ for (i = 0; i < NumIterations; i++)
+ {
+ result = test->check( id );
+ ASSERT( result, "Could not check server" );
+ }
+
+ // Verify the server's hook state.
+ if (local)
+ result = test->check_hook( 2+NumIterations, 2+NumIterations,
+ 2+NumIterations, 2+NumIterations,
+ 0, 0, 0, 0 );
+ else
+ result = test->check_hook( 0, 0, 4+NumIterations, 4+NumIterations,
+ 0, 0, 2+NumIterations, 2+NumIterations );
+ ASSERT( result, "Could not check server hook" );
+
+ // Verify the local hook state.
+ if (local)
+ {
+ result = hook1->check( 5+NumIterations, 5+NumIterations,
+ 5+NumIterations, 5+NumIterations );
+ ASSERT( result, "Bad state for hook 1" );
+ result = hook2->check( 1+NumIterations, 1+NumIterations,
+ 1+NumIterations, 1+NumIterations );
+ ASSERT( result, "Bad state for hook 2" );
+ }
+ else
+ {
+ result = hook1->check( 6+NumIterations, 6+NumIterations, 0, 0 );
+ ASSERT( result, "Bad state for hook 1" );
+ result = hook2->check( 1+NumIterations, 1+NumIterations, 0, 0 );
+ ASSERT( result, "Bad state for hook 2" );
+ }
+
+ // Make a call that fails in get buffer.
+ data = (unsigned char *) CoTaskMemAlloc( 1 );
+ ASSERT_EXPR( data != NULL, "Could not allocate memory." );
+ result = test->get_data( 0x7fffffff, data, 0, &data );
+ ASSERT_EXPR( result != S_OK, "Bad call succeeded." );
+
+ // Make a call that fails in send receive.
+ result = dead->check( id );
+ ASSERT_EXPR( result != S_OK, "Bad call succeeded." );
+
+ // Make a call that faults.
+ result = test->recurse_excp( NULL, 0 );
+ ASSERT_EXPR( result != S_OK, "Bad call succeeded." );
+
+ // Make a call that fails in the server get buffer.
+ result = test->get_data( 0, NULL, 0x7fffffff, &data );
+ ASSERT_EXPR( result != S_OK, "Bad call succeeded." );
+
+ // Make a call that faults in the stub processing out parameters.
+ result = test->crash_out( &i );
+ ASSERT_EXPR( result != S_OK, "Bad call succeeded." );
+
+ // Make a successful call.
+ result = test->check( id );
+ ASSERT( result, "Could not check server" );
+
+ // The test succeeded.
+ success = TRUE;
+cleanup:
+ if (hook1 != NULL)
+ hook1->Release();
+ if (hook2 != NULL)
+ hook2->Release();
+ if (data != NULL)
+ CoTaskMemFree( data );
+ return success;
+}
+
+ /***************************************************************************/
+void do_load_client()
+{
+ BOOL success = FALSE;
+ ITest *server = NULL;
+ HRESULT result;
+ RPC_BINDING_HANDLE handle = NULL;
+ RPC_STATUS status;
+ WCHAR binding[MAX_NAME];
+ void *buffer = NULL;
+ SAptId id;
+ SAptId id2;
+ HANDLE memory = NULL;
+ IStream *stream = NULL;
+ LARGE_INTEGER pos;
+ DWORD time_null;
+ long buf_size;
+ DWORD i;
+
+ // Initialize OLE.
+ hello( "Load_Client" );
+ result = initialize(NULL,ThreadMode);
+ ASSERT( result, "Initialize failed" );
+
+ // Build binding handle for the server.
+ wsprintf( binding, L"%ws:%ws", TestProtseq, Name );
+ status = RpcBindingFromStringBinding( binding, &handle );
+ if (status != RPC_S_OK)
+ {
+ printf( "Could not make binding handle from string binding: 0x%x\n", status );
+ goto cleanup;
+ }
+
+ // Get a marshalled interface from the server over raw RPC.
+ get_interface_buffer( handle, &buf_size, (unsigned char **) &buffer, &id,
+ (error_status_t *) &status );
+ if (status != RPC_S_OK)
+ {
+ printf( "Could not get buffer containing interface: 0x%x\n", status );
+ goto cleanup;
+ }
+
+ // Allocate memory.
+ memory = GlobalAlloc( GMEM_FIXED, buf_size );
+ ASSERT_EXPR( memory != NULL, "Could not GlobalAlloc." );
+
+ // Create a stream.
+ result = CreateStreamOnHGlobal( memory, TRUE, &stream );
+ ASSERT( result, "Could not create stream" );
+
+ // Write the data.
+ result = stream->Write( buffer, buf_size, NULL );
+ ASSERT( result, "Could not write to stream" );
+
+ // Seek back to the start of the stream.
+ pos.QuadPart = 0;
+ result = stream->Seek( pos, STREAM_SEEK_SET, NULL );
+ ASSERT( result, "Could not seek stream to start" );
+
+ // Unmarshal Interface.
+ result = CoUnmarshalInterface( stream, IID_ITest, (void **) &server );
+ ASSERT( result, "Could not unmarshal interface" );
+
+ // Call once to make sure everything is set up.
+ result = server->null();
+ ASSERT( result, "Could not make null call" );
+
+ // Make a lot of null calls.
+ time_null = GetTickCount();
+ for (i = 0; i < NumIterations; i++)
+ {
+ result = server->count();
+ ASSERT( result, "Could not make count call" );
+ }
+ time_null = GetTickCount() - time_null;
+
+ // Notify the server that we are done.
+ release_interface( handle, (error_status_t *) &status );
+ if (status != RPC_S_OK)
+ {
+ printf( "Could not release interface: 0x%x\n", status );
+ goto cleanup;
+ }
+
+ // Print the results.
+ printf( "%d uS / DCOM Null Call\n", time_null*1000/NumIterations );
+
+ // Finally, its all over.
+ success = TRUE;
+cleanup:
+ if (server != NULL)
+ server->Release();
+ if (handle != NULL)
+ RpcBindingFree( &handle );
+ if (buffer != NULL)
+ midl_user_free( buffer );
+ if (stream != NULL)
+ stream->Release();
+ CoUninitialize();
+
+ if (success)
+ printf( "\n\nLoad_Client Test Passed.\n" );
+ else
+ printf( "\n\nLoad_Client Test Failed.\n" );
+}
+
+ /***************************************************************************/
+void do_load_server()
+{
+ BOOL success = FALSE;
+ SAptId id;
+ HRESULT result;
+ RPC_STATUS status;
+ RPC_BINDING_VECTOR *bindings = NULL;
+ HANDLE thread = NULL;
+ DWORD thread_id;
+
+ // Initialize OLE.
+ hello( "Load_Server" );
+ result = initialize(NULL,ThreadMode);
+ ASSERT( result, "Initialize failed" );
+
+ // Start the status thread.
+ thread = CreateThread( NULL, 0, status_helper, NULL, 0, &thread_id );
+ ASSERT_EXPR( thread != 0, "Could not create thread." );
+
+ // Set up thread switching.
+ GlobalThreadId = GetCurrentThreadId();
+
+ // Create a local server
+ GlobalTest = new CTest;
+ ASSERT( !GlobalTest, "Could not create local server" );
+
+ // Register a protseq.
+ status = RpcServerUseProtseq( TestProtseq, RPC_C_PROTSEQ_MAX_REQS_DEFAULT,
+ NULL );
+ ASSERT( status, "Could not register protseq" );
+
+ // Register the dog interface.
+ status = RpcServerRegisterIf(xIDog_v0_1_s_ifspec,
+ NULL, // MgrTypeUuid
+ NULL); // MgrEpv; null means use default
+ ASSERT( status, "Could not register RPC interface" );
+
+ // Inquire the endpoints.
+ status = RpcServerInqBindings(&bindings);
+ ASSERT( status, "Could not inquire bindings" );
+
+ // Register them in the endpoint mapper.
+ status = RpcEpRegister( xIDog_v0_1_s_ifspec, bindings, NULL, NULL );
+ ASSERT( status, "Could not register with endpoint mapper" );
+
+ // Start RPC listening.
+ status = RpcServerListen( 1, RPC_C_LISTEN_MAX_CALLS_DEFAULT, TRUE );
+ ASSERT( status, "Could not start RPC listening" );
+
+ // Wait until the objects are released.
+ server_loop();
+
+ // Finally, its all over.
+ success = TRUE;
+cleanup:
+ if (thread != NULL)
+ CloseHandle( thread );
+ CoUninitialize();
+
+ if (success)
+ printf( "\n\nLoad_Server Test Passed.\n" );
+ else
+ printf( "\n\nLoad_Server Test Failed.\n" );
+}
+
+ /***************************************************************************/
+void do_lots()
+{
+ do_cancel();
+ do_crash();
+ do_null();
+ do_ring();
+ do_rundown();
+}
+
+ /***************************************************************************/
+void do_mmarshal()
+{
+ BOOL success = FALSE;
+ ITest *client1 = NULL;
+ ITest *client2 = NULL;
+ ITest *test = NULL;
+ ITest *callee = NULL;
+ HRESULT result;
+
+ // Initialize OLE.
+ hello( "mmarshal" );
+ result = initialize(NULL,ThreadMode);
+ ASSERT( result, "Initialize failed" );
+
+ // Create a client.
+ result = CoCreateInstance( *ServerClsid, NULL, CLSCTX_LOCAL_SERVER,
+ IID_ITest, (void **) &client1 );
+ ASSERT( result, "Could not create instance of test server" );
+
+ // Create a client.
+ result = CoCreateInstance( *ServerClsid, NULL, CLSCTX_LOCAL_SERVER,
+ IID_ITest, (void **) &client2 );
+ ASSERT( result, "Could not create instance of test server" );
+
+ // Create a client.
+ result = CoCreateInstance( *ServerClsid, NULL, CLSCTX_LOCAL_SERVER,
+ IID_ITest, (void **) &test );
+ ASSERT( result, "Could not create instance of test server" );
+
+ // Create a client.
+ result = CoCreateInstance( *ServerClsid, NULL, CLSCTX_LOCAL_SERVER,
+ IID_ITest, (void **) &callee );
+ ASSERT( result, "Could not create instance of test server" );
+
+ // Tell the first client to start calling the test object.
+ result = client1->interrupt_marshal( test, callee);
+ ASSERT( result, "Could not start client" );
+
+ // Tell the first client to start calling the test object.
+ result = client2->interrupt_marshal( test, callee);
+ ASSERT( result, "Could not start client" );
+
+ // Finally, its all over.
+ success = TRUE;
+cleanup:
+ if (client1 != NULL)
+ client1->Release();
+ if (client2 != NULL)
+ client2->Release();
+ if (test != NULL)
+ test->Release();
+ if (callee != NULL)
+ callee->Release();
+ CoUninitialize();
+
+ if (success)
+ printf( "\n\nMultiple marshal Test passed if all server processes exit.\n" );
+ else
+ printf( "\n\nMultiple marshal Test Failed.\n" );
+}
+
+ /***************************************************************************/
+void do_null()
+{
+ HRESULT result;
+ BOOL success = FALSE;
+ ITest *test = NULL;
+ SAptId id;
+
+ // Initialize OLE.
+ hello( "null" );
+ result = initialize(NULL,ThreadMode);
+ ASSERT( result, "Initialize failed" );
+
+ // Get a test object on another apartment.
+ result = new_apartment_test( &test, &id, NULL );
+ ASSERT( result, "Could not create apartment instance of test server" );
+
+ // Call the test object.
+ result = test->check( id );
+ ASSERT( result, "Could not call check in another apartment" );
+
+ // Finally, its all over.
+ success = TRUE;
+cleanup:
+ if (test != NULL)
+ test->Release();
+ CoUninitialize();
+
+ if (success)
+ printf( "\n\nNull Test Passed.\n" );
+ else
+ printf( "\n\nNull Test Failed.\n" );
+}
+
+ /***************************************************************************/
+void do_one()
+{
+ BOOL success = FALSE;
+ ITest *server = NULL;
+ ITest *server2 = NULL;
+ ITest *local = NULL;
+ ITest *local2 = NULL;
+ SAptId id_server;
+ SAptId id_server2;
+ SAptId id_local;
+ SAptId id_local2;
+ HRESULT result;
+ DWORD i;
+
+ // Initialize OLE.
+ hello( "one" );
+ result = initialize(NULL,ThreadMode);
+ ASSERT( result, "Initialize failed" );
+
+ // Create a possibly remote object.
+ result = create_instance( *ServerClsid, &server, &id_server );
+ ASSERT( result, "Could not create server" );
+
+ // Test delegation
+ if (ThreadMode != COINIT_MULTITHREADED)
+ {
+ // Create a local server
+ result = new_apartment_test( &local, &id_local, NULL );
+ ASSERT( result, "Could not create local instance of test server" );
+
+ // Create a local server
+ result = new_apartment_test( &local2, &id_local2, NULL );
+ ASSERT( result, "Could not create local instance of test server" );
+
+ success = do_security_delegate( local, id_local, local2, id_local2 );
+ if (!success)
+ goto cleanup;
+ success = FALSE;
+ }
+
+ // Create a client possibly on a remote machine.
+ result = create_instance( *ServerClsid, &server2, &id_server2 );
+ ASSERT( result, "Could not create instance of test server" );
+ ASSERT_EXPR( server2 != NULL, "Create instance returned NULL." );
+
+ // Test delegation
+ success = do_security_delegate( server, id_server, server2, id_server2 );
+ if (!success)
+ goto cleanup;
+ success = FALSE;
+
+ // Set security.
+ result = MCoSetProxyBlanket( server, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE,
+ NULL, RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
+ RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE );
+ ASSERT( result, "Could not set blanket" );
+
+ // Verify the authentication information.
+ DWORD authn_svc_out, authz_svc_out, authn_level_out, imp_level_out;
+ WCHAR *princ_name_out;
+ result = MCoQueryProxyBlanket( server, &authn_svc_out, &authz_svc_out,
+ &princ_name_out, &authn_level_out,
+ &imp_level_out, NULL, NULL );
+ if (result == S_OK)
+ {
+ ASSERT_EXPR( princ_name_out == NULL, "Got a principle name." );
+ ASSERT_EXPR( RPC_C_AUTHN_LEVEL_PKT_PRIVACY <= authn_level_out, "Wrong authentication level." );
+ ASSERT_EXPR( RPC_C_IMP_LEVEL_IMPERSONATE == imp_level_out, "Wrong impersonation level." );
+ ASSERT_EXPR( RPC_C_AUTHN_WINNT == authn_svc_out, "Wrong authentication service." );
+ ASSERT_EXPR( RPC_C_AUTHZ_NONE == authz_svc_out, "Wrong authorization service." );
+ }
+
+ // Call it.
+ result = server->check( id_server );
+ ASSERT( result, "Could not check server" );
+
+ // Set security.
+ result = MCoSetProxyBlanket( server, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE,
+ NULL, RPC_C_AUTHN_LEVEL_NONE,
+ RPC_C_IMP_LEVEL_IDENTIFY, NULL, EOAC_NONE );
+ ASSERT( result, "Could not set blanket" );
+
+ // Call it.
+ result = server->check( id_server );
+ ASSERT( result, "Could not check server" );
+
+ // Test nested impersonation for a remote object.
+ success = do_security_nested( server, id_server );
+ if (!success)
+ goto cleanup;
+ success = FALSE;
+
+ // Finally, its all over.
+ success = TRUE;
+cleanup:
+ if (server2 != NULL)
+ server2->Release();
+ if (server != NULL)
+ server->Release();
+ if (local != NULL)
+ local->Release();
+ if (local2 != NULL)
+ local2->Release();
+ CoUninitialize();
+
+ if (success)
+ printf( "\n\nOne Test Passed.\n" );
+ else
+ printf( "\n\nOne Test Failed.\n" );
+}
+
+ /***************************************************************************/
+void do_perf()
+{
+ BOOL success = FALSE;
+ ITest *client1 = NULL;
+ ITest *client2 = NULL;
+ ITest *tmp = NULL;
+ CTest *local = NULL;
+ SAptId id;
+ HRESULT result;
+ DWORD time_remote = -1;
+ DWORD time_local = -1;
+ DWORD time_in = -1;
+ DWORD time_out = -1;
+ DWORD time_lin = -1;
+ DWORD time_lout = -1;
+ int i;
+
+ // Initialize OLE.
+ hello( "perf" );
+ result = initialize(NULL,ThreadMode);
+ ASSERT( result, "Initialize failed" );
+
+ // Create a client.
+ result = CoCreateInstance( *ServerClsid, NULL, CLSCTX_LOCAL_SERVER,
+ IID_ITest, (void **) &client1 );
+ ASSERT( result, "Could not create instance of test server" );
+/**/
+ // Call once to make sure everything is set up.
+ result = client1->null();
+ ASSERT( result, "Could not make null call" );
+
+ // Call a lot of times.
+ time_remote = GetTickCount();
+ for (i = 0; i < NumIterations; i++)
+ {
+ result = client1->null();
+ ASSERT( result, "Could not make null call" );
+ }
+ time_remote = GetTickCount() - time_remote;
+/**/
+ // Create a local client
+ result = new_apartment_test( &client2, &id, NULL );
+ ASSERT( result, "Could not create local client" );
+/**/
+ // Call once to make sure everything is set up.
+ result = client2->null();
+ ASSERT( result, "Could not make null call" );
+
+ // Call a lot of times.
+ time_local = GetTickCount();
+ for (i = 0; i < NumIterations; i++)
+ {
+ result = client2->null();
+ ASSERT( result, "Could not make null call" );
+ }
+ time_local = GetTickCount() - time_local;
+/**/
+ // Create a local object.
+ local = new CTest;
+ ASSERT_EXPR( local != NULL, "Could not create local object" );
+/**/
+ // Pass it to the server once.
+ result = client1->interface_in( local );
+ ASSERT( result, "Could not pass in interface" );
+
+ // Pass it to the server a lot of times.
+ time_in = GetTickCount();
+ for (i = 0; i < NumIterations; i++)
+ {
+ result = client1->interface_in( local );
+ ASSERT( result, "Could not pass in interface" );
+ }
+ time_in = GetTickCount() - time_in;
+
+ // Create another remote object.
+ result = client1->get_obj_from_this_apt( &tmp, &id );
+ ASSERT( result, "Could not get new object." );
+
+ // Have the server remember it.
+ result = client1->remember( tmp, id );
+ ASSERT( result, "Could not remember object" );
+ tmp->Release();
+ tmp = NULL;
+
+ // Get and release the remote object a lot of times.
+ time_out = GetTickCount();
+ for (i = 0; i < NumIterations; i++)
+ {
+ result = client1->get_next( &tmp, &id );
+ ASSERT( result, "Could not pass out interface" );
+ tmp->Release();
+ tmp = NULL;
+ }
+ time_out = GetTickCount() - time_out;
+ client1->forget();
+/**/
+ // Pass the object from this thread to another thread once.
+ result = client2->interface_in( local );
+ ASSERT( result, "Could not pass in interface" );
+
+ // Pass the object from this thread to another thread.
+ time_lin = GetTickCount();
+ for (i = 0; i < NumIterations; i++)
+ {
+ result = client2->interface_in( local );
+ ASSERT( result, "Could not pass in interface" );
+ }
+ time_lin = GetTickCount() - time_lin;
+/**/
+ // Create another remote object.
+ result = client2->get_obj_from_this_apt( &tmp, &id );
+ ASSERT( result, "Could not get new object." );
+
+ // Have the server remember it.
+ result = client2->remember( tmp, id );
+ ASSERT( result, "Could not remember object" );
+ tmp->Release();
+ tmp = NULL;
+
+ // Get and release the remote object a lot of times.
+ time_lout = GetTickCount();
+ for (i = 0; i < NumIterations; i++)
+ {
+ result = client2->get_next( &tmp, &id );
+ ASSERT( result, "Could not pass out interface" );
+ tmp->Release();
+ tmp = NULL;
+ }
+ time_lout = GetTickCount() - time_lout;
+ client2->forget();
+/**/
+ // Print the results.
+ printf( "%d uS / Local Call\n", time_local*1000/NumIterations );
+ printf( "%d uS / Remote Call\n", time_remote*1000/NumIterations );
+ printf( "%d uS / Interface In Call\n", time_in*1000/NumIterations );
+ printf( "%d uS / Interface Out Call\n", time_out*1000/NumIterations );
+ printf( "%d uS / Local Interface In Call\n", time_lin*1000/NumIterations );
+ printf( "%d uS / Local Interface Out Call\n", time_lout*1000/NumIterations );
+
+ // Finally, its all over.
+ success = TRUE;
+cleanup:
+ if (tmp != NULL)
+ tmp->Release();
+ if (client1 != NULL)
+ client1->Release();
+ if (client2 != NULL)
+ client2->Release();
+ if (local != NULL)
+ local->Release();
+ CoUninitialize();
+
+ if (success)
+ printf( "\n\nPerf Test Passed.\n" );
+ else
+ printf( "\n\nPerf Test Failed.\n" );
+}
+
+ /***************************************************************************/
+void do_perfremote()
+{
+ BOOL success = FALSE;
+ ITest *client1 = NULL;
+ SAptId id;
+ HRESULT result;
+ DWORD time_remote;
+ int i;
+
+ // Initialize OLE.
+ hello( "Perf Remote" );
+ result = initialize(NULL,ThreadMode);
+ ASSERT( result, "Initialize failed" );
+
+ // Create a client.
+ result = CoCreateInstance( *ServerClsid, NULL, CLSCTX_LOCAL_SERVER,
+ IID_ITest, (void **) &client1 );
+ ASSERT( result, "Could not create instance of test server" );
+
+ // Call once to make sure everything is set up.
+ result = client1->null();
+ ASSERT( result, "Could not make null call" );
+
+ // Call a lot of times.
+ time_remote = GetTickCount();
+ for (i = 0; i < NumIterations; i++)
+ {
+ result = client1->null();
+ ASSERT( result, "Could not make null call" );
+ }
+ time_remote = GetTickCount() - time_remote;
+
+ // Print the results.
+ printf( "%d uS / Remote Call\n", time_remote*1000/NumIterations );
+
+ // Finally, its all over.
+ success = TRUE;
+cleanup:
+ if (client1 != NULL)
+ client1->Release();
+ CoUninitialize();
+
+ if (success)
+ printf( "\n\nPerf Test Passed.\n" );
+ else
+ printf( "\n\nPerf Test Failed.\n" );
+}
+
+ /***************************************************************************/
+void do_perfrpc()
+{
+ BOOL success = FALSE;
+ ITest *client1 = NULL;
+ SAptId id;
+ HRESULT result;
+ int i;
+ WCHAR *binding = NULL;
+ RPC_BINDING_HANDLE handle = NULL;
+ RPC_BINDING_HANDLE copy = NULL;
+ RPC_BINDING_HANDLE object = NULL;
+ RPC_STATUS status;
+ DWORD time_remote;
+ DWORD time_integrity;
+ DWORD time_copy;
+ DWORD time_copy_secure;
+ DWORD time_object;
+ UUID object_id;
+
+ // Initialize OLE.
+ hello( "Perf RPC" );
+ result = initialize(NULL,ThreadMode);
+ ASSERT( result, "Initialize failed" );
+
+ // Create a client.
+ result = create_instance( *ServerClsid, &client1, &id );
+ ASSERT( result, "Could not create instance of test server" );
+
+ // Ask the server to register rpc.
+ result = client1->register_rpc( TestProtseq, &binding );
+ ASSERT( result, "Could not register rpc interface" );
+
+ // Create a binding handle.
+ status = RpcBindingFromStringBinding( binding, &handle );
+ if (status != RPC_S_OK)
+ {
+ printf( "Could not make binding handle form string binding: 0x%x\n", status );
+ goto cleanup;
+ }
+
+ // Get a binding handle for the object id test.
+ status = RpcBindingCopy( handle, &object );
+ ASSERT( status, "Could not copy binding" );
+
+ // Copy the binding handle once.
+ status = RpcBindingCopy( handle, &copy );
+ ASSERT( status, "Could not copy binding" );
+ RpcBindingFree( &copy );
+ copy = NULL;
+
+ // Time copying the binding handle.
+ time_copy = GetTickCount();
+ for (i = 0; i < NumIterations; i++)
+ {
+ status = RpcBindingCopy( handle, &copy );
+ ASSERT( status, "Could not copy binding" );
+ RpcBindingFree( &copy );
+ copy = NULL;
+ }
+ time_copy = GetTickCount() - time_copy;
+
+ // Make a raw rpc call to make sure everything is set up.
+ nullcall( handle );
+
+ // Call a lot of times.
+ time_remote = GetTickCount();
+ for (i = 0; i < NumIterations; i++)
+ {
+ nullcall( handle );
+ }
+ time_remote = GetTickCount() - time_remote;
+
+ // Set the object id.
+ result = RpcBindingSetObject( object, &object_id );
+ ASSERT( result, "Could not set object id" );
+
+ // Make a raw rpc call to make sure everything is set up.
+ nullcall( object );
+
+ // Call a lot of times.
+ time_object = GetTickCount();
+ for (i = 0; i < NumIterations; i++)
+ {
+ nullcall( object );
+ }
+ time_object = GetTickCount() - time_object;
+
+ // Add security.
+ status = RpcBindingSetAuthInfo( handle, L"none", RPC_C_AUTHN_LEVEL_PKT_INTEGRITY,
+ RPC_C_AUTHN_WINNT, NULL, 0 );
+ ASSERT( status, "Could not set auth info" );
+
+ // Copy the binding handle once.
+ status = RpcBindingCopy( handle, &copy );
+ ASSERT( status, "Could not copy binding" );
+ RpcBindingFree( &copy );
+ copy = NULL;
+
+ // Time copying the binding handle.
+ time_copy_secure = GetTickCount();
+ for (i = 0; i < NumIterations; i++)
+ {
+ status = RpcBindingCopy( handle, &copy );
+ ASSERT( status, "Could not copy binding" );
+ RpcBindingFree( &copy );
+ copy = NULL;
+ }
+ time_copy_secure = GetTickCount() - time_copy_secure;
+
+ // Make a raw rpc call to make sure everything is set up.
+ nullcall( handle );
+
+ // Call a lot of times.
+ time_integrity = GetTickCount();
+ for (i = 0; i < NumIterations; i++)
+ {
+ nullcall( handle );
+ }
+ time_integrity = GetTickCount() - time_integrity;
+
+ // Print the results.
+ printf( "%d uS / Raw RPC Remote Call\n", time_remote*1000/NumIterations );
+ printf( "%d uS / Raw Integrity RPC Remote Call\n", time_integrity*1000/NumIterations );
+ printf( "%d uS / Raw RPC with OID Remote Call\n", time_object*1000/NumIterations );
+ printf( "%d uS / handle copy\n", time_copy*1000/NumIterations );
+ printf( "%d uS / secure handle copy\n", time_copy_secure*1000/NumIterations );
+
+ // Finally, its all over.
+ success = TRUE;
+cleanup:
+ if (client1 != NULL)
+ client1->Release();
+ if (binding != NULL)
+ CoTaskMemFree( binding );
+ if (copy != NULL)
+ RpcBindingFree( &copy );
+ if (object != NULL)
+ RpcBindingFree( &object );
+ if (handle != NULL)
+ RpcBindingFree( &handle );
+ CoUninitialize();
+
+ if (success)
+ printf( "\n\nPerf Test Passed.\n" );
+ else
+ printf( "\n\nPerf Test Failed.\n" );
+}
+
+ /***************************************************************************/
+void do_perfsec()
+{
+ BOOL success = FALSE;
+ ITest *server = NULL;
+ ITest *copy = NULL;
+ SAptId id;
+ HRESULT result;
+ WCHAR *binding = NULL;
+ //DWORD time_null;
+ DWORD time_impersonate;
+ DWORD time_acl;
+ DWORD time_audit;
+ DWORD i;
+ DWORD j;
+ RPC_BINDING_HANDLE handle = NULL;
+ RPC_STATUS status;
+ TOKEN_USER *token_info = NULL;
+ DWORD info_size = 1024;
+ HANDLE token = NULL;
+ PSID pSID = NULL;
+ DWORD level[4];
+ DWORD time_rpc[4];
+ DWORD time_null[4];
+ DWORD time_ifin[4];
+ DWORD time_ifout[4];
+ CTest local;
+ ITest *server2 = NULL;
+ LARGE_INTEGER start;
+ LARGE_INTEGER nothing;
+ LARGE_INTEGER init_sec_none;
+ LARGE_INTEGER init_sec_con;
+ LARGE_INTEGER reg_sec;
+ LARGE_INTEGER query_proxy;
+ LARGE_INTEGER set_proxy;
+ LARGE_INTEGER copy_proxy;
+ LARGE_INTEGER freq;
+ DWORD get_call;
+ DWORD query_client;
+ DWORD impersonate;
+ DWORD revert;
+ DWORD authn_svc;
+ DWORD authz_svc;
+ DWORD authn_level;
+ DWORD imp_level;
+ DWORD capabilities;
+ WCHAR *principal = NULL;
+ SOLE_AUTHENTICATION_SERVICE svc_list;
+
+ // Initialize OLE.
+ hello( "perfsec" );
+ result = initialize(NULL,ThreadMode);
+ ASSERT( result, "Initialize failed" );
+
+ // Import the security APIs.
+ GCoCopyProxy = (CoCopyProxyFn) Fixup( "CoCopyProxy" );
+ GCoInitializeSecurity = (CoInitializeSecurityFn) Fixup( "CoInitializeSecurity" );
+ GCoQueryProxyBlanket = (CoQueryProxyBlanketFn) Fixup( "CoQueryProxyBlanket" );
+ GCoSetProxyBlanket = (CoSetProxyBlanketFn) Fixup( "CoSetProxyBlanket" );
+ if (GCoCopyProxy == NULL ||
+ GCoInitializeSecurity == NULL ||
+ GCoQueryProxyBlanket == NULL ||
+ GCoSetProxyBlanket == NULL)
+ goto cleanup;
+
+ // Measure the performance of nothing.
+ QueryPerformanceFrequency( &freq );
+ QueryPerformanceCounter( &start );
+ QueryPerformanceCounter( &nothing );
+ nothing.QuadPart = 1000000 * (nothing.QuadPart - start.QuadPart) / freq.QuadPart;
+
+ // Measure the performance of initialize.
+ QueryPerformanceCounter( &start );
+ result = MCoInitializeSecurity( NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_NONE,
+ RPC_C_IMP_LEVEL_IMPERSONATE, NULL,
+ EOAC_NONE, NULL );
+ QueryPerformanceCounter( &init_sec_none );
+ init_sec_none.QuadPart = 1000000 * (init_sec_none.QuadPart - start.QuadPart) / freq.QuadPart;
+ ASSERT( result, "Could not initialize security" );
+
+ // Reinitialize.
+ CoUninitialize();
+ result = initialize(NULL,ThreadMode);
+ ASSERT( result, "Reinitialize failed" );
+
+ // Measure the performance of initialize.
+ QueryPerformanceCounter( &start );
+ result = MCoInitializeSecurity( NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_CONNECT,
+ RPC_C_IMP_LEVEL_IMPERSONATE, NULL,
+ EOAC_NONE, NULL );
+ QueryPerformanceCounter( &init_sec_con );
+ init_sec_con.QuadPart = 1000000 * (init_sec_con.QuadPart - start.QuadPart) / freq.QuadPart;
+ ASSERT( result, "Could not initialize security at connect" );
+
+ // Reinitialize.
+ CoUninitialize();
+ result = initialize(NULL,ThreadMode);
+ ASSERT( result, "Reinitialize failed" );
+
+ // Measure the performance of register.
+ svc_list.dwAuthnSvc = RPC_C_AUTHN_WINNT;
+ svc_list.dwAuthzSvc = RPC_C_AUTHZ_NONE;
+ svc_list.pPrincipalName = NULL;
+ QueryPerformanceCounter( &start );
+ result = MCoInitializeSecurity( NULL, 1, &svc_list, NULL,
+ RPC_C_AUTHN_LEVEL_NONE,
+ RPC_C_IMP_LEVEL_IMPERSONATE, NULL,
+ EOAC_NONE, NULL );
+ QueryPerformanceCounter( &reg_sec );
+ reg_sec.QuadPart = 1000000 * (reg_sec.QuadPart - start.QuadPart) / freq.QuadPart;
+ ASSERT( result, "Could not initialize security with authentication services" );
+
+ // Create a client.
+ result = create_instance( *ServerClsid, &server, &id );
+ ASSERT( result, "Could not create instance of test server" );
+
+ // Measure the performance of set proxy.
+ QueryPerformanceCounter( &start );
+ result = MCoSetProxyBlanket( server, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE,
+ NULL, RPC_C_AUTHN_LEVEL_CONNECT, 0, NULL, 0 );
+ QueryPerformanceCounter( &set_proxy );
+ set_proxy.QuadPart = 1000000 * (set_proxy.QuadPart - start.QuadPart) / freq.QuadPart;
+ ASSERT( result, "Could not set proxy" );
+
+ // Measure the performance of query proxy
+ QueryPerformanceCounter( &start );
+ result = MCoQueryProxyBlanket( server, &authn_svc, &authz_svc, &principal,
+ &authn_level, &imp_level, NULL, &capabilities );
+ QueryPerformanceCounter( &query_proxy );
+ query_proxy.QuadPart = 1000000 * (query_proxy.QuadPart - start.QuadPart) / freq.QuadPart;
+ ASSERT( result, "Could not query_proxy" );
+
+ // Measure the performance of copy proxy.
+ QueryPerformanceCounter( &start );
+ result = MCoCopyProxy( server, (IUnknown **) &copy );
+ QueryPerformanceCounter( &copy_proxy );
+ copy_proxy.QuadPart = 1000000 * (copy_proxy.QuadPart - start.QuadPart) / freq.QuadPart;
+ ASSERT( result, "Could not copy proxy" );
+
+ // Make a call to measure the performance of the server side APIs.
+ result = server->security_performance( &get_call, &query_client, &impersonate,
+ &revert );
+ ASSERT( result, "Could not get server API performance" );
+
+ // Ask the server to register rpc.
+ result = server->register_rpc( TestProtseq, &binding );
+ ASSERT( result, "Could not register rpc interface" );
+
+ // Create a binding handle.
+ status = RpcBindingFromStringBinding( binding, &handle );
+ if (status != RPC_S_OK)
+ {
+ printf( "Could not make binding handle from string binding: 0x%x\n", status );
+ goto cleanup;
+ }
+
+ // Create another remote object.
+ result = server->get_obj_from_this_apt( &server2, &id );
+ ASSERT( result, "Could not get new object." );
+
+ // Have the server remember it.
+ result = server->remember( server2, id );
+ ASSERT( result, "Could not remember object" );
+ server2->Release();
+ server2 = NULL;
+
+ // Try several security levels.
+ level[0] = RPC_C_AUTHN_LEVEL_NONE;
+ level[1] = RPC_C_AUTHN_LEVEL_CONNECT;
+ level[2] = RPC_C_AUTHN_LEVEL_PKT_INTEGRITY;
+ level[3] = RPC_C_AUTHN_LEVEL_PKT_PRIVACY;
+ for (j = 0; j < 4; j++)
+ {
+ // Set security on the RPC binding handle.
+ result = RpcBindingSetAuthInfo( handle, NULL, level[j], RPC_C_AUTHN_WINNT,
+ NULL, RPC_C_AUTHZ_NONE );
+ ASSERT( result, "Could not set rpc auth info" );
+
+ // Set security on the proxy.
+ result = MCoSetProxyBlanket( server, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE,
+ NULL, level[j], RPC_C_IMP_LEVEL_IMPERSONATE,
+ NULL, EOAC_NONE );
+ ASSERT( result, "Could not set DCOM auth info" );
+
+ // Make a raw rpc call to make sure everything is set up.
+ nullcall( handle );
+
+ // Make some raw rpc calls.
+ time_rpc[j] = GetTickCount();
+ for (i = 0; i < NumIterations; i++)
+ {
+ nullcall( handle );
+ }
+ time_rpc[j] = GetTickCount() - time_rpc[j];
+
+ // Make a null dcom call to make sure everything is set up.
+ result = server->null();
+ ASSERT( result, "Could not make null call" );
+
+ // Put up a popup about the test starting.
+ if (Popup)
+ MessageBox( NULL, L"Now would be a good time to start ICECAP.",
+ L"Not Me", MB_YESNO | MB_ICONEXCLAMATION );
+
+ // Make some null calls.
+ time_null[j] = GetTickCount();
+ for (i = 0; i < NumIterations; i++)
+ {
+ result = server->null();
+ ASSERT( result, "Could not make null call" );
+ }
+ time_null[j] = GetTickCount() - time_null[j];
+
+ // Put up a popup about the test stopping.
+ if (Popup)
+ MessageBox( NULL, L"Now would be a good time to stop ICECAP.",
+ L"Not Me", MB_YESNO | MB_ICONSTOP );
+
+ // Pass an interface in to set everything up.
+ result = server->interface_in( &local );
+ ASSERT( result, "Could not make interface_in call" );
+
+ // Make some interface in calls.
+ time_ifin[j] = GetTickCount();
+ for (i = 0; i < NumIterations; i++)
+ {
+ result = server->interface_in( &local );
+ ASSERT( result, "Could not make interface_in call" );
+ }
+ time_ifin[j] = GetTickCount() - time_ifin[j];
+
+ // Pass an interface out to set everything up.
+ result = server->get_next( &server2, &id );
+ ASSERT( result, "Could not make interface out call" );
+ server2->Release();
+ server2 = NULL;
+
+ // Make some interface_out calls.
+ time_ifout[j] = GetTickCount();
+ for (i = 0; i < NumIterations; i++)
+ {
+ result = server->get_next( &server2, &id );
+ ASSERT( result, "Could not make interface out call" );
+ server2->Release();
+ server2 = NULL;
+ }
+ time_ifout[j] = GetTickCount() - time_ifout[j];
+ }
+
+ // Release the second remote object.
+ result = server->forget();
+ ASSERT( result, "Could not forget" );
+
+ // Print the DCOM call results.
+ for (j = 0; j < 4; j++)
+ {
+ printf( "% 8d uS / Raw RPC Remote Call at level %d\n",
+ time_rpc[j]*1000/NumIterations, level[j] );
+ printf( "% 8d uS / Null Remote Call at level %d\n",
+ time_null[j]*1000/NumIterations, level[j] );
+ printf( "% 8d uS / Interface in Remote Call at level %d\n",
+ time_ifin[j]*1000/NumIterations, level[j] );
+ printf( "% 8d uS / Interface out Remote Call at level %d\n",
+ time_ifout[j]*1000/NumIterations, level[j] );
+ }
+
+ // Print the API call results.
+ printf( "nothing took %duS\n", nothing.u.LowPart );
+ printf( "CoInitializeSecurity at none took %duS\n", init_sec_none.u.LowPart );
+ printf( "CoInitializeSecurity at connect took %duS\n", init_sec_con.u.LowPart );
+ printf( "CoInitializeSecurity with service took %duS\n", reg_sec.u.LowPart );
+ printf( "CoQueryProxyBlanket took %duS\n", query_proxy.u.LowPart );
+ printf( "CoSetProxyBlanket took %duS\n", set_proxy.u.LowPart );
+ printf( "CoCopyProxy took %duS\n", copy_proxy.u.LowPart );
+ printf( "CoGetCallContext took %duS\n", get_call );
+ printf( "CoQueryClientBlanket took %duS\n", query_client );
+ printf( "CoImpersonateClient took %duS\n", impersonate );
+ printf( "CoRevertToSelf took %duS\n", revert );
+
+/*
+ // Open the process's token.
+ OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY, &token );
+ result = GetLastError();
+ ASSERT( result, "Could not OpenProcessToken" );
+
+ // Lookup SID of process token.
+ token_info = (TOKEN_USER *) malloc( info_size );
+ GetTokenInformation( token, TokenUser, token_info, info_size, &info_size );
+ result = GetLastError();
+ ASSERT( result, "Could not GetTokenInformation" );
+ pSID = token_info->User.Sid;
+
+ // Ask the server to make an ACL.
+ result = server->make_acl( (HACKSID *) pSID );
+ ASSERT( result, "Could not make ACL" );
+
+ // Make a raw rpc call to make sure everything is set up.
+ nullcall( handle );
+
+ // Call a lot of times.
+ time_null = GetTickCount();
+ for (i = 0; i < NumIterations; i++)
+ {
+ nullcall( handle );
+ }
+ time_null = GetTickCount() - time_null;
+
+ // Call a lot of times.
+ time_impersonate = GetTickCount();
+ for (i = 0; i < NumIterations; i++)
+ {
+ result = impersonate_call( handle );
+ ASSERT( result, "Could not make impersonate call" );
+ }
+ time_impersonate = GetTickCount() - time_impersonate;
+
+ // Call a lot of times.
+ time_acl = GetTickCount();
+ for (i = 0; i < NumIterations; i++)
+ {
+ result = acl_call( handle );
+ ASSERT( result, "Could not make acl call" );
+ }
+ time_acl = GetTickCount() - time_acl;
+
+ // Call a lot of times.
+ time_audit = GetTickCount();
+ for (i = 0; i < NumIterations; i++)
+ {
+ result = audit_call( handle );
+ ASSERT( result, "Could not make audit call" );
+ }
+ time_audit = GetTickCount() - time_audit;
+
+ // Print the results.
+ printf( "%d uS / Raw RPC Remote Call\n", time_null*1000/NumIterations );
+ printf( "%d uS / Raw Impersonate RPC Remote Call\n", time_impersonate*1000/NumIterations );
+ printf( "%d uS / Raw ACL RPC Remote Call\n", time_acl*1000/NumIterations );
+ printf( "%d uS / Raw audit RPC Remote Call\n", time_audit*1000/NumIterations );
+*/
+ // Finally, its all over.
+ success = TRUE;
+cleanup:
+ if (principal != NULL)
+ CoTaskMemFree( principal );
+ if (copy != NULL)
+ copy->Release();
+ if (server != NULL)
+ server->Release();
+ if (server2 != NULL)
+ server2->Release();
+ if (binding != NULL)
+ CoTaskMemFree( binding );
+ if (handle != NULL)
+ RpcBindingFree( &handle );
+ if (token_info != NULL)
+ free( token_info );
+ if (token != NULL)
+ CloseHandle( token );
+ CoUninitialize();
+
+ if (success)
+ printf( "\n\nSec Test Passed.\n" );
+ else
+ printf( "\n\nSec Test Failed.\n" );
+}
+
+ /***************************************************************************/
+void do_post()
+{
+ BOOL success = FALSE;
+
+ // Say hello.
+ printf( "Posting a message to window 0x%x\n", NumIterations );
+ success = PostMessageA( (HWND) NumIterations, WM_USER, 0, 0 );
+
+ if (success)
+ printf( "\n\nPostMessageA succeeded.\n" );
+ else
+ printf( "\n\nPostMessageA failed: 0x%x\n", GetLastError() );
+}
+
+ /***************************************************************************/
+void do_reject()
+{
+ BOOL success = FALSE;
+ ITest *client1 = NULL;
+ ITest *client2 = NULL;
+ SAptId id1;
+ SAptId id2;
+ IAdviseSink *advise1 = NULL;
+ IAdviseSink *advise2 = NULL;
+ HRESULT result;
+ CTest *local = NULL;
+
+ // Initialize OLE.
+ hello( "reject" );
+ result = initialize(NULL,ThreadMode);
+ ASSERT( result, "Initialize failed" );
+
+ // Create a local object.
+ local = new CTest;
+ ASSERT_EXPR( local != NULL, "Could not create local instance of test server." );
+
+ // Create a server
+ result = CoCreateInstance( *ServerClsid, NULL, CLSCTX_LOCAL_SERVER,
+ IID_ITest, (void **) &client1 );
+ ASSERT( result, "Could not create instance of test server" );
+ result = client1->get_id( &id1 );
+ ASSERT( result, "Could not get id of server" );
+
+ // Register the local message filter.
+ result = local->register_message_filter( TRUE );
+ ASSERT( result, "Could not register message filter." );
+
+ // Register the remote message filter.
+ result = client1->register_message_filter( TRUE );
+ ASSERT( result, "Could not register message filter." );
+
+ // Make the server reject the next call.
+ result = client1->reject_next();
+ ASSERT( result, "Could not reject next call" );
+
+ // Make us retry the next rejected call.
+ result = local->retry_next();
+ ASSERT( result, "Could not retry next call" );
+
+ // Call check.
+ result = client1->check( id1 );
+ ASSERT( result, "Could not check server" );
+
+ // Create a local server.
+ result = local->get_obj_from_new_apt( &client2, &id2 );
+ ASSERT( result, "Could not get in process server" );
+
+ // Register the remote message filter.
+ result = client2->register_message_filter( TRUE );
+ ASSERT( result, "Could not register message filter." );
+
+ // Make the server reject the next call.
+ result = client2->reject_next();
+ ASSERT( result, "Could not reject next call" );
+
+ // Make us retry the next rejected call.
+ result = local->retry_next();
+ ASSERT( result, "Could not retry next call" );
+
+ // Call check.
+ result = client2->check( id2 );
+ ASSERT( result, "Could not check server" );
+
+ // Release the message filters.
+ result = local->register_message_filter( FALSE );
+ ASSERT( result, "Could not deregister message filter." );
+ result = client1->register_message_filter( FALSE );
+ ASSERT( result, "Could not deregister message filter." );
+ result = client2->register_message_filter( FALSE );
+ ASSERT( result, "Could not deregister message filter." );
+
+ // Create an advise object on another process
+ result = client1->get_advise( &advise1 );
+ ASSERT( result, "Could not get advise: 0x%x" );
+
+ // Make an async call.
+ advise1->OnSave();
+
+ // Create an advise object on another thread
+ result = client2->get_advise( &advise2 );
+ ASSERT( result, "Could not get advise: 0x%x" );
+
+ // Make an async call.
+ advise2->OnSave();
+
+ // Finally, its all over.
+ success = TRUE;
+cleanup:
+ if (advise2 != NULL)
+ advise2->Release();
+ if (advise1 != NULL)
+ advise1->Release();
+ if (client2 != NULL)
+ client2->Release();
+ if (client1 != NULL)
+ client1->Release();
+ if (local != NULL)
+ local->Release();
+ CoUninitialize();
+
+ if (success)
+ printf( "\n\nReject Test Passed.\n" );
+ else
+ printf( "\n\nReject Test Failed.\n" );
+}
+
+ /***************************************************************************/
+void do_remote_client()
+{
+ BOOL success = FALSE;
+ ITest *server = NULL;
+ ITest *server2 = NULL;
+ HRESULT result;
+ RPC_BINDING_HANDLE handle = NULL;
+ RPC_STATUS status;
+ WCHAR binding[MAX_NAME];
+ void *buffer = NULL;
+ SAptId id;
+ SAptId id2;
+ HANDLE memory = NULL;
+ IStream *stream = NULL;
+ LARGE_INTEGER pos;
+ DWORD time_rpc;
+ DWORD time_null;
+ DWORD time_marshal;
+ long buf_size;
+ DWORD i;
+
+ // Initialize OLE.
+ hello( "RemoteClient" );
+ result = initialize(NULL,ThreadMode);
+ ASSERT( result, "Initialize failed" );
+
+ // Build binding handle for the server.
+ wsprintf( binding, L"%ws:%ws", TestProtseq, Name );
+ status = RpcBindingFromStringBinding( binding, &handle );
+ if (status != RPC_S_OK)
+ {
+ printf( "Could not make binding handle from string binding: 0x%x\n", status );
+ goto cleanup;
+ }
+
+ // Get a marshalled interface from the server over raw RPC.
+ get_interface_buffer( handle, &buf_size, (unsigned char **) &buffer, &id,
+ (error_status_t *) &status );
+ if (status != RPC_S_OK)
+ {
+ printf( "Could not get buffer containing interface: 0x%x\n", status );
+ goto cleanup;
+ }
+
+ // Allocate memory.
+ memory = GlobalAlloc( GMEM_FIXED, buf_size );
+ ASSERT_EXPR( memory != NULL, "Could not GlobalAlloc." );
+
+ // Create a stream.
+ result = CreateStreamOnHGlobal( memory, TRUE, &stream );
+ ASSERT( result, "Could not create stream" );
+
+ // Write the data.
+ result = stream->Write( buffer, buf_size, NULL );
+ ASSERT( result, "Could not write to stream" );
+
+ // Seek back to the start of the stream.
+ pos.QuadPart = 0;
+ result = stream->Seek( pos, STREAM_SEEK_SET, NULL );
+ ASSERT( result, "Could not seek stream to start" );
+
+ // Unmarshal Interface.
+ result = CoUnmarshalInterface( stream, IID_ITest, (void **) &server );
+ ASSERT( result, "Could not unmarshal interface" );
+
+ // Call once to make sure everything is set up.
+ result = server->null();
+ ASSERT( result, "Could not make null call" );
+
+ // Make a lot of null calls.
+ time_null = GetTickCount();
+ for (i = 0; i < NumIterations; i++)
+ {
+ result = server->null();
+ ASSERT( result, "Could not make null call" );
+ }
+ time_null = GetTickCount() - time_null;
+
+ // Make a lot of marshalling calls.
+ time_marshal = GetTickCount();
+ for (i = 0; i < NumIterations; i++)
+ {
+ result = server->get_obj_from_this_apt( &server2, &id2);
+ ASSERT( result, "Could not make marshal call" );
+ server2->Release();
+ server2 = NULL;
+ }
+ time_marshal = GetTickCount() - time_marshal;
+
+ // Make a lot of RPC calls
+ nullcall( handle );
+ time_rpc = GetTickCount();
+ for (i = 0; i < NumIterations; i++)
+ {
+ nullcall( handle );
+ }
+ time_rpc = GetTickCount() - time_rpc;
+
+ // Print the results.
+ printf( "%d uS / RPC Null Call\n", time_rpc*1000/NumIterations );
+ printf( "%d uS / DCOM Null Call\n", time_null*1000/NumIterations );
+ printf( "%d uS / DCOM Marshal Call\n", time_marshal*1000/NumIterations );
+
+ // Finally, its all over.
+ success = TRUE;
+cleanup:
+ if (server2 != NULL)
+ server2->Release();
+ if (server != NULL)
+ server->Release();
+ if (handle != NULL)
+ RpcBindingFree( &handle );
+ if (buffer != NULL)
+ midl_user_free( buffer );
+ if (stream != NULL)
+ stream->Release();
+ CoUninitialize();
+
+ if (success)
+ printf( "\n\nRemoteClient Test Passed.\n" );
+ else
+ printf( "\n\nRemoteClient Test Failed.\n" );
+}
+
+ /***************************************************************************/
+void do_remote_server()
+{
+ BOOL success = FALSE;
+ SAptId id;
+ HRESULT result;
+ RPC_STATUS status;
+ RPC_BINDING_VECTOR *bindings = NULL;
+
+ // Initialize OLE.
+ hello( "RemoteServer" );
+ result = initialize(NULL,ThreadMode);
+ ASSERT( result, "Initialize failed" );
+
+ // Set up thread switching.
+ GlobalThreadId = GetCurrentThreadId();
+
+ // Create a local server
+ GlobalTest = new CTest;
+ ASSERT( !GlobalTest, "Could not create local server" );
+
+ // Register a protseq.
+ status = RpcServerUseProtseq( TestProtseq, RPC_C_PROTSEQ_MAX_REQS_DEFAULT,
+ NULL );
+ ASSERT( status, "Could not register protseq" );
+
+ // Register the dog interface.
+ status = RpcServerRegisterIf(xIDog_v0_1_s_ifspec,
+ NULL, // MgrTypeUuid
+ NULL); // MgrEpv; null means use default
+ ASSERT( status, "Could not register RPC interface" );
+
+ // Inquire the endpoints.
+ status = RpcServerInqBindings(&bindings);
+ ASSERT( status, "Could not inquire bindings" );
+
+ // Register them in the endpoint mapper.
+ status = RpcEpRegister( xIDog_v0_1_s_ifspec, bindings, NULL, NULL );
+ ASSERT( status, "Could not register with endpoint mapper" );
+
+ // Start RPC listening.
+ status = RpcServerListen( 1, RPC_C_LISTEN_MAX_CALLS_DEFAULT, TRUE );
+ ASSERT( status, "Could not start RPC listening" );
+
+ // Wait until the objects are released.
+ server_loop();
+
+ // Finally, its all over.
+ success = TRUE;
+cleanup:
+ CoUninitialize();
+
+ if (success)
+ printf( "\n\nRemoteServer Test Passed.\n" );
+ else
+ printf( "\n\nRemoteServer Test Failed.\n" );
+}
+
+ /***************************************************************************/
+void do_ring()
+{
+ BOOL success = FALSE;
+ ITest **array = NULL;
+ SAptId *id_array = NULL;
+ HRESULT result;
+ int i;
+ int j;
+ int k;
+ int l;
+ int num_machines;
+ WCHAR this_machine[MAX_NAME];
+ DWORD ignore;
+ int pos;
+ int length;
+ const IID *(all_class_ids[2]);
+ const IID *class_id = ServerClsid;
+
+ // Initialize OLE.
+ hello( "ring" );
+ result = initialize(NULL,ThreadMode);
+ ASSERT( result, "Initialize failed" );
+ CoUninitialize();
+ result = initialize(NULL,ThreadMode);
+ ASSERT( result, "Recalling Initialize failed" );
+ result = initialize_security();
+ ASSERT( result, "Could not initialize security" );
+
+ // Compute the class ids to use.
+ all_class_ids[0] = ServerClsid;
+ i = ServerClsid - &ClassIds[0];
+ all_class_ids[1] = &ClassIds[(i+5) % NUM_CLASS_IDS];
+
+ // Lookup this machine's name.
+ ignore = sizeof(this_machine);
+ GetComputerName( this_machine, &ignore );
+
+ // If the server is this machine, set the number of machines to 1.
+ if (wcscmp(this_machine, Name) == 0)
+ num_machines = 1;
+ else
+ num_machines = 2;
+
+ // Allocate memory to hold all the server pointers.
+ length = NumProcesses * NumThreads * NumObjects * num_machines;
+ array = (ITest **) malloc( sizeof(ITest *) * length );
+ ASSERT_EXPR( array != NULL, "Could not allocate array." );
+ for (i = 0; i < length; i++)
+ array[i] = NULL;
+
+ // Allocate memory to hold all the server ids.
+ id_array = (SAptId *) malloc( sizeof(SAptId) * length );
+ ASSERT_EXPR( id_array != NULL, "Could not allocate id array." );
+
+ // Loop over all the machines.
+ pos = 0;
+ for (l = 0; l < num_machines; l++)
+ {
+ // Loop over all the processes.
+ for (i = 0; i < NumProcesses; i++)
+ {
+ // If the change flag was set, switch between apartment and
+ // free threaded servers.
+ if (Change)
+ class_id = all_class_ids[i&1];
+
+ // Create another server.
+ if (l == 0)
+ result = CoCreateInstance( *class_id, NULL, CLSCTX_LOCAL_SERVER,
+ IID_ITest, (void **) &array[pos] );
+ else
+ result = create_instance( *class_id, &array[pos], &id_array[pos] );
+ ASSERT( result, "Could not create new server process" );
+ result = array[pos]->get_id( &id_array[pos] );
+ ASSERT( result, "Could not get id for new process" );
+ pos += 1;
+
+ for (j = 0; j < NumThreads; j++)
+ {
+ if (j != 0)
+ {
+ result = array[pos-1]->get_obj_from_new_apt( &array[pos],
+ &id_array[pos] );
+ ASSERT( result, "Could not get in process server" );
+ pos += 1;
+ }
+ for (k = 1; k < NumObjects; k++)
+ {
+ result = array[pos-1]->get_obj_from_this_apt( &array[pos],
+ &id_array[pos] );
+ ASSERT( result, "Could not get in thread server" );
+ pos += 1;
+ }
+ }
+ }
+ }
+
+ // Hook up the ring.
+ for (i = 0; i < length-1; i++)
+ {
+ result = array[i]->remember( array[i+1], id_array[i+1] );
+ ASSERT( result, "Could not connect ring" );
+ }
+ result = array[length-1]->remember( array[0], id_array[0] );
+ ASSERT( result, "Could not connect ring" );
+
+ // Call around the ring.
+ for (i = 0; i < NumIterations; i++)
+ {
+ result = array[0]->ring( length );
+ ASSERT( result, "Could not call around the ring" );
+ }
+
+ // Finally, its all over.
+ success = TRUE;
+cleanup:
+
+ // Release all the servers. Start from the end so the main threads do
+ // not go away till all the secondary threads are done.
+ if (array != NULL)
+ for (i = length-1; i >= 0; i--)
+ if (array[i] != NULL)
+ {
+ result = array[i]->forget();
+ if (result != S_OK)
+ printf( "Could not forget server %x: 0x%x\n", i, result );
+ array[i]->Release();
+ }
+
+ // Release the memory holding the interface pointers.
+ if (array != NULL)
+ free(array);
+
+ // Release the memory for ids.
+ if (id_array != NULL)
+ free( id_array );
+ CoUninitialize();
+
+ if (success)
+ printf( "\n\nRing Test Passed.\n" );
+ else
+ printf( "\n\nRing Test Failed.\n" );
+}
+
+ /***************************************************************************/
+void do_rpc()
+{
+ BOOL success = FALSE;
+ ITest *client1 = NULL;
+ CTest *local = NULL;
+ SAptId id1;
+ SAptId id2;
+ HRESULT result;
+ WCHAR *binding = NULL;
+ RPC_BINDING_HANDLE handle = NULL;
+ RPC_STATUS status;
+
+ // Initialize OLE.
+ hello( "rpc" );
+ result = initialize(NULL,ThreadMode);
+ ASSERT( result, "Initialize failed" );
+
+ // Create a free threaded server.
+ result = CoCreateInstance( ClassIds[free_auto_none], NULL, CLSCTX_LOCAL_SERVER,
+ IID_ITest, (void **) &client1 );
+ ASSERT( result, "Could not create instance of test server" );
+ result = client1->get_id( &id1 );
+ ASSERT( result, "Could not get id of server" );
+
+ // Ask the server to register rpc.
+ result = client1->register_rpc( TestProtseq, &binding );
+ ASSERT( result, "Could not register rpc interface" );
+
+ // Create a binding handle.
+ status = RpcBindingFromStringBinding( binding, &handle );
+ if (status != RPC_S_OK)
+ {
+ printf( "Could not make binding handle from string binding: 0x%x\n", status );
+ goto cleanup;
+ }
+
+ // Make a raw rpc call.
+ result = check_client( handle, (unsigned long *) &status );
+ if (status != RPC_S_OK)
+ {
+ printf( "Could not make RPC call: 0x%x\n", status );
+ goto cleanup;
+ }
+ ASSERT( result, "Server could not check client's id" );
+
+ // Create a local object.
+ local = new CTest;
+ ASSERT_EXPR( local != NULL, "Could not create local object." );
+ result = local->get_id( &id2 );
+ ASSERT( result, "Could not get local id" );
+
+ // Pass an interface through a raw rpc call.
+ result = test( handle, local, id2, (unsigned long *) &status );
+ ASSERT( status, "Com fault testing interface with raw rpc" );
+ ASSERT( result, "Could not pass interface through raw rpc" );
+
+ // Finally, its all over.
+ success = TRUE;
+cleanup:
+ if (local != NULL)
+ local->Release();
+ if (client1 != NULL)
+ client1->Release();
+ if (binding != NULL)
+ CoTaskMemFree( binding );
+ if (handle != NULL)
+ RpcBindingFree( &handle );
+ CoUninitialize();
+
+ if (success)
+ printf( "\n\nRpc Test Passed.\n" );
+ else
+ printf( "\n\nRpc Test Failed.\n" );
+}
+
+ /***************************************************************************/
+/*
+ This routine tests various cases of the client or server going away.
+ All permutations of the following variables are tested.
+
+ Clean exit (release and uninit) vs Dirty exit
+ 1 COM thread/process vs 2 COM threads/process
+ Client dies vs Server dies
+ In process death vs Out of process death
+*/
+void do_rundown()
+{
+ BOOL success = FALSE;
+ ITest *client = NULL;
+ ITest *client2 = NULL;
+ SAptId client_id;
+ SAptId client_id2;
+ HRESULT result;
+
+ // Initialize OLE.
+ hello( "rundown" );
+ result = initialize(NULL,ThreadMode);
+ ASSERT( result, "Initialize failed" );
+
+ // Create a client.
+ result = CoCreateInstance( *ServerClsid, NULL, CLSCTX_LOCAL_SERVER,
+ IID_ITest, (void **) &client );
+ ASSERT( result, "Could not create instance of test server" );
+ result = client->get_id( &client_id );
+ ASSERT( result, "Could not get client id" );
+
+ // Run clean tests with one thread per process.
+ success = do_rundown1( &client, &client_id, 0 );
+ if (!success)
+ goto cleanup;
+
+ // Run clean tests with two threads per process.
+ success = do_rundown2( &client, &client_id, 0 );
+ if (!success)
+ goto cleanup;
+
+ // Run dirty tests with one thread per process.
+ success = do_rundown1( &client, &client_id, dirty_s );
+ if (!success)
+ goto cleanup;
+
+ // Run dirty tests with two threads per process.
+ success = do_rundown2( &client, &client_id, dirty_s );
+ if (!success)
+ goto cleanup;
+ success = FALSE;
+
+ // Create helper.
+ result = client->get_obj_from_new_apt( &client2, &client_id2 );
+ ASSERT( result, "Could not get in process server" );
+
+ // Start the test.
+ result = client->recurse_disconnect( client2, NumRecursion );
+ ASSERT( result, "Could not disconnect in a call" );
+ client2->Release();
+ client2 = NULL;
+ client->Release();
+ client = NULL;
+
+ // Create a client.
+ result = CoCreateInstance( *ServerClsid, NULL, CLSCTX_LOCAL_SERVER,
+ IID_ITest, (void **) &client );
+ ASSERT( result, "Could not create instance of test server" );
+ result = client->get_id( &client_id );
+ ASSERT( result, "Could not get client id" );
+
+ // Tell the client to reinitialize.
+ result = client->reinitialize();
+ ASSERT( result, "Could not reinitialize client" );
+
+ // Give the reinitialize a chance to complete before continuing.
+ printf( "Waiting 5 seconds for reinitialize to complete.\n" );
+ Sleep(5000);
+
+ // Create another object on the same client.
+ result = CoCreateInstance( *ServerClsid, NULL, CLSCTX_LOCAL_SERVER,
+ IID_ITest, (void **) &client2 );
+ ASSERT( result, "Could not create instance of test server" );
+
+ // Check the client.
+ result = client2->get_id( &client_id );
+ ASSERT( result, "Could not get_id from client" );
+
+ // Finally, its all over.
+ success = TRUE;
+cleanup:
+ if (client2 != NULL)
+ client2->Release();
+ if (client != NULL)
+ client->Release();
+ CoUninitialize();
+
+ if (success)
+ printf( "\n\nRundown Test Passed.\n" );
+ else
+ printf( "\n\nRundown Test Failed.\n" );
+}
+
+ /***************************************************************************/
+/*
+ This is a helper routine for do_rundown. It always executes with one
+ thread per process of each type (thus a process might have one client and
+ one server thread). It takes a parameter to indicate whether to execute
+ clean or dirty deaths. It executes all permuations of the remaining
+ variables, listed below. Note that the order of execution is important
+ to reduce the number of process creations. Note that the routine takes
+ a client process on entry and returns a different client process on
+ exit.
+
+ Client death vs Server death
+ In process vs Out of process
+*/
+BOOL do_rundown1( ITest **client, SAptId *client_id, DWORD dirty )
+{
+ BOOL success = FALSE;
+ ITest *server = NULL;
+ HRESULT result;
+ SAptId server_id;
+/**/
+ // Create in process server.
+ result = (*client)->get_obj_from_new_apt( &server, &server_id );
+ ASSERT( result, "Could not get in process server" );
+
+ // Ping.
+ result = (*client)->remember( server, server_id );
+ ASSERT( result, "Could not remember server" );
+ result = (*client)->call_next();
+ ASSERT( result, "Could not call server" );
+
+ // Kill server.
+ result = server->set_state( dirty, THREAD_PRIORITY_NORMAL );
+ ASSERT( result, "Could not set_state on server" );
+ result = server->exit();
+ server->Release();
+ server = NULL;
+ ASSERT( result, "Could not exit server" );
+
+ // Query client.
+ result = (*client)->call_dead();
+ ASSERT( result, "Wrong error calling dead server" );
+/**/
+ // Switch the client to server so the process doesn't go away when we kill
+ // the client. Then create an in process client.
+ server = *client;
+ server_id = *client_id;
+ *client = NULL;
+/**/
+ result = server->get_obj_from_new_apt( client, client_id );
+ ASSERT( result, "Could not get in process client" );
+
+ // Ping.
+ result = (*client)->remember( server, server_id );
+ ASSERT( result, "Could not remember server" );
+ result = (*client)->call_next();
+ ASSERT( result, "Could not call server" );
+
+ // Kill client.
+ result = (*client)->set_state( dirty, THREAD_PRIORITY_NORMAL );
+ ASSERT( result, "Could not set_state on client" );
+ (*client)->Release();
+ *client = NULL;
+
+ // Query server.
+ result = server->check( server_id );
+ ASSERT( result, "Could not check server" );
+
+ // Create out of process client.
+ result = CoCreateInstance( *ServerClsid, NULL, CLSCTX_LOCAL_SERVER,
+ IID_ITest, (void **) client );
+ ASSERT( result, "Could not create out of process client" );
+ result = (*client)->get_id( client_id );
+ ASSERT( result, "Could not get client id" );
+
+ // Ping.
+ result = (*client)->remember( server, server_id );
+ ASSERT( result, "Could not remember server" );
+ result = (*client)->call_next();
+ ASSERT( result, "Could not call server" );
+
+ // Kill client.
+ result = (*client)->set_state( dirty, THREAD_PRIORITY_NORMAL );
+ ASSERT( result, "Could not set_state on client" );
+ (*client)->Release();
+ *client = NULL;
+
+ // Query server.
+ result = server->check( server_id );
+ ASSERT( result, "Could not check server" );
+/**/
+ // Create out of process client.
+ result = CoCreateInstance( *ServerClsid, NULL, CLSCTX_LOCAL_SERVER,
+ IID_ITest, (void **) client );
+ ASSERT( result, "Could not create out of process client" );
+ result = (*client)->get_id( client_id );
+ ASSERT( result, "Could not get client id" );
+
+ // Ping.
+ result = (*client)->remember( server, server_id );
+ ASSERT( result, "Could not remember server" );
+ result = (*client)->call_next();
+ ASSERT( result, "Could not call server" );
+
+ // Kill server.
+ result = server->set_state( dirty, THREAD_PRIORITY_NORMAL );
+ ASSERT( result, "Could not set_state on server" );
+ result = server->exit();
+ server->Release();
+ server = NULL;
+ if ((dirty & dirty_s) == 0)
+ ASSERT( result, "Could not exit server" );
+
+ // Query client.
+ result = (*client)->call_dead();
+ ASSERT( result, "Wrong error calling dead server" );
+
+ success = TRUE;
+cleanup:
+ if (server != NULL)
+ server->Release();
+ return success;
+}
+
+ /***************************************************************************/
+/*
+ This is a helper routine for do_rundown. It always executes with two
+ threads per process of each type (thus a process might have two client and
+ two server threads). It takes a parameter to indicate whether to execute
+ clean or dirty deaths. It executes all permuations of the remaining
+ variables, listed below. Note that the order of execution is important
+ to reduce the number of process creations. Note that the routine takes
+ a client process on entry and returns a different client process on
+ exit.
+
+ Client death vs Server death
+ In process vs Out of process
+*/
+BOOL do_rundown2( ITest **client1, SAptId *client1_id, DWORD dirty )
+{
+ BOOL success = FALSE;
+ ITest *server1 = NULL;
+ ITest *server2 = NULL;
+ ITest *client2 = NULL;
+ SAptId client2_id;
+ SAptId server1_id;
+ SAptId server2_id;
+ HRESULT result;
+
+ // Create in process client.
+ result = (*client1)->get_obj_from_new_apt( &client2, &client2_id );
+ ASSERT( result, "Could not get in process client2" );
+
+ // Create in process server.
+ result = (*client1)->get_obj_from_new_apt( &server1, &server1_id );
+ ASSERT( result, "Could not get in process server1" );
+
+ // Create in process server.
+ result = (*client1)->get_obj_from_new_apt( &server2, &server2_id );
+ ASSERT( result, "Could not get in process server2" );
+
+ // Ping 1.
+ result = (*client1)->remember( server1, server1_id );
+ ASSERT( result, "Could not remember server1" );
+ result = (*client1)->call_next();
+ ASSERT( result, "Could not call server1" );
+
+ // Ping 2.
+ result = client2->remember( server2, server2_id );
+ ASSERT( result, "Could not remember server2" );
+ result = client2->call_next();
+ ASSERT( result, "Could not call server2" );
+
+ // Kill server1.
+ result = server1->set_state( dirty, THREAD_PRIORITY_NORMAL );
+ ASSERT( result, "Could not set_state on server1" );
+ result = server1->exit();
+ server1->Release();
+ server1 = NULL;
+ ASSERT( result, "Could not exit server1" );
+
+ // Query client1.
+ result = (*client1)->call_dead();
+ ASSERT( result, "Wrong error calling dead server1" );
+
+ // Query client2.
+ result = client2->call_next();
+ ASSERT( result, "Could not call server2" );
+
+ // Query server2.
+ result = server2->check( server2_id );
+ ASSERT( result, "Could not check server2" );
+
+ // Switch the client1 to server1 so the process doesn't go away when we kill
+ // the client1. Then create an in process client1.
+ server1 = *client1;
+ server1_id = *client1_id;
+ *client1 = NULL;
+ result = server1->get_obj_from_new_apt( client1, client1_id );
+ ASSERT( result, "Could not get in process client1" );
+
+ // Ping 1.
+ result = (*client1)->remember( server1, server1_id );
+ ASSERT( result, "Could not remember server1" );
+ result = (*client1)->call_next();
+ ASSERT( result, "Could not call server1" );
+
+ // Ping 2.
+ result = client2->call_next();
+ ASSERT( result, "Could not call server2" );
+
+ // Kill client1.
+ result = (*client1)->set_state( dirty, THREAD_PRIORITY_NORMAL );
+ ASSERT( result, "Could not set_state on client1" );
+ (*client1)->Release();
+ *client1 = NULL;
+
+ // Query server1.
+ result = server1->check( server1_id );
+ ASSERT( result, "Could not check server1" );
+
+ // Query server2.
+ result = server2->check( server2_id );
+ ASSERT( result, "Could not check server2" );
+
+ // Query client2.
+ result = client2->call_next();
+ ASSERT( result, "Could not call server2" );
+ client2->Release();
+ client2 = NULL;
+
+ // Create out of process client1.
+ result = CoCreateInstance( *ServerClsid, NULL, CLSCTX_LOCAL_SERVER,
+ IID_ITest, (void **) client1 );
+ ASSERT( result, "Could not create out of process client1" );
+ result = (*client1)->get_id( client1_id );
+ ASSERT( result, "Could not get client1 id" );
+
+ // Create in process client 2.
+ result = (*client1)->get_obj_from_new_apt( &client2, &client2_id );
+ ASSERT( result, "Could not get in process client2" );
+
+ // Ping 1.
+ result = (*client1)->remember( server1, server1_id );
+ ASSERT( result, "Could not remember server1" );
+ result = (*client1)->call_next();
+ ASSERT( result, "Could not call server1" );
+
+ // Ping 2.
+ result = client2->remember( server2, server2_id );
+ ASSERT( result, "Could not remember server2" );
+ result = client2->call_next();
+ ASSERT( result, "Could not call server2" );
+
+ // Kill client2 so process does not exit.
+ result = client2->set_state( dirty, THREAD_PRIORITY_NORMAL );
+ ASSERT( result, "Could not set_state on client2" );
+ client2->Release();
+ client2 = NULL;
+
+ // Query server1.
+ result = server1->check( server1_id );
+ ASSERT( result, "Could not check server1" );
+
+ // Query server2.
+ result = server2->check( server2_id );
+ ASSERT( result, "Could not check server2" );
+
+ // Query client1.
+ result = (*client1)->call_next();
+ ASSERT( result, "Could not call server1" );
+
+ // Create in process client 2.
+ result = (*client1)->get_obj_from_new_apt( &client2, &client2_id );
+ ASSERT( result, "Could not get in process client2" );
+
+ // Ping 1.
+ result = (*client1)->call_next();
+ ASSERT( result, "Could not call server1" );
+
+ // Ping 2.
+ result = client2->remember( server2, server2_id );
+ ASSERT( result, "Could not remember server2" );
+ result = client2->call_next();
+ ASSERT( result, "Could not call server2" );
+
+ // Kill server2 so the server process does not go away.
+ result = server2->set_state( dirty, THREAD_PRIORITY_NORMAL );
+ ASSERT( result, "Could not set_state on server2" );
+ result = server2->exit();
+ server2->Release();
+ server2 = NULL;
+ if ((dirty & dirty_s) == 0)
+ ASSERT( result, "Could not exit server2" );
+
+ // Query client1.
+ result = (*client1)->call_next();
+ ASSERT( result, "Could not call server1" );
+
+ // Query client2.
+ result = client2->call_dead();
+ ASSERT( result, "Wrong error calling dead server2" );
+
+ // Query server1.
+ result = server1->check( server1_id );
+ ASSERT( result, "Could not check server1" );
+
+ success = TRUE;
+cleanup:
+ if (server1 != NULL)
+ server1->Release();
+ if (server2 != NULL)
+ server2->Release();
+ if (client2 != NULL)
+ client2->Release();
+ return success;
+}
+
+ /***************************************************************************/
+void do_securerefs()
+{
+ BOOL success = FALSE;
+ ITest *server = NULL;
+ ITest *server2 = NULL;
+ ITest *local = NULL;
+ SAptId id_server;
+ SAptId id_server2;
+ SAptId id_local;
+ HRESULT result;
+ SOLE_AUTHENTICATION_SERVICE svc_list;
+
+ hello( "securerefs" );
+
+ // Try CoInitializeSecurity before CoInit.
+ result = MCoInitializeSecurity( NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_NONE,
+ RPC_C_IMP_LEVEL_IMPERSONATE, NULL,
+ EOAC_NONE, NULL );
+ ASSERT_EXPR( result != S_OK, "Initialized security before OLE" );
+
+ // Initialize OLE.
+ result = initialize(NULL,ThreadMode);
+ ASSERT( result, "Initialize failed" );
+
+ // Set security to automatic none.
+ result = MCoInitializeSecurity( NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_NONE,
+ RPC_C_IMP_LEVEL_IMPERSONATE, NULL,
+ EOAC_NONE, NULL );
+ ASSERT( result, "Could not initialize security to none" );
+
+ if (ThreadMode == COINIT_APARTMENTTHREADED)
+ {
+ // Create a local server
+ result = new_apartment_test( &local, &id_local, NULL );
+ ASSERT( result, "Could not create local instance of test server" );
+
+ // Call the local server.
+ result = local->check( id_local );
+ ASSERT( result, "Could not call local server" )
+
+ // Release the local server.
+ local->Release();
+ local = NULL;
+ }
+
+ // Create a server possibly on a remote machine.
+ result = create_instance( *ServerClsid, &server, &id_server );
+ ASSERT( result, "Could not create instance of test server" );
+ ASSERT_EXPR( server != NULL, "Create instance returned NULL." );
+
+ // Call the server.
+ result = server->check( id_server );
+ ASSERT( result, "Could not call local server" )
+
+ // Release the server.
+ server->Release();
+ server = NULL;
+
+ // Uninitialize.
+ CoUninitialize();
+
+ // Reinitialize.
+ result = initialize(NULL,ThreadMode);
+ ASSERT( result, "Reinitialize failed" );
+
+ // Initialize security with secure refs but bad authn level.
+ result = MCoInitializeSecurity( NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_NONE,
+ RPC_C_IMP_LEVEL_IMPERSONATE, NULL,
+ EOAC_SECURE_REFS, NULL );
+ ASSERT_EXPR( result != S_OK, "CoInitializeSecurity succeeded with bad parameters" );
+
+ // Initialize security with secure refs.
+ result = MCoInitializeSecurity( NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_CONNECT,
+ RPC_C_IMP_LEVEL_IMPERSONATE, NULL,
+ EOAC_SECURE_REFS, NULL );
+ ASSERT( result, "Could not initialize secure refs" );
+
+ if (ThreadMode == COINIT_APARTMENTTHREADED)
+ {
+ // Create a local server
+ result = new_apartment_test( &local, &id_local, NULL );
+ ASSERT( result, "Could not create local instance of test server" );
+
+ // Call the local server.
+ result = local->check( id_local );
+ ASSERT( result, "Could not call local server" )
+
+ // Release the local server.
+ local->Release();
+ local = NULL;
+ }
+
+ // Create a server possibly on a remote machine.
+ result = create_instance( *ServerClsid, &server, &id_server );
+ ASSERT( result, "Could not create instance of test server" );
+ ASSERT_EXPR( server != NULL, "Create instance returned NULL." );
+
+ // Call the server.
+ result = server->check( id_server );
+ ASSERT( result, "Could not call local server" )
+
+ // Release the server.
+ server->Release();
+ server = NULL;
+
+ // Create a server possibly on a remote machine.
+ result = create_instance( *ServerClsid, &server, &id_server );
+ ASSERT( result, "Could not create instance of test server" );
+ ASSERT_EXPR( server != NULL, "Create instance returned NULL." );
+
+ // Create a server on this machine.
+ result = CoCreateInstance( *ServerClsid, NULL, CLSCTX_LOCAL_SERVER,
+ IID_ITest, (void **) &server2 );
+ ASSERT( result, "Could not create out of process server2" );
+ result = server2->get_id( &id_server2 );
+ ASSERT( result, "Could not get server2 id" );
+
+ // Have the second server remember the first.
+ result = server2->remember( server, id_server );
+ ASSERT( result, "Could not remember server" );
+ result = server2->call_next();
+ ASSERT( result, "Could not call server" );
+
+ // Release some extra public references.
+ success = do_securerefs_helper( &server );
+ if (!success) goto cleanup;
+ success = FALSE;
+
+ // The server should be gone, have the second server try to call.
+ result = server2->call_next();
+ ASSERT_EXPR( result != S_OK, "Call to dead server succeeded" );
+
+ // Have the second server forget the first.
+ result = server2->forget();
+ ASSERT( result, "Could not forget server" );
+
+ // Create a possible machine remote server.
+ result = create_instance( *ServerClsid, &server, &id_server );
+ ASSERT( result, "Could not create instance of test server" );
+ ASSERT_EXPR( server != NULL, "Create instance returned NULL." );
+
+ // Tell the second server to remember it.
+ result = server2->remember( server, id_server );
+ ASSERT( result, "Could not remember server" );
+ result = server2->call_next();
+ ASSERT( result, "Could not call server" );
+
+ // Release all local references.
+ server->Release();
+ server = NULL;
+
+ // Have the second server call it.
+ result = server2->call_next();
+ ASSERT( result, "Could not call server" );
+
+ // Finally, its all over.
+ success = TRUE;
+cleanup:
+ if (server2 != NULL)
+ server2->Release();
+ if (server != NULL)
+ server->Release();
+ if (local != NULL)
+ local->Release();
+
+ CoUninitialize();
+
+ if (success)
+ printf( "\n\nSecureRefs Test Passed.\n" );
+ else
+ printf( "\n\nSecureRefs Test Failed.\n" );
+}
+
+ /***************************************************************************/
+BOOL do_securerefs_helper( ITest **server )
+{
+ ULONG size;
+ HRESULT result;
+ HANDLE memory = NULL;
+ BOOL success;
+ IStream *stream = NULL;
+ LARGE_INTEGER pos;
+
+ // Find out how much memory to allocate.
+ result = CoGetMarshalSizeMax( &size, IID_ITest, *server, 0, NULL,
+ MSHLFLAGS_NORMAL );
+ ASSERT( result, "Could not get marshal size" );
+
+ // Allocate memory.
+ memory = GlobalAlloc( GMEM_FIXED, size );
+ ASSERT_EXPR( memory != NULL, "Could not get memory." );
+
+ // Create a stream.
+ result = CreateStreamOnHGlobal( memory, TRUE, &stream );
+ ASSERT( result, "Could not create stream" );
+
+ // Marshal the proxy.
+ result = CoMarshalInterface( stream, IID_ITest, *server, 0, NULL,
+ MSHLFLAGS_NORMAL );
+ ASSERT( result, "Could not marshal interface" );
+
+ // Release the proxy.
+ (*server)->Release();
+ *server = NULL;
+
+ // Seek back to the start of the stream.
+ pos.QuadPart = 0;
+ result = stream->Seek( pos, STREAM_SEEK_SET, NULL );
+ ASSERT( result, "Could not seek to start" );
+
+ // Unmarshal another copy.
+ result = CoUnmarshalInterface( stream, IID_ITest, (void **) server );
+ ASSERT( result, "Could not unmarshal from stream" );
+
+ // Release the proxy.
+ (*server)->Release();
+ *server = NULL;
+
+ // Seek back to the start of the stream.
+ pos.QuadPart = 0;
+ result = stream->Seek( pos, STREAM_SEEK_SET, NULL );
+ ASSERT( result, "Could not seek to start" );
+
+ // Unmarshal another copy.
+ result = CoUnmarshalInterface( stream, IID_ITest, (void **) server );
+ ASSERT( result, "Could not unmarshal from stream" );
+
+ // Release the proxy.
+ (*server)->Release();
+ *server = NULL;
+
+ success = TRUE;
+cleanup:
+ // The stream releases the memory.
+ if (stream != NULL)
+ stream->Release();
+ return success;
+}
+
+ /***************************************************************************/
+void do_security()
+{
+ BOOL success = FALSE;
+ ITest *server = NULL;
+ ITest *local = NULL;
+ ITest *server2 = NULL;
+ ITest *local2 = NULL;
+ SAptId id_server;
+ SAptId id_local;
+ SAptId id_server2;
+ SAptId id_local2;
+ HRESULT result;
+
+ // Initialize OLE.
+ hello( "security" );
+ result = initialize(NULL,ThreadMode);
+ ASSERT( result, "Initialize failed" );
+
+ // Test automatic security.
+ success = do_security_auto();
+ if (!success)
+ goto cleanup;
+ success = FALSE;
+
+ // Uninitialize.
+ CoUninitialize();
+
+ // Reinitialize.
+ result = initialize(NULL,ThreadMode);
+ ASSERT( result, "Reinitialize failed" );
+
+ // Set security to automatic none.
+ result = MCoInitializeSecurity( NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_NONE,
+ RPC_C_IMP_LEVEL_IMPERSONATE, NULL,
+ EOAC_NONE, NULL );
+ ASSERT( result, "Could not initialize security to none" );
+
+ // Create a local server
+ result = new_apartment_test( &local, &id_local, NULL );
+ ASSERT( result, "Could not create local instance of test server" );
+
+ // Create a client possibly on a remote machine.
+ result = create_instance( *ServerClsid, &server, &id_server );
+ ASSERT( result, "Could not create instance of test server" );
+ ASSERT_EXPR( server != NULL, "Create instance returned NULL." );
+
+ // Test proxy copy for a local object.
+ if (ThreadMode != COINIT_MULTITHREADED)
+ {
+ success = do_security_copy( local, id_local );
+ if (!success)
+ goto cleanup;
+ success = FALSE;
+ }
+
+ // Test proxy copy for a remote object.
+ success = do_security_copy( server, id_server );
+ if (!success)
+ goto cleanup;
+ success = FALSE;
+
+ // Test delegation
+ if (ThreadMode != COINIT_MULTITHREADED)
+ {
+ // Create a local server
+ result = new_apartment_test( &local2, &id_local2, NULL );
+ ASSERT( result, "Could not create local instance of test server" );
+
+ success = do_security_delegate( local, id_local, local2, id_local2 );
+ if (!success)
+ goto cleanup;
+ success = FALSE;
+ }
+
+ // Create a client possibly on a remote machine.
+ result = create_instance( *ServerClsid, &server2, &id_server2 );
+ ASSERT( result, "Could not create instance of test server" );
+ ASSERT_EXPR( server2 != NULL, "Create instance returned NULL." );
+
+ // Test delegation
+ success = do_security_delegate( server, id_server, server2, id_server2 );
+ if (!success)
+ goto cleanup;
+ success = FALSE;
+
+ // Try some calls.
+ if (ThreadMode != COINIT_MULTITHREADED)
+ {
+ success = do_security_handle( local, id_local );
+ if (!success)
+ goto cleanup;
+ success = FALSE;
+ }
+
+ // Try some calls.
+ success = do_security_handle( server, id_server );
+ if (!success)
+ goto cleanup;
+ success = FALSE;
+
+ // Test nested impersonation for a local object.
+ if (ThreadMode != COINIT_MULTITHREADED)
+ {
+ success = do_security_nested( local, id_local );
+ if (!success)
+ goto cleanup;
+ success = FALSE;
+ }
+
+ // Test nested impersonation for a remote object.
+ success = do_security_nested( server, id_server );
+ if (!success)
+ goto cleanup;
+ success = FALSE;
+
+ // Finally, its all over.
+ success = TRUE;
+cleanup:
+ if (server2 != NULL)
+ server2->Release();
+ if (local2 != NULL)
+ local2->Release();
+ if (server != NULL)
+ server->Release();
+ if (local != NULL)
+ local->Release();
+
+ CoUninitialize();
+
+ if (success)
+ printf( "\n\nSecurity Test Passed.\n" );
+ else
+ printf( "\n\nSecurity Test Failed.\n" );
+}
+
+ /***************************************************************************/
+BOOL do_security_auto( )
+{
+ BOOL success = FALSE;
+ DWORD i;
+ DWORD j;
+ DWORD k;
+ HRESULT result;
+ SOLE_AUTHENTICATION_SERVICE svc_list;
+ ITest *server = NULL;
+ SAptId id_server;
+ DWORD authn_level;
+ DWORD authn_level_out;
+ HANDLE thread = NULL;
+
+ // Figure out the class id offset based on the threading model.
+ if (ThreadMode == COINIT_MULTITHREADED)
+ k = 5;
+ else
+ k = 0;
+
+ // Try all types of security initialization.
+ for (i = 0; i < 5; i++)
+ {
+
+ // Initialize security.
+ switch (i)
+ {
+ case 0:
+ authn_level = RPC_C_AUTHN_LEVEL_NONE;
+ result = MCoInitializeSecurity( NULL, -1, NULL, NULL,
+ RPC_C_AUTHN_LEVEL_NONE,
+ RPC_C_IMP_LEVEL_IMPERSONATE, NULL,
+ EOAC_NONE, NULL );
+ ASSERT( result, "Could not initialize security to none" );
+ break;
+ case 1:
+ authn_level = RPC_C_AUTHN_LEVEL_CONNECT;
+ result = MCoInitializeSecurity( NULL, -1, NULL, NULL,
+ RPC_C_AUTHN_LEVEL_CONNECT,
+ RPC_C_IMP_LEVEL_IMPERSONATE, NULL,
+ EOAC_NONE, NULL );
+ ASSERT( result, "Could not initialize security to connect" );
+ break;
+ case 2:
+ authn_level = RPC_C_AUTHN_LEVEL_PKT_INTEGRITY;
+ result = MCoInitializeSecurity( NULL, -1, NULL, NULL,
+ RPC_C_AUTHN_LEVEL_PKT_INTEGRITY,
+ RPC_C_IMP_LEVEL_IMPERSONATE, NULL,
+ EOAC_NONE, NULL );
+ ASSERT( result, "Could not initialize security to integrity" );
+ break;
+ case 3:
+ authn_level = RPC_C_AUTHN_LEVEL_NONE;
+ svc_list.dwAuthnSvc = RPC_C_AUTHN_WINNT;
+ svc_list.dwAuthzSvc = RPC_C_AUTHZ_NONE;
+ svc_list.pPrincipalName = NULL;
+ result = MCoInitializeSecurity( NULL, 1, &svc_list, NULL,
+ RPC_C_AUTHN_LEVEL_NONE,
+ RPC_C_IMP_LEVEL_IMPERSONATE, NULL,
+ EOAC_NONE, NULL );
+ ASSERT( result, "Could not initialize security with authentication services" );
+ break;
+ case 4:
+ // Try legacy security by doing nothing.
+ authn_level = RPC_C_AUTHN_LEVEL_NONE;
+ break;
+ }
+
+ // Try all types of servers.
+ for (j = 0; j < 5; j++)
+ {
+ // Create a server.
+ result = create_instance( ClassIds[j+k], &server, &id_server );
+ ASSERT( result, "Could not create instance of test server" );
+ ASSERT_EXPR( server != NULL, "Create instance returned NULL." );
+
+ // Call it once.
+ success = do_security_lazy_call( server, id_server, authn_level,
+ RPC_C_IMP_LEVEL_IMPERSONATE,
+ RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE,
+ ProcessSid );
+ if (!success) goto cleanup;
+ success = FALSE;
+
+ if (j == 1 || j == 2)
+ {
+ // Set the security too low.
+ result = MCoSetProxyBlanket( server, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE,
+ NULL, RPC_C_AUTHN_LEVEL_NONE,
+ RPC_C_IMP_LEVEL_IMPERSONATE, NULL,
+ EOAC_NONE );
+ ASSERT( result, "Could not set blanket with authentication level none" );
+
+ // Make a bad call. Allow the security provider to up the level.
+ result = server->secure( id_server, RPC_C_AUTHN_LEVEL_NONE,
+ RPC_C_IMP_LEVEL_IMPERSONATE,
+ RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE,
+ NULL, (HACKSID *) ProcessSid, &authn_level_out );
+ ASSERT_EXPR( result != S_OK ||
+ (j == 1 && authn_level_out >= RPC_C_AUTHN_LEVEL_CONNECT) ||
+ (j == 2 && authn_level_out >= RPC_C_AUTHN_LEVEL_PKT_INTEGRITY),
+ "Bad call succeeded." );
+ }
+
+ // Release it.
+ server->Release();
+ server = NULL;
+ }
+
+ if (ThreadMode == COINIT_APARTMENTTHREADED)
+ {
+ // Create a local server.
+ result = new_apartment_test( &server, &id_server, &thread );
+ ASSERT( result, "Could not create local instance of test server" );
+
+ // Make a local call.
+ success = do_security_lazy_call( server, id_server, authn_level,
+ RPC_C_IMP_LEVEL_IMPERSONATE,
+ RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE,
+ ProcessSid );
+ if (!success) goto cleanup;
+ success = FALSE;
+
+ // Release it.
+ server->Release();
+ server = NULL;
+
+ // Wait for the helper thread to die.
+ result = WaitForSingleObject( thread, INFINITE );
+ ASSERT_EXPR( result == WAIT_OBJECT_0, "Could not wait for thread." );
+ CloseHandle( thread );
+ thread = NULL;
+ }
+
+ // Uninitialize OLE.
+ CoUninitialize();
+
+ // Reinitialize OLE.
+ result = initialize(NULL,ThreadMode);
+ ASSERT( result, "Reinitialize failed" );
+ }
+
+ success = TRUE;
+cleanup:
+ if (server != NULL)
+ server->Release();
+ if (thread != NULL)
+ CloseHandle( thread );
+ return success;
+}
+
+ /***************************************************************************/
+BOOL do_security_call( ITest *server, SAptId id, DWORD authn_level,
+ DWORD imp_level, DWORD authn_svc, DWORD authz_svc,
+ SID *sid )
+{
+ BOOL success = FALSE;
+ HRESULT result;
+ DWORD authn_level_out;
+ DWORD imp_level_out;
+ DWORD authn_svc_out;
+ DWORD authz_svc_out;
+ OLECHAR *princ_name_out = NULL;
+
+ result = MCoSetProxyBlanket( server, authn_svc, authz_svc, NULL,
+ authn_level, imp_level, NULL, EOAC_NONE );
+ ASSERT( result, "Could not set blanket" );
+
+ // Verify the authentication information.
+ result = MCoQueryProxyBlanket( server, &authn_svc_out, &authz_svc_out,
+ &princ_name_out, &authn_level_out,
+ &imp_level_out, NULL, NULL );
+ if (result == S_OK)
+ {
+ ASSERT_EXPR( princ_name_out == NULL, "Got a principle name." );
+ ASSERT_EXPR( authn_level <= authn_level_out, "Wrong authentication level." );
+ ASSERT_EXPR( imp_level == imp_level_out, "Wrong impersonation level." );
+ ASSERT_EXPR( authn_svc == authn_svc_out, "Wrong authentication service." );
+ ASSERT_EXPR( authz_svc == authz_svc_out, "Wrong authorization service." );
+ }
+
+ // Make a call.
+ result = server->secure( id, authn_level, imp_level, authn_svc, authz_svc,
+ NULL, (HACKSID *) sid, &authn_level_out );
+ ASSERT( result, "Secure call failed" );
+
+ success = TRUE;
+cleanup:
+ CoTaskMemFree( princ_name_out );
+ return success;
+}
+
+ /***************************************************************************/
+BOOL do_security_copy( ITest *server, SAptId id )
+{
+ BOOL success = FALSE;
+ ITest *copy1 = NULL;
+ ITest *copy2 = NULL;
+ ITest *copy3 = NULL;
+ HRESULT result;
+
+ // Make a copy.
+ result = MCoCopyProxy( server, (IUnknown **) &copy1 );
+ ASSERT( result, "Could not copy proxy" );
+
+ // Verify that it calls at none.
+ success = do_security_lazy_call( copy1, id, RPC_C_AUTHN_LEVEL_NONE,
+ RPC_C_IMP_LEVEL_IMPERSONATE,
+ RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE,
+ ProcessSid );
+ if (!success) goto cleanup;
+ success = FALSE;
+
+ // Verify that the original calls at none.
+ success = do_security_lazy_call( server, id, RPC_C_AUTHN_LEVEL_NONE,
+ RPC_C_IMP_LEVEL_IMPERSONATE,
+ RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE,
+ ProcessSid );
+ if (!success) goto cleanup;
+ success = FALSE;
+
+ // Call on the original at connect.
+ success = do_security_call( server, id, RPC_C_AUTHN_LEVEL_CONNECT,
+ RPC_C_IMP_LEVEL_IMPERSONATE,
+ RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE,
+ ProcessSid );
+ if (!success) goto cleanup;
+ success = FALSE;
+
+ // Verify that the copy still calls at none.
+ success = do_security_lazy_call( copy1, id, RPC_C_AUTHN_LEVEL_NONE,
+ RPC_C_IMP_LEVEL_IMPERSONATE,
+ RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE,
+ ProcessSid );
+ if (!success) goto cleanup;
+ success = FALSE;
+
+ // Call on the copy at encrypt.
+ success = do_security_call( copy1, id, RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
+ RPC_C_IMP_LEVEL_IMPERSONATE,
+ RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE,
+ ProcessSid );
+ if (!success) goto cleanup;
+ success = FALSE;
+
+ // Verify that the original still calls at connect.
+ success = do_security_lazy_call( server, id, RPC_C_AUTHN_LEVEL_CONNECT,
+ RPC_C_IMP_LEVEL_IMPERSONATE,
+ RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE,
+ ProcessSid );
+ if (!success) goto cleanup;
+ success = FALSE;
+
+ // Free the copy.
+ copy1->Release();
+ copy1 = NULL;
+
+ // Make a copy.
+ result = MCoCopyProxy( server, (IUnknown **) &copy1 );
+ ASSERT( result, "Could not copy proxy" );
+
+ // Verify that the copy calls at none.
+ success = do_security_lazy_call( copy1, id, RPC_C_AUTHN_LEVEL_NONE,
+ RPC_C_IMP_LEVEL_IMPERSONATE,
+ RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE,
+ ProcessSid );
+ if (!success) goto cleanup;
+ success = FALSE;
+
+ // Copy the copy.
+ result = MCoCopyProxy( copy1, (IUnknown **) &copy2 );
+ ASSERT( result, "Could not copy a copy of a proxy" );
+
+ // Verify the second copy calls at none.
+ success = do_security_lazy_call( copy2, id, RPC_C_AUTHN_LEVEL_NONE,
+ RPC_C_IMP_LEVEL_IMPERSONATE,
+ RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE,
+ ProcessSid );
+ if (!success) goto cleanup;
+ success = FALSE;
+
+ // Change the first copy to integrity.
+ success = do_security_call( copy1, id, RPC_C_AUTHN_LEVEL_PKT_INTEGRITY,
+ RPC_C_IMP_LEVEL_IMPERSONATE,
+ RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE,
+ ProcessSid );
+ if (!success) goto cleanup;
+ success = FALSE;
+
+ // Change the second copy to encrypt.
+ success = do_security_call( copy2, id, RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
+ RPC_C_IMP_LEVEL_IMPERSONATE,
+ RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE,
+ ProcessSid );
+ if (!success) goto cleanup;
+ success = FALSE;
+
+ // Verify that the original is still connect.
+ success = do_security_lazy_call( server, id, RPC_C_AUTHN_LEVEL_CONNECT,
+ RPC_C_IMP_LEVEL_IMPERSONATE,
+ RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE,
+ ProcessSid );
+ if (!success) goto cleanup;
+ success = FALSE;
+
+ // Querying a copy should return the original.
+ result = copy1->QueryInterface( IID_ITest, (void **) &copy3 );
+ ASSERT( result, "Could not QueryInterface" );
+ ASSERT_EXPR( server == copy3, "QueryInterface did not return the original." );
+ copy3->Release();
+ copy3 = NULL;
+
+ // Free the original.
+ server->Release();
+ server = NULL;
+
+ // Free the second copy.
+ copy2->Release();
+ copy2 = NULL;
+
+ // Make another copy.
+ result = MCoCopyProxy( copy1, (IUnknown **) &copy2 );
+ ASSERT( result, "Could not copy a copy of a proxy" );
+
+ // Verify that it calls at none.
+ success = do_security_lazy_call( copy2, id, RPC_C_AUTHN_LEVEL_NONE,
+ RPC_C_IMP_LEVEL_IMPERSONATE,
+ RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE,
+ ProcessSid );
+ if (!success) goto cleanup;
+ success = FALSE;
+
+ // Query for the original.
+ result = copy1->QueryInterface( IID_ITest, (void **) &server );
+ ASSERT( result, "Could not QueryInterface" );
+
+ // Verify that it calls at connect.
+ success = do_security_lazy_call( server, id, RPC_C_AUTHN_LEVEL_CONNECT,
+ RPC_C_IMP_LEVEL_IMPERSONATE,
+ RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE,
+ ProcessSid );
+ if (!success) goto cleanup;
+ success = FALSE;
+
+ // Verify that the first copy is still at integrity
+ success = do_security_lazy_call( copy1, id, RPC_C_AUTHN_LEVEL_PKT_INTEGRITY,
+ RPC_C_IMP_LEVEL_IMPERSONATE,
+ RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE,
+ ProcessSid );
+ if (!success) goto cleanup;
+ success = FALSE;
+
+ success = TRUE;
+cleanup:
+ if (copy1 != NULL)
+ copy1->Release();
+ if (copy2 != NULL)
+ copy2->Release();
+ if (copy3 != NULL)
+ copy3->Release();
+ return success;
+}
+
+ /***************************************************************************/
+BOOL do_security_delegate( ITest *server, SAptId id, ITest *server2,
+ SAptId id2 )
+{
+ BOOL success = FALSE;
+ HRESULT result;
+
+ // Make a call.
+ result = server->delegate( server2, id2, (HACKSID *) ProcessSid );
+ ASSERT( result, "Delegate call failed" );
+
+ success = TRUE;
+cleanup:
+ return success;
+}
+
+ /***************************************************************************/
+BOOL do_security_handle( ITest *server, SAptId id )
+{
+ BOOL success = FALSE;
+
+ // Make a call with no security.
+ success = do_security_call( server, id, RPC_C_AUTHN_LEVEL_NONE,
+ RPC_C_IMP_LEVEL_IMPERSONATE,
+ RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, ProcessSid );
+ if (!success)
+ return FALSE;
+
+ // Make a call with connect security.
+ success = do_security_call( server, id, RPC_C_AUTHN_LEVEL_CONNECT,
+ RPC_C_IMP_LEVEL_IMPERSONATE,
+ RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, ProcessSid );
+ if (!success)
+ return FALSE;
+
+ // Make a call with integrity security.
+ success = do_security_call( server, id, RPC_C_AUTHN_LEVEL_PKT_INTEGRITY,
+ RPC_C_IMP_LEVEL_IMPERSONATE,
+ RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, ProcessSid );
+ if (!success)
+ return FALSE;
+
+
+ // Make a call with encrypt security.
+ success = do_security_call( server, id, RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
+ RPC_C_IMP_LEVEL_IMPERSONATE,
+ RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, ProcessSid );
+ if (!success)
+ return FALSE;
+
+ // Make a call with no security.
+ success = do_security_call( server, id, RPC_C_AUTHN_LEVEL_NONE,
+ RPC_C_IMP_LEVEL_IDENTIFY,
+ RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, ProcessSid );
+ if (!success)
+ return FALSE;
+
+ // Make a call with connect security.
+ success = do_security_call( server, id, RPC_C_AUTHN_LEVEL_CONNECT,
+ RPC_C_IMP_LEVEL_IDENTIFY,
+ RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, ProcessSid );
+ if (!success)
+ return FALSE;
+
+ // Make a call with integrity security.
+ success = do_security_call( server, id, RPC_C_AUTHN_LEVEL_PKT_INTEGRITY,
+ RPC_C_IMP_LEVEL_IDENTIFY,
+ RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, ProcessSid );
+ if (!success)
+ return FALSE;
+
+
+ // Make a call with encrypt security.
+ success = do_security_call( server, id, RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
+ RPC_C_IMP_LEVEL_IDENTIFY,
+ RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, ProcessSid );
+ if (!success)
+ return FALSE;
+
+ // Finally, its all over.
+ return TRUE;
+}
+
+ /***************************************************************************/
+BOOL do_security_lazy_call( ITest *server, SAptId id, DWORD authn_level,
+ DWORD imp_level, DWORD authn_svc, DWORD authz_svc,
+ SID *sid )
+{
+ BOOL success = FALSE;
+ HRESULT result;
+ DWORD authn_level_out;
+ DWORD imp_level_out;
+ DWORD authn_svc_out;
+ DWORD authz_svc_out;
+ OLECHAR *princ_name_out = NULL;
+
+ // Verify the authentication information.
+ result = MCoQueryProxyBlanket( server, &authn_svc_out, &authz_svc_out,
+ &princ_name_out, &authn_level_out,
+ &imp_level_out, NULL, NULL );
+ if (result == S_OK)
+ {
+ ASSERT_EXPR( princ_name_out == NULL, "Got a principle name." );
+ ASSERT_EXPR( authn_level <= authn_level_out, "Wrong authentication level." );
+ ASSERT_EXPR( imp_level == imp_level_out, "Wrong impersonation level." );
+ ASSERT_EXPR( authn_svc == authn_svc_out, "Wrong authentication service." );
+ ASSERT_EXPR( authz_svc == authz_svc_out, "Wrong authorization service." );
+ }
+
+ // Make a call.
+ result = server->secure( id, authn_level, imp_level, authn_svc, authz_svc,
+ NULL, (HACKSID *) sid, &authn_level_out );
+ ASSERT( result, "Secure call failed" );
+
+ success = TRUE;
+cleanup:
+ CoTaskMemFree( princ_name_out );
+ return success;
+}
+
+ /***************************************************************************/
+BOOL do_security_nested( ITest *server, SAptId id )
+{
+ HRESULT result;
+ CTest test;
+ BOOL success = FALSE;
+ IServerSecurity *security = NULL;
+ TOKEN_USER *token_info = NULL;
+ DWORD info_size = 1024;
+ HANDLE token = NULL;
+ PSID me = NULL;
+
+ // Make a recursive call. The proxy is set to encrypt from the previous test.
+ result = server->recurse_secure( &test, 3, 1, (HACKSID *) ProcessSid );
+ ASSERT( result, "Could not make recursive call with impersonation." );
+
+ // Try to get call context.
+ result = MCoGetCallContext( IID_IServerSecurity, (void **) &security );
+ ASSERT_EXPR( result != S_OK, "Get call context succeeded outside a call." );
+
+ // Open the thread token.
+ if (OpenThreadToken( GetCurrentThread(), TOKEN_QUERY, TRUE, &token ))
+ result = S_OK;
+ else
+ result = GetLastError();
+ ASSERT_EXPR( result == NOERROR || result == ERROR_NO_TOKEN, "Could not OpenThreadToken" );
+
+ // Lookup SID of thread token.
+ token_info = (TOKEN_USER *) malloc( info_size );
+ ASSERT_EXPR( token_info != NULL, "Could not allocate memory for token info." );
+ if (result == NOERROR)
+ {
+ GetTokenInformation( token, TokenUser, token_info, info_size, &info_size );
+ result = GetLastError();
+ ASSERT( result, "Could not GetTokenInformation" );
+ me = token_info->User.Sid;
+
+ // The SID on the thread token should equal the process token.
+ ASSERT_EXPR( EqualSid( me, ProcessSid ), "Wrong thread token." );
+ }
+
+ success = TRUE;
+cleanup:
+ if (security != NULL)
+ security->Release();
+ if (token_info != NULL)
+ free(token_info);
+ if (token != NULL)
+ CloseHandle( token );
+ return success;
+}
+
+ /***************************************************************************/
+void do_send()
+{
+ LRESULT result;
+
+ // Say hello.
+ printf( "Sending a message to window 0x%x\n", NumIterations );
+ result = SendMessageA( (HWND) NumIterations, WM_USER, 0, 0 );
+
+ if (result == 0)
+ printf( "\n\nSendMessageA succeeded.\n" );
+ else
+ printf( "\n\nSendMessageA failed: 0x%x\n", result );
+}
+
+ /***************************************************************************/
+void do_server( )
+{
+ HRESULT result;
+ BOOL success = FALSE;
+ SOLE_AUTHENTICATION_SERVICE svc_list;
+
+ // Initialize OLE.
+ hello( "server" );
+ printf( "Initializing thread 0x%x\n", GetCurrentThreadId() );
+ result = initialize(NULL,ThreadMode);
+ ASSERT( result, "Initialize failed" );
+ result = initialize_security();
+ ASSERT( result, "Could not initialize security" );
+
+ // Create our class factory
+ ClassFactory = new CTestCF();
+ ASSERT_EXPR( ClassFactory != NULL, "Could not create class factory." );
+
+ // Register our class with OLE
+ result = CoRegisterClassObject(*ServerClsid, ClassFactory, CLSCTX_LOCAL_SERVER,
+ REGCLS_SINGLEUSE, &Registration);
+ ASSERT( result, "CoRegisterClassObject failed" );
+
+ // CoRegister bumps reference count so we don't have to!
+ ClassFactory->Release();
+
+ // Do whatever we have to do till it is time to pay our taxes and die.
+ server_loop();
+
+ // Deregister out class - should release object as well
+ if (!dirty_thread())
+ {
+ result = CoRevokeClassObject(Registration);
+ ASSERT( result, "CoRevokeClassObject failed" );
+ }
+
+ success = TRUE;
+cleanup:
+ if (!dirty_thread())
+ {
+ printf( "Uninitializing thread 0x%x\n", GetCurrentThreadId() );
+ CoUninitialize();
+ }
+ else
+ printf( "\n\nI didn't clean up\n" );
+
+ if (success)
+ printf( "\n\nServer Passed.\n" );
+ else
+ printf( "\n\nServer Failed.\n" );
+}
+
+
+ /***************************************************************************/
+void do_sid()
+{
+ BOOL success = FALSE;
+ BOOL call_success;
+ SID *pSID = NULL;
+ DWORD cbSID = 1024;
+ WCHAR *lpszDomain = NULL;
+ DWORD cchDomainName = 80;
+ SID_NAME_USE sid_use;
+ HRESULT result = S_OK;
+ DWORD i;
+
+ // Say hello.
+ printf( "Looking up sid for %ws.\n", Name );
+
+ // Lookup the name.
+ pSID = (SID *) LocalAlloc(LPTR, cbSID*2);
+ lpszDomain = (WCHAR *) LocalAlloc(LPTR, cchDomainName*2);
+ ASSERT_EXPR( pSID != NULL && lpszDomain != NULL, "LocalAlloc" );
+ call_success = LookupAccountName(NULL,
+ Name,
+ pSID,
+ &cbSID,
+ lpszDomain,
+ &cchDomainName,
+ &sid_use);
+ result = GetLastError();
+ ASSERT( result, "Could not LookupAccountName" );
+ ASSERT_EXPR( call_success, "LookupAccountName failed." );
+ ASSERT_EXPR( IsValidSid(pSID), "Got a bad SID." );
+ printf( "SID\n" );
+ printf( " Revision: 0x%02x\n", pSID->Revision );
+ printf( " SubAuthorityCount: 0x%x\n", pSID->SubAuthorityCount );
+ printf( " IdentifierAuthority: 0x%02x%02x%02x%02x%02x%02x\n",
+ pSID->IdentifierAuthority.Value[0],
+ pSID->IdentifierAuthority.Value[1],
+ pSID->IdentifierAuthority.Value[2],
+ pSID->IdentifierAuthority.Value[3],
+ pSID->IdentifierAuthority.Value[4],
+ pSID->IdentifierAuthority.Value[5] );
+ for (i = 0; i < pSID->SubAuthorityCount; i++)
+ printf( " SubAuthority[%d]: 0x%08x\n", i,
+ pSID->SubAuthority[i] );
+ printf( " Domain: %ws\n", lpszDomain );
+ printf( " SID_NAME_USE: 0x%x\n", sid_use );
+
+ success = TRUE;
+cleanup:
+ if (lpszDomain != NULL)
+ LocalFree((HLOCAL) lpszDomain);
+ if (pSID != NULL)
+ LocalFree(pSID);
+
+ if (success)
+ printf( "\n\nSid succeeded.\n" );
+ else
+ printf( "\n\nSid failed.\n" );
+}
+
+ /***************************************************************************/
+void do_simple_rundown()
+{
+ BOOL success = FALSE;
+ ITest *client1 = NULL;
+ CTest *local = NULL;
+ SAptId id1;
+ SAptId local_id;
+ HRESULT result;
+
+ // Initialize OLE.
+ hello( "simple rundown" );
+ result = initialize(NULL,ThreadMode);
+ ASSERT( result, "Initialize failed" );
+
+ // Create a server
+ result = CoCreateInstance( *ServerClsid, NULL, CLSCTX_LOCAL_SERVER,
+ IID_ITest, (void **) &client1 );
+ ASSERT( result, "Could not create server" );
+ result = client1->get_id( &id1 );
+ ASSERT( result, "Could not get id" );
+
+ // Create a local object.
+ local = new CTest;
+ ASSERT_EXPR( local != NULL, "Could not create a local object." );
+ result = local->get_id( &local_id );
+ ASSERT( result, "Could not get id" );
+
+ // Tell it to remember this object.
+ result = client1->remember( local, local_id );
+ ASSERT( result, "Could not remember local object" );
+ local->Release();
+ local = NULL;
+
+ // Tell the other apartment to die.
+ result = client1->set_state( dirty_s, THREAD_PRIORITY_NORMAL );
+ ASSERT( result, "Could not set exit dirty" );
+ result = client1->exit();
+
+ // Wait araound till no one references the local object.
+ printf( "Wait for object to rundown. This could take 12 minutes.\n" );
+ server_loop();
+
+ // Finally, its all over.
+ success = TRUE;
+cleanup:
+ if (client1 != NULL)
+ client1->Release();
+ if (local != NULL)
+ local->Release();
+ CoUninitialize();
+
+ if (success)
+ printf( "\n\nSimple Rundown Test Passed.\n" );
+ else
+ printf( "\n\nSimple Rundown Test Failed.\n" );
+}
+
+ /***************************************************************************/
+void do_thread()
+{
+ BOOL success = FALSE;
+ ITest *client1 = NULL;
+ ITest *client2 = NULL;
+ ITest *client3 = NULL;
+ ITest *client4 = NULL;
+ SAptId id1;
+ SAptId id2;
+ SAptId id4;
+ HRESULT result;
+ GUID guid;
+
+ // Initialize OLE.
+ hello( "thread" );
+ result = initialize(NULL,ThreadMode);
+ ASSERT( result, "Initialize failed" );
+
+ // Create a client on this thread.
+ client3 = new CTest;
+ ASSERT_EXPR( client3 != NULL, "Could not create a local object." );
+
+ // Create a client on another thread in this process
+ result = client3->get_obj_from_new_apt( &client4, &id4 );
+ ASSERT( result, "Could not get in process client" );
+
+ // Create a server
+ result = CoCreateInstance( *ServerClsid, NULL, CLSCTX_LOCAL_SERVER,
+ IID_ITest, (void **) &client1 );
+ ASSERT( result, "Could not create instance of test server" );
+ result = client1->get_id( &id1 );
+ ASSERT( result, "Could not get id of server" );
+
+ // Create an object in another apartment in the server.
+ result = client1->get_obj_from_new_apt( &client2, &id2 );
+ ASSERT( result, "Could not get in process server" );
+
+ // Check each object.
+ result = client1->check( id1 );
+ ASSERT( result, "Could not check server 1" );
+ result = client2->check( id2 );
+ ASSERT( result, "Could not check server 2" );
+
+ // Pass a server to the other thread in this process.
+ result = client4->remember( client1, id1 );
+ ASSERT( result, "Client could not remember server" );
+
+ // Release the second object.
+ client2->Release();
+ client2 = NULL;
+
+ // Check the first object.
+ result = client1->check( id1 );
+ ASSERT( result, "Could not check server 1" );
+
+ // Check the first object from another thread.
+ result = client4->call_next();
+ ASSERT( result, "Could not check server 1 from thread 2" );
+
+ // Release the first object from this thread.
+ client1->Release();
+ client1 = NULL;
+
+ // Check the first object from another thread.
+ result = client4->call_next();
+ ASSERT( result, "Could not check server 1 from thread 2" );
+
+ // Finally, its all over.
+ success = TRUE;
+cleanup:
+ if (client2 != NULL)
+ client2->Release();
+ if (client1 != NULL)
+ client1->Release();
+ if (client3 != NULL)
+ client3->Release();
+ if (client4 != NULL)
+ client4->Release();
+ CoUninitialize();
+
+ if (success)
+ printf( "\n\nThread Test Passed.\n" );
+ else
+ printf( "\n\nThread Test Failed.\n" );
+}
+
+ /***************************************************************************/
+typedef struct
+{
+ ATOM wclass;
+ HWND wdriver;
+ HWND whelper;
+ HANDLE hdriver;
+ HANDLE hhelper;
+ HRESULT result;
+} SSwitchData;
+
+SSwitchData gSwitch;
+
+LRESULT do_three_wndproc(HWND window, UINT message, WPARAM unused, LPARAM params);
+DWORD _stdcall do_three_helper( void *nothing );
+
+void do_three()
+{
+ BOOL success = FALSE;
+ ITest *server = NULL;
+ HRESULT result;
+ int i;
+ WNDCLASS wclass;
+ HANDLE thread = NULL;
+ DWORD thread_id;
+ MSG msg;
+
+ // Initialize OLE.
+ hello( "three" );
+ result = initialize(NULL,ThreadMode);
+ ASSERT( result, "Initialize failed" );
+
+ // Create a remote server.
+ result = CoCreateInstance( *ServerClsid, NULL, CLSCTX_LOCAL_SERVER,
+ IID_ITest, (void **) &server );
+ ASSERT( result, "Could not create server" );
+
+ // Register a window class.
+ wclass.style = 0;
+ wclass.lpfnWndProc = do_three_wndproc;
+ wclass.cbClsExtra = 0;
+ wclass.cbWndExtra = 0;
+ wclass.hInstance = NULL;
+ wclass.hIcon = NULL;
+ wclass.hCursor = NULL;
+ wclass.hbrBackground = (HBRUSH) (COLOR_BACKGROUND + 1);
+ wclass.lpszMenuName = NULL;
+ wclass.lpszClassName = L"That's me";
+ gSwitch.wclass = RegisterClass( &wclass );
+ ASSERT_EXPR( gSwitch.wclass != 0, "Could not register class." );
+
+ // Create a window.
+ gSwitch.wdriver = CreateWindowEx(0,
+ L"That's me",
+ L"My window",
+ // must use WS_POPUP so the window does not get
+ // assigned a hot key by user.
+ (WS_DISABLED | WS_POPUP),
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ NULL,
+ NULL,
+ NULL, // hinst
+ NULL);
+ ASSERT_EXPR( gSwitch.wdriver != NULL, "Could not create window." );
+
+ // Create an event.
+ gSwitch.hdriver = CreateEventA( NULL, FALSE, FALSE, NULL );
+ ASSERT_EXPR( gSwitch.hdriver != NULL, "Could not create event." );
+
+ // Create a thread.
+ thread = CreateThread( NULL, 0, do_three_helper, NULL, 0, &thread_id );
+ ASSERT_EXPR( thread != NULL, "Could not create thread." );
+ CloseHandle( thread );
+
+ // Wait for the thread to initialize.
+ result = WaitForSingleObject( gSwitch.hdriver, INFINITE );
+ ASSERT_EXPR( result == WAIT_OBJECT_0, "Could not wait for thread." );
+ ASSERT( gSwitch.result, "Helper thread failed." );
+
+ // Test some thread switches
+ for (i = 0; i < NumIterations; i++)
+ {
+ // Post a message to the thread.
+ success = PostMessageA( gSwitch.whelper, WM_USER, 0, 0 );
+ ASSERT_EXPR( success, "Could not post message." );
+ success = FALSE;
+
+ // Wait for a post message reply.
+ result = MsgWaitForMultipleObjects( 1, &gSwitch.hdriver, FALSE,
+ 1000, QS_POSTMESSAGE );
+ ASSERT_EXPR( result == WAIT_OBJECT_0+1, "Could not wait for post message." );
+ ASSERT( gSwitch.result, "Helper thread failed." );
+ success = PeekMessage( &msg, gSwitch.wdriver, WM_USER, WM_USER,
+ PM_REMOVE | PM_NOYIELD );
+ ASSERT_EXPR( success, "Could not peek message." );
+ success = FALSE;
+ DispatchMessageA( &msg );
+
+ // Set an event to reply.
+ success = SetEvent( gSwitch.hhelper );
+ ASSERT_EXPR( success, "Could not set event." );
+ success = FALSE;
+
+ // Wait for a set event reply.
+ result = MsgWaitForMultipleObjects( 1, &gSwitch.hdriver, FALSE,
+ 1000, QS_POSTMESSAGE );
+ ASSERT_EXPR( result == WAIT_OBJECT_0, "Could not wait for event." );
+ ASSERT( gSwitch.result, "Helper thread failed." );
+ }
+
+ // Finally, its all over.
+ success = TRUE;
+cleanup:
+ if (server != NULL)
+ server->Release();
+ CoUninitialize();
+
+ if (success)
+ printf( "\n\nThree Test Passed.\n" );
+ else
+ printf( "\n\nThree Test Failed.\n" );
+}
+
+ /***************************************************************************/
+LRESULT do_three_wndproc(HWND window, UINT message, WPARAM unused, LPARAM params)
+{
+ return DefWindowProc( window, message, unused, params );
+}
+
+ /***************************************************************************/
+DWORD _stdcall do_three_helper( void *nothing )
+{
+ HRESULT result;
+ BOOL success;
+ MSG msg;
+
+ // Create an event.
+ gSwitch.hhelper = CreateEventA( NULL, FALSE, FALSE, NULL );
+ ASSERT_EXPR( gSwitch.hhelper != NULL, "Could not create event." );
+
+ // Create a window.
+ gSwitch.whelper = CreateWindowEx(0,
+ L"That's me",
+ L"My window",
+ // must use WS_POPUP so the window does not get
+ // assigned a hot key by user.
+ (WS_DISABLED | WS_POPUP),
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ NULL,
+ NULL,
+ NULL, // hinst
+ NULL);
+ ASSERT_EXPR( gSwitch.whelper != NULL, "Could not create window." );
+
+ // Wake up the driver.
+ gSwitch.result = S_OK;
+ success = SetEvent( gSwitch.hdriver );
+ ASSERT_EXPR( success, "Could not set event." );
+
+ // Loop forever.
+ while (TRUE)
+ {
+ // Wait for a message.
+ success = GetMessageA( &msg, NULL, 0, 0 );
+ ASSERT_EXPR( success, "Could not get message." );
+ TranslateMessage (&msg);
+ DispatchMessageA (&msg);
+
+ // Post a reply.
+ success = PostMessageA( gSwitch.wdriver, WM_USER, 0, 0 );
+ ASSERT_EXPR( success, "Could not post message." );
+ success = FALSE;
+
+ // Wait for an event.
+ result = MsgWaitForMultipleObjects( 1, &gSwitch.hhelper, FALSE,
+ 1000, QS_POSTMESSAGE );
+ ASSERT_EXPR( result == WAIT_OBJECT_0, "Could not wait for event." );
+
+ // Set an event to reply.
+ success = SetEvent( gSwitch.hdriver );
+ ASSERT_EXPR( success, "Could not set event." );
+ }
+
+cleanup:
+ gSwitch.result = E_FAIL;
+ success = SetEvent( gSwitch.hdriver );
+ return E_FAIL;
+}
+
+ /***************************************************************************/
+void do_two()
+{
+ BOOL success = FALSE;
+ ITest *client1 = NULL;
+ SAptId id1;
+ HRESULT result;
+ DWORD i;
+ LARGE_INTEGER freq;
+ LARGE_INTEGER start;
+ LARGE_INTEGER nothing;
+ LARGE_INTEGER init_sec_none;
+ LARGE_INTEGER open;
+ LARGE_INTEGER get_sid;
+ HANDLE hToken = NULL;
+ BYTE aMemory[1024];
+ TOKEN_USER *pTokenUser = (TOKEN_USER *) &aMemory;
+ DWORD lNameLen = 1000;
+ DWORD lDomainLen = 1000;
+ DWORD lIgnore;
+ DWORD lSidLen;
+ WCHAR name[1000];
+ WCHAR domain[1000];
+ LARGE_INTEGER lookup;
+ DWORD xlookup;
+ SID_NAME_USE sIgnore;
+
+ // Initialize OLE.
+ hello( "two" );
+ result = initialize(NULL,ThreadMode);
+ ASSERT( result, "Initialize failed" );
+
+ // Measure the performance of nothing.
+ QueryPerformanceFrequency( &freq );
+ QueryPerformanceCounter( &start );
+ QueryPerformanceCounter( &nothing );
+ nothing.QuadPart = 1000000 * (nothing.QuadPart - start.QuadPart) / freq.QuadPart;
+
+ // Open the process's token.
+ QueryPerformanceCounter( &start );
+ success = OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY, &hToken );
+ QueryPerformanceCounter( &open );
+ open.QuadPart = 1000000 * (open.QuadPart - start.QuadPart) / freq.QuadPart;
+ ASSERT_EXPR( success, "Could not open process token." );
+
+ // Lookup SID of process token.
+ QueryPerformanceCounter( &start );
+ success = GetTokenInformation( hToken, TokenUser, pTokenUser, sizeof(aMemory),
+ &lIgnore );
+ QueryPerformanceCounter( &get_sid );
+ get_sid.QuadPart = 1000000 * (get_sid.QuadPart - start.QuadPart) / freq.QuadPart;
+ ASSERT_EXPR( success, "Could not get token information." );
+
+ // Lookup the name from the sid.
+ QueryPerformanceCounter( &start );
+ LookupAccountSid( NULL, pTokenUser->User.Sid, name, &lNameLen,
+ domain, &lDomainLen, &sIgnore );
+ ASSERT_EXPR( success, "Could not lookup account sid." );
+ QueryPerformanceCounter( &lookup );
+ lookup.QuadPart = 1000000 * (lookup.QuadPart - start.QuadPart) / freq.QuadPart;
+
+ // Lookup the name from the sid a lot of times.
+ xlookup = GetTickCount();
+ for (i = 0; i < NumIterations; i++)
+ {
+ LookupAccountSid( NULL, pTokenUser->User.Sid, name, &lNameLen,
+ domain, &lDomainLen, &sIgnore );
+ ASSERT_EXPR( success, "Could not lookup account sid." );
+ }
+ xlookup = (GetTickCount() - xlookup)*1000/NumIterations;
+
+ // Import the security APIs.
+ GCoInitializeSecurity = (CoInitializeSecurityFn) Fixup( "CoInitializeSecurity" );
+ if (GCoInitializeSecurity == NULL)
+ goto cleanup;
+
+ // Measure the performance of initialize.
+ QueryPerformanceCounter( &start );
+ result = MCoInitializeSecurity( NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_NONE,
+ RPC_C_IMP_LEVEL_IMPERSONATE, NULL,
+ EOAC_NONE, NULL );
+ QueryPerformanceCounter( &init_sec_none );
+ init_sec_none.QuadPart = 1000000 * (init_sec_none.QuadPart - start.QuadPart) / freq.QuadPart;
+ ASSERT( result, "Could not initialize security" );
+
+ // Print the timings.
+ printf( "nothing took %duS\n", nothing.u.LowPart );
+ printf( "OpenProcessToken took %duS\n", open.u.LowPart );
+ printf( "GetTokenInformation took %duS\n", get_sid.u.LowPart );
+ printf( "LookupAccountSid took %duS\n", lookup.u.LowPart );
+ printf( "LookupAccountSid multiple took %duS\n", xlookup );
+ printf( "CoInitializeSecurity at none took %duS\n", init_sec_none.u.LowPart );
+
+ // Finally, its all over.
+ success = TRUE;
+cleanup:
+ if (client1 != NULL)
+ client1->Release();
+ CoUninitialize();
+
+ if (success)
+ printf( "\n\nTwo Test Passed.\n" );
+ else
+ printf( "\n\nTwo Test Failed.\n" );
+}
+
+ /***************************************************************************/
+void do_uninit()
+{
+ BOOL success = FALSE;
+ ITest *server = NULL;
+ ITest *server2 = NULL;
+ SAptId id;
+ SAptId id2;
+ HRESULT result;
+ DWORD i;
+ HANDLE thread[MAX_THREADS];
+ DWORD thread_id;
+
+ // This test always runs in multithreaded mode. It tests a multithread
+ // only problem and uses freethreaded blocking.
+ ThreadMode = COINIT_MULTITHREADED;
+
+ // Initialize OLE.
+ hello( "uninit" );
+ result = initialize( NULL, ThreadMode );
+ ASSERT( result, "Initialize failed" );
+
+ // Create a possibly remote object.
+ result = create_instance( ClassIds[free_auto_none], &server, &id );
+ ASSERT( result, "Could not create server" );
+
+ // Get another object.
+ result = server->get_obj_from_this_apt( &server2, &id2 );
+ ASSERT( result, "Could not get another object" );
+
+ // Tell the server to remember its neighbor
+ result = server->remember( server2, id2 );
+ ASSERT( result, "Could not remember server" );
+ server2->Release();
+ server2 = NULL;
+
+ // Tell it to wait for a call during shutdown and lower its priority.
+ result = server->set_state( late_dispatch_s, THREAD_PRIORITY_LOWEST );
+ ASSERT( result, "Could not set server state" );
+
+ // Don't create too many threads.
+ if (NumThreads > MAX_THREADS)
+ NumThreads = MAX_THREADS;
+
+ // Create some helper threads.
+ GlobalBool = TRUE;
+ for (i = 0; i < NumThreads; i++)
+ {
+ thread[i] = CreateThread( NULL, 0, do_uninit_helper, server, 0, &thread_id );
+ if (thread[i] == NULL)
+ {
+ printf( "Could not create helper thread number %d.\n", i );
+ goto cleanup;
+ }
+ }
+
+ // Call the server. Marshal an interface. Start shutting down.
+ // Wait before returning.
+ result = server->get_next_slowly( &server2, &id2 );
+ ASSERT( result, "Could not call server during shutdown" );
+
+ // Let the helpers run a while.
+ printf( "Waiting 5 seconds for server to die." );
+ Sleep( 5000 );
+
+ // Tell all the helpers to die.
+ GlobalBool = FALSE;
+ result = WaitForMultipleObjects( NumThreads, thread, TRUE, INFINITE );
+ ASSERT_EXPR( result != WAIT_FAILED, "Could not wait for helper threads to die.\n" );
+
+ // Finally, its all over.
+ success = TRUE;
+cleanup:
+ if (server2 != NULL)
+ server2->Release();
+ if (server != NULL)
+ server->Release();
+ CoUninitialize();
+
+ if (success)
+ printf( "\n\nUninit Test Passed.\n" );
+ else
+ printf( "\n\nUninit Test Failed.\n" );
+}
+
+ /***************************************************************************/
+DWORD _stdcall do_uninit_helper( void *param )
+{
+ ITest *server = (ITest *) param;
+ ITest *server2;
+ SAptId id;
+
+ // Call the server till the process terminates.
+ while (GlobalBool)
+ server->get_next( &server2, &id );
+
+ return 0;
+}
+
+ /***************************************************************************/
+void do_unknown()
+{
+ BOOL success = FALSE;
+ ITest *server = NULL;
+ IUnknown *unknown = NULL;
+ SAptId id;
+ HRESULT result;
+
+ // Initialize OLE.
+ hello( "unknown" );
+ result = initialize( NULL, ThreadMode );
+ ASSERT( result, "Initialize failed" );
+
+ // Set security to connect with secure references.
+ result = MCoInitializeSecurity( NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_CONNECT,
+ RPC_C_IMP_LEVEL_IMPERSONATE, NULL,
+ EOAC_SECURE_REFS, NULL );
+ ASSERT( result, "Could not initialize security to connect" );
+
+ if (ThreadMode == COINIT_APARTMENTTHREADED)
+ {
+ // Create a local server
+ result = new_apartment_test( &server, &id, NULL );
+ ASSERT( result, "Could not create local instance of test server" );
+ result = server->QueryInterface( IID_IUnknown, (void **) &unknown );
+ ASSERT( result, "Could not get IUnknown" );
+
+ // Test IUnknown
+ success = do_unknown_helper( unknown );
+ if (!success) goto cleanup;
+ success = FALSE;
+
+ // Release the local server.
+ unknown->Release();
+ unknown = NULL;
+ server->Release();
+ server = NULL;
+ }
+
+ // Create a possibly remote object.
+ result = create_instance( *ServerClsid, &server, &id );
+ ASSERT( result, "Could not create server" );
+ result = server->QueryInterface( IID_IUnknown, (void **) &unknown );
+ ASSERT( result, "Could not get IUnknown" );
+
+ // Test IUnknown
+ success = do_unknown_helper( unknown );
+ if (!success) goto cleanup;
+ success = FALSE;
+
+ // Finally, its all over.
+ success = TRUE;
+cleanup:
+ if (unknown != NULL)
+ unknown->Release();
+ if (server != NULL)
+ server->Release();
+ CoUninitialize();
+
+ if (success)
+ printf( "\n\nUnknown Test Passed.\n" );
+ else
+ printf( "\n\nUnknown Test Failed.\n" );
+}
+
+ /***************************************************************************/
+BOOL do_unknown_call( IUnknown *server, DWORD authn, DWORD imp, REFIID iid )
+{
+ BOOL success = FALSE;
+ HRESULT result;
+ DWORD authn_level_out;
+ DWORD imp_level_out;
+ DWORD authn_svc_out;
+ DWORD authz_svc_out;
+ OLECHAR *princ_name_out = NULL;
+ ITest *test = NULL;
+
+ result = MCoSetProxyBlanket( server, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE,
+ NULL, authn, imp, NULL, EOAC_NONE );
+ ASSERT( result, "Could not set blanket" );
+
+ // Verify the authentication information.
+ result = MCoQueryProxyBlanket( server, &authn_svc_out, &authz_svc_out,
+ &princ_name_out, &authn_level_out,
+ &imp_level_out, NULL, NULL );
+ if (result == S_OK)
+ {
+ ASSERT_EXPR( princ_name_out == NULL, "Got a principle name." );
+ ASSERT_EXPR( authn <= authn_level_out, "Wrong authentication level." );
+ ASSERT_EXPR( imp == imp_level_out, "Wrong impersonation level." );
+ ASSERT_EXPR( RPC_C_AUTHN_WINNT == authn_svc_out, "Wrong authentication service." );
+ ASSERT_EXPR( RPC_C_AUTHZ_NONE == authz_svc_out, "Wrong authorization service." );
+ }
+
+ // Query for the interface.
+ result = server->QueryInterface( iid, (void **) &test );
+ ASSERT( result, "Could not query interface" );
+
+ success = TRUE;
+cleanup:
+ CoTaskMemFree( princ_name_out );
+ if (test != NULL)
+ test->Release();
+ return success;
+}
+
+ /***************************************************************************/
+BOOL do_unknown_helper( IUnknown *server )
+{
+ BOOL success;
+
+ // Make an unsecure impersonate query.
+ success = do_unknown_call( server, RPC_C_AUTHN_LEVEL_NONE,
+ RPC_C_IMP_LEVEL_IMPERSONATE, IID_ITestNoneImp );
+ if (!success) return FALSE;
+
+ // Make a connect level impersonate query.
+ success = do_unknown_call( server, RPC_C_AUTHN_LEVEL_CONNECT,
+ RPC_C_IMP_LEVEL_IMPERSONATE, IID_ITestConnectImp );
+ if (!success) return FALSE;
+
+ // Make an encrypt level impersonate query.
+ success = do_unknown_call( server, RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
+ RPC_C_IMP_LEVEL_IMPERSONATE, IID_ITestEncryptImp );
+ if (!success) return FALSE;
+
+ // Make an unsecure identify query.
+ success = do_unknown_call( server, RPC_C_AUTHN_LEVEL_NONE,
+ RPC_C_IMP_LEVEL_IDENTIFY, IID_ITestNoneId );
+ if (!success) return FALSE;
+
+ // Make a connect level identify query.
+ success = do_unknown_call( server, RPC_C_AUTHN_LEVEL_CONNECT,
+ RPC_C_IMP_LEVEL_IDENTIFY, IID_ITestConnectId );
+ if (!success) return FALSE;
+
+ // Make an encrypt level identify query.
+ success = do_unknown_call( server, RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
+ RPC_C_IMP_LEVEL_IDENTIFY, IID_ITestEncryptId );
+ if (!success) return FALSE;
+ return TRUE;
+}
+
+ /***************************************************************************/
+void *Fixup( char *name )
+{
+ HINSTANCE ole;
+ void *fn;
+
+ // Load ole32.dll
+ ole = LoadLibraryA( "ole32.dll" );
+ if (ole == NULL)
+ {
+ printf( "Could not load ole32.dll to get security function.\n" );
+ return NULL;
+ }
+
+ // Get the function
+ fn = GetProcAddress( ole, name );
+ FreeLibrary( ole );
+ if (fn == NULL)
+ {
+ printf( "Could not find %s in ole32.dll.\n", name );
+ return NULL;
+ }
+
+ // Call function
+ return fn;
+}
+
+ /***************************************************************************/
+HRESULT __stdcall FixupCoCopyProxy(
+ IUnknown *pProxy,
+ IUnknown **ppCopy )
+{
+ HINSTANCE ole;
+ HRESULT result;
+
+ // Load ole32.dll
+ ole = LoadLibraryA( "ole32.dll" );
+ if (ole == NULL)
+ {
+ printf( "Could not load ole32.dll to get security function.\n" );
+ return E_NOTIMPL;
+ }
+
+ // Get the function
+ GCoCopyProxy = (CoCopyProxyFn) GetProcAddress( ole, "CoCopyProxy" );
+ FreeLibrary( ole );
+ if (GCoCopyProxy == NULL)
+ {
+ printf( "Could not find security in ole32.dll.\n" );
+ return E_NOTIMPL;
+ }
+
+ // Call function
+ return GCoCopyProxy( pProxy, ppCopy );
+}
+
+ /***************************************************************************/
+HRESULT __stdcall FixupCoGetCallContext( REFIID riid, void **ppInterface )
+{
+ HINSTANCE ole;
+ HRESULT result;
+
+ // Load ole32.dll
+ ole = LoadLibraryA( "ole32.dll" );
+ if (ole == NULL)
+ {
+ printf( "Could not load ole32.dll to get security function.\n" );
+ return E_NOTIMPL;
+ }
+
+ // Get the function
+ GCoGetCallContext = (CoGetCallContextFn)
+ GetProcAddress( ole, "CoGetCallContext" );
+ FreeLibrary( ole );
+ if (GCoGetCallContext == NULL)
+ {
+ printf( "Could not find security in ole32.dll.\n" );
+ return E_NOTIMPL;
+ }
+
+ // Call function
+ return GCoGetCallContext( riid, ppInterface );
+}
+
+ /***************************************************************************/
+HRESULT __stdcall FixupCoImpersonateClient()
+{
+ HINSTANCE ole;
+ HRESULT result;
+
+ // Load ole32.dll
+ ole = LoadLibraryA( "ole32.dll" );
+ if (ole == NULL)
+ {
+ printf( "Could not load ole32.dll to get security function.\n" );
+ return E_NOTIMPL;
+ }
+
+ // Get the function
+ GCoImpersonateClient = (CoImpersonateClientFn)
+ GetProcAddress( ole, "CoImpersonateClient" );
+ FreeLibrary( ole );
+ if (GCoImpersonateClient == NULL)
+ {
+ printf( "Could not find security in ole32.dll.\n" );
+ return E_NOTIMPL;
+ }
+
+ // Call function
+ return GCoImpersonateClient();
+}
+
+ /***************************************************************************/
+HRESULT __stdcall FixupCoInitializeSecurity(
+ SECURITY_DESCRIPTOR *pSecDesc,
+ DWORD cAuthSvc,
+ SOLE_AUTHENTICATION_SERVICE *asAuthSvc,
+ WCHAR *pPrincName,
+ DWORD dwAuthnLevel,
+ DWORD dwImpLevel,
+ RPC_AUTH_IDENTITY_HANDLE pAuthInfo,
+ DWORD dwCapabilities,
+ void *pReserved )
+{
+ HINSTANCE ole;
+ HRESULT result;
+
+ // Load ole32.dll
+ ole = LoadLibraryA( "ole32.dll" );
+ if (ole == NULL)
+ {
+ printf( "Could not load ole32.dll to get security function.\n" );
+ return E_NOTIMPL;
+ }
+
+ // Get the function
+ GCoInitializeSecurity = (CoInitializeSecurityFn)
+ GetProcAddress( ole, "CoInitializeSecurity" );
+ FreeLibrary( ole );
+ if (GCoInitializeSecurity == NULL)
+ {
+ printf( "Could not find security in ole32.dll.\n" );
+ return E_NOTIMPL;
+ }
+
+ // Call function
+ return GCoInitializeSecurity( pSecDesc, cAuthSvc, asAuthSvc, pPrincName,
+ dwAuthnLevel, dwImpLevel, pAuthInfo,
+ dwCapabilities, pReserved );
+}
+
+ /***************************************************************************/
+HRESULT __stdcall FixupCoQueryAuthenticationServices( DWORD *pcbAuthSvc,
+ SOLE_AUTHENTICATION_SERVICE **asAuthSvc )
+{
+ HINSTANCE ole;
+ HRESULT result;
+
+ // Load ole32.dll
+ ole = LoadLibraryA( "ole32.dll" );
+ if (ole == NULL)
+ {
+ printf( "Could not load ole32.dll to get security function.\n" );
+ return E_NOTIMPL;
+ }
+
+ // Get the function
+ GCoQueryAuthenticationServices = (CoQueryAuthenticationServicesFn)
+ GetProcAddress( ole, "CoQueryAuthenticationServices" );
+ FreeLibrary( ole );
+ if (GCoQueryAuthenticationServices == NULL)
+ {
+ printf( "Could not find security in ole32.dll.\n" );
+ return E_NOTIMPL;
+ }
+
+ // Call function
+ return GCoQueryAuthenticationServices( pcbAuthSvc, asAuthSvc );
+}
+
+ /***************************************************************************/
+HRESULT __stdcall FixupCoQueryClientBlanket(
+ DWORD *pAuthnSvc,
+ DWORD *pAuthzSvc,
+ OLECHAR **pServerPrincName,
+ DWORD *pAuthnLevel,
+ DWORD *pImpLevel,
+ RPC_AUTHZ_HANDLE *pPrivs,
+ DWORD *pCapabilities )
+{
+ HINSTANCE ole;
+ HRESULT result;
+
+ // Load ole32.dll
+ ole = LoadLibraryA( "ole32.dll" );
+ if (ole == NULL)
+ {
+ printf( "Could not load ole32.dll to get security function.\n" );
+ return E_NOTIMPL;
+ }
+
+ // Get the function
+ GCoQueryClientBlanket = (CoQueryClientBlanketFn)
+ GetProcAddress( ole, "CoQueryClientBlanket" );
+ FreeLibrary( ole );
+ if (GCoQueryClientBlanket == NULL)
+ {
+ printf( "Could not find security in ole32.dll.\n" );
+ return E_NOTIMPL;
+ }
+
+ // Call function
+ return GCoQueryClientBlanket( pAuthnSvc, pAuthzSvc, pServerPrincName,
+ pAuthnLevel, pImpLevel, pPrivs, pCapabilities );
+}
+
+ /***************************************************************************/
+HRESULT __stdcall FixupCoQueryProxyBlanket(
+ IUnknown *pProxy,
+ DWORD *pAuthnSvc,
+ DWORD *pAuthzSvc,
+ OLECHAR **pServerPrincName,
+ DWORD *pAuthnLevel,
+ DWORD *pImpLevel,
+ RPC_AUTH_IDENTITY_HANDLE *pAuthInfo,
+ DWORD *pCapabilities )
+{
+ HINSTANCE ole;
+ HRESULT result;
+
+ // Load ole32.dll
+ ole = LoadLibraryA( "ole32.dll" );
+ if (ole == NULL)
+ {
+ printf( "Could not load ole32.dll to get security function.\n" );
+ return E_NOTIMPL;
+ }
+
+ // Get the function
+ GCoQueryProxyBlanket = (CoQueryProxyBlanketFn)
+ GetProcAddress( ole, "CoQueryProxyBlanket" );
+ FreeLibrary( ole );
+ if (GCoQueryProxyBlanket == NULL)
+ {
+ printf( "Could not find security in ole32.dll.\n" );
+ return E_NOTIMPL;
+ }
+
+ // Call function
+ return GCoQueryProxyBlanket( pProxy, pAuthnSvc, pAuthzSvc, pServerPrincName,
+ pAuthnLevel, pImpLevel, pAuthInfo, pCapabilities );
+}
+
+ /***************************************************************************/
+HRESULT __stdcall FixupCoRevertToSelf()
+{
+ HINSTANCE ole;
+ HRESULT result;
+
+ // Load ole32.dll
+ ole = LoadLibraryA( "ole32.dll" );
+ if (ole == NULL)
+ {
+ printf( "Could not load ole32.dll to get security function.\n" );
+ return E_NOTIMPL;
+ }
+
+ // Get the function
+ GCoRevertToSelf = (CoRevertToSelfFn) GetProcAddress( ole, "CoRevertToSelf" );
+ FreeLibrary( ole );
+ if (GCoRevertToSelf == NULL)
+ {
+ printf( "Could not find security in ole32.dll.\n" );
+ return E_NOTIMPL;
+ }
+
+ // Call function
+ return GCoRevertToSelf();
+}
+
+ /***************************************************************************/
+HRESULT __stdcall FixupCoSetProxyBlanket(
+ IUnknown *pProxy,
+ DWORD dwAuthnSvc,
+ DWORD dwAuthzSvc,
+ OLECHAR *pServerPrincName,
+ DWORD dwAuthnLevel,
+ DWORD dwImpLevel,
+ RPC_AUTH_IDENTITY_HANDLE *pAuthInfo,
+ DWORD dwCapabilities )
+{
+ HINSTANCE ole;
+ HRESULT result;
+
+ // Load ole32.dll
+ ole = LoadLibraryA( "ole32.dll" );
+ if (ole == NULL)
+ {
+ printf( "Could not load ole32.dll to get security function.\n" );
+ return E_NOTIMPL;
+ }
+
+ // Get the function
+ GCoSetProxyBlanket = (CoSetProxyBlanketFn)
+ GetProcAddress( ole, "CoSetProxyBlanket" );
+ FreeLibrary( ole );
+ if (GCoSetProxyBlanket == NULL)
+ {
+ printf( "Could not find security in ole32.dll.\n" );
+ return E_NOTIMPL;
+ }
+
+ // Call function
+ return GCoSetProxyBlanket( pProxy, dwAuthnSvc, dwAuthzSvc, pServerPrincName,
+ dwAuthnLevel, dwImpLevel, pAuthInfo, dwCapabilities );
+}
+
+ /***************************************************************************/
+HRESULT __stdcall FixupCoSwitchCallContext( IUnknown *pNewObject, IUnknown **ppOldObject )
+{
+ HINSTANCE ole;
+ HRESULT result;
+
+ // Load ole32.dll
+ ole = LoadLibraryA( "ole32.dll" );
+ if (ole == NULL)
+ {
+ printf( "Could not load ole32.dll to get security function.\n" );
+ return E_NOTIMPL;
+ }
+
+ // Get the function
+ GCoSwitchCallContext = (CoSwitchCallContextFn)
+ GetProcAddress( ole, "CoSwitchCallContext" );
+ FreeLibrary( ole );
+ if (GCoSwitchCallContext == NULL)
+ {
+ printf( "Could not find security in ole32.dll.\n" );
+ return E_NOTIMPL;
+ }
+
+ // Call function
+ return GCoSwitchCallContext( pNewObject, ppOldObject );
+}
+
+ /***************************************************************************/
+DWORD get_sequence()
+{
+ if (ThreadMode == COINIT_MULTITHREADED)
+ return ProcessAptData.sequence++;
+ else
+ {
+ SAptData *tls_data = (SAptData *) TlsGetValue( TlsIndex );
+ return tls_data->sequence++;
+ }
+}
+
+ /***************************************************************************/
+void hello( char *test )
+{
+ // Say hello.
+ if (ThreadMode == COINIT_SINGLETHREADED)
+ printf( "Running %s test in single threaded mode.\n", test );
+ else if (ThreadMode == COINIT_APARTMENTTHREADED)
+ printf( "Running %s test in apartment threaded mode.\n", test );
+ else
+ printf( "Running %s test in multithreaded mode.\n", test );
+}
+
+ /***************************************************************************/
+void increment_object_count()
+{
+ if (ThreadMode == COINIT_MULTITHREADED)
+ {
+ InterlockedIncrement( &ProcessAptData.object_count );
+ ProcessAptData.what_next = wait_wn;
+ }
+ else
+ {
+ SAptData *tls_data = (SAptData *) TlsGetValue( TlsIndex );
+ tls_data->object_count += 1;
+ tls_data->what_next = wait_wn;
+ }
+
+}
+
+ /***************************************************************************/
+HRESULT initialize( void *reserved, ULONG flags )
+{
+ HINSTANCE ole;
+ INIT_FN init_ex;
+ HRESULT result;
+
+ // For the apartment model, just use CoInitialize.
+ if (flags == COINIT_APARTMENTTHREADED)
+ return CoInitialize( NULL );
+
+ // For free threading, try to find the CoInitializeEx API.
+ ole = LoadLibraryA( "ole32.dll" );
+ if (ole == NULL)
+ {
+ printf( "Could not load ole32.dll to get CoInitializeEx.\n" );
+ return E_NOTIMPL;
+ }
+
+ // Get CoInitializeEx.
+ init_ex = (INIT_FN) GetProcAddress( ole, "CoInitializeEx" );
+ if (init_ex == NULL)
+ {
+ FreeLibrary( ole );
+ printf( "Could not find CoInitializeEx in ole32.dll.\n" );
+ return E_NOTIMPL;
+ }
+
+ // Call CoInitializeEx.
+ result = init_ex( reserved, flags );
+ FreeLibrary( ole );
+ return result;
+}
+
+ /***************************************************************************/
+HRESULT initialize_security()
+{
+ HRESULT result;
+ SOLE_AUTHENTICATION_SERVICE svc_list;
+
+ // Initialize security.
+ if (GlobalSecurityModel == basic_sm)
+ {
+ printf( "Basic security model.\n" );
+ svc_list.dwAuthnSvc = RPC_C_AUTHN_WINNT;
+ svc_list.dwAuthzSvc = RPC_C_AUTHZ_NONE;
+ svc_list.pPrincipalName = NULL;
+ result = MCoInitializeSecurity( NULL, 1, &svc_list, NULL, GlobalAuthnLevel,
+ RPC_C_IMP_LEVEL_IMPERSONATE, NULL,
+ EOAC_NONE, NULL );
+ }
+ else if (GlobalSecurityModel == auto_sm)
+ {
+ printf( "Automatic security model.\n" );
+ result = MCoInitializeSecurity( NULL, -1, NULL, NULL, GlobalAuthnLevel,
+ RPC_C_IMP_LEVEL_IMPERSONATE, NULL,
+ EOAC_NONE, NULL );
+ }
+ else
+ {
+ printf( "Legacy security model.\n" );
+ result = S_OK;
+ }
+ return result;
+}
+
+ /***************************************************************************/
+void interrupt()
+{
+ while (GlobalInterruptTest)
+ {
+ GlobalTest->check( GlobalApt );
+ check_for_request();
+ }
+ GlobalTest->Release();
+}
+
+ /***************************************************************************/
+void interrupt_marshal()
+{
+ int i;
+
+ for (i = 0; i < NUM_MARSHAL_LOOP; i++ )
+ {
+ GlobalTest->recurse( GlobalTest2, 1 );
+ check_for_request();
+ }
+ GlobalTest->Release();
+ GlobalTest2->Release();
+ what_next( wait_wn );
+}
+
+ /***************************************************************************
+ Function: main
+
+ Synopsis: Executes the BasicBnd test
+
+ Effects: None
+
+
+ Returns: Exits with exit code 0 if success, 1 otherwise
+
+***************************************************************************/
+
+int _cdecl main(int argc, char *argv[])
+{
+ HRESULT result;
+ SAptData tls_data;
+ BOOL success = TRUE;
+ DWORD ignore;
+ TOKEN_USER *token_info = NULL;
+ DWORD info_size = 1024;
+ HANDLE token = NULL;
+
+ // Initialize Globals.
+ MainThread = GetCurrentThreadId();
+ ignore = sizeof(Name);
+ GetComputerName( Name, &ignore );
+
+ // Create an event for termination notification.
+ Done = CreateEventA( NULL, FALSE, FALSE, NULL );
+ if (Done == NULL)
+ {
+ printf( "Could not create event.\n" );
+ return 0;
+ }
+
+ // Get an event for signalling raw RPCs.
+ RawEvent = CreateEventA( NULL, FALSE, FALSE, NULL );
+ if (RawEvent == NULL)
+ {
+ printf( "Could not create event.\n" );
+ return 0;
+ }
+
+ // Allocate a TLS index.
+ TlsIndex = TlsAlloc();
+ if (TlsIndex == 0xffffffff)
+ {
+ printf( "Could not allocate TLS index.\n" );
+ return 0;
+ }
+
+ // Open the process's token.
+ OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY, &token );
+ result = GetLastError();
+ if (result != 0)
+ {
+ printf( "Could not OpenProcessToken.\n" );
+ return 0;
+ }
+
+ // Lookup SID of process token.
+ token_info = (TOKEN_USER *) malloc( info_size );
+ if (token_info == NULL)
+ {
+ printf( "Could not allocate memory for token info.\n" );
+ return 0;
+ }
+ GetTokenInformation( token, TokenUser, token_info, info_size, &info_size );
+ result = GetLastError();
+ if (result != 0)
+ {
+ printf( "Could not GetTokenInformation.\n" );
+ return 0;
+ }
+ ProcessSid = (SID *) token_info->User.Sid;
+ CloseHandle( token );
+
+ // Parse the parameters.
+ if (!parse( argc, argv ))
+ return 0;
+
+ // Make sure the registry is set.
+ if (!registry_setup( argv[0] ))
+ return 0;
+
+ // Initiailize the apartment global data for the multithreaded mode.
+ if (ThreadMode == COINIT_MULTITHREADED)
+ {
+ ProcessAptData.object_count = 0;
+ ProcessAptData.what_next = setup_wn;
+ ProcessAptData.exit_dirty = FALSE;
+ ProcessAptData.sequence = 0;
+ }
+
+ // In the single threaded mode, stick a pointer to the object count
+ // in TLS.
+ else
+ {
+ tls_data.object_count = 0;
+ tls_data.what_next = setup_wn;
+ tls_data.exit_dirty = FALSE;
+ tls_data.sequence = 0;
+ TlsSetValue( TlsIndex, &tls_data );
+ }
+
+ // Switch to the correct test.
+ switch_test();
+
+ // Cleanup.
+ TlsFree( TlsIndex );
+ CloseHandle( Done );
+ return 1;
+}
+
+ /*************************************************************************/
+void __RPC_FAR * __RPC_API midl_user_allocate( size_t count )
+{
+ return malloc(count);
+}
+
+ /*************************************************************************/
+void __RPC_USER midl_user_free( void __RPC_FAR * p )
+{
+ free( p );
+}
+
+ /*************************************************************************/
+HRESULT new_apartment_test( ITest ** test, SAptId *id, HANDLE *thread_out )
+{
+ new_apt_params params;
+ HANDLE thread;
+ DWORD thread_id;
+ DWORD status;
+ HRESULT result;
+ IClassFactory *factory;
+
+ // Create an event.
+ params.stream = NULL;
+ params.ready = CreateEventA( NULL, FALSE, FALSE, NULL );
+ if (params.ready == NULL)
+ return E_OUTOFMEMORY;
+
+ // Start a new thread/apartment.
+ thread = CreateThread( NULL, 0, apartment_base, &params, 0, &thread_id );
+ if (thread == NULL)
+ {
+ result = E_OUTOFMEMORY;
+ goto cleanup;
+ }
+
+ // Wait till it has marshalled a class factory.
+ status = WaitForSingleObject( params.ready, INFINITE );
+ if (status != WAIT_OBJECT_0 || params.stream == NULL)
+ {
+ result = E_FAIL;
+ goto cleanup;
+ }
+
+ // Unmarshal the class factory.
+ result = CoUnmarshalInterface( params.stream, IID_IClassFactory,
+ (void **) &factory );
+ params.stream->Release();
+ if (FAILED(result))
+ goto cleanup;
+
+ // Create a test object.
+ result = factory->CreateInstance( NULL, IID_ITest, (void **) test );
+ factory->Release();
+ if (*test != NULL)
+ (*test)->get_id( id );
+
+cleanup:
+ if (thread_out != NULL && SUCCEEDED(result))
+ *thread_out = thread;
+ else
+ CloseHandle( thread );
+ if (params.ready != NULL)
+ CloseHandle( params.ready );
+ return result;
+}
+
+ /*************************************************************************/
+/* Parse the arguments. */
+BOOL parse( int argc, char *argv[] )
+{
+ int i;
+ int len;
+ char buffer[80];
+
+ WhatTest = lots_wt;
+ ThreadMode = COINIT_APARTMENTTHREADED;
+
+ // Parse each item, skip the command name
+ for (i = 1; i < argc; i++)
+ {
+ if (_stricmp( argv[i], "Apartment" ) == 0)
+ ThreadMode = COINIT_APARTMENTTHREADED;
+
+ else if (_stricmp( argv[i], "-auto" ) == 0)
+ {
+ if (argv[++i] == NULL)
+ {
+ printf( "You must include an authentication level after the -auto option.\n" );
+ return FALSE;
+ }
+ sscanf( argv[i], "%d", &GlobalAuthnLevel );
+ GlobalSecurityModel = auto_sm;
+ }
+
+ else if (_stricmp( argv[i], "-b" ) == 0)
+ DebugBreak();
+
+ else if (_stricmp( argv[i], "-basic" ) == 0)
+ GlobalSecurityModel = basic_sm;
+
+ else if (_stricmp( argv[i], "-c" ) == 0)
+ Change = TRUE;
+
+ else if (_stricmp( argv[i], "Cancel" ) == 0)
+ WhatTest = cancel_wt;
+
+ else if (_stricmp( argv[i], "Crash" ) == 0)
+ WhatTest = crash_wt;
+
+ else if (_stricmp( argv[i], "Cstress" ) == 0)
+ WhatTest = cstress_wt;
+
+ else if (_stricmp( argv[i], "-d" ) == 0)
+ {
+ if (argv[++i] == NULL)
+ {
+ printf( "You must include a debugger after the -d option.\n" );
+ return FALSE;
+ }
+ WriteClass = TRUE;
+ if (_stricmp( argv[i], "none" ) == 0)
+ strcpy( Debugger, "" );
+ // MultiByteToWideChar( CP_ACP, 0, "", 0, Debugger, sizeof(Debugger) );
+ else
+ strcpy( Debugger, argv[i] );
+ // MultiByteToWideChar( CP_ACP, 0, argv[i], strlen(argv[i], Debugger,
+ // sizeof(Debugger) );
+ if (WhatTest = lots_wt)
+ WhatTest = none_wt;
+ }
+
+ else if (_stricmp( argv[i], "-Embedding" ) == 0)
+ WhatTest = server_wt;
+
+ else if (_stricmp( argv[i], "-i" ) == 0)
+ {
+ if (argv[++i] == NULL)
+ {
+ printf( "You must include an iteration count after the -i option.\n" );
+ return FALSE;
+ }
+ sscanf( argv[i], "%d", &NumIterations );
+ }
+
+ else if (_stricmp( argv[i], "Hook" ) == 0)
+ WhatTest = hook_wt;
+
+ else if (_stricmp( argv[i], "-legacy" ) == 0)
+ GlobalSecurityModel = legacy_sm;
+
+ else if (_stricmp( argv[i], "load_client" ) == 0)
+ WhatTest = load_client_wt;
+
+ else if (_stricmp( argv[i], "Load_Server" ) == 0)
+ WhatTest = load_server_wt;
+
+ else if (_stricmp( argv[i], "Mmarshal" ) == 0)
+ WhatTest = mmarshal_wt;
+
+ else if (_stricmp( argv[i], "Multi" ) == 0)
+ ThreadMode = COINIT_MULTITHREADED;
+
+ else if (_stricmp( argv[i], "-n" ) == 0)
+ {
+ if (argv[++i] == NULL)
+ {
+ printf( "You must include a name after the -n option.\n" );
+ return FALSE;
+ }
+ MultiByteToWideChar( CP_ACP, 0, argv[i], strlen(argv[i]), Name,
+ sizeof(Name) );
+ Name[strlen(argv[i])] = 0;
+ }
+
+ else if (_stricmp( argv[i], "Null" ) == 0)
+ WhatTest = null_wt;
+
+ else if (_stricmp( argv[i], "One" ) == 0)
+ WhatTest = one_wt;
+
+ else if (_stricmp( argv[i], "Perf" ) == 0)
+ WhatTest = perf_wt;
+
+ else if (_stricmp( argv[i], "PerfRemote" ) == 0)
+ WhatTest = perfremote_wt;
+
+ else if (_stricmp( argv[i], "PerfRpc" ) == 0)
+ WhatTest = perfrpc_wt;
+
+ else if (_stricmp( argv[i], "PerfSec" ) == 0)
+ WhatTest = perfsec_wt;
+
+ else if (_stricmp( argv[i], "Post" ) == 0)
+ WhatTest = post_wt;
+
+ else if (_stricmp( argv[i], "-o" ) == 0)
+ {
+ if (argv[++i] == NULL)
+ {
+ printf( "You must include an object count after the -o option.\n" );
+ return FALSE;
+ }
+ sscanf( argv[i], "%d", &NumObjects );
+ }
+
+ else if (_stricmp( argv[i], "-o" ) == 0)
+ {
+ if (argv[++i] == NULL)
+ {
+ printf( "You must include an object count after the -o option.\n" );
+ return FALSE;
+ }
+ sscanf( argv[i], "%d", &NumObjects );
+ }
+
+ else if (_stricmp( argv[i], "-p" ) == 0)
+ {
+ if (argv[++i] == NULL)
+ {
+ printf( "You must include a process count after the -p option.\n" );
+ return FALSE;
+ }
+ sscanf( argv[i], "%d", &NumProcesses );
+ }
+
+ else if (_stricmp( argv[i], "-popup" ) == 0)
+ Popup = TRUE;
+
+ else if (_stricmp( argv[i], "-r" ) == 0)
+ {
+ if (argv[++i] == NULL)
+ {
+ printf( "You must include a recursion count after the -r option.\n" );
+ return FALSE;
+ }
+ sscanf( argv[i], "%d", &NumRecursion );
+ }
+
+ else if (_stricmp( argv[i], "Reject" ) == 0)
+ WhatTest = reject_wt;
+
+ else if (_stricmp( argv[i], "Remote_client" ) == 0)
+ WhatTest = remote_client_wt;
+
+ else if (_stricmp( argv[i], "Remote_server" ) == 0)
+ WhatTest = remote_server_wt;
+
+ else if (_stricmp( argv[i], "Ring" ) == 0)
+ WhatTest = ring_wt;
+
+ else if (_stricmp( argv[i], "Rpc" ) == 0)
+ WhatTest = rpc_wt;
+
+ else if (_stricmp( argv[i], "Rundown" ) == 0)
+ WhatTest = rundown_wt;
+
+ else if (_stricmp( argv[i], "-s" ) == 0)
+ {
+ if (argv[++i] == NULL)
+ {
+ printf( "You must include a protocol sequence after the -s option.\n" );
+ return FALSE;
+ }
+ MultiByteToWideChar( CP_ACP, 0, argv[i], strlen(argv[i]), TestProtseq,
+ sizeof(TestProtseq) );
+ TestProtseq[strlen(argv[i])] = 0;
+ }
+
+ else if (_stricmp( argv[i], "Security" ) == 0)
+ WhatTest = security_wt;
+
+ else if (_stricmp( argv[i], "SecureRefs" ) == 0)
+ WhatTest = securerefs_wt;
+
+ else if (_stricmp( argv[i], "Send" ) == 0)
+ WhatTest = send_wt;
+
+ else if (_stricmp( argv[i], "-t" ) == 0)
+ {
+ if (argv[++i] == NULL)
+ {
+ printf( "You must include a thread count after the -t option.\n" );
+ return FALSE;
+ }
+ sscanf( argv[i], "%d", &NumThreads );
+ }
+
+ else if (_stricmp( argv[i], "sid" ) == 0)
+ WhatTest = sid_wt;
+
+ else if (_stricmp( argv[i], "Simple_rundown" ) == 0)
+ WhatTest = simple_rundown_wt;
+
+ else if (_stricmp( argv[i], "Thread" ) == 0)
+ WhatTest = thread_wt;
+
+ else if (_stricmp( argv[i], "Three" ) == 0)
+ WhatTest = three_wt;
+
+ else if (_stricmp( argv[i], "Two" ) == 0)
+ WhatTest = two_wt;
+
+ else if (_stricmp( argv[i], "Uninit" ) == 0)
+ WhatTest = uninit_wt;
+
+ else if (_stricmp( argv[i], "Unknown" ) == 0)
+ WhatTest = unknown_wt;
+
+ else
+ {
+ printf( "You don't know what you are doing!\n" );
+ printf( "This program tests the channel.\n" );
+ printf( "\n" );
+ printf( "Apartment Apartment threading mode.\n" );
+ printf( "Cancel Cancel test.\n" );
+ printf( "Crash Crash test.\n" );
+ printf( "Cstress Cancel stress test.\n" );
+ printf( "Hook Channel hook test.\n" );
+ printf( "Load_Client Remote load performance - client.\n" );
+ printf( "Load_Server Remote load performance - server.\n" );
+ printf( "Mmarshal Multiple marshal test.\n" );
+ printf( "Multi Multithreaded mode.\n" );
+ printf( "Null Apartment null call test.\n" );
+ printf( "One Used for testing new tests.\n" );
+ printf( "Perf Performance test.\n" );
+ printf( "PerfRemote Remote call performance test.\n" );
+ printf( "PerfRpc Raw RPC performance test.\n" );
+ printf( "PerfSec Security performance test.\n" );
+ printf( "Post Post a message to window specified by -i.\n" );
+ printf( "Reject Reject test.\n" );
+ printf( "Remote_Client Remote performance - client.\n" );
+ printf( "Remote_Server Remote performance - server.\n" );
+ printf( "Ring Run ring test.\n" );
+ printf( "Rpc Test both RPC and OLE calls.\n" );
+ printf( "Rundown Rundown test.\n" );
+ printf( "SecureRefs Secure Addref/Release Test.\n" );
+ printf( "Security Security test.\n" );
+ printf( "Send Send a message to window specified by -i.\n" );
+ printf( "Sid Lookup the sid for the name specified by -n\n" );
+ printf( "Simple_Rundown Wait for object exporter to timeout.\n" );
+ printf( "Thread Calling on multiple threads.\n" );
+ printf( "Three Used for reproducing bugs.\n" );
+ printf( "Two Used for reproducing bugs.\n" );
+ printf( "Uninit Calls during uninitialization.\n" );
+ printf( "Unknown IUnknown security.\n" );
+ printf( "\n" );
+ printf( "-auto n Use automatic security set to level n.\n" );
+ printf( "-b Stop in debugger before going on.\n" );
+ printf( "-basic Use basic security.\n" );
+ printf( "-c Change the test.\n" );
+ printf( "-d debugger Debugger to run app under of none.\n" );
+ printf( "-Embedding Server side.\n" );
+ printf( "-legacy Use legacy security.\n" );
+ printf( "-i n Number of iterations.\n" );
+ printf( "-n name String name.\n" );
+ printf( "-o n Number of objects.\n" );
+ printf( "-p n Number of processes.\n" );
+ printf( "-popup Display popups for sync during test.\n" );
+ printf( "-r n Number of recursions.\n" );
+ printf( "-s protseq Change default protocol sequence.\n" );
+ printf( "-t n Number of threads.\n" );
+ printf( "\n" );
+ printf( "The test currently only runs in the single threaded mode\n" );
+ printf( "and requires the apartment model.\n" );
+ printf( "If no test is specified the cancel, crash, null,\n" );
+ printf( "ring, and rundown tests will be run. The options have the\n" );
+ printf( "following default values.\n" );
+ printf( " authn level - %d\n", GlobalAuthnLevel );
+ printf( " iterations - 1000\n" );
+ printf( " name - %ws\n", Name );
+ printf( " objects - 2\n" );
+ printf( " processes - 2\n" );
+ printf( " recurse - 2\n" );
+ printf( " protseq - %ws\n", TestProtseq );
+ printf( " security model - %d\n", GlobalSecurityModel );
+ printf( " threads - 2\n" );
+ return FALSE;
+ }
+ }
+
+ // Figure out the class id based on the thread model and security model.
+ if (GlobalSecurityModel == auto_sm)
+ if (GlobalAuthnLevel == RPC_C_AUTHN_LEVEL_CONNECT)
+ i = 1;
+ else if (GlobalAuthnLevel == RPC_C_AUTHN_LEVEL_PKT_INTEGRITY)
+ i = 2;
+ else
+ i = 0;
+ else if (GlobalSecurityModel == basic_sm)
+ i = 3;
+ else
+ i = 4;
+ if (ThreadMode == COINIT_MULTITHREADED)
+ ServerClsid = &ClassIds[free_auto_none+i];
+ else
+ ServerClsid = &ClassIds[apt_auto_none+i];
+
+ return TRUE;
+}
+
+ /***************************************************************************/
+BOOL registry_setup( char *argv0 )
+{
+ char value[REGISTRY_ENTRY_LEN];
+ LONG value_size;
+ LONG result;
+ char directory[MAX_PATH];
+ char *appname;
+ int i;
+ int j;
+ char *class_id;
+ HKEY key = NULL;
+ DWORD ignore;
+ SECURITY_DESCRIPTOR *sec;
+
+ // Find out if the registry is setup.
+ value_size = sizeof(value);
+ result = RegQueryValueA(
+ HKEY_CLASSES_ROOT,
+ REG_CLASS_EXE,
+ value,
+ &value_size );
+
+ // If the registry is not setup or needs to be rewritten, write it.
+ if (result != ERROR_SUCCESS || WriteClass)
+ {
+ // Write all the interface ids.
+ for (i = 0; i < NUM_INTERFACE_IDS; i++)
+ {
+ // Write the interface name.
+ strcpy( value, "Interface\\{60000200-76d7-11cf-9af1-0020af6e72f4}" );
+ value[18] += i;
+ result = RegSetValueA(
+ HKEY_CLASSES_ROOT,
+ value,
+ REG_SZ,
+ REG_INTERFACE_NAME[i],
+ strlen(REG_INTERFACE_NAME[i]) );
+ ASSERT( result, "Could not set interface name: 0x%x" );
+
+ // Write the interface to proxy class id translation.
+ strcpy( value, "Interface\\{60000200-76d7-11cf-9af1-0020af6e72f4}\\ProxyStubClsid32" );
+ value[18] += i;
+ result = RegSetValueA(
+ HKEY_CLASSES_ROOT,
+ value,
+ REG_SZ,
+ REG_INTERFACE_CLASS,
+ strlen(REG_INTERFACE_CLASS) );
+ ASSERT( result, "Could not set interface class: 0x%x" );
+ }
+
+ // Write the proxy name.
+ result = RegSetValueA(
+ HKEY_CLASSES_ROOT,
+ "CLSID\\{60000200-76d7-11cf-9af1-0020af6e72f4}",
+ REG_SZ,
+ REG_PROXY_NAME,
+ strlen(REG_PROXY_NAME) );
+ ASSERT( result, "Could not set interface name: 0x%x" );
+
+ // Compute the path to the application.
+ result = GetFullPathNameA( argv0, sizeof(directory), directory, &appname );
+ ASSERT_EXPR( result != 0, "Could not GetFullPathName." );
+ result = appname - directory;
+ if (result + strlen(REG_PROXY_DLL) > MAX_PATH ||
+ result + strlen(REG_APP_EXE) + strlen(Debugger) > MAX_PATH)
+ {
+ printf( "Buffer too small.\n" );
+ goto cleanup;
+ }
+
+ // Write the proxy dll path.
+ strcpy( appname, REG_PROXY_DLL );
+ result = RegSetValueA(
+ HKEY_CLASSES_ROOT,
+ "CLSID\\{60000200-76d7-11cf-9af1-0020af6e72f4}\\InprocServer32",
+ REG_SZ,
+ directory,
+ strlen(directory) );
+ ASSERT( result, "Could not set interface name: 0x%x" );
+
+ // Open the registry key for the app id.
+ result = RegCreateKeyExA( HKEY_CLASSES_ROOT,
+ "AppID\\{60000200-76d7-11cf-9af1-0020af6e72f4}",
+ NULL,
+ NULL,
+ REG_OPTION_NON_VOLATILE,
+ KEY_READ | KEY_WRITE,
+ NULL,
+ &key,
+ &ignore );
+ ASSERT( result, "Could not create app id key: 0x%x" );
+
+ // Write the app id.
+ result = RegSetValueExA(
+ key,
+ NULL,
+ NULL,
+ REG_SZ,
+ (UCHAR *) REG_APPID_NAME,
+ strlen(REG_APPID_NAME) );
+ ASSERT( result, "Could not set app id name: 0x%x" );
+
+ // Make a simple security descriptor allowing everyone access.
+ i = GetLengthSid( ProcessSid );
+ sec = (SECURITY_DESCRIPTOR *) CoTaskMemAlloc( sizeof(SECURITY_DESCRIPTOR) +
+ i*2 );
+ ASSERT_EXPR( sec != NULL, "Could not allocate memory." );
+ sec->Revision = SECURITY_DESCRIPTOR_REVISION;
+ sec->Sbz1 = 0;
+ sec->Control = SE_SELF_RELATIVE;
+ sec->Owner = (SID *) sizeof(SECURITY_DESCRIPTOR);
+ sec->Group = (SID *) (sizeof(SECURITY_DESCRIPTOR) + i);
+ sec->Sacl = NULL;
+ sec->Dacl = NULL;
+ memcpy( sec+1, ProcessSid, i );
+ memcpy( ((char *) (sec+1)) + i, ProcessSid, i );
+
+ // Write the launch permissions.
+ result = RegSetValueExA(
+ key,
+ "LaunchPermission",
+ NULL,
+ REG_BINARY,
+ (UCHAR *) sec,
+ sizeof(SECURITY_DESCRIPTOR) + 2*i );
+ ASSERT( result, "Could not set launch permissions: 0x%x" );
+
+ // Write the access permissions.
+ result = RegSetValueExA(
+ key,
+ "AccessPermission",
+ NULL,
+ REG_BINARY,
+ (UCHAR *) sec,
+ sizeof(SECURITY_DESCRIPTOR) + 2*i );
+ ASSERT( result, "Could not set access permissions: 0x%x" );
+
+ // Write the value to run as logged on user.
+ result = RegSetValueExA(
+ key,
+ "RunAs",
+ NULL,
+ REG_SZ,
+ (unsigned char *) REG_LOGGED_ON,
+ strlen(REG_LOGGED_ON) );
+ ASSERT( result, "Could not set RunAs value: 0x%x" );
+ RegCloseKey( key );
+ key = NULL;
+
+ // Open the registry key for the module name.
+ result = RegCreateKeyExA( HKEY_CLASSES_ROOT,
+ "AppID\\app.exe",
+ NULL,
+ NULL,
+ REG_OPTION_NON_VOLATILE,
+ KEY_READ | KEY_WRITE,
+ NULL,
+ &key,
+ &ignore );
+ ASSERT( result, "Could not create module name key: 0x%x" );
+
+ // Write the app id under the module name.
+ result = RegSetValueExA(
+ key,
+ "AppID",
+ NULL,
+ REG_SZ,
+ (unsigned char *) REG_INTERFACE_CLASS,
+ strlen(REG_INTERFACE_CLASS) );
+ ASSERT( result, "Could not set appid value: 0x%x" );
+ RegCloseKey( key );
+ key = NULL;
+
+ // Compute the base application execution command.
+ strcpy( appname, REG_APP_EXE );
+ i = strlen( Debugger );
+ if (i != 0)
+ Debugger[i++] = ' ';
+ strcpy( &Debugger[i], directory );
+ i = strlen( Debugger );
+
+ // Allocate strings for the class id name keys.
+ class_id = (char *) _alloca( strlen(REG_CLASS_ID) + 1 );
+ if (class_id == NULL)
+ {
+ printf( "Could not _alloca string space.\n" );
+ return FALSE;
+ }
+ strcpy( class_id, REG_CLASS_ID );
+
+ // Write all the class ids.
+ for (j = 0; j < NUM_CLASS_IDS; j++)
+ {
+ // Adjust the id in the class strings.
+ class_id[14] = '0'+j;
+
+ // Open the registry key for the app id.
+ result = RegCreateKeyExA( HKEY_CLASSES_ROOT,
+ class_id,
+ NULL,
+ NULL,
+ REG_OPTION_NON_VOLATILE,
+ KEY_READ | KEY_WRITE,
+ NULL,
+ &key,
+ &ignore );
+ ASSERT( result, "Could not create class id key: 0x%x" );
+
+ // Write the application class name for the apartment class.
+ result = RegSetValueExA(
+ key,
+ NULL,
+ NULL,
+ REG_SZ,
+ (UCHAR *) REG_APP_NAME[j],
+ strlen(REG_APP_NAME[j]) );
+ ASSERT( result, "Could not set interface name: 0x%x" );
+
+ // Write the application path.
+ strcpy( &Debugger[i], REG_APP_OPTIONS[j] );
+ result = RegSetValueA(
+ key,
+ "LocalServer32",
+ REG_SZ,
+ Debugger,
+ strlen(Debugger) );
+ ASSERT( result, "Could not set app exe: 0x%x" );
+
+ // Write the application id value.
+ result = RegSetValueExA(
+ key,
+ "AppID",
+ NULL,
+ REG_SZ,
+ (unsigned char *) REG_INTERFACE_CLASS,
+ strlen(REG_INTERFACE_CLASS) );
+ ASSERT( result, "Could not set appid value: 0x%x" );
+ RegCloseKey( key );
+ key = NULL;
+ }
+ }
+
+ return TRUE;
+
+cleanup:
+ if (key != NULL)
+ RegCloseKey( key );
+ return FALSE;
+}
+
+ /***************************************************************************/
+void reinitialize()
+{
+ HRESULT result;
+ SAptData *mine;
+
+ // Get the apartment specific data.
+ if (ThreadMode == COINIT_MULTITHREADED)
+ mine = &ProcessAptData;
+ else
+ mine = (SAptData *) TlsGetValue( TlsIndex );
+ mine->what_next = quit_wn;
+
+ // Revoke the class factory.
+ ClassFactory->AddRef();
+ result = CoRevokeClassObject(Registration);
+ if (!SUCCEEDED(result))
+ {
+ printf( "CoRevokeClassObject failed: %x\n", result );
+ return;
+ }
+
+ // Reinitialize.
+ CoUninitialize();
+ result = initialize(NULL,ThreadMode);
+ if (!SUCCEEDED(result))
+ {
+ printf( "Could not reinitialize server: 0x%x\n", result );
+ return;
+ }
+
+ // Register our class with OLE
+ result = CoRegisterClassObject(*ServerClsid, ClassFactory, CLSCTX_LOCAL_SERVER,
+ REGCLS_SINGLEUSE, &Registration);
+ if (!SUCCEEDED(result))
+ {
+ printf( "CoRegisterClassObject failed: %x\n", result );
+ return;
+ }
+
+ // Make the server loop think we've started over.
+ mine->what_next = setup_wn;
+ mine->object_count = 0;
+}
+
+ /***************************************************************************/
+void server_loop( )
+{
+ register SAptData *mine;
+
+ // Get the apartment specific data.
+ if (ThreadMode == COINIT_MULTITHREADED)
+ mine = &ProcessAptData;
+ else
+ mine = (SAptData *) TlsGetValue( TlsIndex );
+
+ // Do whatever we have to do till it is time to pay our taxes and die.
+ while ((mine->what_next == setup_wn || mine->object_count > 0) &&
+ mine->what_next != quit_wn)
+ switch (mine->what_next)
+ {
+
+ // Wait till a quit arrives.
+ case setup_wn:
+ case wait_wn:
+ wait_for_message();
+ break;
+
+ case callback_wn:
+ callback();
+ mine->what_next = wait_wn;
+ break;
+
+ case catch_wn:
+ __try
+ {
+ mine->what_next = wait_wn;
+ server_loop();
+ }
+ __except(EXCEPTION_EXECUTE_HANDLER)
+ {
+ printf( "Caught exception at top of thread 0x%x\n",
+ GetCurrentThreadId() );
+ mine->what_next = crippled_wn;
+ }
+ break;
+
+ case crippled_wn:
+ crippled();
+ break;
+
+ case interrupt_wn:
+ interrupt();
+ break;
+
+ case interrupt_marshal_wn:
+ interrupt_marshal();
+ break;
+
+ case reinitialize_wn:
+ reinitialize();
+ break;
+
+ case rest_and_die_wn:
+ Sleep(5000);
+ mine->what_next = quit_wn;
+ break;
+ }
+}
+
+
+ /***************************************************************************/
+void switch_test()
+{
+ switch (WhatTest)
+ {
+ case cancel_wt:
+ do_cancel();
+ break;
+
+ case crash_wt:
+ do_crash();
+ break;
+
+ case cstress_wt:
+ do_cstress();
+ break;
+
+ case hook_wt:
+ do_hook();
+ break;
+
+ case load_client_wt:
+ do_load_client();
+ break;
+
+ case load_server_wt:
+ do_load_server();
+ break;
+
+ case lots_wt:
+ do_lots();
+ break;
+
+ case mmarshal_wt:
+ do_mmarshal();
+ break;
+
+ case none_wt:
+ break;
+
+ case null_wt:
+ do_null();
+ break;
+
+ case one_wt:
+ do_one();
+ break;
+
+ case perf_wt:
+ do_perf();
+ break;
+
+ case perfremote_wt:
+ do_perfremote();
+ break;
+
+ case perfrpc_wt:
+ do_perfrpc();
+ break;
+
+ case perfsec_wt:
+ do_perfsec();
+ break;
+
+ case post_wt:
+ do_post();
+ break;
+
+ case reject_wt:
+ do_reject();
+ break;
+
+ case remote_client_wt:
+ do_remote_client();
+ break;
+
+ case remote_server_wt:
+ do_remote_server();
+ break;
+
+ case ring_wt:
+ do_ring();
+ break;
+
+ case rpc_wt:
+ do_rpc();
+ break;
+
+ case rundown_wt:
+ do_rundown();
+ break;
+
+ case securerefs_wt:
+ do_securerefs();
+ break;
+
+ case security_wt:
+ do_security();
+ break;
+
+ case send_wt:
+ do_send();
+ break;
+
+ case server_wt:
+ do_server();
+ break;
+
+ case sid_wt:
+ do_sid();
+ break;
+
+ case simple_rundown_wt:
+ do_simple_rundown();
+ break;
+
+ case thread_wt:
+ do_thread();
+ break;
+
+ case three_wt:
+ do_three();
+ break;
+
+ case two_wt:
+ do_two();
+ break;
+
+ case uninit_wt:
+ do_uninit();
+ break;
+
+ case unknown_wt:
+ do_unknown();
+ break;
+
+ default:
+ printf( "I don't know what to do - %d\n", WhatTest );
+ break;
+ }
+}
+
+ /***************************************************************************/
+DWORD _stdcall thread_helper( void *param )
+{
+ ITest *test = (ITest *) param;
+ HRESULT result;
+
+ // Call the server.
+ result = test->sleep( 2000 );
+
+ // Check the result for multithreaded mode.
+ if (ThreadMode == COINIT_MULTITHREADED)
+ {
+ if (result != S_OK)
+ {
+ printf( "Could not make multiple calls in multithreaded mode: 0x%x\n",
+ result );
+ Multicall_Test = FALSE;
+ }
+ }
+
+ // Check the result for single threaded mode.
+ else
+ {
+ if (SUCCEEDED(result))
+ {
+ Multicall_Test = FALSE;
+ printf( "Call succeeded on wrong thread in single threaded mode: 0x%x.\n",
+ result );
+ }
+#if NEVER
+ else if (DebugCoGetRpcFault() != RPC_E_ATTEMPTED_MULTITHREAD)
+ {
+ printf( "Multithread failure code was 0x%x not 0x%x\n",
+ DebugCoGetRpcFault(), RPC_E_ATTEMPTED_MULTITHREAD );
+ Multicall_Test = FALSE;
+ }
+#endif
+ }
+
+#define DO_DA 42
+ return DO_DA;
+}
+
+ /***************************************************************************/
+DWORD _stdcall status_helper( void *param )
+{
+ long num_calls;
+ long num_clients;
+ long total_clients;
+ DWORD last_time;
+ DWORD this_time;
+ DWORD rate;
+
+ // Wake up periodically and print statistics.
+ last_time = GetTickCount();
+ while (TRUE)
+ {
+ Sleep( STATUS_DELAY );
+ num_calls = InterlockedExchange( &GlobalCalls, 0 );
+ num_clients = GlobalClients;
+ total_clients = GlobalTotal;
+ this_time = GetTickCount();
+ if (num_calls != 0)
+ rate = (this_time - last_time)*1000/num_calls;
+ else
+ rate = 99999999;
+ printf( "Time: %d Calls: %d Clients: %d Total Clients: %d uSec/Call: %d\n",
+ this_time - last_time, num_calls, num_clients, total_clients,
+ rate );
+ last_time = this_time;
+ }
+ return 0;
+}
+
+ /***************************************************************************/
+HRESULT switch_thread( SIMPLE_FN fn, void *param )
+{
+ MSG msg;
+
+ if (ThreadMode == COINIT_MULTITHREADED)
+ {
+ fn( param );
+ return S_OK;
+ }
+ else
+ {
+ if (PostThreadMessage( GlobalThreadId, WM_USER+1, (unsigned int) fn,
+ (long) param ))
+ {
+ GetMessage( &msg, NULL, 0, 0 );
+ return S_OK;
+ }
+ else
+ return E_FAIL;
+ }
+}
+
+ /***************************************************************************/
+void thread_get_interface_buffer( void *p )
+{
+ SGetInterface *getif = (SGetInterface *) p;
+ HANDLE memory = NULL;
+ IStream *stream = NULL;
+ LARGE_INTEGER pos;
+ DWORD size;
+ void *objref;
+ WCHAR name[MAX_COMPUTERNAME_LENGTH+1];
+ DWORD name_size = sizeof(name)/sizeof(WCHAR);
+
+ // Find out how much memory to allocate.
+ getif->status = RPC_S_OUT_OF_RESOURCES;
+ getif->status = CoGetMarshalSizeMax( (unsigned long *) getif->buf_size,
+ IID_ITest, GlobalTest,
+ MSHCTX_DIFFERENTMACHINE,
+ NULL,
+ MSHLFLAGS_NORMAL );
+ ASSERT( getif->status, "Could not marshal server object" );
+
+ // Add the size of the long form extension.
+ ASSERT_EXPR( GetComputerName( name, &name_size ), "Could not get computer name." );
+ *getif->buf_size += 20 + 2*name_size*sizeof(WCHAR);
+
+ // Allocate memory.
+ memory = GlobalAlloc( GMEM_FIXED, *getif->buf_size );
+ ASSERT_EXPR( memory != NULL, "Could not allocate memory." );
+
+ // Create a stream.
+ getif->status = CreateStreamOnHGlobal( memory, TRUE, &stream );
+ ASSERT( getif->status, "Could not create stream" );
+
+ // Marshal the object.
+ getif->status = CoMarshalInterface( stream, IID_ITest, GlobalTest,
+ MSHCTX_DIFFERENTMACHINE,
+ NULL,
+ MSHLFLAGS_NORMAL );
+ ASSERT( getif->status, "Could not marshal object" );
+
+ // Find the object reference in the stream.
+ objref = (void *) GlobalLock( memory );
+
+ // Allocate a buffer for MIDL.
+ *getif->buffer = (unsigned char *) midl_user_allocate( *getif->buf_size );
+ ASSERT_EXPR( *getif->buffer != NULL, "Could not allocate MIDL memory." );
+
+ // Copy the stream to the buffer.
+ memcpy( *getif->buffer, objref, *getif->buf_size );
+ GlobalUnlock( memory );
+
+ // Make sure that the original reference to the object gets released once.
+ if (InterlockedExchange( &GlobalFirst, FALSE ) == TRUE)
+ GlobalTest->Release();
+
+ // Return the buffer.
+ getif->status = RPC_S_OK;
+cleanup:
+ if (stream != NULL)
+ stream->Release();
+ PostThreadMessage( getif->thread, WM_USER, 0, 0 );
+}
+
+ /***************************************************************************/
+void __RPC_USER transmit_crash_to_xmit( transmit_crash __RPC_FAR *c, DWORD __RPC_FAR * __RPC_FAR *x )
+{
+
+ *x = (DWORD *) CoTaskMemAlloc( 4 );
+ **x = 1 / *c;
+ *c -= 1;
+}
+
+ /***************************************************************************/
+void __RPC_USER transmit_crash_from_xmit( DWORD __RPC_FAR *x, transmit_crash __RPC_FAR *c )
+{
+ *c = *x;
+}
+
+ /***************************************************************************/
+void __RPC_USER transmit_crash_free_inst( transmit_crash __RPC_FAR *x )
+{
+}
+
+ /***************************************************************************/
+void __RPC_USER transmit_crash_free_xmit( DWORD __RPC_FAR *x )
+{
+ CoTaskMemFree( x );
+}
+
+ /***************************************************************************/
+void wait_for_message()
+{
+ MSG msg;
+ DWORD status;
+
+ if (ThreadMode == COINIT_MULTITHREADED)
+ {
+ status = WaitForSingleObject( Done, INFINITE );
+ if (status != WAIT_OBJECT_0 )
+ {
+ printf( "Could not wait for event.\n" );
+ }
+ }
+ else
+ {
+ if (GetMessageA( &msg, NULL, 0, 0 ))
+ {
+ if (msg.hwnd == NULL && msg.message == WM_USER+1)
+ ((SIMPLE_FN) msg.wParam)( (void *) msg.lParam );
+ else
+ {
+ TranslateMessage (&msg);
+ DispatchMessageA (&msg);
+ }
+ }
+ }
+}
+
+ /***************************************************************************/
+void wake_up_and_smell_the_roses()
+{
+ if (ThreadMode == COINIT_MULTITHREADED)
+ SetEvent( Done );
+}
+
+ /***************************************************************************/
+void what_next( what_next_en what )
+{
+ if (ThreadMode == COINIT_MULTITHREADED)
+ {
+ ProcessAptData.what_next = what;
+ }
+ else
+ {
+ SAptData *tls_data = (SAptData *) TlsGetValue( TlsIndex );
+ tls_data->what_next = what;
+ }
+}
+
+ /***************************************************************************/
+unsigned long xacl_call( handle_t binding )
+{
+ RPC_STATUS status;
+ RPC_STATUS status2;
+ BOOL success;
+ DWORD granted_access;
+ BOOL access;
+ BOOL ignore;
+ HANDLE token;
+ PRIVILEGE_SET privilege;
+ DWORD privilege_size = sizeof(privilege);
+ GENERIC_MAPPING gmap;
+ LARGE_INTEGER start;
+ LARGE_INTEGER impersonate;
+ LARGE_INTEGER open;
+ LARGE_INTEGER accesscheck;
+ LARGE_INTEGER close;
+ LARGE_INTEGER revert;
+ LARGE_INTEGER freq;
+
+#if 0
+ QueryPerformanceCounter( &start );
+#endif
+ status = RpcImpersonateClient( binding );
+#if 0
+ QueryPerformanceCounter( &impersonate );
+#endif
+ if (status == RPC_S_OK)
+ {
+ // Get the thread token.
+ success = OpenThreadToken( GetCurrentThread(), TOKEN_READ,
+ TRUE, &token );
+#if 0
+ QueryPerformanceCounter( &open );
+#endif
+ if (!success)
+ {
+ printf( "Could not OpenThreadToken.\n" );
+ status = E_FAIL;
+ }
+
+ // Check access.
+ else
+ {
+ gmap.GenericRead = READ_CONTROL;
+ gmap.GenericWrite = READ_CONTROL;
+ gmap.GenericExecute = READ_CONTROL;
+ gmap.GenericAll = READ_CONTROL;
+ privilege.PrivilegeCount = 1;
+ privilege.Control = 0;
+ success = AccessCheck( GlobalSecurityDescriptor, token, READ_CONTROL,
+ &gmap, &privilege, &privilege_size,
+ &granted_access, &access );
+#if 0
+ QueryPerformanceCounter( &accesscheck );
+#endif
+
+ if (!success)
+ {
+ printf( "Bad parameters to AccessCheck: 0x%x.\n",
+ GetLastError() );
+ status = E_FAIL;
+ }
+ else if (!access)
+ {
+ printf( "Could not get access.\n" );
+ status = ERROR_ACCESS_DENIED;
+ }
+ CloseHandle( token );
+#if 0
+ QueryPerformanceCounter( &close );
+#endif
+ }
+ status2 = RpcRevertToSelf();
+#if 0
+ QueryPerformanceCounter( &revert );
+ QueryPerformanceFrequency( &freq );
+ start.QuadPart = 1000000 * (impersonate.QuadPart - start.QuadPart) / freq.QuadPart;
+ printf( "RpcImpersonateClient took %duS\n", start.u.LowPart );
+ impersonate.QuadPart = 1000000 * (open.QuadPart - impersonate.QuadPart) / freq.QuadPart;
+ printf( "OpenThreadToken took %duS\n", impersonate.u.LowPart );
+ open.QuadPart = 1000000 * (accesscheck.QuadPart - open.QuadPart) / freq.QuadPart;
+ printf( "AccessCheckAndAuditAlarm took %duS\n", open.u.LowPart );
+ accesscheck.QuadPart = 1000000 * (close.QuadPart - accesscheck.QuadPart) / freq.QuadPart;
+ printf( "CloseHandle took %duS\n", accesscheck.u.LowPart );
+ close.QuadPart = 1000000 * (revert.QuadPart - close.QuadPart) / freq.QuadPart;
+ printf( "RpcRevertToSelf took %duS\n", close.u.LowPart );
+#endif
+ if (status2 != RPC_S_OK)
+ status = status2;
+ }
+
+ return status;
+}
+
+ /***************************************************************************/
+unsigned long xaudit_call( handle_t binding )
+{
+ RPC_STATUS status;
+ RPC_STATUS status2;
+ BOOL success;
+ DWORD granted_access;
+ BOOL access;
+ BOOL ignore;
+ HANDLE token;
+ GENERIC_MAPPING gmap;
+ LARGE_INTEGER start;
+ LARGE_INTEGER impersonate;
+ LARGE_INTEGER accesscheck;
+ LARGE_INTEGER revert;
+ LARGE_INTEGER freq;
+
+#if 0
+ QueryPerformanceCounter( &start );
+#endif
+ status = RpcImpersonateClient( binding );
+#if 0
+ QueryPerformanceCounter( &impersonate );
+#endif
+ if (status == RPC_S_OK)
+ {
+ // Check access and do audits.
+ gmap.GenericRead = READ_CONTROL;
+ gmap.GenericWrite = READ_CONTROL;
+ gmap.GenericExecute = READ_CONTROL;
+ gmap.GenericAll = READ_CONTROL;
+ success = AccessCheckAndAuditAlarm( L"Test",
+ NULL,
+ L"Test Type Name",
+ L"Test Name",
+ GlobalSecurityDescriptor,
+ READ_CONTROL,
+ &gmap,
+ FALSE,
+ &granted_access,
+ &access,
+ &ignore );
+#if 0
+ QueryPerformanceCounter( &accesscheck );
+#endif
+ if (!success)
+ {
+ printf( "Bad parameters to AccessCheckAndAuditAlarm: 0x%x.\n",
+ GetLastError() );
+ status = E_FAIL;
+ }
+ else if (!access)
+ {
+ printf( "Could not get access.\n" );
+ status = E_FAIL;
+ }
+ status2 = RpcRevertToSelf();
+#if 0
+ QueryPerformanceCounter( &revert );
+ QueryPerformanceFrequency( &freq );
+ start.QuadPart = 1000000 * (impersonate.QuadPart - start.QuadPart) / freq.QuadPart;
+ printf( "RpcImpersonateClient took %duS\n", start.u.LowPart );
+ impersonate.QuadPart = 1000000 * (accesscheck.QuadPart - impersonate.QuadPart) / freq.QuadPart;
+ printf( "AccessCheckAndAuditAlarm took %duS\n", impersonate.u.LowPart );
+ accesscheck.QuadPart = 1000000 * (revert.QuadPart - accesscheck.QuadPart) / freq.QuadPart;
+ printf( "RpcRevertToSelf took %duS\n", accesscheck.u.LowPart );
+#endif
+ if (status2 != RPC_S_OK)
+ status = status2;
+ }
+
+ return status;
+}
+
+ /***************************************************************************/
+unsigned long xcheck_client( handle_t binding, error_status_t *error_status )
+{
+ HANDLE client_token = NULL;
+ HANDLE server_token = NULL;
+ TOKEN_USER *client_sid;
+ TOKEN_USER *server_sid;
+ DWORD count;
+ char buffer1[100];
+ char buffer2[100];
+ HRESULT result = S_OK;
+ RPC_STATUS status;
+ HANDLE process = NULL;
+
+ // Get this process's security token.
+ *error_status = RPC_S_OK;
+ if (!OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY, &server_token ))
+ {
+ printf( "Could not GetProcessToken: 0x%x\n", GetLastError() );
+ result = E_FAIL;
+ goto cleanup;
+ }
+
+ // Get the token's user id.
+ if (!GetTokenInformation( server_token, TokenUser, &buffer1, sizeof(buffer1),
+ &count ))
+ {
+ printf( "Could not GetTokenInformation: 0x%x\n", GetLastError() );
+ result = E_FAIL;
+ goto cleanup;
+ }
+ server_sid = (TOKEN_USER *) &buffer1;
+
+ // Impersonate the client.
+ status = RpcImpersonateClient( binding );
+ if (status != RPC_S_OK)
+ {
+ printf( "Could not impersonate client: 0x%x\n", status );
+ result = MAKE_WIN32( status );
+ goto cleanup;
+ }
+
+ // Get the clients security token.
+ if (!OpenThreadToken( GetCurrentThread(), TOKEN_QUERY, FALSE, &client_token ))
+ {
+ printf( "Could not GetProcessToken: 0x%x\n", GetLastError() );
+ result = E_FAIL;
+ goto cleanup;
+ }
+
+ // Get the token's user id.
+ if (!GetTokenInformation( client_token, TokenUser, &buffer2, sizeof(buffer2),
+ &count ))
+ {
+ printf( "Could not GetTokenInformation: 0x%x\n", GetLastError() );
+ result = E_FAIL;
+ goto cleanup;
+ }
+ client_sid = (TOKEN_USER *) &buffer2;
+
+ // Compare the client and server.
+ if (!EqualSid( server_sid->User.Sid, client_sid->User.Sid))
+ {
+ printf( "Client and server have different SIDs.\n" );
+ result = E_FAIL;
+ goto cleanup;
+ }
+
+ // Try to open this process while impersonating the client.
+ process = OpenProcess( PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId() );
+ if (process == NULL)
+ {
+ printf( "Could not open process.\n" );
+ result = E_FAIL;
+ goto cleanup;
+ }
+
+ // Undo the impersonation.
+ status = RpcRevertToSelf();
+ if (status != RPC_S_OK)
+ {
+ printf( "Could not revert to self: 0x%x\n", status );
+ result = MAKE_WIN32( status );
+ goto cleanup;
+ }
+
+cleanup:
+ if (client_token != NULL)
+ CloseHandle( client_token );
+ if (server_token != NULL)
+ CloseHandle( server_token );
+ if (process != NULL)
+ CloseHandle( process );
+ return result;
+}
+
+ /***************************************************************************/
+void xget_interface_buffer( handle_t binding, long *buf_size,
+ unsigned char **buffer, SAptId *id,
+ error_status_t *status )
+{
+ SGetInterface get_interface;
+
+ *buffer = NULL;
+ get_interface.buf_size = buf_size;
+ get_interface.buffer = buffer;
+ get_interface.thread = GetCurrentThreadId();
+ *status = switch_thread( thread_get_interface_buffer, (void *) &get_interface );
+ if (*status == RPC_S_OK)
+ *status = get_interface.status;
+ InterlockedIncrement( &GlobalClients );
+ InterlockedIncrement( &GlobalTotal );
+}
+
+ /***************************************************************************/
+unsigned long ximpersonate_call( handle_t binding )
+{
+ RPC_STATUS status;
+
+ status = RpcImpersonateClient( binding );
+ if (status == RPC_S_OK)
+ status = RpcRevertToSelf();
+
+ return status;
+}
+
+ /***************************************************************************/
+void xnullcall( handle_t binding )
+{
+}
+
+ /***************************************************************************/
+void xrelease_interface( handle_t binding, error_status_t *status )
+{
+ *status = RPC_S_OK;
+ InterlockedDecrement( &GlobalClients );
+}
+
+ /***************************************************************************/
+void xset_status( handle_t binding, HRESULT result, error_status_t *status )
+{
+ RawResult = result;
+ *status = RPC_S_OK;
+ SetEvent( RawEvent );
+}
+
+ /***************************************************************************/
+unsigned long xtest( handle_t binding, ITest *obj, SAptId id,
+ error_status_t *status )
+{
+ *status = RPC_S_OK;
+ return obj->check( id );
+}
+
+ /***************************************************************************/
+unsigned long xtransitive( handle_t handle, wchar_t *binding )
+{
+ return 0;
+}
+
+
+
diff --git a/private/oleutest/channel/app/app_i.c b/private/oleutest/channel/app/app_i.c
new file mode 100644
index 000000000..06ffc5e19
--- /dev/null
+++ b/private/oleutest/channel/app/app_i.c
@@ -0,0 +1,28 @@
+#pragma warning(disable:4101) // Ignore variable not use warning
+
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: iperf_i.c
+//
+// Contents: IID_IPerf
+//
+// History: Created by Microsoft (R) MIDL Compiler Version 1.10.83
+//
+//--------------------------------------------------------------------------
+typedef struct _IID
+{
+ unsigned long x;
+ unsigned short s1;
+ unsigned short s2;
+ unsigned char c[8];
+} IID;
+
+
+const IID CLSID_ITest =
+{0x60000430, 0xAB0F, 0x101A, {0xB4, 0xAE, 0x08, 0x00, 0x2B, 0x30, 0x61, 0x2C}};
+
+const IID CLSID_ITestMulti =
+{0x25724a70, 0x283f, 0x11ce, {0x95, 0x31, 0x08, 0x00, 0x2b, 0x2a, 0xb6, 0x12}};
diff --git a/private/oleutest/channel/app/makefile b/private/oleutest/channel/app/makefile
new file mode 100644
index 000000000..8991c0d2e
--- /dev/null
+++ b/private/oleutest/channel/app/makefile
@@ -0,0 +1,20 @@
+############################################################################
+#
+# Copyright (C) 1992, Microsoft Corporation.
+#
+# All rights reserved.
+#
+############################################################################
+
+!ifdef NTMAKEENV
+
+!include $(NTMAKEENV)\makefile.def
+
+!else # NTMAKEENV
+
+default: all
+
+!include $(CAIROLE)\com\makefile
+!include $(DEPENDFILE)
+
+!endif # NTMAKEENV
diff --git a/private/oleutest/channel/app/prxydll.def b/private/oleutest/channel/app/prxydll.def
new file mode 100644
index 000000000..f812a2719
--- /dev/null
+++ b/private/oleutest/channel/app/prxydll.def
@@ -0,0 +1,7 @@
+DESCRIPTION 'Microsoft (R) OLE 2.0 Proxy/Stub DLL 1.00'
+
+EXPORTS
+
+ DllGetClassObject @1
+ DllCanUnloadNow @2
+
diff --git a/private/oleutest/channel/app/sources b/private/oleutest/channel/app/sources
new file mode 100644
index 000000000..02bc2d3bb
--- /dev/null
+++ b/private/oleutest/channel/app/sources
@@ -0,0 +1,70 @@
+
+MAJORCOMP = cairole
+MINORCOMP = com
+
+#
+# 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= app
+
+#
+# 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
+
+#DLLDEF= ..\proxy\prxydll.def
+LINKER_FLAGS=-DEF:prxydll.def
+
+INCLUDES= ..\idl;$(BASEDIR)\private\dcomidl\daytona;$(BASEDIR)\private\dcomidl\obj
+
+C_DEFINES= \
+ $(C_DEFINES) \
+ -DFLAT \
+ -DWIN32=100 \
+ -D_NT1X_=100 \
+ -DUNICODE \
+ -D_UNICODE \
+ -DNOEXCEPTIONS \
+ -DCAIROLE_DOWNLEVEL
+
+BLDCRT= 1
+
+SOURCES= \
+ app.cxx \
+ dog_c.c \
+ dog_s.c \
+ itest_p.c \
+ itest_i.c \
+ dlldata.c
+
+
+UMTYPE= console
+UMENTRY=
+UMAPPL=
+UMTEST=
+UMLIBS= \
+ $(BASEDIR)\public\sdk\lib\*\uuid.lib \
+ $(BASEDIR)\public\sdk\lib\*\ole32.lib \
+ $(BASEDIR)\public\sdk\lib\*\rpcndr.lib \
+ $(BASEDIR)\public\sdk\lib\*\rpcrt4.lib \
+ $(BASEDIR)\public\sdk\lib\*\rpcns4.lib \
+ $(BASEDIR)\public\sdk\lib\*\mpr.lib \
+ $(BASEDIR)\public\sdk\lib\*\netapi32.lib \
+ $(BASEDIR)\public\sdk\lib\*\kernel32.lib \
+ $(BASEDIR)\public\sdk\lib\*\user32.lib \
+ $(BASEDIR)\public\sdk\lib\*\advapi32.lib \
+ $(BASEDIR)\public\sdk\lib\*\libcmt.lib \
+ $(BASEDIR)\public\sdk\lib\*\security.lib
+
diff --git a/private/oleutest/channel/dirs b/private/oleutest/channel/dirs
new file mode 100644
index 000000000..cda324fa1
--- /dev/null
+++ b/private/oleutest/channel/dirs
@@ -0,0 +1,38 @@
+!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:
+
+ Dean Edwards (DeanE) 11-Jan-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= \
+ idl \
+ app
+
+#
+# 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=
+
diff --git a/private/oleutest/channel/idl/dog.acf b/private/oleutest/channel/idl/dog.acf
new file mode 100644
index 000000000..8c67cfe4c
--- /dev/null
+++ b/private/oleutest/channel/idl/dog.acf
@@ -0,0 +1,9 @@
+interface IDog
+
+{
+ check_client ( [comm_status, fault_status] status );
+ get_interface_buffer ( [comm_status, fault_status] status );
+ release_interface ( [comm_status, fault_status] status );
+ set_status ( [comm_status, fault_status] status );
+ test ( [comm_status, fault_status] status );
+}
diff --git a/private/oleutest/channel/idl/dog.idl b/private/oleutest/channel/idl/dog.idl
new file mode 100644
index 000000000..97d6e3d0c
--- /dev/null
+++ b/private/oleutest/channel/idl/dog.idl
@@ -0,0 +1,45 @@
+//+-------------------------------------------------------------------
+//
+// Interface: IDog
+//
+// Purpose: Interface for manipulating performance
+//
+// History: 8 Nov 94 AlexMit Created
+//
+// Notes:
+//
+//--------------------------------------------------------------------
+
+import "itest.idl";
+
+[ uuid(e0b4ab10-fb6d-11cd-b3ae-00aa003c9fdc),
+ version(0.1),
+ pointer_default(unique) ]
+
+interface IDog
+{
+ unsigned long acl_call ( [in] handle_t handle );
+ unsigned long audit_call ( [in] handle_t handle );
+ unsigned long check_client ( [in] handle_t handle,
+ [out] error_status_t *status );
+ void get_interface_buffer ( [in] handle_t handle,
+ [out] long *size,
+ [out, size_is(,*size)] char **buffer,
+ [out] SAptId *id,
+ [out] error_status_t *status );
+ unsigned long impersonate_call ( [in] handle_t handle );
+ void nullcall ( [in] handle_t handle );
+ void release_interface ( [in] handle_t handle,
+ [out] error_status_t *status );
+ void set_status ( [in] handle_t handle,
+ [in] long result,
+ [out] error_status_t *status );
+ unsigned long test ( [in] handle_t handle,
+ [in] ITest *obj,
+ [in] SAptId id,
+ [out] error_status_t *status );
+ unsigned long transitive ( [in] handle_t handle,
+ [in, string] wchar_t *binding );
+}
+
+
diff --git a/private/oleutest/channel/idl/itest.acf b/private/oleutest/channel/idl/itest.acf
new file mode 100644
index 000000000..d11570c04
--- /dev/null
+++ b/private/oleutest/channel/idl/itest.acf
@@ -0,0 +1,4 @@
+interface ITest
+{
+ typedef [allocate(dont_free)] STRING;
+}
diff --git a/private/oleutest/channel/idl/itest.idl b/private/oleutest/channel/idl/itest.idl
new file mode 100644
index 000000000..7f2437650
--- /dev/null
+++ b/private/oleutest/channel/idl/itest.idl
@@ -0,0 +1,192 @@
+//[ ITest_itf
+//+-------------------------------------------------------------------
+//
+// Interface: ITest (ib)
+//
+// Purpose: Interface for manipulating performance
+//
+// History: 5-Oct-93 AlexMit Created
+//
+// Notes:
+//
+//--------------------------------------------------------------------
+
+[
+ object,
+ uuid(60000200-76d7-11cf-9af1-0020af6e72f4),
+ pointer_default(unique)
+]
+
+interface ITest : IUnknown
+{
+ import "unknwn.idl";
+ import "objidl.idl";
+
+ typedef struct
+ {
+ DWORD process;
+ DWORD thread;
+ DWORD sequence;
+ } SAptId;
+
+ typedef struct
+ {
+ UCHAR Value[6];
+ } HACKHACKHACK_SID_IDENTIFIER_AUTHORITY;
+
+ typedef struct
+ {
+ UCHAR Revision;
+ UCHAR SubAuthorityCount;
+ HACKHACKHACK_SID_IDENTIFIER_AUTHORITY IdentifierAuthority;
+#ifdef MIDL_PASS
+ [size_is(SubAuthorityCount)] ULONG SubAuthority[*];
+#else // MIDL_PASS
+ ULONG SubAuthority[ANYSIZE_ARRAY];
+#endif // MIDL_PASS
+ } HACKSID;
+
+ typedef [string] wchar_t *STRING;
+
+ typedef [transmit_as(DWORD)] DWORD transmit_crash;
+
+ HRESULT align ( [in] unsigned char x[17] );
+ HRESULT call_canceled ( [in] long recurse, [in] long cancel,
+ [in] ITest *callback );
+ HRESULT call_dead ();
+ HRESULT call_me_back ( [in] ITest *callback );
+ HRESULT call_next ();
+ HRESULT callback ();
+ HRESULT cancel ();
+ HRESULT cancel_now ();
+ HRESULT cancel_pending_call ( [out] DWORD *thread );
+ HRESULT cancel_stress ( [in] ITest *obj );
+ HRESULT catch_at_top ( [in] BOOL catch_me_im_falling,
+ [in] ITest *callback,
+ [in] STRING binding );
+ HRESULT check ( [in] SAptId id );
+ HRESULT check_hook ( [in] DWORD cg1, [in] DWORD cn1,
+ [in] DWORD sg1, [in] DWORD sn1,
+ [in] DWORD cg2, [in] DWORD cn2,
+ [in] DWORD sg2, [in] DWORD sn2 );
+ HRESULT count ();
+ HRESULT crash_out ( [out] transmit_crash *data );
+ HRESULT delegate ( [in] ITest *obj, [in] SAptId id,
+ [in] HACKSID *caller );
+ HRESULT exit ();
+ HRESULT forget ();
+ HRESULT get_advise ( [out] IAdviseSink **advise );
+ HRESULT get_data ( [in] DWORD isize,
+ [in, unique, size_is(isize)] char *idata,
+ [in] DWORD osize,
+ [out, size_is(,osize)] char **odata );
+ HRESULT get_id ( [out] SAptId *id );
+ HRESULT get_next ( [out] ITest **obj, [out] SAptId *id );
+ HRESULT get_next_slowly ( [out] ITest **obj, [out] SAptId *id );
+ HRESULT get_obj_from_new_apt ( [out] ITest **obj, [out] SAptId *id );
+ HRESULT get_obj_from_this_apt ( [out] ITest **obj, [out] SAptId *id );
+ HRESULT get_sid ( [out] HACKSID **sid );
+ HRESULT interface_in ( [in] ITest *obj );
+ HRESULT interrupt ( [in] ITest *obj, [in] SAptId id, BOOL go );
+ HRESULT interrupt_marshal ( [in] ITest *obj1, [in] ITest *obj2 );
+ HRESULT make_acl ( [in] HACKSID *allow );
+ HRESULT null ();
+ HRESULT out ( [out] ITest **obj );
+ HRESULT pointer ( [in] DWORD *ptr );
+ HRESULT recurse ( [in] ITest *callback, [in] ULONG depth );
+ HRESULT recurse_disconnect ( [in] ITest *callback, [in] ULONG depth );
+ HRESULT recurse_excp ( [in] ITest *callback, [in] ULONG depth );
+ HRESULT recurse_fatal ( [in] ITest *callback,
+ [in] ULONG catch_depth,
+ [in] ULONG throw_depth,
+ [in] BOOL cancel );
+ HRESULT register_hook ( [in] GUID ext, [in] DWORD seq );
+ HRESULT recurse_interrupt ( [in] ITest *callback, [in] ULONG depth );
+ HRESULT recurse_secure ( [in] ITest *callback, [in] ULONG depth,
+ [in] ULONG imp_depth, [in] HACKSID *Caller );
+ HRESULT register_message_filter( BOOL );
+ HRESULT register_rpc ( [in] STRING protseq, [out] STRING *binding );
+ HRESULT reinitialize ();
+ HRESULT reject_next ();
+ HRESULT remember ( [in] ITest *neighbor, [in] SAptId id );
+ HRESULT rest_and_die ();
+ HRESULT retry_next ();
+ HRESULT ring ( [in] DWORD length );
+ HRESULT secure ( [in] SAptId id,
+ [in] DWORD AuthnLevel, [in] DWORD ImpLevel,
+ [in] DWORD AuthnSvc, [in] DWORD AuthzSvc,
+ [in, unique] STRING PrincName,
+ [in] HACKSID *Caller,
+ [out] DWORD *QueryAuthnLevel );
+ HRESULT security_performance ( [out] DWORD *get_call,
+ [out] DWORD *query_client,
+ [out] DWORD *impersonate,
+ [out] DWORD *revert );
+ HRESULT set_state ( [in] DWORD flags, [in] DWORD priority );
+ HRESULT sick ( [in] ULONG throw_val );
+ HRESULT sleep ( [in] ULONG time );
+ HRESULT test ( [in] ULONG gronk );
+
+}
+
+[
+ object,
+ uuid(60000201-76d7-11cf-9af1-0020af6e72f4),
+ pointer_default(unique)
+]
+interface ITestNoneImp : ITest
+{
+ HRESULT dummy();
+}
+
+[
+ object,
+ uuid(60000202-76d7-11cf-9af1-0020af6e72f4),
+ pointer_default(unique)
+]
+interface ITestConnectImp : ITest
+{
+ HRESULT dummy();
+}
+
+[
+ object,
+ uuid(60000203-76d7-11cf-9af1-0020af6e72f4),
+ pointer_default(unique)
+]
+interface ITestEncryptImp : ITest
+{
+ HRESULT dummy();
+}
+
+[
+ object,
+ uuid(60000204-76d7-11cf-9af1-0020af6e72f4),
+ pointer_default(unique)
+]
+interface ITestNoneId : ITest
+{
+ HRESULT dummy();
+}
+
+[
+ object,
+ uuid(60000205-76d7-11cf-9af1-0020af6e72f4),
+ pointer_default(unique)
+]
+interface ITestConnectId : ITest
+{
+ HRESULT dummy();
+}
+
+[
+ object,
+ uuid(60000206-76d7-11cf-9af1-0020af6e72f4),
+ pointer_default(unique)
+]
+interface ITestEncryptId : ITest
+{
+ HRESULT dummy();
+}
+
+//]
diff --git a/private/oleutest/channel/idl/makefile b/private/oleutest/channel/idl/makefile
new file mode 100644
index 000000000..510cce95d
--- /dev/null
+++ b/private/oleutest/channel/idl/makefile
@@ -0,0 +1,9 @@
+############################################################################
+#
+# Copyright (C) 1992, Microsoft Corporation.
+#
+# All rights reserved.
+#
+############################################################################
+
+!include $(NTMAKEENV)\makefile.def
diff --git a/private/oleutest/channel/idl/makefile.inc b/private/oleutest/channel/idl/makefile.inc
new file mode 100644
index 000000000..d74e26319
--- /dev/null
+++ b/private/oleutest/channel/idl/makefile.inc
@@ -0,0 +1,37 @@
+itest.h: itest.idl
+ midl itest.idl \
+ -Zp8 \
+ -I$(INCLUDES:;= -I) \
+ -ms_ext \
+ -c_ext \
+ -Os \
+ -out ..\app \
+ -header ..\idl\itest.h \
+ -iid ..\app\itest_i.c \
+ $(C_DEFINES) \
+ -DMIDL_PASS
+
+dog.h: dog.idl
+ midl dog.idl \
+ -Zp8 \
+ -I$(INCLUDES:;= -I) \
+ -ms_ext \
+ -c_ext \
+ -Os \
+ -out ..\app \
+ -header ..\idl\dog.h \
+ -iid ..\app\dog_i.c \
+ -prefix server x \
+ $(C_DEFINES) \
+ -DMIDL_PASS
+
+#
+# This target compiles all .idl files into their corresponding _?.c?? and
+# .h components
+#
+allidl: itest.h dog.h
+
+clean:
+ erase itest.h >NUL 2>NUL
+ erase dog.h >NUL 2>NUL
+
diff --git a/private/oleutest/channel/idl/pch.cxx b/private/oleutest/channel/idl/pch.cxx
new file mode 100644
index 000000000..984d8d2bf
--- /dev/null
+++ b/private/oleutest/channel/idl/pch.cxx
@@ -0,0 +1,18 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1991 - 1992.
+//
+// File: PCH.CXX
+//
+// Contents: Precompiled header
+//
+// History: 12-Jul-93 ShannonC Created
+//
+//--------------------------------------------------------------------------
+
+#include "stdrpc.hxx"
+#pragma hdrstop
+
+
+
diff --git a/private/oleutest/channel/idl/prxydll.def b/private/oleutest/channel/idl/prxydll.def
new file mode 100644
index 000000000..e09e1ce91
--- /dev/null
+++ b/private/oleutest/channel/idl/prxydll.def
@@ -0,0 +1,47 @@
+#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 ITEST
+
+DESCRIPTION 'Microsoft (R) OLE 2.0 Proxy/Stub DLL 1.00'
+
+EXPORTS
+
+#if defined(i386)
+
+ DllGetClassObject=DllGetClassObject@12 @1
+ DllCanUnloadNow=DllCanUnloadNow@0 @2
+
+#elif defined(_MIPS_)
+
+ DllGetClassObject @1
+ DllCanUnloadNow @2
+
+#endif // i386 - MIPS
+
+#endif // FLAT
diff --git a/private/oleutest/channel/idl/sources b/private/oleutest/channel/idl/sources
new file mode 100644
index 000000000..0112b8e8d
--- /dev/null
+++ b/private/oleutest/channel/idl/sources
@@ -0,0 +1,66 @@
+!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:
+
+ Dean Edwards (DeanE) 11-Jan-1993
+
+!ENDIF
+
+MAJORCOMP = comutest
+MINORCOMP = channel
+
+#
+# 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= idl
+
+#
+# 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= LIBRARY
+
+INCLUDES= $(BASEDIR)\public\sdk\inc
+
+C_DEFINES= $(C_DEFINES)
+
+BLDCRT= 1
+
+SOURCES=
+
+UMTYPE= windows
+UMAPPL=
+UMTEST=
+UMLIBS=
+
+USE_LIBCMT=
+
+NTTARGETFILE0= allidl
+
+PRECOMPILED_INCLUDE=
+
diff --git a/private/oleutest/channel/idl/test.reg b/private/oleutest/channel/idl/test.reg
new file mode 100644
index 000000000..40112de96
--- /dev/null
+++ b/private/oleutest/channel/idl/test.reg
@@ -0,0 +1,24 @@
+
+; registry entries for ITest interface. these map the interfaces
+; to the proxy/stub code in itest.dll
+
+
+\Registry\MACHINE\SOFTWARE\Classes\Interface\{60000494-AB0F-101A-B4AE-08002B30612C}
+ = ITest
+\Registry\MACHINE\SOFTWARE\Classes\Interface\{60000494-AB0F-101A-B4AE-08002B30612C}\ProxyStubClsid32
+ = {60000494-AB0F-101A-B4AE-08002B30612C}
+
+\Registry\MACHINE\SOFTWARE\Classes\CLSID\{60000494-AB0F-101A-B4AE-08002B30612C}
+ = CPrxyITest
+\Registry\MACHINE\SOFTWARE\Classes\CLSID\{60000494-AB0F-101A-B4AE-08002B30612C}\InprocServer32
+ = itest.dll
+
+\Registry\MACHINE\SOFTWARE\Classes\CLSID\{60000430-AB0F-101A-B4AE-08002B30612C}
+ = CTestCF
+\Registry\MACHINE\SOFTWARE\Classes\CLSID\{60000430-AB0F-101A-B4AE-08002B30612C}\LocalServer32
+ = app.exe
+
+
+
+
+ \ No newline at end of file
diff --git a/private/oleutest/channel/idl/test2.reg b/private/oleutest/channel/idl/test2.reg
new file mode 100644
index 000000000..1f8a8407a
--- /dev/null
+++ b/private/oleutest/channel/idl/test2.reg
@@ -0,0 +1,16 @@
+REGEDIT
+
+
+HKEY_CLASSES_ROOT\Interface\{60000494-AB0F-101A-B4AE-08002B30612C} = ITest
+HKEY_CLASSES_ROOT\Interface\{60000494-AB0F-101A-B4AE-08002B30612C}\ProxyStubClsid32 = {60000494-AB0F-101A-B4AE-08002B30612C}
+
+HKEY_CLASSES_ROOT\CLSID\{60000494-AB0F-101A-B4AE-08002B30612C} = CPrxyITest
+HKEY_CLASSES_ROOT\CLSID\{60000494-AB0F-101A-B4AE-08002B30612C}\InprocServer32 = itest.dll
+
+HKEY_CLASSES_ROOT\CLSID\{60000430-AB0F-101A-B4AE-08002B30612C} = CTestCF
+HKEY_CLASSES_ROOT\CLSID\{60000430-AB0F-101A-B4AE-08002B30612C}\LocalServer32 = app.exe
+
+
+
+
+ \ No newline at end of file
diff --git a/private/oleutest/channel/rel.cmd b/private/oleutest/channel/rel.cmd
new file mode 100644
index 000000000..e8b1be215
--- /dev/null
+++ b/private/oleutest/channel/rel.cmd
@@ -0,0 +1,3 @@
+copy proxy\obj\i386\itest.dll \tmp
+copy app\obj\i386\app.exe \tmp
+copy idl\test.reg \tmp
diff --git a/private/oleutest/chicago.inc b/private/oleutest/chicago.inc
new file mode 100644
index 000000000..222ea958d
--- /dev/null
+++ b/private/oleutest/chicago.inc
@@ -0,0 +1,23 @@
+# This is the global include file for the daytona version of CairOLE.
+# It is included by all project sources files.
+
+C_DEFINES= \
+ $(C_DEFINES) \
+ -DFLAT \
+ -DWIN32=200 \
+ -D_CHICAGO_=200 \
+ -DINC_OLE2 \
+ -DNOEXCEPTIONS \
+ -DCAIROLE_DOWNLEVEL \
+ -DMULTI_THREADING \
+ $(TRACELOG)
+
+# For the Chicago project, we do not want to use CRTDLL.DLL, so leave this
+# line commented out.
+#
+# BLDCRT= 1
+
+USE_LIBCMT= 1
+
+CHICAGO_PRODUCT=1
+
diff --git a/private/oleutest/cmarshal/app/app.cxx b/private/oleutest/cmarshal/app/app.cxx
new file mode 100644
index 000000000..fe9768312
--- /dev/null
+++ b/private/oleutest/cmarshal/app/app.cxx
@@ -0,0 +1,764 @@
+//+-------------------------------------------------------------
+//
+// File: perfcli.cxx
+//
+// Contents: First attempt at getting perfcliing to work
+//
+// This is the client side
+//
+//
+//---------------------------------------------------------------
+
+#include <windows.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <io.h>
+
+#include <ole2.h>
+#include <com.hxx>
+#include "app.hxx"
+#include <memalloc.h>
+#include <objerror.h>
+
+#pragma hdrstop
+
+//+--------------------------------------------------------------
+/* Definitions. */
+
+#define MAX_CALLS 1000
+#define MAX_THREADS 10
+
+typedef enum what_next_en
+{
+ wait_wn,
+ interrupt_wn,
+ quit_wn
+} what_next_en;
+
+//+--------------------------------------------------------------
+/* Prototypes. */
+void interrupt ( void );
+void check_for_request ( void );
+BOOL server_loop ( void );
+DWORD _stdcall ThreadHelper ( void * );
+void wait_for_message ( void );
+void wake_up_and_smell_the_roses( void );
+
+
+//+--------------------------------------------------------------
+/* Globals. */
+DWORD thread_mode = COINIT_MULTITHREADED;
+HANDLE Done;
+BOOL server;
+BOOL Multicall_Test;
+BOOL InterruptTestResults;
+BOOL InterruptTestDone;
+DWORD MainThread;
+DWORD NestedCallCount = 0;
+what_next_en WhatNext;
+ITest *global_test = NULL;
+BOOL global_interrupt_test;
+
+
+ /***************************************************************************/
+STDMETHODIMP_(ULONG) CTest::AddRef( THIS )
+{
+ InterlockedIncrement( (long *) &ref_count );
+ return ref_count;
+}
+
+ /***************************************************************************/
+CTest::CTest()
+{
+ ref_count = 1;
+ custom = NULL;
+}
+
+ /***************************************************************************/
+CTest::~CTest()
+{
+ if (custom != NULL)
+ {
+ custom->Release();
+ custom = NULL;
+ }
+}
+
+ /***************************************************************************/
+STDMETHODIMP CTest::sick( ULONG val )
+{
+ TRY
+ {
+ THROW( CException(val) );
+ }
+ CATCH( CException, exp )
+ {
+ }
+ END_CATCH;
+ return S_OK;
+}
+
+ /***************************************************************************/
+STDMETHODIMP CTest::die_cpp( ULONG val )
+{
+ THROW( CException(val) );
+ return S_OK;
+}
+
+ /***************************************************************************/
+STDMETHODIMP CTest::die_nt( ULONG val )
+{
+ RaiseException( val, 0, 0, NULL );
+ return S_OK;
+}
+
+ /***************************************************************************/
+STDMETHODIMP_(DWORD) CTest::die( ITest *callback, ULONG catch_depth,
+ ULONG throw_depth, ULONG throw_val )
+{
+ if (catch_depth == 0)
+ {
+ TRY
+ {
+ return callback->die( this, catch_depth - 1, throw_depth - 1, throw_val );
+ }
+ CATCH( CException, exp )
+ {
+#if DBG==1
+ if (DebugCoGetRpcFault() != throw_val)
+ {
+ printf( "Propogated server fault was returned as 0x%x not 0x%x\n",
+ DebugCoGetRpcFault(), throw_val );
+// return FALSE;
+ }
+#endif
+ return TRUE;
+ }
+ END_CATCH
+ }
+ else if (throw_depth == 0)
+ {
+ THROW( CException(throw_val) );
+ }
+ else
+ return callback->die( this, catch_depth - 1, throw_depth - 1, throw_val );
+ return FALSE;
+}
+
+ /***************************************************************************/
+STDMETHODIMP CTest::interrupt( ITest *param, BOOL go )
+{
+ global_interrupt_test = go;
+ if (go)
+ {
+ global_test = param;
+ global_test->AddRef();
+ WhatNext = interrupt_wn;
+ wake_up_and_smell_the_roses();
+ }
+ else
+ WhatNext = wait_wn;
+ return S_OK;
+}
+
+ /***************************************************************************/
+STDMETHODIMP_(BOOL) CTest::hello()
+{
+ if (GetCurrentThreadId() == MainThread)
+ printf( "Hello on the main thread.\n" );
+ else
+ printf( "Hello on thread %d.\n", GetCurrentThreadId );
+ return !InterruptTestDone;
+}
+
+ /***************************************************************************/
+STDMETHODIMP CTest::recurse( ITest *callback, ULONG depth )
+{
+ if (depth == 0)
+ return S_OK;
+ else
+ return callback->recurse( this, depth-1 );
+}
+
+ /***************************************************************************/
+STDMETHODIMP CTest::recurse_interrupt( ITest *callback, ULONG depth )
+{
+ MSG msg;
+
+ if (PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ))
+ {
+ TranslateMessage (&msg);
+ DispatchMessage (&msg);
+ }
+
+ if (depth == 0)
+ return S_OK;
+ else
+ return callback->recurse( this, depth-1 );
+}
+
+ /***************************************************************************/
+STDMETHODIMP CTest::sleep( ULONG time )
+{
+
+ // For single threaded mode, verify that this is the only call on the
+ // main thread.
+ NestedCallCount += 1;
+ printf( "Sleeping on thread %d for the %d time concurrently.\n",
+ GetCurrentThreadId(), NestedCallCount );
+ if (thread_mode == COINIT_SINGLETHREADED)
+ {
+ if (GetCurrentThreadId() != MainThread)
+ {
+ printf( "Sleep called on the wrong thread in single threaded mode.\n" );
+ NestedCallCount -= 1;
+ return FALSE;
+ }
+ else if (NestedCallCount != 1)
+ {
+ printf( "Sleep nested call count is %d instead of not 1 in single threaded mode.\n",
+ NestedCallCount );
+ NestedCallCount -= 1;
+ return FALSE;
+ }
+ }
+
+ // For multithreaded mode, verify that this is not the main thread.
+ else if (GetCurrentThreadId() == MainThread)
+ {
+ printf( "Sleep called on the main thread in multi threaded mode.\n" );
+ NestedCallCount -= 1;
+ return FALSE;
+ }
+
+ Sleep( time );
+ NestedCallCount -= 1;
+ return S_OK;
+}
+
+ /***************************************************************************/
+STDMETHODIMP_(DWORD) CTest::DoTest( ITest *test, ITest *another )
+{
+ HRESULT result;
+ int i;
+ BOOL success;
+ HANDLE helper[MAX_THREADS];
+ DWORD thread_id;
+ DWORD status;
+
+ // Let the server throw and exception and catch it before returning.
+ result = test->sick( 95 );
+ if (result != S_OK)
+ {
+ printf( "Internal server fault was not dealt with correctly.\n" );
+ return FALSE;
+ }
+
+ // Let the server throw a C++ exception here.
+ result = test->die_cpp( 0xdeaff00d );
+ if (result != RPC_E_FAULT)
+ {
+ printf( "C++ server fault was not dealt with correctly.\n" );
+ return FALSE;
+ }
+#if DBG==1
+ if (DebugCoGetRpcFault() != 0xdeaff00d)
+ {
+ printf( "C++ server fault was returned as 0x%x not 0x%x\n",
+ DebugCoGetRpcFault(), 0xdeaff00d );
+// return FALSE;
+ }
+#endif
+
+ // Let the server throw a NT exception here.
+ result = test->die_nt( 0xaaaabdbd );
+ if (result != RPC_E_FAULT)
+ {
+ printf( "NT server fault was not dealt with correctly.\n" );
+ return FALSE;
+ }
+#if DBG==1
+ if (DebugCoGetRpcFault() != 0xaaaabdbd)
+ {
+ printf( "C++ server fault was returned as 0x%x not 0x%x\n",
+ DebugCoGetRpcFault(), 0xaaaabdbd );
+ return FALSE;
+ }
+#endif
+
+ // Test a recursive call.
+ result = test->recurse( this, 10 );
+ if (result != S_OK)
+ {
+ printf( "Recursive call failed: 0x%x\n", result );
+ return FALSE;
+ }
+
+ // Test throwing and immediately catching an exception.
+ //success = test->die( this, 2, 3, 0x12345678 );
+ //if (!success)
+ //{
+ // printf( "Could not catch server exception.\n" );
+ // return FALSE;
+ //}
+
+ // Test throwing, propogating, and then catching an exception.
+ // success = test->die( this, 1, 3, 0x87654321 );
+ //if (!success)
+ //{
+ // printf( "Could not catch propogated server exception.\n" );
+ // return FALSE;
+ //}
+
+ // Test multiple threads.
+ Multicall_Test = TRUE;
+ for (i = 0; i < MAX_THREADS; i++)
+ {
+ helper[i] = CreateThread( NULL, 0, ThreadHelper, test, 0, &thread_id );
+ if (helper == NULL)
+ {
+ printf( "Could not create helper thread number %d.\n", i );
+ return FALSE;
+ }
+ }
+ result = test->sleep(4000);
+ if (result != S_OK)
+ {
+ printf( "Multiple call failed on main thread: 0x%x\n", result );
+ return FALSE;
+ }
+ status = WaitForMultipleObjects( MAX_THREADS, helper, TRUE, INFINITE );
+ if (status == WAIT_FAILED)
+ {
+ printf( "Could not wait for helper threads to die: 0x%x\n", status );
+ return FALSE;
+ }
+ if (!Multicall_Test)
+ {
+ printf( "Multiple call failed on helper thread.\n" );
+ return FALSE;
+ }
+
+ // See if methods can correctly call GetMessage.
+ another->interrupt( test, TRUE );
+ result = test->recurse_interrupt( this, 10 );
+ if (result != S_OK)
+ {
+ printf( "Recursive call with interrupts failed: 0x%x\n", result );
+ return FALSE;
+ }
+ another->interrupt( test, FALSE );
+
+ // Finally, its all over.
+ return TRUE;
+}
+
+ /***************************************************************************/
+STDMETHODIMP CTest::QueryInterface( THIS_ REFIID riid, LPVOID FAR* ppvObj)
+{
+ if (IsEqualIID(riid, IID_IUnknown) ||
+ IsEqualIID(riid, IID_ITest))
+ {
+ *ppvObj = (IUnknown *) this;
+ AddRef();
+ return S_OK;
+ }
+ else if (IsEqualIID( riid, IID_IMarshal))
+ {
+ if (custom == NULL)
+ {
+ custom = new CCMarshal;
+ if (custom == NULL)
+ return E_FAIL;
+ }
+ *ppvObj = (IMarshal *) custom;
+ custom->AddRef();
+ return S_OK;
+ }
+ else
+ {
+ *ppvObj = NULL;
+ return E_NOINTERFACE;
+ }
+}
+
+ /***************************************************************************/
+STDMETHODIMP_(ULONG) CTest::Release( THIS )
+{
+ if (InterlockedDecrement( (long*) &ref_count ) == 0)
+ {
+ WhatNext = quit_wn;
+ wake_up_and_smell_the_roses();
+ delete this;
+ return 0;
+ }
+ else
+ return ref_count;
+}
+
+ /***************************************************************************/
+STDMETHODIMP_(ULONG) CTestCF::AddRef( THIS )
+{
+ InterlockedIncrement( (long *) &ref_count );
+ return ref_count;
+}
+
+ /***************************************************************************/
+CTestCF::CTestCF()
+{
+ ref_count = 1;
+}
+
+ /***************************************************************************/
+CTestCF::~CTestCF()
+{
+}
+
+ /***************************************************************************/
+STDMETHODIMP CTestCF::CreateInstance(
+ IUnknown FAR* pUnkOuter,
+ REFIID iidInterface,
+ void FAR* FAR* ppv)
+{
+ *ppv = NULL;
+ if (pUnkOuter != NULL)
+ {
+ return E_FAIL;
+ }
+
+ if (!IsEqualIID( iidInterface, IID_ITest ))
+ return E_NOINTERFACE;
+
+ CTest *Test = new FAR CTest();
+
+ if (Test == NULL)
+ {
+ return E_OUTOFMEMORY;
+ }
+
+ *ppv = Test;
+ return S_OK;
+}
+
+ /***************************************************************************/
+STDMETHODIMP CTestCF::LockServer(BOOL fLock)
+{
+ return E_FAIL;
+}
+
+
+ /***************************************************************************/
+STDMETHODIMP CTestCF::QueryInterface( THIS_ REFIID riid, LPVOID FAR* ppvObj)
+{
+ if (IsEqualIID(riid, IID_IUnknown) ||
+ IsEqualIID(riid, IID_IClassFactory))
+ {
+ *ppvObj = (IUnknown *) this;
+ AddRef();
+ return S_OK;
+ }
+
+ *ppvObj = NULL;
+ return E_NOINTERFACE;
+}
+
+ /***************************************************************************/
+STDMETHODIMP_(ULONG) CTestCF::Release( THIS )
+{
+ if (InterlockedDecrement( (long*) &ref_count ) == 0)
+ {
+ delete this;
+ return 0;
+ }
+ else
+ return ref_count;
+}
+
+ /***************************************************************************/
+void interrupt()
+{
+ while (global_interrupt_test)
+ {
+ global_test->hello();
+ check_for_request();
+ }
+ global_test->Release();
+}
+
+//+--------------------------------------------------------------
+// Function: Main
+//
+// Synopsis: Executes the BasicBnd test
+//
+// Effects: None
+//
+//
+// Returns: Exits with exit code 0 if success, 1 otherwise
+//
+// History: 05-Mar-92 Sarahj Created
+//
+//---------------------------------------------------------------
+
+int _cdecl main(int argc, char *argv[])
+{
+ HRESULT result;
+ DWORD wrong;
+ BOOL success = TRUE;
+ ITest *another = NULL;
+ ITest *test = NULL;
+ CTest *tester = new CTest;
+
+ // Initialize Globals.
+ MainThread = GetCurrentThreadId();
+
+ // Create an event for termination notification.
+ Done = CreateEvent( NULL, FALSE, FALSE, NULL );
+ if (Done == NULL)
+ {
+ printf( "Could not create event.\n" );
+ success = FALSE;
+ goto exit_main;
+ }
+
+ int len;
+ TCHAR buffer[80];
+
+ // Look up the thread mode from the win.ini file.
+ len = GetProfileString( L"My Section", L"ThreadMode", L"MultiThreaded", buffer,
+ sizeof(buffer) );
+ if (lstrcmp(buffer, L"SingleThreaded") == 0)
+ {
+ thread_mode = COINIT_SINGLETHREADED;
+ wrong = COINIT_MULTITHREADED;
+ printf( "Testing channel in single threaded mode.\n" );
+ }
+ else if (lstrcmp(buffer, L"MultiThreaded") == 0)
+ {
+ thread_mode = COINIT_MULTITHREADED;
+ wrong = COINIT_SINGLETHREADED;
+ printf( "Testing channel in multithreaded mode.\n" );
+ }
+
+ // Initialize OLE.
+ result = OleInitializeEx(NULL, thread_mode);
+ if (!SUCCEEDED(result))
+ {
+ success = FALSE;
+ printf( "OleInitializeEx failed: %x\n", result );
+ goto exit_main;
+ }
+ result = CoInitializeEx(NULL, thread_mode);
+ if (!SUCCEEDED(result))
+ {
+ success = FALSE;
+ printf( "Recalling CoInitializeEx failed: %x\n", result );
+ goto exit_main;
+ }
+ result = CoInitializeEx(NULL, wrong);
+ if (result == S_OK)
+ {
+ success = FALSE;
+ printf( "Recalling CoInitializeEx with wrong thread mode succeeded: %x\n", result );
+ goto exit_main;
+ }
+ CoUninitialize();
+ CoUninitialize();
+
+ // If this is a server app, register and wait for a quit message.
+ if (argv[1] == NULL)
+ server = FALSE;
+ else
+ server = strcmp( argv[1], "-Embedding" ) == 0;
+ if (server)
+ {
+ success = server_loop( );
+ }
+
+ // Initialize and run the tests.
+ else
+ {
+ // Get a test object.
+ result = CoCreateInstance( CLSID_ITest, NULL, CLSCTX_LOCAL_SERVER,
+ IID_ITest, (void **) &test );
+ if (!SUCCEEDED(result))
+ {
+ printf( "Could not create instance of test server: %x\n", result );
+ success = FALSE;
+ goto exit_main;
+ }
+
+ // Get another test object.
+ result = CoCreateInstance( CLSID_ITest, NULL, CLSCTX_LOCAL_SERVER,
+ IID_ITest, (void **) &another );
+ if (!SUCCEEDED(result))
+ {
+ printf( "Could not create another instance of test server: %x\n", result );
+ success = FALSE;
+ goto exit_main;
+ }
+
+ success = tester->DoTest( test, another );
+ }
+
+exit_main:
+
+ // Release the external test objects used.
+ if (test != NULL)
+ test->Release();
+ if (another != NULL)
+ another->Release();
+
+ // Release the internal test object.
+ tester->Release();
+ //wait_for_message();
+
+ OleUninitialize();
+
+ if (!server)
+ if (success)
+ printf("\nChannel Unit Test: PASSED\n");
+ else
+ printf("\nChannel Unit Test: FAILED\n");
+
+ return !success;
+}
+
+//+--------------------------------------------------------------
+void check_for_request()
+{
+ MSG msg;
+
+ if (thread_mode == COINIT_SINGLETHREADED)
+ {
+ if (PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ))
+ {
+ TranslateMessage (&msg);
+ DispatchMessage (&msg);
+ }
+ }
+}
+
+//+--------------------------------------------------------------
+BOOL server_loop( )
+{
+ HRESULT result;
+ DWORD dwRegistration;
+
+ // Create our class factory
+ WhatNext = wait_wn;
+ CTestCF *test_cf = new CTestCF();
+
+ // Register our class with OLE
+ result = CoRegisterClassObject(CLSID_ITest, test_cf, CLSCTX_LOCAL_SERVER,
+ REGCLS_SINGLEUSE, &dwRegistration);
+ if (!SUCCEEDED(result))
+ {
+ printf( "CoRegisterClassObject failed: %x\n", result );
+ return FALSE;
+ }
+
+ // CoRegister bumps reference count so we don't have to!
+ test_cf->Release();
+
+ // Do whatever we have to do till it is time to pay our taxes and die.
+ while (WhatNext != quit_wn)
+ switch (WhatNext)
+ {
+
+ // Wait till a quit arrives.
+ case wait_wn:
+ wait_for_message();
+ break;
+
+ case interrupt_wn:
+ interrupt();
+ break;
+ }
+
+ // Deregister out class - should release object as well
+ result = CoRevokeClassObject(dwRegistration);
+ if (!SUCCEEDED(result))
+ {
+ printf( "CoRevokeClassObject failed: %x\n", result );
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+ /***************************************************************************/
+DWORD _stdcall ThreadHelper( void *param )
+{
+ ITest *test = (ITest *) param;
+ HRESULT result;
+
+ // Call the server.
+ result = test->sleep( 2000 );
+
+ // Check the result for single threaded mode.
+ if (thread_mode == COINIT_SINGLETHREADED)
+ {
+ if (SUCCEEDED(result))
+ {
+ Multicall_Test = FALSE;
+ printf( "Call succeeded on wrong thread in single threaded mode: 0x%x.\n",
+ result );
+ }
+#if DBG==1
+ else if (DebugCoGetRpcFault() != RPC_E_ATTEMPTED_MULTITHREAD)
+ {
+ printf( "Multithread failure code was 0x%x not 0x%x\n",
+ DebugCoGetRpcFault(), RPC_E_ATTEMPTED_MULTITHREAD );
+ Multicall_Test = FALSE;
+ }
+#endif
+ }
+
+ // Check the result for multithreaded mode.
+ else if (result != S_OK)
+ {
+ printf( "Could not make multiple calls in multithreaded mode: 0x%x\n",
+ result );
+ Multicall_Test = FALSE;
+ }
+
+#define DO_DA 42
+ return DO_DA;
+}
+
+ /***************************************************************************/
+void wait_for_message()
+{
+ MSG msg;
+ DWORD status;
+
+ if (thread_mode == COINIT_MULTITHREADED)
+ {
+ status = WaitForSingleObject( Done, INFINITE );
+ if (status != WAIT_OBJECT_0 )
+ {
+ printf( "Could not wait for event.\n" );
+ }
+ }
+ else
+ {
+ while (GetMessage( &msg, NULL, 0, 0 ) && msg.message != WM_USER)
+ {
+ TranslateMessage (&msg);
+ DispatchMessage (&msg);
+ }
+ }
+}
+
+ /***************************************************************************/
+void wake_up_and_smell_the_roses()
+{
+ if (thread_mode == COINIT_MULTITHREADED)
+ SetEvent( Done );
+ else
+ PostThreadMessage(MainThread, WM_USER, 0, 0);
+}
+
diff --git a/private/oleutest/cmarshal/app/app.hxx b/private/oleutest/cmarshal/app/app.hxx
new file mode 100644
index 000000000..91339b76c
--- /dev/null
+++ b/private/oleutest/cmarshal/app/app.hxx
@@ -0,0 +1,108 @@
+//+-------------------------------------------------------------------
+//
+// File: Testsrv.hxx
+//
+// Contents: This file contins the DLL entry points
+// LibMain
+// DllGetClassObject (Bindings key func)
+// DllCanUnloadNow
+// CBasicBndCF (class factory)
+// History: 30-Mar-92 SarahJ Created
+//
+//---------------------------------------------------------------------
+
+#ifndef __APP_H__
+#define __APP_H__
+
+#include "..\idl\itest.h"
+#include "cmarshal.hxx"
+
+extern "C" const IID CLSID_ITest;
+
+//+-------------------------------------------------------------------
+//
+// Class: CTestCF
+//
+// Synopsis: Class Factory for CTest
+//
+// Methods: IUnknown - QueryInterface, AddRef, Release
+// IClassFactory - CreateInstance
+//
+// History: 21-Mar-92 SarahJ Created
+//
+//--------------------------------------------------------------------
+
+
+class FAR CTestCF: public IClassFactory
+{
+public:
+
+ // Constructor/Destructor
+ CTestCF();
+ ~CTestCF();
+
+ // IUnknown
+ STDMETHODIMP QueryInterface(REFIID iid, void FAR * FAR * ppv);
+ STDMETHOD_(ULONG,AddRef) ( void );
+ STDMETHOD_(ULONG,Release) ( void );
+
+ // IClassFactory
+ STDMETHODIMP CreateInstance(
+ IUnknown FAR* pUnkOuter,
+ REFIID iidInterface,
+ void FAR* FAR* ppv);
+
+ STDMETHODIMP LockServer(BOOL fLock);
+
+private:
+
+ ULONG ref_count;
+};
+
+//+-------------------------------------------------------------------
+//
+// Class: CTest
+//
+// Synopsis: Test class
+//
+// Methods:
+//
+// History: 21-Mar-92 SarahJ Created
+//
+//--------------------------------------------------------------------
+
+
+class FAR CTest: public ITest
+{
+public:
+ CTest();
+
+ ~CTest();
+
+ // IUnknown
+ STDMETHODIMP QueryInterface(REFIID iid, void FAR * FAR * ppv);
+ STDMETHOD_(ULONG,AddRef) ( void );
+ STDMETHOD_(ULONG,Release) ( void );
+
+ // ITest
+ STDMETHOD_(DWORD, die) ( ITest *, ULONG, ULONG, ULONG );
+ STDMETHOD (die_cpp) ( ULONG );
+ STDMETHOD (die_nt) ( ULONG );
+ STDMETHOD_(DWORD, DoTest) ( ITest *, ITest * );
+ STDMETHOD_(BOOL, hello) ( );
+ STDMETHOD (interrupt) ( ITest *, BOOL );
+ STDMETHOD (recurse) ( ITest *, ULONG );
+ STDMETHOD (recurse_interrupt)( ITest *, ULONG );
+ STDMETHOD (sick) ( ULONG );
+ STDMETHOD (sleep) ( ULONG );
+
+
+
+private:
+
+ ULONG ref_count;
+ CCMarshal *custom;
+};
+
+
+#endif
diff --git a/private/oleutest/cmarshal/app/app_i.c b/private/oleutest/cmarshal/app/app_i.c
new file mode 100644
index 000000000..fa7732cce
--- /dev/null
+++ b/private/oleutest/cmarshal/app/app_i.c
@@ -0,0 +1,26 @@
+#pragma warning(disable:4101) // Ignore variable not use warning
+
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: iperf_i.c
+//
+// Contents: IID_IPerf
+//
+// History: Created by Microsoft (R) MIDL Compiler Version 1.10.83
+//
+//--------------------------------------------------------------------------
+typedef struct _IID
+{
+ unsigned long x;
+ unsigned short s1;
+ unsigned short s2;
+ unsigned char c[8];
+} IID;
+
+
+const IID CLSID_ITest =
+{0x60000430, 0xAB0F, 0x101A, {0xB4, 0xAE, 0x08, 0x00, 0x2B, 0x30, 0x61, 0x2C}};
+
diff --git a/private/oleutest/cmarshal/app/cmarshal.cxx b/private/oleutest/cmarshal/app/cmarshal.cxx
new file mode 100644
index 000000000..8f6471c66
--- /dev/null
+++ b/private/oleutest/cmarshal/app/cmarshal.cxx
@@ -0,0 +1,317 @@
+//+-------------------------------------------------------------------
+//
+// File: cmarshal.cxx
+//
+// Contents: This file contins the DLL entry points
+// LibMain
+// DllGetClassObject (Bindings key func)
+// CBasicBndCF (class factory)
+// CBasicBnd (actual class implementation)
+//
+// Classes: CBasicBndCF, CBasicBnd
+//
+//
+// History: 30-Nov-92 SarahJ Created
+//
+//---------------------------------------------------------------------
+
+#include <windows.h>
+#include <ole2.h>
+#include "app.hxx"
+
+
+ /***************************************************************************/
+STDMETHODIMP_(ULONG) CCMarshal::AddRef( THIS )
+{
+ InterlockedIncrement( (long *) &ref_count );
+ return ref_count;
+}
+
+ /***************************************************************************/
+CCMarshal::CCMarshal()
+{
+ ref_count = 1;
+}
+
+ /***************************************************************************/
+CCMarshal::~CCMarshal()
+{
+}
+
+ /***************************************************************************/
+STDMETHODIMP CCMarshal::sick( ULONG val )
+{
+ return proxy->sick( val );
+}
+
+ /***************************************************************************/
+STDMETHODIMP CCMarshal::die_cpp( ULONG val )
+{
+ return proxy->die_cpp( val );
+}
+
+ /***************************************************************************/
+STDMETHODIMP CCMarshal::die_nt( ULONG val )
+{
+ return proxy->die_nt( val );
+}
+
+ /***************************************************************************/
+STDMETHODIMP_(DWORD) CCMarshal::die( ITest *callback, ULONG catch_depth,
+ ULONG throw_depth, ULONG throw_val )
+{
+ return proxy->die( callback, catch_depth, throw_depth, throw_val );
+}
+
+ /***************************************************************************/
+STDMETHODIMP CCMarshal::interrupt( ITest *param, BOOL go )
+{
+ return proxy->interrupt( param, go );
+}
+
+ /***************************************************************************/
+STDMETHODIMP_(BOOL) CCMarshal::hello()
+{
+ return proxy->hello();
+}
+
+ /***************************************************************************/
+STDMETHODIMP CCMarshal::recurse( ITest *callback, ULONG depth )
+{
+ return proxy->recurse( callback, depth );
+}
+
+ /***************************************************************************/
+STDMETHODIMP CCMarshal::recurse_interrupt( ITest *callback, ULONG depth )
+{
+ return proxy->recurse_interrupt( callback, depth );
+}
+
+ /***************************************************************************/
+STDMETHODIMP CCMarshal::sleep( ULONG time )
+{
+ return proxy->sleep( time );
+}
+
+ /***************************************************************************/
+STDMETHODIMP_(DWORD) CCMarshal::DoTest( ITest *test, ITest *another )
+{
+ return proxy->DoTest( test, another );
+}
+
+ /***************************************************************************/
+STDMETHODIMP CCMarshal::QueryInterface( THIS_ REFIID riid, LPVOID FAR* ppvObj)
+{
+ if (IsEqualIID(riid, IID_IUnknown) ||
+ IsEqualIID(riid, IID_ITest))
+ {
+ *ppvObj = (ITest *) this;
+ AddRef();
+ return S_OK;
+ }
+ else
+ {
+ *ppvObj = NULL;
+ return E_NOINTERFACE;
+ }
+}
+
+ /***************************************************************************/
+STDMETHODIMP_(ULONG) CCMarshal::Release( THIS )
+{
+ if (InterlockedDecrement( (long*) &ref_count ) == 0)
+ {
+ delete this;
+ return 0;
+ }
+ else
+ return ref_count;
+}
+
+
+ /***************************************************************************/
+STDMETHODIMP_(ULONG) CCMarshalCF::AddRef( THIS )
+{
+ InterlockedIncrement( (long *) &ref_count );
+ return ref_count;
+}
+
+ /***************************************************************************/
+CCMarshalCF::CCMarshalCF()
+{
+ ref_count = 1;
+}
+
+ /***************************************************************************/
+CCMarshalCF::~CCMarshalCF()
+{
+}
+
+ /***************************************************************************/
+STDMETHODIMP CCMarshalCF::CreateInstance(
+ IUnknown FAR* pUnkOuter,
+ REFIID iidInterface,
+ void FAR* FAR* ppv)
+{
+ *ppv = NULL;
+ if (pUnkOuter != NULL)
+ {
+ return E_FAIL;
+ }
+
+ if (!IsEqualIID( iidInterface, IID_ITest ))
+ return E_NOINTERFACE;
+
+ CCMarshal *Test = new FAR CCMarshal();
+
+ if (Test == NULL)
+ {
+ return E_OUTOFMEMORY;
+ }
+
+ *ppv = Test;
+ return S_OK;
+}
+
+ /***************************************************************************/
+STDMETHODIMP CCMarshalCF::LockServer(BOOL fLock)
+{
+ return E_FAIL;
+}
+
+
+ /***************************************************************************/
+STDMETHODIMP CCMarshalCF::QueryInterface( THIS_ REFIID riid, LPVOID FAR* ppvObj)
+{
+ if (IsEqualIID(riid, IID_IUnknown) ||
+ IsEqualIID(riid, IID_IClassFactory))
+ {
+ *ppvObj = (IUnknown *) this;
+ AddRef();
+ return S_OK;
+ }
+
+ *ppvObj = NULL;
+ return E_NOINTERFACE;
+}
+
+ /***************************************************************************/
+STDMETHODIMP_(ULONG) CCMarshalCF::Release( THIS )
+{
+ if (InterlockedDecrement( (long*) &ref_count ) == 0)
+ {
+ delete this;
+ return 0;
+ }
+ else
+ return ref_count;
+}
+
+
+
+CMarshalBase::CMarshalBase()
+{
+ proxy = NULL;
+ marshaller = NULL;
+}
+
+
+CMarshalBase::~CMarshalBase()
+{
+ if (proxy != NULL)
+ {
+ proxy->Release();
+ proxy = NULL;
+ }
+ if (marshaller != NULL)
+ {
+ marshaller->Release();
+ marshaller = NULL;
+ }
+}
+
+
+// Returns the clsid of the object that created this CMarshalBase.
+//
+ STDMETHODIMP CMarshalBase::GetUnmarshalClass(REFIID riid, LPVOID pv,
+ DWORD dwDestContext, LPVOID pvDestContext, DWORD mshlflags, CLSID * pCid)
+{
+ *pCid = CLSID_ITest;
+ return S_OK;
+}
+
+
+ STDMETHODIMP CMarshalBase::GetMarshalSizeMax(REFIID riid, LPVOID pv,
+ DWORD dwDestContext, LPVOID pvDestContext, DWORD mshlflags, DWORD * pSize)
+{
+ SCODE result;
+
+ if (marshaller == NULL)
+ {
+ result = CoGetStandardMarshal( riid, this, dwDestContext, pvDestContext,
+ mshlflags, &marshaller );
+ if (FAILED(result))
+ return result;
+ }
+ return marshaller->GetMarshalSizeMax( riid, this, dwDestContext,
+ pvDestContext, mshlflags, pSize );
+}
+
+
+ STDMETHODIMP CMarshalBase::MarshalInterface(IStream * pStm,
+ REFIID riid, void * pv,
+ DWORD dwDestContext, LPVOID pvDestContext, DWORD mshlflags)
+{
+ SCODE result;
+
+ if (marshaller == NULL)
+ return E_FAIL;
+
+ result = marshaller->MarshalInterface( pStm, riid, this, dwDestContext,
+ pvDestContext, mshlflags );
+ if (SUCCEEDED(result))
+ {
+ proxy = (ITest *) pv;
+ ((IUnknown *) pv)->AddRef();
+ }
+ return result;
+}
+
+
+ STDMETHODIMP CMarshalBase::UnmarshalInterface(IStream * pStm,
+ REFIID riid, void * * ppv)
+{
+ SCODE result;
+
+ if (marshaller == NULL)
+ {
+ result = CoGetStandardMarshal( riid, this, 0, NULL,
+ MSHLFLAGS_NORMAL, &marshaller );
+ if (FAILED(result))
+ return result;
+ }
+
+ result = marshaller->UnmarshalInterface( pStm, riid, (void **) &proxy );
+ if (SUCCEEDED(result))
+ {
+ *ppv = this;
+ AddRef();
+ }
+ else
+ *ppv = NULL;
+ return result;
+}
+
+
+ STDMETHODIMP CMarshalBase::ReleaseMarshalData(IStream * pStm)
+{
+ return marshaller->ReleaseMarshalData( pStm );
+}
+
+
+ STDMETHODIMP CMarshalBase::DisconnectObject(DWORD dwReserved)
+{
+ return marshaller->DisconnectObject( dwReserved );
+}
+
+
diff --git a/private/oleutest/cmarshal/app/cmarshal.hxx b/private/oleutest/cmarshal/app/cmarshal.hxx
new file mode 100644
index 000000000..4cd89d5b6
--- /dev/null
+++ b/private/oleutest/cmarshal/app/cmarshal.hxx
@@ -0,0 +1,131 @@
+//+-------------------------------------------------------------------
+//
+// File: cmarshal.hxx
+//
+// Contents: This file contins the DLL entry points
+// LibMain
+// DllGetClassObject (Bindings key func)
+// DllCanUnloadNow
+// CCMarshalCF (class factory)
+// History: 30-Mar-92 SarahJ Created
+//
+//---------------------------------------------------------------------
+
+#ifndef __CMARSHAL_H__
+#define __CMARSHAL_H__
+
+
+//+-------------------------------------------------------------------
+//
+// Class: CCMarshalCF
+//
+// Synopsis: Class Factory for CCMarshal
+//
+// Methods: IUnknown - QueryInterface, AddRef, Release
+// IClassFactory - CreateInstance
+//
+// History: 21-Mar-92 SarahJ Created
+//
+//--------------------------------------------------------------------
+
+
+class FAR CCMarshalCF: public IClassFactory
+{
+public:
+
+ // Constructor/Destructor
+ CCMarshalCF();
+ ~CCMarshalCF();
+
+ // IUnknown
+ STDMETHODIMP QueryInterface(REFIID iid, void FAR * FAR * ppv);
+ STDMETHODIMP_(ULONG) AddRef(void);
+ STDMETHODIMP_(ULONG) Release(void);
+
+
+ // IClassFactory
+ STDMETHODIMP CreateInstance(IUnknown FAR* pUnkOuter,
+ REFIID iidInterface,
+ void FAR* FAR* ppv);
+
+ STDMETHODIMP LockServer(BOOL fLock);
+
+private:
+
+ ULONG ref_count;;
+};
+
+
+
+class CMarshalBase : public IMarshal
+{
+ public:
+
+ CMarshalBase();
+ ~CMarshalBase();
+
+ // IMarshal
+ STDMETHOD(GetUnmarshalClass) (THIS_ REFIID riid, LPVOID pv,
+ DWORD dwDestContext, LPVOID pvDestContext,
+ DWORD mshlflags, LPCLSID pCid);
+ STDMETHOD(GetMarshalSizeMax) (THIS_ REFIID riid, LPVOID pv,
+ DWORD dwDestContext, LPVOID pvDestContext,
+ DWORD mshlflags, LPDWORD pSize);
+ STDMETHOD(MarshalInterface) (THIS_ IStream * pStm, REFIID riid,
+ LPVOID pv, DWORD dwDestContext, LPVOID pvDestContext,
+ DWORD mshlflags);
+ STDMETHOD(UnmarshalInterface)(THIS_ IStream * pStm, REFIID riid,
+ LPVOID * ppv);
+ STDMETHOD(ReleaseMarshalData)(THIS_ IStream * pStm);
+ STDMETHOD(DisconnectObject) (THIS_ DWORD dwReserved);
+
+ ITest *proxy;
+
+ private:
+ IMarshal *marshaller;
+
+};
+
+//+-------------------------------------------------------------------
+//
+// Class: CCMarshal
+//
+// Synopsis: Test class CCMarshal
+//
+// Methods:
+//
+// History: 21-Mar-92 SarahJ Created
+//
+//--------------------------------------------------------------------
+
+
+class FAR CCMarshal: public ITest, public CMarshalBase
+{
+public:
+// Constructor/Destructor
+ CCMarshal();
+ ~CCMarshal();
+
+ // IUnknown
+ STDMETHODIMP QueryInterface(REFIID iid, void FAR * FAR * ppv);
+ STDMETHODIMP_(ULONG) AddRef(void);
+ STDMETHODIMP_(ULONG) Release(void);
+
+ // ITest
+ STDMETHOD_(DWORD, die) ( ITest *, ULONG, ULONG, ULONG );
+ STDMETHOD (die_cpp) ( ULONG );
+ STDMETHOD (die_nt) ( ULONG );
+ STDMETHOD_(DWORD, DoTest) ( ITest *, ITest * );
+ STDMETHOD_(BOOL, hello) ( );
+ STDMETHOD (interrupt) ( ITest *, BOOL );
+ STDMETHOD (recurse) ( ITest *, ULONG );
+ STDMETHOD (recurse_interrupt)( ITest *, ULONG );
+ STDMETHOD (sick) ( ULONG );
+ STDMETHOD (sleep) ( ULONG );
+
+private:
+
+ ULONG ref_count;
+};
+
+#endif
diff --git a/private/oleutest/cmarshal/app/filelist.mk b/private/oleutest/cmarshal/app/filelist.mk
new file mode 100644
index 000000000..bf78a6ba4
--- /dev/null
+++ b/private/oleutest/cmarshal/app/filelist.mk
@@ -0,0 +1,55 @@
+############################################################################
+#
+# Copyright (C) 1992, Microsoft Corporation.
+#
+# 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 = app.exe
+
+TARGET_DESCRIPTION = "$(PLATFORM) $(BUILDTYPE) Cariole DRT Driver"
+
+RELEASEDRT = 1
+
+#
+# Source files. Remember to prefix each name with .\
+#
+# MTHREAD=1
+
+CXXFILES = .\app.cxx \
+ .\cmarshal.cxx
+
+CFILES = .\app_i.c
+
+RCFILES =
+
+OBJFILES = ..\idl\objind\itest_i.obj
+
+#
+# Libraries and other object files to link.
+#
+
+LIBS = $(COMMON)\src\ole\$(OBJDIR)\olecom.lib\
+ $(CAIROLIB) \
+
+#
+# Precompiled headers.
+#
+
+PXXFILE =
+PFILE =
+
+DEFFILE =
+
+CINC = $(CINC) -I. -I..\common -I. -I..\strms\server -I$(CAIROLE)\ole\inc
+
+NO_WINMAIN = 1
+
+NEWDEF = 1
diff --git a/private/oleutest/cmarshal/app/makefile b/private/oleutest/cmarshal/app/makefile
new file mode 100644
index 000000000..9baa61272
--- /dev/null
+++ b/private/oleutest/cmarshal/app/makefile
@@ -0,0 +1,13 @@
+############################################################################
+#
+# Copyright (C) 1992, Microsoft Corporation.
+#
+# All rights reserved.
+#
+############################################################################
+
+default: all
+!include filelist.mk
+!include $(COMMON)\src\win40.mk
+!include depend.mk
+
diff --git a/private/oleutest/cmarshal/cmarshal/cmarshal.def b/private/oleutest/cmarshal/cmarshal/cmarshal.def
new file mode 100644
index 000000000..9561f2ae7
--- /dev/null
+++ b/private/oleutest/cmarshal/cmarshal/cmarshal.def
@@ -0,0 +1,48 @@
+#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 cmarshal
+
+DESCRIPTION 'Microsoft (R) OLE 2.0 Proxy DLL 1.00'
+
+EXPORTS
+#if defined(i386)
+
+ DllGetClassObject@12 @1
+ DllGetClassObject=DllGetClassObject@12
+ DllCanUnloadNow@0 @2
+ DllCanUnloadNow=DllCanUnloadNow@0
+
+#elif defined(_MIPS_)
+
+ DllGetClassObject @1
+ DllCanUnloadNow @2
+
+#endif // i386 - MIPS
+
+#endif // FLAT
diff --git a/private/oleutest/cmarshal/cmarshal/filelist.mk b/private/oleutest/cmarshal/cmarshal/filelist.mk
new file mode 100644
index 000000000..af3c48394
--- /dev/null
+++ b/private/oleutest/cmarshal/cmarshal/filelist.mk
@@ -0,0 +1,52 @@
+############################################################################
+#
+# Copyright (C) 1992, Microsoft Corporation.
+#
+# 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 = cmarshal.dll
+
+COFFBASE = testdll
+TARGET_DESCRIPTION = "$(PLATFORM) $(BUILDTYPE) Cariole DRT DLL Server"
+
+RELEASEDRT = 1
+#
+# Source files. Remember to prefix each name with .\
+#
+
+CXXFILES = .\inproc.cxx
+
+CFILES =
+RCFILES =
+DEFFILE = cmarshal.def
+CINC = $(CINC) -I. -I..\common -I..\app
+
+#
+# Libraries and other object files to link.
+#
+
+
+LIBS = $(COMMON)\src\ole\$(OBJDIR)\olecom.lib\
+ $(CAIROLIB)
+
+
+OBJFILES = ..\app\$(OBJDIR)\cmarshal.obj \
+ ..\app\$(OBJDIR)\app_i.obj \
+ ..\idl\$(OBJDIR)\itest_i.obj
+
+
+
+#
+# Precompiled headers.
+#
+
+PXXFILE =
+PFILE =
diff --git a/private/oleutest/cmarshal/cmarshal/inproc.cxx b/private/oleutest/cmarshal/cmarshal/inproc.cxx
new file mode 100644
index 000000000..e974949fc
--- /dev/null
+++ b/private/oleutest/cmarshal/cmarshal/inproc.cxx
@@ -0,0 +1,77 @@
+#include <windows.h>
+#include <ole2.h>
+#include <app.hxx>
+
+//+-------------------------------------------------------------------
+//
+// Function: LibMain
+//
+// Synopsis: Entry point to DLL - does little else
+//
+// Arguments:
+//
+// Returns: TRUE
+//
+// History: 21-Nov-92 SarahJ Created
+//
+//--------------------------------------------------------------------
+
+
+
+//
+// Entry point to DLL is traditional LibMain
+// Do nothing in here
+//
+
+
+extern "C" BOOL _cdecl LibMain ( HINSTANCE hinst,
+ HANDLE segDS,
+ UINT cbHeapSize,
+ LPTSTR lpCmdLine)
+{
+ return TRUE;
+}
+
+
+//+-------------------------------------------------------------------
+//
+// Function: DllGetClassObject
+//
+// Synopsis: Called by client (from within BindToObject et al)
+// interface requested should be IUnknown or IClassFactory -
+// Creates ClassFactory object and returns pointer to it
+//
+// Arguments: REFCLSID clsid - class id
+// REFIID iid - interface id
+// void FAR* FAR* ppv- pointer to class factory interface
+//
+// Returns: TRUE
+//
+// History: 21-Nov-92 SarahJ Created
+//
+//--------------------------------------------------------------------
+
+
+STDAPI DllGetClassObject(REFCLSID clsid, REFIID iid, void FAR* FAR* ppv)
+{
+ if (!IsEqualIID(iid, IID_IUnknown) && !IsEqualIID(iid, IID_IClassFactory))
+ {
+ return E_NOINTERFACE;
+ }
+
+ if (IsEqualIID(clsid, CLSID_ITest))
+ {
+ *ppv = new CCMarshalCF();
+ return S_OK;
+ }
+
+ return E_FAIL;
+}
+
+
+STDAPI DllCanUnloadNow(void)
+{
+ return S_FALSE;
+}
+
+
diff --git a/private/oleutest/cmarshal/cmarshal/makefile b/private/oleutest/cmarshal/cmarshal/makefile
new file mode 100644
index 000000000..9baa61272
--- /dev/null
+++ b/private/oleutest/cmarshal/cmarshal/makefile
@@ -0,0 +1,13 @@
+############################################################################
+#
+# Copyright (C) 1992, Microsoft Corporation.
+#
+# All rights reserved.
+#
+############################################################################
+
+default: all
+!include filelist.mk
+!include $(COMMON)\src\win40.mk
+!include depend.mk
+
diff --git a/private/oleutest/cmarshal/idl/filelist.mk b/private/oleutest/cmarshal/idl/filelist.mk
new file mode 100644
index 000000000..29eeaf9e5
--- /dev/null
+++ b/private/oleutest/cmarshal/idl/filelist.mk
@@ -0,0 +1,81 @@
+############################################################################
+#
+# Copyright (C) 1992, Microsoft Corporation.
+#
+# 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 = itest.dll
+
+TARGET_DESCRIPTION = "$(PLATFORM) $(BUILDTYPE) Proxy for IBalls ICube interfaces"
+
+COFFBASE = piballs
+
+RELEASE =
+
+
+ITFFILES =
+
+#
+# Source files. Remember to prefix each name with .\
+#
+
+IDLFILES = .\itest.idl
+
+
+CXXFILES = \
+ .\itest_c.cxx \
+ .\itest_s.cxx \
+ .\itest_p.cxx
+
+CFILES = .\itest_i.c
+
+OBJFILES = \
+ $(COMMON)\types\$(OBJDIR)\unknwn_i.obj \
+ $(COMMON)\types\$(OBJDIR)\classf_i.obj \
+ $(COMMON)\types\$(OBJDIR)\psfbuf_i.obj \
+ $(COMMON)\types\$(OBJDIR)\proxyb_i.obj \
+ $(COMMON)\types\$(OBJDIR)\stubb_i.obj \
+ $(COMMON)\types\$(OBJDIR)\rchanb_i.obj \
+ $(COMMON)\types\$(OBJDIR)\marshl_i.obj \
+ $(COMMON)\types\$(OBJDIR)\stdrpc.obj \
+ $(COMMON)\types\$(OBJDIR)\stdclass.obj \
+ $(COMMON)\types\$(OBJDIR)\pch.obj
+
+RCFILES =
+
+CDLFILES =
+
+
+#
+# Libraries and other object files to link.
+#
+
+DEFFILE = prxydll.def
+
+LIBS = $(CAIROLIB) \
+ $(RPCLIBS) \
+
+
+
+#
+# Precompiled headers.
+#
+
+PXXFILE = .\pch.cxx
+PFILE =
+
+CINC = -I. -DUNICODE
+
+
+CLEANFILES = $(HSOURCES) $(CFILES)
+
+CLEANTARGET = $(OBJDIR)
+
diff --git a/private/oleutest/cmarshal/idl/itest.idl b/private/oleutest/cmarshal/idl/itest.idl
new file mode 100644
index 000000000..630f9a734
--- /dev/null
+++ b/private/oleutest/cmarshal/idl/itest.idl
@@ -0,0 +1,38 @@
+//[ ITest_itf
+//+-------------------------------------------------------------------
+//
+// Interface: ITest (ib)
+//
+// Purpose: Interface for manipulating performance
+//
+// History: 5-Oct-93 AlexMit Created
+//
+// Notes:
+//
+//--------------------------------------------------------------------
+
+[ object,
+
+ uuid(60000494-AB0F-101A-B4AE-08002B30612C),
+ pointer_default(unique) ]
+
+interface ITest : IUnknown
+{
+ import "unknwn.idl";
+
+ DWORD die ( [in] ITest *, [in] ULONG, [in] ULONG, [in] ULONG );
+ HRESULT die_cpp ( [in] ULONG );
+ HRESULT die_nt ( [in] ULONG );
+ DWORD DoTest ( [in] ITest *, [in] ITest * );
+ BOOL hello ();
+ HRESULT interrupt( [in] ITest *, BOOL );
+ HRESULT recurse ( [in] ITest *, [in] ULONG );
+ HRESULT recurse_interrupt ( [in] ITest *, [in] ULONG );
+ HRESULT sick ( [in] ULONG );
+ HRESULT sleep ( [in] ULONG );
+
+}
+
+//]
+
+ \ No newline at end of file
diff --git a/private/oleutest/cmarshal/idl/makefile b/private/oleutest/cmarshal/idl/makefile
new file mode 100644
index 000000000..6a490bebc
--- /dev/null
+++ b/private/oleutest/cmarshal/idl/makefile
@@ -0,0 +1,17 @@
+############################################################################
+#
+# Copyright (C) 1992, Microsoft Corporation.
+#
+# All rights reserved.
+#
+############################################################################
+
+default: all
+!include filelist.mk
+!include $(COMMON)\src\win40.mk
+
+MIDL=$(TOOLPATH)\midl76.exe
+
+all: $(OBJS)
+
+!include depend.mk
diff --git a/private/oleutest/cmarshal/idl/pch.cxx b/private/oleutest/cmarshal/idl/pch.cxx
new file mode 100644
index 000000000..984d8d2bf
--- /dev/null
+++ b/private/oleutest/cmarshal/idl/pch.cxx
@@ -0,0 +1,18 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1991 - 1992.
+//
+// File: PCH.CXX
+//
+// Contents: Precompiled header
+//
+// History: 12-Jul-93 ShannonC Created
+//
+//--------------------------------------------------------------------------
+
+#include "stdrpc.hxx"
+#pragma hdrstop
+
+
+
diff --git a/private/oleutest/cmarshal/idl/prxydll.def b/private/oleutest/cmarshal/idl/prxydll.def
new file mode 100644
index 000000000..e09e1ce91
--- /dev/null
+++ b/private/oleutest/cmarshal/idl/prxydll.def
@@ -0,0 +1,47 @@
+#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 ITEST
+
+DESCRIPTION 'Microsoft (R) OLE 2.0 Proxy/Stub DLL 1.00'
+
+EXPORTS
+
+#if defined(i386)
+
+ DllGetClassObject=DllGetClassObject@12 @1
+ DllCanUnloadNow=DllCanUnloadNow@0 @2
+
+#elif defined(_MIPS_)
+
+ DllGetClassObject @1
+ DllCanUnloadNow @2
+
+#endif // i386 - MIPS
+
+#endif // FLAT
diff --git a/private/oleutest/cmarshal/idl/test.reg b/private/oleutest/cmarshal/idl/test.reg
new file mode 100644
index 000000000..4a67b2593
--- /dev/null
+++ b/private/oleutest/cmarshal/idl/test.reg
@@ -0,0 +1,26 @@
+
+; registry entries for ITest interface. these map the interfaces
+; to the proxy/stub code in itest.dll
+
+
+\Registry\MACHINE\SOFTWARE\Classes\Interface\{60000494-AB0F-101A-B4AE-08002B30612C}
+ = ITest
+\Registry\MACHINE\SOFTWARE\Classes\Interface\{60000494-AB0F-101A-B4AE-08002B30612C}\ProxyStubClsid
+ = {60000494-AB0F-101A-B4AE-08002B30612C}
+
+\Registry\MACHINE\SOFTWARE\Classes\CLSID\{60000494-AB0F-101A-B4AE-08002B30612C}
+ = CPrxyITest
+\Registry\MACHINE\SOFTWARE\Classes\CLSID\{60000494-AB0F-101A-B4AE-08002B30612C}\InprocServer
+ = itest.dll
+
+\Registry\MACHINE\SOFTWARE\Classes\CLSID\{60000430-AB0F-101A-B4AE-08002B30612C}
+ = CTestCF
+\Registry\MACHINE\SOFTWARE\Classes\CLSID\{60000430-AB0F-101A-B4AE-08002B30612C}\LocalServer
+ = app.exe
+\Registry\MACHINE\SOFTWARE\Classes\CLSID\{60000430-AB0F-101A-B4AE-08002B30612C}\InprocServer
+ = cmarshal.dll
+
+
+
+
+ \ No newline at end of file
diff --git a/private/oleutest/common/com.hxx b/private/oleutest/common/com.hxx
new file mode 100644
index 000000000..fe8a8e8c2
--- /dev/null
+++ b/private/oleutest/common/com.hxx
@@ -0,0 +1,18 @@
+#ifndef __COM_HXX__
+#define __COM_HXX__
+
+static GUID CLSID_BasicBnd =
+ {0x99999999,0x0000,0x0008,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x49}};
+
+static GUID CLSID_AdvBnd =
+ {0x99999999,0x0000,0x0008,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x48}};
+
+static GUID CLSID_TestEmbed =
+ {0x99999999,0x0000,0x0008,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x47}};
+
+inline GuidEqual(const GUID& guid1, const GUID& guid2)
+{
+ return memcmp(&guid1, &guid2, sizeof(GUID)) == 0;
+}
+
+#endif // __COM_HXX__
diff --git a/private/oleutest/common/oleport.h b/private/oleutest/common/oleport.h
new file mode 100644
index 000000000..8a115cd81
--- /dev/null
+++ b/private/oleutest/common/oleport.h
@@ -0,0 +1,50 @@
+#ifndef __OLEPORT_H__
+#define __OLEPORT_H__
+
+#include <string.h>
+#include <stdlib.h>
+
+#ifdef __cplusplus
+// BUGBUG: This definition is here to ease porting. In the future
+// it s/b removed to use the single official definition along
+// with all the changes that will be required in the code.
+#define GUID_DEFINED
+
+struct GUID
+{
+ unsigned long Data1;
+ unsigned short Data2;
+ unsigned short Data3;
+ unsigned char Data4[8];
+
+ int operator==(const GUID& iidOther) const
+ { return !memcmp(&Data1, &iidOther.Data1, sizeof(GUID)); }
+
+ int operator!=(const GUID& iidOther) const
+ { return !((*this) == iidOther); }
+};
+#endif // __cplusplus
+
+#include <windows.h>
+
+// Handle port problems easily
+#define WIN32
+
+#ifdef _NTIDW340
+#ifdef __cplusplus
+#define jmp_buf int
+#endif // __cplusplus
+#endif // _NTIDW340
+
+// PORT: HTASK no longer seems to be defined in Win32
+#define HTASK DWORD
+#define HINSTANCE_ERROR 32
+#define __loadds
+#define __segname
+#define BASED_CODE
+#define HUGE
+#define _ffree free
+#define __based(x)
+#include <port1632.h>
+
+#endif // __OLEPORT_H__
diff --git a/private/oleutest/daytona.inc b/private/oleutest/daytona.inc
new file mode 100644
index 000000000..1e7c175a8
--- /dev/null
+++ b/private/oleutest/daytona.inc
@@ -0,0 +1,26 @@
+# This is the global include file for the daytona version of CairOLE.
+# It is included by all project sources files.
+
+C_DEFINES= \
+ $(C_DEFINES) \
+ -DFLAT \
+ -DWIN32=100 \
+ -D_NT1X_=100 \
+ -DUNICODE \
+ -D_UNICODE \
+ -DINC_OLE2 \
+ -DNOEXCEPTIONS \
+ -DCAIROLE_DOWNLEVEL \
+ -DMULTI_THREADING \
+ $(TRACELOG)
+
+
+BLDCRT= 1
+
+# For the Daytona build, we do not want statically linked compiler runtimes,
+# so leave this commented out.
+#
+# USE_LIBCMT= 1
+
+
+USE_CRTDLL=1
diff --git a/private/oleutest/dirs b/private/oleutest/dirs
new file mode 100644
index 000000000..c4ca576f1
--- /dev/null
+++ b/private/oleutest/dirs
@@ -0,0 +1,50 @@
+!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) 22-Jan-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= \
+ act \
+ assert \
+ oledll2 \
+ dll \
+ olebind \
+ server1 \
+ server2 \
+ server3 \
+ stgdrt \
+ letest \
+ simpdnd \
+ simpsvr \
+ simpcntr \
+ uthread \
+ oletest
+
+#
+# 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=
diff --git a/private/oleutest/dll/daytona/makefile b/private/oleutest/dll/daytona/makefile
new file mode 100644
index 000000000..1d3728d41
--- /dev/null
+++ b/private/oleutest/dll/daytona/makefile
@@ -0,0 +1,10 @@
+############################################################################
+#
+# Copyright (C) 1992, Microsoft Corporation.
+#
+# All rights reserved.
+#
+############################################################################
+
+!include $(NTMAKEENV)\makefile.def
+
diff --git a/private/oleutest/dll/daytona/makefile.inc b/private/oleutest/dll/daytona/makefile.inc
new file mode 100644
index 000000000..071024ed2
--- /dev/null
+++ b/private/oleutest/dll/daytona/makefile.inc
@@ -0,0 +1 @@
+obj\i386\oleimpl.def: oleimpl.src
diff --git a/private/oleutest/dll/daytona/oleimpl.src b/private/oleutest/dll/daytona/oleimpl.src
new file mode 100644
index 000000000..9805be702
--- /dev/null
+++ b/private/oleutest/dll/daytona/oleimpl.src
@@ -0,0 +1,37 @@
+#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 oleimpl
+
+DESCRIPTION 'OLEIMPL'
+
+EXPORTS
+ DllGetClassObject PRIVATE
+ DllCanUnloadNow PRIVATE
+
+#endif // FLAT
diff --git a/private/oleutest/dll/daytona/sources b/private/oleutest/dll/daytona/sources
new file mode 100644
index 000000000..9fef44e10
--- /dev/null
+++ b/private/oleutest/dll/daytona/sources
@@ -0,0 +1,109 @@
+!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:
+
+ Donna Liu (DonnaLi) 19-Dec-1993
+
+!ENDIF
+
+MAJORCOMP = cairole
+MINORCOMP = com
+
+# This links against oleutest\assert which is built before this directory.
+# So we block here and collect our threads to assure that "assert" is
+# finished building.
+# Blocking here also allows "olebind", "Server1", "Server2" and
+# "Server3", which also need "assert", to build without SYNCHRONZATION.
+
+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= oleimpl
+
+#
+# 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= DYNLINK
+
+DLLDEF= obj\*\oleimpl.def
+
+DLLBASE=@$(BASEDIR)\PUBLIC\SDK\LIB\coffbase.txt,usermode
+
+INCLUDES= ..\..\..\ole32\common\daytona;..\..\..\ole32\ih;..;..\..\common
+
+C_DEFINES= \
+ $(C_DEFINES) \
+ -DFLAT \
+ -DWIN32=100 \
+ -D_NT1X_=100 \
+ -DUNICODE \
+ -D_UNICODE \
+ -DINC_OLE2 \
+ -DNOEXCEPTIONS \
+ -DCAIROLE_DOWNLEVEL
+
+BLDCRT= 1
+
+SOURCES= \
+ ..\oleimpl.cxx \
+ ..\iclisite.cxx
+
+DLLENTRY=_DllMainCRTStartup
+
+UMTYPE= windows
+UMAPPL=
+UMTEST=
+LINKER_FLAGS=-verbose
+LINKLIBS= \
+ ..\..\assert\daytona\obj\*\assert.lib \
+ ..\..\oledll2\daytona\obj\*\oledll2.lib \
+ $(BASEDIR)\public\sdk\lib\*\uuid.lib \
+ $(BASEDIR)\public\sdk\lib\*\ole32.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\*\crtdll.lib
+
+USE_CRTDLL= 1
+
+!IF $(386)
+NTTARGETFILE0=$(DLLDEF:*=i386)
+!ENDIF
+
+!IF $(MIPS)
+NTTARGETFILE0=$(DLLDEF:*=mips)
+!ENDIF
+
+!IF $(ALPHA)
+NTTARGETFILE0=$(DLLDEF:*=alpha)
+!ENDIF
diff --git a/private/oleutest/dll/dirs b/private/oleutest/dll/dirs
new file mode 100644
index 000000000..1d0b9edbb
--- /dev/null
+++ b/private/oleutest/dll/dirs
@@ -0,0 +1,38 @@
+!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/dll/iclisite.cxx b/private/oleutest/dll/iclisite.cxx
new file mode 100644
index 000000000..f168e1e35
--- /dev/null
+++ b/private/oleutest/dll/iclisite.cxx
@@ -0,0 +1,108 @@
+//+-------------------------------------------------------------
+// File: iclisite.cxx
+//
+// Contents: CObjClientSite object implementation
+//
+// Methods: CObjClientSite
+// ~CObjClientSite
+// Create
+// QueryInterface
+// AddRef
+// Release
+// SaveObject (NYI)
+// GetMoniker (NYI)
+// GetContainer
+// ShowObject (NYI)
+// OnShowWindow
+//
+// History: 04-Dec-92 Created DeanE
+//---------------------------------------------------------------
+#pragma optimize("",off)
+#include <windows.h>
+#include <ole2.h>
+#include <com.hxx>
+#include "oleimpl.hxx"
+
+//+-------------------------------------------------------------------
+// Method: CBasicBnd::SaveObject
+//
+// Synopsis: See spec 2.00.09 p107. This object should be saved.
+//
+// Returns: Should always return S_OK.
+//
+// History: 04-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP CBasicBnd::SaveObject(void)
+{
+ // BUGBUG - NYI
+ // Returning S_OK tells OLE that we actually saved this object
+ return(S_OK);
+}
+
+
+//+-------------------------------------------------------------------
+// Method: CBasicBnd::GetContainer
+//
+// Synopsis: See spec 2.00.09 p108. Return the container in which
+// this object is found.
+//
+// Returns: Should return S_OK.
+//
+// History: 04-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP CBasicBnd::GetContainer(LPOLECONTAINER FAR *ppContainer)
+{
+ return QueryInterface(IID_IOleContainer, (void **) ppContainer);
+}
+
+
+//+-------------------------------------------------------------------
+// Method: CBasicBnd::ShowObject
+//
+// Synopsis: See spec 2.00.09 p109. Server for this object is asking
+// us to display it. Caller should not assume we have
+// actually worked, but we return S_OK either way. Great!
+//
+// Returns: S_OK whether we work or not...
+//
+// History: 04-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP CBasicBnd::ShowObject(void)
+{
+ return(S_OK);
+}
+
+
+//+-------------------------------------------------------------------
+// Method: CBasicBnd::OnShowWindow
+//
+// Synopsis: ???
+//
+// Parameters: [fShow] -
+//
+// Returns: S_OK?
+//
+// History: 16-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP CBasicBnd::OnShowWindow(BOOL fShow)
+{
+ return(S_OK);
+}
+
+
+
+//+-------------------------------------------------------------------
+// Method: CBasicBnd::RequestNewObjectLayout
+//
+// Synopsis: ???
+//
+// Parameters: [fShow] -
+//
+// Returns: S_OK?
+//
+// History: 16-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP CBasicBnd::RequestNewObjectLayout(void)
+{
+ return(S_OK);
+}
diff --git a/private/oleutest/dll/oleimpl.cxx b/private/oleutest/dll/oleimpl.cxx
new file mode 100644
index 000000000..018e3d402
--- /dev/null
+++ b/private/oleutest/dll/oleimpl.cxx
@@ -0,0 +1,898 @@
+//+-------------------------------------------------------------------
+//
+// File: oleimpl.cxx
+//
+// Contents: This file contins the DLL entry points
+// LibMain
+// DllGetClassObject (Bindings key func)
+// CBasicBndCF (class factory)
+// CBasicBnd (actual class implementation)
+//
+// Classes: CBasicBndCF, CBasicBnd
+//
+//
+// History: 30-Nov-92 SarahJ Created
+// 31-Dec-93 ErikGav Chicago port
+// 30-Jun-94 AndyH Add call to another DLL
+//
+//---------------------------------------------------------------------
+
+// Turn off ole Cairol IUnknown
+#include <windows.h>
+#include <ole2.h>
+#include <debnot.h>
+#include <com.hxx>
+#include "oleimpl.hxx"
+extern "C" {
+#include "..\oledll2\oledll2.h"
+}
+
+ULONG g_UseCount = 0;
+
+CBasicBndCF *g_pcf = NULL;
+
+static const char *szFatalError = "OLEIMPL.DLL - Fatal Error";
+
+void MsgBox(char *pszMsg)
+{
+ MessageBoxA(NULL, pszMsg, szFatalError, MB_OK);
+}
+
+void HrMsgBox(char *pszMsg, HRESULT hr)
+{
+ char awcBuf[512];
+
+ // Build string for output
+ wsprintfA(awcBuf, "%s HRESULT = %lx", pszMsg, hr);
+
+ // Display message box
+ MessageBoxA(NULL, &awcBuf[0], szFatalError, MB_OK);
+}
+
+
+//+-------------------------------------------------------------------
+//
+// Function: LibMain
+//
+// Synopsis: Entry point to DLL - does little else
+// Added call to anther DLL. This is to test loading of in
+// InProcServer that uses another statically linked DLL.
+// The extra DLL (OleDll2.DLL) should not be on the path
+// when the test is run. The entry point FuntionInAnotherDLL
+// is exported by OleDll2.DLL
+//
+// Arguments:
+//
+// Returns: TRUE
+//
+// History: 21-Nov-92 SarahJ Created
+//
+//--------------------------------------------------------------------
+
+
+
+//
+// Entry point to DLL is traditional LibMain
+// Call FunctionInAnotherDLL().
+//
+
+
+extern "C" BOOL _cdecl LibMain ( HINSTANCE hinst,
+ HANDLE segDS,
+ UINT cbHeapSize,
+ LPTSTR lpCmdLine)
+{
+ FunctionInAnotherDLL();
+ return TRUE;
+}
+
+
+//+-------------------------------------------------------------------
+//
+// Function: DllGetClassObject
+//
+// Synopsis: Called by client (from within BindToObject et al)
+// interface requested should be IUnknown or IClassFactory -
+// Creates ClassFactory object and returns pointer to it
+//
+// Arguments: REFCLSID clsid - class id
+// REFIID iid - interface id
+// void FAR* FAR* ppv- pointer to class factory interface
+//
+// Returns: TRUE
+//
+// History: 21-Nov-92 SarahJ Created
+//
+//--------------------------------------------------------------------
+
+
+STDAPI DllGetClassObject(REFCLSID clsid, REFIID iid, void FAR* FAR* ppv)
+{
+ if (!GuidEqual(iid, IID_IUnknown) && !GuidEqual(iid, IID_IClassFactory))
+ {
+ return E_NOINTERFACE;
+ }
+
+ if (GuidEqual(clsid, CLSID_BasicBnd))
+ {
+ if (g_pcf)
+ {
+ *ppv = g_pcf;
+ g_pcf->AddRef();
+ }
+ else
+ {
+ *ppv = new CBasicBndCF();
+ }
+
+ return (*ppv != NULL) ? S_OK : E_FAIL;
+ }
+
+ return E_FAIL;
+}
+
+
+STDAPI DllCanUnloadNow(void)
+{
+ return (g_UseCount == 0)
+ ? S_OK
+ : S_FALSE;
+}
+
+//+-------------------------------------------------------------------
+//
+// Class: CBasicBndCF
+//
+// Synopsis: Class Factory for CBasicBnd
+//
+// Interfaces: IUnknown - QueryInterface, AddRef, Release
+// IClassFactory - CreateInstance
+//
+// History: 21-Nov-92 SarahJ Created
+//
+//--------------------------------------------------------------------
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CBasicBndCF::CBasicBndCF()
+//
+// Synopsis: The constructor for CBAsicBnd.
+//
+// Arguments: None
+//
+// History: 21-Nov-92 SarahJ Created
+//
+//--------------------------------------------------------------------
+
+CBasicBndCF::CBasicBndCF() : _cRefs(1)
+{
+ g_UseCount++;
+}
+
+//+-------------------------------------------------------------------
+//
+// Member: CBasicBnd::~CBasicBndObj()
+//
+// Synopsis: The destructor for CBAsicBnd.
+//
+// History: 21-Nov-92 SarahJ Created
+//
+//--------------------------------------------------------------------
+
+CBasicBndCF::~CBasicBndCF()
+{
+ g_UseCount--;
+ return;
+}
+
+
+//+-------------------------------------------------------------------
+//
+// Method: CBasicBndCF::QueryInterface
+//
+// Synopsis: Only IUnknown and IClassFactory supported
+//
+//--------------------------------------------------------------------
+
+
+STDMETHODIMP CBasicBndCF::QueryInterface(REFIID iid, void FAR * FAR * ppv)
+{
+ if (GuidEqual(iid, IID_IUnknown) || GuidEqual(iid, IID_IClassFactory))
+ {
+ *ppv = this;
+ AddRef();
+ return S_OK;
+ }
+ else
+ {
+ *ppv = NULL;
+ return E_NOINTERFACE;
+ }
+}
+
+STDMETHODIMP_(ULONG) CBasicBndCF::AddRef(void)
+{
+ return ++_cRefs;
+}
+
+STDMETHODIMP_(ULONG) CBasicBndCF::Release(void)
+{
+ ULONG cRefs = --_cRefs;
+
+ if (cRefs == 0)
+ {
+ delete this;
+ }
+
+ return cRefs;
+}
+
+
+
+//+-------------------------------------------------------------------
+//
+// Method: CBasicBndCF::CreateInstance
+//
+// Synopsis: This is called by Binding process to create the
+// actual class object
+//
+//--------------------------------------------------------------------
+STDMETHODIMP CBasicBndCF::CreateInstance(IUnknown FAR* pUnkOuter,
+ REFIID iidInterface,
+ void FAR* FAR* ppv)
+{
+ HRESULT hresult = S_OK;
+
+ class CUnknownBasicBnd *pubb = new FAR CUnknownBasicBnd(pUnkOuter);
+
+ if (pubb == NULL)
+ {
+ return E_OUTOFMEMORY;
+ }
+
+ // Because when an aggregate is being requested, the controlling
+ // must be returned, no QI is necessary.
+ if (pUnkOuter == NULL)
+ {
+ hresult = pubb->QueryInterface(iidInterface, ppv);
+
+ pubb->Release();
+ }
+ else
+ {
+ *ppv = (void *) pubb;
+ }
+
+ return hresult;
+}
+
+//+-------------------------------------------------------------------
+//
+// Method: CBasicBndCF::LockServer
+//
+// Synopsis: Who knows what this is for?
+//
+//--------------------------------------------------------------------
+
+STDMETHODIMP CBasicBndCF::LockServer(BOOL fLock)
+{
+ return E_FAIL;
+}
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CBasicBnd::CBasicBnd()
+//
+// Synopsis: The constructor for CBAsicBnd. I
+//
+// Arguments: None
+//
+// History: 21-Nov-92 SarahJ Created
+//
+//--------------------------------------------------------------------
+
+CBasicBnd::CBasicBnd(IUnknown *punk)
+ : _punk(punk), _pmkContainer(NULL)
+{
+ // Create storage for "contained" objects
+ SCODE sc = StgCreateDocfile(NULL,
+ STGM_DELETEONRELEASE|STGM_DFRALL|STGM_CREATE, 0, &_psStg1);
+
+ if (sc != S_OK)
+ {
+ HrMsgBox("CBasicBnd::CBasicBnd Create of first storage failed", sc);
+ }
+
+ sc = StgCreateDocfile(NULL,
+ STGM_DELETEONRELEASE|STGM_DFRALL|STGM_CREATE, 0, &_psStg2);
+
+ if (sc != S_OK)
+ {
+ HrMsgBox("CBasicBnd::CBasicBnd Create of second storage failed", sc);
+ }
+}
+
+//+-------------------------------------------------------------------
+//
+// Member: CBasicBnd::~CBasicBndObj()
+//
+// Synopsis: The destructor for CBAsicBnd.
+//
+// History: 21-Nov-92 SarahJ Created
+//
+//--------------------------------------------------------------------
+
+CBasicBnd::~CBasicBnd()
+{
+ if (_pmkContainer)
+ {
+ _pmkContainer->Release();
+ }
+
+ if (_psStg1)
+ {
+ _psStg1->Release();
+ }
+
+ if (_psStg2)
+ {
+ _psStg2->Release();
+ }
+
+ return;
+}
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CBasicBnd::QueryInterface
+//
+// Returns: S_OK
+//
+// History: 21-Nov-92 SarahJ Created
+//
+//--------------------------------------------------------------------
+
+
+STDMETHODIMP CBasicBnd::QueryInterface(REFIID iid, void **ppiuk)
+{
+ return _punk->QueryInterface(iid, ppiuk);
+}
+
+//+-------------------------------------------------------------------
+//
+// Member: CBasicBnd::AddRef
+//
+// Synopsis: Standard stuff
+//
+// History: 21-Nov-92 SarahJ Created
+//
+//--------------------------------------------------------------------
+STDMETHODIMP_(ULONG) CBasicBnd::AddRef(void)
+{
+ return _punk->AddRef();
+}
+
+//+-------------------------------------------------------------------
+//
+// Member: CBasicBnd::Release
+//
+// Synopsis: Standard stuff
+//
+// History: 21-Nov-92 SarahJ Created
+//
+//--------------------------------------------------------------------
+
+STDMETHODIMP_(ULONG) CBasicBnd::Release(void)
+{
+ return _punk->Release();
+}
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CBasicBnd::Load
+//
+// Synopsis: IPeristFile interface - needed 'cause we bind with
+// file moniker and BindToObject insists on calling this
+//
+// History: 21-Nov-92 SarahJ Created
+//
+//--------------------------------------------------------------------
+STDMETHODIMP CBasicBnd::Load(LPCWSTR lpszFileName, DWORD grfMode)
+{
+ if (grfMode & ~(STGM_READWRITE | STGM_SHARE_EXCLUSIVE))
+ {
+ // Test requires default bind storage request and caller
+ // has set some other bits so we fail.
+ return STG_E_INVALIDPARAMETER;
+ }
+
+ return S_OK;
+}
+
+//+-------------------------------------------------------------------
+//
+// Member: CBasicBnd::Save
+//
+// Synopsis: IPeristFile interface - save
+// does little but here for commentry
+//
+// History: 21-Nov-92 SarahJ Created
+//
+//--------------------------------------------------------------------
+STDMETHODIMP CBasicBnd::Save(LPCWSTR lpszFileName, BOOL fRemember)
+{
+ return S_OK;
+}
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CBasicBnd::SaveCpmpleted
+// CBasicBnd::GetCurFile
+// CBasicBnd::IsDirty
+//
+// Synopsis: More IPeristFile interface methods
+//
+// History: 21-Nov-92 SarahJ Created
+//
+//--------------------------------------------------------------------
+STDMETHODIMP CBasicBnd::SaveCompleted(LPCWSTR lpszFileName)
+{
+ return S_OK;
+}
+
+STDMETHODIMP CBasicBnd::GetCurFile(LPWSTR FAR *lpszFileName)
+{
+ return S_OK;
+}
+
+STDMETHODIMP CBasicBnd::IsDirty()
+{
+ return S_OK;
+}
+
+//+-------------------------------------------------------------------
+//
+// Interface: IPersist
+//
+// Synopsis: IPersist interface methods
+// Need to return a valid class id here
+//
+// History: 21-Nov-92 SarahJ Created
+//
+
+STDMETHODIMP CBasicBnd::GetClassID(LPCLSID classid)
+{
+ *classid = CLSID_BasicBnd;
+ return S_OK;
+}
+
+// *** IOleObject methods ***
+STDMETHODIMP CBasicBnd::SetClientSite(LPOLECLIENTSITE pClientSite)
+{
+ return E_FAIL;
+}
+
+STDMETHODIMP CBasicBnd::GetClientSite(LPOLECLIENTSITE FAR* ppClientSite)
+{
+ return E_FAIL;
+}
+
+
+STDMETHODIMP CBasicBnd::SetHostNames(
+ LPCWSTR szContainerApp,
+ LPCWSTR szContainerObj)
+{
+ return E_FAIL;
+}
+
+STDMETHODIMP CBasicBnd::Close(DWORD dwSaveOption)
+{
+ return E_FAIL;
+}
+
+STDMETHODIMP CBasicBnd::SetMoniker(DWORD dwWhichMoniker, LPMONIKER pmk)
+{
+ if (_pmkContainer)
+ {
+ _pmkContainer->Release();
+
+ }
+
+ _pmkContainer = pmk;
+
+ pmk->AddRef();
+
+ return S_OK;
+}
+
+STDMETHODIMP CBasicBnd::GetMoniker(
+ DWORD dwAssign,
+ DWORD dwWhichMoniker,
+ LPMONIKER FAR* ppmk)
+{
+ if (_pmkContainer != NULL)
+ {
+ *ppmk = _pmkContainer;
+ _pmkContainer->AddRef();
+ return S_OK;
+ }
+
+ return E_FAIL;
+}
+
+STDMETHODIMP CBasicBnd::InitFromData(
+ LPDATAOBJECT pDataObject,
+ BOOL fCreation,
+ DWORD dwReserved)
+{
+ return E_FAIL;
+}
+
+STDMETHODIMP CBasicBnd::GetClipboardData(
+ DWORD dwReserved,
+ LPDATAOBJECT FAR* ppDataObject)
+{
+ return E_FAIL;
+}
+
+STDMETHODIMP CBasicBnd::DoVerb(
+ LONG iVerb,
+ LPMSG lpmsg,
+ LPOLECLIENTSITE pActiveSite,
+ LONG reserved,
+ HWND hwndParent,
+ LPCRECT lprcPosRect)
+{
+ return E_FAIL;
+}
+
+STDMETHODIMP CBasicBnd::EnumVerbs(IEnumOLEVERB FAR* FAR* ppenumOleVerb)
+{
+ return E_FAIL;
+}
+
+STDMETHODIMP CBasicBnd::Update(void)
+{
+ return E_FAIL;
+}
+
+STDMETHODIMP CBasicBnd::IsUpToDate(void)
+{
+ return E_FAIL;
+}
+
+STDMETHODIMP CBasicBnd::GetUserClassID(CLSID FAR* pClsid)
+{
+ return E_FAIL;
+}
+
+STDMETHODIMP CBasicBnd::GetUserType(DWORD dwFormOfType, LPWSTR FAR* pszUserType)
+{
+ return E_FAIL;
+}
+
+STDMETHODIMP CBasicBnd::SetExtent(DWORD dwDrawAspect, LPSIZEL lpsizel)
+{
+ return E_FAIL;
+}
+
+STDMETHODIMP CBasicBnd::GetExtent(DWORD dwDrawAspect, LPSIZEL lpsizel)
+{
+ return E_FAIL;
+}
+
+STDMETHODIMP CBasicBnd::Advise(
+ IAdviseSink FAR* pAdvSink,
+ DWORD FAR* pdwConnection)
+{
+ return E_FAIL;
+}
+
+STDMETHODIMP CBasicBnd::Unadvise(DWORD dwConnection)
+{
+ return E_FAIL;
+}
+
+STDMETHODIMP CBasicBnd::EnumAdvise(LPENUMSTATDATA FAR* ppenumAdvise)
+{
+ return E_FAIL;
+}
+
+STDMETHODIMP CBasicBnd::GetMiscStatus(DWORD dwAspect, DWORD FAR* pdwStatus)
+{
+ return E_FAIL;
+}
+
+STDMETHODIMP CBasicBnd::SetColorScheme(LPLOGPALETTE lpLogpal)
+{
+ return E_FAIL;
+}
+
+// *** IParseDisplayName method ***
+STDMETHODIMP CBasicBnd::ParseDisplayName(
+ LPBC pbc,
+ LPWSTR lpszDisplayName,
+ ULONG FAR* pchEaten,
+ LPMONIKER FAR* ppmkOut)
+{
+ *pchEaten = wcslen(lpszDisplayName);
+ return CreateItemMoniker(L"\\", lpszDisplayName, ppmkOut);
+}
+
+// *** IOleContainer methods ***
+STDMETHODIMP CBasicBnd::EnumObjects(
+ DWORD grfFlags,
+ LPENUMUNKNOWN FAR* ppenumUnknown)
+{
+ return E_FAIL;
+}
+
+STDMETHODIMP CBasicBnd::LockContainer(BOOL fLock)
+{
+ return E_FAIL;
+}
+
+// *** IOleItemContainer methods ***
+STDMETHODIMP CBasicBnd::GetObject(
+ LPWSTR lpszItem,
+ DWORD dwSpeedNeeded,
+ LPBINDCTX pbc,
+ REFIID riid,
+ LPVOID FAR* ppvObject)
+{
+ IStorage *psStorage;
+ IOleObject *poo;
+ IUnknown *punk;
+
+ if (wcscmp(lpszItem, L"1") == 0)
+ {
+ psStorage = _psStg1;
+ }
+ else if (wcscmp(lpszItem, L"2") == 0)
+ {
+ psStorage = _psStg2;
+ }
+ else
+ {
+ return E_FAIL;
+ }
+
+ IOleClientSite * pocsObjCliSite;
+
+ HRESULT hresult = QueryInterface(IID_IOleClientSite,
+ (void **) &pocsObjCliSite);
+
+ // Call OleCreate to create our embedded object
+ hresult = OleCreate(
+ CLSID_TestEmbed, // Class ID of the object we are
+ // creating
+ IID_IOleObject, // Interface by which we want to talk
+ // to the object
+ OLERENDER_NONE, // We don't want to draw the object
+ // when it is not active
+ NULL, // Used if we do draw the object when
+ // it is non-active
+ pocsObjCliSite, // IOleClientSite the server will use
+ psStorage, // IStorage the server will use
+ (void **) &poo); // Pointer to the object
+
+ if (FAILED(hresult))
+ {
+ HrMsgBox("CBasicBnd::GetObject OlCreate Failed!", hresult);
+ return hresult;
+ }
+
+ // Set the client site
+ hresult = poo->SetClientSite(pocsObjCliSite);
+
+ if (FAILED(hresult))
+ {
+ HrMsgBox("CBasicBnd::GetObject SetClientSite failed!", hresult);
+ return hresult;
+ }
+
+ hresult = poo->QueryInterface(IID_IUnknown, (void **)&punk);
+
+ if (FAILED(hresult))
+ {
+ HrMsgBox("CBasicBnd::GetObject QI to IUnknown failed!", hresult);
+ return hresult;
+ }
+
+ hresult = OleRun(punk);
+
+ if (FAILED(hresult))
+ {
+ HrMsgBox("CBasicBnd::GetObject OleRun failed!", hresult);
+ return hresult;
+ }
+
+ punk->Release();
+
+ LPRECT lprPosRect = (LPRECT) new RECT;
+
+ hresult = poo->DoVerb(
+ OLEIVERB_SHOW, // Verb we are invoking
+ NULL, // MSG that causes us to do this verb
+ pocsObjCliSite, // Client site of this object
+ 0, // Reserved - definitive value?
+ 0, // hwndParent - ???
+ lprPosRect); // lprcPosRect - rectangle wrt hwndParent
+
+ if (FAILED(hresult))
+ {
+ HrMsgBox("CBasicBnd::GetObject DoVerb failed!", hresult);
+ return hresult;
+ }
+
+ delete lprPosRect;
+
+ pocsObjCliSite->Release();
+
+ *ppvObject = (void *) poo;
+
+ return hresult;
+}
+
+STDMETHODIMP CBasicBnd::GetObjectStorage(
+ LPWSTR lpszItem,
+ LPBINDCTX pbc,
+ REFIID riid,
+ LPVOID FAR* ppvStorage)
+{
+ return E_FAIL;
+}
+
+STDMETHODIMP CBasicBnd::IsRunning(LPWSTR lpszItem)
+{
+ return E_FAIL;
+}
+
+CUnknownBasicBnd::CUnknownBasicBnd(IUnknown *punk)
+ : _pbasicbnd(NULL), _cRefs(1)
+{
+ if (punk == NULL)
+ {
+ punk = (IUnknown *) this;
+ }
+
+ // BUGBUG: No error checking!
+ _pbasicbnd = new CBasicBnd(punk);
+ g_UseCount++;
+}
+
+CUnknownBasicBnd::~CUnknownBasicBnd(void)
+{
+ g_UseCount--;
+ delete _pbasicbnd;
+}
+
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CUnknownBasicBnd::QueryInterface
+//
+// Returns: S_OK
+//
+// History: 21-Nov-92 SarahJ Created
+//
+//--------------------------------------------------------------------
+
+
+STDMETHODIMP CUnknownBasicBnd::QueryInterface(
+ REFIID iid,
+ void **ppiuk)
+{
+ if (GuidEqual(iid, IID_IUnknown))
+ {
+ *ppiuk = (IUnknown *) this;
+ }
+ else if (GuidEqual(iid, IID_IOleClientSite))
+ {
+ *ppiuk = (IOleClientSite *) _pbasicbnd;
+ }
+ else if (GuidEqual(iid, IID_IPersistFile)
+ || GuidEqual(iid, IID_IPersist))
+ {
+ *ppiuk = (IPersistFile *) _pbasicbnd;
+ }
+ else if (GuidEqual(iid, IID_IOleObject))
+ {
+ *ppiuk = (IOleObject *) _pbasicbnd;
+ }
+ else if (GuidEqual(iid, IID_IOleItemContainer))
+ {
+ *ppiuk = (IOleItemContainer *)_pbasicbnd;
+ }
+ else if (GuidEqual(iid, IID_IOleContainer))
+ {
+ *ppiuk = (IOleContainer *)_pbasicbnd;
+ }
+ else if (GuidEqual(iid, IID_IParseDisplayName))
+ {
+ *ppiuk = (IParseDisplayName *)_pbasicbnd;
+ }
+ else
+ {
+ *ppiuk = NULL;
+ return E_NOINTERFACE;
+ }
+
+ _pbasicbnd->AddRef();
+ return S_OK;
+}
+
+
+STDMETHODIMP_(ULONG) CUnknownBasicBnd::AddRef(void)
+{
+ return ++_cRefs;
+}
+
+STDMETHODIMP_(ULONG) CUnknownBasicBnd::Release(void)
+{
+ ULONG cRefs = --_cRefs;
+
+ if (cRefs == 0)
+ {
+ delete this;
+ }
+
+ return cRefs;
+}
+
+
+
+#ifdef CAIROLE_DOWNLEVEL
+
+extern "C"
+{
+ EXPORTDEF void APINOT
+ RegisterWithCommnot(void);
+
+ EXPORTDEF void APINOT
+ DeRegisterWithCommnot(void);
+}
+
+//+-------------------------------------------------------------------
+//
+// Function: RegisterWithCommnot
+//
+// Synopsis: Used by Cairo to work around DLL unloading problems
+//
+// Arguments: <none>
+//
+// History: 06-Oct-92 BryanT Created
+//
+//--------------------------------------------------------------------
+EXPORTIMP void APINOT
+RegisterWithCommnot( void )
+{
+}
+
+//+-------------------------------------------------------------------
+//
+// Function: DeRegisterWithCommnot
+//
+// Synopsis: Used by Cairo to work around DLL unloading problems
+//
+// Arguments: <none>
+//
+// History: 06-Oct-92 BryanT Created
+//
+// Notes: BUGBUG: Keep in touch with BryanT to see if this is
+// obsolete.
+//
+//--------------------------------------------------------------------
+
+EXPORTIMP void APINOT
+DeRegisterWithCommnot( void )
+{
+}
+
+#endif
diff --git a/private/oleutest/dll/oleimpl.hxx b/private/oleutest/dll/oleimpl.hxx
new file mode 100644
index 000000000..f472c4273
--- /dev/null
+++ b/private/oleutest/dll/oleimpl.hxx
@@ -0,0 +1,242 @@
+//+-------------------------------------------------------------------
+//
+// File: oleimpl.hxx
+//
+// Contents: This file contins the DLL entry points
+// LibMain
+// DllGetClassObject (Bindings key func)
+// DllCanUnloadNow
+// CBasicBndCF (class factory)
+// History: 30-Mar-92 SarahJ Created
+// 31-Dec-93 ErikGav Chicago port
+//
+//---------------------------------------------------------------------
+
+#ifndef __OLEIMPL_H__
+#define __OLEIMPL_H__
+
+
+#define STGM_DFRALL (STGM_READWRITE | STGM_TRANSACTED | STGM_SHARE_DENY_WRITE)
+
+//+---------------------------------------------------------------------------
+//
+// Function: operator new, public
+//
+// Synopsis: Global operator new which does not throw exceptions.
+//
+// Arguments: [size] -- Size of the memory to allocate.
+//
+// Returns: A pointer to the allocated memory. Is *NOT* initialized to 0!
+//
+// Notes: We override new to make delete easier.
+//
+//----------------------------------------------------------------------------
+
+inline void* _CRTAPI1
+operator new (size_t size)
+{
+ return(CoTaskMemAlloc(size));
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: ::operator delete
+//
+// Synopsis: Free a block of memory
+//
+// Arguments: [lpv] - block to free.
+//
+//--------------------------------------------------------------------------
+
+inline void _CRTAPI1 operator delete(void FAR* lpv)
+{
+ CoTaskMemFree(lpv);
+}
+
+
+//
+// Define the interface we are going to use here - avoiding MIDL stuff
+//
+
+//+-------------------------------------------------------------------
+//
+// Class: CBasicBndCF
+//
+// Synopsis: Class Factory for CBasicBnd
+//
+// Methods: IUnknown - QueryInterface, AddRef, Release
+// IClassFactory - CreateInstance
+//
+// History: 21-Mar-92 SarahJ Created
+//
+//--------------------------------------------------------------------
+
+
+class FAR CBasicBndCF: public IClassFactory
+{
+public:
+
+ // Constructor/Destructor
+ CBasicBndCF();
+ ~CBasicBndCF();
+
+ // IUnknown
+ STDMETHODIMP QueryInterface(REFIID iid, void FAR * FAR * ppv);
+ STDMETHODIMP_(ULONG) AddRef(void);
+ STDMETHODIMP_(ULONG) Release(void);
+
+
+ // IClassFactory
+ STDMETHODIMP CreateInstance(IUnknown FAR* pUnkOuter,
+ REFIID iidInterface,
+ void FAR* FAR* ppv);
+
+ STDMETHODIMP LockServer(BOOL fLock);
+
+ BOOL ReleaseClass(void);
+
+private:
+
+ ULONG _cRefs;
+};
+
+
+
+//+-------------------------------------------------------------------
+//
+// Class: CBasicBnd
+//
+// Synopsis: Test class CBasicBnd
+//
+// Methods:
+//
+// History: 21-Mar-92 SarahJ Created
+//
+//--------------------------------------------------------------------
+
+
+class FAR CBasicBnd: public IPersistFile, public IOleClientSite,
+ public IOleObject, public IOleItemContainer
+{
+public:
+// Constructor/Destructor
+ CBasicBnd(IUnknown *punk);
+ ~CBasicBnd();
+
+// IUnknown
+ STDMETHODIMP QueryInterface(REFIID iid, void FAR * FAR * ppv);
+ STDMETHODIMP_(ULONG) AddRef(void);
+ STDMETHODIMP_(ULONG) Release(void);
+
+// IPersist - needed 'cause IPersistFile inherits from this
+ STDMETHODIMP GetClassID(LPCLSID lpClassID);
+
+
+// IPersitFile
+ STDMETHODIMP IsDirty();
+ STDMETHODIMP Load(LPCWSTR lpszFileName, DWORD grfMode);
+ STDMETHODIMP Save(LPCWSTR lpszFileName, BOOL fRemember);
+ STDMETHODIMP SaveCompleted(LPCWSTR lpszFileName);
+ STDMETHODIMP GetCurFile(LPWSTR FAR * lplpszFileName);
+
+ // *** IOleObject methods ***
+ STDMETHODIMP SetClientSite( LPOLECLIENTSITE pClientSite);
+ STDMETHODIMP GetClientSite( LPOLECLIENTSITE FAR* ppClientSite);
+ STDMETHODIMP SetHostNames( LPCWSTR szContainerApp, LPCWSTR szContainerObj);
+ STDMETHODIMP Close(DWORD dwSaveOption);
+ STDMETHODIMP SetMoniker( DWORD dwWhichMoniker, LPMONIKER pmk);
+ STDMETHODIMP GetMoniker( DWORD dwAssign, DWORD dwWhichMoniker,
+ LPMONIKER FAR* ppmk);
+ STDMETHODIMP InitFromData( LPDATAOBJECT pDataObject,
+ BOOL fCreation,
+ DWORD dwReserved);
+ STDMETHODIMP GetClipboardData( DWORD dwReserved,
+ LPDATAOBJECT FAR* ppDataObject);
+ STDMETHODIMP DoVerb( LONG iVerb,
+ LPMSG lpmsg,
+ LPOLECLIENTSITE pActiveSite,
+ LONG lindex,
+ HWND hwndParent,
+ LPCRECT lprcPosRect);
+ STDMETHODIMP EnumVerbs(LPENUMOLEVERB FAR* ppenumOleVerb);
+ STDMETHODIMP Update(void);
+ STDMETHODIMP IsUpToDate(void);
+ STDMETHODIMP GetUserClassID(CLSID FAR *pClsid);
+ STDMETHODIMP GetUserType(DWORD dwFormOfType, LPWSTR FAR* pszUserType);
+ STDMETHODIMP SetExtent( DWORD dwDrawAspect, LPSIZEL lpsizel);
+ STDMETHODIMP GetExtent( DWORD dwDrawAspect, LPSIZEL lpsizel);
+
+ STDMETHODIMP Advise( LPADVISESINK pAdvSink, DWORD FAR* pdwConnection);
+ STDMETHODIMP Unadvise( DWORD dwConnection);
+ STDMETHODIMP EnumAdvise( LPENUMSTATDATA FAR* ppenumAdvise);
+ STDMETHODIMP GetMiscStatus(DWORD dwAspect, DWORD FAR* pdwStatus);
+ STDMETHODIMP SetColorScheme( LPLOGPALETTE lpLogpal);
+
+ // *** IParseDisplayName method ***
+ STDMETHODIMP ParseDisplayName(
+ LPBC pbc,
+ LPWSTR lpszDisplayName,
+ ULONG FAR* pchEaten,
+ LPMONIKER FAR* ppmkOut) ;
+
+ // *** IOleContainer methods ***
+ STDMETHODIMP EnumObjects(DWORD grfFlags, LPENUMUNKNOWN FAR* ppenumUnknown);
+ STDMETHODIMP LockContainer(BOOL fLock);
+
+ // *** IOleItemContainer methods ***
+ STDMETHODIMP GetObject(
+ LPWSTR lpszItem,
+ DWORD dwSpeedNeeded,
+ LPBINDCTX pbc,
+ REFIID riid,
+ LPVOID FAR* ppvObject);
+
+ STDMETHODIMP GetObjectStorage(
+ LPWSTR lpszItem,
+ LPBINDCTX pbc,
+ REFIID riid,
+ LPVOID FAR* ppvStorage);
+
+ STDMETHODIMP IsRunning(LPWSTR lpszItem) ;
+
+ // IOleClientSite
+ STDMETHODIMP SaveObject (void);
+ STDMETHODIMP GetContainer (LPOLECONTAINER FAR *ppContainer);
+ STDMETHODIMP ShowObject (void);
+ STDMETHODIMP OnShowWindow (BOOL fShow);
+ STDMETHODIMP RequestNewObjectLayout (void);
+
+private:
+
+ IUnknown * _punk;
+
+ IMoniker * _pmkContainer;
+
+ IStorage * _psStg1;
+
+ IStorage * _psStg2;
+};
+
+
+class CUnknownBasicBnd : public IUnknown
+{
+public:
+
+ CUnknownBasicBnd(IUnknown *punk);
+
+ ~CUnknownBasicBnd(void);
+
+ // IUnknown
+ STDMETHODIMP QueryInterface(REFIID iid, void FAR * FAR * ppv);
+ STDMETHODIMP_(ULONG) AddRef(void);
+ STDMETHODIMP_(ULONG) Release(void);
+
+private:
+
+ CBasicBnd * _pbasicbnd;
+
+ ULONG _cRefs;
+};
+
+
+#endif
diff --git a/private/oleutest/inc/testmess.h b/private/oleutest/inc/testmess.h
new file mode 100644
index 000000000..0669b2a1e
--- /dev/null
+++ b/private/oleutest/inc/testmess.h
@@ -0,0 +1,52 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: testmess.h
+//
+// Contents: Declarations for private test messages
+//
+// Classes:
+//
+// Functions:
+//
+// History: dd-mmm-yy Author Comment
+// 06-Feb-94 alexgo author
+//
+//--------------------------------------------------------------------------
+
+#ifndef __TESTMESS_H
+#define __TESTMESS_H
+
+#define TEST_SUCCESS 0
+#define TEST_FAILURE 1
+#define TEST_UNKNOWN 2
+
+// Test End: sent back to the driver from the test app idicating the
+// success or failure of the test (and optionally a failure code)
+// wParam == TEST_SUCCESS | TEST_FAILURE
+// lParam == HRESULT (optional)
+#define WM_TESTEND WM_USER + 1
+
+// Test Register: sent back to the driver from the test app giving
+// the driver a window handle that it can send messages to.
+// wParam == HWND of the test app
+#define WM_TESTREG WM_USER + 2
+
+// Tests Completed: used to indicate that all requested tests have
+// been completed
+#define WM_TESTSCOMPLETED WM_USER + 3
+
+// Test Start: used to kick the task stack interpreter into action
+#define WM_TESTSTART WM_USER + 4
+
+// Individual test messages. Sent by the driver app to the test app
+// telling it to start an individual test.
+#define WM_TEST1 WM_USER + 10
+#define WM_TEST2 WM_USER + 11
+#define WM_TEST3 WM_USER + 12
+#define WM_TEST4 WM_USER + 13
+#define WM_TEST5 WM_USER + 14
+
+#endif // !__TESTMESS_H
diff --git a/private/oleutest/inc/tstclsid.h b/private/oleutest/inc/tstclsid.h
new file mode 100644
index 000000000..0653551e2
--- /dev/null
+++ b/private/oleutest/inc/tstclsid.h
@@ -0,0 +1,25 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: tstclsid.h
+//
+// Contents: CLSID's for various test apps
+//
+// Classes:
+//
+// Functions:
+//
+// History: dd-mmm-yy Author Comment
+// 08-Feb-94 alexgo author
+//
+//--------------------------------------------------------------------------
+
+#ifndef __TSTCLSID_H
+#define __TSTCLSID_H
+
+extern "C" CLSID CLSID_SimpleServer;
+
+#endif
+
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
diff --git a/private/oleutest/makefil0 b/private/oleutest/makefil0
new file mode 100644
index 000000000..1a9fe50ec
--- /dev/null
+++ b/private/oleutest/makefil0
@@ -0,0 +1,36 @@
+# 16 bit unit tests makefile
+# Copyright (c) 1994, Microsoft Corporation
+#
+# History:
+# 29-Jun-1994 TerryRu
+#
+# If you add a new sub-component , make sure to add it in cleanup
+# section too.
+#
+
+!INCLUDE $(NTMAKEENV)\makefile.plt
+
+all:
+!if "$(PROCESSOR_ARCHITECTURE)" == "x86"
+ @echo Build_Status Build 16 bit spdnd16 under NTVDM.
+ cd utests16\simpdnd
+ $(MAKE)
+ cd ..\..\utests16\simpsvr
+ @echo Build_Status Build 16 bit spsvr16 under NTVDM.
+ $(MAKE)
+ cd ..
+!endif
+!IF "$(BUILDMSG)" != ""
+ @ech ; $(BUILDMSG) ;
+!ENDIF
+
+cleanup:
+!if "$(PROCESSOR_ARCHITECTURE)" == "x86"
+ cd utests16\simpdnd
+ $(MAKE) clean
+ cd ..\..\utests16\simpsvr
+ $(MAKE) clean
+ cd ..\..\
+!endif
+
+clean: cleanup all
diff --git a/private/oleutest/memalloc/daytona/makefile b/private/oleutest/memalloc/daytona/makefile
new file mode 100644
index 000000000..58068c375
--- /dev/null
+++ b/private/oleutest/memalloc/daytona/makefile
@@ -0,0 +1,20 @@
+############################################################################
+#
+# Microsoft Windows
+# Copyright (C) Microsoft Corporation, 1992 - 1992.
+# All rights reserved.
+#
+############################################################################
+
+!ifdef NTMAKEENV
+
+!include $(NTMAKEENV)\makefile.def
+
+!else # NTMAKEENV
+
+default: all
+!include filelist.mk
+!include $(COMMON)\src\win40.mk
+!include depend.mk
+
+!endif # NTMAKEENV
diff --git a/private/oleutest/memalloc/daytona/makefile.inc b/private/oleutest/memalloc/daytona/makefile.inc
new file mode 100644
index 000000000..539124b6d
--- /dev/null
+++ b/private/oleutest/memalloc/daytona/makefile.inc
@@ -0,0 +1,31 @@
+!if $(386)
+CPP_CMD=cl386
+!endif
+
+!if $(MIPS)
+CPP_CMD=mcl
+!endif
+
+!if $(ALPHA)
+CPP_CMD=$(ALPHA_CC)
+!endif
+
+allidl: test.h
+
+clean:
+ erase test.h 1>nul 2>nul
+
+test.h: ..\test.idl
+ midl ..\test.idl \
+ -cswtch test_z.c \
+ -Zp8 \
+ -I$(INCLUDES) \
+ -no_warn \
+ -char unsigned \
+ -mode c_port \
+ -DMIDL_PASS \
+ $(C_DEFINES) \
+ -cpp_cmd "$(CPP_CMD)" \
+ -cpp_opt "-nologo -DMIDL_PASS $(C_DEFINES) -I$(INCLUDES) -E -Tc"
+
+
diff --git a/private/oleutest/memalloc/daytona/sources b/private/oleutest/memalloc/daytona/sources
new file mode 100644
index 000000000..f4cce7a59
--- /dev/null
+++ b/private/oleutest/memalloc/daytona/sources
@@ -0,0 +1,88 @@
+!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:
+
+ Carl Hamilton (CarlH) 18-Jan-1994
+
+!ENDIF
+
+MAJORCOMP = cairole
+MINORCOMP = com
+
+#
+# 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= memtest
+
+#
+# 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
+
+DLLDEF= memtest.def
+
+INCLUDES= ..;.
+
+C_DEFINES= \
+ $(C_DEFINES) \
+ -DFLAT \
+ -DWIN32=100 \
+ -D_NT1X_=100 \
+ -DUNICODE \
+ -D_UNICODE \
+ -DNOEXCEPTIONS \
+ -DCAIROLE_DOWNLEVEL
+
+BLDCRT= 1
+
+SOURCES= \
+ ..\memtask.cxx \
+ ..\memtest.cxx \
+ ..\memory.cxx \
+ ..\midl.cxx \
+ ..\preinit.cxx \
+ ..\signal.cxx \
+ test_s.c \
+ test_y.c \
+ test_z.c
+
+UMTYPE= console
+UMAPPL=
+UMTEST=
+UMLIBS= \
+ $(BASEDIR)\public\sdk\lib\*\compob32.lib \
+ $(BASEDIR)\public\sdk\lib\*\storag32.lib \
+ $(BASEDIR)\public\sdk\lib\*\user32.lib \
+ $(BASEDIR)\public\sdk\lib\*\rpcrt4.lib \
+ $(BASEDIR)\public\sdk\lib\*\crtdll.lib \
+ $(BASEDIR)\public\sdk\lib\*\uuid.lib
+
+USE_CRTDLL= 1
+
+NTTARGETFILE0=allidl
diff --git a/private/oleutest/memalloc/dirs b/private/oleutest/memalloc/dirs
new file mode 100644
index 000000000..e2374d93c
--- /dev/null
+++ b/private/oleutest/memalloc/dirs
@@ -0,0 +1,38 @@
+!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:
+
+ Carl Hamilton (CarlH) 24-Jan-94
+
+!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/memalloc/headers.cxx b/private/oleutest/memalloc/headers.cxx
new file mode 100644
index 000000000..4c401f069
--- /dev/null
+++ b/private/oleutest/memalloc/headers.cxx
@@ -0,0 +1,16 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: headers.cxx
+//
+// Contents: Memory allocation unit test headers
+//
+// History: 13-Aug-93 CarlH Created
+//
+//--------------------------------------------------------------------------
+#include "memtest.hxx"
+#pragma hdrstop
+
+
diff --git a/private/oleutest/memalloc/makefile b/private/oleutest/memalloc/makefile
new file mode 100644
index 000000000..4edc4a765
--- /dev/null
+++ b/private/oleutest/memalloc/makefile
@@ -0,0 +1,16 @@
+############################################################################
+#
+# Copyright (C) 1992, Microsoft Corporation.
+#
+# All rights reserved.
+#
+############################################################################
+
+# We need to do the following so that build will stop reading from the
+# pipe.
+
+all :
+ echo $(BUILDMSG)
+
+clean : all
+
diff --git a/private/oleutest/memalloc/memory.cxx b/private/oleutest/memalloc/memory.cxx
new file mode 100644
index 000000000..c69eb85a6
--- /dev/null
+++ b/private/oleutest/memalloc/memory.cxx
@@ -0,0 +1,138 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: memory.cxx
+//
+// Contents: Memory allocation tests
+//
+// Functions:
+//
+// History: 13-Aug-93 CarlH Created
+//
+//--------------------------------------------------------------------------
+#include "memtest.hxx"
+#pragma hdrstop
+
+
+static char g_szMemory[] = "memory";
+
+// WARNING: Do not just start whacking on the elements of this
+// array. The third element of each structure may hold
+// the index of another entry in the array. If elements
+// are inserted, these indices may get hosed!
+//
+static SMemTask g_amemtskStandard[] =
+{
+ {memopAlloc, 128, 0, S_OK},
+ {memopFree, 0, 0, S_OK},
+ {memopAlloc, 12, 0, S_OK},
+ {memopAlloc, 1423, 0, S_OK},
+ {memopFree, 0, 2, S_OK},
+ {memopAlloc, 12, 0, S_OK},
+ {memopFree, 0, 3, S_OK},
+ {memopFree, 0, 5, S_OK}
+};
+
+static ULONG g_cmemtskStandard =
+ sizeof(g_amemtskStandard) / sizeof(g_amemtskStandard[0]);
+
+
+// WARNING: See warning on the above array definition.
+//
+static SMemTask g_amemtskMIDL[] =
+{
+ {memopMIDLAlloc, 128, 0, S_OK},
+ {memopMIDLFree, 0, 0, S_OK},
+ {memopMIDLAlloc, 12, 0, S_OK},
+ {memopMIDLAlloc, 1423, 0, S_OK},
+ {memopMIDLFree, 0, 2, S_OK},
+ {memopMIDLAlloc, 12, 0, S_OK},
+ {memopMIDLFree, 0, 3, S_OK},
+ {memopMIDLFree, 0, 5, S_OK}
+};
+
+static ULONG g_cmemtskMIDL =
+ sizeof(g_amemtskMIDL) / sizeof(g_amemtskMIDL[0]);
+
+
+BOOL TestStandard(DWORD grfOptions);
+BOOL TestMIDL(DWORD grfOptions);
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: TestMemory, public
+//
+// Synopsis: Tests simple memory allocation functionality
+//
+// Arguments: [grfOptions] - options for test
+//
+// Returns: TRUE if successful, FALSE otherwise
+//
+// History: 17-Aug-93 CarlH Created
+//
+//--------------------------------------------------------------------------
+BOOL TestMemory(DWORD grfOptions)
+{
+ BOOL fPassed;
+
+ PrintHeader(g_szMemory);
+
+ if (!(fPassed = TestStandard(grfOptions)))
+ goto done;
+
+#ifdef TEST_MIDL
+ if (!(fPassed = TestMIDL(grfOptions)))
+ goto done;
+#endif // TEST_MIDL
+
+done:
+ PrintResult(g_szMemory, fPassed);
+
+ return (fPassed);
+}
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: TestStandard, public
+//
+// Synopsis: Tests standard memory allocation routines (not linked)
+//
+// Arguments: [grfOptions] - options for test
+//
+// Returns: TRUE if successful, FALSE otherwise
+//
+// History: 17-Aug-93 CarlH Created
+//
+//--------------------------------------------------------------------------
+BOOL TestStandard(DWORD grfOptions)
+{
+ PrintTrace(g_szMemory, "testing standard allocations\n");
+
+ return (RunMemoryTasks(g_szMemory, g_amemtskStandard, g_cmemtskStandard));
+}
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: TestMIDL, public
+//
+// Synopsis: Tests RPC memory allocation routines (not linked)
+//
+// Arguments: [grfOptions] - options for test
+//
+// Returns: TRUE if successful, FALSE otherwise
+//
+// History: 17-Aug-93 CarlH Created
+//
+//--------------------------------------------------------------------------
+BOOL TestMIDL(DWORD grfOptions)
+{
+ PrintTrace(g_szMemory, "testing MIDL allocations\n");
+
+ return (RunMemoryTasks(g_szMemory, g_amemtskMIDL, g_cmemtskMIDL));
+}
+
diff --git a/private/oleutest/memalloc/memtask.cxx b/private/oleutest/memalloc/memtask.cxx
new file mode 100644
index 000000000..286a2f0d1
--- /dev/null
+++ b/private/oleutest/memalloc/memtask.cxx
@@ -0,0 +1,196 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: memtask.cxx
+//
+// Contents: Memory task functions
+//
+// Functions: RunMemoryTasks
+//
+// History: 17-Aug-93 CarlH Created
+//
+//--------------------------------------------------------------------------
+#include "memtest.hxx"
+#pragma hdrstop
+
+
+#ifdef LINKED_COMPATIBLE
+#include <memalloc.h>
+#endif
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: RunMemoryTasks, public
+//
+// Synopsis: Runs through a series of memory tasks
+//
+// Arguments: [pszComponent] - current test component name
+// [pmemtsk] - pointer to memory tasks to run
+// [cmemtsk] - count of memory tasks
+//
+// Returns: TRUE if successful, FALSE otherwise
+//
+// Algorithm: A buffer is first allocated and cleared to hold the
+// blocks returned by any allocations. The array of
+// tasks is then iterated through an each memory task
+// is performed. The given task array should be
+// constructed so that all allocated memory is freed.
+//
+// History: 17-Aug-93 CarlH Created
+//
+//--------------------------------------------------------------------------
+BOOL RunMemoryTasks(char *pszComponent, SMemTask *pmemtsk, ULONG cmemtsk)
+{
+ void **ppvMemory;
+ HRESULT hr;
+ BOOL fPassed = TRUE;
+
+ // Allocate and clear an array of void *'s to hold the pointers
+ // returned by any allocations made during the test.
+ //
+ ppvMemory = new void *[cmemtsk];
+ for (ULONG ipv = 0; ipv < cmemtsk; ipv++)
+ {
+ ppvMemory[ipv] = NULL;
+ }
+
+ // For each entry in the array of tasks, figure out what type
+ // of operation is being requested and do it.
+ //
+ for (ULONG imemtsk = 0; (imemtsk < cmemtsk) && fPassed; imemtsk++)
+ {
+ switch (pmemtsk[imemtsk].memop)
+ {
+#ifdef LINKED_COMPATIBLE
+ case memopOldAlloc:
+ PrintTrace(
+ pszComponent,
+ "old allocating a block of %lu bytes\n",
+ pmemtsk[imemtsk].cb);
+ hr = MemAlloc(pmemtsk[imemtsk].cb, ppvMemory + imemtsk);
+ PrintTrace(
+ pszComponent,
+ "old allocated block at %p\n",
+ ppvMemory[imemtsk]);
+ break;
+
+ case memopOldAllocLinked:
+ PrintTrace(
+ pszComponent,
+ "old allocating a linked block of %lu bytes on %p\n",
+ pmemtsk[imemtsk].cb,
+ ppvMemory[pmemtsk[imemtsk].imemtsk]);
+ hr = MemAllocLinked(
+ ppvMemory[pmemtsk[imemtsk].imemtsk],
+ pmemtsk[imemtsk].cb,
+ ppvMemory + imemtsk);
+ PrintTrace(
+ pszComponent,
+ "old allocated block at %p\n",
+ ppvMemory[imemtsk]);
+ break;
+
+ case memopOldFree:
+ PrintTrace(
+ pszComponent,
+ "old freeing block at %p\n",
+ ppvMemory[pmemtsk[imemtsk].imemtsk]);
+ hr = MemFree(ppvMemory[pmemtsk[imemtsk].imemtsk]);
+ break;
+
+#ifdef TEST_MIDL
+ case memopMIDLAlloc:
+ TRY
+ {
+ PrintTrace(
+ pszComponent,
+ "MIDL allocating a block of %lu bytes\n",
+ pmemtsk[imemtsk].cb);
+ ppvMemory[imemtsk] = MIDL_user_allocate(pmemtsk[imemtsk].cb);
+ PrintTrace(
+ pszComponent,
+ "MIDL allocated block at %p\n",
+ ppvMemory[imemtsk]);
+ hr = NO_ERROR;
+ }
+ CATCH(CException, e)
+ {
+ hr = e.GetErrorCode();
+ }
+ END_CATCH;
+ break;
+
+ case memopMIDLFree:
+ TRY
+ {
+ PrintTrace(
+ pszComponent,
+ "MIDL freeing block at %p\n",
+ ppvMemory[pmemtsk[imemtsk].imemtsk]);
+ MIDL_user_free(ppvMemory[pmemtsk[imemtsk].imemtsk]);
+ hr = NO_ERROR;
+ }
+ CATCH(CException, e)
+ {
+ hr = e.GetErrorCode();
+ }
+ END_CATCH;
+ break;
+#endif // TEST_MIDL
+
+#endif // LINKED_COMPATIBLE
+ case memopAlloc:
+ // A standard memory allocation is being requested.
+ // Allocate the number of bytes given in the task
+ // description and store the block in our array of
+ // void *'s.
+ //
+ PrintTrace(
+ pszComponent,
+ "allocating a block of %lu bytes\n",
+ pmemtsk[imemtsk].cb);
+ ppvMemory[imemtsk] = CoTaskMemAlloc(pmemtsk[imemtsk].cb);
+ PrintTrace(
+ pszComponent,
+ "allocated block at %p\n",
+ ppvMemory[imemtsk]);
+ hr = (ppvMemory[imemtsk] != 0 ? S_OK : -1);
+ break;
+
+ case memopFree:
+ // A standard memory free is being requested. Free
+ // the block found in our array of void *'s specified
+ // by the index found in the task description.
+ //
+ PrintTrace(
+ pszComponent,
+ "freeing block at %p\n",
+ ppvMemory[pmemtsk[imemtsk].imemtsk]);
+ CoTaskMemFree(ppvMemory[pmemtsk[imemtsk].imemtsk]);
+ hr = S_OK;
+ break;
+
+ default:
+ // Uh oh. We found a memory operation that we don't
+ // understand. Set the result code to a value that
+ // we know will cause the test to fail.
+ //
+ PrintError(pszComponent, "unknown memory operation\n");
+ hr = pmemtsk[imemtsk].hr + 1;
+ break;
+ }
+
+ // Make sure that the returned error code was what we expected
+ // for this task.
+ //
+ fPassed = (hr == pmemtsk[imemtsk].hr);
+ }
+
+ delete ppvMemory;
+
+ return (fPassed);
+}
+
diff --git a/private/oleutest/memalloc/memtest.cxx b/private/oleutest/memalloc/memtest.cxx
new file mode 100644
index 000000000..1a2b373bf
--- /dev/null
+++ b/private/oleutest/memalloc/memtest.cxx
@@ -0,0 +1,436 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: memtest.cxx
+//
+// Contents: Memory allocation API unit test
+//
+// Functions:
+//
+// History: 13-Aug-93 CarlH Created
+//
+//--------------------------------------------------------------------------
+#include "memtest.hxx"
+#pragma hdrstop
+
+#include <stdlib.h>
+#include <stdio.h>
+
+
+static DWORD g_grfGlobal = GLOBAL_RUN | GLOBAL_CLEANUP;
+static DWORD g_grfPreInit = 0;
+static DWORD g_grfMemory = 0;
+static DWORD g_grfMIDL = MIDL_AUTOGO | MIDL_AUTOEND;
+static DWORD g_grfCompat = 0;
+
+static BOOL g_fServer = FALSE;
+
+
+static BOOL ParseArguments(char *pszName, int cpsz, char **ppsz);
+static BOOL Initialize(void);
+static BOOL Uninitialize(void);
+
+static void PrintUsage(char *pszName);
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: main, public
+//
+// Synopsis: Memory allocation test entry point
+//
+// Arguments: [argc] - count of arguments
+// [argv] - list of arguments
+//
+// Returns: Zero if successful, non-zero otherwise
+//
+// History: 19-May-93 CarlH Created
+//
+//--------------------------------------------------------------------------
+int _cdecl main(int argc, char *argv[])
+{
+ DWORD grfOptions;
+ BOOL fPassed;
+
+ if (!(fPassed = ParseArguments(argv[0], argc - 1, argv + 1)))
+ goto done;
+
+ if (g_fServer)
+ {
+ if (!(fPassed = Initialize()))
+ goto done;
+
+ grfOptions = g_grfGlobal | g_grfMIDL;
+ if (grfOptions & GLOBAL_RUN)
+ {
+ if (!(fPassed = TestMIDLServer(grfOptions)))
+ goto done;
+ }
+ }
+ else
+ {
+ // This test has to be run before initialization since that is
+ // its point. It tests the memory allocation APIs functionality
+ // before CoInitialize() is called.
+ //
+ grfOptions = g_grfGlobal | g_grfPreInit;
+ if (grfOptions & GLOBAL_RUN)
+ {
+ if (!(fPassed = TestPreInit(grfOptions)))
+ goto done;
+ }
+
+ if (!(fPassed = Initialize()))
+ goto done;
+
+ grfOptions = g_grfGlobal | g_grfMemory;
+ if (grfOptions & GLOBAL_RUN)
+ {
+ if (!(fPassed = TestMemory(grfOptions)))
+ goto done;
+ }
+
+ grfOptions = g_grfGlobal | g_grfMIDL;
+ if (grfOptions & GLOBAL_RUN)
+ {
+ WCHAR wszServer[MAX_PATH + 1];
+
+ mbstowcs(wszServer, argv[0], MAX_PATH);
+ if (!(fPassed = TestMIDLClient(wszServer, grfOptions)))
+ goto done;
+ }
+
+#ifdef LINKED_COMPATIBLE
+ grfOptions = g_grfGlobal | g_grfCompat;
+ if (grfOptions & GLOBAL_RUN)
+ {
+ if (!(fPassed = TestCompatibility(grfOptions)))
+ goto done;
+ }
+#endif // LINKED_COMPATIBLE
+ }
+
+ if (!(fPassed = Uninitialize()))
+ goto done;
+
+done:
+ fprintf(stdout, "%s: %s\n", argv[0], fPassed ? "PASSED" : "FAILED");
+
+ return (fPassed ? 0 : 1);
+}
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: Initialize, public
+//
+// Synopsis: Global initialization routine
+//
+// Returns: TRUE if successful, FALSE otherwise
+//
+// History: 07-May-93 CarlH Created
+//
+//--------------------------------------------------------------------------
+BOOL Initialize(void)
+{
+ return (SUCCEEDED(CoInitialize(NULL)));
+}
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: Uninitialize, public
+//
+// Synopsis: Global clean-up routine
+//
+// Returns: TRUE if successful, FALSE otherwise
+//
+// History: 07-May-93 CarlH Created
+//
+//--------------------------------------------------------------------------
+BOOL Uninitialize(void)
+{
+ CoUninitialize();
+
+ return (TRUE);
+}
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: PrintHeader, public
+//
+// Synopsis: Prints the header for a component's test
+//
+// Arguments: [pszComponent] - component test to print header for
+//
+// History: 28-Feb-93 CarlH Created
+//
+//--------------------------------------------------------------------------
+void PrintHeader(char const *pszComponent)
+{
+ if (g_grfGlobal & GLOBAL_STATUS)
+ {
+ fprintf(stdout, "%s - running tests\n", pszComponent);
+ }
+}
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: PrintResult, public
+//
+// Synopsis: Prints the result of a component's test
+//
+// Arguments: [pszComponent] - component test to print result for
+//
+// History: 28-Feb-93 CarlH Created
+//
+//--------------------------------------------------------------------------
+void PrintResult(char const *pszComponent, BOOL fPassed)
+{
+ if (g_grfGlobal & GLOBAL_STATUS)
+ {
+ fprintf(
+ stdout,
+ "%s - tests %s\n",
+ pszComponent,
+ fPassed ? "passed" : "failed");
+ }
+}
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: PrintTrace, public
+//
+// Synopsis: Prints a trace message if verbose mode on
+//
+// Arguments: [pszComponent] - component name issuing trace
+// [pszFormat] - format string
+// [...] - arguments for format string
+//
+// History: 24-Feb-93 CarlH Created
+//
+//--------------------------------------------------------------------------
+void PrintTrace(char const *pszComponent, char const *pszFormat, ...)
+{
+ if (g_grfGlobal & GLOBAL_VERBOSE)
+ {
+ va_list va;
+
+ fprintf(stdout, "trace: %s - ", pszComponent);
+
+ va_start(va, pszFormat);
+ vfprintf(stdout, pszFormat, va);
+ va_end(va);
+ }
+}
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: PrintError, public
+//
+// Synopsis: Prints an error message
+//
+// Arguments: [pszComponent] - component name issuing trace
+// [pszFormat] - format string
+// [...] - arguments for format string
+//
+// History: 24-Feb-93 CarlH Created
+//
+//--------------------------------------------------------------------------
+void PrintError(char const *pszComponent, char const *pszFormat, ...)
+{
+ va_list va;
+
+ fprintf(stderr, "error: %s - ", pszComponent);
+
+ va_start(va, pszFormat);
+ vfprintf(stderr, pszFormat, va);
+ va_end(va);
+}
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: PrintUsage, private
+//
+// Synopsis: Prints a the usage message for this test
+//
+// Arguments: [pszName] - name of the executable
+//
+// History: 24-Feb-93 CarlH Created
+//
+//--------------------------------------------------------------------------
+void PrintUsage(char *pszName)
+{
+ fprintf(stdout, "Usage: %s {<flag>|<comp>}*\n", pszName);
+ fprintf(stdout, "Where: <flag> = {+|-}{?dgecsv}+\n");
+ fprintf(stdout, " <comp> = {preinit|memory|compat|midl}\n");
+ fprintf(stdout, " ? - displays this message\n");
+ fprintf(stdout, " d - turns MIDL debugging on/OFF\n");
+ fprintf(stdout, " g - turns MIDL debugging auto go ON/off\n");
+ fprintf(stdout, " e - turns MIDL debugging auto end ON/off\n");
+ fprintf(stdout, " c - turns cleanup ON/off\n");
+ fprintf(stdout, " s - turns status messages on/OFF\n");
+ fprintf(stdout, " v - turns verbosity on/OFF\n");
+}
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: ParseArguments, private
+//
+// Synopsis: Parses command line arguments
+//
+// Arguments: [pszName] - name of executable
+// [cpsz] - number of strings in [ppsz]
+// [ppsz] - array of command line arguments
+//
+// Returns: TRUE if successfull, FALSE otherwise
+//
+// History: 24-Feb-93 CarlH Created
+//
+//--------------------------------------------------------------------------
+BOOL ParseArguments(char *pszName, int cpsz, char **ppsz)
+{
+ BOOL fOK = TRUE;
+
+ // As long as we haven't encountered an error, we want to loop
+ // through all of the arguments, excluding the first, which is
+ // the name of the program (argv[0]).
+ //
+ for (int ipsz = 0; fOK && (ipsz < cpsz); ipsz++)
+ {
+ // If the first character of the argument is a plus or minus,
+ // this argument must be a series of flags.
+ //
+ if ((ppsz[ipsz][0] == '+') || (ppsz[ipsz][0] == '-'))
+ {
+ BOOL fFlag = (ppsz[ipsz][0] == '+');
+
+ // We want to check the rest of the characters in the
+ // argument.
+ //
+ for (int ich = 1; fOK && (ppsz[ipsz][ich] != '\0'); ich++)
+ {
+ switch (ppsz[ipsz][ich])
+ {
+ case '?':
+ // User is requesting help, so print the usage
+ // message and stop parsing.
+ //
+ PrintUsage(pszName);
+ fOK = FALSE;
+ break;
+
+ case 'D':
+ case 'd':
+ g_grfMIDL = (fFlag ?
+ g_grfMIDL | MIDL_DEBUG :
+ g_grfMIDL & ~MIDL_DEBUG);
+ break;
+
+ case 'G':
+ case 'g':
+ g_grfMIDL = (fFlag ?
+ g_grfMIDL | MIDL_AUTOGO :
+ g_grfMIDL & ~MIDL_AUTOGO);
+ break;
+
+ case 'E':
+ case 'e':
+ g_grfMIDL = (fFlag ?
+ g_grfMIDL | MIDL_AUTOEND :
+ g_grfMIDL & ~MIDL_AUTOEND);
+ break;
+
+ case 'C':
+ case 'c':
+ // Turn test cleanup on or off depending on the
+ // first character of this argument.
+ //
+ g_grfGlobal = (fFlag ?
+ g_grfGlobal | GLOBAL_CLEANUP :
+ g_grfGlobal & ~GLOBAL_CLEANUP);
+ break;
+
+ case 'S':
+ case 's':
+ // Turn status messages on or off depending on the
+ // first character of this argument.
+ //
+ g_grfGlobal = (fFlag ?
+ g_grfGlobal | GLOBAL_STATUS :
+ g_grfGlobal & ~GLOBAL_STATUS);
+ break;
+
+ case 'V':
+ case 'v':
+ // Turn verbose mode on or off depending on the
+ // first character of this argument.
+ //
+ g_grfGlobal = (fFlag ?
+ g_grfGlobal | GLOBAL_VERBOSE :
+ g_grfGlobal & ~GLOBAL_VERBOSE);
+ break;
+
+ default:
+ // We don't know what the hell this is, so tell
+ // the user and stop parsing.
+ //
+ PrintError(
+ pszName,
+ "unrecognized switch '%c'\n",
+ ppsz[ipsz][ich]);
+ fOK = FALSE;
+ break;
+ }
+ }
+ }
+ else
+ if (stricmp(ppsz[ipsz], "preinit") == 0)
+ {
+ g_grfGlobal &= ~GLOBAL_RUN;
+ g_grfPreInit |= GLOBAL_RUN;
+ }
+ else
+ if (stricmp(ppsz[ipsz], "memory") == 0)
+ {
+ g_grfGlobal &= ~GLOBAL_RUN;
+ g_grfMemory |= GLOBAL_RUN;
+ }
+ else
+ if (stricmp(ppsz[ipsz], "compat") == 0)
+ {
+ g_grfGlobal &= ~GLOBAL_RUN;
+ g_grfCompat |= GLOBAL_RUN;
+ }
+ else
+ if (stricmp(ppsz[ipsz], "midl") == 0)
+ {
+ g_grfGlobal &= ~GLOBAL_RUN;
+ g_grfMIDL |= GLOBAL_RUN;
+ }
+ else
+ if (stricmp(ppsz[ipsz], "midlserver") == 0)
+ {
+ g_fServer = TRUE;
+ }
+ else
+ {
+ PrintError(
+ pszName,
+ "unrecognized argument \"%s\"\n",
+ ppsz[ipsz]);
+ fOK = FALSE;
+ }
+ }
+
+ return (fOK);
+}
+
diff --git a/private/oleutest/memalloc/memtest.hxx b/private/oleutest/memalloc/memtest.hxx
new file mode 100644
index 000000000..6bdbbf1d6
--- /dev/null
+++ b/private/oleutest/memalloc/memtest.hxx
@@ -0,0 +1,89 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: memtest.hxx
+//
+// Contents: Memory allocation API unit test declarations
+//
+// Functions:
+//
+// History: 13-Aug-93 CarlH Created
+//
+//--------------------------------------------------------------------------
+#include <windows.h>
+#include <ole2.h>
+#include "signal.hxx"
+
+
+#define GLOBAL_RUN 0x00010000
+#define GLOBAL_CLEANUP 0x00020000
+#define GLOBAL_STATUS 0x00040000
+#define GLOBAL_VERBOSE 0x00080000
+
+#define MIDL_DEBUG 0x00000001
+#define MIDL_AUTOGO 0x00000002
+#define MIDL_AUTOEND 0x00000004
+
+
+BOOL TestPreInit(DWORD grfOptions);
+BOOL TestMemory(DWORD grfOptions);
+BOOL TestExceptions(DWORD grfOptions);
+BOOL TestMIDLClient(WCHAR *pwszServer, DWORD grfOptions);
+BOOL TestMIDLServer(DWORD grfOptions);
+
+#ifdef LINKED_COMPATIBLE
+BOOL TestCompatibility(DWORD grfOptions);
+#endif
+
+void PrintHeader(char const *pszComponent);
+void PrintResult(char const *pszComponent, BOOL fPassed);
+
+void PrintTrace(char const *pszComponent, char const *pszFormat, ...);
+void PrintError(char const *pszComponent, char const *pszFormat, ...);
+
+
+//+-------------------------------------------------------------------------
+//
+// Enum: MemOp (memop)
+//
+// Purpose: Describes a particualr memory operation
+//
+// History: 17-Aug-93 CarlH Created
+//
+//--------------------------------------------------------------------------
+enum MemOp
+{
+#ifdef LINKED_COMPATIBLE
+ memopOldAlloc, // Allocate with MemAlloc
+ memopOldAllocLinked,// Allocate with MemAllocLinked
+ memopOldFree, // Free with MemFree
+#endif
+ memopAlloc, // Allocate regular block of memory
+ memopFree, // Free regular block of memory
+ memopMIDLAlloc, // Allocate with MIDL_user_alloc
+ memopMIDLFree // Free with MIDL_user_free
+};
+
+
+//+-------------------------------------------------------------------------
+//
+// Struct: SMemTask (memtsk)
+//
+// Purpose: Holds a description of a memory allocation task
+//
+// History: 17-Aug-93 CarlH Created
+//
+//--------------------------------------------------------------------------
+struct SMemTask
+{
+ MemOp memop; // Memory operation to execute
+ ULONG cb; // Size of operation (for alloc)
+ ULONG imemtsk; // Related memory task (for free and linking)
+ HRESULT hr; // Expected result code
+};
+
+
+BOOL RunMemoryTasks(char *pszComponent, SMemTask *pmemtsk, ULONG cmemtsk);
+
diff --git a/private/oleutest/memalloc/midl.cxx b/private/oleutest/memalloc/midl.cxx
new file mode 100644
index 000000000..0149661e5
--- /dev/null
+++ b/private/oleutest/memalloc/midl.cxx
@@ -0,0 +1,357 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: midl.cxx
+//
+// Contents: MIDL memory allocation tests
+//
+// Functions:
+//
+// History: 29-Sep-93 CarlH Created
+//
+//--------------------------------------------------------------------------
+#include "memtest.hxx"
+#pragma hdrstop
+#include <rpc.h>
+#include "test.h"
+
+
+static const char g_szMIDLClient[] = "midl";
+static const char g_szMIDLServer[] = "server";
+
+static const WCHAR g_wszMIDLSignal[] = L"testsignal";
+static const WCHAR g_wszStopSignal[] = L"stopsignal";
+
+static const DWORD g_ccallMin = 1;
+static const DWORD g_ccallMax = 1;
+
+static CSignal g_sigStop(g_wszStopSignal);
+
+
+BYTE g_ab0[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07};
+BYTE g_ab1[] = {0x00, 0xFF};
+BYTE g_ab2[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
+BYTE g_ab3[] = {0x69};
+
+SCountedBytes g_acbIn[] =
+{
+ {(sizeof(g_ab0) / sizeof(g_ab0[0])), g_ab0},
+ {(sizeof(g_ab1) / sizeof(g_ab1[0])), g_ab1},
+ {(sizeof(g_ab2) / sizeof(g_ab2[0])), g_ab2},
+ {(sizeof(g_ab3) / sizeof(g_ab3[0])), g_ab3}
+};
+
+
+SCountedCountedBytes g_ccbIn =
+{
+ sizeof(g_acbIn) / sizeof(g_acbIn[0]),
+ g_acbIn
+};
+
+
+DWORD StartServer(WCHAR *pwszServer, DWORD grfOptions);
+DWORD ConnectServer(void);
+DWORD DisconnectServer(void);
+
+BOOL CompareBytes(SCountedCountedBytes *pccbA, SCountedCountedBytes *pccbB);
+BOOL FreeBytes(SCountedCountedBytes *pccb);
+
+BOOL TestMIDLClient(WCHAR *pwszServer, DWORD grfOptions)
+{
+ CSignal sig(g_wszMIDLSignal);
+ SCountedCountedBytes ccbOut = {0, NULL};
+ RPC_STATUS stat;
+ BOOL fPassed;
+
+ PrintHeader(g_szMIDLClient);
+
+ PrintTrace(g_szMIDLClient, "starting server\n");
+ stat = StartServer(pwszServer, grfOptions);
+ if (!(fPassed = (stat == 0)))
+ goto done;
+
+ PrintTrace(g_szMIDLClient, "waiting for server\n");
+ stat = sig.Wait(grfOptions & MIDL_DEBUG ? INFINITE : 10000);
+ if (!(fPassed = (stat == 0)))
+ goto done;
+
+ PrintTrace(g_szMIDLClient, "connecting to server\n");
+ stat = ConnectServer();
+ if (!(fPassed = (stat == 0)))
+ goto done;
+
+ PrintTrace(g_szMIDLClient, "copying bytes\n");
+ fPassed = _CopyBytes(&g_ccbIn, &ccbOut);
+ if (!fPassed)
+ goto done;
+
+ PrintTrace(g_szMIDLClient, "stopping server\n");
+ fPassed = _StopServer();
+ if (!fPassed)
+ goto done;
+
+ PrintTrace(g_szMIDLClient, "comparing bytes\n");
+ fPassed = CompareBytes(&g_ccbIn, &ccbOut);
+ if (!fPassed)
+ goto done;
+
+ PrintTrace(g_szMIDLClient, "freeing bytes\n");
+ fPassed = FreeBytes(&ccbOut);
+ if (!fPassed)
+ goto done;
+
+ PrintTrace(g_szMIDLClient, "disconnecting from server\n");
+ stat = DisconnectServer();
+ if (!(fPassed = (stat == 0)))
+ goto done;
+
+done:
+ PrintResult(g_szMIDLClient, fPassed);
+
+ return (fPassed);
+}
+
+
+BOOL TestMIDLServer(DWORD grfOptions)
+{
+ CSignal sig(g_wszMIDLSignal);
+ RPC_STATUS stat;
+ BOOL fPassed;
+
+ PrintHeader(g_szMIDLServer);
+
+ PrintTrace(g_szMIDLServer, "registering protocol\n");
+ stat = RpcServerUseAllProtseqsIf(g_ccallMax, Test_ServerIfHandle, NULL);
+ if (!(fPassed = (stat == 0)))
+ goto done;
+
+ PrintTrace(g_szMIDLServer, "registering interface\n");
+ stat = RpcServerRegisterIf(Test_ServerIfHandle, NULL, NULL);
+ if (!(fPassed = (stat == 0)))
+ goto done;
+
+#ifdef NO_OLE_RPC
+ PrintTrace(g_szMIDLServer, "listening\n");
+ stat = RpcServerListen(
+ g_ccallMin,
+ g_ccallMax,
+ TRUE);
+ if (!(fPassed = ((stat == 0) || (stat == RPC_S_ALREADY_LISTENING))))
+ goto done;
+#endif // NO_OLE_RPC
+
+ PrintTrace(g_szMIDLServer, "signaling client\n");
+ stat = sig.Signal();
+ if (!(fPassed = (stat == 0)))
+ goto done;
+
+ PrintTrace(g_szMIDLServer, "waiting...\n");
+#ifdef NO_OLE_RPC
+ stat = RpcMgmtWaitServerListen();
+ if (!(fPassed = ((stat == 0) || (stat == RPC_S_ALREADY_LISTENING))))
+ goto done;
+#else
+ g_sigStop.Wait();
+#endif // NO_OLE_RPC
+
+
+done:
+ PrintResult(g_szMIDLServer, fPassed);
+
+ return (fPassed);
+}
+
+
+boolean CopyBytes(SCountedCountedBytes *pccbIn, SCountedCountedBytes *pccbOut)
+{
+ HRESULT hr;
+ BOOL fPassed;
+ long ccb = pccbIn->ccb;
+ long icb;
+
+ PrintTrace(g_szMIDLServer, "copying bytes\n");
+
+ pccbOut->ccb = ccb;
+
+ pccbOut->pcb = (SCountedBytes *)CoTaskMemAlloc(ccb * sizeof(*pccbOut->pcb));
+ if (!(fPassed = (pccbOut != 0)))
+ goto done;
+
+ for (icb = 0; icb < ccb; icb++)
+ {
+ long cb = pccbIn->pcb[icb].cb;
+
+ pccbOut->pcb[icb].cb = cb;
+
+ pccbOut->pcb[icb].pb = (byte *)CoTaskMemAlloc(cb);
+ if (!(fPassed = (pccbOut->pcb[icb].pb != 0)))
+ goto done;
+
+ memcpy(pccbOut->pcb[icb].pb, pccbIn->pcb[icb].pb, cb);
+ }
+
+done:
+ return (fPassed);
+}
+
+
+BOOL CompareBytes(SCountedCountedBytes *pccbA, SCountedCountedBytes *pccbB)
+{
+ BOOL fPassed;
+ long icb;
+
+ if (!(fPassed = (pccbA->ccb == pccbB->ccb)))
+ goto done;
+
+ for (icb = 0; icb < pccbA->ccb; icb++)
+ {
+ if (!(fPassed = (pccbA->pcb[icb].cb == pccbB->pcb[icb].cb)))
+ goto done;
+
+ int cmp = memcmp(
+ pccbA->pcb[icb].pb,
+ pccbB->pcb[icb].pb,
+ pccbB->pcb[icb].cb);
+ if (!(fPassed = (cmp == 0)))
+ goto done;
+ }
+
+done:
+ return (fPassed);
+}
+
+
+BOOL FreeBytes(SCountedCountedBytes *pccb)
+{
+ BOOL fPassed = TRUE;
+
+ for (long icb = 0; icb < pccb->ccb; icb++)
+ {
+ CoTaskMemFree(pccb->pcb[icb].pb);
+ }
+
+ CoTaskMemFree(pccb->pcb);
+
+done:
+ return (fPassed);
+}
+
+
+boolean StopServer(void)
+{
+ BOOL fPassed;
+
+ PrintTrace(g_szMIDLServer, "stopping\n");
+
+#ifdef NO_OLE_RPC
+ fPassed = (RpcMgmtStopServerListening(NULL) == 0);
+#else
+ g_sigStop.Signal();
+ fPassed = TRUE;
+#endif // NO_OLE_RPC
+
+ return (fPassed);
+}
+
+
+DWORD StartServer(WCHAR *pwszServer, DWORD grfOptions)
+{
+ WCHAR wszCommandLine[MAX_PATH + 1];
+ ULONG cwchDebug;
+ BOOL fOK;
+ DWORD stat;
+
+ if (grfOptions & MIDL_DEBUG)
+ {
+ cwchDebug = wsprintf(
+ wszCommandLine,
+ L"ntsd %ws %ws ",
+ (grfOptions & MIDL_AUTOGO ? L"-g" : L""),
+ (grfOptions & MIDL_AUTOEND ? L"-G" : L""));
+ }
+ else
+ {
+ cwchDebug = 0;
+ }
+
+ wsprintf(
+ wszCommandLine + cwchDebug,
+ L"%ws midlserver %cc %cs %cv",
+ pwszServer,
+ (grfOptions & GLOBAL_CLEANUP ? '+' : '-'),
+ (grfOptions & GLOBAL_STATUS ? '+' : '-'),
+ (grfOptions & GLOBAL_VERBOSE ? '+' : '-'));
+
+ PrintTrace(g_szMIDLClient, "server command line: %ws\n", wszCommandLine);
+
+ STARTUPINFO sui;
+ PROCESS_INFORMATION pi;
+
+ sui.cb = sizeof(sui);
+ sui.lpReserved = 0;
+ sui.lpDesktop = 0;
+ sui.lpTitle = wszCommandLine;
+ sui.dwFlags = 0;
+ sui.cbReserved2 = 0;
+ sui.lpReserved2 = 0;
+
+ fOK = CreateProcess(
+ NULL,
+ wszCommandLine,
+ NULL,
+ NULL,
+ FALSE,
+ CREATE_NEW_CONSOLE,
+ NULL,
+ NULL,
+ &sui,
+ &pi);
+ if (fOK)
+ {
+ CloseHandle(pi.hThread);
+ CloseHandle(pi.hProcess);
+
+ stat = 0;
+ }
+ else
+ {
+ stat = GetLastError();
+ }
+
+ return (stat);
+}
+
+
+DWORD ConnectServer(void)
+{
+ RPC_STATUS stat;
+ WCHAR *pwszBinding;
+
+ stat = RpcStringBindingCompose(
+ NULL,
+ PWSZ_PROTOCOL,
+ NULL,
+ PWSZ_ENDPOINT,
+ NULL,
+ &pwszBinding);
+ if (stat == 0)
+ {
+ stat = RpcBindingFromStringBinding(pwszBinding, &g_hbindTest);
+ RpcStringFree(&pwszBinding);
+ }
+
+ return (stat);
+}
+
+
+DWORD DisconnectServer(void)
+{
+ RPC_STATUS stat;
+
+ stat = RpcBindingFree(&g_hbindTest);
+
+ return (stat);
+}
+
diff --git a/private/oleutest/memalloc/preinit.cxx b/private/oleutest/memalloc/preinit.cxx
new file mode 100644
index 000000000..6af5d512c
--- /dev/null
+++ b/private/oleutest/memalloc/preinit.cxx
@@ -0,0 +1,121 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: preinit.cxx
+//
+// Contents: Pre-initialization memory allocation tests
+//
+// Functions: TestPreInit
+//
+// History: 24-Jan-94 CarlH Created
+//
+//--------------------------------------------------------------------------
+#include "memtest.hxx"
+#pragma hdrstop
+
+
+static char g_szPreInit[] = "preinit";
+
+// WARNING: Do not just start whacking on the elements of this
+// array. The third element of each structure may hold
+// the index of another entry in the array. If elements
+// are inserted, these indices may get hosed!
+//
+static SMemTask g_amemtskPreInitialize[] =
+{
+ {memopAlloc, 128, 0, S_OK},
+ {memopFree, 0, 0, S_OK},
+ {memopAlloc, 12, 0, S_OK},
+ {memopAlloc, 1423, 0, S_OK},
+ {memopFree, 0, 2, S_OK},
+ {memopAlloc, 12, 0, S_OK},
+ {memopFree, 0, 3, S_OK},
+ {memopFree, 0, 5, S_OK}
+};
+
+static ULONG g_cmemtskPreInitialize =
+ sizeof(g_amemtskPreInitialize) / sizeof(g_amemtskPreInitialize[0]);
+
+
+BOOL TestGetAllocator(DWORD grfOptions);
+BOOL TestPreInitialize(DWORD grfOptions);
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: TestPreInitialize, public
+//
+// Synopsis: Tests pre-initialization memory allocation functionality
+//
+// Arguments: [grfOptions] - options for test
+//
+// Returns: TRUE if successful, FALSE otherwise
+//
+// History: 24-Jan-94 CarlH Created
+//
+//--------------------------------------------------------------------------
+BOOL TestPreInit(DWORD grfOptions)
+{
+ BOOL fPassed;
+
+ PrintHeader(g_szPreInit);
+
+ if (!(fPassed = TestGetAllocator(grfOptions)))
+ goto done;
+
+ if (!(fPassed = TestPreInitialize(grfOptions)))
+ goto done;
+
+done:
+ PrintResult(g_szPreInit, fPassed);
+
+ return (fPassed);
+}
+
+
+BOOL TestGetAllocator(DWORD grfOptions)
+{
+ IMalloc *pmalloc;
+ HRESULT hr;
+ BOOL fPassed;
+
+ PrintTrace(g_szPreInit, "testing default allocator\n");
+
+ hr = CoGetMalloc(MEMCTX_TASK, &pmalloc);
+ if (fPassed = SUCCEEDED(hr))
+ {
+ pmalloc->Release();
+ }
+
+ return (fPassed);
+}
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: TestPreInitialize, public
+//
+// Synopsis: Tests standard memory allocation routines
+//
+// Arguments: [grfOptions] - options for test
+//
+// Returns: TRUE if successful, FALSE otherwise
+//
+// History: 24-Jan-94 CarlH Created
+//
+//--------------------------------------------------------------------------
+BOOL TestPreInitialize(DWORD grfOptions)
+{
+ PrintTrace(g_szPreInit, "testing standard allocations\n");
+
+ return (
+ RunMemoryTasks(
+ g_szPreInit,
+ g_amemtskPreInitialize,
+ g_cmemtskPreInitialize));
+}
+
+
+
diff --git a/private/oleutest/memalloc/signal.cxx b/private/oleutest/memalloc/signal.cxx
new file mode 100644
index 000000000..a45a8b5e8
--- /dev/null
+++ b/private/oleutest/memalloc/signal.cxx
@@ -0,0 +1,89 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: signal.cxx
+//
+// Contents: Signal class implementation
+//
+// Classes: CSignal
+//
+// History: 29-Sep-93 CarlH Created
+//
+//--------------------------------------------------------------------------
+#include <windows.h>
+#include "signal.hxx"
+#pragma hdrstop
+
+
+CSignal::CSignal(WCHAR const *pwszName) :
+ _pwszName(new WCHAR[wcslen(pwszName) + 1]),
+ _hevent(0)
+{
+ wcscpy(_pwszName, pwszName);
+}
+
+
+CSignal::~CSignal(void)
+{
+ delete _pwszName;
+ if (_hevent != 0)
+ {
+ CloseHandle(_hevent);
+ }
+}
+
+
+DWORD CSignal::Wait(DWORD dwTimeout)
+{
+ DWORD stat = 0;
+
+ if (_hevent == 0)
+ {
+ _hevent = CreateEvent(NULL, TRUE, FALSE, _pwszName);
+ if (_hevent == 0)
+ {
+ stat = GetLastError();
+ }
+ }
+
+ if (stat == 0)
+ {
+ stat = WaitForSingleObject(_hevent, dwTimeout);
+ if (stat == 0)
+ {
+ ResetEvent(_hevent);
+ }
+ }
+
+ return (stat);
+}
+
+
+DWORD CSignal::Signal(void)
+{
+ DWORD stat = 0;
+
+ if (_hevent == 0)
+ {
+ _hevent = CreateEvent(NULL, TRUE, FALSE, _pwszName);
+ if (_hevent == 0)
+ {
+ stat = GetLastError();
+ }
+ }
+
+ if (stat == 0)
+ {
+ if (!SetEvent(_hevent))
+ {
+ stat = GetLastError();
+ }
+ }
+
+ return (stat);
+}
+
+
+
diff --git a/private/oleutest/memalloc/signal.hxx b/private/oleutest/memalloc/signal.hxx
new file mode 100644
index 000000000..a6545bac3
--- /dev/null
+++ b/private/oleutest/memalloc/signal.hxx
@@ -0,0 +1,39 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: signal.hxx
+//
+// Contents: Signal class delcrations
+//
+// Classes: CSignal
+//
+// Functions:
+//
+// History: 29-Sep-93 CarlH Created
+//
+//--------------------------------------------------------------------------
+#ifndef SIGNAL_HXX
+#define SIGNAL_HXX
+
+
+class CSignal
+{
+public:
+ CSignal(WCHAR const *pwszName);
+ ~CSignal(void);
+
+ DWORD Wait(DWORD dwTimeout = INFINITE);
+ DWORD Signal(void);
+
+private:
+ WCHAR *_pwszName;
+ HANDLE _hevent;
+};
+
+
+#endif
+
+
+
diff --git a/private/oleutest/memalloc/test.acf b/private/oleutest/memalloc/test.acf
new file mode 100644
index 000000000..62ea23711
--- /dev/null
+++ b/private/oleutest/memalloc/test.acf
@@ -0,0 +1,7 @@
+[
+ implicit_handle(handle_t g_hbindTest)
+]
+interface Test
+{
+}
+
diff --git a/private/oleutest/memalloc/test.idl b/private/oleutest/memalloc/test.idl
new file mode 100644
index 000000000..2d4e51008
--- /dev/null
+++ b/private/oleutest/memalloc/test.idl
@@ -0,0 +1,29 @@
+[
+ uuid(9D4ED230-A00B-101A-9160-08002B284C2C),
+ version(1.0),
+ endpoint("ncalrpc:[memtest]"),
+ pointer_default(unique)
+]
+interface Test
+{
+ cpp_quote("#define PWSZ_PROTOCOL L\"ncalrpc\"")
+ cpp_quote("#define PWSZ_ENDPOINT L\"memtest\"")
+
+ typedef struct
+ {
+ long cb;
+ [size_is(cb)] byte *pb;
+ } SCountedBytes;
+
+ typedef struct
+ {
+ long ccb;
+ [size_is(ccb)] SCountedBytes *pcb;
+ } SCountedCountedBytes;
+
+ boolean CopyBytes(
+ [in] SCountedCountedBytes *pccbIn,
+ [out] SCountedCountedBytes *pccbOut);
+ boolean StopServer(void);
+}
+
diff --git a/private/oleutest/ole1/clidemo/clidemo b/private/oleutest/ole1/clidemo/clidemo
new file mode 100644
index 000000000..3bb04e9ac
--- /dev/null
+++ b/private/oleutest/ole1/clidemo/clidemo
@@ -0,0 +1,37 @@
+# Nmake macros for building Windows 32-Bit apps
+
+!include <ntwin32.mak>
+
+my_lib = advapi32.lib olecli32.lib shell32.lib
+
+all: clidemo.exe
+
+# Update the resource if necessary
+
+clidemo.res: clidemo.rc
+ $(rc) $(rcvars) -r clidemo.rc
+
+# Update the object file if necessary
+
+clidemo.obj: clidemo.c
+ $(cc) $(cflags) $(cvars) $(cdebug) clidemo.c
+
+dialog.obj: dialog.c
+ $(cc) $(cflags) $(cvars) $(cdebug) dialog.c
+
+object.obj: object.c
+ $(cc) $(cflags) $(cvars) $(cdebug) object.c
+
+register.obj: register.c
+ $(cc) $(cflags) $(cvars) $(cdebug) register.c
+
+stream.obj: stream.c
+ $(cc) $(cflags) $(cvars) $(cdebug) stream.c
+
+utility.obj: utility.c
+ $(cc) $(cflags) $(cvars) $(cdebug) utility.c
+
+# Update the executable file if necessary, and if so, add the resource back in.
+
+clidemo.exe: clidemo.obj dialog.obj object.obj register.obj stream.obj utility.obj clidemo.res clidemo.def
+ $(link) $(linkdebug) $(guiflags) -out:clidemo.exe clidemo.obj dialog.obj object.obj register.obj stream.obj utility.obj clidemo.res $(guilibs) $(my_lib)
diff --git a/private/oleutest/ole1/clidemo/clidemo.c b/private/oleutest/ole1/clidemo/clidemo.c
new file mode 100644
index 000000000..f1ff6f8ba
--- /dev/null
+++ b/private/oleutest/ole1/clidemo/clidemo.c
@@ -0,0 +1,1032 @@
+/*
+ * clidemo.c - OLE client application sample code
+ *
+ * Created by Microsoft Corporation.
+ * (c) Copyright Microsoft Corp. 1990 - 1992 All Rights Reserved
+ *
+ */
+
+ /***************************************************************************
+ * IMPORTANT - README:
+ * OLE client applications are windows programs which use the OLE client
+ * APIs. Therefore it is imperative that you understand how these APIs
+ * operate. Most importantly it is essential that you keep in mind which
+ * procedure calls result in asynchronous states: a state where the operation
+ * is not truely complete after a return from the call.
+ *
+ * Many functions produce asynchronous states, for example, OleActivate,
+ * OleClose, OleCopyFromLink, OleCreate ... Reference your SDK manual for
+ * a complete list.
+ *
+ * So whenever you call any of these library functions keep in mind that
+ * the operation is not necessarily complete once a return is made.
+ * These operations require communications with a server application. With
+ * OLE the inter-application communication is done through DDE. In order
+ * for a DDE conversation to complete several DDE messages need to be
+ * sent and recieved by both the server and client OLE DLLs. So, the
+ * asynchronous operations will not complete until the client application
+ * enters a message dipatch loop. Therefore, it is necessary to enter
+ * a dispatch loop and wait for completion. It is not necessary to block
+ * all other operation; however, it is very important to coordinate the
+ * user activity to prevent disastrous re-entry cases.
+ *
+ * In this application I have written a macro to prevent re-entry
+ * problems. Namely: ANY_OBJECT_BUSY which prevents a user from initiating
+ * an action which will result in an asynchronous call if there is an object
+ * already in an asynchronous state.
+ *
+ * The following is brief summary of the three macros:
+ *
+ * ANY_OBJECT_BUSY: checks to see if any object in the document is busy.
+ * This prevents a new document from being saved to file if there are
+ * objects in asynchronous states.
+ *
+ * So, the problem is that we have to enter a message dispatch loop in order
+ * to let DDE messages get through so that asynchronous operations can finish.
+ * And while we are in the message dispatch loops (WaitForObject or WaitForAllObjects)
+ * we have to prevent the user from doing things that can't be done when an
+ * object(s) is busy. Yes, it is confusing , but, the end result is a super
+ * cool application that can have linked and embbeded objects!
+ ***************************************************************************/
+
+//*** INCLUDES ***
+
+#include <windows.h> //* WINDOWS
+#include <ole.h> //* OLE structs and defines
+#include <shellapi.h> //* Shell, drag and drop headers
+
+#include "demorc.h" //* header for resource file
+#include "global.h" //* global app variables
+#include "clidemo.h" //* app includes:
+#include "register.h"
+#include "stream.h"
+#include "object.h"
+#include "dialog.h"
+#include "utility.h"
+
+//*** VARIABLES ***
+
+//** Global
+HANDLE hInst;
+BOOL fRetry = FALSE;
+HWND hwndFrame; //* main window
+HANDLE hAccTable; //* accelerator table
+CHAR szFrameClass[] = "CliDemo";//* main window class name
+CHAR szItemClass[] = "ItemClass";//* item window class name
+CHAR szAppName[CBMESSAGEMAX];//* Application name
+INT iObjects = 0; //* object count
+INT iObjectNumber = 0; //* object number for object name
+CHAR szFileName[CBPATHMAX];
+
+extern INT giXppli ;
+extern INT giYppli ;
+ //* ClipBoard formats:
+OLECLIPFORMAT vcfLink; //* "ObjectLink"
+OLECLIPFORMAT vcfNative; //* "Native"
+OLECLIPFORMAT vcfOwnerLink; //* "OwnerLink"
+
+
+/***************************************************************************
+ * WinMain() - Main Windows routine
+ ***************************************************************************/
+int APIENTRY WinMain(
+ HINSTANCE hInstance,
+ HINSTANCE hPrevInst,
+ LPSTR lpCmdLine,
+ INT nCmdLine
+){
+ hInst = hInstance;
+
+ if (!InitApplication(hInst)) //* register window classes
+ return FALSE;
+
+ if (!InitInstance(hInst)) //* create window instance
+ return FALSE;
+
+ OfnInit(hInst); //* setup to use <commdlg.dll>
+
+ //* register clipboard formats
+ //* used for OLE
+ vcfLink = RegisterClipboardFormat("ObjectLink");
+ vcfNative = RegisterClipboardFormat("Native");
+ vcfOwnerLink = RegisterClipboardFormat("OwnerLink");
+
+
+ ShowWindow(hwndFrame, SW_SHOWNORMAL);
+ UpdateWindow(hwndFrame);
+ ProcessCmdLine(lpCmdLine);
+
+ while (ProcessMessage(hwndFrame, hAccTable)) ;
+
+ return FALSE;
+}
+
+/***************************************************************************
+ * InitApplication()
+ *
+ * registers the window classes used by the application.
+ *
+ * Returns BOOL: - TRUE if successful.
+ ***************************************************************************/
+
+static BOOL InitApplication( //* ENTRY:
+ HANDLE hInst //* instance handle
+){ //* LOCAL:
+ WNDCLASS wc; //* temp wind-class structure
+
+ wc.style = 0;
+ wc.lpfnWndProc = (WNDPROC)FrameWndProc;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = 0;
+ wc.hInstance = hInst;
+ wc.hIcon = LoadIcon(hInst, MAKEINTRESOURCE(ID_APPLICATION));
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wc.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE + 1);
+ wc.lpszMenuName = MAKEINTRESOURCE(ID_APPLICATION);
+ wc.lpszClassName = szFrameClass;
+
+ if (!RegisterClass(&wc))
+ return FALSE;
+ //* application item class
+ wc.style = CS_DBLCLKS | CS_VREDRAW | CS_HREDRAW;
+ wc.lpfnWndProc = (WNDPROC)ItemWndProc;
+ wc.hIcon = NULL;
+ wc.cbWndExtra = sizeof(APPITEMPTR);
+ wc.lpszMenuName = NULL;
+ wc.lpszClassName = szItemClass;
+
+ if (!RegisterClass(&wc))
+ return FALSE;
+
+ return TRUE;
+
+}
+
+/***************************************************************************
+ * InitInstance()
+ *
+ * create the main application window.
+ *
+ * Returns BOOL: - TRUE if successful else FALSE.
+ ***************************************************************************/
+
+static BOOL InitInstance( //* ENTRY:
+ HANDLE hInst //* instance handel
+){
+ HDC hDC ;
+
+ hAccTable = LoadAccelerators(hInst, MAKEINTRESOURCE(ID_APPLICATION));
+
+ if (!(hwndFrame =
+ CreateWindow(
+ szFrameClass, "",
+ WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
+ CW_USEDEFAULT, CW_USEDEFAULT,
+ CW_USEDEFAULT, CW_USEDEFAULT,
+ NULL,
+ NULL,
+ hInst,
+ NULL
+ )))
+ return FALSE; //* ERROR return
+
+ LoadString(hInst, IDS_APPNAME, szAppName, CBMESSAGEMAX);
+ DragAcceptFiles(hwndFrame, TRUE); //* allow dragged and dropped files
+
+ hDC = GetDC (NULL); // Get the hDC of the desktop window
+ giXppli = GetDeviceCaps (hDC, LOGPIXELSX);
+ giYppli = GetDeviceCaps (hDC, LOGPIXELSY);
+ ReleaseDC (NULL, hDC);
+
+
+
+ return TRUE; //* SUCCESS return
+
+}
+
+/***************************************************************************
+ * ProcessCmdLine()
+ *
+ * process command line getting any command arguments.
+ ***************************************************************************/
+
+VOID ProcessCmdLine(LPSTR lpCmdLine)
+{ //* LOCAL:
+ OFSTRUCT ofs;
+
+
+ if (*lpCmdLine)
+ { //* look for file extension
+ LPSTR lpstrExt = lpCmdLine; //* pointer to file extension
+
+ while (*lpstrExt && *lpstrExt != '.')
+ lpstrExt = AnsiNext(lpstrExt);
+
+ lstrcpy(szFileName, lpCmdLine);
+ if (!(*lpstrExt)) //* append default extension
+ {
+ lstrcat(szFileName,".");
+ lstrcat(szFileName,szDefExtension);
+ }
+ //* get the files fully
+ OpenFile(szFileName, &ofs, OF_PARSE);//* qualified name
+ lstrcpy(szFileName, ofs.szPathName);
+ }
+ else
+ *szFileName = 0;
+ //* pass filename to main winproc
+ SendMessage(hwndFrame,WM_INIT,(WPARAM)0,(LPARAM)0);
+
+}
+
+
+/***************************************************************************
+ * FrameWndProc()
+ *
+ * Message handler for the application frame window.
+ *
+ * Returns long - Variable, depends on message.
+ ***************************************************************************/
+
+LONG APIENTRY FrameWndProc( //* ENTRY:
+ HWND hwnd, //* standard wind-proc parameters
+ UINT msg,
+ DWORD wParam,
+ LONG lParam
+){ //* LOCAL:
+ //* ^ Document file name
+ static LHCLIENTDOC lhcDoc; //* Document Handle
+ static LPOLECLIENT lpClient; //* pointer to client
+ static LPAPPSTREAM lpStream; //* pointer to stream vtbl
+ APPITEMPTR pItem; //* application item pointer
+
+ switch (msg)
+ {
+ case WM_INIT: //* user defined message
+ if (!InitAsOleClient(hInst, hwnd, szFileName, &lhcDoc, &lpClient, &lpStream))
+ DestroyWindow(hwnd);
+ break;
+ //* the following three messages are
+ //* used to avoid problems with OLE
+ //* see the comment in object.h
+ case WM_DELETE: //* user defined message
+ pItem = (APPITEMPTR) lParam; //* delete object
+ WaitForObject(pItem);
+ ObjDelete(pItem,OLE_OBJ_DELETE);
+ if (wParam)
+ cOleWait--;
+ break;
+
+ case WM_ERROR: //* user defined message
+ ErrorMessage(wParam); //* display error message
+ break;
+
+ case WM_RETRY: //* user defined message
+ RetryMessage((APPITEMPTR)lParam, RD_RETRY | RD_CANCEL);
+ break;
+
+ case WM_INITMENU:
+ UpdateMenu((HMENU)wParam);
+ break;
+
+ case WM_COMMAND:
+ {
+ WORD wID = LOWORD(wParam);
+
+ pItem = GetTopItem();
+
+ switch (wID)
+ {
+ case IDM_NEW:
+ ANY_OBJECT_BUSY;
+ NewFile(szFileName,&lhcDoc,lpStream);
+ break;
+
+ case IDM_OPEN:
+ ANY_OBJECT_BUSY;
+ MyOpenFile(szFileName,&lhcDoc,lpClient,lpStream);
+ break;
+
+ case IDM_SAVE:
+ ANY_OBJECT_BUSY;
+ SaveFile(szFileName,lhcDoc,lpStream);
+ break;
+
+ case IDM_SAVEAS:
+ ANY_OBJECT_BUSY;
+ SaveasFile(szFileName,lhcDoc,lpStream);
+ break;
+
+ case IDM_ABOUT:
+ AboutBox();
+ break;
+
+ case IDM_INSERT:
+ ANY_OBJECT_BUSY;
+ ObjInsert(lhcDoc, lpClient);
+ break;
+
+ case IDM_INSERTFILE:
+ ANY_OBJECT_BUSY;
+ ObjCreateFromTemplate(lhcDoc,lpClient);
+ break;
+
+ case IDM_PASTE:
+ case IDM_PASTELINK:
+ ANY_OBJECT_BUSY;
+ ObjPaste(wID == IDM_PASTE,lhcDoc,lpClient);
+ break;
+
+ case IDM_LINKS:
+ ANY_OBJECT_BUSY;
+ pItem = GetTopItem();
+ LinkProperties();
+ break;
+
+ case IDM_EXIT:
+ ANY_OBJECT_BUSY;
+ SendMessage(hwnd, WM_SYSCOMMAND, SC_CLOSE, 0L);
+ break;
+
+ case IDM_COPY:
+ case IDM_CUT:
+ ANY_OBJECT_BUSY;
+
+ if (!ObjCopy(pItem))
+ {
+ ErrorMessage((wParam == IDM_CUT) ?
+ E_CLIPBOARD_CUT_FAILED : E_CLIPBOARD_COPY_FAILED);
+ break;
+ }
+
+ if (wParam == IDM_COPY)
+ break;
+
+ case IDM_CLEAR: //* CUT falls through to clear
+ ANY_OBJECT_BUSY;
+ ClearItem(pItem);
+ break;
+
+ case IDM_CLEARALL:
+ ANY_OBJECT_BUSY;
+ ClearAll(lhcDoc,OLE_OBJ_DELETE);
+ Dirty(DOC_DIRTY);
+ break;
+
+ default:
+ if( (wParam >= IDM_VERBMIN) && (wParam <= IDM_VERBMAX) )
+ {
+ ANY_OBJECT_BUSY;
+ ExecuteVerb(wParam - IDM_VERBMIN,pItem);
+ break;
+ }
+ return DefWindowProc(hwnd, msg, wParam, lParam);
+ }
+ break;
+ }
+
+ case WM_DROPFILES:
+ ANY_OBJECT_BUSY;
+ ObjCreateWrap((HANDLE)wParam, lhcDoc, lpClient);
+ break;
+
+ case WM_CLOSE:
+ ANY_OBJECT_BUSY;
+ if (!SaveAsNeeded(szFileName, lhcDoc, lpStream))
+ break;
+ DeregDoc(lhcDoc);
+ DestroyWindow(hwnd);
+ break;
+
+ case WM_DESTROY:
+ EndStream(lpStream);
+ EndClient(lpClient);
+ PostQuitMessage(0);
+ break;
+
+ case WM_QUERYENDSESSION: //* don't let windows terminate
+ return (QueryEndSession(szFileName,lhcDoc, lpStream));
+
+ default:
+ return DefWindowProc(hwnd, msg, wParam, lParam);
+ }
+ return 0L;
+
+}
+
+/***************************************************************************
+ * InitAsOleClient()
+ *
+ * Initiates the creation of stream and client vtbls. These vtbls are very
+ * important for the proper operation of this application. The stream vtbl
+ * lets the OLE librarys know where the location of the stream I/O routines
+ * reside. The stream routines are used by OleLoadFromStream and the like.
+ * The client vtbl is used to hold the pointer to the CallBack function.
+ * IMPORTANT: both the client and the stream structures have pointers to
+ * vtbls which have the pointers to the functions. Therefore, it is
+ * necessary to allocate space for the vtbl and the client structure
+ * which has the pointer to the vtbl.
+ **************************************************************************/
+
+static BOOL InitAsOleClient( //* ENTRY:
+ HANDLE hInstance, //* applicaion instance handle
+ HWND hwnd, //* main window handle
+ PSTR pFileName, //* document file name
+ LHCLIENTDOC *lhcDoc, //* pointer to document Handle
+ LPOLECLIENT *lpClient, //* pointer to client pointer
+ LPAPPSTREAM *lpStream //* pointer to APPSTREAM pointer
+){
+ //* initiate client vtbl creation
+ if (!(*lpClient = InitClient(hInstance)))
+ {
+ SendMessage(hwnd, WM_SYSCOMMAND, SC_CLOSE, 0L);
+ return FALSE; //* ERROR return
+ }
+ //* initiate stream vtbl creation
+ if (!(*lpStream = InitStream(hInstance)))
+ {
+ SendMessage(hwnd, WM_SYSCOMMAND, SC_CLOSE, 0L);
+ return FALSE; //* ERROR return
+ }
+
+ if (*pFileName && RegDoc(pFileName,lhcDoc)
+ && LoadFile(pFileName,*lhcDoc,*lpClient,*lpStream))
+ {
+ SetTitle(pFileName);
+ return TRUE; //* SUCCESS return
+ }
+
+ NewFile(pFileName, lhcDoc, *lpStream);
+ return TRUE; //* SUCCESS return
+
+} //* SUCCESS return
+
+/****************************************************************************
+ * InitClient()
+ *
+ * Initialize the OLE client structure, create and fill the OLECLIENTVTBL
+ * structure.
+ *
+ * Returns LPOLECLIENT - if successful a pointer to a client structure
+ * , otherwise NULL.
+ ***************************************************************************/
+
+static LPOLECLIENT InitClient( //* ENTRY:
+ HANDLE hInstance //* application instance handle
+){ //* LOCAL:
+ LPOLECLIENT lpClient=NULL; //* pointer to client struct
+ //* Allocate vtbls
+ if (!(lpClient = (LPOLECLIENT)GlobalLock(
+ GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT, sizeof(OLECLIENT))
+ )))
+ goto Error; //* ERROR jump
+
+ if (!(lpClient->lpvtbl = (LPOLECLIENTVTBL)GlobalLock(
+ GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT, sizeof(OLECLIENTVTBL))
+ )))
+ goto Error; //* ERROR jump
+ //* set the CALLBACK function
+ //* pointer
+ lpClient->lpvtbl->CallBack = CallBack;
+
+ return lpClient; //* SUCCESS return
+
+Error: //* ERROR Tag
+
+ ErrorMessage(E_FAILED_TO_ALLOC);
+ EndClient(lpClient); //* free any allocated space
+
+ return NULL; //* ERROR return
+
+}
+
+/****************************************************************************
+ * InitStream()
+ *
+ * Create and fill the STREAMVTBL. Create a stream structure and initialize
+ * pointer to stream vtbl.
+ *
+ * Returns LPAPPSTREAM - if successful a pointer to a stream structure
+ * , otherwise NULL .
+ ***************************************************************************/
+
+static LPAPPSTREAM InitStream( //* ENTRY:
+ HANDLE hInstance //* handle to application instance
+){ //* LOCAL:
+ LPAPPSTREAM lpStream = NULL; //* pointer to stream structure
+
+ if (!(lpStream = (LPAPPSTREAM)GlobalLock(
+ GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT, sizeof(APPSTREAM))
+ )))
+ goto Error; //* ERROR jump
+
+ if (!(lpStream->olestream.lpstbl = (LPOLESTREAMVTBL)GlobalLock(
+ GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT, sizeof(OLESTREAMVTBL))
+ )))
+ goto Error; //* ERROR jump
+
+ //* set stream func. pointers
+ lpStream->olestream.lpstbl->Get = (DWORD ( CALLBACK *)(LPOLESTREAM, VOID FAR *, DWORD)) ReadStream;
+ lpStream->olestream.lpstbl->Put = (DWORD ( CALLBACK *)(LPOLESTREAM, OLE_CONST VOID FAR *, DWORD)) WriteStream;
+
+ return lpStream; //* SUCCESS return
+
+Error: //* ERROR Tag
+
+ ErrorMessage(E_FAILED_TO_ALLOC);
+ EndStream(lpStream);
+
+ return NULL; //* ERROR return
+
+}
+
+/***************************************************************************
+ * UpdateMenu()
+ *
+ * Enabling or disable menuitems based upon program state.
+ ***************************************************************************/
+
+static VOID UpdateMenu( //* ENTRY:
+ HMENU hMenu //* menu handle to updated
+){ //* LOCAL:
+ INT mf; //* generic menu flag
+ APPITEMPTR paItem; //* app item pointer
+ HMENU hSub;
+ //* there must be at least on object
+ //* for the following to be enabled
+
+ paItem = GetTopItem() ;
+
+ mf = (paItem ? MF_ENABLED : MF_GRAYED);
+ EnableMenuItem(hMenu, IDM_CUT, mf); //* i.e. Cut,Copy,Clear,Clearall...
+ EnableMenuItem(hMenu, IDM_COPY, mf);
+ EnableMenuItem(hMenu, IDM_CLEAR, mf);
+ EnableMenuItem(hMenu, IDM_CLEARALL, mf);
+ //* enable links option only if there
+ //* is at least one linked object
+ EnableMenuItem(hMenu, IDM_LINKS, MF_GRAYED);
+ for (; paItem; paItem = GetNextItem(paItem))
+ {
+ if (paItem->otObject == OT_LINK)
+ {
+ EnableMenuItem(hMenu, IDM_LINKS, MF_ENABLED);
+ break;
+ }
+ }
+
+ if (hSub = GetSubMenu(hMenu,POS_EDITMENU))
+ UpdateObjectMenuItem(hSub);
+
+ if (OleQueryCreateFromClip(STDFILEEDITING, olerender_draw, 0) == OLE_OK)
+ EnableMenuItem(hMenu, IDM_PASTE, MF_ENABLED);
+ else if (OleQueryCreateFromClip(STATICP, olerender_draw, 0) == OLE_OK)
+ EnableMenuItem(hMenu, IDM_PASTE, MF_ENABLED);
+ else
+ EnableMenuItem(hMenu, IDM_PASTE, MF_GRAYED);
+
+ if (OleQueryLinkFromClip(STDFILEEDITING, olerender_draw, 0) == OLE_OK)
+ EnableMenuItem(hMenu, IDM_PASTELINK, MF_ENABLED);
+ else
+ EnableMenuItem(hMenu, IDM_PASTELINK, MF_GRAYED);
+
+}
+
+/***************************************************************************
+ * NewFile()
+ *
+ * Save the present document and open a new blank one.
+ ***************************************************************************/
+
+static VOID NewFile( //* ENTRY:
+ PSTR pFileName, //* open file name
+ LHCLIENTDOC *lhcptrDoc, //* pointer to client doc. handle
+ LPAPPSTREAM lpStream //* pointer to stream structure
+){ //* LOCAL:
+ static CHAR szUntitled[CBMESSAGEMAX] = "";//* "(Untitled)" string
+ LHCLIENTDOC lhcDocNew; //* handle for new doc.
+
+ if (!(*szUntitled))
+ LoadString(hInst, IDS_UNTITLED, (LPSTR)szUntitled, CBMESSAGEMAX);
+
+ if (SaveAsNeeded(pFileName, *lhcptrDoc, lpStream))
+ { //* try to register new document
+ if (!RegDoc(szUntitled, &lhcDocNew))
+ return; //* before deregistring the old one
+ DeregDoc(*lhcptrDoc);
+ *lhcptrDoc = lhcDocNew;
+ Dirty(DOC_CLEAN); //* new document is clean
+ lstrcpy(pFileName,szUntitled);
+ SetTitle(pFileName);
+ iObjectNumber = 0;
+ }
+
+}
+
+/***************************************************************************
+ * MyOpenFile()
+ *
+ * Open a file and load it. Notice that the new file is loaded before
+ * the old is removed. This is done to assure a succesful file load
+ * before removing an existing document.
+ ***************************************************************************/
+
+static VOID MyOpenFile( //* ENTRY:
+ PSTR pFileName, //* open file name
+ LHCLIENTDOC *lhcptrDoc, //* pointer to document handle
+ LPOLECLIENT lpClient, //* pointer to client structure
+ LPAPPSTREAM lpStream //* pointer to stream structure
+){ //* LOCAL:
+ CHAR szNewFile[CBPATHMAX];//* new file name buffer
+ LHCLIENTDOC lhcDocNew; //* handle of new document
+ APPITEMPTR pItem; //* hold top item
+
+ if (SaveAsNeeded(pFileName, *lhcptrDoc, lpStream))
+ {
+ *szNewFile = 0;
+
+ if (!OfnGetName(hwndFrame, szNewFile, IDM_OPEN))
+ return; //* ERROR return
+
+ if (!RegDoc(szNewFile,&lhcDocNew))
+ return; //* ERROR return
+
+ pItem = GetTopItem();
+ ShowDoc(*lhcptrDoc,0); //* make old doc objects hidden.
+ //* try to load the new file before
+ if (!LoadFile(szNewFile, lhcDocNew, lpClient, lpStream))
+ { //* before removing the old.
+ DeregDoc(lhcDocNew); //* restore old document if new
+ SetTopItem(pItem); //* file did not load
+ ShowDoc(*lhcptrDoc,1);
+ return; //* ERROR return
+ }
+
+ DeregDoc(*lhcptrDoc); //* deregister old document
+ *lhcptrDoc = lhcDocNew;
+ lstrcpy(pFileName,szNewFile);
+ SetTitle(pFileName); //* set new title
+ Dirty(DOC_CLEAN);
+ }
+
+} //* SUCCESS return
+
+/***************************************************************************
+ * SaveasFile()
+ *
+ * Prompt the user for a new file name. Write the document to the new
+ * filename.
+ ***************************************************************************/
+
+static VOID SaveasFile( //* ENTRY:
+ PSTR pFileName, //* old filename
+ LHCLIENTDOC lhcDoc, //* document handle
+ LPAPPSTREAM lpStream //* pointer to stream structure
+){
+ CHAR szNewFile[CBPATHMAX];//* new file name
+
+ *szNewFile = 0; //* prompt user for new file name
+ if (!OfnGetName(hwndFrame, szNewFile, IDM_SAVEAS))
+ return; //* ERROR return
+ //* rename document
+ if (!SaveFile(szNewFile, lhcDoc, lpStream))
+ return;
+
+ if (Error(OleRenameClientDoc(lhcDoc, szNewFile)))
+ {
+ ErrorMessage(W_FAILED_TO_NOTIFY);
+ return; //* ERROR return
+ }
+
+ lstrcpy(pFileName,szNewFile);
+ SetTitle(pFileName);
+
+} //* SUCCESS return
+
+/***************************************************************************
+ * SaveFile()
+ *
+ * Save a compound document file. If the file is untitled, ask the user
+ * for a name and save the document to that file.
+ ***************************************************************************/
+
+static BOOL SaveFile( //* ENTRY:
+ PSTR pFileName, //* file to save document to
+ LHCLIENTDOC lhcDoc, //* OLE document handle
+ LPAPPSTREAM lpStream //* pointer to app. stream struct
+){ //* LOCAL:
+ CHAR szNewFile[CBPATHMAX];//* New file name strings
+ CHAR szOemFileName[2*CBPATHMAX];
+ static CHAR szUntitled[CBMESSAGEMAX] = "";
+ int fh; //* file handle
+
+ *szNewFile = 0;
+ if (!(*szUntitled))
+ LoadString(hInst, IDS_UNTITLED, (LPSTR)szUntitled, CBMESSAGEMAX);
+
+ if (!lstrcmp(szUntitled, pFileName))//* get filename for the untitled case
+ {
+ if (!OfnGetName(hwndFrame, szNewFile, IDM_SAVEAS))
+ return FALSE; //* CANCEL return
+ lstrcpy(pFileName,szNewFile);
+ SetTitle(pFileName);
+ }
+
+ AnsiToOem(pFileName, szOemFileName);
+ if ((fh = _lcreat((LPSTR)szOemFileName, 0)) <= 0)
+ {
+ ErrorMessage(E_INVALID_FILENAME);
+ return FALSE; //* ERROR return
+ }
+
+ lpStream->fh = fh;
+ //* save file on disk
+ if (!WriteToFile(lpStream))
+ {
+ _lclose(fh);
+ ErrorMessage(E_FAILED_TO_SAVE_FILE);
+ return FALSE; //* ERROR return
+ }
+ _lclose(fh);
+
+ if (Error(OleSavedClientDoc(lhcDoc)))
+ {
+ ErrorMessage(W_FAILED_TO_NOTIFY);
+ return FALSE; //* ERROR return
+ }
+
+ Dirty(DOC_CLEAN);
+ return TRUE; //* SUCCESS return
+
+}
+
+/***************************************************************************
+ * LoadFile()
+ *
+ * Load a document file from disk.
+ ***************************************************************************/
+
+static BOOL LoadFile( //* ENTRY:
+ PSTR pFileName, //* file name
+ LHCLIENTDOC lhcDoc, //* document handle
+ LPOLECLIENT lpClient, //* pointer to client structure
+ LPAPPSTREAM lpStream //* pointer to stream structure
+){ //* LOCAL:
+ //* OEM file name
+ CHAR szOemFileName[2*CBPATHMAX];
+ int fh; //* file handle
+ INT iObjectNumberHold; //* hold object number
+
+ AnsiToOem(pFileName, szOemFileName);
+ if ((fh = _lopen(szOemFileName, OF_READ | OF_SHARE_DENY_WRITE)) == -1)
+ {
+ ErrorMessage(E_FAILED_TO_READ_FILE);
+ return FALSE; //* ERROR return
+ }
+
+ lpStream->fh = fh;
+
+ iObjectNumberHold = iObjectNumber; //* save object number so it can
+ iObjectNumber = 0; //* be restored if read from file
+ //* fails
+ if (!ReadFromFile(lpStream, lhcDoc, lpClient))
+ {
+ _lclose(fh);
+ ErrorMessage(E_FAILED_TO_READ_FILE);
+ iObjectNumber = iObjectNumberHold;
+ return FALSE; //* ERROR return
+ }
+ _lclose(fh);
+ return TRUE; //* SUCCESS return
+
+}
+
+/***************************************************************************
+ * RegDoc()
+ *
+ * Register the client document with the OLE library.
+ **************************************************************************/
+
+static BOOL RegDoc( //* ENTRY:
+ PSTR pFileName, //* file name
+ LHCLIENTDOC *lhcptrDoc //* pointer to client document handle
+){
+
+ if (Error(OleRegisterClientDoc(szAppName, (LPSTR)pFileName, 0L, lhcptrDoc)))
+ {
+ ErrorMessage(W_FAILED_TO_NOTIFY);
+ return FALSE; //* ERROR return
+ }
+ return TRUE; //* SUCCESS return
+
+}
+
+/****************************************************************************
+ * DeregDoc()
+ *
+ * This function initiates the removal of all OLE objects from the
+ * current document and deregisters the document with the OLE library.
+ ***************************************************************************/
+
+static VOID DeregDoc( //* ENTRY:
+ LHCLIENTDOC lhcDoc //* client document handle
+){
+
+ if (lhcDoc)
+ { //* release all OLE objects
+ ClearAll(lhcDoc,OLE_OBJ_RELEASE); //* and remove them from the screen
+ WaitForAllObjects();
+ if (Error(OleRevokeClientDoc(lhcDoc)))
+ ErrorMessage(W_FAILED_TO_NOTIFY);
+ }
+
+} //* SUCCESS return
+
+/***************************************************************************
+ * ClearAll()
+ *
+ * This function will destroy all of the item windows in the current
+ * document and delete all OLE objects. The loop is basically an enum
+ * of all child windows.
+ **************************************************************************/
+
+static VOID ClearAll( //* ENTRY:
+ LHCLIENTDOC lhcDoc, //* application document handle
+ BOOL fDelete //* Delete / Release
+){ //* LOCAL:
+ APPITEMPTR pItemNext; //* working handles
+ APPITEMPTR pItem; //* pointer to application item
+
+ pItem = GetTopItem();
+
+ while (pItem)
+ {
+ pItemNext = GetNextItem(pItem);
+ if (pItem->lhcDoc == lhcDoc)
+ ObjDelete(pItem, fDelete);
+ pItem = pItemNext;
+ }
+
+}
+ //* SUCCESS return
+/***************************************************************************
+ * ClearItem()
+ *
+ * This function will destroy an item window, and make the
+ * next window active.
+ **************************************************************************/
+
+VOID FAR ClearItem( //* ENTRY:
+ APPITEMPTR pItem //* application item pointer
+){
+
+ pItem->fVisible = FALSE;
+ SetTopItem(GetNextActiveItem());
+ ObjDelete(pItem, OLE_OBJ_DELETE);
+ Dirty(DOC_DIRTY);
+
+}
+
+/****************************************************************************
+ * SaveAsNeeded()
+ *
+ * This function will have the file saved if and only
+ * if the document has been modified. If the fDirty flag has
+ * been set to TRUE, then the document needs to be saved.
+ *
+ * Returns: BOOL - TRUE if document doesn't need saving or if the
+ * document has been saved successfully.
+ ***************************************************************************/
+
+static BOOL SaveAsNeeded( //* ENTRY:
+ PSTR pFileName, //* file to save
+ LHCLIENTDOC lhcDoc, //* OLE doc handle
+ LPAPPSTREAM lpStream //* pointer to OLE stream vtbl ...
+){ //* LOCAL:
+ CHAR sz[CBMESSAGEMAX]; //* work strings
+ CHAR sz2[CBMESSAGEMAX + CBPATHMAX];
+
+ if (Dirty(DOC_QUERY)) //* if doc is clean don't bother
+ {
+
+ LoadString(hInst, IDS_MAYBESAVE, sz, CBMESSAGEMAX);
+ wsprintf(sz2, sz, (LPSTR)pFileName );
+
+ switch (MessageBox(hwndFrame, sz2, szAppName, MB_YESNOCANCEL | MB_ICONQUESTION))
+ {
+
+ case IDCANCEL:
+ return FALSE; //* CANCEL return
+
+ case IDYES:
+ return (SaveFile(pFileName,lhcDoc,lpStream));
+
+ default:
+ break;
+ }
+ }
+ return TRUE; //* SUCCESS return
+
+}
+
+/****************************************************************************
+ * SetTitle()
+ *
+ * Set the window caption to the current file name. If szFileName is
+ * NULL, the caption will be set to "(Untitled)".
+ ***************************************************************************/
+
+static VOID SetTitle( //* ENTRY:
+ PSTR pFileName //* file name
+){ //* LOCAL
+ //* window title string
+ CHAR szTitle[CBMESSAGEMAX + CBPATHMAX];
+
+ wsprintf(szTitle, "%s - %s", (LPSTR)szAppName, (LPSTR)pFileName);
+ SetWindowText(hwndFrame, szTitle);
+
+}
+
+/***************************************************************************
+ * EndClient()
+ *
+ * Perform cleanup prior to app termination. The OLECLIENT
+ * memory blocks and procedure instance thunks freed.
+ **************************************************************************/
+
+static VOID EndStream( //* ENTRY:
+ LPAPPSTREAM lpStream //* pointer to stream structure
+){ //* LOCAL:
+ HANDLE hGeneric; //* temp handle
+
+ if (lpStream) //* is there a STREAM struct?
+ {
+ if (lpStream->olestream.lpstbl)
+ {
+ FreeProcInstance((FARPROC)lpStream->olestream.lpstbl->Get);
+ FreeProcInstance((FARPROC)lpStream->olestream.lpstbl->Put);
+ hGeneric = GlobalHandle((LPSTR)lpStream->olestream.lpstbl);
+ GlobalUnlock(hGeneric);
+ GlobalFree(hGeneric);
+ }
+ hGeneric = GlobalHandle((LPSTR)lpStream);
+ GlobalUnlock(hGeneric);
+ GlobalFree(hGeneric);
+ }
+
+} //* SUCCESS return
+
+/***************************************************************************
+ * EndClient()
+ *
+ * Perform cleanup prior to app termination. The OLECLIENT
+ * memory blocks and procedure instance thunks are freed.
+ **************************************************************************/
+
+static VOID EndClient( //* ENTRY:
+ LPOLECLIENT lpClient //* pointer to client structure
+){ //* LOCAL:
+ HANDLE hGeneric; //* temp handle
+
+ if (lpClient) //* is there a client structure
+ {
+ if (lpClient->lpvtbl)
+ {
+ FreeProcInstance(lpClient->lpvtbl->CallBack);
+ hGeneric = GlobalHandle((LPSTR)lpClient->lpvtbl);
+ GlobalUnlock(hGeneric);
+ GlobalFree(hGeneric);
+ }
+ hGeneric = GlobalHandle((LPSTR)lpClient);
+ GlobalUnlock(hGeneric);
+ GlobalFree(hGeneric);
+ }
+
+} //* SUCCESS return
+
+/****************************************************************************
+ * QueryEndSession()
+ ***************************************************************************/
+
+static LONG QueryEndSession( //* ENTRY:
+ PSTR pFileName, //* document name
+ LHCLIENTDOC lhcDoc, //* client document handle
+ LPAPPSTREAM lpStream //* application stream pointer
+){ //* LOCAL:
+ APPITEMPTR pItem; //* application item pointer
+
+
+ for (pItem = GetTopItem(); pItem; pItem = GetNextItem(pItem))
+ if (OleQueryOpen(pItem->lpObject) == OLE_OK)
+ {
+ MessageBox(hwndFrame,"Exit CliDemo1 before closing Windows",
+ szAppName, MB_OK | MB_ICONSTOP);
+ return 0L;
+ }
+
+ if (!SaveAsNeeded(pFileName, lhcDoc, lpStream))
+ return 0L;
+ DeregDoc(lhcDoc);
+ return 1L;
+
+}
+
diff --git a/private/oleutest/ole1/clidemo/clidemo.def b/private/oleutest/ole1/clidemo/clidemo.def
new file mode 100644
index 000000000..faecf4704
--- /dev/null
+++ b/private/oleutest/ole1/clidemo/clidemo.def
@@ -0,0 +1,35 @@
+NAME clidemo
+
+DESCRIPTION 'Microsoft OLE Sample Client Application'
+
+EXETYPE WINDOWS
+
+CODE PRELOAD MOVEABLE DISCARDABLE
+DATA PRELOAD MOVEABLE MULTIPLE
+
+HEAPSIZE 16000
+STACKSIZE 32000
+
+EXPORTS
+; Window procedures
+;
+ FrameWndProc @1
+ ItemWndProc @2
+
+; Dialog procedures
+;
+ fnProperties @3
+ fnInsertNew @4
+ fnAbout @5
+ fnRetry @6
+ fnInvalidLink @7
+
+; OLE Client callbacks
+;
+ CallBack @8
+ ReadStream @9
+ WriteStream @10
+
+; timer callback
+;
+ fnTimerBlockProc @11
diff --git a/private/oleutest/ole1/clidemo/clidemo.h b/private/oleutest/ole1/clidemo/clidemo.h
new file mode 100644
index 000000000..a7535359e
--- /dev/null
+++ b/private/oleutest/ole1/clidemo/clidemo.h
@@ -0,0 +1,62 @@
+/*
+ * clidemo.h
+ *
+ * Created by Microsoft Corporation.
+ * (c) Copyright Microsoft Corp. 1990 - 1992 All Rights Reserved
+ */
+
+//*** CONSTANTS ***
+
+#define CXDEFAULT 400 //* Default object size: 400 x 300
+#define CYDEFAULT 300
+#define COBJECTSMAX 50 //* max number of objects in our app
+
+//*** PROTOTYPES ***
+
+//*** Exported window procedures
+
+LONG APIENTRY FrameWndProc(HWND, UINT, DWORD, LONG);
+
+//*** FAR
+
+VOID FAR FixObjectBounds(LPRECT lprc);
+
+//*** Local
+
+static LPOLECLIENT InitClient(HANDLE);
+static VOID EndClient(LPOLECLIENT);
+static LPAPPSTREAM InitStream(HANDLE);
+static VOID EndStream(LPAPPSTREAM);
+static VOID ProcessCmdLine(LPSTR);
+static BOOL InitApplication(HANDLE);
+static BOOL InitInstance(HANDLE);
+static VOID SetTitle(PSTR);
+static VOID MyOpenFile(PSTR,LHCLIENTDOC *, LPOLECLIENT, LPAPPSTREAM);
+static VOID NewFile(PSTR,LHCLIENTDOC *, LPAPPSTREAM);
+static BOOL SaveFile(PSTR, LHCLIENTDOC, LPAPPSTREAM);
+static VOID SaveasFile(PSTR, LHCLIENTDOC, LPAPPSTREAM);
+static BOOL LoadFile(PSTR, LHCLIENTDOC, LPOLECLIENT, LPAPPSTREAM);
+static VOID ClearAll(LHCLIENTDOC, BOOL);
+static VOID EndInstance(VOID);
+static BOOL SaveAsNeeded(PSTR,LHCLIENTDOC,LPAPPSTREAM);
+static VOID UpdateMenu(HMENU);
+static BOOL RegDoc(PSTR, LHCLIENTDOC *);
+static VOID DeregDoc(LHCLIENTDOC);
+static BOOL InitAsOleClient(HANDLE, HWND, PSTR, LHCLIENTDOC *, LPOLECLIENT *, LPAPPSTREAM *);
+VOID FAR ClearItem(APPITEMPTR);
+static LONG QueryEndSession(PSTR, LHCLIENTDOC, LPAPPSTREAM);
+
+//*** MACROS ***
+
+/*
+ * ANY_OBJECT_BUSY
+ * checks to see if any object in the document is busy. This prevents
+ * a new document from being saved to file if there are objects in
+ * asynchronous states.
+ */
+
+#define ANY_OBJECT_BUSY {\
+ if (ObjectsBusy()) \
+ break; \
+}
+
diff --git a/private/oleutest/ole1/clidemo/clidemo.ico b/private/oleutest/ole1/clidemo/clidemo.ico
new file mode 100644
index 000000000..114e1c58c
--- /dev/null
+++ b/private/oleutest/ole1/clidemo/clidemo.ico
Binary files differ
diff --git a/private/oleutest/ole1/clidemo/clidemo.rc b/private/oleutest/ole1/clidemo/clidemo.rc
new file mode 100644
index 000000000..88aa4b04a
--- /dev/null
+++ b/private/oleutest/ole1/clidemo/clidemo.rc
@@ -0,0 +1,231 @@
+/*
+ * clidemo.rc - OLE Client Demonstration application resource file
+ *
+ * Created by Microsoft Corporation.
+ * (c) Copyright Microsoft Corp. 1990 - 1992 All Rights Reserved
+ */
+
+#include <windows.h>
+#include "demorc.h"
+#include "clidemo.rcv"
+
+ID_APPLICATION ICON CLIDEMO.ICO
+
+ID_APPLICATION MENU
+BEGIN
+ POPUP "&File"
+ BEGIN
+ MENUITEM "&New", IDM_NEW
+ MENUITEM "&Open...", IDM_OPEN
+ MENUITEM "&Save", IDM_SAVE
+ MENUITEM "Save &As...", IDM_SAVEAS
+ MENUITEM SEPARATOR
+
+ MENUITEM "E&xit", IDM_EXIT
+ MENUITEM "A&bout...", IDM_ABOUT
+ END
+
+ POPUP "&Edit"
+ BEGIN
+ MENUITEM "Cu&t\tShift+Del", IDM_CUT
+ MENUITEM "&Copy\tCtrl+Ins", IDM_COPY
+ MENUITEM "&Paste\tShift+Ins", IDM_PASTE
+ MENUITEM "Paste &Link", IDM_PASTELINK
+ MENUITEM SEPARATOR
+ MENUITEM "Clea&r\tDel", IDM_CLEAR
+ MENUITEM "Clear &All", IDM_CLEARALL
+ MENUITEM SEPARATOR
+ MENUITEM "Lin&ks...", IDM_LINKS
+ MENUITEM "&Objects", IDM_VERBMIN
+ END
+
+ POPUP "&Insert"
+ BEGIN
+ MENUITEM "&Object...", IDM_INSERT
+ MENUITEM "&Template...", IDM_INSERTFILE
+ END
+END
+
+ID_APPLICATION ACCELERATORS
+BEGIN
+ VK_DELETE, IDM_CLEAR, VIRTKEY
+ VK_DELETE, IDM_CUT, VIRTKEY, SHIFT
+ VK_INSERT, IDM_COPY, VIRTKEY, CONTROL
+ VK_INSERT, IDM_PASTE, VIRTKEY, SHIFT
+END
+
+/*
+ * Dialog for Link Properties...
+ */
+
+DTPROP DIALOG 45, 38, 292, 103
+STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "Links"
+BEGIN
+ LISTBOX IDD_LINKNAME, 2, 14, 240, 43, LBS_EXTENDEDSEL |
+ LBS_MULTIPLESEL | WS_VSCROLL
+ LTEXT "Update:", -1, 3, 58, 44, 8
+ RADIOBUTTON "&Automatic", IDD_AUTO, 31, 56, 46, 12, WS_TABSTOP
+ RADIOBUTTON "&Manual", IDD_MANUAL, 78, 56, 42, 12, WS_TABSTOP
+ PUSHBUTTON "&Update Now", IDD_UPDATE, 40, 75, 48, 14
+ PUSHBUTTON "&Cancel Link", IDD_FREEZE, 98, 75, 45, 14
+ PUSHBUTTON "C&hange Link...", IDD_CHANGE, 153, 75, 52, 14
+ PUSHBUTTON "OK", IDOK, 254, 12, 32, 14
+ DEFPUSHBUTTON "Cancel", IDCANCEL, 254, 30, 32, 14
+ LTEXT "&Links:", 5, 2, 4, 27, 8
+END
+
+INVALIDLINK DIALOG 9, 25, 155, 55
+STYLE MB_ICONEXCLAMATION | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "CliDemo"
+BEGIN
+ LTEXT "Some linked files were unavailable", -1, 30, 5, 140, 8, NOT WS_GROUP
+ LTEXT "and could not be updated.", -1, 30, 14, 112, 8, NOT WS_GROUP
+ PUSHBUTTON "OK", IDOK, 30, 33, 36, 14
+ PUSHBUTTON "&Links...", IDD_CHANGE, 85, 33, 40, 14
+ CONTROL 32515, -1, "static", SS_ICON | WS_CHILD, 7, 7, 18, 26
+END
+
+DTCREATE DIALOG 50, 26, 183, 62
+STYLE DS_MODALFRAME| WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "Insert New Object"
+BEGIN
+ LTEXT "Object Type:", -1, 7, 5, 123, 8, NOT WS_GROUP
+ LISTBOX IDD_LISTBOX, 5, 15, 125, 41, LBS_SORT | WS_TABSTOP | WS_VSCROLL
+ PUSHBUTTON "OK", IDOK, 140, 8, 35, 14, WS_TABSTOP
+ PUSHBUTTON "Cancel", IDCANCEL, 140, 25, 35, 14, WS_TABSTOP
+END
+
+
+STRINGTABLE LOADONCALL {
+ IDS_APPNAME, "CliDemo"
+ IDS_UNTITLED, "(Untitled)"
+ IDS_MAYBESAVE, "Save Changes to %s?"
+ IDS_OPENFILE, "File Open"
+ IDS_SAVEFILE, "File Save As"
+ IDS_INSERTFILE, "Insert Object from File"
+ IDS_FILTER, "OLE Object(s)"
+ IDS_EXTENSION, "OLE"
+ IDS_CHANGELINK, "Change Link"
+ IDS_ALLFILTER, "All Files (*.*)"
+ IDS_EMBEDDED, "Embedded %s"
+ IDS_UPDATELINKS, "This file contains links to other\ndocuments.\n\nUpdate links now?"
+ IDS_RENAME, "The selected links to %s have been \nupdated. %s contains additional links \nto %s\n\n Update additional links?"
+ IDS_INVALID_LINK, "Link is invalid!\n Modify Links?"
+ IDS_SAVE_CHANGES, "Save changes made to links?"
+ IDS_UPDATE_OBJ, "This object has been changed.\nUpdate %s before proceeding?"
+ IDS_RETRY_TEXT1, """%.20s"" is busy. You may 'Switch to'"
+ IDS_RETRY_TEXT2, """%.20s"" and correct the problem."
+
+ E_FAILED_TO_OPEN_FILE, "Failed to open file."
+ E_FAILED_TO_READ_FILE, "Failed to read file."
+ E_FAILED_TO_SAVE_FILE, "Failed to save file."
+ E_INVALID_FILENAME, "Invalid filename."
+ E_FAILED_TO_DELETE_OBJECT, "Failed to delete object."
+ E_FAILED_TO_RELEASE_OBJECT, "Failed to release object."
+ E_CLIPBOARD_CUT_FAILED, "Cut to clipboard failed."
+ E_CLIPBOARD_COPY_FAILED, "Copy to clipboard failed."
+ E_GET_FROM_CLIPBOARD_FAILED, "Failed to paste object from clipboard."
+ E_CREATE_FROM_TEMPLATE, "Failed to create object from file."
+ E_FAILED_TO_WRITE_OBJECT, "Failed to write object."
+ E_FAILED_TO_READ_OBJECT, "Failed to read object."
+ E_FAILED_TO_CREATE_CHILD_WINDOW,"Failed to create child window."
+ E_FAILED_TO_CREATE_OBJECT, "Failed to create new object."
+ E_OBJECT_BUSY, "Object is currently busy."
+ E_UNEXPECTED_RELEASE, "DDE conversation is invalid."
+ E_FAILED_TO_LAUNCH_SERVER, "Failed to launch server application."
+ E_FAILED_TO_UPDATE, "Failed to update object."
+ E_FAILED_TO_FREEZE, "Failed to freeze object."
+ E_FAILED_TO_UPDATE_LINK, "Failed to update link options."
+ E_SERVER_BUSY, "Unable to process command, server busy."
+ E_FAILED_TO_RECONNECT_OBJECT, "Failed to reconnect link to server."
+ E_FAILED_TO_CONNECT, "Failed to connect;\nLink may be broken."
+ E_FAILED_TO_ALLOC, "Memory Allocation Failed."
+ E_FAILED_TO_LOCK, "Fail to lock OLE data."
+ E_FAILED_TO_DO_VERB, "Could not Edit / Play object."
+
+ W_IMPROPER_LINK_OPTIONS, "Warning: Improper link options."
+ W_STATIC_OBJECT, "Warning: Static object"
+ W_FAILED_TO_CLONE_UNDO, "Warning: Couldn't clone object."
+ W_FAILED_TO_NOTIFY, "Warning: Failed to notify library."
+
+ SZAUTO, "Automatic"
+ SZMANUAL, "Manual"
+ SZFROZEN, "Canceled"
+
+ E_OLE_ERROR_MEMORY, "OLE - Could not alloc or lock memory"
+ E_OLE_ERROR_STREAM, "OLE - (OLESTREAM) stream error"
+ E_OLE_ERROR_STATIC, "OLE - Non static object expected"
+ E_OLE_ERROR_BLANK, "OLE - Critical data missing"
+ E_OLE_ERROR_DRAW, "OLE - Error while drawing"
+ E_OLE_ERROR_METAFILE, "OLE - Invalid metafile"
+ E_OLE_ERROR_ABORT, "OLE - Client chose to abort metafile drawing"
+ E_OLE_ERROR_CLIPBOARD, "OLE - Failed to get/set clipboard data"
+ E_OLE_ERROR_FORMAT, "OLE - Requested format is not available"
+ E_OLE_ERROR_OBJECT, "OLE - Not a valid object"
+ E_OLE_ERROR_OPTION, "OLE - Invalid option (link update / render)"
+ E_OLE_ERROR_PROTOCOL, "OLE - Invalid protocol"
+ E_OLE_ERROR_ADDRESS, "OLE - One of the pointers is invalid"
+ E_OLE_ERROR_NOT_EQUAL, "OLE - Objects are not equal"
+ E_OLE_ERROR_HANDLE, "OLE - Invalid handle encountered"
+ E_OLE_ERROR_GENERIC, "OLE - Some general error"
+ E_OLE_ERROR_CLASS, "OLE - Invalid class"
+ E_OLE_ERROR_SYNTAX, "OLE - Command syntax is invalid"
+ E_OLE_ERROR_DATATYPE, "OLE - Data format is not supported"
+ E_OLE_ERROR_PALETTE, "OLE - Invalid color palette"
+ E_OLE_ERROR_NOT_LINK, "OLE - Not a linked object"
+ E_OLE_ERROR_NOT_EMPTY, "OLE - Client doc contains objects"
+ E_OLE_ERROR_SIZE, "OLE - Incorrect buffer size passed to E_OLE api"
+ E_OLE_ERROR_DRIVE, "OLE - Drive letter in doc name is invalid"
+ E_OLE_ERROR_NETWORK, "OLE - Failed to establish connection to network"
+ E_OLE_ERROR_NAME, "OLE - Invalid name (doc name, object name)"
+ E_OLE_ERROR_TEMPLATE, "OLE - Server failed to load template"
+ E_OLE_ERROR_NEW, "OLE - Server failed to create new doc"
+ E_OLE_ERROR_EDIT, "OLE - Server failed to edit object"
+ E_OLE_ERROR_OPEN, "OLE - Server failed to open document"
+ E_OLE_ERROR_NOT_OPEN, "OLE - Object is not open for editing"
+ E_OLE_ERROR_LAUNCH, "OLE - Failed to launch server"
+ E_OLE_ERROR_COMM, "OLE - Failed to communicate with server"
+ E_OLE_ERROR_TERMINATE, "OLE - Error in termination"
+ E_OLE_ERROR_COMMAND, "OLE - Error in execute"
+ E_OLE_ERROR_SHOW, "OLE - Error in show"
+ E_OLE_ERROR_DOVERB, "OLE - Error in doing verb"
+ E_OLE_ERROR_ADVISE_NATIVE, "OLE - Item could be missing"
+ E_OLE_ERROR_ADVISE_PICT, "OLE - Server can't recognize item format"
+ E_OLE_ERROR_ADVISE_RENAME, "OLE - Server doesn't support rename"
+ E_OLE_ERROR_POKE_NATIVE, "OLE - Failure of poking native data to server"
+ E_OLE_ERROR_REQUEST_NATIVE, "OLE - Server failed to render native data"
+ E_OLE_ERROR_REQUEST_PICT, "OLE - Server failed to render presentation data"
+ E_OLE_ERROR_SERVER_BLOCKED, "OLE - Server is blocked"
+ E_OLE_ERROR_REGISTRATION, "OLE - Server is not registered"
+ E_OLE_ERROR_ALREADY_REGISTERED, "OLE - Trying to register same doc multiple times"
+ E_OLE_ERROR_TASK, "OLE - Server or client task is invalid"
+ E_OLE_ERROR_OUTOFDATE, "OLE - Object is out of date"
+ E_OLE_ERROR_CANT_UPDATE_CLIENT, "OLE - embed doc's client doesn't accept"
+ E_OLE_ERROR_UPDATE, "OLE - error while trying to update object"
+
+}
+
+AboutBox DIALOG LOADONCALL MOVEABLE DISCARDABLE 22, 17, 160, 75
+CAPTION "About Clidemo1"
+STYLE DS_MODALFRAME | WS_CAPTION | WS_SYSMENU
+BEGIN
+ CTEXT "Microsoft Windows" -1, 0, 5, 160, 8
+ CTEXT "OLE 1.0 Client Test Application" -1, 0, 14, 160, 8
+ CTEXT "Version 1.00" -1, 0, 23, 160, 8
+ CTEXT "(c) Copyright Microsoft Corp. 1990 - 1992" -1, 0, 39, 160, 8
+ DEFPUSHBUTTON "OK" IDOK, 61, 59, 32, 14, WS_GROUP
+END
+
+RetryBox DIALOG 26, 26, 220, 78
+CAPTION "CLIDEMO"
+FONT 8, "Helv"
+STYLE WS_SYSMENU | WS_CAPTION | WS_VISIBLE | DS_MODALFRAME | WS_POPUP
+BEGIN
+ PUSHBUTTON "&Switch To...", IDD_SWITCH, 35, 55, 50, 14
+ DEFPUSHBUTTON "&Cancel", IDCANCEL, 120, 55, 50, 14
+ LTEXT "This action cannot be completed because", -1, 35, 9, 160, 8
+ LTEXT "", IDD_RETRY_TEXT1, 35, 18, 180, 8
+ LTEXT "", IDD_RETRY_TEXT2, 35, 27, 180, 8
+ CONTROL 32515, -1, "static", SS_ICON | WS_CHILD, 7, 15, 18, 26
+END
diff --git a/private/oleutest/ole1/clidemo/clidemo.rcv b/private/oleutest/ole1/clidemo/clidemo.rcv
new file mode 100644
index 000000000..5dbf54f35
--- /dev/null
+++ b/private/oleutest/ole1/clidemo/clidemo.rcv
@@ -0,0 +1,33 @@
+#include "cliver.h"
+
+
+VS_VERSION_INFO VERSIONINFO
+FILEVERSION CLIVER_FILEVERSION
+PRODUCTVERSION CLIVER_PRODUCTVERSION
+FILEFLAGSMASK 0x0000003FL
+FILEFLAGS CLIVER_FILEFLAGS
+FILEOS CLIVER_FILEOS
+FILETYPE VFT_APP
+FILESUBTYPE VFT2_UNKNOWN
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904E4"
+ BEGIN
+ VALUE "CompanyName", "Microsoft Corporation\0"
+ VALUE "FileDescription", "Object Linking and Embedding Client Demo Application\0"
+ VALUE "FileVersion", "1.00.000\0"
+ VALUE "InternalName", "CliDemo\0"
+ VALUE "LegalCopyright", "Copyright \251 Microsoft Corp. 1991-1992\0"
+ VALUE "ProductName", "Microsoft Object Linking and Embedding Demo Client for Windows"
+ VALUE "ProductVersion", "1.01.000\0"
+ END
+ END
+
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x0409, 1252
+ END
+
+END
+
diff --git a/private/oleutest/ole1/clidemo/cliver.h b/private/oleutest/ole1/clidemo/cliver.h
new file mode 100644
index 000000000..97238b195
--- /dev/null
+++ b/private/oleutest/ole1/clidemo/cliver.h
@@ -0,0 +1,9 @@
+#define CLIVER_DEBUG 0
+#define CLIVER_PRERELEASE 1
+
+#define CLIVER_FILEFLAGS (CLIVER_PRERELEASE|CLIVER_DEBUG)
+
+#define CLIVER_FILEOS VOS_DOS_WINDOWS16
+#define CLIVER_FILEVERSION 1,01
+#define CLIVER_PRODUCTVERSION 1,01,0,00
+
diff --git a/private/oleutest/ole1/clidemo/daytona/makefile b/private/oleutest/ole1/clidemo/daytona/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/oleutest/ole1/clidemo/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/ole1/clidemo/daytona/sources b/private/oleutest/ole1/clidemo/daytona/sources
new file mode 100644
index 000000000..568bae5a3
--- /dev/null
+++ b/private/oleutest/ole1/clidemo/daytona/sources
@@ -0,0 +1,26 @@
+TARGETNAME=clidemo1
+TARGETPATH=obj
+TARGETTYPE=PROGRAM
+TARGETLIBS=
+
+INCLUDES= .
+C_DEFINES = -DWIN32 -DSTRICT
+NTDEBUG=
+
+SOURCES=..\clidemo.c \
+ ..\object.c \
+ ..\utility.c \
+ ..\dialog.c \
+ ..\register.c \
+ ..\stream.c \
+ ..\clidemo.rc
+
+UMTYPE=windows
+UMENTRY=winmain
+UMLIBS= \
+ $(BASEDIR)\public\sdk\lib\*\advapi32.lib \
+ $(BASEDIR)\public\sdk\lib\*\shell32.lib \
+ $(BASEDIR)\public\sdk\lib\*\comdlg32.lib \
+ $(BASEDIR)\public\sdk\lib\*\olecli32.lib \
+ obj\*\clidemo.res
+
diff --git a/private/oleutest/ole1/clidemo/demorc.h b/private/oleutest/ole1/clidemo/demorc.h
new file mode 100644
index 000000000..e87a5b345
--- /dev/null
+++ b/private/oleutest/ole1/clidemo/demorc.h
@@ -0,0 +1,180 @@
+/*
+ * demorc.h - Header file for OLE demo's resource file.
+ *
+ * Created by Microsoft Corporation.
+ * (c) Copyright Microsoft Corp. 1990 - 1992 All Rights Reserved
+ */
+
+/* Application resource ID */
+
+#define ID_APPLICATION 1
+
+#define POS_FILEMENU 0
+/* File menu */
+#define IDM_NEW 0x100
+#define IDM_OPEN 0x101
+#define IDM_SAVE 0x102
+#define IDM_SAVEAS 0x103
+#define IDM_EXIT 0x104
+#define IDM_ABOUT 0x105
+
+#define POS_EDITMENU 1
+/* Edit menu */
+#define IDM_CUT 0x200
+#define IDM_COPY 0x201
+#define IDM_PASTE 0x202
+#define IDM_PASTELINK 0x203
+#define IDM_CLEAR 0x204
+#define IDM_CLEARALL 0x205
+#define IDM_LINKS 0x206
+
+/* Object popup menu */
+#define POS_OBJECT 9 // position of Object item in Edit menu
+#define IDM_OBJECT 0x210
+#define IDM_VERBMIN 0x211
+#define IDM_VERBMAX 0x220 // Put this up to 220 (15 verbs) !!!
+#define CVERBSMAX (IDM_VERBMAX - IDM_VERBMIN + 1)
+
+#define POS_OBJECTMENU 2
+#define IDM_INSERT 0x300
+#define IDM_INSERTFILE 0x301
+
+#define IDM_UNDO 0x400 /* Only used internally */
+#define IDM_LOAD 0x401
+#define IDM_UPDATE 0x402
+
+
+/* Dialog box ids */
+#define DTPROP 1
+#define DTINVALIDLINK 2
+#define DTCREATE 3
+
+#define IDD_LINKNAME 0x200
+#define IDD_AUTO 0x201 // Auto update
+#define IDD_MANUAL 0x202 // Manual update
+#define IDD_EDIT 0x203 // Edit Object button
+#define IDD_FREEZE 0x204 // Cancel Link button
+#define IDD_UPDATE 0x205 // Update Now Button
+#define IDD_CHANGE 0x206 // Change Links Button
+#define IDD_LINKDONE 0x207 // ???
+#define IDD_PLAY 0x208 // Activate Button
+#define IDD_LISTBOX 0x209 // List of Links List Box
+#define IDD_DESTROY 0x20A
+
+#define IDD_YES 0x210
+#define IDD_NO 0x211
+#define IDD_RETRY 0x212
+#define IDD_SWITCH 0x213
+#define IDD_RETRY_TEXT1 0x214
+#define IDD_RETRY_TEXT2 0x215
+
+/* String table constants */
+#define CBMESSAGEMAX 80
+#define IDS_APPNAME 0x100
+#define IDS_UNTITLED 0x101
+#define IDS_MAYBESAVE 0x102
+#define IDS_OPENFILE 0x103
+#define IDS_SAVEFILE 0x104
+#define IDS_INSERTFILE 0x105
+#define IDS_FILTER 0x106
+#define IDS_EXTENSION 0x107
+#define IDS_CHANGELINK 0x108
+#define IDS_ALLFILTER 0x109
+#define IDS_EMBEDDED 0x10a
+#define IDS_UPDATELINKS 0x10b
+#define IDS_RENAME 0x10c
+#define IDS_INVALID_LINK 0x10d
+#define IDS_SAVE_CHANGES 0x10e
+#define IDS_UPDATE_OBJ 0x110
+#define IDS_RETRY_TEXT1 0x111
+#define IDS_RETRY_TEXT2 0x112
+
+/* Error messages */
+#define E_FAILED_TO_OPEN_FILE 0x200
+#define E_FAILED_TO_READ_FILE 0x201
+#define E_FAILED_TO_SAVE_FILE 0x202
+#define E_INVALID_FILENAME 0x203
+#define E_CREATE_FROM_TEMPLATE 0x204
+#define E_FAILED_TO_WRITE_OBJECT 0x205
+#define E_FAILED_TO_READ_OBJECT 0x206
+#define E_FAILED_TO_DELETE_OBJECT 0x207
+#define E_CLIPBOARD_CUT_FAILED 0x208
+#define E_CLIPBOARD_COPY_FAILED 0x209
+#define E_GET_FROM_CLIPBOARD_FAILED 0x20a
+#define E_FAILED_TO_CREATE_CHILD_WINDOW 0x20b
+#define E_FAILED_TO_CREATE_OBJECT 0x20c
+#define E_OBJECT_BUSY 0x20d
+#define E_UNEXPECTED_RELEASE 0x20e
+#define E_FAILED_TO_LAUNCH_SERVER 0x20f
+#define E_FAILED_TO_UPDATE 0x210
+#define E_FAILED_TO_FREEZE 0x211
+#define E_FAILED_TO_UPDATE_LINK 0x212
+#define E_SERVER_BUSY 0x213
+#define E_FAILED_TO_RECONNECT_OBJECT 0x214
+#define E_FAILED_TO_CONNECT 0x215
+#define E_FAILED_TO_RELEASE_OBJECT 0x216
+#define E_FAILED_TO_ALLOC 0x217
+#define E_FAILED_TO_LOCK 0x218
+#define E_FAILED_TO_DO_VERB 0x219
+
+#define W_IMPROPER_LINK_OPTIONS 0x300
+#define W_STATIC_OBJECT 0x301
+#define W_FAILED_TO_CLONE_UNDO 0x302
+#define W_FAILED_TO_NOTIFY 0x303
+
+#define SZAUTO 0x400
+#define SZMANUAL 0x401
+#define SZFROZEN 0x402
+
+#define E_OLE_ERROR_PROTECT_ONLY 3
+#define E_OLE_ERROR_MEMORY 4
+#define E_OLE_ERROR_STREAM 5
+#define E_OLE_ERROR_STATIC 6
+#define E_OLE_ERROR_BLANK 7
+#define E_OLE_ERROR_DRAW 8
+#define E_OLE_ERROR_METAFILE 9
+#define E_OLE_ERROR_ABORT 10
+#define E_OLE_ERROR_CLIPBOARD 11
+#define E_OLE_ERROR_FORMAT 12
+#define E_OLE_ERROR_OBJECT 13
+#define E_OLE_ERROR_OPTION 14
+#define E_OLE_ERROR_PROTOCOL 15
+#define E_OLE_ERROR_ADDRESS 16
+#define E_OLE_ERROR_NOT_EQUAL 17
+#define E_OLE_ERROR_HANDLE 18
+#define E_OLE_ERROR_GENERIC 19
+#define E_OLE_ERROR_CLASS 20
+#define E_OLE_ERROR_SYNTAX 21
+#define E_OLE_ERROR_DATATYPE 22
+#define E_OLE_ERROR_PALETTE 23
+#define E_OLE_ERROR_NOT_LINK 24
+#define E_OLE_ERROR_NOT_EMPTY 25
+#define E_OLE_ERROR_SIZE 26
+#define E_OLE_ERROR_DRIVE 27
+#define E_OLE_ERROR_NETWORK 28
+#define E_OLE_ERROR_NAME 29
+#define E_OLE_ERROR_TEMPLATE 30
+#define E_OLE_ERROR_NEW 31
+#define E_OLE_ERROR_EDIT 32
+#define E_OLE_ERROR_OPEN 33
+#define E_OLE_ERROR_NOT_OPEN 34
+#define E_OLE_ERROR_LAUNCH 35
+#define E_OLE_ERROR_COMM 36
+#define E_OLE_ERROR_TERMINATE 37
+#define E_OLE_ERROR_COMMAND 38
+#define E_OLE_ERROR_SHOW 39
+#define E_OLE_ERROR_DOVERB 40
+#define E_OLE_ERROR_ADVISE_NATIVE 41
+#define E_OLE_ERROR_ADVISE_PICT 42
+#define E_OLE_ERROR_ADVISE_RENAME 43
+#define E_OLE_ERROR_POKE_NATIVE 44
+#define E_OLE_ERROR_REQUEST_NATIVE 45
+#define E_OLE_ERROR_REQUEST_PICT 46
+#define E_OLE_ERROR_SERVER_BLOCKED 47
+#define E_OLE_ERROR_REGISTRATION 48
+#define E_OLE_ERROR_ALREADY_REGISTERED 49
+#define E_OLE_ERROR_TASK 50
+#define E_OLE_ERROR_OUTOFDATE 51
+#define E_OLE_ERROR_CANT_UPDATE_CLIENT 52
+#define E_OLE_ERROR_UPDATE 53
+
diff --git a/private/oleutest/ole1/clidemo/dialog.c b/private/oleutest/ole1/clidemo/dialog.c
new file mode 100644
index 000000000..1e5eb6cc0
--- /dev/null
+++ b/private/oleutest/ole1/clidemo/dialog.c
@@ -0,0 +1,1150 @@
+/*
+ * dialog.c - Handles the Windows 3.1 common dialogs.
+ *
+ * Created by Microsoft Corporation.
+ * (c) Copyright Microsoft Corp. 1990 - 1992 All Rights Reserved
+ */
+
+//*** INCLUDES ****
+
+#include <windows.h> //* WINDOWS
+#include <ole.h> //* OLE
+
+#include "global.h" //* global
+#include "demorc.h" //* String table constants
+#include "register.h" //* Class registration library
+#include "utility.h"
+#include "dialog.h"
+#include "object.h"
+
+//*** GLOBALS ***
+ //* strings used with commdlg
+CHAR szDefExtension[CBMESSAGEMAX];
+CHAR szFilterSpec[CBFILTERMAX];
+CHAR szInsertFilter[CBFILTERMAX];
+CHAR szLastDir[CBPATHMAX];
+OPENFILENAME OFN;
+HWND hwndProp = NULL;
+HWND hRetry;
+
+/***************************************************************************
+ * OfnInit()
+ * Initializes the standard file dialog OFN structure.
+ **************************************************************************/
+
+VOID FAR OfnInit( //* ENTRY:
+ HANDLE hInst //* instance handle
+){ //* LOCAL:
+ LPSTR lpstr; //* string pointer
+
+ LoadString(hInst, IDS_FILTER, szFilterSpec, CBMESSAGEMAX);
+ LoadString(hInst, IDS_EXTENSION, szDefExtension, CBMESSAGEMAX);
+
+ OFN.lStructSize = sizeof(OPENFILENAME);
+ OFN.hInstance = hInst;
+ OFN.nMaxCustFilter = CBFILTERMAX;
+ OFN.nMaxFile = CBPATHMAX;
+ OFN.lCustData = 0;
+ OFN.lpfnHook = NULL;
+ OFN.lpTemplateName = NULL;
+ OFN.lpstrFileTitle = NULL;
+ //* Construct the filter string
+ //* for the Open and Save dialogs
+ lpstr = (LPSTR)szFilterSpec;
+ lstrcat(lpstr, " (*.");
+ lstrcat(lpstr, szDefExtension);
+ lstrcat(lpstr, ")");
+ lpstr += lstrlen(lpstr) + 1;
+
+ lstrcpy(lpstr, "*.");
+ lstrcat(lpstr, szDefExtension);
+ lpstr += lstrlen(lpstr) + 1;
+ *lpstr = 0;
+
+ RegMakeFilterSpec(NULL, NULL, (LPSTR)szInsertFilter);
+
+}
+
+/***************************************************************************
+ * OfnGetName()
+ *
+ * Calls the standard file dialogs to get a file name
+ **************************************************************************/
+
+BOOL FAR OfnGetName( //* ENTRY:
+ HWND hwnd, //* parent window handle
+ LPSTR szFileName, //* File name
+ WORD msg //* operation
+){ //* LOCAL:
+ BOOL frc; //* return flag
+ CHAR szCaption[CBMESSAGEMAX];//* dialog caption
+
+ OFN.hwndOwner = hwnd; //* window
+ OFN.nFilterIndex = 1;
+ OFN.lpstrInitialDir = (LPSTR)szLastDir;
+ OFN.Flags = OFN_HIDEREADONLY;
+
+ switch (msg) //* message
+ {
+ case IDM_OPEN: //* open file
+ Normalize(szFileName);
+ OFN.lpstrDefExt = (LPSTR)szDefExtension;
+ OFN.lpstrFile = (LPSTR)szFileName;
+ OFN.lpstrFilter = (LPSTR)szFilterSpec;
+ LoadString(hInst, IDS_OPENFILE, szCaption, CBMESSAGEMAX);
+ OFN.lpstrTitle = (LPSTR)szCaption;
+ OFN.Flags |= OFN_FILEMUSTEXIST;
+ return GetOpenFileName((LPOPENFILENAME)&OFN);
+ break;
+
+ case IDM_SAVEAS: //* save as file
+ Normalize(szFileName);
+ OFN.lpstrDefExt = (LPSTR)szDefExtension;
+ OFN.lpstrFile = (LPSTR)szFileName;
+ OFN.lpstrFilter = (LPSTR)szFilterSpec;
+ LoadString(hInst, IDS_SAVEFILE, szCaption, CBMESSAGEMAX);
+ OFN.lpstrTitle = (LPSTR)szCaption;
+ OFN.Flags |= OFN_PATHMUSTEXIST;
+ return GetSaveFileName((LPOPENFILENAME)&OFN);
+ break;
+
+ case IDM_INSERTFILE: //* insert file
+ OFN.lpstrDefExt = NULL;
+ OFN.lpstrFile = (LPSTR)szFileName;
+ OFN.lpstrFilter = (LPSTR)szInsertFilter;
+ LoadString(hInst, IDS_INSERTFILE, szCaption, CBMESSAGEMAX);
+ OFN.lpstrTitle = (LPSTR)szCaption;
+ OFN.Flags |= OFN_FILEMUSTEXIST;
+ frc = GetOpenFileName((LPOPENFILENAME)&OFN);
+ AddExtension(&OFN);
+ return frc;
+ break;
+
+ default: //* default
+ break;
+ }
+
+}
+
+/***************************************************************************
+ * OfnGetNewLinkName() - Sets up the "Change Link..." dialog box
+ *
+ * returns LPSTR - fully qualified filename
+ **************************************************************************/
+
+LPSTR FAR OfnGetNewLinkName( //* ENTRY:
+ HWND hwnd, //* calling window or dialog
+ LPSTR lpstrData //* link data
+){ //* LOCAL:
+ LPSTR lpReturn = NULL; //* return string
+ LPSTR lpstrFile = NULL; //* non-qualified file name
+ LPSTR lpstrPath = NULL; //* pathname
+ LPSTR lpstrTemp = NULL; //* work string
+ CHAR szDocFile[CBPATHMAX];//* document name
+ CHAR szDocPath[CBPATHMAX];//* document path name
+ CHAR szServerFilter[CBPATHMAX];
+ CHAR szCaption[CBMESSAGEMAX];
+
+ //* Figure out the link's path
+ //* name and file name
+ lpstrTemp = lpstrData;
+ while (*lpstrTemp++);
+ lpstrPath = lpstrFile = lpstrTemp;
+
+ while (*(lpstrTemp = AnsiNext(lpstrTemp)))
+ if (*lpstrTemp == '\\')
+ lpstrFile = lpstrTemp + 1;
+ //* Copy the document name
+ lstrcpy(szDocFile, lpstrFile);
+ *(lpstrFile - 1) = 0;
+ //* Copy the path name
+ lstrcpy(szDocPath, ((lpstrPath != lpstrFile) ? lpstrPath : ""));
+ if (lpstrPath != lpstrFile) //* Restore the backslash
+ *(lpstrFile - 1) = '\\';
+ while (*lpstrFile != '.' && *lpstrFile)//* Get the extension
+ lpstrFile++;
+ //* Make a filter that respects
+ //* the link's class name
+ OFN.hwndOwner = hwnd;
+ OFN.nFilterIndex = RegMakeFilterSpec(lpstrData, lpstrFile, szServerFilter);
+ OFN.lpstrDefExt = NULL;
+ OFN.lpstrFile = (LPSTR)szDocFile;
+ OFN.lpstrFilter = (LPSTR)szServerFilter;
+ OFN.lpstrInitialDir = (LPSTR)szDocPath;
+ LoadString(hInst, IDS_CHANGELINK, szCaption, CBMESSAGEMAX);
+ OFN.lpstrTitle = (LPSTR)szCaption;
+ OFN.lpstrCustomFilter = NULL;
+ OFN.Flags = OFN_HIDEREADONLY | OFN_FILEMUSTEXIST;
+
+ //* If we get a file... */
+ if (GetOpenFileName((LPOPENFILENAME)&OFN))
+ {
+ if (!(lpReturn = GlobalLock(GlobalAlloc(LHND, CBPATHMAX))))
+ goto Error;
+
+ AddExtension(&OFN);
+ lstrcpy(lpReturn, szDocFile);
+
+ OFN.lpstrInitialDir = (LPSTR)szLastDir;
+ }
+
+ return lpReturn; //* SUCCESS return
+
+Error: //* ERROR Tag
+
+ return NULL; //* ERROR return
+
+}
+
+/***************************************************************************
+ * Normalize()
+ * Removes the path specification from the file name.
+ *
+ * Note: It isn't possible to get "<drive>:<filename>" as input because
+ * the path received will always be fully qualified.
+ **************************************************************************/
+
+VOID Normalize( //* ENTRY:
+ LPSTR lpstrFile //* file name
+){ //* LOCAL:
+ LPSTR lpstrBackslash = NULL;//* back slash
+ LPSTR lpstrTemp = lpstrFile;//* file name
+
+ while (*lpstrTemp)
+ {
+ if (*lpstrTemp == '\\')
+ lpstrBackslash = lpstrTemp;
+
+ lpstrTemp = AnsiNext(lpstrTemp);
+ }
+ if (lpstrBackslash)
+ lstrcpy(lpstrFile, lpstrBackslash + 1);
+
+}
+
+/***************************************************************************
+ * AddExtension()
+ *
+ * Adds the extension corresponding to the filter dropdown.
+ **************************************************************************/
+
+VOID AddExtension( //* ENTRY:
+ LPOPENFILENAME lpOFN //* open file structure
+){
+
+ if (lpOFN->nFileExtension == (WORD)lstrlen(lpOFN->lpstrFile)
+ && lpOFN->nFilterIndex)
+ {
+ LPSTR lpstrFilter = (LPSTR)lpOFN->lpstrFilter;
+
+ while (*lpstrFilter && --lpOFN->nFilterIndex)
+ {
+ while (*lpstrFilter++) ;
+ while (*lpstrFilter++) ;
+ }
+ //* If we got to the filter,
+ if (*lpstrFilter) //* retrieve the extension
+ {
+ while (*lpstrFilter++) ;
+ lpstrFilter++;
+ //* Copy the extension
+ if (lpstrFilter[1] != '*')
+ lstrcat(lpOFN->lpstrFile, lpstrFilter);
+ }
+ }
+
+}
+/****************************************************************************
+ * fnInsertNew()
+ *
+ * Dialog procedure for the Insert New dialog.
+ *
+ * Returns int - TRUE if message processed, FALSE otherwise
+ ***************************************************************************/
+
+BOOL APIENTRY fnInsertNew( //* ENTRY:
+ HWND hDlg, //* standard dialog box paramters
+ UINT msg,
+ WPARAM wParam,
+ LPARAM lParam //* (LPSTR) class name
+){ //* LOCAL:
+ HWND hwndList; //* handle to listbox
+ static LPSTR lpClassName; //* classname for return value
+
+ hwndList = GetDlgItem(hDlg, IDD_LISTBOX);
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ if (!RegGetClassNames(hwndList))
+ EndDialog(hDlg, IDCANCEL);
+
+ lpClassName = (LPSTR)lParam;
+ SetFocus(hwndList);
+ SendMessage(hwndList, LB_SETCURSEL, 0, 0L);
+ return (FALSE);
+
+ case WM_COMMAND:
+ {
+ WORD wID = LOWORD(wParam);
+ WORD wCmd = HIWORD(wParam);
+
+ switch (wID)
+ {
+ case IDD_LISTBOX:
+ if (wCmd != LBN_DBLCLK)
+ break;
+
+ case IDOK:
+ if (!RegCopyClassName(hwndList, lpClassName))
+ wParam = IDCANCEL;
+
+ case IDCANCEL:
+ EndDialog(hDlg, wParam);
+ break;
+ }
+ break;
+ }
+ }
+ return FALSE;
+
+}
+
+/***************************************************************************
+ * LinkProperties();
+ *
+ * Manage the link properties dialog box.
+ **************************************************************************/
+
+VOID FAR LinkProperties()
+{ //* LOCAL
+
+ DialogBox (
+ hInst,
+ MAKEINTRESOURCE(DTPROP),
+ hwndFrame,
+ (DLGPROC)fnProperties
+ );
+
+}
+
+/***************************************************************************
+ * fnProperties()
+ *
+ * Dialog procedure for link properties. The Links dialog allows the user to
+ * change the link options, edit/play the object, cancel the link as
+ * well change links.
+ *
+ * returns BOOL - TRUE if processed, FALSE otherwise
+ **************************************************************************/
+
+BOOL APIENTRY fnProperties( //* ENTRY:
+ HWND hDlg, //* standard dialog box parameters
+ UINT msg,
+ WPARAM wParam,
+ LPARAM lParam //* (HWND) child window with focus
+){ //* LOCAL:
+ static APPITEMPTR *pLinks; //* pointer to links (associated windows)
+ static INT nLinks; //* number of links
+ static HWND hwndList; //* handle to listbox window
+ static BOOL fTry;
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ hwndProp = hDlg;
+ hwndList = GetDlgItem(hDlg, IDD_LINKNAME);
+ if (!(InitLinkDlg(hDlg, &nLinks, hwndList, &pLinks)))
+ EndDialog(hDlg, TRUE);
+ UpdateLinkButtons(hDlg,nLinks,hwndList,pLinks);
+ break;
+
+ case WM_COMMAND:
+ {
+ WORD wID = LOWORD(wParam);
+
+ switch (wID)
+ {
+ case IDD_CHANGE: //* change links
+ BLOCK_BUSY(fTry);
+ if (ChangeLinks(hDlg,nLinks,hwndList,pLinks))
+ DisplayUpdate(nLinks,hwndList,pLinks, FALSE);
+ return TRUE;
+
+ case IDD_FREEZE: //* cancel links
+ BLOCK_BUSY(fTry);
+ CancelLinks(hDlg,nLinks,hwndList,pLinks);
+ UpdateLinkButtons(hDlg,nLinks,hwndList,pLinks);
+ return TRUE;
+
+ case IDD_UPDATE: //* update links
+ BLOCK_BUSY(fTry);
+ DisplayUpdate(nLinks,hwndList,pLinks,TRUE);
+ UpdateLinkButtons(hDlg,nLinks,hwndList,pLinks);
+ return TRUE;
+
+ case IDD_AUTO:
+ case IDD_MANUAL: //* change link update options
+ BLOCK_BUSY(fTry);
+ if (!SendMessage(GetDlgItem(hDlg,wParam),BM_GETCHECK, 0, 0L))
+ {
+ CheckRadioButton(hDlg, IDD_AUTO ,IDD_MANUAL ,wParam);
+ ChangeUpdateOptions(hDlg,nLinks,hwndList,pLinks,
+ (wParam == IDD_AUTO ? oleupdate_always : oleupdate_oncall));
+ UpdateLinkButtons(hDlg,nLinks,hwndList,pLinks);
+ }
+ return TRUE;
+
+ case IDD_LINKNAME:
+ if (HIWORD(wParam) == LBN_SELCHANGE)
+ UpdateLinkButtons(hDlg,nLinks,hwndList,pLinks);
+ return TRUE;
+
+ case IDCANCEL:
+ BLOCK_BUSY(fTry);
+ UndoObjects();
+ END_PROP_DLG(hDlg,pLinks);
+ return TRUE;
+
+ case IDOK:
+ BLOCK_BUSY(fTry);
+ DelUndoObjects(FALSE);
+ END_PROP_DLG(hDlg,pLinks);
+ return TRUE;
+ }
+ }
+ }
+ return FALSE;
+}
+
+
+/****************************************************************************
+ * InitLinkDlg();
+ *
+ * Initialize the list box of links.
+ ***************************************************************************/
+
+static BOOL InitLinkDlg ( //* ENTRY:
+ HWND hDlg, //* dialog box handle
+ INT *nLinks, //* pointer to number of links
+ HWND hwndList, //* listbox handle
+ APPITEMPTR **pLinks //* list of window handles of links
+){ //* LOCAL
+ APPITEMPTR pItem; //* application item pointer
+ LPSTR lpstrData = NULL; //* pointer to link data
+ CHAR szFull[CBMESSAGEMAX * 4];//* list box entry string
+ CHAR pLinkData[OBJECT_LINK_MAX];//* holder of link data
+ BOOL fSelect = FALSE; //* item selected flag
+ HANDLE hWork; //* working memory handle
+ APPITEMPTR pTop; //* pointer to the top object
+
+ if (!(*pLinks = (APPITEMPTR *)LocalLock(LocalAlloc(LHND,sizeof(APPITEMPTR)*10))))
+ {
+ ErrorMessage(E_FAILED_TO_ALLOC);
+ return 0;
+ }
+ *nLinks = 0;
+ //* set tabs
+ SendMessage(hwndList,WM_SETREDRAW,FALSE,0L);
+ //* enumerate child windows
+ for (pTop = pItem = GetTopItem(); pItem; pItem = GetNextItem(pItem))
+ {
+ if (pItem->otObject == OT_LINK && pItem->fVisible)
+ {
+ *(*pLinks + *nLinks) = pItem;
+ if (!((*nLinks += 1)%10))
+ { //* add blocks of ten
+ hWork = LocalHandle((LPSTR)(*pLinks));
+ LocalUnlock(hWork);
+ if (!(hWork = LocalReAlloc(hWork,(*nLinks+10)*sizeof(APPITEMPTR),0)))
+ {
+ ErrorMessage(E_FAILED_TO_ALLOC);
+ return FALSE; //* ERROR return
+ }
+ *pLinks = (APPITEMPTR *)LocalLock(hWork);
+ }
+
+ if (pTop == pItem)
+ fSelect = TRUE;
+
+ if (!ObjGetData(pItem, pLinkData))
+ continue;
+ //* make listbox entry
+ MakeListBoxString(pLinkData, szFull, pItem->uoObject);
+ //* add listbox entry
+ SendMessage(hwndList, LB_ADDSTRING, 0, (LONG)(LPSTR)szFull);
+ }
+ }
+
+ if (fSelect)
+ SendMessage(hwndList, LB_SETSEL, 1, 0L);
+
+ SendMessage(hwndList,WM_SETREDRAW,TRUE,0L);
+ UpdateWindow(hwndList);
+
+ return TRUE; //* SUCCESS return
+
+}
+
+/****************************************************************************
+ * MakeListBoxString()
+ *
+ * build an listbox entry string
+ ***************************************************************************/
+
+static VOID MakeListBoxString( //* ENTRY:
+ LPSTR lpLinkData, //* pointer to link data
+ LPSTR lpBoxData, //* return string
+ OLEOPT_UPDATE oleopt_update //* OLE update option
+){ //* LOCAL:
+ CHAR szType[CBMESSAGEMAX];//* holds update option string
+ LPSTR lpTemp; //* working string pointer
+ INT i; //* index
+
+ //* get classname
+ RegGetClassId(lpBoxData, lpLinkData);
+ lstrcat(lpBoxData, " - "); //* ads tab
+
+ while (*lpLinkData++); //* skip to document name
+
+ lpTemp = lpLinkData;
+ while (*lpTemp) //* copy document name;
+ { //* strip drive an directory
+ if (*lpTemp == '\\' || *lpTemp == ':')
+ lpLinkData = lpTemp + 1;
+ lpTemp = AnsiNext(lpTemp);
+ }
+ lstrcat(lpBoxData, lpLinkData);
+ lstrcat(lpBoxData, " - ");
+
+ while (*lpLinkData++); //* copy item data
+ lstrcat(lpBoxData, lpLinkData);
+ lstrcat(lpBoxData, " - ");
+ //* add update option string
+ switch (oleopt_update)
+ {
+ case oleupdate_always: i = SZAUTO; break;
+ case oleupdate_oncall: i = SZMANUAL; break;
+ default: i = SZFROZEN;
+ }
+ LoadString(hInst, i, szType, CBMESSAGEMAX);
+ lstrcat(lpBoxData, szType);
+
+} //* SUCCESS return
+
+/***************************************************************************
+ * UpdateLinkButtons()
+ *
+ * Keep link buttons active as appropriate. This routine is called after
+ * a selection is made so the buttons reflect the selected items.
+ **************************************************************************/
+
+static VOID UpdateLinkButtons( //* ENTRY:
+ HWND hDlg, //* dialog box handle
+ INT nLinks, //* number of links
+ HWND hwndList, //* listbox handle
+ APPITEMPTR *pLinks //* pointer to link's window handles
+){ //* LOCAL:
+ ATOM aCurName=0; //* atom of current doc
+ BOOL fChangeLink = TRUE; //* enable/disable changelink button
+ INT iAuto,iManual,i; //* count of manual and auto links
+ APPITEMPTR pItem; //* application item pointer
+ INT iStatic;
+
+ iStatic = iAuto = iManual = 0;
+
+ for (i = 0; i < nLinks; i++) //* enum selected links
+ {
+ if (SendMessage(hwndList, LB_GETSEL, i, 0L))
+ {
+ pItem = *(pLinks+i);
+ if (pItem->otObject == OT_STATIC)
+ iStatic++;
+ else
+ {
+ switch(pItem->uoObject)
+ { //* count number of manual and
+ case oleupdate_always: //* automatic links selected
+ iAuto++;
+ break;
+ case oleupdate_oncall:
+ iManual++;
+ break;
+ }
+ //* check if all selected links are
+ if (!aCurName) //* linked to same file
+ aCurName = pItem->aLinkName;
+ else if (aCurName != pItem->aLinkName)
+ fChangeLink = FALSE;
+ }
+ }
+ }
+
+ if (!(iAuto || iManual || iStatic) //* if no links disable all buttons
+ || (!iAuto && !iManual && iStatic))
+ {
+ EnableWindow(GetDlgItem(hDlg, IDD_FREEZE), FALSE );
+ EnableWindow(GetDlgItem(hDlg, IDD_CHANGE), FALSE );
+ EnableWindow(GetDlgItem(hDlg, IDD_UPDATE), FALSE );
+ CheckDlgButton(hDlg, IDD_AUTO, FALSE);
+ EnableWindow(GetDlgItem(hDlg, IDD_AUTO),FALSE);
+ CheckDlgButton(hDlg, IDD_MANUAL, FALSE);
+ EnableWindow(GetDlgItem(hDlg, IDD_MANUAL),FALSE);
+ }
+ else
+ {
+ EnableWindow(GetDlgItem(hDlg, IDD_UPDATE), TRUE );
+ EnableWindow(GetDlgItem(hDlg, IDD_FREEZE), TRUE );
+
+ if (iAuto && iManual || !(iAuto || iManual))
+ { //* Set update buttons
+ CheckDlgButton(hDlg, IDD_AUTO, FALSE);
+ EnableWindow(GetDlgItem(hDlg, IDD_AUTO),FALSE);
+ CheckDlgButton(hDlg, IDD_MANUAL, FALSE);
+ EnableWindow(GetDlgItem(hDlg, IDD_MANUAL),FALSE);
+ }
+ else
+ {
+ EnableWindow(GetDlgItem(hDlg, IDD_MANUAL), TRUE);
+ EnableWindow(GetDlgItem(hDlg, IDD_AUTO), TRUE);
+ if (iAuto)
+ {
+ CheckDlgButton(hDlg, IDD_AUTO, TRUE);
+ CheckDlgButton(hDlg, IDD_MANUAL, FALSE);
+ }
+ else
+ {
+ CheckDlgButton(hDlg, IDD_AUTO, FALSE);
+ CheckDlgButton(hDlg, IDD_MANUAL, TRUE);
+ }
+ }
+ }
+
+ EnableWindow(GetDlgItem(hDlg, IDD_CHANGE),fChangeLink && aCurName);
+
+}
+
+/****************************************************************************
+ * ChangeLinks()
+ *
+ * This routine changes the linked data if the user chooses a new file to
+ * replace the old document data portion of the linked date. The routine
+ * does nothing if the user cancels.
+ *
+ * returns TRUE - if data changed FALSE if user cancel or err.
+ ***************************************************************************/
+
+static BOOL ChangeLinks( //* ENTRY:
+ HWND hDlg, //* dialog handle
+ INT nLinks, //* number of links in listbox
+ HWND hwndList, //* listbox
+ APPITEMPTR *pLinks //* list of application link handles
+){ //* LOCAL
+ INT i; //* general index
+ HANDLE hWork; //* work
+ APPITEMPTR pItem; //* application item
+ LPSTR lpNewDoc = NULL; //* new document
+ ATOM aOldDoc; //* atom of old doc. name
+ ATOM aCurDoc = 0; //* atom of change-to doc. name
+ BOOL fMessage = FALSE; //* error message flag
+ LPSTR lpLinkData; //* pointer to link data
+
+ lpLinkData = NULL;
+ //* This loop finds all selected links
+ for (i = 0; i < nLinks; i++) //* and updates them
+ {
+ if (SendMessage(hwndList, LB_GETSEL, i, 0L))
+ {
+ pItem = *(pLinks+i);
+ CHECK_IF_STATIC(pItem);
+
+ pItem->lpLinkData = lpLinkData;
+ if (!ObjGetData(pItem,NULL))
+ continue;
+
+ if (!lpNewDoc)
+ {
+ if (!(lpNewDoc = OfnGetNewLinkName(hDlg, pItem->lpLinkData)))
+ return FALSE; //* ERROR jump
+ aOldDoc = pItem->aLinkName;
+ aCurDoc = AddAtom(lpNewDoc);
+ SendMessage(hwndList,WM_SETREDRAW,FALSE,0L);
+ }
+
+ ObjSaveUndo(pItem);
+ ObjChangeLinkData(pItem,lpNewDoc);
+ pItem->aLinkName = aCurDoc;
+ lpLinkData = pItem->lpLinkData;
+
+ CHANGE_LISTBOX_STRING(hwndList, i, pItem, pItem->lpLinkData);
+
+ pItem->lpLinkData = NULL;
+ }
+ }
+
+ /*************************************************************************
+ * now deal with non-selected links and look for a match...
+ *************************************************************************/
+
+ //* this loop finds non-selected links
+ for (i = 0; i < nLinks; i++) //* and asks the user to update these?
+ {
+ if (!SendMessage(hwndList, LB_GETSEL, i, 0L))
+ {
+ pItem = *(pLinks+i);
+ if (pItem->otObject == OT_STATIC)
+ continue;
+
+ if (!ObjGetData(pItem,NULL))
+ continue;
+
+ if (pItem->aLinkName == aOldDoc)
+ {
+ if (!fMessage)
+ {
+ CHAR szMessage[2*CBMESSAGEMAX+3*CBPATHMAX];
+ CHAR szRename[2*CBMESSAGEMAX];
+ CHAR szOldDoc[CBMESSAGEMAX];
+ LPSTR pOldDoc;
+
+ GetAtomName(aOldDoc,szOldDoc,CBMESSAGEMAX);
+ pOldDoc =(LPSTR)UnqualifyPath(szOldDoc);
+ LoadString(hInst, IDS_RENAME, szRename, 2*CBMESSAGEMAX);
+ wsprintf(
+ szMessage,
+ szRename,
+ pOldDoc,
+ (LPSTR)UnqualifyPath(szFileName),
+ pOldDoc
+ );
+
+ if (MessageBox(hDlg, szMessage,
+ szAppName, MB_YESNO | MB_ICONEXCLAMATION) == IDNO)
+ break;
+ fMessage = TRUE;
+ }
+
+ ObjSaveUndo(pItem);
+ ObjChangeLinkData(pItem,lpNewDoc);
+ CHANGE_LISTBOX_STRING(hwndList, i, pItem, pItem->lpLinkData);
+
+ pItem->aLinkName = aCurDoc;
+ }
+ }
+ }
+
+ if(lpNewDoc)
+ {
+ hWork = GlobalHandle(lpNewDoc);
+ GlobalUnlock(hWork);
+ GlobalFree(hWork);
+ }
+
+#if 0
+// This is bogus -- this memory is owned by OLECLI32.DLL, not this app,
+// so it should not be freed here.
+ if (lpLinkData)
+ FreeLinkData(lpLinkData);
+#endif
+
+ SendMessage(hwndList,WM_SETREDRAW,TRUE,0L);
+ InvalidateRect(hwndList,NULL,TRUE);
+ UpdateWindow(hwndList);
+
+ WaitForAllObjects();
+
+ if (aCurDoc)
+ DeleteAtom(aCurDoc);
+
+ return(TRUE);
+}
+
+/****************************************************************************
+ * DisplayUpdate()
+ *
+ * Get the most up to date rendering information and show it.
+ ***************************************************************************/
+
+static VOID DisplayUpdate( //* ENTRY:
+ INT nLinks, //* number of links in listbox
+ HWND hwndList, //* listbox
+ APPITEMPTR *pLinks, //* list of application link handles
+ BOOL fSaveUndo //* save undo objects
+){ //* LOCAL:
+ INT i; //* index
+ APPITEMPTR pItem; //* temporary item pointer
+
+
+ for (i = 0; i < nLinks; i++)
+ if (SendMessage(hwndList, LB_GETSEL, i, 0L))
+ {
+ pItem = *(pLinks+i);
+ CHECK_IF_STATIC(pItem);
+ if (fSaveUndo)
+ ObjSaveUndo(pItem);
+ Error(OleUpdate(pItem->lpObject));
+ }
+
+ WaitForAllObjects();
+
+}
+
+/****************************************************************************
+ * UndoObjects()
+ *
+ * Bring objects back to their original state.
+ ***************************************************************************/
+
+static VOID UndoObjects()
+{
+ APPITEMPTR pItem; //* application item pointer
+ //* enum objects
+ for (pItem = GetTopItem(); pItem; pItem = GetNextItem(pItem))
+ if (pItem->lpObjectUndo)
+ ObjUndo(pItem);
+
+ WaitForAllObjects();
+
+}
+
+
+/****************************************************************************
+ * DelUndoObjects()
+ *
+ * remove all objects created for undo operation.
+ ***************************************************************************/
+
+static VOID DelUndoObjects( //* ENTRY:
+ BOOL fPrompt //* prompt user?
+){ //* LOCAL:
+ APPITEMPTR pItem; //* application item pointer
+ BOOL fPrompted = FALSE; //* prompted user?
+
+ for (pItem = GetTopItem(); pItem; pItem = GetNextItem(pItem))
+ {
+ if (pItem->lpObjectUndo)
+ {
+ if (fPrompt && !fPrompted) //* prompt user in activation case
+ {
+ CHAR szPrompt[CBMESSAGEMAX];
+
+ LoadString(hInst, IDS_SAVE_CHANGES, szPrompt, CBMESSAGEMAX);
+
+ if (MessageBox(hwndFrame, szPrompt,
+ szAppName, MB_YESNO | MB_ICONEXCLAMATION) == IDNO)
+ {
+ UndoObjects();
+ return; //* user canceled operation
+ }
+ fPrompted = TRUE;
+ }
+ ObjDelUndo(pItem); //* delete udo object
+ }
+ }
+
+ WaitForAllObjects();
+
+} //* SUCCESS return
+
+/****************************************************************************
+ * CancelLinks()
+ ***************************************************************************/
+
+static VOID CancelLinks( //* ENTRY:
+ HWND hDlg, //* calling dialog
+ INT nLinks, //* number of links in listbox
+ HWND hwndList, //* listbox
+ APPITEMPTR *pLinks //* list of application link handles
+){ //* LOCAL:
+ APPITEMPTR pItem; //* application item pointer
+ INT i; //* index
+ CHAR pLinkData[OBJECT_LINK_MAX];//* holder of link data
+
+ SendMessage(hwndList,WM_SETREDRAW,FALSE,0L);
+ for (i = 0; i < nLinks; i++)
+ if (SendMessage(hwndList, LB_GETSEL, i, 0L))
+ {
+ pItem = *(pLinks+i);
+ CHECK_IF_STATIC(pItem);
+ ObjGetData(pItem,pLinkData);
+ ObjSaveUndo(pItem);
+ ObjFreeze(pItem);
+
+ CHANGE_LISTBOX_STRING(hwndList, i, pItem, pLinkData);
+ }
+
+ SendMessage(hwndList,WM_SETREDRAW,TRUE,0L);
+ InvalidateRect(hwndList,NULL,TRUE);
+ UpdateWindow(hwndList);
+
+}
+
+
+/****************************************************************************
+ * ChangeUpdateOptions()
+ *
+ * Change the update options for all selected objects.
+ ***************************************************************************/
+
+static VOID ChangeUpdateOptions( //* ENTRY:
+ HWND hDlg, //* calling dialog
+ INT nLinks, //* number of links in listbox
+ HWND hwndList, //* listbox
+ APPITEMPTR *pLinks, //* list of application link handles
+ OLEOPT_UPDATE lUpdate //* update option
+){ //* LOCAL:
+ APPITEMPTR pItem; //* application item
+ INT i; //* index
+ CHAR pLinkData[OBJECT_LINK_MAX];
+
+ SendMessage(hwndList,WM_SETREDRAW,FALSE,0L);
+
+ for (i = 0; i < nLinks; i++) //* enum selected objects
+ {
+ if (SendMessage(hwndList, LB_GETSEL, i, 0L))
+ {
+ pItem = *(pLinks+i);
+ CHECK_IF_STATIC(pItem);
+ ObjGetData(pItem,pLinkData);
+ ObjSaveUndo(pItem);
+ if (Error(OleSetLinkUpdateOptions(pItem->lpObject,lUpdate)))
+ continue;
+ pItem->uoObject = lUpdate;
+
+ CHANGE_LISTBOX_STRING(hwndList, i, pItem, pLinkData);
+ }
+ }
+
+ SendMessage(hwndList,WM_SETREDRAW,TRUE,0L);
+ InvalidateRect(hwndList,NULL,TRUE);
+ UpdateWindow(hwndList);
+ WaitForAllObjects();
+
+}
+/****************************************************************************
+ * InvalidLink()
+ *
+ * Deal with letting the user know that the program has inadvertently come
+ * across an invalid link.
+ *
+ * Global fPropBoxActive - flag to determine whether or not the link dialog
+ * box is active. If it is not active we give the
+ * user an opportunity to enter the links property
+ * dialog directly from here.
+ ***************************************************************************/
+
+VOID FAR InvalidLink()
+{
+
+ if (!hwndProp)
+ DialogBox(hInst, "InvalidLink", hwndFrame, (DLGPROC)fnInvalidLink);
+ else
+ ErrorMessage(E_FAILED_TO_CONNECT);
+
+}
+
+/****************************************************************************
+ * fnABout()
+ *
+ * About box dialog box procedure.
+ ***************************************************************************/
+
+BOOL APIENTRY fnInvalidLink( //* ENTRY:
+ HWND hDlg, //* standard windows dialog box
+ UINT message,
+ WPARAM wParam,
+ LPARAM lParam
+){
+
+ switch (message)
+ {
+ case WM_INITDIALOG:
+ return (TRUE);
+
+ case WM_COMMAND:
+ if (LOWORD(wParam) == IDD_CHANGE)
+ LinkProperties();
+ EndDialog(hDlg, TRUE);
+ return (TRUE);
+ }
+ return (FALSE);
+
+}
+
+/****************************************************************************
+ * AboutBox()
+ *
+ * Show the About Box dialog.
+ ***************************************************************************/
+
+VOID FAR AboutBox()
+{
+
+ DialogBox(hInst, "AboutBox", hwndFrame, (DLGPROC)fnAbout);
+
+}
+
+/****************************************************************************
+ * fnABout()
+ *
+ * About box dialog box procedure.
+ ***************************************************************************/
+
+BOOL APIENTRY fnAbout( //* ENTRY:
+ HWND hDlg, //* standard windows dialog box
+ UINT message,
+ WPARAM wParam,
+ LPARAM lParam
+){
+
+ switch (message)
+ {
+ case WM_INITDIALOG:
+ return (TRUE);
+
+ case WM_COMMAND:
+ {
+ WORD wID = LOWORD(wParam);
+
+ if (wID == IDOK || wID == IDCANCEL)
+ {
+ EndDialog(hDlg, TRUE);
+ return (TRUE);
+ }
+ break;
+ }
+ }
+ return (FALSE);
+
+}
+
+
+
+/***************************************************************************
+ * RetryMessage()
+ *
+ * give the user the chance to abort when a server is in retry case.
+ *
+ * Returns BOOL - TRUE if user chooses to cancel
+ **************************************************************************/
+
+VOID FAR RetryMessage ( //* ENTRY:
+ APPITEMPTR paItem, //* application item pointer
+ LONG lParam
+){
+ RETRYPTR pRetry;
+ LONG objectType;
+ HANDLE hData;
+ static CHAR szServerName[KEYNAMESIZE];
+ HWND hwnd; //* window handle
+
+ if (IsWindow(hwndProp))
+ hwnd = hwndProp;
+ else if (IsWindow(hwndFrame))
+ hwnd = hwndFrame;
+ else
+ return; //* should not happen
+ //* get the busy servers name
+ lstrcpy(szServerName, "server application");
+
+ if (paItem)
+ {
+ if (!paItem->aServer)
+ {
+ OleQueryType(paItem->lpObject, &objectType );
+ if (OLE_OK == OleGetData(paItem->lpObject, (OLECLIPFORMAT) (objectType == OT_LINK ? vcfLink : vcfOwnerLink), &hData ))
+ {
+ RegGetClassId(szServerName, GlobalLock(hData));
+ paItem->aServer = AddAtom(szServerName);
+ GlobalUnlock( hData );
+ }
+ }
+ else
+ GetAtomName(paItem->aServer,szServerName,KEYNAMESIZE);
+
+ }
+
+ hData = LocalAlloc(LHND,sizeof(RETRYSTRUCT));
+ if(!(pRetry = (RETRYPTR)LocalLock(hData)))
+ return;
+
+ pRetry->lpserver = (LPSTR)szServerName;
+ pRetry->bCancel = (BOOL)(lParam & RD_CANCEL);
+ pRetry->paItem = paItem;
+
+ DialogBoxParam(hInst, "RetryBox", hwnd, (DLGPROC)fnRetry, (LONG)pRetry );
+
+ LocalUnlock(hData);
+ LocalFree(hData);
+
+ hRetry = NULL;
+
+}
+
+/****************************************************************************
+ * fnRetry()
+ *
+ * Retry message box nothing to tricky; however, when a server becomes
+ * unbusy a message is posted to automatically get rid of this dialog.
+ * I send a no.
+ ***************************************************************************/
+
+BOOL APIENTRY fnRetry( //* ENTRY
+ HWND hDlg, //* standard dialog entry
+ UINT message,
+ WPARAM wParam,
+ LPARAM lParam
+){
+ static RETRYPTR pRetry;
+
+ switch (message)
+ {
+ case WM_COMMAND:
+ {
+ WORD wID = LOWORD(wParam);
+
+ switch (wParam)
+ {
+ case IDD_SWITCH:
+ DefWindowProc( hDlg, WM_SYSCOMMAND, SC_TASKLIST, 0);
+ break;
+
+ case IDCANCEL:
+ if (pRetry->paItem)
+ pRetry->paItem->fRetry = FALSE;
+ EndDialog(hDlg, TRUE);
+ return TRUE;
+
+ default:
+ break;
+ }
+ break;
+ }
+
+ case WM_INITDIALOG:
+ {
+ CHAR szBuffer[CBMESSAGEMAX];
+ CHAR szText[2*CBMESSAGEMAX];
+
+ pRetry = (RETRYPTR)lParam;
+ hRetry = hDlg;
+
+ LoadString(hInst, IDS_RETRY_TEXT1, szBuffer, CBMESSAGEMAX);
+ wsprintf(szText, szBuffer, pRetry->lpserver);
+ SetWindowText (GetDlgItem(hDlg, IDD_RETRY_TEXT1), szText);
+
+ LoadString(hInst, IDS_RETRY_TEXT2, szBuffer, CBMESSAGEMAX);
+ wsprintf(szText, szBuffer, pRetry->lpserver);
+ SetWindowText (GetDlgItem(hDlg, IDD_RETRY_TEXT2), szText);
+
+ EnableWindow (GetDlgItem(hDlg, IDCANCEL), pRetry->bCancel);
+
+ return TRUE;
+ }
+
+ default:
+ break;
+ }
+
+ return FALSE;
+}
diff --git a/private/oleutest/ole1/clidemo/dialog.h b/private/oleutest/ole1/clidemo/dialog.h
new file mode 100644
index 000000000..9768fad1a
--- /dev/null
+++ b/private/oleutest/ole1/clidemo/dialog.h
@@ -0,0 +1,85 @@
+/*
+ * dialog.h
+ *
+ * Created by Microsoft Corporation.
+ * (c) Copyright Microsoft Corp. 1990 - 1992 All Rights Reserved
+ */
+
+//*** INCLUDES ***
+
+#include <commdlg.h>
+
+//*** PROTOTYPES ***
+
+//*** FAR
+BOOL FAR FullyQualify(LPSTR, LPSTR);
+BOOL FAR OfnGetName(HWND, LPSTR, WORD);
+LPSTR FAR OfnGetNewLinkName(HWND, LPSTR);
+VOID FAR OfnInit(HANDLE);
+BOOL APIENTRY fnInsertNew(HWND, UINT, WPARAM, LPARAM);
+BOOL APIENTRY fnProperties(HWND, UINT, WPARAM, LPARAM);
+VOID FAR LinkProperties(VOID);
+VOID FAR AboutBox(VOID);
+BOOL APIENTRY fnAbout( HWND, UINT, WPARAM, LPARAM);
+VOID FAR RetryMessage (APPITEMPTR,LONG);
+BOOL APIENTRY fnRetry(HWND, UINT, WPARAM, LPARAM);
+VOID FAR InvalidLink(VOID);
+BOOL APIENTRY fnInvalidLink(HWND, UINT, WPARAM, LPARAM);
+
+//*** Local
+static VOID AddExtension(LPOPENFILENAME);
+static VOID Normalize(LPSTR);
+static BOOL InitLinkDlg (HWND, INT *, HWND, APPITEMPTR **);
+static VOID UpdateLinkButtons(HWND, INT, HWND, APPITEMPTR *);
+static BOOL ChangeLinks(HWND, INT, HWND, APPITEMPTR *);
+static VOID CancelLinks(HWND, INT, HWND, APPITEMPTR *);
+static VOID DisplayUpdate(INT, HWND, APPITEMPTR *, BOOL);
+static VOID UndoObjects(VOID);
+static VOID DelUndoObjects(BOOL);
+static VOID ChangeUpdateOptions(HWND, INT, HWND, APPITEMPTR *, OLEOPT_UPDATE);
+static VOID MakeListBoxString(LPSTR, LPSTR, OLEOPT_UPDATE);
+
+//*** MACROS ***
+
+#define END_PROP_DLG(hDlg,pLinks) { \
+ HANDLE handle; \
+ handle = LocalHandle((LPSTR)pLinks); \
+ LocalUnlock(handle); \
+ LocalFree(handle); \
+ Hourglass(FALSE); \
+ hwndProp = (HWND)NULL; \
+ EndDialog(hDlg, TRUE); \
+}
+
+#define CHANGE_LISTBOX_STRING(hwnd,i,pItem,lpLinkData) {\
+ char pString[CBMESSAGEMAX*4];\
+ MakeListBoxString(lpLinkData,pString,pItem->uoObject);\
+ SendMessage(hwndList,LB_DELETESTRING, i , 0L);\
+ SendMessage(hwndList,LB_INSERTSTRING, i , (long)((LPSTR)pString));\
+ SendMessage(hwndList,LB_SETSEL, 1, (long)i);\
+}
+
+#define CHECK_IF_STATIC(pItem) {\
+ if (pItem->otObject == OT_STATIC)\
+ continue;\
+}
+
+#define BLOCK_BUSY(fTest) {\
+ if (fTest)\
+ {\
+ fTest = FALSE;\
+ return TRUE;\
+ }\
+ if (cOleWait)\
+ {\
+ fTest = TRUE;\
+ RetryMessage(NULL,RD_CANCEL);\
+ fTest = FALSE;\
+ return TRUE;\
+ }\
+}
+
+
+
+
+
diff --git a/private/oleutest/ole1/clidemo/dirs b/private/oleutest/ole1/clidemo/dirs
new file mode 100644
index 000000000..606df65eb
--- /dev/null
+++ b/private/oleutest/ole1/clidemo/dirs
@@ -0,0 +1,4 @@
+DIRS=
+OPTIONAL_DIRS= \
+ \
+ daytona
diff --git a/private/oleutest/ole1/clidemo/global.h b/private/oleutest/ole1/clidemo/global.h
new file mode 100644
index 000000000..f2cbabd8b
--- /dev/null
+++ b/private/oleutest/ole1/clidemo/global.h
@@ -0,0 +1,108 @@
+/*
+ * global.h
+ *
+ * Created by Microsoft Corporation.
+ * (c) Copyright Microsoft Corp. 1990 - 1992 All Rights Reserved
+ */
+
+//*** CONSTANTS ***
+
+#define PROTOCOL_STRLEN 15 //* protocol name string size
+#define CFILTERMAX 20 //* Max # filters
+ //* Max # chars/filter
+#define CBFILTERMAX (100 * CFILTERMAX)
+#define CBPATHMAX 250 //* max qualified file name
+#define CBOBJNAMEMAX 14 //* maximum length of object name
+#define CBVERBTEXTMAX 30 //* maximum length of verb text
+#define CBVERBNUMBMAX 8 //* maximum number of verbs
+#define OBJECT_LINK_MAX 256*3 //* maximum size of object link data
+#define CDIGITSMAX 5
+#define KEYNAMESIZE 300 //* Maximum registration key length
+#define RETRY 3
+ //* protocol name strings
+#define STDFILEEDITING ((LPSTR)"StdFileEditing")
+#define STATICP ((LPSTR)"Static")
+ //* object name prefixes
+#define OBJPREFIX ((LPSTR)"CliDemo #")
+#define OBJCLONE ((LPSTR)"CliDemo1#")
+#define OBJTEMP ((LPSTR)"CliDemo2#")
+
+#define DOC_CLEAN 0 //* Dirty() methods
+#define DOC_DIRTY 1
+#define DOC_UNDIRTY 2
+#define DOC_QUERY 3
+
+#define OLE_OBJ_RELEASE FALSE //* object deletion type
+#define OLE_OBJ_DELETE TRUE
+
+#define WM_ERROR WM_USER + 1 //* user defined messages
+#define WM_INIT WM_USER + 2
+#define WM_DELETE WM_USER + 3
+#define WM_RETRY WM_USER + 4
+#define WM_CHANGE WM_USER + 5
+
+#define RD_CANCEL 0x00000001
+#define RD_RETRY 0x00000002
+
+//*** TYPES ***
+
+typedef struct _APPSTREAM FAR *LPAPPSTREAM;
+
+typedef struct _APPSTREAM {
+ OLESTREAM olestream;
+ INT fh;
+} APPSTREAM;
+
+typedef struct _APPITEM *APPITEMPTR;
+
+typedef struct _APPITEM { //* Application item
+ OLECLIENT oleclient;
+ HWND hwnd;
+ LPOLEOBJECT lpObject; //* OLE object pointers
+ LPOLEOBJECT lpObjectUndo; //* undo object
+ LONG otObject; //* OLE object type
+ LONG otObjectUndo;
+ OLEOPT_UPDATE uoObject; //* OLE object update option
+ OLEOPT_UPDATE uoObjectUndo; //* link name atom
+ ATOM aLinkName; //* Save the link's document name
+ ATOM aLinkUndo; //* Save the link's document name
+ LPSTR lpLinkData; //* pointer to link data
+ BOOL fVisible; //* TRUE: item is to be displayed
+ BOOL fOpen; //* server open? --for undo objects
+ BOOL fRetry; //* retry flag for busy servers
+ BOOL fNew;
+ BOOL fServerChangedBounds;
+ RECT rect; //* bounding rectangle
+ LHCLIENTDOC lhcDoc; //* client document handle
+ ATOM aServer;
+} APPITEM;
+
+
+typedef struct _RETRY *RETRYPTR;
+
+typedef struct _RETRY { //* Application item
+ LPSTR lpserver;
+ BOOL bCancel;
+ APPITEMPTR paItem;
+} RETRYSTRUCT;
+
+//*** GLOBALS ***
+
+extern OLECLIPFORMAT vcfLink; //* ObjectLink clipboard format
+extern OLECLIPFORMAT vcfNative; //* Native clipboard format
+extern OLECLIPFORMAT vcfOwnerLink; //* OwnerLink clipboard format
+
+extern HANDLE hInst; //* instance handle
+extern HWND hwndFrame; //* main window handle
+extern HANDLE hAccTable; //* accelerator table
+extern HWND hwndProp; //* link properties dialog
+extern HWND hRetry; //* retry dialog box handle
+extern INT cOleWait; //* wait for asyncc commands
+extern INT iObjects; //* object count
+extern INT iObjectNumber; //* unique name id
+extern CHAR szItemClass[]; //* item class name
+extern CHAR szDefExtension[]; //* default file extension
+extern CHAR szAppName[]; //* application name
+extern BOOL fLoadFile; //* load file flag
+extern CHAR szFileName[]; //* open file name
+extern FARPROC lpfnTimerProc; //* pointer to timer callback function
diff --git a/private/oleutest/ole1/clidemo/object.c b/private/oleutest/ole1/clidemo/object.c
new file mode 100644
index 000000000..5e8bc8583
--- /dev/null
+++ b/private/oleutest/ole1/clidemo/object.c
@@ -0,0 +1,1177 @@
+/*
+ * object.c - OLE object support routines
+ *
+ * Created by Microsoft Corporation.
+ * (c) Copyright Microsoft Corp. 1990 - 1992 All Rights Reserved
+ */
+
+//*** INCLUDES ****
+
+#include <windows.h> //* WINDOWS
+#include <shellapi.h> //* SHELL
+#include <ole.h> //* OLE
+
+#include "global.h" //* global variables and structures
+#include "stream.h" //* application includes:
+#include "dialog.h"
+#include "object.h"
+#include "clidemo.h"
+#include "demorc.h"
+#include "utility.h"
+#include "register.h"
+
+#define HIMETRIC_PER_INCH 2540
+
+//*** VARIABLES ***
+
+//*** Globals
+INT cOleWait = 0;
+
+INT giXppli ;
+INT giYppli ;
+
+
+
+/***************************************************************************
+ * CallBack()
+ *
+ * This routine will be called whenever an object has been changed,
+ * saved, renamed, is being painted, or an asynchronous operation has
+ * completed. This routine is called by the OLE client DLL in the
+ * above situations. A pointer to this function is kept in the client
+ * vtbl. It is our obligation as a client application to insure that a
+ * pointer to this procedure is in the vtbl.
+ *
+ * IMMPORTANT: notice that we are posting messages here rather that doing
+ * the work right away. Well, this is done to avoid any possibility of
+ * getting into another dispatch message loop. A MessageBox woul do this!
+ *
+ * Returns int - see below
+ *
+ * The return value is generally ignored, except for these notifications:
+ * OLE_QUERY_PAINT and OLE_QUERY_RETRY. For these two notifications,
+ * returning TRUE means continue the current operation(eg painting or retry)
+ * Returning FALSE means stop the current operation. This is useful as an
+ * object which takes a long time to paint can be interrupted in order to
+ * perform other operations.
+ ***************************************************************************/
+
+INT APIENTRY CallBack( //* ENTRY:
+ LPOLECLIENT lpClient, //* client application pointer
+ OLE_NOTIFICATION flags, //* notification code being sent
+ LPOLEOBJECT lpObject //* OLE object pointer
+){ //* LOCAL:
+ APPITEMPTR pItem; //* application item pointer
+
+
+ pItem = (APPITEMPTR)lpClient;
+ switch (flags)
+ {
+ case OLE_CLOSED: //* server has closed
+ if (!pItem->fVisible)
+ {
+ PostMessage(hwndFrame, WM_DELETE, 0L, (DWORD)pItem);
+ Dirty(DOC_UNDIRTY);
+ }
+ SetFocus( hwndFrame );
+ break;
+
+ case OLE_SAVED: //* server has saved object
+ case OLE_CHANGED: //* object has changes
+ cOleWait++;
+ pItem->fServerChangedBounds = pItem->fVisible = TRUE;
+ PostMessage(pItem->hwnd, WM_CHANGE, 0, 0L);
+ break;
+
+ case OLE_RELEASE: //* notification that an asynchronous
+ ToggleBlockTimer(FALSE); //* toggle timer off
+ if (hRetry)
+ PostMessage(hRetry,WM_COMMAND,IDCANCEL,0L);
+
+ if (cOleWait) //* operation has completed
+ {
+ pItem->fRetry = TRUE;
+ if (!--cOleWait)
+ Hourglass(FALSE);
+ Release(pItem);
+ }
+ break;
+
+ case OLE_QUERY_RETRY: //* Continue retrying.
+ ToggleBlockTimer(FALSE); //* toggle timer off
+ if (!hRetry && pItem->fRetry)
+ PostMessage(hwndFrame,WM_RETRY,0L, (DWORD)pItem);
+ return (pItem->fRetry);
+
+ case OLE_QUERY_PAINT: //* continue repainting
+ return TRUE; //* a false return terminates either
+
+ default:
+ break;
+ }
+ return 0; //* return value is ignored in
+ //* most cases, see header
+}
+
+/***************************************************************************
+ * Release()
+ *
+ * Check for an error on the OLE_RELEASE notification.
+ **************************************************************************/
+
+static VOID Release( //* ENTRY:
+ APPITEMPTR pItem //* Item pointer
+){ //* LOCAL:
+ DWORD wParam; //* error code parameter
+
+ if ((wParam = OleQueryReleaseError(pItem->lpObject)) == OLE_OK)
+ return;
+
+ switch (OleQueryReleaseMethod(pItem->lpObject))
+ {
+ case OLE_LNKPASTE:
+ pItem->fVisible = FALSE;
+ break;
+
+ case OLE_CREATEFROMTEMPLATE:
+ case OLE_CREATE:
+ pItem->fVisible = FALSE;
+ cOleWait++;
+ PostMessage(hwndFrame, WM_DELETE,1L, (DWORD)pItem);
+ Dirty(DOC_UNDIRTY);
+ }
+ //* post a message to the main window
+ //* which will display a message box
+ PostMessage(hwndFrame,WM_ERROR,wParam,0);
+
+}
+
+/***************************************************************************
+ * Error()
+ *
+ * This function checks for error conditions
+ * generated by OLE API callsFor OLE_WAIT_FOR_RELEASE,
+ * we keep track of the number of objects waiting, when
+ * this count is zero, it is safe to exit the application.
+ *
+ * Returns OLESTATUS - 0 if OLE_WAIT_FOR_RELEASE or OLE_OK
+ * otherwise the OLESTATUS returned after an action
+ * is taken.
+ *************************************************************************/
+
+OLESTATUS FAR Error( //* ENTRY
+ OLESTATUS olestat //* OLE status
+){
+
+ switch (olestat)
+ {
+ case OLE_WAIT_FOR_RELEASE:
+ if (!cOleWait)
+ Hourglass(TRUE);
+ cOleWait++; //* increment wait count
+
+ case OLE_OK:
+ return 0;
+
+ case OLE_ERROR_STATIC: //* static object
+ ErrorMessage(W_STATIC_OBJECT);
+ break;
+
+ case OLE_ERROR_REQUEST_PICT:
+ case OLE_ERROR_ADVISE_RENAME:
+ case OLE_ERROR_DOVERB:
+ case OLE_ERROR_SHOW:
+ case OLE_ERROR_OPEN:
+ case OLE_ERROR_NETWORK:
+ case OLE_ERROR_ADVISE_PICT:
+ case OLE_ERROR_COMM: //* Invalid links
+ InvalidLink();
+ break;
+
+ case OLE_BUSY:
+ RetryMessage(NULL,RD_CANCEL);
+
+ default:
+ break;
+ }
+ return olestat;
+}
+
+
+/****************************************************************************
+ * PreItemCreate()
+ *
+ * This routine allocates an application item structure. A pointer to this
+ * structure is passed as the client structure, therefore we need to
+ * have a pointer to the vtbl as the first entry. We are doing this
+ * to allow acess to the application item information during a OLE
+ * DLL callback. This approach simplifies matters.
+ *
+ * Returns APPITEMPTR - a pointer to a new application item structure
+ * which can operate as a client structure.
+ ***************************************************************************/
+
+APPITEMPTR FAR PreItemCreate( //* ENTRY:
+ LPOLECLIENT lpClient, //* OLE client pointer
+ BOOL fShow, //* show/no-show flag
+ LHCLIENTDOC lhcDoc //* client document handle
+){ //* LOCAL:
+ HANDLE hitem; //* temp handle for new item
+ APPITEMPTR pItem; //* application item pointer
+
+
+ if (hitem = LocalAlloc(LMEM_MOVEABLE | LMEM_ZEROINIT, sizeof(APPITEM)))
+ if (pItem = (APPITEMPTR)LocalLock(hitem))
+ { //* set the vtbl pointer
+ pItem->oleclient.lpvtbl = lpClient->lpvtbl;
+ pItem->lpObjectUndo = NULL;
+ pItem->fVisible = fShow;
+ pItem->fServerChangedBounds = FALSE;
+ pItem->lhcDoc = lhcDoc;
+
+ return pItem; //* SUCCESS return
+ }
+
+ ErrorMessage(E_FAILED_TO_ALLOC);
+ return NULL; //* ERROR return
+
+}
+
+
+/***************************************************************************
+ * ItemWndProc()
+ *
+ * This function handles item window message processing.
+ * There is an item window for each OLE object. This was done to
+ * to simplify hit testing and repainting. These windows are child
+ * windows.
+
+ * returns long - standard child routine
+ **************************************************************************/
+
+LONG APIENTRY ItemWndProc( //* ENTRY:
+ HWND hwnd, //* standard windows parameters
+ UINT msg,
+ DWORD wParam,
+ LONG lParam
+){ //* LOCAL:
+ static POINT dragPt; //* Mouse drag point
+ static RECT dragRect; //* Mouse drag rectangle
+ static BOOL fCaptured; //* captured flag
+ APPITEMPTR pItem; //* application item pointer
+ PAINTSTRUCT ps; //* paint structure
+ POINT pt; //* point
+ RECT rc; //* bounding rectangle
+// char lpstr[256];
+
+ switch (msg)
+ {
+ case WM_SIZE:
+ if (pItem = (APPITEMPTR)GetWindowLong(hwnd,0))
+ {
+ if (!pItem->fServerChangedBounds && pItem->otObject == OT_EMBEDDED)
+ ObjSetBounds(pItem);
+ else
+ pItem->fServerChangedBounds = FALSE;
+ }
+ break;
+
+ case WM_CHANGE:
+ --cOleWait;
+ pItem = (APPITEMPTR)GetWindowLong(hwnd,0);
+ if (!Error(OleQueryBounds(pItem->lpObject, &rc)))
+ {
+ ConvertToClient(&rc);
+
+ SetWindowPos(
+ hwnd,
+ NULL,
+ 0,
+ 0,
+ rc.right - rc.left + 2*GetSystemMetrics(SM_CXFRAME),
+ rc.bottom - rc.top + 2*GetSystemMetrics(SM_CYFRAME),
+ SWP_NOZORDER | SWP_NOMOVE | SWP_DRAWFRAME
+ );
+
+ if (!pItem->fNew && !fLoadFile)
+ ShowNewWindow(pItem);
+ else
+ InvalidateRect(hwnd, NULL, TRUE);
+
+ Dirty(DOC_DIRTY);
+ }
+ break;
+
+ case WM_NCLBUTTONDOWN:
+ SetTopItem((APPITEMPTR)GetWindowLong(hwnd,0));
+ return (DefWindowProc(hwnd, msg, wParam, lParam));
+
+ case WM_PAINT:
+ BeginPaint(hwnd, (LPPAINTSTRUCT)&ps);
+ GetClientRect(hwnd, &rc);
+ pItem = (APPITEMPTR)GetWindowLong(hwnd, 0);
+ //* Call OLE draw
+ Error(OleDraw(pItem->lpObject, ps.hdc, &rc, NULL, NULL));
+
+ EndPaint(hwnd, (LPPAINTSTRUCT)&ps);
+ break;
+
+ case WM_LBUTTONDBLCLK: //* execute a verb
+ ANY_OBJECT_BUSY;
+ ExecuteVerb(OLEVERB_PRIMARY,(APPITEMPTR)GetWindowLong(hwnd,0));
+ break;
+
+ case WM_LBUTTONDOWN:
+ GetWindowRect(hwnd, (LPRECT)&dragRect);
+ ScreenToClient(hwndFrame, (LPPOINT)&dragRect);
+ ScreenToClient(hwndFrame, (LPPOINT)&dragRect.right);
+
+ dragPt.x = (LONG)(SHORT)LOWORD(lParam);
+ dragPt.y = (LONG)(SHORT)HIWORD(lParam);
+
+ ClientToScreen(hwnd, (LPPOINT)&dragPt);
+ ScreenToClient(hwndFrame, (LPPOINT)&dragPt);
+
+ SetCapture(hwnd);
+ fCaptured = TRUE;
+ SetTopItem((APPITEMPTR)GetWindowLong(hwnd,0));
+ break;
+
+ case WM_LBUTTONUP:
+ if (!fCaptured)
+ break;
+ ReleaseCapture();
+ fCaptured = FALSE;
+ Dirty(DOC_DIRTY);
+ break;
+
+ case WM_MOUSEMOVE:
+ if (!fCaptured)
+ break;
+ pt.x = (LONG)(SHORT)LOWORD(lParam);
+ pt.y = (LONG)(SHORT)HIWORD(lParam);
+
+ ClientToScreen(hwnd, (LPPOINT)&pt);
+ ScreenToClient(hwndFrame, (LPPOINT)&pt);
+
+ OffsetRect(
+ (LPRECT)&dragRect,
+ pt.x - dragPt.x,
+ pt.y - dragPt.y
+ );
+
+ MoveWindow(
+ hwnd,
+ dragRect.left, dragRect.top,
+ dragRect.right - dragRect.left,
+ dragRect.bottom - dragRect.top, TRUE
+ );
+
+ dragPt.x = pt.x;
+ dragPt.y = pt.y;
+ break;
+
+ default:
+ return (DefWindowProc(hwnd, msg, wParam, lParam));
+ }
+ return 0L;
+
+}
+
+/****************************************************************************
+ * PostItemCreate()
+ *
+ * This function creates a child window which will contain the newly
+ * created OLE object. A pointer to our item information is stored in the
+ * extra bytes of this window. This is where we internally keep track
+ * of information related to the object as well as the
+ * pointer to the object for subsequent OLE API calls. This routine is
+ * called after an OLE object has been created by the client library.
+ *
+ * Returns BOOL - TRUE if application item has been created.
+ ****************************************************************************/
+
+BOOL FAR PostItemCreate( //* ENTRY:
+ LPOLEOBJECT lpObject, //* OLE object pointer
+ LONG otObject, //* OLE object type
+ LPRECT lprcObject, //* object bounding rect
+ APPITEMPTR pItem //* application item pointer
+){ //* LOCAL:
+ INT i; //* index
+ RECT rc; //* bounding rectangle
+ CHAR pData[OBJECT_LINK_MAX];//* copy of link data
+
+ if (lprcObject) //* if the size of the objects
+ rc = *lprcObject; //* bounding rectangle is not
+ else if (OleQueryBounds(lpObject, &rc) == OLE_OK)
+ ConvertToClient(&rc);
+ else
+ SetRect(&rc, 0, 0, 0, 0);
+
+ if (!(pItem->hwnd = CreateWindow( //* Create the child window
+ szItemClass, "",
+ WS_BORDER | WS_CHILD | WS_CLIPSIBLINGS | WS_THICKFRAME,
+ rc.left,rc.top,
+ rc.right - rc.left + 2 * GetSystemMetrics(SM_CXFRAME),
+ rc.bottom - rc.top + 2 * GetSystemMetrics(SM_CYFRAME),
+ hwndFrame, NULL, hInst, NULL
+ ))) goto Error;
+
+ //* in windows extra bytes
+ SetWindowLong(pItem->hwnd, 0, (LONG)pItem);
+
+ pItem->otObject = otObject;
+ pItem->lpObject = lpObject;
+ pItem->fRetry = TRUE;
+
+ if( pItem->otObject == OT_EMBEDDED )//* if object is embedded tell library
+ { //* the container name and object name.
+ UINT cb=CBOBJNAMEMAX; //* The name will be the server window title.
+ CHAR sz[CBOBJNAMEMAX]; //* when the object is edited.
+
+ OleQueryName(lpObject, (LPSTR)sz, (UINT FAR *)&cb );
+
+
+ WaitForObject(pItem);
+ Error(OleSetHostNames(lpObject, (LPSTR)szAppName, (LPSTR)sz ));
+ WaitForObject(pItem);
+ }
+ else if (pItem->otObject == OT_LINK)//* if the object is linked
+ { //* retrieve update options
+
+ WaitForObject(pItem);
+ if(Error(OleGetLinkUpdateOptions(pItem->lpObject, &pItem->uoObject)))
+ goto Error;
+
+ if (ObjGetData(pItem,pData))
+ {
+ for (i=0; pData[i];i++); //* Skip past the server name
+ pItem->aLinkName = AddAtom(&pData[++i]);
+ }
+ else
+ pItem->aLinkName = AddAtom("");
+ }
+ iObjects++;
+ Dirty(DOC_DIRTY);
+ //* a user interface recommendations.
+ return TRUE; //* SUCCESS return
+
+Error: //* ERROR Tag
+
+ ErrorMessage(E_FAILED_TO_CREATE_CHILD_WINDOW);
+ FreeAppItem(pItem);
+
+ return FALSE; //* ERROR return
+
+}
+
+/***************************************************************************
+ * ConvertToClient()
+ *
+ * This function will convert to client from himetric.
+ **************************************************************************/
+
+VOID FAR ConvertToClient( //* ENTRY:
+ LPRECT lprc //* pointer to bounding rectangle
+){ //* LOCAL
+
+ //* If we have an empty rectangle then set the default size
+ if (!(lprc->left || lprc->top || lprc->right || lprc->bottom))
+ SetRect(lprc, 0, 0, CXDEFAULT, CYDEFAULT);
+ else
+ {
+ //* We got the himetric units, converts them to pixels now.
+ lprc->right = MulDiv (giXppli, (lprc->right - lprc->left),
+ HIMETRIC_PER_INCH);
+
+ lprc->bottom = MulDiv (giYppli, (lprc->top - lprc->bottom),
+ HIMETRIC_PER_INCH);
+
+ lprc->left = 0;
+ lprc->top = 0;
+ }
+}
+
+/***************************************************************************
+ * ObjInsert()
+ *
+ * Query the user for object type to insert and insert the new OLE object
+ ***************************************************************************/
+
+VOID FAR ObjInsert( //* ENTRY:
+ LHCLIENTDOC lhcDoc, //* OLE document handle
+ LPOLECLIENT lpClient //* pointer to OLE client structure
+){ //* LOCAL:
+ LPOLEOBJECT lpObject; //* pointer to OLE object
+ APPITEMPTR pItem; //* item pointer
+ CHAR szServerName[CBPATHMAX];//* Class name for OleCreate()
+ CHAR szClassName[CBPATHMAX];//* Class name for OleCreate()
+ CHAR szTmp[CBOBJNAMEMAX]; //* buffer to unique object name
+
+ if (DialogBoxParam(hInst, MAKEINTRESOURCE(DTCREATE),hwndFrame,
+ (DLGPROC) fnInsertNew, (LONG)((LPSTR)szClassName)) != IDCANCEL)
+ {
+ if (pItem = PreItemCreate(lpClient, FALSE, lhcDoc))
+ {
+ RegGetClassId(szServerName, szClassName);
+ pItem->aServer = AddAtom(szServerName);
+ if ( Error( OleCreate(STDFILEEDITING,(LPOLECLIENT)&(pItem->oleclient),
+ (LPSTR)szClassName, lhcDoc,CreateNewUniqueName(szTmp),
+ &lpObject,olerender_draw, 0)))
+ {
+ ErrorMessage(E_FAILED_TO_CREATE_OBJECT);
+ FreeAppItem(pItem);
+ }
+ else
+ PostItemCreate(lpObject, OT_EMBEDDED, NULL, pItem);
+ }
+ }
+
+
+}
+
+/***************************************************************************
+ * ObjDelete()
+ *
+ * Delete an OLE object. For this application, all OLE objects
+ * are associated with a child window; therefore the window must be
+ * destroyed.
+ *
+ * NOTE: There is one case when we call OleRelease and the other when
+ * we call OleDelete. We call OleRelease when we are deregistering
+ * a document and OleDelete when removing an object from a document.
+ **************************************************************************/
+
+VOID FAR ObjDelete( //* ENTRY:
+ APPITEMPTR pItem, //* pointer to application item
+ BOOL fDelete //* delete or release flag
+){ //* LOCAL:
+
+ if (pItem->lpObjectUndo)
+ {
+ Error(OleDelete(pItem->lpObjectUndo));
+ //* wait for asynchronous operation
+ WaitForObject(pItem);
+ }
+
+ if (fDelete ? Error(OleDelete(pItem->lpObject))
+ : Error(OleRelease(pItem->lpObject)))
+ {
+ ErrorMessage(E_FAILED_TO_DELETE_OBJECT);
+ return; //* ERROR return
+ }
+
+ if (pItem->fVisible)
+ {
+ ShowWindow(pItem->hwnd, SW_HIDE);
+ pItem->fVisible = FALSE;
+ }
+ //* the operation has to complete
+ WaitForObject(pItem); //* before the application structure
+
+ FreeAppItem(pItem);
+ iObjects--;
+
+}
+
+
+/***************************************************************************
+ * ObjPaste()
+ *
+ * This function obtains an object from the clipboard.
+ * Handles both embedded and linked objects. An item window is
+ * created for each new object.
+ *
+ * Returns BOOL - TRUE if object was pasted succesfully.
+ **************************************************************************/
+
+VOID FAR ObjPaste( //* ENTRY:
+ BOOL fPaste, //* Paste/PasteLink flag
+ LHCLIENTDOC lhcDoc, //* client document handle
+ LPOLECLIENT lpClient //* pointer to client
+){ //* LOCAL:
+ LPOLEOBJECT lpObject; //* object pointer
+ LONG otObject; //* object type
+ APPITEMPTR pItem; //* application item pointer
+ CHAR szTmp[CBOBJNAMEMAX]; //* temporary object name string
+
+ if (!(pItem = PreItemCreate(lpClient, TRUE, lhcDoc)))
+ return; //* ERROR return
+
+ if (!OpenClipboard(hwndFrame))
+ goto Error; //* ERROR jump
+
+
+ if (fPaste) //* PASTE the object.
+ { //* Try "StdFileEditing" protocol
+ if (Error(OleCreateFromClip(STDFILEEDITING,(LPOLECLIENT)&(pItem->oleclient),lhcDoc,
+ CreateNewUniqueName(szTmp),&lpObject, olerender_draw,0)))
+ {
+ //* next try "Static" protocol
+ if (Error(OleCreateFromClip(
+ STATICP, (LPOLECLIENT)&(pItem->oleclient), lhcDoc,
+ CreateNewUniqueName(szTmp), &lpObject, olerender_draw, 0)))
+ goto Error; //* ERROR jump
+ }
+ }
+ else
+ { //* LINK therefore must be
+ // "STdFileEditing" protocol
+ if (Error(OleCreateLinkFromClip(
+ STDFILEEDITING,(LPOLECLIENT)&(pItem->oleclient), lhcDoc,
+ CreateNewUniqueName(szTmp), &lpObject, olerender_draw, 0)))
+ goto Error; //* ERROR jump
+ }
+
+ OleQueryType(lpObject, &otObject);
+ CloseClipboard();
+
+ if (!PostItemCreate(lpObject, otObject, NULL, pItem))
+ return; //* ERROR return
+
+ ShowNewWindow(pItem);
+ return; //* SUCCESS return
+
+
+Error: //* TAG Error
+
+ ErrorMessage(E_GET_FROM_CLIPBOARD_FAILED);
+ CloseClipboard();
+ FreeAppItem(pItem);
+
+ return; //* ERROR return
+
+}
+
+/***************************************************************************
+ * ObjCopy()
+ *
+ * This function places an OLE object on the clipboard via the \
+ * OleCopyToClipboard() function.
+ *
+ * Returns BOOL - TRUE if object successfully placed on clipboard
+ **************************************************************************/
+
+BOOL FAR ObjCopy( //* ENTRY:
+ APPITEMPTR pItem //* pointer to app item
+){ //* LOCAL:
+ BOOL fReturn = TRUE; //* return value
+
+ if (!OpenClipboard(hwndFrame))
+ return FALSE; //* ERROR return
+
+ EmptyClipboard();
+
+ if (Error(OleCopyToClipboard(pItem->lpObject)))
+ fReturn = FALSE; //* prepare for ERROR out
+
+ CloseClipboard();
+ return fReturn; //* ERROR or SUCCESS
+
+}
+
+/***************************************************************************
+ * ObjCreateFromTemplate()
+ *
+ * Creates an embedded object from file.
+ **************************************************************************/
+
+VOID FAR ObjCreateFromTemplate( //* ENTRY:
+ LHCLIENTDOC lhcDoc, //* client document handle
+ LPOLECLIENT lpClient //* client vtbl. pointer
+){ //* LOCAL:
+ LPOLEOBJECT lpObject; //* OLE object pointer
+ APPITEMPTR pItem; //* application item pointer
+ CHAR szTmp[CBOBJNAMEMAX]; //* temporary object name string
+ CHAR szFileName[CBPATHMAX];//* file name string
+
+ *szFileName = 0;
+
+ if (!OfnGetName(hwndFrame, szFileName, IDM_INSERTFILE))
+ return; //* ERROR operation aborted by user
+
+ if (!(pItem = PreItemCreate(lpClient, FALSE, lhcDoc)))
+ return; //* ERROR
+
+ if (Error(OleCreateFromTemplate(STDFILEEDITING, (LPOLECLIENT)pItem, szFileName,
+ lhcDoc, CreateNewUniqueName(szTmp), &lpObject, olerender_draw, 0)))
+ {
+ ErrorMessage(E_CREATE_FROM_TEMPLATE);
+ FreeAppItem(pItem);
+ return; //* ERROR
+ }
+
+ PostItemCreate(lpObject, OT_EMBEDDED, NULL, pItem);
+
+} //* SUCCESS
+
+
+/****************************************************************************
+ * ObjGetData()
+ *
+ * Get the object link data. The data that is retrieved from OLE is copied
+ * into lpLinkData if lpLinkData is not NULL. Otherwise, space is dynamically
+ * allocated or reallocated; space is allocated if pItem->lpLinkData is NULL
+ * otherwise the pointer is reallocated. The data is returned is freed if
+ * there has been an OLE_WARN_DELETE_DATA error.
+ ***************************************************************************/
+
+BOOL FAR ObjGetData( //* ENTRY:
+ APPITEMPTR pItem, //* OLE object
+ LPSTR lpLinkData //* pointer to linkdata
+){ //* LOCAL:
+ HANDLE hData; //* handle to OLE link data
+ LPSTR lpData; //* pointer to OLE link data
+ LPSTR lpWork; //* copy of OLE link data
+ BOOL fFree = FALSE; //* free OLE memory flag
+ LONG lSize; //* size of OLE link data
+ INT i;
+
+ switch (Error(OleGetData(pItem->lpObject,
+ (OLECLIPFORMAT)(pItem->otObject == OT_LINK ? vcfLink : vcfOwnerLink), &hData)))
+ {
+ case OLE_WARN_DELETE_DATA:
+ fFree = TRUE;
+ case OLE_OK:
+ if(lpData = GlobalLock(hData))
+ {
+ //* copy the link data to new buffer
+ lSize=SizeOfLinkData(lpData);
+
+ if (!lpLinkData)
+ {
+ if (!pItem->lpLinkData) //* allocate
+ AllocLinkData(pItem,lSize);
+ else //* otherwise reallocate
+ ReallocLinkData(pItem,lSize);
+ lpWork = pItem->lpLinkData;
+ }
+ else
+ lpWork = lpLinkData;
+
+ if (lpWork)
+ for (i=0L; i<(INT)lSize; i++)
+ *(lpWork+i)=*(lpData+i);
+
+ GlobalUnlock(hData); //* free the linked data as needed
+ if (fFree)
+ GlobalFree(hData);
+
+ return TRUE; //* SUCCESS
+ }
+ default:
+ return FALSE; //* FAILURE
+ }
+
+}
+
+/***************************************************************************
+ * ObjChangeLink()
+ *
+ * Change the linkdata. This routine will change the document portion of
+ * link data to lpDoc. The old linkdata is expected to be in
+ * lpaItem->lpLinkData
+ **************************************************************************/
+
+VOID FAR ObjChangeLinkData( //* ENTRY:
+ APPITEMPTR pItem, //* OLE object
+ LPSTR lpDoc //* document name
+){ //* LOCAL:
+ LONG lSize; //* used to link data size
+ LPSTR lpLinkData; //* OLE link data pointer
+ static CHAR pWork[OBJECT_LINK_MAX]; //* used to construct new link data
+ INT i; //* index
+ HANDLE hData;
+
+ pItem->aLinkName = AddAtom(lpDoc);
+
+ for (
+ lpLinkData = pItem->lpLinkData, i=0;
+ pWork[i] = *lpLinkData;
+ lpLinkData++, i++
+ );
+ //* into working buffer.
+ lstrcpy((LPSTR)&pWork[++i],lpDoc); //* copy new document name.
+
+ for (; pWork[i]; i++); //* skip to end of document name
+ for (++lpLinkData;*lpLinkData;lpLinkData++);
+ //* copy item name.
+ lstrcpy((LPSTR)&pWork[++i],++lpLinkData);
+ for (; pWork[i]; i++); //* skip to end of buffer
+ //* which is the end of item info.
+ pWork[++i] = 0; //* add extra null.
+
+ lSize = SizeOfLinkData(pWork); //* reallocate space so there is
+ ReallocLinkData(pItem,lSize); //* a properly sized block of info
+ //* to send the linked data to the
+ if (lpLinkData = pItem->lpLinkData) //* OLE DLL.
+ for (i=0; i<(INT)lSize; i++) //* copy new linkdata into this space
+ *lpLinkData++ = pWork[i];
+ else
+ return; //* ERROR return
+
+ Error(OleSetData(pItem->lpObject, vcfLink, GlobalHandle(pItem->lpLinkData)));
+
+ /*
+ * The handle passed into OleSetData is owned by the OLE client library
+ * and should not be used after the call. On win32s, it is inaccessible
+ * after the call, so restore it by calling OleGetData. Note that the
+ * data is *still* owned by the library, but we will now have access
+ * to the memory.
+ */
+ Error(OleGetData(pItem->lpObject, vcfLink, &hData));
+ if (hData) {
+ pItem->lpLinkData = GlobalLock(hData);
+ }
+} //* SUCCESS return
+
+/****************************************************************************
+ * ObjSaveUndo()
+ *
+ * Clone the OLE object so that any changes to object can be undone if the
+ * user choses to exit without update.
+ ***************************************************************************/
+
+VOID FAR ObjSaveUndo( //* ENTRY:
+ APPITEMPTR pItem //* application item
+){ //* LOCAL:
+ CHAR szTmp[CBOBJNAMEMAX]; //* holder of object name
+ LPSTR lpClone; //* pointer to clond object name
+ UINT i=CBOBJNAMEMAX;
+
+ if (!pItem->lpObjectUndo)
+ {
+ OleQueryName(pItem->lpObject, szTmp, &i);
+ //* give clone a unique name by
+ //* altering object name prefix.
+ for (lpClone = OBJCLONE, i=0; *lpClone; szTmp[i++] = *lpClone++);
+
+ if (Error(OleClone(pItem->lpObject, (LPOLECLIENT)pItem,
+ pItem->lhcDoc, szTmp, &(pItem->lpObjectUndo))))
+ return; //* ERROR return
+
+ pItem->otObjectUndo = pItem->otObject;
+ pItem->uoObjectUndo = pItem->uoObject;
+ pItem->aLinkUndo = pItem->aLinkName;
+
+ GetClientRect(pItem->hwnd, &pItem->rect);
+
+ if (OleQueryOpen(pItem->lpObject) == OLE_OK)
+ pItem->fOpen = TRUE;
+
+ }
+
+} //* SUCCESS return
+
+/****************************************************************************
+ * ObjUndo()
+ *
+ * Restore an object to its state before changes. The lpObject Undo is a
+ * clone to the original object with a different name, therefore, all we
+ * have to do is rename that object and ditch the changed object.
+ ***************************************************************************/
+
+VOID FAR ObjUndo( //* ENTRY:
+ APPITEMPTR pItem //* application item
+){ //* LOCAL:
+ CHAR szTmp[CBOBJNAMEMAX]; //* object name holder
+ UINT i = CBOBJNAMEMAX;
+
+ OleQueryName(pItem->lpObject, szTmp, &i);
+ if (Error(OleDelete(pItem->lpObject)))
+ return; //* ERROR return
+ //* reset app item vars
+ pItem->lpObject = pItem->lpObjectUndo;
+ pItem->otObject = pItem->otObjectUndo;
+ pItem->uoObject = pItem->uoObjectUndo;
+ pItem->aLinkName = pItem->aLinkUndo;
+ pItem->lpObjectUndo = (LPOLEOBJECT)NULL;
+ pItem->otObjectUndo = (LONG)NULL;
+
+ if (Error(OleRename(pItem->lpObject,szTmp)))
+ return; //* ERROR return
+
+ if (pItem->fOpen)
+ {
+ Error(OleReconnect(pItem->lpObject));
+ pItem->fOpen = FALSE;
+ }
+
+ SetWindowPos(
+ pItem->hwnd,
+ NULL, 0, 0,
+ pItem->rect.right - pItem->rect.left + 2*GetSystemMetrics(SM_CXFRAME),
+ pItem->rect.bottom - pItem->rect.top + 2*GetSystemMetrics(SM_CYFRAME),
+ SWP_NOZORDER | SWP_NOMOVE | SWP_DRAWFRAME
+ );
+
+ InvalidateRect(pItem->hwnd,NULL,TRUE);
+
+} //* SUCCESS return
+
+
+/****************************************************************************
+ * ObjDelUndo()
+ *
+ * Delete the undo object if the user is happy with the changes he/she made.
+ ***************************************************************************/
+
+VOID FAR ObjDelUndo( //* ENTRY:
+ APPITEMPTR pItem //* application item
+){
+
+ if (Error(OleDelete(pItem->lpObjectUndo)))
+ return; //* ERROR return
+
+ pItem->lpObjectUndo = (LPOLEOBJECT)NULL;
+ pItem->otObjectUndo = (LONG)NULL;
+ DeleteAtom(pItem->aLinkUndo);
+ pItem->lpObjectUndo = NULL;
+
+} //* SUCCESS return
+
+/****************************************************************************
+ * ObjFreeze()
+ *
+ * Convert an object to a static object.
+ ***************************************************************************/
+
+VOID FAR ObjFreeze( //* ENTRY:
+ APPITEMPTR pItem //* application item
+){ //* LOCAL:
+ CHAR szTmp[CBOBJNAMEMAX]; //* temporary object name
+ LPSTR lpTemp; //* temporary prefix string
+ LPOLEOBJECT lpObjectTmp; //* temporary object pointer
+ UINT i=CBOBJNAMEMAX;
+
+ OleQueryName(pItem->lpObject, szTmp, &i);
+ //* create a unique name by changing
+ //* the object name prefix
+ for (lpTemp = OBJTEMP, i=0; *lpTemp; szTmp[i++] = *lpTemp++);
+
+ //* this API creates a static object
+ if (Error(OleObjectConvert(pItem->lpObject, STATICP, (LPOLECLIENT)pItem,
+ pItem->lhcDoc, szTmp, &lpObjectTmp)))
+ return;
+ //* delete old object
+ if (Error(OleDelete(pItem->lpObject)))
+ return;
+
+ WaitForObject(pItem);
+
+ pItem->lpObject = lpObjectTmp;
+ pItem->otObject = OT_STATIC;
+ pItem->uoObject = -1L;
+
+ for (lpTemp = OBJPREFIX, i=0; *lpTemp; szTmp[i++] = *lpTemp++);
+ if (Error(OleRename(pItem->lpObject,szTmp)))
+ return;
+
+
+}
+
+/***************************************************************************
+ * ObjCreateWrap()
+ *
+ * Create a wrapped object from the drag and drop feature of the 3.1 shell.
+ * NOTE: We are assuming that only one file has been dropped. See the SDK
+ * documentation for instructions on how to deal with multiple files.
+ ***************************************************************************/
+
+VOID FAR ObjCreateWrap( //* ENTRY:
+ HANDLE hdrop, //* handle to dropped object
+ LHCLIENTDOC lhcDoc, //* document handle
+ LPOLECLIENT lpClient //* pointer to client structure
+){ //* LOCAL:
+ CHAR szDragDrop[CBPATHMAX];//* Drag and drop file name
+ LPOLEOBJECT lpObject; //* pointer to OLE object
+ POINT pt; //* position of dropped object
+ RECT rc; //* object size and position
+ CHAR szTmp[CBOBJNAMEMAX]; //* buffer for unique object name
+ APPITEMPTR pItem; //* application item pointer
+ INT x,y; //* icon sizes
+
+ x = GetSystemMetrics(SM_CXICON) / 2;
+ y = GetSystemMetrics(SM_CYICON) / 2;
+ //* Get the drag and drop filename
+ //* position
+ DragQueryPoint(hdrop, &pt);
+ DragQueryFile(hdrop, 0, szDragDrop, CBPATHMAX);
+ DragFinish(hdrop);
+
+ SetRect(&rc, pt.x - x, pt.y - y, pt.x + x, pt.y + y);
+
+ if (!(pItem = PreItemCreate(lpClient, TRUE, lhcDoc)))
+ return; //* ERROR return
+ //* create OLE object
+ if (Error(OleCreateFromFile(STDFILEEDITING, (LPOLECLIENT)pItem,
+ "Package", szDragDrop, lhcDoc, CreateNewUniqueName(szTmp),
+ &lpObject, olerender_draw, 0)))
+ {
+ ErrorMessage(E_FAILED_TO_CREATE_OBJECT);
+ FreeAppItem(pItem);
+ return; //* ERROR return
+ }
+
+ if (PostItemCreate(lpObject, OT_EMBEDDED, &rc, pItem))
+ ShowNewWindow(pItem);
+
+} //* SUCCESS return
+
+/***************************************************************************
+ * UpdateObjectMenuItem()
+ *
+ * Add an object popup menu for the chosen object if multiple verbs exist.
+ * The registration system is used to determine which verbs exist for the
+ * given object.
+ **************************************************************************/
+
+VOID FAR UpdateObjectMenuItem( //* ENTRY:
+ HMENU hMenu //* main menu
+){ //* LOCAL
+ INT cVerbs; //* verb
+ APPITEMPTR pItem; //* application item ponter
+ DWORD dwSize = KEYNAMESIZE;
+ CHAR szClass[KEYNAMESIZE], szBuffer[200];
+ CHAR szVerb[KEYNAMESIZE];
+ HMENU hPopupNew=NULL;
+ HKEY hkeyTemp;
+ CHAR pLinkData[OBJECT_LINK_MAX];
+ //* delete current item and submenu
+ DeleteMenu(hMenu, POS_OBJECT, MF_BYPOSITION );
+
+ if (!(pItem = GetTopItem()) )
+ goto Error; //* ERROR jump
+ else if (!pItem->fVisible)
+ goto Error; //* ERROR jump
+ //* if STATIC ?
+ if ((pItem->otObject != OT_EMBEDDED) && (pItem->otObject != OT_LINK))
+ goto Error; //* ERROR jump
+
+ if (!ObjGetData(pItem, pLinkData)) //* get linkdata as key reg database
+ goto Error; //* ERROR jump
+ //* open reg database
+ szClass[0] = 0;
+ if (RegOpenKey(HKEY_CLASSES_ROOT, szClass, &hkeyTemp))
+ goto Error; //* ERROR jump
+ //* check if class is reg-db
+ if (RegQueryValue(HKEY_CLASSES_ROOT, pLinkData, szClass, &dwSize))
+ {
+ RegCloseKey(hkeyTemp);
+ goto Error; //* ERROR jump
+ }
+
+ for (cVerbs=0; ;++cVerbs) //* extract all verbs from reg-db
+ {
+ dwSize = KEYNAMESIZE;
+ wsprintf(szBuffer, "%s\\protocol\\StdFileEditing\\verb\\%d",
+ (LPSTR)pLinkData,cVerbs);
+
+ if (RegQueryValue(HKEY_CLASSES_ROOT, szBuffer, szVerb, &dwSize))
+ break;
+
+ if (!hPopupNew)
+ hPopupNew = CreatePopupMenu();
+
+ InsertMenu(hPopupNew, (UINT)-1, MF_BYPOSITION, IDM_VERBMIN+cVerbs, szVerb);
+ }
+
+ //* NOTE: For International versions the following verb menu
+ //* may need to be formatted differently.
+
+ switch (cVerbs) //* determine how many verbs found
+ {
+ case 0: //* none
+ wsprintf(szBuffer, "Edit %s %s", (LPSTR)szClass, (LPSTR)"&Object");
+ InsertMenu(hMenu, POS_OBJECT, MF_BYPOSITION, IDM_VERBMIN, szBuffer);
+ break;
+
+ case 1: //* one
+ wsprintf(szBuffer, "%s %s %s", (LPSTR)szVerb, (LPSTR)szClass,
+ (LPSTR)"&Object");
+ DestroyMenu(hPopupNew);
+ InsertMenu(hMenu, POS_OBJECT, MF_BYPOSITION, IDM_VERBMIN, szBuffer);
+ break;
+
+ default: //* > 1
+ wsprintf(szBuffer, "%s %s", (LPSTR)szClass, (LPSTR)"&Object");
+ InsertMenu(hMenu, POS_OBJECT, MF_BYPOSITION | MF_POPUP, (UINT)hPopupNew, szBuffer);
+ EnableMenuItem(hMenu, POS_OBJECT, MF_ENABLED|MF_BYPOSITION);
+ break;
+ }
+
+ RegCloseKey(hkeyTemp); //* close reg-db
+ return; //* SUCCESS return
+
+Error: //* ERROR tag
+ InsertMenu(hMenu, POS_OBJECT, MF_BYPOSITION, 0, "&Object");
+ EnableMenuItem(hMenu, POS_OBJECT, MF_GRAYED | MF_BYPOSITION);
+
+} //* ERROR return
+
+/***************************************************************************
+ * ExecuteVerb()
+ *
+ * Execute the verb for the given object.
+ ***************************************************************************/
+
+VOID FAR ExecuteVerb( //* ENTRY:
+ UINT iVerb, //* verb
+ APPITEMPTR pItem //* application item pointer
+){ //* LOCAL
+ RECT rc; //* holds client area bounding rect
+
+ if (pItem->otObject == OT_STATIC) //* if the object is static beep
+ {
+ ErrorMessage(W_STATIC_OBJECT);
+ return; //* return
+ }
+ //* get cliet area rectangle
+ GetClientRect(hwndFrame, (LPRECT)&rc);
+ //* execute OLE verb
+ if (Error(OleActivate(pItem->lpObject, iVerb, TRUE, TRUE, hwndFrame, &rc)))
+ return;
+
+ WaitForObject(pItem); //* wait for async. operation
+
+ ObjSetBounds(pItem);
+
+
+} //* SUCCESS return
+
+/****************************************************************************
+ * ObjSetBounds
+ *
+ * Set the object bounds. The object bounds are the child windos bounding
+ * rectangle. OLE servers recieve need the bounding rectangle in HIMETRIC
+ * coordinates. So, we convert from screen coordinates to HIMETRIC.
+ *
+ * Returns BOOL - TRUE if successful.
+ ***************************************************************************/
+BOOL FAR ObjSetBounds( //* ENTRY:
+ APPITEMPTR pItem //* application item pointer
+){ //* LOCAL:
+ RECT itemRect; //* bounding rectangle
+
+ GetWindowRect(pItem->hwnd,&itemRect);//* get item window react
+
+ itemRect.right -= GetSystemMetrics(SM_CXFRAME);
+ itemRect.left += GetSystemMetrics(SM_CXFRAME);
+ itemRect.top += GetSystemMetrics(SM_CYFRAME);
+ itemRect.bottom -= GetSystemMetrics(SM_CYFRAME);
+
+ itemRect.right = MulDiv ((itemRect.right - itemRect.left),
+ HIMETRIC_PER_INCH, giXppli);
+ itemRect.bottom = - MulDiv((itemRect.bottom - itemRect.top),
+ HIMETRIC_PER_INCH, giYppli);
+ itemRect.top = 0;
+ itemRect.left = 0;
+ //* set the rect for the server
+ if (Error(OleSetBounds(pItem->lpObject,(LPRECT)&itemRect)))
+ return FALSE; //* ERROR return
+
+ WaitForObject(pItem); //* wait for async. operation
+ return TRUE; //* SUCCESS return
+
+}
+
diff --git a/private/oleutest/ole1/clidemo/object.h b/private/oleutest/ole1/clidemo/object.h
new file mode 100644
index 000000000..e928d9882
--- /dev/null
+++ b/private/oleutest/ole1/clidemo/object.h
@@ -0,0 +1,40 @@
+/*
+ * object.h
+ *
+ * Created by Microsoft Corporation.
+ * (c) Copyright Microsoft Corp. 1990 - 1992 All Rights Reserved
+ */
+
+//*** PROTOTYPES ***
+
+//* OLE Callbacks
+
+INT APIENTRY CallBack(LPOLECLIENT, OLE_NOTIFICATION, LPOLEOBJECT);
+
+//* Exported Windows procedures
+
+LONG APIENTRY ItemWndProc(HWND, UINT, DWORD, LONG);
+
+//* Far
+VOID FAR ObjDelete(APPITEMPTR, BOOL);
+VOID FAR ConvertToClient(LPRECT);
+OLESTATUS FAR Error(OLESTATUS);
+APPITEMPTR FAR PreItemCreate(LPOLECLIENT, BOOL, LHCLIENTDOC);
+BOOL FAR PostItemCreate(LPOLEOBJECT, LONG, LPRECT, APPITEMPTR);
+VOID FAR ObjPaste(BOOL, LHCLIENTDOC, LPOLECLIENT);
+BOOL FAR ObjCopy(APPITEMPTR);
+BOOL FAR ObjGetData (APPITEMPTR, LPSTR);
+VOID FAR ObjChangeLinkData(APPITEMPTR, LPSTR);
+VOID FAR ObjSaveUndo(APPITEMPTR);
+VOID FAR ObjDelUndo(APPITEMPTR);
+VOID FAR ObjUndo(APPITEMPTR);
+VOID FAR ObjFreeze(APPITEMPTR);
+VOID FAR ObjInsert(LHCLIENTDOC, LPOLECLIENT);
+VOID FAR ObjCreateFromTemplate(LHCLIENTDOC, LPOLECLIENT);
+VOID FAR ObjCreateWrap(HANDLE, LHCLIENTDOC, LPOLECLIENT);
+VOID FAR UpdateObjectMenuItem(HMENU);
+VOID FAR ExecuteVerb(UINT, APPITEMPTR);
+
+//* Local
+static VOID Release(APPITEMPTR);
+BOOL FAR ObjSetBounds(APPITEMPTR);
diff --git a/private/oleutest/ole1/clidemo/register.c b/private/oleutest/ole1/clidemo/register.c
new file mode 100644
index 000000000..9a7b7ae90
--- /dev/null
+++ b/private/oleutest/ole1/clidemo/register.c
@@ -0,0 +1,196 @@
+/*
+ * register.c - Handles the Win 3.1 registration library.
+ *
+ * Created by Microsoft Corporation.
+ * (c) Copyright Microsoft Corp. 1990 - 1992 All Rights Reserved
+ */
+
+//*** INCLUDES ***
+
+#include <windows.h>
+#include <ole.h>
+
+#include "global.h"
+#include "register.h"
+#include "clidemo.h"
+#include "demorc.h"
+
+/****************************************************************************
+ * RegGetClassId() - Retrieves the string name of a class.
+ *
+ * Retrieve the string name of a class. Classes are guarenteed to be
+ * in ASCII, but should not be used directly as a rule because they
+ * might be meaningless if running non-English Windows.
+ ***************************************************************************/
+
+VOID FAR RegGetClassId( //* ENTRY:
+ LPSTR lpstrName, //* destination string name of class
+ LPSTR lpstrClass //* source name of class
+){ //* LOCAL:
+ DWORD dwSize = KEYNAMESIZE; //* size of keyname string
+ CHAR szName[KEYNAMESIZE]; //* string name for class
+
+ if (!RegQueryValue(HKEY_CLASSES_ROOT, lpstrClass, (LPSTR)szName, &dwSize))
+ lstrcpy(lpstrName, (LPSTR)szName);
+ else
+ lstrcpy(lpstrName, lpstrClass);
+
+}
+
+
+
+/***************************************************************************
+ * RegMakeFilterSpec() - Retrieves class-associated default extensions.
+ *
+ * Get the class-associated default extensions, and build a filter spec,
+ * to be used in the "Change Link" standard dialog box, which contains
+ * all the default extensions which are associated with the given class
+ * name. Again, the class names are guaranteed to be in ASCII.
+ *
+ * Returns int - The index idFilterIndex states which filter item
+ * matches the extension, or 0 if none is found.
+ ***************************************************************************/
+
+INT FAR RegMakeFilterSpec( //* ENTRY:
+ LPSTR lpstrClass, //* class name
+ LPSTR lpstrExt, //* file extension
+ LPSTR lpstrFilterSpec //* destination filter spec
+){ //* LOCAL:
+ DWORD dwSize; //* size of reg request
+ CHAR szClass[KEYNAMESIZE];//* class name
+ CHAR szName[KEYNAMESIZE]; //* name of subkey
+ CHAR szString[KEYNAMESIZE];//* name of subkey
+ INT i; //* index of subkey query
+ INT idWhich = 0; //* index of combo box item
+ INT idFilterIndex = 0; //* index to filter matching extension
+
+ for (i = 0; !RegEnumKey(HKEY_CLASSES_ROOT, i++, szName, KEYNAMESIZE); )
+ {
+ if ( *szName == '.' //* Default Extension...
+ && (dwSize = KEYNAMESIZE)
+ && !RegQueryValue(HKEY_CLASSES_ROOT, szName, szClass, &dwSize)
+ && (!lpstrClass || !lstrcmpi(lpstrClass, szClass))
+ && (dwSize = KEYNAMESIZE)
+ && !RegQueryValue(HKEY_CLASSES_ROOT, szClass, szString, &dwSize))
+ {
+ idWhich++;
+
+ if (lpstrExt && !lstrcmpi(lpstrExt, szName))
+ idFilterIndex = idWhich;
+ //* Copy over "<Class Name String>
+ //* (*<Default Extension>)"
+ //* e.g. "Server Picture (*.PIC)"
+ lstrcpy(lpstrFilterSpec, szString);
+ lstrcat(lpstrFilterSpec, " (*");
+ lstrcat(lpstrFilterSpec, szName);
+ lstrcat(lpstrFilterSpec, ")");
+ lpstrFilterSpec += lstrlen(lpstrFilterSpec) + 1;
+ //* Copy over "*<Default Extension>"
+ //* (e.g. "*.PIC") */
+ lstrcpy(lpstrFilterSpec, "*");
+ lstrcat(lpstrFilterSpec, szName);
+ lpstrFilterSpec += lstrlen(lpstrFilterSpec) + 1;
+ }
+ }
+
+ *lpstrFilterSpec = 0;
+
+ return idFilterIndex;
+
+}
+
+
+
+/***************************************************************************
+ * RegCopyClassName()
+ *
+ * Get the class name from the registration data base. We have the
+ * descriptive name and we search for the class name.
+ *
+ * returns BOOL - TRUE if class name was found and retrieved from the
+ * registration database.
+ ***************************************************************************/
+
+BOOL FAR RegCopyClassName( //* ENTRY:
+ HWND hwndList, //* HANDLE to list box
+ LPSTR lpstrClassName //* destination character string
+){ //* LOCAL:
+ DWORD dwSize; //* key name size
+ HKEY hkeyTemp; //* temp key
+ CHAR szClass[KEYNAMESIZE];//* class name string
+ CHAR szKey[KEYNAMESIZE]; //* key name string
+ INT i; //* index
+
+ szClass[0] = '\0';
+
+ if (!RegOpenKey(HKEY_CLASSES_ROOT, szClass, &hkeyTemp))
+ {
+ i = (INT)SendMessage(hwndList, LB_GETCURSEL, 0, 0L);
+ SendMessage(hwndList, LB_GETTEXT, i, (DWORD)(LPSTR)szKey);
+
+ for (i = 0; !RegEnumKey(HKEY_CLASSES_ROOT, i++, szClass, KEYNAMESIZE); )
+ if (*szClass != '.')
+ {
+ dwSize = KEYNAMESIZE;
+ if (!RegQueryValue(HKEY_CLASSES_ROOT, szClass, lpstrClassName, &dwSize))
+ if (!lstrcmp(lpstrClassName, szKey))
+ {
+ RegCloseKey(hkeyTemp);
+ lstrcpy(lpstrClassName,szClass);
+ return TRUE;
+ }
+ }
+ RegCloseKey(hkeyTemp);
+ }
+
+ *lpstrClassName = 0;
+ return FALSE;
+
+}
+
+
+
+/***************************************************************************
+ * RegGetClassNames()
+ *
+ * Fills in the list box in the Insert New dialog with the names of
+ * OLE Servers.
+ *
+ * returns TRUE if the listbox filled successfully.
+ **************************************************************************/
+
+BOOL FAR RegGetClassNames( //* ENTRY:
+ HWND hwndList //* HANDLE to the listbox being filled
+){ //* LOCAL:
+ DWORD dwSize; //* sixe of data
+ HKEY hkeyTemp; //* temporary registration key
+ CHAR szExec[KEYNAMESIZE]; //* executables name
+ CHAR szClass[KEYNAMESIZE];//* class name
+ CHAR szName[KEYNAMESIZE]; //* key name
+ INT i;
+
+ SendMessage(hwndList, LB_RESETCONTENT, 0, 0L);
+
+ szClass[0]='\0';
+
+ if (!RegOpenKey(HKEY_CLASSES_ROOT, szClass, &hkeyTemp))
+ {
+ for (i = 0; !RegEnumKey(HKEY_CLASSES_ROOT, i++, szClass, KEYNAMESIZE); )
+ if (*szClass != '.')
+ {
+ lstrcpy(szExec, szClass);
+ lstrcat(szExec, "\\protocol\\StdFileEditing\\server");
+ dwSize = KEYNAMESIZE;
+ if (!RegQueryValue(HKEY_CLASSES_ROOT, szExec, szName, &dwSize))
+ {
+ dwSize = KEYNAMESIZE;
+ if (!RegQueryValue(HKEY_CLASSES_ROOT, szClass, szName, &dwSize))
+ SendMessage(hwndList, LB_ADDSTRING, 0, (DWORD)(LPSTR)szName);
+ }
+ }
+ RegCloseKey(hkeyTemp);
+ return TRUE;
+ }
+ return FALSE;
+
+}
diff --git a/private/oleutest/ole1/clidemo/register.h b/private/oleutest/ole1/clidemo/register.h
new file mode 100644
index 000000000..f99da1e8a
--- /dev/null
+++ b/private/oleutest/ole1/clidemo/register.h
@@ -0,0 +1,17 @@
+/*
+ * <register.h>
+ *
+ * Created by Microsoft Corporation.
+ * (c) Copyright Microsoft Corp. 1990 - 1992 All Rights Reserved
+ */
+
+//*** PROTOTYPES ***
+
+//* Far
+
+BOOL FAR RegCopyClassName(HWND hwndList, LPSTR lpstrClassName);
+VOID FAR RegGetClassId(LPSTR lpstrName, LPSTR lpstrClass);
+BOOL FAR RegGetClassNames(HWND hwndList);
+VOID FAR RegInit(HANDLE hInst);
+INT FAR RegMakeFilterSpec(LPSTR lpstrClass, LPSTR lpstrExt, LPSTR lpstrFilterSpec);
+VOID FAR RegTerm(VOID);
diff --git a/private/oleutest/ole1/clidemo/stream.c b/private/oleutest/ole1/clidemo/stream.c
new file mode 100644
index 000000000..1f0c77d56
--- /dev/null
+++ b/private/oleutest/ole1/clidemo/stream.c
@@ -0,0 +1,348 @@
+/*
+ * stream.c - io stream function callbacks
+ *
+ * Created by Microsoft Corporation.
+ * (c) Copyright Microsoft Corp. 1990 - 1992 All Rights Reserved
+ */
+
+/***************************************************************************
+ * This file contains all routines that directly and indirectly deal with
+ * file i/o. The OLE stream call back functions exist in this file.
+ **************************************************************************/
+
+//*** INCLUDES ***
+
+#include <windows.h>
+#include <ole.h>
+
+#include "global.h"
+#include "utility.h"
+#include "stream.h"
+#include "object.h"
+#include "demorc.h"
+
+//*** Globals ***
+
+BOOL fLoadFile = FALSE;
+
+/***************************************************************************
+ * ReadStream() - OLE Callback Function (Get)
+ *
+ * This function is pointed to from the OLESTREAM vtbl; it is Get.
+ *
+ * returns DWORD - number of bytes actually read
+ **************************************************************************/
+
+DWORD APIENTRY ReadStream( //* ENTRY:
+ LPAPPSTREAM lpStream, //* application stream pointer
+ LPSTR lpstr, //* string pointer
+ DWORD cb //* byte count
+){
+
+ return _lread(lpStream->fh, lpstr, cb);
+
+}
+
+/***************************************************************************
+ * WriteStream() - OLE Callback function (Put)
+ *
+ * This function is pointed to from the OLESTREAM vtbl; it is Put.
+ *
+ * Returns DWORD - number of bytes actually written
+ **************************************************************************/
+
+DWORD APIENTRY WriteStream( //* ENTRY:
+ LPAPPSTREAM lpStream, //* application stream pointer
+ LPSTR lpstr, //* string pointer
+ DWORD cb //* number of bytes to write
+){
+
+ return _lwrite(lpStream->fh, lpstr, cb);
+
+}
+
+/****************************************************************************
+ * ReadFromFile()
+ *
+ * This function reads OLE objects from a file. If the document
+ * contains manual links, the user will be prompted to update those links.
+ *
+ * Returns BOOL - TRUE if the read(s) were successful
+ ***************************************************************************/
+
+BOOL FAR ReadFromFile( //* ENTRY:
+ LPAPPSTREAM lpStream, //* application stream pointer
+ LHCLIENTDOC lhcDoc, //* document handle
+ LPOLECLIENT lpClient //* pointer to OLE client structure
+){ //* LOCAL:
+ BOOL bReturn = FALSE; //* return value
+ INT cFileObjects; //* number of file objects
+
+ Hourglass(TRUE);
+ fLoadFile = TRUE;
+
+ SetFilePointer((HANDLE)lpStream->fh, 0, NULL, 0);
+ //* in the file
+ if (_lread(lpStream->fh, (LPSTR)&cFileObjects, sizeof(INT)) < sizeof(INT))
+ goto Error;
+
+ for (; cFileObjects; --cFileObjects)
+ {
+ if (!ObjRead(lpStream,lhcDoc,lpClient))
+ {
+ ErrorMessage(E_FAILED_TO_READ_OBJECT);
+ goto Error;
+ }
+ }
+
+ ShowDoc(lhcDoc,1);
+ UpdateLinks(lhcDoc);
+
+ bReturn = TRUE; //* SUCCESS
+
+Error: //* ERROR Tag
+
+ Hourglass(FALSE);
+ fLoadFile = FALSE;
+ return bReturn; //* return
+
+}
+
+/****************************************************************************
+ * ObjRead()
+ *
+ * Rread an object from the specified file. The file pointer will
+ * be advanced past the object.
+ *
+ * HANDLE fh - DOS file handle of file to be read from
+ *
+ * returns HWND - window handle to item window containing the OLE object
+ ***************************************************************************/
+
+BOOL FAR ObjRead( //* ENTRY:
+ LPAPPSTREAM lpStream, //* application stream pointer
+ LHCLIENTDOC lhcDoc, //* document handle
+ LPOLECLIENT lpClient //* pointer to OLE client structure
+){ //* LOCAL:
+ APPITEMPTR pItem; //* application item pointer
+ LPOLEOBJECT lpObject; //* pointer ole object
+ LONG otObject; //* type of object
+ RECT rcObject; //* object rect
+ CHAR szTmp[CBOBJNAMEMAX]; //* temporary string buffer
+ CHAR szProto[PROTOCOL_STRLEN+1];//* protocol string
+ INT i; //* index
+
+ if (_lread(lpStream->fh, szTmp, CBOBJNAMEMAX) < CBOBJNAMEMAX )
+ return FALSE;
+
+ if (_lread(lpStream->fh, szProto, PROTOCOL_STRLEN) < PROTOCOL_STRLEN )
+ return FALSE;
+
+ for (i=0; szProto[i] != ' '; i++);
+ szProto[i] = 0;
+
+ ValidateName( szTmp );
+
+ if (!(pItem = PreItemCreate(lpClient, TRUE, lhcDoc)))
+ return FALSE;
+
+ if (Error(OleLoadFromStream((LPOLESTREAM)&(lpStream->olestream),
+ szProto,(LPOLECLIENT)&(pItem->oleclient), lhcDoc, szTmp, &lpObject)))
+ goto Error;
+
+ if (_lread(lpStream->fh, (LPSTR)&rcObject, sizeof(RECT)) < sizeof(RECT))
+ goto Error;
+
+ if (_lread(lpStream->fh, (LPSTR)&otObject, sizeof(LONG)) < sizeof(LONG))
+ goto Error;
+
+ if (PostItemCreate(lpObject, otObject, &rcObject, pItem))
+ {
+ pItem->fNew = TRUE;
+ ObjSetBounds(pItem);
+ return TRUE; //* SUCCESS return
+ }
+ else
+ return FALSE;
+
+Error: //* ERROR Tag
+
+ FreeAppItem(pItem);
+ return FALSE;
+
+}
+
+/*************************************************************************
+ * WriteToFile()
+ *
+ * Write current document to a file.
+ *
+ * returns BOOL - TRUE if file successfully written
+ ************************************************************************/
+
+BOOL FAR WriteToFile( //* ENTRY:
+ LPAPPSTREAM lpStream //* application stream pointer
+){ //* LOCAL:
+ INT iObjectsWritten=0; //* counter of objects written to file
+ APPITEMPTR pItem; //* application Item pointer
+
+ UpdateFromOpenServers();
+
+ SetFilePointer((HANDLE)lpStream->fh, 0, NULL, 0);
+
+ Hourglass(TRUE);
+
+ if (_lwrite(lpStream->fh, (LPSTR)&iObjects, sizeof(INT)) < sizeof(INT))
+ goto Error;
+
+ for (pItem = GetTopItem(); pItem; pItem = GetNextItem(pItem))
+ {
+ if (!ObjWrite(lpStream, pItem))
+ goto Error;
+ iObjectsWritten++;
+ }
+
+ if (iObjectsWritten != iObjects)
+ goto Error;
+
+
+ Dirty(DOC_CLEAN);
+ Hourglass(FALSE);
+ return(TRUE); //* SUCCESS return
+
+Error: //* ERROR Tag
+
+ Hourglass(FALSE);
+ return(FALSE); //* ERROR return
+
+}
+
+/****************************************************************************
+ * ObjWrite()
+ *
+ * This function writes an object to the specified
+ * file. The file pointer will be advanced past the end of
+ * the written object.
+
+ * Returns BOOL - TRUE if object written successfully
+ ***************************************************************************/
+
+BOOL FAR ObjWrite( //* ENTRY:
+ LPAPPSTREAM lpStream, //* application stream pointer
+ APPITEMPTR pItem //* application item pointer
+){ //* LOCAL:
+ POINT pt; //* center of rec point
+ RECT rc; //* bounding rectangle
+ UINT cbTmp = CBOBJNAMEMAX;
+ CHAR szTmp[PROTOCOL_STRLEN];//* protocol string
+
+ OleQueryName(pItem->lpObject, szTmp, &cbTmp);
+
+ if (_lwrite(lpStream->fh, szTmp, CBOBJNAMEMAX) < CBOBJNAMEMAX )
+ return FALSE;
+
+ if (pItem->otObject == OT_STATIC)
+ wsprintf(szTmp, "%-15s", STATICP);
+ else
+ wsprintf(szTmp, "%-15s", STDFILEEDITING);
+
+ if (_lwrite(lpStream->fh, szTmp, PROTOCOL_STRLEN) < PROTOCOL_STRLEN )
+ return FALSE;
+
+ if (Error(OleSaveToStream(pItem->lpObject, (LPOLESTREAM)&(lpStream->olestream))))
+ return FALSE;
+
+ GetClientRect(pItem->hwnd, (LPRECT)&rc);
+ pt = *(LPPOINT)&rc;
+ ClientToScreen(pItem->hwnd, (LPPOINT)&pt);
+ ScreenToClient(hwndFrame, (LPPOINT)&pt);
+ OffsetRect(
+ &rc,
+ pt.x - rc.left - GetSystemMetrics(SM_CXFRAME),
+ pt.y - rc.top - GetSystemMetrics(SM_CYFRAME)
+ );
+
+ if (_lwrite(lpStream->fh, (LPSTR)&rc, sizeof(RECT)) < sizeof(RECT)
+ || _lwrite(lpStream->fh, (LPSTR)&(pItem->otObject), sizeof(LONG)) < sizeof(LONG))
+ return FALSE;
+
+ return TRUE; //* SUCCESS return
+
+}
+
+/****************************************************************************
+ * UpdateLinks()
+ *
+ * Get the most up to date rendering information and show it.
+ ***************************************************************************/
+
+static VOID UpdateLinks( //* ENTRY
+ LHCLIENTDOC lhcDoc //* client document handle
+){ //* LOCAL:
+ INT i=0; //* index
+ APPITEMPTR pItem; //* temporary item pointer
+ CHAR szUpdate[CBMESSAGEMAX];//* update message?
+
+ for (pItem = GetTopItem(); pItem; pItem = GetNextItem(pItem))
+ {
+ if (pItem->lhcDoc == lhcDoc && pItem->otObject == OT_LINK)
+ {
+ if (!i)
+ {
+ LoadString(hInst, IDS_UPDATELINKS, szUpdate, CBMESSAGEMAX);
+ if (MessageBox(hwndFrame, szUpdate, szAppName,
+ MB_YESNO | MB_ICONEXCLAMATION) != IDYES)
+ break;
+ i++;
+ }
+ Error(OleUpdate(pItem->lpObject));
+ }
+ }
+
+ WaitForAllObjects();
+
+}
+
+/****************************************************************************
+ * UpdateFromOpenServers()
+ *
+ * Get the most up to date rendering information before storing it.
+ ***************************************************************************/
+
+static VOID UpdateFromOpenServers(VOID)
+{ //* LOCAL:
+ APPITEMPTR pItem; //* temporary item pointer
+ APPITEMPTR pItemNext;
+
+ for (pItem = GetTopItem(); pItem; pItem = pItemNext)
+ {
+ pItemNext = GetNextItem(pItem);
+ if (pItem->otObject == OT_EMBEDDED ||
+ (pItem->uoObject == oleupdate_oncall
+ && pItem->otObject == OT_LINK ))
+
+ if (OleQueryOpen(pItem->lpObject) == OLE_OK)
+ {
+ CHAR szMessage[2*CBMESSAGEMAX];
+ CHAR szBuffer[CBMESSAGEMAX];
+ UINT cb = CBOBJNAMEMAX; //* The name will be the server window title.
+ CHAR szTmp[CBOBJNAMEMAX]; //* when the object is edited.
+
+ Error(OleQueryName(pItem->lpObject,szTmp,&cb));
+ LoadString(hInst, IDS_UPDATE_OBJ, szBuffer, CBMESSAGEMAX);
+ wsprintf(szMessage, szBuffer, (LPSTR)szTmp);
+
+ if (MessageBox(hwndFrame, szMessage, szAppName, MB_YESNO | MB_ICONEXCLAMATION) == IDYES)
+ {
+ Error(OleUpdate(pItem->lpObject));
+ WaitForObject(pItem);
+ }
+ if (!pItem->fVisible)
+ ObjDelete(pItem, OLE_OBJ_DELETE);
+ }
+
+ }
+
+ WaitForAllObjects();
+
+}
diff --git a/private/oleutest/ole1/clidemo/stream.h b/private/oleutest/ole1/clidemo/stream.h
new file mode 100644
index 000000000..f28efcfc2
--- /dev/null
+++ b/private/oleutest/ole1/clidemo/stream.h
@@ -0,0 +1,35 @@
+/*
+ * stream.h - OLE stream I/O headers.
+ *
+ * Created by Microsoft Corporation.
+ * (c) Copyright Microsoft Corp. 1990 - 1992 All Rights Reserved
+ */
+
+//*** CONSTANTS ***
+
+#define MAXREAD ((LONG) (60L * 1024L))
+
+//*** GLOBALS ***
+
+extern DWORD vcbObject;
+
+//*** PROTOTYPES ***
+
+//* OLE callbacks
+
+DWORD APIENTRY ReadStream(LPAPPSTREAM, LPSTR, DWORD);
+DWORD APIENTRY WriteStream(LPAPPSTREAM, LPSTR, DWORD);
+
+//* Far
+
+BOOL FAR WriteToFile(LPAPPSTREAM);
+BOOL FAR ObjWrite(LPAPPSTREAM, APPITEMPTR);
+BOOL FAR ReadFromFile(LPAPPSTREAM, LHCLIENTDOC, LPOLECLIENT);
+BOOL FAR ObjRead(LPAPPSTREAM, LHCLIENTDOC, LPOLECLIENT);
+
+//* Local
+
+DWORD lread(int, VOID FAR *, DWORD);
+DWORD lwrite(int, VOID FAR *, DWORD);
+static VOID UpdateLinks(LHCLIENTDOC);
+static VOID UpdateFromOpenServers(VOID);
diff --git a/private/oleutest/ole1/clidemo/utility.c b/private/oleutest/ole1/clidemo/utility.c
new file mode 100644
index 000000000..da84c0e25
--- /dev/null
+++ b/private/oleutest/ole1/clidemo/utility.c
@@ -0,0 +1,612 @@
+/*
+ * utility.c - general purpose utility routines
+ *
+ * Created by Microsoft Corporation.
+ * (c) Copyright Microsoft Corp. 1990 - 1992 All Rights Reserved
+ *
+ */
+
+//*** INCLUDES ****
+
+#include <windows.h>
+#include <ole.h>
+
+#include "global.h"
+#include "demorc.h"
+#include "utility.h"
+#include "object.h"
+#include "dialog.h"
+
+static INT iTimerID = 0;
+static APPITEMPTR lpaItemHold;
+
+
+/****************************************************************************
+ * ErrorMessage()
+ *
+ * Display a message box containing the specified string from the table.
+ *
+ * id WORD - Index into string table.
+ ***************************************************************************/
+
+VOID FAR ErrorMessage( //* ENTRY:
+ DWORD id //* message ID
+){ //* LOCAL:
+ CHAR sz[CBMESSAGEMAX]; //* string
+ HWND hwnd; //* parent window handle
+
+ if (IsWindow(hwndProp))
+ hwnd = hwndProp;
+ else if (IsWindow(hwndFrame))
+ hwnd = hwndFrame;
+ else
+ return;
+
+ LoadString(hInst, id, sz, CBMESSAGEMAX);
+ MessageBox(hwnd, sz, szAppName, MB_OK | MB_ICONEXCLAMATION);
+
+}
+
+
+/****************************************************************************
+ * Hourglass()
+ *
+ * Put up or takes down the hourglass cursor as needed.
+ *
+ * int bToggle - TRUE turns the hour glass on
+ * HG_OFF turn it off
+ ***************************************************************************/
+
+VOID FAR Hourglass( //* ENTRY:
+ BOOL bOn //* hourglass on/off
+){ //* LOCAL:
+ static HCURSOR hcurWait = NULL; //* hourglass cursor
+ static HCURSOR hcurSaved; //* old cursor
+ static iCount = 0;
+
+
+ if (bOn)
+ {
+ iCount++;
+ if (!hcurWait)
+ hcurWait = LoadCursor(NULL, IDC_WAIT);
+ if (!hcurSaved)
+ hcurSaved = SetCursor(hcurWait);
+ }
+ else if (!bOn)
+ {
+ if (--iCount < 0 )
+ iCount = 0;
+ else if (!iCount)
+ {
+ SetCursor(hcurSaved);
+ hcurSaved = NULL;
+ }
+ }
+
+}
+
+/***************************************************************************
+ * WaitForObject()
+ *
+ * Dispatch messagee until the specified object is not busy.
+ * This allows asynchronous processing to occur.
+ *
+ * lpObject LPOLEOBJECT - pointer to object
+ **************************************************************************/
+
+void FAR WaitForObject( //* ENTRY:
+ APPITEMPTR paItem //* pointer to OLE object
+){ //* LOCAL
+ BOOL bTimerOn = FALSE;
+
+ while (OleQueryReleaseStatus(paItem->lpObject) == OLE_BUSY)
+ {
+ lpaItemHold = paItem;
+ if (!bTimerOn)
+ bTimerOn = ToggleBlockTimer(TRUE);//* set timer
+ ProcessMessage(hwndFrame, hAccTable);
+ }
+
+ if (bTimerOn)
+ ToggleBlockTimer(FALSE);//* toggle timer off
+}
+
+/***************************************************************************
+ * WaitForAllObjects()
+ *
+ * Wait for all asynchronous operations to complete.
+ **************************************************************************/
+
+VOID FAR WaitForAllObjects(VOID)
+{
+ BOOL bTimerOn = FALSE;
+
+ while (cOleWait)
+ {
+ if (!bTimerOn)
+ bTimerOn = ToggleBlockTimer(TRUE);//* set timer
+
+ ProcessMessage(hwndFrame, hAccTable) ;
+ }
+
+ if (bTimerOn)
+ ToggleBlockTimer(FALSE);//* toggle timer off
+
+}
+
+/****************************************************************************
+ * ProcessMessage()
+ *
+ * Obtain and dispatch a message. Used when in a message dispatch loop.
+ *
+ * Returns BOOL - TRUE if message other than WM_QUIT retrieved
+ * FALSE if WM_QUIT retrieved.
+ ***************************************************************************/
+
+BOOL FAR ProcessMessage( //* ENTRY:
+ HWND hwndFrame, //* main window handle
+ HANDLE hAccTable //* accelerator table handle
+){ //* LOCAL:
+ BOOL fReturn; //* return value
+ MSG msg; //* message
+
+ if (fReturn = GetMessage(&msg, NULL, 0, 0))
+ {
+ if (cOleWait || !TranslateAccelerator(hwndFrame, hAccTable, &msg))
+ {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ }
+ return fReturn;
+
+}
+
+
+/****************************************************************************
+ * Dirty()
+ *
+ * Keep track of weather modifications have been made
+ * to the document or not.
+ *
+ * iAction - action type:
+ * DOC_CLEAN set document clean flag true
+ * DOC_DIRTY the opposite
+ * DOC_UNDIRTY undo one dirty op
+ * DOC_QUERY return present state
+ *
+ * Returs int - present value of fDirty; 0 is clean.
+ ***************************************************************************/
+
+INT FAR Dirty( //* ENTRY:
+ INT iAction //* see above comment
+){ //* LOCAL:
+ static INT iDirty = 0; //* dirty state >0 is dirty
+
+ switch (iAction)
+ {
+ case DOC_CLEAN:
+ iDirty = 0;
+ break;
+ case DOC_DIRTY:
+ iDirty++;
+ break;
+ case DOC_UNDIRTY:
+ iDirty--;
+ break;
+ case DOC_QUERY:
+ break;
+ }
+ return(iDirty);
+
+}
+
+/***************************************************************************
+ * ObjectsBusy()
+ *
+ * This function enumerates the OLE objects in the current document
+ * and displays a message box stating whether an object is busy.
+ * This function calls the DisplayBusyMessage() function which
+ * performs most of the work. This function is only used by the macro
+ * BUSY_CHECK(), defined in object.h.
+ *
+ * fSelectionOnly BOOL -NOT USED?
+ *
+ * BOOL - TRUE if one or more objects found to be busy
+ * FALSE otherwise
+ *
+ ***************************************************************************/
+
+BOOL FAR ObjectsBusy ()
+{
+ APPITEMPTR pItem;
+
+ if (iTimerID)
+ {
+ RetryMessage(NULL,RD_CANCEL);
+ return TRUE;
+ }
+
+ for (pItem = GetTopItem(); pItem; pItem = GetNextItem(pItem))
+ if (DisplayBusyMessage(pItem))
+ return TRUE;
+
+ return FALSE;
+
+}
+
+/***************************************************************************
+ * DisplayBusyMessage()
+ *
+ * This function determines if an object is busy and displays
+ * a message box stating this status.
+ *
+ * Returns BOOL - TRUE if object is busy
+ **************************************************************************/
+
+BOOL FAR DisplayBusyMessage ( //* ENTRY:
+ APPITEMPTR paItem //* application item pointer
+){ //* LOCAL:
+
+ if (OleQueryReleaseStatus(paItem->lpObject) == OLE_BUSY)
+ {
+ RetryMessage(paItem,RD_CANCEL);
+ return TRUE;
+ }
+ return FALSE;
+
+}
+
+/***************************************************************************
+ * CreateNewUniqueName()
+ *
+ * Create a string name unique to this document. This is done by using the
+ * prefix string("OleDemo #") and appending a counter to the end of the
+ * prefix string. The counter is incremented whenever a new object is added.
+ * String will be 14 bytes long.
+ *
+ * Return LPSTR - pointer to unique object name.
+ ***************************************************************************/
+
+LPSTR FAR CreateNewUniqueName( //* ENTRY:
+ LPSTR lpstr //* destination pointer
+){
+
+ wsprintf( lpstr, "%s%04d", OBJPREFIX, iObjectNumber++ );
+ return( lpstr );
+
+}
+
+/***************************************************************************
+ * ValidateName()
+ *
+ * This function ensures that the given object name is valid and unique.
+ *
+ * Returns: BOOL - TRUE if object name valid
+ **************************************************************************/
+
+BOOL FAR ValidateName( //* ENTRY:
+ LPSTR lpstr //* pointer to object name
+){ //* LOCAL:
+ LPSTR lp; //* worker string
+ INT n;
+ //* check for "OleDemo #" prefix
+ lp = OBJPREFIX;
+
+ while( *lp )
+ {
+ if( *lpstr != *lp )
+ return( FALSE );
+
+ lpstr++; lp++;
+ }
+ //* convert string number to int
+ for (n = 0 ; *lpstr ; n = n*10 + (*lpstr - '0'),lpstr++);
+
+ if( n > 9999 ) //* 9999 is largest legal number
+ return FALSE;
+
+ if( iObjectNumber <= n) //* Make count > than any current
+ iObjectNumber = n + 1; //* object to ensure uniqueness
+
+ return TRUE;
+}
+
+/***************************************************************************
+ * FreeAppItem()
+ *
+ * Free application item structure and destroy the associated structure.
+ **************************************************************************/
+
+VOID FAR FreeAppItem( //* ENTRY:
+ APPITEMPTR pItem //* pointer to application item
+){ //* LOCAL:
+ HANDLE hWork; //* handle used to free
+
+ if (pItem)
+ { //* destroy the window
+ if (pItem->hwnd)
+ DestroyWindow(pItem->hwnd);
+
+ hWork = LocalHandle((LPSTR)pItem);//* get handle from pointer
+
+ if (pItem->aLinkName)
+ DeleteAtom(pItem->aLinkName);
+
+ if (pItem->aServer)
+ DeleteAtom(pItem->aServer);
+
+ LocalUnlock(hWork);
+ LocalFree(hWork);
+ }
+
+}
+
+/***************************************************************************
+ * SizeOfLinkData()
+ *
+ * Find the size of a linkdata string.
+ **************************************************************************/
+
+LONG FAR SizeOfLinkData( //* ENTRY:
+ LPSTR lpData //* pointer to link data
+){ //* LOCAL:
+ LONG lSize; //* total size
+
+ lSize = (LONG)lstrlen(lpData)+1; //* get size of classname
+ lSize += (LONG)lstrlen(lpData+lSize)+1; //* get size of doc.
+ lSize += (LONG)lstrlen(lpData+lSize)+2;//* get size of item
+ return lSize;
+
+}
+
+/****************************************************************************
+ * ShowDoc()
+ *
+ * Display all the child windows associated with a document, or make all the
+ * child windows hidden.
+ ***************************************************************************/
+
+VOID FAR ShowDoc( //* ENTRY:
+ LHCLIENTDOC lhcDoc, //* document handle
+ INT iShow //* show/hide
+){ //* LOCAL:
+ APPITEMPTR pItem; //* application item pointer
+ APPITEMPTR pItemTop = NULL;
+
+ for (pItem = GetTopItem(); pItem; pItem = GetNextItem(pItem))
+ {
+ if (pItem->lhcDoc == lhcDoc)
+ {
+ if (!pItemTop)
+ pItemTop = pItem;
+ ShowWindow(pItem->hwnd,(iShow ? SW_SHOW : SW_HIDE));
+ pItem->fVisible = (BOOL)iShow;
+ }
+ }
+
+ if (pItemTop)
+ SetTopItem(pItemTop);
+
+}
+
+/****************************************************************************
+ * GetNextActiveItem()
+ *
+ * Returns HWND - the next visible window.
+ ***************************************************************************/
+
+APPITEMPTR FAR GetNextActiveItem()
+{ //* LOCAL:
+ APPITEMPTR pItem; //* application item pointer
+
+ for (pItem = GetTopItem(); pItem; pItem = GetNextItem(pItem))
+ if (pItem->fVisible)
+ break;
+
+ return pItem;
+
+}
+
+/****************************************************************************
+ * GetTopItem()
+ ***************************************************************************/
+
+APPITEMPTR FAR GetTopItem()
+{
+ HWND hwnd;
+
+ if (hwnd = GetTopWindow(hwndFrame))
+ return ((APPITEMPTR)GetWindowLong(hwnd,0));
+ else
+ return NULL;
+
+}
+/****************************************************************************
+ * GetNextItem()
+ ***************************************************************************/
+
+APPITEMPTR FAR GetNextItem( //* ENTRY:
+ APPITEMPTR pItem //* application item pointer
+){ //* LOCAL:
+ HWND hwnd; //* next item window handle
+
+ if (hwnd = GetNextWindow(pItem->hwnd, GW_HWNDNEXT))
+ return((APPITEMPTR)GetWindowLong(hwnd,0));
+ else
+ return NULL;
+
+}
+
+/****************************************************************************
+ * SetTopItem()
+ ***************************************************************************/
+
+VOID FAR SetTopItem(
+ APPITEMPTR pItem
+){
+ APPITEMPTR pLastItem;
+
+ pLastItem = GetTopItem();
+ if (pLastItem && pLastItem != pItem)
+ SendMessage(pLastItem->hwnd,WM_NCACTIVATE, 0, 0L);
+
+ if (!pItem)
+ return;
+
+ if (pItem->fVisible)
+ {
+ BringWindowToTop(pItem->hwnd);
+ SendMessage(pItem->hwnd,WM_NCACTIVATE, 1, 0L);
+ }
+
+}
+
+/***************************************************************************
+ * ReallocLinkData()
+ *
+ * Reallocate link data in order to avoid creating lots and lots of global
+ * memory thunks.
+ **************************************************************************/
+
+BOOL FAR ReallocLinkData( //* ENTRY:
+ APPITEMPTR pItem, //* application item pointer
+ LONG lSize //* new link data size
+){ //* LOCAL:
+ HANDLE handle; //* temporary memory handle
+
+ handle = GlobalHandle(pItem->lpLinkData);
+ GlobalUnlock(handle);
+
+ if (!(pItem->lpLinkData = GlobalLock(GlobalReAlloc(handle, lSize, 0))))
+ {
+ ErrorMessage(E_FAILED_TO_ALLOC);
+ return FALSE;
+ }
+
+ return TRUE;
+
+}
+
+/***************************************************************************
+ * AllocLinkData()
+ *
+ * Allocate link data space.
+ **************************************************************************/
+
+BOOL FAR AllocLinkData( //* ENTRY:
+ APPITEMPTR pItem, //* application item pointer
+ LONG lSize //* link data size
+){
+
+ if (!(pItem->lpLinkData = GlobalLock(
+ GlobalAlloc(GMEM_DDESHARE | GMEM_ZEROINIT ,lSize)
+ )))
+ {
+ ErrorMessage(E_FAILED_TO_ALLOC);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/***************************************************************************
+ * FreeLinkData()
+ *
+ * Free the space associated with a linkdata pointer.
+ **************************************************************************/
+
+VOID FAR FreeLinkData( //* ENTRY:
+ LPSTR lpLinkData //* pointer to linkdata
+){ //* LOCAL:
+ HANDLE handle; //* temporary memory handle
+
+ if (lpLinkData)
+ {
+ handle = GlobalHandle(lpLinkData);
+ GlobalUnlock(handle);
+ GlobalFree(handle);
+ }
+}
+
+/****************************************************************************
+ * ShowNewWindow()
+ *
+ * Show a new application item window.
+ ***************************************************************************/
+
+VOID FAR ShowNewWindow( //* ENTRY:
+ APPITEMPTR pItem
+){
+
+ if (pItem->fVisible)
+ {
+ pItem->fNew = TRUE;
+ SetTopItem(pItem);
+ ShowWindow(pItem->hwnd,SW_SHOW);
+ }
+ else
+ ObjDelete(pItem,OLE_OBJ_DELETE);
+
+}
+
+/****************************************************************************
+ * UnqualifyPath()
+ *
+ * return pointer to unqualified path name.
+ ***************************************************************************/
+
+PSTR FAR UnqualifyPath(PSTR pPath)
+{
+ PSTR pReturn;
+
+ for (pReturn = pPath; *pPath; pPath++)
+ if (*pPath == ':' || *pPath == '\\')
+ pReturn = pPath+1;
+
+ return pReturn;
+
+}
+
+/****************************************************************************
+ * ToggleBlockTimer()
+ *
+ * Toggle a timer used to check for blocked servers.
+ ***************************************************************************/
+
+BOOL FAR ToggleBlockTimer(BOOL bSet)
+{
+ if (bSet && !iTimerID)
+ {
+ if (iTimerID = SetTimer(hwndFrame,1, 3000, (TIMERPROC) fnTimerBlockProc))
+ return TRUE;
+ }
+ else if (iTimerID)
+ {
+ KillTimer(hwndFrame,1);
+ iTimerID = 0;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/****************************************************************************
+ * fnTimerBlockProc()
+ *
+ * Timer callback procedure
+ ***************************************************************************/
+
+VOID CALLBACK fnTimerBlockProc( //* ENTRY:
+ HWND hWnd,
+ UINT wMsg,
+ UINT iTimerID,
+ DWORD dwTime
+){
+
+ if (!hRetry)
+ RetryMessage(lpaItemHold, RD_RETRY | RD_CANCEL);
+
+}
+
diff --git a/private/oleutest/ole1/clidemo/utility.h b/private/oleutest/ole1/clidemo/utility.h
new file mode 100644
index 000000000..42a8113d9
--- /dev/null
+++ b/private/oleutest/ole1/clidemo/utility.h
@@ -0,0 +1,34 @@
+/*
+ * utility.h
+ *
+ * Created by Microsoft Corporation.
+ * (c) Copyright Microsoft Corp. 1990 - 1992 All Rights Reserved
+ */
+
+//*** PROTO TYPES ***
+
+//* FAR
+BOOL FAR ObjectsBusy(VOID);
+VOID FAR WaitForAllObjects(VOID);
+VOID FAR WaitForObject(APPITEMPTR);
+VOID FAR ErrorMessage(DWORD);
+VOID FAR Hourglass(BOOL);
+BOOL FAR DisplayBusyMessage (APPITEMPTR);
+BOOL FAR Dirty(INT);
+LPSTR FAR CreateNewUniqueName(LPSTR);
+BOOL FAR ValidateName(LPSTR);
+BOOL FAR ProcessMessage(HWND, HANDLE);
+VOID FAR FreeAppItem(APPITEMPTR);
+LONG FAR SizeOfLinkData (LPSTR);
+VOID FAR ShowDoc(LHCLIENTDOC, INT);
+APPITEMPTR FAR GetTopItem(VOID);
+VOID FAR SetTopItem(APPITEMPTR);
+APPITEMPTR FAR GetNextActiveItem(VOID);
+APPITEMPTR FAR GetNextItem(APPITEMPTR);
+BOOL FAR ReallocLinkData(APPITEMPTR,LONG);
+BOOL FAR AllocLinkData(APPITEMPTR,LONG);
+VOID FAR FreeLinkData(LPSTR);
+VOID FAR ShowNewWindow(APPITEMPTR);
+PSTR FAR UnqualifyPath(PSTR);
+VOID CALLBACK fnTimerBlockProc(HWND, UINT, UINT, DWORD);
+BOOL FAR ToggleBlockTimer(BOOL);
diff --git a/private/oleutest/ole1/dirs b/private/oleutest/ole1/dirs
new file mode 100644
index 000000000..63c0844fa
--- /dev/null
+++ b/private/oleutest/ole1/dirs
@@ -0,0 +1,38 @@
+!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) 22-Jan-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= \
+ clidemo \
+ srvrdemo
+
+#
+# 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=
+
diff --git a/private/oleutest/ole1/srvrdemo/daytona/makefile b/private/oleutest/ole1/srvrdemo/daytona/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/oleutest/ole1/srvrdemo/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/ole1/srvrdemo/daytona/sources b/private/oleutest/ole1/srvrdemo/daytona/sources
new file mode 100644
index 000000000..0b2f64075
--- /dev/null
+++ b/private/oleutest/ole1/srvrdemo/daytona/sources
@@ -0,0 +1,25 @@
+
+TARGETNAME=srvdemo1
+TARGETPATH=obj
+TARGETTYPE=PROGRAM
+TARGETLIBS=
+
+UMTYPE=windows
+UMENTRY=winmain
+
+INCLUDES=.
+NTDEBUG=ntsd
+C_DEFINES= -DWIN32
+
+SOURCES=..\srvrdemo.c \
+ ..\obj.c \
+ ..\doc.c \
+ ..\file.c \
+ ..\server.c \
+ ..\srvrdemo.rc
+
+UMLIBS=obj\*\srvrdemo.res \
+ $(BASEDIR)\public\sdk\lib\*\advapi32.lib \
+ $(BASEDIR)\public\sdk\lib\*\comdlg32.lib \
+ $(BASEDIR)\public\sdk\lib\*\olesvr32.lib
+
diff --git a/private/oleutest/ole1/srvrdemo/dirs b/private/oleutest/ole1/srvrdemo/dirs
new file mode 100644
index 000000000..606df65eb
--- /dev/null
+++ b/private/oleutest/ole1/srvrdemo/dirs
@@ -0,0 +1,4 @@
+DIRS=
+OPTIONAL_DIRS= \
+ \
+ daytona
diff --git a/private/oleutest/ole1/srvrdemo/doc.c b/private/oleutest/ole1/srvrdemo/doc.c
new file mode 100644
index 000000000..8849d5f69
--- /dev/null
+++ b/private/oleutest/ole1/srvrdemo/doc.c
@@ -0,0 +1,594 @@
+/*
+ OLE SERVER DEMO
+ Doc.c
+
+ This file contains document methods and various document-related support
+ functions.
+
+ (c) Copyright Microsoft Corp. 1990 - 1992 All Rights Reserved
+*/
+
+/*
+ Important Note:
+
+ No method should ever dispatch a DDE message or allow a DDE message to
+ be dispatched.
+ Therefore, no method should ever enter a message dispatch loop.
+ Also, a method should not show a dialog or message box, because the
+ processing of the dialog box messages will allow DDE messages to be
+ dispatched.
+*/
+
+
+
+#define SERVERONLY
+#include <windows.h>
+#include <ole.h>
+
+#include "srvrdemo.h"
+
+/* AssociateClient
+ * ---------------
+ *
+ * Add a client to the list of clients associated with an object.
+ *
+ * This function is necessary only because ServerDemo does not create object
+ * structures as they are requested, but rather has a fixed set of objects.
+ * When DocGetObject is called with a NULL object name, the entire
+ * document is requested, but ServerDemo does not currently support making
+ * the entire document an object, so DocGetObject returns one object.
+ * That object now goes by two names: NULL and its real name. Therefore
+ * we need to keep track of both lpoleclient's that were passed to
+ * DocGetObject. Ideally, DocGetObject should always create a new OBJ
+ * structure containing a pointer (or some reference) to the object's native
+ * data and also containing one lpoleclient.
+ *
+ * LPOLECLIENT lpoleclient - the client to be associated with the object.
+ * LPOBJ lpobj - the object
+ *
+ * RETURNS: TRUE if successful
+ * FALSE if out of memory
+ *
+ * CUSTOMIZATION: Server Demo specific
+ *
+ */
+static BOOL AssociateClient (LPOLECLIENT lpoleclient, LPOBJ lpobj)
+{
+ INT i;
+ for (i=0; i < clpoleclient; i++)
+ {
+ if (lpobj->lpoleclient[i]==lpoleclient)
+ {
+ return TRUE;
+ }
+ if (lpobj->lpoleclient[i]==NULL)
+ {
+ lpobj->lpoleclient[i]=lpoleclient;
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+
+
+/* CreateNewDoc
+ * ------------
+ *
+ * If lhdoc == NULL then we must register the new document by calling
+ * OleRegisterServerDoc, which will return a new handle which will be stored
+ * in docMain.lhdoc.
+ * Also if lhdoc==NULL then this document is being created at the request of
+ * the user, not of the client library.
+ *
+ * LONG lhdoc - Document handle
+ * LPSTR lpszDoc - Title of the new document
+ * DOCTYPE doctype - What type of document is being created
+ *
+ * RETURNS: TRUE if successful, FALSE otherwise.
+ *
+ * CUSTOMIZATION: Re-implement
+ *
+ */
+BOOL CreateNewDoc (LONG lhdoc, LPSTR lpszDoc, DOCTYPE doctype)
+{
+ INT i;
+
+ // Fill in the fields of the document structure.
+
+ docMain.doctype = doctype;
+ docMain.oledoc.lpvtbl= &docvtbl;
+
+ if (lhdoc == 0)
+ {
+ if (OLE_OK != OleRegisterServerDoc
+ (srvrMain.lhsrvr,
+ lpszDoc,
+ (LPOLESERVERDOC) &docMain,
+ (LHSERVERDOC FAR *) &docMain.lhdoc))
+ return FALSE;
+ }
+ else
+ docMain.lhdoc = lhdoc;
+
+ // Reset all the flags because no object numbers have been used.
+ for (i=1; i <= cfObjNums; i++)
+ docMain.rgfObjNums[i] = FALSE;
+
+ fDocChanged = FALSE;
+
+ SetTitle (lpszDoc, doctype == doctypeEmbedded);
+ return TRUE;
+}
+
+
+
+/* DestroyDoc
+ * ----------
+ *
+ * Free all memory that had been allocated for a document.
+ *
+ *
+ * CUSTOMIZATION: Re-implement. Your application will probably use some
+ * other method for enumerating all the objects in a document.
+ * ServerDemo enumerates the child windows, but if each object
+ * does not have its own window, this will not work.
+ *
+ */
+VOID DestroyDoc (VOID)
+{
+ HWND hwnd;
+ HWND hwndNext;
+
+ // Delete all object windows.
+ hwnd = SelectedObjectWindow();
+ while (hwnd)
+ {
+ hwndNext = GetWindow (hwnd, GW_HWNDNEXT);
+ // Each object window frees its own memory upon receiving WM_DESTROY.
+ DestroyWindow (hwnd);
+ hwnd = hwndNext;
+ }
+
+ if (docMain.aName)
+ {
+ GlobalDeleteAtom (docMain.aName);
+ docMain.aName = '\0';
+ }
+
+ if (docMain.hpal)
+ DeleteObject (docMain.hpal);
+}
+
+
+
+/* DocClose DOCUMENT "Close" METHOD
+ * --------
+ *
+ * The library calls this method to unconditionally close the document.
+ *
+ * LPOLESERVERDOC lpoledoc - The server document to close
+ *
+ * RETURNS: Return value from RevokeDoc.
+ *
+ * CUSTOMIZATION: None
+ *
+ */
+OLESTATUS APIENTRY DocClose (LPOLESERVERDOC lpoledoc)
+{
+ return RevokeDoc();
+}
+
+
+
+/* DocExecute DOCUMENT "Execute" METHOD
+ * ----------
+ *
+ * This application does not support the execution of DDE execution commands.
+ *
+ * LPOLESERVERDOC lpoledoc - The server document
+ * HANDLE hCommands - DDE execute commands
+ *
+ * RETURNS: OLE_ERROR_COMMAND
+ *
+ * CUSTOMIZATION: Re-implement if your application supports the execution of
+ * DDE commands.
+ *
+ */
+OLESTATUS APIENTRY DocExecute (LPOLESERVERDOC lpoledoc, HANDLE hCommands)
+{
+ return OLE_ERROR_COMMAND;
+}
+
+
+
+/* DocGetObject DOCUMENT "GetObject" METHOD
+ * ------------
+ *
+ * The library uses this method to get an object's structure for the
+ * client. Memory needs to be allocated and initialized here for this.
+ * A NULL string indicates that the client has an embedded object
+ * which was started from Create, CreateFromTemplate, or Edit, but not Open.
+ *
+ * First see if the object name is NULL. If so, you would ordinarily
+ * return the entire document, but Server Demo returns the selected object.
+ * If the object name is not NULL, then go through the list of objects,
+ * searching for one with that name. Return an error if there is not one.
+ *
+ * LPOLESERVERDOC lpoledoc - The server document
+ * OLE_LPCSTR lpszObjectName - The name of the object to get data for
+ * LPOLEOBJECT FAR *lplpoleobject - The object's data is put here
+ * LPOLECLIENT lpoleclient - The client structure
+ *
+ * RETURNS: OLE_OK
+ * OLE_ERROR_NAME if object not found
+ * OLE_ERROR_MEMORY if no more memory to store lpoleclient
+ *
+ * CUSTOMIZATION: Re-implement.
+ * lpszObjectName == "" indicates that the whole document
+ * should be the object returned.
+ *
+ */
+OLESTATUS APIENTRY DocGetObject
+ (LPOLESERVERDOC lpoledoc, OLE_LPCSTR lpszObjectName,
+ LPOLEOBJECT FAR *lplpoleobject, LPOLECLIENT lpoleclient)
+{
+ HWND hwnd;
+ ATOM aName;
+ LPOBJ lpobj;
+
+
+ if (lpszObjectName == NULL || lpszObjectName[0] == '\0')
+ {
+ // Return a new object or the selected object.
+ hwnd = SelectedObjectWindow();
+ lpobj = hwnd ? HwndToLpobj (hwnd) : CreateNewObj (FALSE);
+ *lplpoleobject = (LPOLEOBJECT) lpobj;
+ // Associate client with object.
+ if (!AssociateClient (lpoleclient, lpobj))
+ return OLE_ERROR_MEMORY;
+ return OLE_OK;
+ }
+
+ if (!(aName = GlobalFindAtom (lpszObjectName)))
+ return OLE_ERROR_NAME;
+
+ hwnd = SelectedObjectWindow();
+
+ // Go through all the child windows and find the window whose name
+ // matches the given object name.
+
+ while (hwnd)
+ {
+ lpobj = HwndToLpobj (hwnd);
+
+ if (aName == lpobj->aName)
+ {
+ // Return the object with the matching name.
+ *lplpoleobject = (LPOLEOBJECT) lpobj;
+ // Associate client with the object.
+ if (!AssociateClient (lpoleclient, lpobj))
+ return OLE_ERROR_MEMORY;
+ return OLE_OK;
+ }
+ hwnd = GetWindow (hwnd, GW_HWNDNEXT);
+ }
+
+ if (((DOCPTR)lpoledoc)->doctype == doctypeEmbedded)
+ {
+ lpobj = CreateNewObj (FALSE);
+ *lplpoleobject = (LPOLEOBJECT) lpobj;
+
+ // Associate client with object.
+ if (!AssociateClient (lpoleclient, lpobj))
+ return OLE_ERROR_MEMORY;
+ return OLE_OK;
+ }
+
+ // Object with name lpszObjName was not found.
+ return OLE_ERROR_NAME;
+}
+
+/* DocRelease DOCUMENT "Release" METHOD
+ * ----------
+ *
+ * The library uses this method to notify the server that a revoked
+ * document has finally finished all conversations, and can be
+ * destroyed.
+ * It sets fWaitingForDocRelease to FALSE so a new document can be created
+ * and the user can continue working.
+ *
+ * LPOLESERVERDOC lpoledoc - The server document
+ *
+ * RETURNS: OLE_OK
+ *
+ * CUSTOMIZATION: None
+ *
+ */
+OLESTATUS APIENTRY DocRelease (LPOLESERVERDOC lpoledoc)
+{
+ fWaitingForDocRelease = FALSE;
+ // Free all memory that has been allocated for the document.
+ DestroyDoc();
+
+ return OLE_OK;
+}
+
+
+
+/* DocSave DOCUMENT "Save" METHOD
+ * -------
+ *
+ * Save document to a file.
+ *
+ * LPOLESERVERDOC lpoledoc - The document to save
+ *
+ * RETURNS: OLE_OK
+ *
+ * CUSTOMIZATION: None
+ *
+ */
+OLESTATUS APIENTRY DocSave (LPOLESERVERDOC lpoledoc)
+{
+ if (docMain.doctype == doctypeFromFile)
+ {
+ // No "File Save As" dialog box will be brought up because the
+ // file name is already known.
+ return SaveDoc() ? OLE_OK : OLE_ERROR_GENERIC;
+ }
+ else
+ return OLE_ERROR_GENERIC;
+}
+
+
+
+/* DocSetDocDimensions DOCUMENT "SetDocDimensions" METHOD
+ * -------------------
+ *
+ * The library calls this method to tell the server the bounds on
+ * the target device for rendering the document.
+ * A call to this method is ignored for linked objects because the size of
+ * a linked document depends only on the source file.
+ *
+ * LPOLESERVERDOC lpoledoc - The server document
+ * CONST LPRECT lprect - The target size in MM_HIMETRIC units
+ *
+ * RETURNS: OLE_OK
+ *
+ * CUSTOMIZATION: Re-implement
+ * How an object is sized is application-specific. (Server Demo
+ * uses MoveWindow.)
+ *
+ */
+OLESTATUS APIENTRY DocSetDocDimensions
+ (LPOLESERVERDOC lpoledoc, OLE_CONST RECT FAR * lprect)
+{
+ if (docMain.doctype == doctypeEmbedded)
+ {
+ RECT rect = *lprect;
+
+ // the units are in HIMETRIC
+ rect.right = rect.right - rect.left;
+ // the following was bottom - top
+ rect.bottom = rect.top - rect.bottom;
+
+ HiMetricToDevice ( (LPPOINT) &rect.right );
+ MoveWindow (SelectedObjectWindow(), 0, 0,
+ rect.right + 2 * GetSystemMetrics(SM_CXFRAME),
+ rect.bottom + 2 * GetSystemMetrics(SM_CYFRAME),
+ TRUE);
+ /* If for some reason your application needs to notify the client that
+ the data has changed because DocSetDocDimensions has been called,
+ then notify the client here.
+ SendDocMsg (OLE_CHANGED);
+ */
+ }
+ return OLE_OK;
+}
+
+
+
+/* DocSetHostNames DOCUMENT "SetHostNames" METHOD
+ * ---------------
+ *
+ * The library uses this method to set the name of the document
+ * window.
+ * All this function does is change the title bar text, although it could
+ * do more if necesary.
+ * This function is only called for embedded objects; linked objects
+ * use their filenames for the title bar text.
+ *
+ * LPOLESERVERDOC lpoledoc - The server document
+ * OLE_LPCSTR lpszClient - The name of the client
+ * OLE_LPCSTR lpszDoc - The client's name for the document
+ *
+ * RETURNS: OLE_OK
+ *
+ * CUSTOMIZATION: None
+ *
+ */
+OLESTATUS APIENTRY DocSetHostNames
+ (LPOLESERVERDOC lpoledoc, OLE_LPCSTR lpszClient, OLE_LPCSTR lpszDoc)
+{
+ SetTitle ((LPSTR)lpszDoc, TRUE);
+ lstrcpy ((LPSTR) szClient, lpszClient);
+ lstrcpy ((LPSTR) szClientDoc, Abbrev((LPSTR)lpszDoc));
+ UpdateFileMenu (IDM_UPDATE);
+ return OLE_OK;
+}
+
+
+
+/* DocSetColorScheme DOCUMENT "SetColorScheme" METHOD
+ * -----------------
+ *
+ * The client calls this method to suggest a color scheme (palette) for
+ * the server to use.
+ * In Server Demo the document's palette is never actually used because each
+ * object has its own palette. See ObjSetColorScheme.
+ *
+ * LPOLESERVERDOC lpoledoc - The server document
+ * CONST LOGPALETTE FAR * lppal - Suggested palette
+ *
+ * RETURNS: OLE_ERROR_PALETTE if CreatePalette fails,
+ * OLE_OK otherwise
+ *
+ *
+ * CUSTOMIZATION: If your application supports color schemes, then this
+ * function is a good example of how to create and store
+ * a palette.
+ */
+OLESTATUS APIENTRY DocSetColorScheme
+ (LPOLESERVERDOC lpoledoc, OLE_CONST LOGPALETTE FAR * lppal)
+{
+ HPALETTE hpal = CreatePalette (lppal);
+
+ if (hpal==NULL)
+ return OLE_ERROR_PALETTE;
+
+ if (docMain.hpal)
+ {
+ // Delete old palette
+ DeleteObject (docMain.hpal);
+ }
+ // Store handle to new palette
+ docMain.hpal = hpal;
+ return OLE_OK;
+}
+
+
+
+/* RevokeDoc
+ * ---------
+ *
+ * Call OleRevokeServerDoc.
+ * If the return value is OLE_WAIT_FOR_BUSY, then set fWaitingForDocRelease
+ * and enter a message-dispatch loop until fWaitingForDocRelease is reset.
+ * As long as fWaitingForDocRelease is set, the user interface will be
+ * disabled so that the user will not be able to manipulate the document.
+ * When the DocRelease method is called, it will reset fWaitingForDocRelease,
+ * allowing RevokeDoc to free the document's memory and return.
+ *
+ * This is essentially a way to make an asynchronous operation synchronous.
+ * We need to wait until the old document is revoked before we can delete
+ * its data and create a new one.
+ *
+ * Note that we cannot call RevokeDoc from a method because it is illegal to
+ * enter a message-dispatch loop within a method.
+ *
+ * RETURNS: The return value of OleRevokeServerDoc.
+ *
+ * CUSTOMIZATION: lhdoc may need to be passed in as a parameter if your
+ * application does not have a global variable corresponding
+ * to docMain.
+ *
+ */
+OLESTATUS RevokeDoc (VOID)
+{
+ OLESTATUS olestatus;
+
+ if ((olestatus = OleRevokeServerDoc(docMain.lhdoc)) > OLE_WAIT_FOR_RELEASE)
+ DestroyDoc();
+
+ docMain.lhdoc = 0; // A NULL handle indicates that the document
+ // has been revoked or is being revoked.
+ return olestatus;
+
+}
+
+
+
+/* SaveChangesOption
+ * -----------------
+ *
+ * Give the user the opportunity to save changes to the current document
+ * before continuing.
+ *
+ * BOOL *pfUpdateLater - Will be set to TRUE if the client does not accept
+ * the update and needs to be updated when the document
+ * is closed. In that case, OLE_CLOSED will be sent.
+ *
+ * RETURNS: IDYES, IDNO, or IDCANCEL
+ *
+ * CUSTOMIZATION: None
+ *
+ */
+INT SaveChangesOption (BOOL *pfUpdateLater)
+{
+ INT nReply;
+ CHAR szBuf[cchFilenameMax];
+
+ *pfUpdateLater = FALSE;
+
+ if (fDocChanged)
+ {
+ CHAR szTmp[cchFilenameMax];
+
+ if (docMain.aName)
+ GlobalGetAtomName (docMain.aName, szTmp, cchFilenameMax);
+ else
+ szTmp[0] = '\0';
+
+ if (docMain.doctype == doctypeEmbedded)
+ wsprintf (szBuf, "The object has been changed.\n\nUpdate %s before closing the object?", Abbrev (szTmp));
+ else
+ lstrcpy (szBuf, (LPSTR) "Save changes?");
+
+ nReply = MessageBox (hwndMain, szBuf, szAppName,
+ MB_ICONEXCLAMATION | MB_YESNOCANCEL);
+
+ switch (nReply)
+ {
+ case IDYES:
+ if (docMain.doctype != doctypeEmbedded)
+ SaveDoc();
+ else
+ switch (OleSavedServerDoc (docMain.lhdoc))
+ {
+ case OLE_ERROR_CANT_UPDATE_CLIENT:
+ *pfUpdateLater = TRUE;
+ break;
+ case OLE_OK:
+ break;
+ default:
+ ErrorBox ("Fatal Error: Cannot update.");
+ }
+ return IDYES;
+ case IDNO:
+ return IDNO;
+ case IDCANCEL:
+ return IDCANCEL;
+ }
+ }
+ return TRUE;
+}
+
+
+
+/* SendDocMsg
+ * ----------
+ *
+ * This function sends messages to all the objects in a document when
+ * the document has changed.
+ *
+ * WORD wMessage - The message to send
+ *
+ * CUSTOMIZATION: The means of enumerating all the objects in a document
+ * is application specific.
+ */
+VOID SendDocMsg (WORD wMessage)
+{
+ HWND hwnd;
+
+ // Get handle to first object window.
+ hwnd = SelectedObjectWindow();
+
+ // Send message to all object windows.
+ while (hwnd)
+ {
+ SendObjMsg (HwndToLpobj(hwnd), wMessage);
+ hwnd = GetWindow (hwnd, GW_HWNDNEXT);
+ }
+}
+
+
diff --git a/private/oleutest/ole1/srvrdemo/file.c b/private/oleutest/ole1/srvrdemo/file.c
new file mode 100644
index 000000000..d1c3ce752
--- /dev/null
+++ b/private/oleutest/ole1/srvrdemo/file.c
@@ -0,0 +1,534 @@
+/*
+ OLE SERVER DEMO
+ File.c
+
+ This file contains file input/output functions for for the OLE server demo.
+
+ (c) Copyright Microsoft Corp. 1990 - 1992 All Rights Reserved
+*/
+
+
+
+#include <windows.h>
+#include <commDlg.h>
+#include <ole.h>
+
+#include "srvrdemo.h"
+
+// File signature stored in the file.
+#define szSignature "ServerDemo"
+#define cchSigLen (10+1)
+
+// Delimiter for fields in the file
+#define chDelim ':'
+
+// Default file extension
+#define szDefExt "sd1"
+
+// File header structure
+typedef struct
+{
+ CHAR szSig [cchSigLen];
+ CHAR chDelim1;
+ VERSION version;
+ CHAR chDelim2;
+ CHAR rgfObjNums [cfObjNums+1];
+} HEADER;
+
+// BOOL GetFileSaveFilename (LPSTR lpszFilename);
+static VOID InitOfn (OPENFILENAME *pofn);
+static BOOL SaveDocIntoFile (PSTR);
+static LPOBJ ReadObj (INT fh);
+
+
+
+/* CreateDocFromFile
+ * -----------------
+ *
+ * Read a document from the specified file.
+ *
+ * LPSTR lpszDoc - Name of the file containing the document
+ * LHSERVERDOC lhdoc - Handle to the document
+ * DOCTYPE doctype - In what state the document is created
+ *
+ * RETURNS: TRUE if successful, FALSE otherwise
+ *
+ * CUSTOMIZATION: Re-implement
+ * This function will need to be completely re-implemented
+ * to support your application's file format.
+ *
+ */
+BOOL CreateDocFromFile (LPSTR lpszDoc, LHSERVERDOC lhdoc, DOCTYPE doctype)
+{
+ INT fh; // File handle
+ HEADER hdr;
+ INT i;
+
+ if ((fh =_lopen(lpszDoc, OF_READ)) == -1)
+ return FALSE;
+
+ // Read header from file.
+ if (_lread(fh, (LPSTR) &hdr, (UINT)sizeof(HEADER)) < sizeof (HEADER))
+ goto Error;
+
+ // Check to see if file is a server demo file.
+ if (lstrcmp(hdr.szSig, szSignature))
+ goto Error;
+
+ if (hdr.chDelim1 != chDelim)
+ goto Error;
+
+ // Check to see if file was saved under the most recent version.
+ // Here is where you would handle reading in old versions.
+ if (hdr.version != version)
+ goto Error;
+
+ if (hdr.chDelim2 != chDelim)
+ goto Error;
+
+ if (!CreateNewDoc (lhdoc, lpszDoc, doctype))
+ goto Error;
+
+ // Get the array indicating which object numbers have been used.
+ for (i=1; i <= cfObjNums; i++)
+ docMain.rgfObjNums[i] = hdr.rgfObjNums[i];
+
+ // Read in object data.
+ for (i=0; ReadObj (fh); i++);
+
+ if (!i)
+ {
+ OLESTATUS olestatus;
+
+ fRevokeSrvrOnSrvrRelease = FALSE;
+
+ if ((olestatus = RevokeDoc()) > OLE_WAIT_FOR_RELEASE)
+ goto Error;
+ else if (olestatus == OLE_WAIT_FOR_RELEASE)
+ Wait (&fWaitingForDocRelease);
+
+ fRevokeSrvrOnSrvrRelease = TRUE;
+ EmbeddingModeOff();
+ goto Error;
+ }
+
+ _lclose(fh);
+
+ fDocChanged = FALSE;
+ return TRUE;
+
+Error:
+ _lclose(fh);
+ return FALSE;
+
+}
+
+
+
+/* OpenDoc
+ * -------
+ *
+ * Prompt the user for which document he wants to open
+ *
+ * RETURNS: TRUE if successful, FALSE otherwise.
+ *
+ * CUSTOMIZATION: None, except your application may or may not call
+ * CreateNewObj to create a default object.
+ *
+ */
+BOOL OpenDoc (VOID)
+{
+ CHAR szDoc[cchFilenameMax];
+ BOOL fUpdateLater;
+ OLESTATUS olestatus;
+
+ if (SaveChangesOption (&fUpdateLater) == IDCANCEL)
+ return FALSE;
+
+ if (!GetFileOpenFilename (szDoc))
+ {
+ if (fUpdateLater)
+ {
+ // The user chose the "Yes, Update" button but the
+ // File Open dialog box failed for some reason
+ // (perhaps the user chose Cancel).
+ // Even though the user chose "Yes, Update", there is no way
+ // to update a client that does not accept updates
+ // except when the document is closed.
+ }
+ return FALSE;
+ }
+
+ if (fUpdateLater)
+ {
+ // The non-standard OLE client did not accept the update when
+ // we requested it, so we are sending the client OLE_CLOSED now that
+ // we are closing the document.
+ SendDocMsg (OLE_CLOSED);
+ }
+
+ fRevokeSrvrOnSrvrRelease = FALSE;
+
+ if ((olestatus = RevokeDoc()) > OLE_WAIT_FOR_RELEASE)
+ return FALSE;
+ else if (olestatus == OLE_WAIT_FOR_RELEASE)
+ Wait (&fWaitingForDocRelease);
+
+ fRevokeSrvrOnSrvrRelease = TRUE;
+ EmbeddingModeOff();
+
+ if (!CreateDocFromFile (szDoc, 0, doctypeFromFile))
+ {
+ MessageBox (hwndMain,
+ "Reading from file failed.\r\nFile may not be in proper file format.",
+ szAppName,
+ MB_ICONEXCLAMATION | MB_OK);
+ // We already revoked the document, so give the user a new one to edit.
+ CreateNewDoc (0, "(Untitled)", doctypeNew);
+ CreateNewObj (FALSE);
+ return FALSE;
+ }
+ fDocChanged = FALSE;
+ return TRUE;
+}
+
+
+
+/* ReadObj
+ * --------
+ *
+ * Read the next object from a file, allocate memory for it, and return
+ * a pointer to it.
+ *
+ * int fh - File handle
+ *
+ * RETURNS: A pointer to the object
+ *
+ * CUSTOMIZATION: Server Demo specific
+ *
+ */
+static LPOBJ ReadObj (INT fh)
+{
+ HANDLE hObj = NULL;
+ LPOBJ lpobj = NULL;
+
+ hObj = LocalAlloc (LMEM_MOVEABLE | LMEM_ZEROINIT, sizeof (OBJ));
+
+ if (hObj == NULL)
+ return NULL;
+
+ lpobj = (LPOBJ) LocalLock (hObj);
+
+ if (lpobj==NULL)
+ {
+ LocalFree (hObj);
+ return NULL;
+ }
+
+ if (_lread(fh, (LPSTR) &lpobj->native, (UINT)sizeof(NATIVE)) < sizeof (NATIVE))
+ {
+ LocalUnlock (hObj);
+ LocalFree (hObj);
+ return NULL;
+ }
+
+ lpobj->hObj = hObj;
+ lpobj->oleobject.lpvtbl = &objvtbl;
+ lpobj->aName = GlobalAddAtom (lpobj->native.szName);
+
+ if (!CreateWindow(
+ "ObjClass",
+ "Obj",
+ WS_THICKFRAME | WS_BORDER | WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE ,
+ lpobj->native.nX,
+ lpobj->native.nY,
+ lpobj->native.nWidth,
+ lpobj->native.nHeight,
+ hwndMain,
+ NULL,
+ hInst,
+ (LPSTR) lpobj ))
+ {
+ LocalUnlock (hObj);
+ LocalFree (hObj);
+ return NULL;
+ }
+
+ return lpobj;
+}
+
+
+
+/* SaveDoc
+ * -------
+ *
+ * Save the document.
+ *
+ * CUSTOMIZATION: None
+ *
+ */
+
+BOOL SaveDoc (VOID)
+{
+ if (docMain.doctype == doctypeNew)
+ return SaveDocAs();
+ else
+ {
+ CHAR szDoc [cchFilenameMax];
+
+ GlobalGetAtomName (docMain.aName, szDoc, cchFilenameMax);
+ return SaveDocIntoFile(szDoc);
+ }
+}
+
+
+
+/* SaveDocAs
+ * ---------
+ *
+ * Prompt the user for a filename, and save the document under that filename.
+ *
+ * RETURNS: TRUE if successful or user chose CANCEL
+ * FALSE if SaveDocIntoFile fails
+ *
+ * CUSTOMIZATION: None
+ *
+ */
+BOOL SaveDocAs (VOID)
+{
+ CHAR szDoc[cchFilenameMax];
+ BOOL fUpdateLater;
+ CHAR szDocOld[cchFilenameMax];
+
+ // If document is embedded, give user a chance to update.
+ // Save old document name in case the save fails.
+ if (!GlobalGetAtomName (docMain.aName, szDocOld, cchFilenameMax))
+ ErrorBox ("Fatal Error: Document name is invalid.");
+
+ if (GetFileSaveFilename (szDoc))
+
+ {
+
+ if (docMain.doctype == doctypeEmbedded)
+ return SaveDocIntoFile(szDoc);
+
+ if (fUpdateLater)
+ {
+ // The non-standard OLE client did not accept the update when
+ // we requested it, so we are sending the client OLE_CLOSED now that
+ // we are closing the document.
+ SendDocMsg (OLE_CLOSED);
+ }
+
+ // Set the window title bar.
+ SetTitle (szDoc, FALSE);
+ OleRenameServerDoc(docMain.lhdoc, szDoc);
+
+ if (SaveDocIntoFile(szDoc))
+ return TRUE;
+ else
+ { // Restore old name
+ SetTitle (szDocOld, FALSE);
+ OleRenameServerDoc(docMain.lhdoc, szDocOld);
+ return FALSE;
+ }
+ }
+ else // user chose Cancel
+ return FALSE;
+ // The user chose the "Yes, Update" button but the
+ // File Open dialog box failed for some reason
+ // (perhaps the user chose Cancel).
+ // Even though the user chose "Yes, Update", there is no way
+ // to update a non-standard OLE client that does not accept updates
+ // except when the document is closed.
+}
+
+
+
+/* SaveDocIntoFile
+ * ---------------
+ *
+ * Save the document into a file whose name is determined from docMain.aName.
+ *
+ * RETURNS: TRUE if successful
+ * FALSE otherwise
+ *
+ * CUSTOMIZATION: Re-implement
+ *
+ */
+static BOOL SaveDocIntoFile (PSTR pDoc)
+{
+ HWND hwnd;
+ INT fh; // File handle
+ LPOBJ lpobj;
+ HEADER hdr;
+ INT i;
+
+ hwnd = GetWindow (hwndMain, GW_CHILD);
+
+ if (!hwnd)
+ {
+ ErrorBox ("Could not save NULL file.");
+ return FALSE;
+ }
+
+ // Get document name.
+ if ((fh =_lcreat(pDoc, 0)) == -1)
+ {
+ ErrorBox ("Could not save file.");
+ return FALSE;
+ }
+
+ // Fill in header.
+ lstrcpy (hdr.szSig, szSignature);
+ hdr.chDelim1 = chDelim;
+ hdr.version = version;
+ hdr.chDelim2 = chDelim;
+ for (i=1; i <= cfObjNums; i++)
+ hdr.rgfObjNums[i] = docMain.rgfObjNums[i];
+
+ // Write header to file.
+ if (_lwrite(fh, (LPSTR) &hdr, (UINT)sizeof(HEADER)) < sizeof(HEADER))
+ goto Error; // Error writing file header
+
+ // Write each object's native data.
+ while (hwnd)
+ {
+ lpobj = (LPOBJ) GetWindowLong (hwnd, ibLpobj);
+ if (_lwrite(fh, (LPSTR)&lpobj->native, (UINT)sizeof (NATIVE))
+ < sizeof(NATIVE))
+ goto Error; // Error writing file header
+
+ hwnd = GetWindow (hwnd, GW_HWNDNEXT);
+ }
+ _lclose(fh);
+
+
+ if (docMain.doctype != doctypeEmbedded)
+ {
+ docMain.doctype = doctypeFromFile;
+ OleSavedServerDoc(docMain.lhdoc);
+ fDocChanged = FALSE;
+ }
+
+ return TRUE;
+
+Error:
+ _lclose(fh);
+ ErrorBox ("Could not save file.");
+ return FALSE;
+
+}
+
+
+
+/* Common Dialog functions */
+
+
+/* InitOfn
+ * -------
+ *
+ * Initialize an OPENFILENAME structure with default values.
+ * OPENFILENAME is defined in CommDlg.h.
+ *
+ *
+ * CUSTOMIZATION: Change lpstrFilter. You may also customize the common
+ * dialog box if you wish. (See the Windows SDK documentation.)
+ *
+ */
+static VOID InitOfn (OPENFILENAME *pofn)
+{
+ // GetOpenFileName or GetSaveFileName will put the 8.3 filename into
+ // szFileTitle[].
+ // SrvrDemo does not use this filename, but rather uses the fully qualified
+ // pathname in pofn->lpstrFile[].
+ static CHAR szFileTitle[13];
+
+ pofn->Flags = 0;
+ pofn->hInstance = hInst;
+ pofn->hwndOwner = hwndMain;
+ pofn->lCustData = 0;
+ pofn->lpfnHook = NULL;
+ pofn->lpstrCustomFilter = NULL;
+ pofn->lpstrDefExt = szDefExt;
+ // lpstrFile[] is the initial filespec that appears in the edit control.
+ // Must be set to non-NULL before calling the common dialog box function.
+ // On return, lpstrFile[] will contain the fully-qualified pathname
+ // corresponding to the file the user chose.
+ pofn->lpstrFile = NULL;
+ pofn->lpstrFilter = "Server Demo (*." szDefExt ")\0*." szDefExt "\0" ;
+ // lpstrFileTitle[] will contain the user's chosen filename without a path.
+ pofn->lpstrFileTitle = szFileTitle;
+ pofn->lpstrInitialDir= NULL;
+ // Title Bar. NULL means use default title.
+ pofn->lpstrTitle = NULL;
+ pofn->lpTemplateName = NULL;
+ pofn->lStructSize = sizeof (OPENFILENAME);
+ pofn->nFilterIndex = 1L;
+ pofn->nFileOffset = 0;
+ pofn->nFileExtension = 0;
+ pofn->nMaxFile = cchFilenameMax;
+ pofn->nMaxCustFilter = 0L;
+}
+
+
+
+
+/* GetFileOpenFilename
+ * -------------------
+ *
+ * Call the common dialog box function GetOpenFileName to get a file name
+ * from the user when the user chooses the "File Open" menu item.
+ *
+ * LPSTR lpszFilename - will contain the fully-qualified pathname on exit.
+ *
+ * RETURNS: TRUE if successful, FALSE otherwise.
+ *
+ * CUSTOMIZATION: None
+ *
+ */
+BOOL GetFileOpenFilename (LPSTR lpszFilename)
+{
+ OPENFILENAME ofn;
+ InitOfn (&ofn);
+ ofn.Flags |= OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
+ // Create initial filespec.
+ wsprintf (lpszFilename, "*.%s", (LPSTR) szDefExt);
+ // Have the common dialog function return the filename in lpszFilename.
+ ofn.lpstrFile = lpszFilename;
+ if (!GetOpenFileName (&ofn))
+ return FALSE;
+ return TRUE;
+}
+
+
+
+/* GetFileSaveFilename
+ * -------------------
+ *
+ * Call the common dialog box function GetSaveFileName to get a file name
+ * from the user when the user chooses the "File Save As" menu item, or the
+ * "File Save" menu item for an unnamed document.
+ *
+ * LPSTR lpszFilename - will contain the fully-qualified pathname on exit.
+ *
+ * RETURNS: TRUE if successful, FALSE otherwise.
+ *
+ * CUSTOMIZATION: None
+ *
+ */
+BOOL GetFileSaveFilename (LPSTR lpszFilename)
+{
+ OPENFILENAME ofn;
+ InitOfn (&ofn);
+ ofn.Flags |= OFN_PATHMUSTEXIST | OFN_HIDEREADONLY;
+ // Create initial filespec.
+ wsprintf (lpszFilename, "*.%s", (LPSTR) szDefExt);
+ // Have the common dialog function return the filename in lpszFilename.
+ ofn.lpstrFile = lpszFilename;
+ if (!GetSaveFileName (&ofn))
+ return FALSE;
+ return TRUE;
+}
+
+
diff --git a/private/oleutest/ole1/srvrdemo/obj.c b/private/oleutest/ole1/srvrdemo/obj.c
new file mode 100644
index 000000000..e509c9125
--- /dev/null
+++ b/private/oleutest/ole1/srvrdemo/obj.c
@@ -0,0 +1,1187 @@
+/*
+ OLE SERVER DEMO
+ Obj.c
+
+ This file contains object methods and various object-related support
+ functions.
+
+ (c) Copyright Microsoft Corp. 1990 - 1992 All Rights Reserved
+*/
+
+/*
+ Important Note:
+
+ No method should ever dispatch a DDE message or allow a DDE message to
+ be dispatched.
+ Therefore, no method should ever enter a message dispatch loop.
+ Also, a method should not show a dialog or message box, because the
+ processing of the dialog box messages will allow DDE messages to be
+ dispatched.
+*/
+
+
+#define SERVERONLY
+#include <windows.h>
+#include <ole.h>
+
+#include "srvrdemo.h"
+
+
+
+// Static functions.
+static HBITMAP GetBitmap (LPOBJ lpobj);
+static HANDLE GetLink (LPOBJ lpobj);
+static HANDLE GetMetafilePict (LPOBJ lpobj);
+static HANDLE GetEnhMetafile (LPOBJ lpobj);
+static HANDLE GetNative (LPOBJ lpobj);
+static INT GetObjNum (LPOBJ lpobj);
+static HANDLE GetText (LPOBJ lpobj);
+static VOID DrawObj (HDC hdc, LPOBJ lpobj, RECT rc, INT dctype);
+
+
+
+/* CreateNewObj
+ * ------------
+ *
+ * BOOL fDoc_Changed - The new value for the global variable fDocChanged.
+ * When initializing a new document, we need to create
+ * a new object without the creation counting as a
+ * change to the document.
+ *
+ * RETURNS: A pointer to the new object
+ *
+ *
+ * CUSTOMIZATION: Re-implement
+ * Some applications (like Server Demo) have a finite number of
+ * fixed, distinct, non-overlapping objects. Other applications
+ * allow the user to create an object from any section of the
+ * document. For example, the user might select a portion of
+ * a bitmap from a paint program, or a few lines of text from
+ * a word processor. This latter type of application probably
+ * will not have a function like CreateNewObj.
+ *
+ */
+LPOBJ CreateNewObj (BOOL fDoc_Changed)
+{
+ HANDLE hObj = NULL;
+ LPOBJ lpobj = NULL;
+ // index into an array of flags indicating if that object number is used.
+ INT ifObj = 0;
+
+ if ((hObj = LocalAlloc (LMEM_MOVEABLE|LMEM_ZEROINIT, sizeof (OBJ))) == NULL)
+ return NULL;
+
+ if ((lpobj = (LPOBJ) LocalLock (hObj)) == NULL)
+ {
+ LocalFree (hObj);
+ return NULL;
+ }
+
+ // Fill the fields in the object structure.
+
+ // Find an unused number.
+ for (ifObj=1; ifObj <= cfObjNums; ifObj++)
+ {
+ if (docMain.rgfObjNums[ifObj]==FALSE)
+ {
+ docMain.rgfObjNums[ifObj]=TRUE;
+ break;
+ }
+ }
+
+ if (ifObj==cfObjNums+1)
+ {
+ // Cannot create any more objects.
+ MessageBeep(0);
+ return NULL;
+ }
+
+ wsprintf (lpobj->native.szName, "Object %d", ifObj);
+
+ lpobj->aName = GlobalAddAtom (lpobj->native.szName);
+ lpobj->hObj = hObj;
+ lpobj->oleobject.lpvtbl = &objvtbl;
+ lpobj->native.idmColor = IDM_RED; // Default color
+ lpobj->native.version = version;
+ lpobj->native.nWidth = OBJECT_WIDTH; // Default size
+ lpobj->native.nHeight = OBJECT_HEIGHT;
+ SetHiMetricFields (lpobj);
+
+ // Place object in a location corrsponding to its number, for aesthetics.
+ lpobj->native.nX = (ifObj - 1) * 20;
+ lpobj->native.nY = (ifObj - 1) * 20;
+
+ if (!CreateWindow (
+ "ObjClass",
+ "Obj",
+ WS_BORDER | WS_THICKFRAME | WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE,
+ lpobj->native.nX,
+ lpobj->native.nY,
+ lpobj->native.nWidth,
+ lpobj->native.nHeight,
+ hwndMain,
+ NULL,
+ hInst,
+ (LPSTR) lpobj ))
+ return FALSE;
+
+ fDocChanged = fDoc_Changed;
+
+ return lpobj;
+}
+
+
+
+/* CutOrCopyObj
+ * ------------
+ *
+ * Put data onto clipboard in all the formats supported. If the
+ * fOpIsCopy is TRUE, the operation is COPY, otherwise it is CUT.
+ * This is important, because we cannot put the Object Link format
+ * onto the clipboard if the object was cut from the document (there is
+ * no longer anything to link to).
+ *
+ * BOOL fOpIsCopy - TRUE if the operation is COPY; FALSE if CUT
+ *
+ * CUSTOMIZATION: None
+ *
+ *
+ */
+VOID CutOrCopyObj (BOOL fOpIsCopy)
+{
+ LPOBJ lpobj;
+ HANDLE hData;
+// UINT hBit;
+
+ if (OpenClipboard (hwndMain))
+ {
+ EmptyClipboard ();
+
+ lpobj = SelectedObject();
+
+ if ((hData = GetNative (lpobj)) != NULL)
+ SetClipboardData(cfNative, hData);
+
+ if ((hData = GetLink(lpobj)) != NULL)
+ SetClipboardData(cfOwnerLink, hData);
+
+ if (fOpIsCopy && docMain.doctype == doctypeFromFile)
+ {
+ // Can create a link if object exists in a file.
+ if ((hData = GetLink(lpobj)) != NULL)
+ SetClipboardData(cfObjectLink, hData);
+ }
+
+ if ((hData = GetEnhMetafile(lpobj)) != NULL)
+ {
+ SetClipboardData(CF_ENHMETAFILE, hData);
+ GlobalFree(hData);
+ }
+
+ if ((hData = GetBitmap(lpobj)) != NULL)
+ {
+ // SetClipboardData(CF_BITMAP, GetBitmap(lpobj));
+ SetClipboardData(CF_BITMAP, hData);
+ DeleteObject(hData);
+ }
+
+
+ CloseClipboard ();
+ }
+}
+
+
+/* DestroyObj
+ * ----------
+ *
+ * Revoke an object, and free all memory that had been allocated for it.
+ *
+ * HWND hwnd - The object's window
+ *
+ * CUSTOMIZATION: Re-implement, making sure you free all the memory that
+ * had been allocated for the OBJ structure and each of its
+ * fields.
+ *
+ */
+VOID DestroyObj (HWND hwnd)
+{
+ LPOBJ lpobj = HwndToLpobj (hwnd);
+
+ if(lpobj->aName)
+ {
+ GlobalDeleteAtom (lpobj->aName);
+ lpobj->aName = '\0';
+ }
+
+ if (lpobj->hpal)
+ DeleteObject (lpobj->hpal);
+ // Allow the object's number to be reused.
+ docMain.rgfObjNums [GetObjNum(lpobj)] = FALSE;
+
+
+ // Free the memory that had been allocated for the object structure itself.
+ LocalUnlock (lpobj->hObj);
+ LocalFree (lpobj->hObj);
+}
+
+
+
+/* DrawObj
+ * -------
+ *
+ * This function draws an object onto the screen, into a metafile, or into
+ * a bitmap.
+ * The object will always look the same.
+ *
+ * HDC hdc - The device context to render the object into
+ * LPOBJ lpobj - The object to render
+ * RECT rc - The rectangle bounds of the object
+ * DCTYPE dctype - The type of device context.
+ *
+ * CUSTOMIZATION: Server Demo specific
+ *
+ */
+static VOID DrawObj (HDC hdc, LPOBJ lpobj, RECT rc, INT dctype)
+{
+ HPEN hpen;
+ HPEN hpenOld;
+ HPALETTE hpalOld = NULL;
+
+
+ if (dctype == dctypeMetafile)
+ {
+ SetWindowOrgEx (hdc, 0, 0, NULL);
+ // Paint entire object into the given rectangle.
+ SetWindowExtEx (hdc, rc.right, rc.bottom, NULL);
+ }
+
+ if (lpobj->hpal)
+ {
+ hpalOld = SelectPalette (hdc, lpobj->hpal, TRUE);
+ RealizePalette (hdc);
+ }
+
+ // Select brush of the color specified in the native data.
+ SelectObject (hdc, hbrColor [lpobj->native.idmColor - IDM_RED] );
+
+ hpen = CreatePen (PS_SOLID,
+ /* Width */ (rc.bottom-rc.top) / 10,
+ /* Gray */ 0x00808080);
+ hpenOld = SelectObject (hdc, hpen);
+
+ // Draw rectangle with the gray pen and fill it in with the selected brush.
+ Rectangle(hdc, rc.left, rc.top, rc.right, rc.bottom);
+
+ // Print name of object inside rectangle.
+ SetBkMode (hdc, TRANSPARENT);
+ SetTextAlign (hdc, TA_BASELINE | TA_CENTER);
+ TextOut (hdc,
+ rc.right/2,
+ (rc.top+rc.bottom)/2,
+ lpobj->native.szName,
+ lstrlen (lpobj->native.szName));
+
+ // Restore original objects
+ SelectObject (hdc,
+ (dctype == dctypeMetafile || dctype == dctypeEnhMetafile)
+ ? GetStockObject (BLACK_PEN) : hpenOld);
+ if (hpalOld)
+ {
+ SelectPalette (hdc,
+ (dctype == dctypeMetafile || dctype == dctypeEnhMetafile)
+ ? GetStockObject (DEFAULT_PALETTE) : hpalOld,
+ TRUE);
+ }
+
+ DeleteObject (hpen);
+}
+
+
+
+/* GetBitmap
+ * ---------
+ *
+ * Return a handle to an object's picture data in bitmap format.
+ *
+ * LPOBJ lpobj - The object
+ *
+ * RETURNS: A handle to the object's picture data
+ *
+ * CUSTOMIZATION: Re-implement
+ *
+ */
+static HBITMAP GetBitmap (LPOBJ lpobj)
+{
+ HDC hdcObj;
+ HDC hdcMem;
+ RECT rc;
+ HBITMAP hbitmap;
+ HBITMAP hbitmapOld;
+
+
+ hdcObj = GetDC (lpobj->hwnd);
+ // Create a memory device context.
+ hdcMem = CreateCompatibleDC (hdcObj);
+ GetClientRect (lpobj->hwnd, (LPRECT)&rc);
+ // Create new bitmap object based on the bitmap of the OLE object.
+ hbitmap = CreateCompatibleBitmap
+ (hdcObj, rc.right - rc.left, rc.bottom - rc.top);
+ // Select new bitmap as the bitmap object for the memory device context.
+ hbitmapOld = SelectObject (hdcMem, hbitmap);
+
+ // Paint directly into the memory dc using the new bitmap object.
+ DrawObj (hdcMem, lpobj, rc, dctypeBitmap);
+
+ // Restore old bitmap object.
+ hbitmap = SelectObject (hdcMem, hbitmapOld);
+ DeleteDC (hdcMem);
+ ReleaseDC (lpobj->hwnd, hdcObj);
+
+ // convert width and height to HIMETRIC units
+ rc.right = rc.right - rc.left;
+ rc.bottom = rc.bottom - rc.top;
+ DeviceToHiMetric ( (LPPOINT) &rc.right );
+
+ // Set the 1/10 of HIMETRIC units for the bitmap
+ SetBitmapDimensionEx (hbitmap, (DWORD) (rc.right/10), (DWORD) (rc.bottom/10), NULL);
+
+// if (OpenClipboard (hwndMain))
+// {
+// // EmptyClipboard ();
+// SetClipboardData(CF_BITMAP, hbitmap);
+// CloseClipboard();
+// }
+ return hbitmap;
+}
+
+
+
+/* GetLink
+ * -------
+ *
+ * Return a handle to an object's object or owner link data.
+ * Link information is in the form of three zero-separated strings,
+ * terminated with two zero bytes: CLASSNAME\0DOCNAME\0OBJNAME\0\0
+ *
+ * LPOBJ lpobj - The object
+ *
+ * RETURNS: A handle to the object's link data
+ *
+ * CUSTOMIZATION: Re-implement
+ *
+ */
+static HANDLE GetLink (LPOBJ lpobj)
+{
+
+ CHAR sz[cchFilenameMax];
+ LPSTR lpszLink = NULL;
+ HANDLE hLink = NULL;
+ INT cchLen;
+ INT i;
+
+ // First make the class name.
+ lstrcpy (sz, szClassName);
+ cchLen = lstrlen (sz) + 1;
+
+ // Then the document name.
+ cchLen += GlobalGetAtomName
+ (docMain.aName, (LPSTR)sz + cchLen,
+ cchFilenameMax - cchLen) + 1;
+
+ // Then the object name.
+ lstrcpy (sz + cchLen, lpobj->native.szName);
+ cchLen += lstrlen (lpobj->native.szName) + 1;
+
+ // Add a second null to the end.
+ sz[cchLen++] = 0;
+
+
+ hLink = GlobalAlloc (GMEM_DDESHARE | GMEM_ZEROINIT, cchLen);
+ if (hLink == NULL)
+ return NULL;
+ if ((lpszLink = GlobalLock (hLink)) == NULL)
+ {
+ GlobalFree (hLink);
+ return NULL;
+ }
+
+ for (i=0; i < cchLen; i++)
+ lpszLink[i] = sz[i];
+
+ GlobalUnlock (hLink);
+
+ return hLink;
+}
+
+
+
+/* GetMetafilePict
+ * ---------------
+ *
+ * Return a handle to an object's picture data in metafile format.
+ *
+ * LPOBJ lpobj - The object
+ *
+ * RETURNS: A handle to the object's data in metafile format.
+ *
+ * CUSTOMIZATION: Re-implement
+ *
+ */
+static HANDLE GetMetafilePict (LPOBJ lpobj)
+{
+
+ LPMETAFILEPICT lppict = NULL;
+ HANDLE hpict = NULL;
+ HANDLE hMF = NULL;
+ RECT rc;
+ HDC hdc;
+
+ hdc = CreateMetaFile(NULL);
+
+ GetClientRect (lpobj->hwnd, (LPRECT)&rc);
+
+ // Paint directly into the metafile.
+ DrawObj (hdc, lpobj, rc, dctypeMetafile);
+
+ // Get handle to the metafile.
+ if ((hMF = CloseMetaFile (hdc)) == NULL)
+ return NULL;
+
+ if(!(hpict = GlobalAlloc (GMEM_DDESHARE, sizeof (METAFILEPICT))))
+ {
+ DeleteMetaFile (hMF);
+ return NULL;
+ }
+
+ if ((lppict = (LPMETAFILEPICT)GlobalLock (hpict)) == NULL)
+ {
+ DeleteMetaFile (hMF);
+ GlobalFree (hpict);
+ return NULL;
+ }
+
+ rc.right = rc.right - rc.left;
+ rc.bottom = rc.bottom - rc.top;
+
+ DeviceToHiMetric ( (LPPOINT) &rc.right);
+
+ lppict->mm = MM_ANISOTROPIC;
+ lppict->hMF = hMF;
+ lppict->xExt = rc.right;
+ lppict->yExt = rc.bottom;
+ GlobalUnlock (hpict);
+ return hpict;
+}
+
+/* GetEnhMetafile
+ * ---------------
+ *
+ * Return a handle to an object's picture data in metafile format.
+ *
+ * LPOBJ lpobj - The object
+ *
+ * RETURNS: A handle to the object's data in metafile format.
+ *
+ * CUSTOMIZATION: Re-implement
+ *
+ */
+static HANDLE GetEnhMetafile (LPOBJ lpobj)
+{
+
+ LPMETAFILEPICT lppict = NULL;
+ HANDLE hemf = NULL;
+ HANDLE hMF = NULL;
+ RECT rc;
+ HDC hdc, hdc2;
+
+
+ GetClientRect (lpobj->hwnd, (LPRECT)&rc);
+
+ rc.right -= rc.left;
+ rc.bottom -= rc.top;
+ rc.left = rc.top = 0;
+
+ DeviceToHiMetric ( (LPPOINT) &rc.right );
+
+ hdc = CreateEnhMetaFile ( NULL, NULL, &rc, NULL );
+
+ //* this is necessary because
+ //* we need to draw the object
+ //* in device coordinates that are
+ //* the same physical size as the HIMETRIC
+ //* logical space used in CreateEnhMetaFile.
+ //* In this case we have scaled the HIMETRIC
+ //* units down in order to use the logical
+ //* pixel ratio (which is recommended UI)
+ //* so we therefore have to convert the
+ //* scaled HIMETRIC units back to Device.
+
+ hdc2 = GetDC(NULL);
+
+ SetMapMode(hdc2, MM_HIMETRIC);
+ LPtoDP (hdc2, (LPPOINT)&rc.right, 1);
+ if (rc.bottom < 0) rc.bottom *= -1;
+
+ ReleaseDC(NULL,hdc2);
+
+ DrawObj (hdc, lpobj, rc, dctypeMetafile);
+
+ if ((hemf = (HANDLE)CloseEnhMetaFile (hdc)) == NULL)
+ return NULL;
+
+ return hemf;
+}
+
+
+/* GetNative
+ * ---------
+ *
+ * Return a handle to an object's native data.
+ *
+ * LPOBJ lpobj - The object whose native data is to be retrieved.
+ *
+ * RETURNS: a handle to the object's native data.
+ *
+ * CUSTOMIZATION: The line "*lpnative = lpobj->native;" will change to
+ * whatever code is necessary to copy an object's native data.
+ *
+ */
+static HANDLE GetNative (LPOBJ lpobj)
+{
+ LPNATIVE lpnative = NULL;
+ HANDLE hNative = NULL;
+
+ hNative = GlobalAlloc (GMEM_DDESHARE | GMEM_ZEROINIT, sizeof (NATIVE));
+ if (hNative == NULL)
+ return NULL;
+ if ((lpnative = (LPNATIVE) GlobalLock (hNative)) == NULL)
+ {
+ GlobalFree (hNative);
+ return NULL;
+ }
+
+ // Copy the native data.
+ *lpnative = lpobj->native;
+
+ GlobalUnlock (hNative);
+ return hNative;
+}
+
+
+
+/* GetObjNum
+ * ---------
+ *
+ * LPSTR lpobj - The object whose number is desired
+ *
+ * RETURNS: The number of the object, i.e., the numerical portion of its name.
+ *
+ * CUSTOMIZATION: Server Demo specific
+ */
+static INT GetObjNum (LPOBJ lpobj)
+{
+ LPSTR lpsz;
+ INT n=0;
+
+ lpsz = lpobj->native.szName + 7;
+ while (*lpsz && *lpsz>='0' && *lpsz<='9')
+ n = 10*n + *lpsz++ - '0';
+ return n;
+}
+
+
+
+/* GetText
+ * -------
+ *
+ * Return a handle to an object's data in text form.
+ * This function simply returns the name of the object.
+ *
+ * LPOBJ lpobj - The object
+ *
+ * RETURNS: A handle to the object's text.
+ *
+ * CUSTOMIZATION: Re-implement, if your application supports CF_TEXT as a
+ * presentation format.
+ *
+ */
+static HANDLE GetText (LPOBJ lpobj)
+{
+ HANDLE hText = NULL;
+ LPSTR lpszText = NULL;
+
+ if(!(hText = GlobalAlloc (GMEM_DDESHARE, sizeof (lpobj->native.szName))))
+ return NULL;
+
+ if (!(lpszText = GlobalLock (hText)))
+ return NULL;
+
+ lstrcpy (lpszText, lpobj->native.szName);
+
+ GlobalUnlock (hText);
+
+ return hText;
+}
+
+
+
+/* ObjDoVerb OBJECT "DoVerb" METHOD
+ * ---------
+ *
+ * This method is called by the client, through the library, to either
+ * PLAY, or EDIT the object. PLAY is implemented as a beep, and
+ * EDIT will bring up the server and show the object for editing.
+ *
+ * LPOLEOBJECT lpoleobject - The OLE object
+ * WORD wVerb - The verb acting on the object: PLAY or EDIT
+ * BOOL fShow - Should the object be shown?
+ * BOOL fTakeFocus - Should the object window get the focus?
+ *
+ * RETURNS: OLE_OK
+ *
+ * CUSTOMIZATION: Add any more verbs your application supports.
+ * Implement verbPlay if your application supports it.
+ *
+ */
+OLESTATUS APIENTRY ObjDoVerb
+ (LPOLEOBJECT lpoleobject, UINT wVerb, BOOL fShow, BOOL fTakeFocus)
+{
+ switch (wVerb)
+ {
+ case verbPlay:
+ { // The application can do whatever is appropriate for the object.
+ INT i;
+ for (i=0; i<25;i++) MessageBeep (0);
+ return OLE_OK;
+ }
+
+ case verbEdit:
+ if (fShow)
+ return objvtbl.Show (lpoleobject, fTakeFocus);
+ else
+ return OLE_OK;
+ default:
+ // Unknown verb.
+ return OLE_ERROR_DOVERB;
+ }
+}
+
+
+
+/* ObjEnumFormats OBJECT "EnumFormats" METHOD
+ * ---------------
+ *
+ * This method is used to enumerate all supported clipboard formats.
+ * Terminate by returning NULL.
+ *
+ * LPOLEOBJECT lpoleobject - The OLE object
+ * OLECLIPFORMAT cfFormat - The 'current' clipboard format
+ *
+ * RETURNS: The 'next' clipboard format which is supported.
+ *
+ * CUSTOMIZATION: Verify that the list of formats this function
+ * returns matches the list of formats your application
+ * supports.
+ *
+ */
+OLECLIPFORMAT APIENTRY ObjEnumFormats
+ (LPOLEOBJECT lpoleobject, OLECLIPFORMAT cfFormat)
+{
+ if (cfFormat == 0)
+ return cfNative;
+
+ if (cfFormat == cfNative)
+ return cfOwnerLink;
+
+ if (cfFormat == cfOwnerLink)
+ return CF_ENHMETAFILE;
+
+ if (cfFormat == CF_ENHMETAFILE)
+ return CF_METAFILEPICT;
+
+ if (cfFormat == CF_METAFILEPICT)
+ return CF_BITMAP;
+
+ if (cfFormat == CF_BITMAP)
+ return cfObjectLink;
+
+ if (cfFormat == cfObjectLink)
+ return 0;
+
+ return 0;
+}
+
+
+
+/* ObjGetData OBJECT "GetData" METHOD
+ * -----------
+ *
+ * Return the data requested for the specified object in the specified format.
+ *
+ * LPOLEOBJECT lpoleobject - The OLE object
+ * WORD cfFormat - The data type requested in standard
+ * clipboard format
+ * LPHANDLE lphandle - Pointer to handle to memory where data
+ * will be stored
+ *
+ * RETURNS: OLE_OK if successful
+ * OLE_ERROR_MEMORY if there was an error getting the data.
+ * OLE_ERROR_FORMAT if the requested format is unknown.
+ *
+ *
+ * CUSTOMIZATION: Add any additional formats your application supports, and
+ * remove any formats it does not support.
+ *
+ */
+OLESTATUS APIENTRY ObjGetData
+ (LPOLEOBJECT lpoleobject, OLECLIPFORMAT cfFormat, LPHANDLE lphandle)
+{
+
+ LPOBJ lpobj;
+
+ lpobj = (LPOBJ) lpoleobject;
+
+ if (cfFormat == cfNative)
+ {
+ if (!(*lphandle = GetNative (lpobj)))
+ return OLE_ERROR_MEMORY;
+ // The client has requested the data in native format, therefore
+ // the data in the client and server are in sync.
+ fDocChanged = FALSE;
+ return OLE_OK;
+ }
+
+ if (cfFormat == CF_ENHMETAFILE)
+ {
+ if (!(*lphandle = GetEnhMetafile (lpobj)))
+ return OLE_ERROR_MEMORY;
+ return OLE_OK;
+ }
+
+ if (cfFormat == CF_METAFILEPICT)
+ {
+ if (!(*lphandle = GetMetafilePict (lpobj)))
+ return OLE_ERROR_MEMORY;
+ return OLE_OK;
+ }
+
+ if (cfFormat == CF_BITMAP)
+ {
+ if (!(*lphandle = (HANDLE)GetBitmap (lpobj)))
+ return OLE_ERROR_MEMORY;
+ return OLE_OK;
+ }
+
+ if (cfFormat == CF_TEXT)
+ {
+ if (!(*lphandle = GetText (lpobj)))
+ return OLE_ERROR_MEMORY;
+ return OLE_OK;
+ }
+
+ if (cfFormat == cfObjectLink)
+ {
+ if (!(*lphandle = GetLink (lpobj)))
+ return OLE_ERROR_MEMORY;
+ return OLE_OK;
+ }
+
+ if (cfFormat == cfOwnerLink)
+ {
+ if (!(*lphandle = GetLink (lpobj)))
+ return OLE_ERROR_MEMORY;
+ return OLE_OK;
+ }
+
+ return OLE_ERROR_FORMAT;
+}
+
+
+
+/* ObjQueryProtocol OBJECT "QueryProtocol" METHOD
+ * ----------------
+ *
+ * LPOLEOBJECT lpoleobject - The OLE object
+ * OLE_LPCSTR lpszProtocol - The protocol name, either "StdFileEditing"
+ * or "StdExecute"
+ *
+ * RETURNS: If lpszProtocol is supported, return a pointer to an OLEOBJECT
+ * structure with an appropriate method table for that protocol.
+ * Otherwise, return NULL.
+ *
+ * CUSTOMIZATION: Allow any additional protocols your application supports.
+ *
+ *
+ */
+LPVOID APIENTRY ObjQueryProtocol
+ (LPOLEOBJECT lpoleobject, OLE_LPCSTR lpszProtocol)
+{
+ return lstrcmp (lpszProtocol, "StdFileEditing") ? NULL : lpoleobject ;
+}
+
+
+
+/* ObjRelease OBJECT "Release" METHOD
+ * -----------
+ *
+ * The server application should not destroy data when the library calls the
+ * ReleaseObj method.
+ * The library calls the ReleaseObj method when no clients are connected
+ * to the object.
+ *
+ * LPOLEOBJECT lpoleobject - The OLE object
+ *
+ * RETURNS: OLE_OK
+ *
+ * CUSTOMIZATION: Re-implement. Do whatever needs to be done, if anything,
+ * when no clients are connected to an object.
+ *
+ */
+OLESTATUS APIENTRY ObjRelease (LPOLEOBJECT lpoleobject)
+{
+ INT i;
+ /* No client is connected to the object so break all assocaiations
+ between clients and the object. */
+ for (i=0; i < clpoleclient; i++)
+ ((LPOBJ)lpoleobject)->lpoleclient[i] = NULL;
+ return OLE_OK;
+}
+
+
+
+/* ObjSetBounds OBJECT "SetBounds" METHOD
+ * ------------
+ *
+ * This method is called to set new bounds for an object.
+ * The bounds are in HIMETRIC units.
+ * A call to this method is ignored for linked objects because the size of
+ * a linked object depends only on the source file.
+ *
+ * LPOLEOBJECT lpoleobject - The OLE object
+ * OLE_CONST RECT FAR* lprect - The new bounds
+ *
+ * RETURNS: OLE_OK
+ *
+ * CUSTOMIZATION: Re-implement
+ * How an object is sized is application-specific. (Server Demo
+ * uses MoveWindow.)
+ *
+ */
+OLESTATUS APIENTRY ObjSetBounds (LPOLEOBJECT lpoleobj, OLE_CONST RECT FAR * lprect)
+{
+ if (docMain.doctype == doctypeEmbedded)
+ {
+ RECT rect = *lprect;
+ LPOBJ lpobj = (LPOBJ) lpoleobj;
+
+ // the units are in HIMETRIC
+ rect.right = rect.right - rect.left;
+ rect.bottom = rect.top - rect.bottom;
+ HiMetricToDevice ( (LPPOINT) &rect.right);
+ MoveWindow (lpobj->hwnd, lpobj->native.nX, lpobj->native.nY,
+ rect.right + 2 * GetSystemMetrics(SM_CXFRAME),
+ rect.bottom + 2 * GetSystemMetrics(SM_CYFRAME),
+ TRUE);
+ }
+ return OLE_OK;
+}
+
+
+
+/* ObjSetColorScheme OBJECT "SetColorScheme" METHOD
+ * -----------------
+ *
+ * The client calls this method to suggest a color scheme (palette) for
+ * the server to use for the object.
+ *
+ * LPOLEOBJECT lpoleobject - The OLE object
+ * OLE_CONST LOGPALETTE FAR * lppal - Suggested palette
+ *
+ * RETURNS: OLE_ERROR_PALETTE if CreatePalette fails,
+ * OLE_OK otherwise
+ *
+ *
+ * CUSTOMIZATION: If your application supports color schemes, then this
+ * function is a good example of how to create and store
+ * a palette.
+ *
+ */
+OLESTATUS APIENTRY ObjSetColorScheme
+ (LPOLEOBJECT lpoleobject, OLE_CONST LOGPALETTE FAR *lppal)
+{
+ HPALETTE hpal = CreatePalette (lppal);
+ LPOBJ lpobj = (LPOBJ) lpoleobject;
+
+ if (hpal==NULL)
+ return OLE_ERROR_PALETTE;
+
+ if (lpobj->hpal)
+ DeleteObject (lpobj->hpal);
+ lpobj->hpal = hpal;
+ return OLE_OK;
+}
+
+
+
+/* ObjSetData OBJECT "SetData" METHOD
+ * ----------
+ *
+ * This method is used to store data into the object in the specified
+ * format. This will be called with Native format after an embedded
+ * object has been opened by the Edit method.
+ *
+ * LPOLEOBJECT lpoleobject - The OLE object
+ * WORD cfFormat - Data type, i.e., clipboard format
+ * HANDLE hdata - Handle to the data.
+ *
+ * RETURNS: OLE_OK if the data was stored properly
+ * OLE_ERROR_FORMAT if format was not cfNative.
+ * OLE_ERROR_MEMORY if memory could not be locked.
+ *
+ * CUSTOMIZATION: The large then-clause will need to be re-implemented for
+ * your application. You may wish to support additional
+ * formats besides cfNative.
+ *
+ */
+OLESTATUS APIENTRY ObjSetData
+ (LPOLEOBJECT lpoleobject, OLECLIPFORMAT cfFormat, HANDLE hdata)
+{
+ LPNATIVE lpnative;
+ LPOBJ lpobj;
+
+ lpobj = (LPOBJ)lpoleobject;
+
+ if (cfFormat != cfNative)
+ {
+ return OLE_ERROR_FORMAT;
+ }
+
+ lpnative = (LPNATIVE) GlobalLock (hdata);
+
+ if (lpnative)
+ {
+ lpobj->native = *lpnative;
+ if (lpobj->aName)
+ GlobalDeleteAtom (lpobj->aName);
+ lpobj->aName = GlobalAddAtom (lpnative->szName);
+ // CreateNewObj made an "Object 1" but we may be changing its number.
+ docMain.rgfObjNums[1] = FALSE;
+ docMain.rgfObjNums [GetObjNum(lpobj)] = TRUE;
+
+ MoveWindow (lpobj->hwnd, 0, 0,
+// lpobj->native.nWidth + 2 * GetSystemMetrics(SM_CXFRAME),
+// lpobj->native.nHeight+ 2 * GetSystemMetrics(SM_CYFRAME),
+ lpobj->native.nWidth,
+ lpobj->native.nHeight,
+
+ FALSE);
+ GlobalUnlock (hdata);
+ }
+ // Server is responsible for deleting the data.
+ GlobalFree(hdata);
+ return lpnative ? OLE_OK : OLE_ERROR_MEMORY;
+}
+
+
+
+/* ObjSetTargetDevice OBJECT "SetTargetDevice" METHOD
+ * -------------------
+ *
+ * This method is used to indicate the device type that an object
+ * will be rendered on. It is the server's responsibility to free hdata.
+ *
+ * LPOLEOBJECT lpoleobject - The OLE object
+ * HANDLE hdata - Handle to memory containing
+ * a StdTargetDevice structure
+ *
+ * RETURNS: OLE_OK
+ *
+ * CUSTOMIZATION: Implement. Server Demo currently does not do anything.
+ *
+ */
+OLESTATUS APIENTRY ObjSetTargetDevice (LPOLEOBJECT lpoleobject, HANDLE hdata)
+{
+ if (hdata == NULL)
+ {
+ // Rendering for the screen is requested.
+ }
+ else
+ {
+ LPSTR lpstd = (LPSTR) GlobalLock (hdata);
+ // lpstd points to a StdTargetDevice structure.
+ // Use it to do whatever is appropriate to generate the best results
+ // on the specified target device.
+ GlobalUnlock (hdata);
+ // Server is responsible for freeing the data.
+ GlobalFree (hdata);
+ }
+ return OLE_OK;
+}
+
+
+
+/* ObjShow OBJECT "Show" METHOD
+ * --------
+ *
+ * This method is used to display the object.
+ * The server application should be activated and brought to the top.
+ * Also, in a REAL server application, the object should be scrolled
+ * into view. The object should be selected.
+ *
+ * LPOLEOBJECT lpoleobject - Pointer to the OLE object
+ * BOOL fTakeFocus - Should server window get the focus?
+ *
+ * RETURNS: OLE_OK
+ *
+ *
+ * CUSTOMIZATION: In your application, the document should be scrolled
+ * to bring the object into view. Server Demo brings the
+ * object to the front, in case it is a linked object inside a
+ * document with other objects obscuring it.
+ *
+ */
+OLESTATUS APIENTRY ObjShow (LPOLEOBJECT lpoleobject, BOOL fTakeFocus)
+{
+ LPOBJ lpobj;
+ HWND hwndOldFocus;
+
+ hwndOldFocus = GetFocus();
+ lpobj = (LPOBJ) lpoleobject;
+
+ if (fTakeFocus)
+ SetForegroundWindow (lpobj->hwnd);
+
+ ShowWindow(hwndMain, SW_SHOWNORMAL);
+
+ SetFocus (fTakeFocus ? lpobj->hwnd : hwndOldFocus);
+ return OLE_OK;
+}
+
+
+
+/* PaintObj
+ * ---------
+ *
+ * This function is called by the WM_PAINT message to paint an object
+ * on the screen.
+ *
+ * HWND hwnd - The object window in which to paint the object
+ *
+ * CUSTOMIZATION: Server Demo specific
+ *
+ */
+VOID PaintObj (HWND hwnd)
+{
+ LPOBJ lpobj;
+ RECT rc;
+ HDC hdc;
+ PAINTSTRUCT paintstruct;
+
+ BeginPaint (hwnd, &paintstruct);
+ hdc = GetDC (hwnd);
+
+ lpobj = HwndToLpobj (hwnd);
+ GetClientRect (hwnd, (LPRECT) &rc);
+
+ DrawObj (hdc, lpobj, rc, dctypeScreen);
+
+ ReleaseDC (hwnd, hdc);
+ EndPaint (hwnd, &paintstruct);
+}
+
+
+
+/* RevokeObj
+ * ---------
+ *
+ * Call OleRevokeObject because the user has destroyed the object.
+ *
+ * LPOBJ lpobj - The object which has been destroyed
+ *
+ *
+ * CUSTOMIZATION: You will only need to call OleRevokeObject once if there
+ * is only one LPOLECLIENT in your OBJ structure, which there
+ * should be.
+ *
+ */
+VOID RevokeObj (LPOBJ lpobj)
+{
+ INT i;
+
+ for (i=0; i< clpoleclient; i++)
+ {
+ if (lpobj->lpoleclient[i])
+ OleRevokeObject (lpobj->lpoleclient[i]);
+ else
+ /* if lpobj->lpoleclient[i]==NULL then there are no more non-NULLs
+ in the array. */
+ break;
+ }
+}
+
+
+
+/* SendObjMsg
+ * ----------
+ *
+ * This function sends a message to a specific object.
+ *
+ * LPOBJ lpobj - The object
+ * WORD wMessage - The message to send
+ *
+ * CUSTOMIZATION: You will only need to call CallBack once if there
+ * is only one LPOLECLIENT in your OBJ structure, which there
+ * should be.
+ *
+ */
+VOID SendObjMsg (LPOBJ lpobj, WORD wMessage)
+{
+ INT i;
+ for (i=0; i < clpoleclient; i++)
+ {
+ if (lpobj->lpoleclient[i])
+ {
+ // Call the object's Callback function.
+ lpobj->lpoleclient[i]->lpvtbl->CallBack
+ (lpobj->lpoleclient[i], wMessage, (LPOLEOBJECT) lpobj);
+ }
+ else
+ break;
+ }
+}
+
+
+
+/* SizeObj
+ * -------
+ *
+ * Change the size of an object.
+ *
+ * HWND hwnd - The object's window
+ * RECT rect - The requested new size in device units
+ * BOOL fMove - Should the object be moved? (or just resized?)
+ *
+ * CUSTOMIZATION: Server Demo specific
+ *
+ */
+VOID SizeObj (HWND hwnd, RECT rect, BOOL fMove)
+{
+ LPOBJ lpobj;
+
+ lpobj = HwndToLpobj (hwnd);
+ if (fMove)
+ {
+ lpobj->native.nX = rect.left;
+ lpobj->native.nY = rect.top;
+ }
+ lpobj->native.nWidth = rect.right - rect.left;
+ lpobj->native.nHeight = rect.bottom - rect.top ;
+ SetHiMetricFields (lpobj);
+ InvalidateRect (hwnd, (LPRECT)NULL, TRUE);
+ fDocChanged = TRUE;
+ if (docMain.doctype == doctypeFromFile)
+ {
+ // If object is linked, update it in client now.
+ SendObjMsg (lpobj, OLE_CHANGED);
+ }
+}
diff --git a/private/oleutest/ole1/srvrdemo/server.c b/private/oleutest/ole1/srvrdemo/server.c
new file mode 100644
index 000000000..da647bfdc
--- /dev/null
+++ b/private/oleutest/ole1/srvrdemo/server.c
@@ -0,0 +1,538 @@
+/*
+ OLE SERVER DEMO
+ Server.c
+
+ This file contains server methods and various server-related support
+ functions.
+
+ (c) Copyright Microsoft Corp. 1990 - 1992 All Rights Reserved
+*/
+
+
+
+#define SERVERONLY
+#include <windows.h>
+#include <ole.h>
+
+#include "srvrdemo.h"
+
+CLASS_STRINGS ClassStrings = {
+ "SrvrDemo10", "*.sd1", "Srvr Demo10", "svrdemo1.exe"
+};
+
+/*
+ Important Note:
+
+ No method should ever dispatch a DDE message or allow a DDE message to
+ be dispatched.
+ Therefore, no method should ever enter a message dispatch loop.
+ Also, a method should not show a dialog or message box, because the
+ processing of the dialog box messages will allow DDE messages to be
+ dispatched.
+*/
+BOOL RegServer(){
+
+ LONG fRet;
+ HKEY hKey;
+ CHAR szKeyName[300]; //Get better value
+ BOOL retVal = FALSE;
+
+ lstrcpy(szKeyName, ClassStrings.pClassName);
+ lstrcat(szKeyName, "\\protocol\\StdFileEditing\\verb");
+
+ //Check if Class is installed, following should hold correct if class is installed.
+ if ((fRet = RegOpenKey(HKEY_CLASSES_ROOT, szKeyName, &hKey)) == ERROR_SUCCESS)
+ return FALSE;
+
+ RegCloseKey(hKey);
+
+ if ((fRet = RegSetValue(HKEY_CLASSES_ROOT, (LPSTR)(ClassStrings.pFileSpec+1),
+ REG_SZ, ClassStrings.pClassName, 7)) != ERROR_SUCCESS)
+ return FALSE;
+
+ if((fRet = RegSetValue(HKEY_CLASSES_ROOT, ClassStrings.pClassName, REG_SZ,
+ ClassStrings.pHumanReadable, 7)) != ERROR_SUCCESS)
+ return FALSE;
+
+ lstrcat(szKeyName, "\\0");
+ if((fRet = RegSetValue(HKEY_CLASSES_ROOT, (LPSTR)szKeyName, REG_SZ, "PLAY", 4))
+ != ERROR_SUCCESS)
+ return FALSE;
+
+ szKeyName[lstrlen(szKeyName) - 1] = '1';
+ if((fRet = RegSetValue(HKEY_CLASSES_ROOT, (LPSTR)szKeyName, REG_SZ, "EDIT", 4))
+ != ERROR_SUCCESS)
+ return FALSE;
+
+ lstrcpy(szKeyName, ClassStrings.pClassName);
+ lstrcat(szKeyName, "\\protocol\\StdFileEditing\\Server");
+ if((fRet = RegSetValue(HKEY_CLASSES_ROOT, (LPSTR)szKeyName, REG_SZ, ClassStrings.pExeName, 11))
+ != ERROR_SUCCESS)
+ return FALSE;
+
+ lstrcpy(szKeyName, ClassStrings.pClassName);
+ lstrcat(szKeyName, "\\protocol\\StdExecute\\Server");
+ if((fRet = RegSetValue(HKEY_CLASSES_ROOT, (LPSTR)szKeyName, REG_SZ, ClassStrings.pExeName, 11))
+ != ERROR_SUCCESS)
+ return FALSE;
+
+
+ return TRUE;
+
+}
+
+
+/* Abbrev
+ * ------
+ *
+ * Return a pointer to the filename part of a fully-qualified pathname.
+ *
+ * LPSTR lpsz - Fully qualified pathname
+ *
+ * CUSTOMIZATION: May be useful, but not necessary.
+ *
+ */
+LPSTR Abbrev (LPSTR lpsz)
+{
+ LPSTR lpszTemp;
+
+ lpszTemp = lpsz + lstrlen(lpsz) - 1;
+ while (lpszTemp > lpsz && lpszTemp[-1] != '\\')
+ lpszTemp--;
+ return lpszTemp;
+}
+
+
+
+
+
+/* InitServer
+ * ----------
+ *
+ * Initialize the server by allocating memory for it, and calling
+ * the OleRegisterServer method. Requires that the server method table
+ * has been properly initialized.
+ *
+ * HWND hwnd - Handle to the main window
+ * LPSTR lpszLine - The Windows command line
+ *
+ * RETURNS: TRUE if the memory could be allocated, and the server
+ * was properly registered.
+ * FALSE otherwise
+ *
+ * CUSTOMIZATION: Your application might not use a global variable
+ * for srvrMain.
+ *
+ */
+BOOL InitServer (HWND hwnd, HANDLE hInst)
+{
+ RegServer();
+ srvrMain.olesrvr.lpvtbl = &srvrvtbl;
+
+ if (OLE_OK != OleRegisterServer
+ (szClassName, (LPOLESERVER) &srvrMain, &srvrMain.lhsrvr, hInst,
+ OLE_SERVER_MULTI))
+ return FALSE;
+ else
+ return TRUE;
+}
+
+
+
+/* InitVTbls
+ * ---------
+ *
+ * Create procedure instances for all the OLE methods.
+ *
+ *
+ * CUSTOMIZATION: Your application might not use global variables for srvrvtbl,
+ * docvtbl, and objvtbl.
+ */
+VOID InitVTbls (VOID)
+{
+ typedef LPVOID ( APIENTRY *LPVOIDPROC) (LPOLEOBJECT, LPSTR);
+
+ // Server method table
+ srvrvtbl.Create = SrvrCreate;
+ srvrvtbl.CreateFromTemplate = SrvrCreateFromTemplate;
+ srvrvtbl.Edit = SrvrEdit;
+ srvrvtbl.Execute = SrvrExecute;
+ srvrvtbl.Exit = SrvrExit;
+ srvrvtbl.Open = SrvrOpen;
+ srvrvtbl.Release = SrvrRelease;
+
+ // Document method table
+ docvtbl.Close = DocClose;
+ docvtbl.GetObject = DocGetObject;
+ docvtbl.Execute = DocExecute;
+ docvtbl.Release = DocRelease;
+ docvtbl.Save = DocSave;
+ docvtbl.SetColorScheme = DocSetColorScheme;
+ docvtbl.SetDocDimensions = DocSetDocDimensions;
+ docvtbl.SetHostNames = DocSetHostNames;
+
+ // Object method table
+ objvtbl.DoVerb = ObjDoVerb;
+ objvtbl.EnumFormats = ObjEnumFormats;
+ objvtbl.GetData = ObjGetData;
+ objvtbl.QueryProtocol = ObjQueryProtocol;
+ objvtbl.Release = ObjRelease;
+ objvtbl.SetBounds = ObjSetBounds;
+ objvtbl.SetColorScheme = ObjSetColorScheme;
+ objvtbl.SetData = ObjSetData;
+ objvtbl.SetTargetDevice = ObjSetTargetDevice;
+ objvtbl.Show = ObjShow;
+
+}
+
+
+
+/* SetTitle
+ * --------
+ *
+ * Sets the main window's title bar. The format of the title bar is as follows
+ *
+ * If embedded
+ * <Server App name> - <object type> in <client doc name>
+ *
+ * Example: "Server Demo - SrvrDemo Shape in OLECLI.DOC"
+ * where OLECLI.DOC is a Winword document
+ *
+ * otherwise
+ * <Server App name> - <server document name>
+ *
+ * Example: "Srvr Demo10 - OLESVR.SD1"
+ * where OLESVR.SD1 is a Server demo document
+ *
+ * LPSTR lpszDoc - document name
+ * BOOL fEmbedded - If TRUE embedded document, else normal document
+ *
+ * RETURNS: OLE_OK
+ *
+ *
+ * CUSTOMIZATION: Your application may store the document's name somewhere
+ * other than docMain.aName. Other than that, you may
+ * find this a useful utility function as is.
+ *
+ */
+VOID SetTitle (LPSTR lpszDoc, BOOL fEmbedded)
+{
+ CHAR szBuf[cchFilenameMax];
+
+ if (lpszDoc && lpszDoc[0])
+ {
+ // Change document name.
+ if (docMain.aName)
+ GlobalDeleteAtom (docMain.aName);
+ docMain.aName = GlobalAddAtom (lpszDoc);
+ }
+
+ if (fEmbedded)
+ {
+ //
+ if (lpszDoc && lpszDoc[0])
+ {
+ wsprintf (szBuf, "%s - SrvrDemo10 Shape in %s", (LPSTR) szAppName,
+ Abbrev (lpszDoc));
+ }
+ else
+ {
+ // Use name from docMain
+ CHAR szDoc [cchFilenameMax];
+
+ GlobalGetAtomName (docMain.aName, szDoc, cchFilenameMax);
+ wsprintf (szBuf, "%s - SrvrDemo Shape10 in %s", (LPSTR) szAppName,
+ Abbrev (szDoc));
+ }
+ SetWindowText (hwndMain, (LPSTR)szBuf);
+ }
+ else if (lpszDoc && lpszDoc[0])
+ {
+ wsprintf (szBuf, "%s - %s", (LPSTR) szAppName, Abbrev(lpszDoc));
+ SetWindowText (hwndMain, szBuf);
+ }
+}
+
+
+
+
+/* SrvrCreate SERVER "Create" METHOD
+ * ----------
+ *
+ * Create a document, allocate and initialize the OLESERVERDOC structure,
+ * and associate the library's handle with it.
+ * In this demo server, we also create an object for the user to edit.
+ *
+ * LPOLESERVER lpolesrvr - The server structure registered by
+ * the application
+ * LHSERVERDOC lhdoc - The library's handle
+ * OLE_LPCSTR lpszClassName - The class of document to create
+ * OLE_LPCSTR lpszDoc - The name of the document
+ * LPOLESERVERDOC FAR *lplpoledoc - Indicates the server doc structure to be
+ * created
+ *
+ * RETURNS: OLE_OK if the named document was created.
+ * OLE_ERROR_NEW if the document could not be created.
+ *
+ * CUSTOMIZATION: Your application might not call CreateNewObj.
+ *
+ */
+OLESTATUS APIENTRY SrvrCreate
+ (LPOLESERVER lpolesrvr, LHSERVERDOC lhdoc, OLE_LPCSTR lpszClassName,
+ OLE_LPCSTR lpszDoc, LPOLESERVERDOC FAR *lplpoledoc)
+{
+ if (!CreateNewDoc (lhdoc, (LPSTR) lpszDoc, doctypeEmbedded))
+ return OLE_ERROR_NEW;
+
+ // Although the document has not actually been changed, the client has not
+ // received any data from the server yet, so the client will need to be
+ // updated. Therefore, CreateNewObj sets fDocChanged to TRUE.
+ CreateNewObj (TRUE);
+ *lplpoledoc = (LPOLESERVERDOC) &docMain;
+ EmbeddingModeOn();
+ return OLE_OK;
+}
+
+
+
+/* SrvrCreateFromTemplate SERVER "CreateFromTemplate" METHOD
+ * ----------------------
+ *
+ * Create a document, allocate and initialize the OLESERVERDOC structure,
+ * initializing the document with the contents named in the template name,
+ * and associate the library's handle with the document structure.
+ *
+ * LPOLESERVER lpolesrvr - The server structure registered by
+ * the application
+ * LHSERVERDOC lhdoc - The library's handle
+ * OLE_LPCSTR lpszClassName - The class of document to create
+ * OLE_LPCSTR lpszDoc - The name of the document
+ * OLE_LPCSTR lpszTemplate - The name of the template
+ * LPOLESERVERDOC FAR *lplpoledoc - Indicates the server doc structure
+ * to be created
+ *
+ * RETURNS: OLE_OK if the named document was created.
+ * OLE_ERROR_TEMPLATE if the document could not be created.
+ *
+ * CUSTOMIZATION: None
+ *
+ */
+OLESTATUS APIENTRY SrvrCreateFromTemplate
+ (LPOLESERVER lpolesrvr, LHSERVERDOC lhdoc, OLE_LPCSTR lpszClassName,
+ OLE_LPCSTR lpszDoc, OLE_LPCSTR lpszTemplate, LPOLESERVERDOC FAR *lplpoledoc)
+{
+ if (!CreateDocFromFile((LPSTR) lpszTemplate, (LHSERVERDOC) lhdoc, doctypeEmbedded))
+ return OLE_ERROR_TEMPLATE;
+
+ *lplpoledoc = (LPOLESERVERDOC) &docMain;
+
+ // Although the document has not actually been changed, the client has not
+ // received any data from the server yet, so the client will need to be
+ // updated.
+ fDocChanged = TRUE;
+ EmbeddingModeOn();
+ return OLE_OK;
+}
+
+
+
+/* SrvrEdit SERVER "Edit" METHOD
+ * --------
+ *
+ * A request by the libraries to create a document, allocate and
+ * initialize the OLESERVERDOC structure, and associate the
+ * library's handle with the document structure.
+ * We create an object which will be modified by the SetData method
+ * before the user has a chance to touch it.
+ *
+ * LPOLESERVER lpolesrvr - The server structure registered by
+ * the application
+ * LHSERVERDOC lhdoc - The library's handle
+ * OLE_LPCSTR lpszClassName - The class of document to create
+ * OLE_LPCSTR lpszDoc - The name of the document
+ * LPOLESERVERDOC FAR *lplpoledoc - Indicates the server doc structure to be
+ * created
+ *
+ * RETURNS: OLE_OK if the named document was created.
+ * OLE_ERROR_EDIT if the document could not be created.
+ *
+ * CUSTOMIZATION: None
+ *
+ */
+OLESTATUS APIENTRY SrvrEdit
+ (LPOLESERVER lpolesrvr, LHSERVERDOC lhdoc, OLE_LPCSTR lpszClassName,
+ OLE_LPCSTR lpszDoc, LPOLESERVERDOC FAR *lplpoledoc)
+{
+ if (!CreateNewDoc ((LONG)lhdoc, (LPSTR)lpszDoc, doctypeEmbedded))
+ return OLE_ERROR_EDIT;
+
+ // The client is creating an embedded object for the server to edit,
+ // so initially the client and server are in sync.
+ fDocChanged = FALSE;
+ *lplpoledoc = (LPOLESERVERDOC) &docMain;
+ EmbeddingModeOn();
+ return OLE_OK;
+
+}
+
+
+/* SrvrExecute SERVER "Execute" METHOD
+ * --------
+ *
+ * This application does not support the execution of DDE execution commands.
+ *
+ * LPOLESERVER lpolesrvr - The server structure registered by
+ * the application
+ * HANDLE hCommands - DDE execute commands
+ *
+ * RETURNS: OLE_ERROR_COMMAND
+ *
+ * CUSTOMIZATION: Re-implement if your application supports the execution of
+ * DDE commands.
+ *
+ */
+OLESTATUS APIENTRY SrvrExecute (LPOLESERVER lpolesrvr, HANDLE hCommands)
+{
+ return OLE_ERROR_COMMAND;
+}
+
+
+
+/* SrvrExit SERVER "Exit" METHOD
+ * --------
+ *
+ * This method is called the library to instruct the server to exit.
+ *
+ * LPOLESERVER lpolesrvr - The server structure registered by
+ * the application
+ *
+ * RETURNS: OLE_OK
+ *
+ * CUSTOMIZATION: None
+ *
+ */
+OLESTATUS APIENTRY SrvrExit (LPOLESERVER lpolesrvr)
+{
+ if (srvrMain.lhsrvr)
+ // If we haven't already tried to revoke the server.
+ {
+ StartRevokingServer();
+ }
+ return OLE_OK;
+}
+
+
+
+/* SrvrOpen SERVER "Open" METHOD
+ * --------
+ *
+ * Open the named document, allocate and initialize the OLESERVERDOC
+ * structure, and associate the library's handle with it.
+ *
+ * LPOLESERVER lpolesrvr - The server structure registered by
+ * the application
+ * LHSERVERDOC lhdoc - The library's handle
+ * OLE_LPCSTR lpszDoc - The name of the document
+ * LPOLESERVERDOC FAR *lplpoledoc - Indicates server doc structure to be
+ * created
+ *
+ * RETURNS: OLE_OK if the named document was opened.
+ * OLE_ERROR_OPEN if document could not be opened correctly.
+ *
+ * CUSTOMIZATION: None
+ *
+ */
+OLESTATUS APIENTRY SrvrOpen (LPOLESERVER lpolesrvr, LHSERVERDOC lhdoc,
+ OLE_LPCSTR lpszDoc, LPOLESERVERDOC FAR *lplpoledoc)
+{
+ if (!CreateDocFromFile ((LPSTR)lpszDoc, (LHSERVERDOC)lhdoc, doctypeFromFile))
+ return OLE_ERROR_OPEN;
+
+ *lplpoledoc = (LPOLESERVERDOC) &docMain;
+ return OLE_OK;
+}
+
+
+
+/* SrvrRelease SERVER "Release" METHOD
+ * -----------
+ *
+ * This library calls the SrvrRelease method when it is safe to quit the
+ * application. Note that the server application is not required to quit.
+ *
+ * srvrMain.lhsrvr != NULL indicates that SrvrRelease has been called
+ * because the client is no longer connected, not because the server called
+ * OleRevokeServer.
+ * Therefore, only start the revoking process if the document is of type
+ * doctypeEmbedded or if the server was opened for an invisible update.
+ *
+ * srvrmain.lhsrvr == NULL indicates that OleRevokeServer has already
+ * been called (by the server application), and srvrMain is a lame duck.
+ * It is safe to quit now because SrvrRelease has just been called.
+ *
+ * Note that this method may be called twice: when OleRevokeServer is
+ * called in StartRevokingServer, SrvrRelease is called again.
+ * Therefore we need to be reentrant.
+ *
+ * LPOLESERVER lpolesrvr - The server structure to release
+ *
+ * RETURNS: OLE_OK
+ *
+ * CUSTOMIZATION: None
+ *
+ */
+OLESTATUS APIENTRY SrvrRelease (LPOLESERVER lpolesrvr)
+{
+ if (srvrMain.lhsrvr)
+ {
+ if (fRevokeSrvrOnSrvrRelease
+ && (docMain.doctype == doctypeEmbedded
+ || !IsWindowVisible (hwndMain)))
+ StartRevokingServer();
+ }
+ else
+ {
+ fWaitingForSrvrRelease = FALSE;
+ // Here you should free any memory that had been allocated for the server.
+ PostQuitMessage (0);
+ }
+ return OLE_OK;
+}
+
+
+
+/* StartRevokingServer
+ * -------------------
+ *
+ * Hide the window, and start to revoke the server.
+ * Revoking the server will let the library close any registered documents.
+ * OleRevokeServer may return OLE_WAIT_FOR_RELEASE.
+ * Calling StartRevokingServer starts a chain of events that will eventually
+ * lead to the application being terminated.
+ *
+ * RETURNS: The return value from OleRevokeServer
+ *
+ * CUSTOMIZATION: None
+ *
+ */
+OLESTATUS StartRevokingServer (VOID)
+{
+ OLESTATUS olestatus;
+
+ if (srvrMain.lhsrvr)
+ {
+ LHSERVER lhserver;
+ // Hide the window so user can do nothing while we are waiting.
+ ShowWindow (hwndMain, SW_HIDE);
+ lhserver = srvrMain.lhsrvr;
+ // Set lhsrvr to NULL to indicate that srvrMain is a lame duck and that
+ // if SrvrRelease is called, then it is ok to quit the application.
+ srvrMain.lhsrvr = 0;
+ olestatus = OleRevokeServer (lhserver);
+ }
+ else
+ // The programmer should ensure that this never happens.
+ ErrorBox ("Fatal Error: StartRevokingServer called on NULL server.");
+ return olestatus;
+}
+
diff --git a/private/oleutest/ole1/srvrdemo/srvrdemo b/private/oleutest/ole1/srvrdemo/srvrdemo
new file mode 100644
index 000000000..44b846700
--- /dev/null
+++ b/private/oleutest/ole1/srvrdemo/srvrdemo
@@ -0,0 +1,33 @@
+
+!include <ntwin32.mak>
+
+my_lib = advapi32.lib olesvr32.lib
+
+all: srvrdemo.exe
+
+# Update the resource if necessary
+
+srvrdemo.res: srvrdemo.rc
+ $(rc) $(rcvars) -r srvrdemo.rc
+
+# Update the object file if necessary
+
+srvrdemo.obj: srvrdemo.c
+ $(cc) $(cflags) $(cvars) $(cdebug) srvrdemo.c
+
+doc.obj: doc.c
+ $(cc) $(cflags) $(cvars) $(cdebug) doc.c
+
+obj.obj: obj.c
+ $(cc) $(cflags) $(cvars) $(cdebug) obj.c
+
+file.obj: file.c
+ $(cc) $(cflags) $(cvars) $(cdebug) file.c
+
+server.obj: server.c
+ $(cc) $(cflags) $(cvars) $(cdebug) server.c
+
+# Update the executable file if necessary, and if so, add the resource back in.
+
+srvrdemo.exe: srvrdemo.obj doc.obj obj.obj server.obj file.obj srvrdemo.res srvrdemo.def
+ $(link) $(linkdebug) $(guiflags) -out:srvrdemo.exe srvrdemo.obj file.obj doc.obj obj.obj server.obj srvrdemo.res $(guilibs) $(my_lib)
diff --git a/private/oleutest/ole1/srvrdemo/srvrdemo.c b/private/oleutest/ole1/srvrdemo/srvrdemo.c
new file mode 100644
index 000000000..081f27ceb
--- /dev/null
+++ b/private/oleutest/ole1/srvrdemo/srvrdemo.c
@@ -0,0 +1,1335 @@
+/*
+ OLE SERVER DEMO
+ SrvrDemo.c
+
+ This file contains the window handlers, and various initialization and
+ utility functions.
+
+ (c) Copyright Microsoft Corp. 1990 - 1992 All Rights Reserved
+*/
+
+
+#define SERVERONLY
+#include <windows.h>
+#include <ole.h>
+
+#include "srvrdemo.h"
+
+/* Global variable definitions */
+
+HWND hwndMain = 0;
+
+// Used in converting units from pixels to Himetric and vice-versa
+int giXppli = 0; // pixels per logical inch along width
+int giYppli = 0; // pixels per logical inch along height
+
+
+
+// Since this is a not an MDI app, there can be only one server and one doc.
+SRVR srvrMain;
+DOC docMain;
+CHAR szClient[cchFilenameMax];
+CHAR szClientDoc[cchFilenameMax];
+
+// Has the user made changes to the document?
+BOOL fDocChanged = FALSE;
+
+// Is this the first instance of this application currently running?
+BOOL fFirstInstance = TRUE;
+
+// This flag is used when OleRevokeServerDoc returns OLE_WAIT_FOR_RELEASE,
+// and we must wait until DocRelease is called.
+BOOL fWaitingForDocRelease = FALSE;
+
+// This flag is used when OleRevokeServer returns OLE_WAIT_FOR_RELEASE,
+// and we must wait until SrvrRelease is called.
+BOOL fWaitingForSrvrRelease = FALSE;
+
+// This flag is set to TRUE after an application has called OleBlockServer
+// and now wishes to unblock the queued messages. See WinMain.
+// Server Demo never sets fUnblock to TRUE because it never calls
+// OleBlockServer.
+BOOL fUnblock = FALSE;
+
+// Set this to FALSE if you want to guarantee that the server will not revoke
+// itself when SrvrRelease is called. This is used in the IDM_NEW case and
+// the IDM_OPEN case (in OpenDoc).
+BOOL fRevokeSrvrOnSrvrRelease = TRUE;
+
+// Version number, which is stored in the native data.
+VERSION version = 1;
+
+HBRUSH hbrColor[chbrMax];
+
+// Clipboard formats
+OLECLIPFORMAT cfObjectLink;
+OLECLIPFORMAT cfOwnerLink;
+OLECLIPFORMAT cfNative;
+
+// Method tables.
+OLESERVERDOCVTBL docvtbl;
+OLEOBJECTVTBL objvtbl;
+OLESERVERVTBL srvrvtbl;
+
+HANDLE hInst;
+HANDLE hAccelTable;
+HMENU hMainMenu = NULL;
+
+// Window dimensions saved in private profile.
+static struct
+{
+ INT nX;
+ INT nY;
+ INT nWidth;
+ INT nHeight;
+} dimsSaved, dimsCurrent;
+
+
+static enum
+{
+ // Corresponds to the order of the menus in the .rc file.
+ menuposFile,
+ menuposEdit,
+ menuposColor,
+ menuposObject
+};
+
+
+// Static functions.
+static VOID DeleteInstance (VOID);
+static BOOL ExitApplication (BOOL);
+static VOID GetWord (LPSTR *plpszSrc, LPSTR lpszDst);
+static BOOL InitApplication( HANDLE hInstance);
+static BOOL InitInstance (HANDLE hInstance);
+static BOOL ProcessCmdLine (LPSTR,HWND);
+static VOID SaveDimensions (VOID);
+static VOID SkipBlanks (LPSTR *plpsz);
+static VOID UpdateObjMenus (VOID);
+static BOOL FailedUpdate(HWND);
+
+/* WinMain
+ * -------
+ *
+ * Standard windows entry point
+ *
+ * CUSTOMIZATION: None
+ *
+ */
+int APIENTRY WinMain(
+ HINSTANCE hInstance,
+ HINSTANCE hPrevInstance,
+ LPSTR lpCmdLine,
+ INT nCmdShow
+){
+ MSG msg;
+
+ if (!InitApplication(hInstance))
+ return FALSE;
+
+ msg.wParam = FALSE;
+
+ if (!InitInstance(hInstance))
+ goto errRtn;
+
+ if (!InitServer (hwndMain, hInstance))
+ goto errRtn;
+
+ if (!ProcessCmdLine(lpCmdLine,hwndMain))
+ {
+ ExitApplication(FALSE);
+ goto errRtn;
+ }
+
+ for (;;)
+ {
+ // Your application should set fUnblock to TRUE when it decides
+ // to unblock.
+ if (fUnblock)
+ {
+ BOOL fMoreMsgs = TRUE;
+ while (fMoreMsgs)
+ {
+ if (srvrMain.lhsrvr == 0)
+ OleUnblockServer (srvrMain.lhsrvr, &fMoreMsgs);
+ }
+ // We have taken care of all the messages in the OLE queue
+ fUnblock = FALSE;
+ }
+
+ if (!GetMessage(&msg, NULL, 0, 0))
+ break;
+ if( !TranslateAccelerator(hwndMain, hAccelTable, &msg))
+ {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ }
+
+
+errRtn:
+
+ DeleteInstance ();
+ return (msg.wParam);
+}
+
+
+
+/* InitApplication
+ * ---------------
+ *
+ * Initialize the application - register the window classes
+ *
+ * HANDLE hInstance
+ *
+ * RETURNS: TRUE if classes are properly registered.
+ * FALSE otherwise
+ *
+ * CUSTOMIZATION: Re-implement
+ *
+ */
+static BOOL InitApplication( HANDLE hInstance )
+{
+ WNDCLASS wc;
+
+ wc.lpszClassName = "MainClass";
+ wc.lpfnWndProc = (WNDPROC)MainWndProc;
+ wc.style = 0;
+ wc.cbClsExtra = 4;
+ wc.cbWndExtra = 0;
+ wc.hInstance = hInstance;
+ wc.hIcon = LoadIcon(hInstance, "DocIcon");
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wc.hbrBackground = GetStockObject(WHITE_BRUSH);
+ wc.lpszMenuName = "MainMenu";
+
+ if (!RegisterClass(&wc))
+ return FALSE;
+
+ wc.lpszClassName = "ObjClass";
+ wc.lpfnWndProc = (WNDPROC)ObjWndProc;
+ wc.hIcon = NULL;
+ wc.cbWndExtra = cbWindExtra;
+ wc.lpszMenuName = NULL;
+ wc.hCursor = LoadCursor(NULL, IDC_CROSS);
+
+ if (!RegisterClass(&wc))
+ return FALSE;
+
+ return TRUE;
+}
+
+
+
+/* InitInstance
+ * ------------
+ *
+ * Create brushes used by the program, the main window, and
+ * do any other per-instance initialization.
+ *
+ * HANDLE hInstance
+ *
+ * RETURNS: TRUE if successful
+ * FALSE otherwise.
+ *
+ * CUSTOMIZATION: Re-implement
+ *
+ */
+static BOOL InitInstance (HANDLE hInstance)
+{
+ LONG rglColor [chbrMax] =
+ {
+ 0x000000ff, // Red
+ 0x0000ff00, // Green
+ 0x00ff0000, // Blue
+ 0x00ffffff, // White
+ 0x00808080, // Gray
+ 0x00ffff00, // Cyan
+ 0x00ff00ff, // Magenta
+ 0x0000ffff // Yellow
+ };
+
+
+ INT iColor;
+ HDC hDC ;
+
+ hInst = hInstance;
+
+ // Initialize the method tables.
+ InitVTbls ();
+
+ // Initialize the brushes used.
+ for (iColor = 0; iColor < chbrMax; iColor++)
+ hbrColor[iColor] = CreateSolidBrush (rglColor[iColor]);
+
+ // Register clipboard formats.
+ cfObjectLink= RegisterClipboardFormat ("ObjectLink");
+ cfOwnerLink = RegisterClipboardFormat ("OwnerLink");
+ cfNative = RegisterClipboardFormat ("Native");
+
+ hAccelTable = LoadAccelerators(hInst, "Accelerators");
+// hMainMenu = LoadMenu(hInst, "MainMenu");
+
+
+ hwndMain = CreateWindow(
+ "MainClass",
+ szAppName,
+ WS_OVERLAPPEDWINDOW,
+ CW_USEDEFAULT, CW_USEDEFAULT,
+ 3*OBJECT_WIDTH, 3*OBJECT_HEIGHT,
+ NULL,
+ NULL,
+ hInstance,
+ NULL
+ );
+
+
+ if (!hwndMain)
+ return FALSE;
+
+ szClient[0] = '\0';
+ lstrcpy (szClientDoc, "Client Document");
+
+ // Initialize global variables with LOGPIXELSX and LOGPIXELSY
+
+ hDC = GetDC (NULL); // Get the hDC of the desktop window
+ giXppli = GetDeviceCaps (hDC, LOGPIXELSX);
+ giYppli = GetDeviceCaps (hDC, LOGPIXELSY);
+ ReleaseDC (NULL, hDC);
+
+
+ return TRUE;
+
+}
+
+
+
+/* DeleteInstance
+ * --------------
+ *
+ * Deallocate the VTables, and the brushes created for this instance
+ *
+ *
+ * CUSTOMIZATION: The call to FreeVTbls must remain.
+ *
+ */
+static VOID DeleteInstance (VOID)
+{
+ INT i;
+
+ for (i = 0; i < chbrMax; i++)
+ DeleteObject (hbrColor[i]);
+
+}
+
+
+
+/* ExitApplication
+ * ---------------
+ *
+ * Handles the WM_CLOSE and WM_COMMAND/IDM_EXIT messages.
+ *
+ * RETURNS: TRUE if application should really terminate
+ * FALSE if not
+ *
+ *
+ * CUSTOMIZATION: None
+ *
+ */
+static BOOL ExitApplication (BOOL fUpdateLater)
+{
+
+ if (fUpdateLater)
+ {
+ // The non-standard OLE client did not accept the update
+ // when we requested it, so we are sending the client
+ // OLE_CLOSED now that we are closing the document.
+ SendDocMsg (OLE_CLOSED);
+ }
+
+ if (StartRevokingServer() == OLE_WAIT_FOR_RELEASE)
+ Wait (&fWaitingForSrvrRelease);
+ /* SrvrRelease will not necessarily post a WM_QUIT message.
+ If the document is not embedded, SrvrRelease by itself does
+ not cause the application to terminate. But now we want it to.
+ */
+ if (docMain.doctype != doctypeEmbedded)
+ PostQuitMessage(0);
+ SaveDimensions();
+ return TRUE;
+}
+
+
+
+/* MainWndProc
+ * -----------
+ *
+ * Main window message handler.
+ *
+ *
+ * CUSTOMIZATION: Remove the color menu and the object menu entirely.
+ * Add handlers for your application's menu items and any
+ * Windows messages your application needs to handle.
+ * The handlers for the menu items that involve OLE
+ * can be added to, but no logic should be removed.
+ *
+ *
+ */
+LONG APIENTRY MainWndProc
+ (HWND hwnd, UINT message, WPARAM wParam, LONG lParam )
+{
+ LPOBJ lpobj;
+
+ switch (message)
+ {
+ case WM_COMMAND:
+ {
+ WORD wID = LOWORD(wParam);
+
+ if (fWaitingForDocRelease)
+ {
+ ErrorBox ("Waiting for a document to be revoked.\n\rPlease wait.");
+ return 0;
+ }
+
+ switch (wID)
+ {
+ case IDM_EXIT:
+ SendMessage(hwnd, WM_SYSCOMMAND, SC_CLOSE, 0L);
+ break;
+
+ case IDM_ABOUT:
+ DialogBox(hInst, "AboutBox", hwnd, (DLGPROC)About);
+ break;
+
+ case IDM_NEW:
+ {
+ BOOL fUpdateLater;
+ OLESTATUS olestatus;
+
+ if (SaveChangesOption (&fUpdateLater) == IDCANCEL)
+ break;
+ else if (fUpdateLater)
+ SendDocMsg (OLE_CLOSED);
+
+ // We want to revoke the doc but not the server, so if
+ // SrvrRelease is called, do not revoke server.
+ fRevokeSrvrOnSrvrRelease = FALSE;
+
+ if ((olestatus = RevokeDoc()) > OLE_WAIT_FOR_RELEASE)
+ {
+ ErrorBox ("Serious Error: Cannot revoke document.");
+ break;
+ }
+ else if (olestatus == OLE_WAIT_FOR_RELEASE)
+ Wait (&fWaitingForDocRelease);
+
+ fRevokeSrvrOnSrvrRelease = TRUE;
+
+ if (!CreateNewDoc (0, "(Untitled)", doctypeNew))
+ {
+ ErrorBox ("Serious Error: Cannot create new document.");
+ break;
+ }
+ // Your application need not create a default object.
+ CreateNewObj (FALSE);
+ EmbeddingModeOff();
+ break;
+ }
+ case IDM_OPEN:
+ OpenDoc();
+ UpdateObjMenus();
+ break;
+
+ case IDM_SAVE:
+ SaveDoc();
+ break;
+
+ case IDM_SAVEAS:
+ if (!SaveDocAs ())
+ break;
+ if (docMain.doctype != doctypeEmbedded)
+ EmbeddingModeOff();
+ break;
+
+ case IDM_UPDATE:
+ switch (OleSavedServerDoc (docMain.lhdoc))
+ {
+ case OLE_ERROR_CANT_UPDATE_CLIENT:
+ if (!FailedUpdate(hwnd))
+ ExitApplication(TRUE);
+ break;
+ case OLE_OK:
+ break;
+ default:
+ ErrorBox ("Serious Error: Cannot update.");
+ }
+ break;
+
+ /* Color menu */
+
+ case IDM_RED:
+ case IDM_GREEN:
+ case IDM_BLUE:
+ case IDM_WHITE:
+ case IDM_GRAY:
+ case IDM_CYAN:
+ case IDM_MAGENTA:
+ case IDM_YELLOW:
+ lpobj = SelectedObject();
+ lpobj->native.idmColor = wID;
+ // Recolor the object on the screen.
+ InvalidateRect (lpobj->hwnd, (LPRECT)NULL, TRUE);
+ UpdateWindow (lpobj->hwnd);
+ fDocChanged = TRUE;
+ if (docMain.doctype == doctypeFromFile)
+ // If object is linked, update it in client now.
+ SendObjMsg (lpobj, OLE_CHANGED);
+ break;
+
+ /* Edit menu */
+
+ case IDM_COPY:
+ CutOrCopyObj (TRUE);
+ break;
+
+ case IDM_CUT:
+ CutOrCopyObj (FALSE);
+ // Fall through.
+
+ case IDM_DELETE:
+ RevokeObj (SelectedObject());
+ DestroyWindow (SelectedObjectWindow());
+ UpdateObjMenus();
+ break;
+
+ /* Object menu */
+
+ case IDM_NEXTOBJ:
+ lpobj = SelectedObject();
+ /* The 1 in the second parameter puts the current window
+ at the bottom of the current window list. */
+ SetWindowPos(lpobj->hwnd, (HANDLE)1, 0,0,0,0,
+ SWP_NOMOVE | SWP_NOSIZE);
+ break;
+
+ case IDM_NEWOBJ:
+ lpobj = CreateNewObj (TRUE);
+ BringWindowToTop(lpobj->hwnd);
+ break;
+
+ default:
+ ErrorBox ("Unknown Command.");
+ break;
+ }
+ break;
+ }
+
+ case WM_NCCALCSIZE:
+ if (!IsIconic(hwnd) && !IsZoomed(hwnd))
+ {
+ dimsCurrent.nX = ((LPRECT)lParam)->left;
+ dimsCurrent.nWidth = ((LPRECT)lParam)->right - dimsCurrent.nX;
+ dimsCurrent.nY = ((LPRECT)lParam)->top;
+ dimsCurrent.nHeight = ((LPRECT)lParam)->bottom - dimsCurrent.nY;
+ }
+ return DefWindowProc(hwnd, message, wParam, lParam);
+ break;
+
+ case WM_QUERYENDSESSION:
+ {
+ BOOL fUpdateLater;
+
+ if (SaveChangesOption(&fUpdateLater) == IDCANCEL)
+ return FALSE;
+
+ if (fUpdateLater)
+ {
+ // The non-standard OLE client did not accept the update
+ // when we requested it, so we are sending the client
+ // OLE_CLOSED now that we are closing the document.
+ SendDocMsg (OLE_CLOSED);
+ }
+ return TRUE;
+ }
+
+ case WM_CLOSE:
+ {
+ BOOL fUpdateLater;
+
+ if (SaveChangesOption(&fUpdateLater) != IDCANCEL)
+ ExitApplication(fUpdateLater);
+ break;
+ }
+
+ default:
+ return DefWindowProc(hwnd, message, wParam, lParam);
+ }
+ return 0;
+}
+
+
+
+/* About
+ * -----
+ *
+ * "About Box" dialog handler.
+ *
+ * CUSTOMIZATION: None
+ *
+ */
+BOOL APIENTRY About (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ switch (message)
+ {
+ case WM_INITDIALOG:
+ return TRUE;
+
+ case WM_COMMAND:
+ {
+ WORD wID = LOWORD(wParam);
+
+ if (wID == IDOK || wID == IDCANCEL)
+ {
+ EndDialog(hDlg, TRUE);
+ return TRUE;
+ }
+ break;
+ }
+ }
+ return FALSE;
+}
+
+
+
+
+/* ObjWndProc
+ * ----------
+ *
+ * Message handler for the object windows.
+ *
+ *
+ * CUSTOMIZATION: Server Demo specific
+ *
+ */
+LONG APIENTRY ObjWndProc
+ (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ static BOOL fCapture = FALSE;
+ static struct {RECT rect; POINT pt;} drag;
+ static RECT rectMain;
+
+ switch (message)
+ {
+ case WM_CREATE:
+ {
+ LPOBJ lpobj;
+ LPCREATESTRUCT lpcs;
+ // The call to CreateWindow puts lpobj into lpCreateParams
+ lpcs = (LPCREATESTRUCT) lParam;
+ lpobj = (LPOBJ) lpcs->lpCreateParams;
+ // Associate the window just created with the object.
+ lpobj->hwnd = hwnd;
+ /* Store pointer to object in the window structure. */
+ SetWindowLong(hwnd, ibLpobj, (LONG) lpobj);
+ UpdateObjMenus ();
+ break;
+ }
+ case WM_SIZE:
+ {
+ RECT rect;
+ if (fWaitingForDocRelease)
+ {
+ ErrorBox ("Waiting for a document to be revoked.\n\rPlease wait.");
+ return 0;
+ }
+ // Get coordinates of object relative to main window's client area.
+ GetWindowRect (hwnd, (LPRECT)&rect);
+ ScreenToClient (hwndMain, (LPPOINT)&rect);
+ ScreenToClient (hwndMain, (LPPOINT)&rect.right);
+ SizeObj (hwnd, rect, TRUE);
+ // Fall through.
+ }
+ case WM_PAINT:
+ PaintObj (hwnd);
+ break;
+
+ case WM_LBUTTONDOWN:
+ if (fWaitingForDocRelease)
+ {
+ ErrorBox ("Waiting for a document to be revoked.\n\rPlease wait.");
+ return 0;
+ }
+ BringWindowToTop (hwnd);
+
+ GetWindowRect (hwnd, (LPRECT) &drag.rect);
+ ScreenToClient (hwndMain, (LPPOINT)&drag.rect.left);
+ ScreenToClient (hwndMain, (LPPOINT)&drag.rect.right);
+
+ drag.pt.x = LOWORD(lParam);
+ drag.pt.y = HIWORD(lParam);
+
+ // Convert drag.pt to the main window's client coordinates.
+ ClientToScreen (hwnd, (LPPOINT)&drag.pt);
+ ScreenToClient (hwndMain, (LPPOINT)&drag.pt);
+
+ // Remember the coordinates of the main window so we do not drag
+ // an object outside the main window.
+ GetClientRect (hwndMain, (LPRECT) &rectMain);
+
+ SetCapture (hwnd);
+ fCapture = TRUE;
+ break;
+
+ case WM_MOUSEMOVE:
+ {
+ HDC hdc;
+ POINT pt;
+
+ if (!fCapture)
+ break;
+
+ fDocChanged = TRUE;
+ pt.x = LOWORD(lParam);
+ pt.y = HIWORD(lParam);
+
+ // Convert pt to the main window's client coordinates.
+ ClientToScreen (hwnd, (LPPOINT)&pt);
+ ScreenToClient (hwndMain, (LPPOINT)&pt);
+
+ if (!PtInRect (&rectMain, pt))
+ break;
+
+ hdc = GetDC(hwndMain);
+
+ // Erase old drag rectangle
+ InvertRect (hdc, (LPRECT)&drag.rect);
+
+ // Update drag.rect
+ OffsetRect (&drag.rect, pt.x - drag.pt.x, pt.y - drag.pt.y);
+
+ // Update drag.pt
+ drag.pt.x = pt.x;
+ drag.pt.y = pt.y;
+
+ // Show new drag rectangle
+ InvertRect (hdc, (LPRECT)&drag.rect);
+ ReleaseDC (hwndMain, hdc);
+ break;
+ }
+
+ case WM_LBUTTONUP:
+ {
+ LPOBJ lpobj;
+ if (!fCapture)
+ return TRUE;
+
+ fCapture = FALSE;
+ ReleaseCapture ();
+
+ MoveWindow (hwnd, drag.rect.left, drag.rect.top,
+ drag.rect.right - drag.rect.left,
+ drag.rect.bottom - drag.rect.top, TRUE);
+ InvalidateRect (hwnd, (LPRECT)NULL, TRUE);
+ lpobj = HwndToLpobj (hwnd);
+ lpobj->native.nX = drag.rect.left;
+ lpobj->native.nY = drag.rect.top;
+ break;
+ }
+ case WM_DESTROY:
+ DestroyObj (hwnd);
+ return DefWindowProc(hwnd, message, wParam, lParam);
+
+ default:
+ return DefWindowProc(hwnd, message, wParam, lParam);
+ }
+ return 0;
+}
+
+
+
+/* DeviceToHiMetric
+ * ----------------
+ *
+ * Converts a point from device units to HiMetric units.
+ * This function is designed to be generic enough to be reused.
+ *
+ * HWND hwnd - The window whose display context is to be used
+ * LPPOINT lppt - The point to be converted.
+ *
+ * CUSTOMIZATION: None
+ *
+ */
+void DeviceToHiMetric ( LPPOINT lppt)
+{
+ lppt->x = MulDiv (lppt->x, HIMETRIC_PER_INCH, giXppli);
+ lppt->y = MulDiv (lppt->y, HIMETRIC_PER_INCH, giYppli);
+}
+
+
+/* UpdateFileMenu
+ * --------------
+ *
+ * Updates the "Update <Client doc>" and "Exit & Return to <Client doc>"
+ * with the currently set client document name
+ *
+ * CUSTOMIZATION: Re-implement
+ *
+ */
+VOID UpdateFileMenu (INT iSaveUpdateId)
+{
+ CHAR str[cchFilenameMax];
+ HMENU hMenu = GetMenu(hwndMain);
+
+ /* Change File menu so it contains "Update" instead of "Save". */
+
+ lstrcpy (str, "&Update ");
+ lstrcat (str, szClientDoc);
+ ModifyMenu(hMenu, iSaveUpdateId, MF_BYCOMMAND|MF_STRING, IDM_UPDATE, str);
+
+ /* Change File menu so it contains "Exit & Return to <client doc>" */
+ /* instead of just "Exit" */
+
+ lstrcpy (str, "E&xit && Return to ");
+ lstrcat (str, szClientDoc);
+ ModifyMenu(hMenu, IDM_EXIT, MF_BYCOMMAND|MF_STRING, IDM_EXIT, str);
+}
+
+
+
+/* EmbeddingModeOn
+ * ---------------
+ *
+ * Do whatever is necessary for the application to start "embedding mode."
+ *
+ * CUSTOMIZATION: Re-implement
+ *
+ */
+VOID EmbeddingModeOn(VOID)
+{
+ HMENU hMenu = GetMenu(hwndMain);
+
+ UpdateFileMenu (IDM_SAVE);
+
+ /* Change File menu so it contains "Save Copy As..." instead of */
+ /* "Save As..." */
+ ModifyMenu(hMenu, IDM_SAVEAS, MF_BYCOMMAND|MF_STRING, IDM_SAVEAS,
+ "Save Copy As..");
+
+ /* In embedded mode, the user can edit only the embedded object, not
+ create new ones. */
+ EnableMenuItem(hMenu, menuposObject, MF_BYPOSITION | MF_GRAYED);
+ EnableMenuItem(hMenu, IDM_CUT, MF_BYCOMMAND | MF_GRAYED);
+ EnableMenuItem(hMenu, IDM_DELETE, MF_BYCOMMAND | MF_GRAYED);
+ DrawMenuBar (hwndMain);
+}
+
+
+
+
+/* EmbeddingModeOff
+ * ----------------
+ *
+ * Do whatever is necessary for the application to end "embedding mode."
+ *
+ * CUSTOMIZATION: Re-implement
+ *
+ */
+VOID EmbeddingModeOff (VOID)
+{
+ HMENU hMenu = GetMenu(hwndMain);
+
+ /* Change File menu so it contains "Save" instead of "Update". */
+ ModifyMenu(hMenu, IDM_UPDATE, MF_BYCOMMAND | MF_STRING, IDM_SAVE, "&Save");
+ /* Change File menu so it contains "Exit & Return to <client doc>" */
+ /* instead of just "Exit" */
+ ModifyMenu(hMenu, IDM_EXIT, MF_BYCOMMAND | MF_STRING, IDM_EXIT, "E&xit");
+
+ /* Change File menu so it contains "Save As..." instead of */
+ /* "Save Copy As..." */
+ ModifyMenu(hMenu, IDM_SAVEAS, MF_BYCOMMAND|MF_STRING, IDM_SAVEAS,
+ "Save &As..");
+
+ /* In non-embedded mode, the user can create new objects. */
+ EnableMenuItem(hMenu, menuposObject, MF_BYPOSITION | MF_ENABLED);
+
+ lstrcpy (szClientDoc, "Client Document");
+ DrawMenuBar (hwndMain);
+}
+
+
+
+/* ErrorBox
+ * --------
+ *
+ * char *szMessage - String to display inside message box.
+ *
+ * CUSTOMIZATION: Server Demo specific
+ *
+ */
+VOID ErrorBox (CHAR *szMessage)
+{
+ MessageBox (hwndMain, szMessage, szAppName, MB_OK);
+}
+
+
+
+/* GetWord
+ * -------
+ *
+ * LPSTR *plpszSrc - Pointer to a 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.
+ * When done, *plpszSrc will point to the character after the word.
+ *
+ * CUSTOMIZATION: Server Demo specific
+ *
+ */
+static VOID GetWord (LPSTR *plpszSrc, LPSTR lpszDst)
+{
+ INT i = 0;
+ while (**plpszSrc && **plpszSrc != ' ')
+ {
+ lpszDst[i++] = *(*plpszSrc)++;
+ }
+ lpszDst[i] = '\0';
+}
+
+
+
+/* HiMetricToDevice
+ * ----------------
+ *
+ * Converts a point from HiMetric units to device units.
+ * This function is designed to be generic enough to be reused.
+ *
+ * HWND hwnd - The window whose display context is to be used
+ * LPPOINT lppt - The point to be converted.
+ *
+ * CUSTOMIZATION: None
+ *
+ */
+void HiMetricToDevice ( LPPOINT lppt )
+{
+ lppt->x = MulDiv (giXppli, lppt->x, HIMETRIC_PER_INCH);
+ lppt->y = MulDiv (giYppli, lppt->y, HIMETRIC_PER_INCH);
+}
+
+
+
+/* HwndToLpobj
+ * -----------
+ *
+ * Given an object's window, return a pointer to the object.
+ * The GetWindowLong call extracts an LPOBJ from the extra data stored with
+ * the window.
+ *
+ * HWND hwndObj - Handle to the object's window
+ *
+ * RETURNS: A pointer to the object
+ *
+ * CUSTOMIZATION: Server Demo specific
+ *
+ */
+LPOBJ HwndToLpobj (HWND hwndObj)
+{
+ return (LPOBJ) GetWindowLong (hwndObj, ibLpobj);
+}
+
+
+
+/* CreateUntitledDoc
+ * -----------------
+ *
+ * Create a fresh document with one object.
+ *
+ * RETURNS: TRUE if successful
+ * FALSE otherwise
+ *
+ * CUSTOMIZATION: Re-implement
+ *
+ */
+static BOOL CreateUntitledDoc (INT nCmdShow)
+{
+ if (!CreateNewDoc (0, "(Untitled)", doctypeNew))
+ return FALSE;
+ CreateNewObj (FALSE);
+ ShowWindow(hwndMain, nCmdShow);
+ UpdateWindow(hwndMain);
+ return TRUE;
+}
+
+
+/* ProcessCmdLine
+ * --------------
+ *
+ * Parses the Windows command line which was passed to WinMain.
+ *
+ * Case One: SrvrDemo.exe
+ * fEmbedding = FALSE
+ * Create an untitled document.
+ *
+ * Case two: SrvrDemo.exe filename
+ * fEmbedding = FALSE
+ * Create a new document from the file.
+ *
+ * Case three: SrvrDemo.exe -Embedding
+ * fEmbedding = TRUE
+ * Do not create or register a document.
+ * Do not show window until client requests it.
+ *
+ * Case four: SrvrDemo.exe -Embedding filename
+ * fEmbedding = TRUE
+ * Load file.
+ * Call OleRegisterServerDoc.
+ * Do not show window until client requests it.
+ *
+ *
+ * LPSTR lpszLine - The Windows command line
+ * int nCmdShow - Parameter to WinMain
+ * HWND hwndMain - The application's main window
+ *
+ * RETURNS: TRUE if the command line was processed correctly.
+ * FALSE if a filename was specified which did not
+ * contain a proper document.
+ *
+ * CUSTOMIZATION: None.
+ *
+ */
+
+static BOOL ProcessCmdLine (LPSTR lpszLine, HWND hwndMain)
+{
+ CHAR szBuf[cchFilenameMax];
+ BOOL fEmbedding = FALSE; // Is "-Embedding" on the command line?
+ INT i=0;
+ OFSTRUCT of;
+
+ if (!*lpszLine) // No filename or options, so start a fresh document.
+ {
+ return CreateUntitledDoc(SW_SHOWNORMAL);
+ }
+
+ SkipBlanks (&lpszLine);
+
+ // Check for "-Embedding" or "/Embedding" and set fEmbedding.
+ if(*lpszLine == '-' || *lpszLine == '/')
+ {
+ lpszLine++;
+ GetWord (&lpszLine, szBuf);
+ fEmbedding = !lstrcmp(szBuf, szEmbeddingFlag);
+ }
+
+ SkipBlanks (&lpszLine);
+
+ if (*lpszLine) // if there is a filename
+ {
+ // Put filename into szBuf.
+ GetWord (&lpszLine, szBuf);
+
+ if (-1 == OpenFile(szBuf, &of, OF_READ | OF_EXIST))
+ {
+ // File not found
+ if (fEmbedding)
+ return FALSE;
+ else
+ {
+ CHAR sz[100];
+ wsprintf (sz, "File %s not found.", (LPSTR) szBuf);
+ ErrorBox (sz);
+ return CreateUntitledDoc(SW_SHOWNORMAL);
+ }
+ }
+
+ if (!CreateDocFromFile (szBuf, 0, doctypeFromFile))
+ {
+ // File not in proper format.
+ if (fEmbedding)
+ return FALSE;
+ else
+ {
+ CHAR sz[100];
+ wsprintf (sz, "File %s not in proper format.", (LPSTR) szBuf);
+ ErrorBox (sz);
+ return CreateUntitledDoc(SW_SHOWNORMAL);
+ }
+ }
+ }
+
+ if (fEmbedding)
+ {
+ /* Do not show window until told to do so by client. */
+ ShowWindow(hwndMain, SW_HIDE);
+ }
+ else
+ {
+ ShowWindow(hwndMain, SW_SHOWNORMAL);
+ UpdateWindow(hwndMain);
+ }
+ return TRUE;
+}
+
+
+
+/* SaveDimensions
+ * --------------
+ *
+ * Save the dimensions of the main window in a private profile file.
+ *
+ * CUSTOMIZATION: This function may be removed. If you wish to support
+ * intelligent window placement, then the only necessary
+ * change is to change the string "SrvrDemo.Ini" to a filename
+ * appropriate for your application.
+ */
+static VOID SaveDimensions (VOID)
+{
+ if ((dimsCurrent.nX != dimsSaved.nX) ||
+ (dimsCurrent.nY != dimsSaved.nY) ||
+ (dimsCurrent.nWidth != dimsSaved.nWidth) ||
+ (dimsCurrent.nHeight != dimsSaved.nHeight) )
+ {
+ // Save current window dimensions to private profile.
+ CHAR szBuf[7];
+ wsprintf (szBuf, "%d", dimsCurrent.nX);
+ WritePrivateProfileString
+ (szAppName, "x", szBuf, "SrvrDemo.Ini");
+ wsprintf (szBuf, "%d", dimsCurrent.nY);
+ WritePrivateProfileString
+ (szAppName, "y", szBuf, "SrvrDemo.Ini");
+ wsprintf (szBuf, "%d", dimsCurrent.nWidth);
+ WritePrivateProfileString
+ (szAppName, "w", szBuf, "SrvrDemo.Ini");
+ wsprintf (szBuf, "%d", dimsCurrent.nHeight);
+ WritePrivateProfileString
+ (szAppName, "h", szBuf, "SrvrDemo.Ini");
+ }
+}
+
+
+
+/* SelectedObject
+ * --------------
+ *
+ * Return a pointer to the currently selected object.
+ *
+ * CUSTOMIZATION: What a "selected object" is will vary from application
+ * to application. You may find it useful to have a function
+ * like this. In your application it may be necessary to
+ * actually create an OBJ structure based on what data the
+ * user has selected from the document (by highlighting some
+ * text for example).
+ *
+ */
+LPOBJ SelectedObject (VOID)
+{
+ return HwndToLpobj (SelectedObjectWindow());
+}
+
+
+
+
+/* SelectedObjectWindow
+ * --------------------
+ *
+ * Return a handle to the window for the currently selected object.
+ * The GetWindow calls returns a handle to the main window's first child,
+ * which is the selected object's window.
+ *
+ * CUSTOMIZATION: Server Demo specific
+ *
+ */
+HWND SelectedObjectWindow (VOID)
+{
+ return GetWindow (hwndMain, GW_CHILD);
+}
+
+
+
+/* SetHiMetricFields
+ * -----------------
+ *
+ * Adjust the nHiMetricWidth and nHiMetricHeight fields of a NATIVE structure
+ * so that they are equivalent to the nWidth and nHeight fields.
+ * The negative sign in the last line is necessary because the positive
+ * y direction is toward the top of the screen in MM_HIMETRIC mode.
+ *
+ * LPOBJ lpobj - Pointer to the object whose native data will be adjusted
+ *
+ * CUSTOMIZATION: Server Demo specific, although you may need a function like
+ * this if you keep track of the size of an object, and an
+ * object handler needs to know the object's size in
+ * HiMetric units.
+ *
+ *
+ */
+VOID SetHiMetricFields (LPOBJ lpobj)
+{
+ POINT pt;
+
+ pt.x = lpobj->native.nWidth;
+ pt.y = lpobj->native.nHeight;
+ DeviceToHiMetric ( &pt);
+ lpobj->native.nHiMetricWidth = pt.x;
+ lpobj->native.nHiMetricHeight = pt.y;
+}
+
+
+
+/* SkipBlanks
+ * ----------
+ *
+ * LPSTR *plpsz - Pointer to a pointer to a character
+ *
+ * Increment *plpsz past any blanks in the character string.
+ * This function is used in ProcessCmdLine.
+ *
+ */
+static VOID SkipBlanks (LPSTR *plpsz)
+{
+ while (**plpsz && **plpsz == ' ')
+ (*plpsz)++;
+}
+
+
+
+/* UpdateObjMenus
+ * ---------------
+ *
+ * Grey or Ungrey menu items depending on the existence of at least one
+ * object in the document.
+ *
+ * CUSTOMIZATION: Server Demo specific
+ *
+ */
+static VOID UpdateObjMenus (VOID)
+{
+ static BOOL fObjMenusEnabled = TRUE;
+ BOOL fOneObjExists; // Does at least one object exist?
+ WORD wEnable;
+ HMENU hMenu;
+
+ fOneObjExists = (SelectedObjectWindow() != NULL);
+ if (fOneObjExists == fObjMenusEnabled)
+ {
+ // Nothing has changed.
+ return;
+ }
+
+ wEnable = (WORD)(fOneObjExists ? MF_ENABLED : MF_GRAYED);
+
+ hMenu = GetMenu(hwndMain);
+ EnableMenuItem(hMenu, menuposColor, MF_BYPOSITION | wEnable);
+
+ hMenu = GetSubMenu(GetMenu(hwndMain), menuposFile);
+ EnableMenuItem(hMenu, IDM_SAVE, MF_BYCOMMAND | wEnable);
+ EnableMenuItem(hMenu, IDM_SAVEAS, MF_BYCOMMAND | wEnable);
+
+ hMenu = GetSubMenu(GetMenu(hwndMain), menuposEdit);
+ EnableMenuItem(hMenu, IDM_CUT, MF_BYCOMMAND | wEnable);
+ EnableMenuItem(hMenu, IDM_COPY, MF_BYCOMMAND | wEnable);
+ EnableMenuItem(hMenu, IDM_DELETE, MF_BYCOMMAND | wEnable);
+
+ hMenu = GetSubMenu(GetMenu(hwndMain), menuposObject);
+ EnableMenuItem(hMenu, IDM_NEXTOBJ, MF_BYCOMMAND | wEnable);
+
+ DrawMenuBar (hwndMain);
+ fObjMenusEnabled = fOneObjExists;
+}
+
+
+
+/* Wait
+ * ----
+ *
+ * Dispatch messages until the given flag is set to FALSE.
+ * One use of this function is to wait until a Release method is called
+ * after a function has returned OLE_WAIT_FOR_RELEASE.
+ *
+ * BOOL *pf - Pointer to the flag being waited on.
+ *
+ * CUSTOMIZATION: The use of OleUnblockServer is for illustration only.
+ * Since Server Demo does not call OleBlockServer, there
+ * will never be any messages in the OLE queue.
+ *
+ */
+VOID Wait (BOOL *pf)
+{
+ MSG msg;
+ BOOL fMoreMsgs = FALSE;
+
+ *pf = TRUE;
+ while (*pf==TRUE)
+ {
+ OleUnblockServer (srvrMain.lhsrvr, &fMoreMsgs);
+ if (!fMoreMsgs)
+ // if there are no more messages in the OLE queue, go to system queue
+ {
+ if (GetMessage (&msg, NULL, 0, 0))
+ {
+ TranslateMessage (&msg);
+ DispatchMessage (&msg);
+ }
+ }
+ }
+}
+
+static BOOL FailedUpdate(HWND hwnd)
+{
+
+ return(DialogBox(hInst, "FailedUpdate", hwnd, (DLGPROC)fnFailedUpdate));
+
+}
+
+BOOL APIENTRY fnFailedUpdate (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
+{
+
+ switch (message)
+ {
+ case WM_COMMAND:
+ {
+ WORD wID = LOWORD(wParam);
+
+ switch (wID)
+ {
+ case IDCANCEL:
+ case IDD_CONTINUEEDIT:
+ EndDialog(hDlg, TRUE);
+ break;
+
+ case IDD_UPDATEEXIT:
+ EndDialog(hDlg, FALSE);
+ break;
+
+ default:
+ break;
+ }
+ break;
+ }
+
+ case WM_INITDIALOG:
+ {
+ CHAR szMsg[200];
+
+ szMsg[0] = '\0';
+
+ wsprintf(
+ szMsg,
+ "This %s document can only be updated when you exit %s.",
+ (LPSTR) szClient,
+ (LPSTR) szAppName
+ );
+
+ SetDlgItemText(hDlg, IDD_TEXT, szMsg);
+ return TRUE;
+ }
+
+ default:
+ break;
+ }
+
+ return FALSE;
+}
+
+
+
+
diff --git a/private/oleutest/ole1/srvrdemo/srvrdemo.def b/private/oleutest/ole1/srvrdemo/srvrdemo.def
new file mode 100644
index 000000000..b249f42ad
--- /dev/null
+++ b/private/oleutest/ole1/srvrdemo/srvrdemo.def
@@ -0,0 +1,56 @@
+; SrvrDemo.def
+; OLE SERVER DEMO
+;
+; The module-definition file.
+;
+; (c) Copyright Microsoft Corp. 1991 - 1992 All Rights Reserved
+
+
+NAME SrvrDemo
+
+DESCRIPTION 'Microsoft OLE Server Demonstration'
+
+EXETYPE WINDOWS
+
+STUB 'WINSTUB.EXE'
+
+CODE PRELOAD MOVEABLE DISCARDABLE
+DATA PRELOAD MOVEABLE MULTIPLE
+
+HEAPSIZE 1000
+STACKSIZE 16000
+
+EXPORTS
+ About @1
+ MainWndProc @2
+ ObjWndProc @3
+
+ SrvrCreate @4
+ SrvrCreateFromTemplate @5
+ SrvrEdit @6
+ SrvrExecute @7
+ SrvrExit @8
+ SrvrOpen @9
+ SrvrRelease @10
+
+ DocClose @11
+ DocExecute @12
+ DocGetObject @13
+ DocRelease @14
+ DocSave @15
+ DocSetColorScheme @16
+ DocSetDocDimensions @17
+ DocSetHostNames @18
+
+ ObjDoVerb @19
+ ObjEnumFormats @20
+ ObjGetData @21
+ ObjQueryProtocol @22
+ ObjRelease @23
+ ObjSetBounds @24
+ ObjSetColorScheme @25
+ ObjSetData @26
+ ObjSetTargetDevice @27
+ ObjShow @28
+
+ fnFailedUpdate @29
diff --git a/private/oleutest/ole1/srvrdemo/srvrdemo.h b/private/oleutest/ole1/srvrdemo/srvrdemo.h
new file mode 100644
index 000000000..2f4dfb6e4
--- /dev/null
+++ b/private/oleutest/ole1/srvrdemo/srvrdemo.h
@@ -0,0 +1,333 @@
+/*
+ OLE SERVER DEMO
+ SrvrDemo.h
+
+ This file contains typedefs, defines, global variable declarations, and
+ function prototypes.
+
+ (c) Copyright Microsoft Corp. 1990 - 1992 All Rights Reserved
+*/
+
+
+
+/*
+ Explanation of Function Comments.
+
+ Every function has a comment preceding it which gives the following
+ information:
+
+ 1) Function name.
+ 2) A description of what the function does.
+ 3) A list of parameters, each with its type and a short description.
+ 4) A list of return values, each with an explanation of the condition that
+ will cause the function to return that value.
+ 5) A customization section giving tips on how to customize this function
+ for your OLE application.
+ If the customization section says "None" then you may find the function
+ usable as is.
+ If the customization section says "Re-implement" then the function
+ should still serve the same purpose and do what is indicated in the
+ function comment, but will probably need to be re-implemented for
+ your particular application. Any Server Demo code relating to OLE
+ will be useful as a guide in your re-implementation.
+ If the customization section says "Server Demo specific" then the
+ function will probably have no counterpart in your application.
+*/
+
+
+/* Menu Identifiers */
+
+// File menu
+
+#define IDM_NEW 100
+#define IDM_OPEN 101
+#define IDM_SAVE 102
+#define IDM_SAVEAS 103
+#define IDM_EXIT 104
+#define IDM_ABOUT 105
+#define IDM_UPDATE 106
+
+// Edit menu
+
+#define IDM_CUT 107
+#define IDM_COPY 108
+#define IDM_DELETE 109
+
+// Color menu
+
+#define IDM_RED 110
+#define IDM_GREEN 111
+#define IDM_BLUE 112
+#define IDM_WHITE 113
+#define IDM_GRAY 114
+#define IDM_CYAN 115
+#define IDM_MAGENTA 116
+#define IDM_YELLOW 117
+
+// New object menu
+
+#define IDM_NEWOBJ 118
+#define IDM_NEXTOBJ 119
+
+#define IDD_CONTINUEEDIT 120
+#define IDD_UPDATEEXIT 121
+#define IDD_TEXT 122
+
+#define OBJECT_WIDTH 120
+#define OBJECT_HEIGHT 60
+
+// number HIMETRIC units per inch
+#define HIMETRIC_PER_INCH 2540
+
+/* Types */
+
+// Document type
+
+typedef enum
+{
+ doctypeNew, // The document is untitled.
+ doctypeFromFile, // The document exists in a file and may be linked.
+ doctypeEmbedded // The document is an embedded document.
+} DOCTYPE;
+
+
+// Device context type, passed to DrawObj.
+
+typedef enum
+{
+ dctypeScreen,
+ dctypeBitmap,
+ dctypeMetafile,
+ dctypeEnhMetafile
+} DCTYPE ;
+
+
+// Version
+
+typedef WORD VERSION;
+
+
+// Verb
+
+typedef enum
+{
+ verbPlay = OLEVERB_PRIMARY,
+ verbEdit
+} VERB;
+
+
+// Server structure
+
+typedef struct
+{
+ OLESERVER olesrvr; // This must be the first field so that
+ // an LPOLESERVER can be cast to a SRVR*.
+ LHSERVER lhsrvr; // Registration handle
+} SRVR ;
+
+
+// How many objects (distinct numbers) will we allow?
+#define cfObjNums 20
+
+// How many distinct clients can be associated with the object?
+#define clpoleclient 20
+
+
+// Document structure
+
+typedef struct
+{
+ OLESERVERDOC oledoc; // This must be the first field so that an
+ // LPOLESERVERDOC can be cast to an DOC*.
+ LHSERVERDOC lhdoc; // Registration handle
+ DOCTYPE doctype; // Document type
+ ATOM aName; // Document name
+ HPALETTE hpal; // Handle to a logical color palette
+ BYTE rgfObjNums[cfObjNums+1]; // What object numbers have been used
+} DOC, *DOCPTR ;
+
+
+// Native data structure
+
+typedef struct
+{
+ INT idmColor;
+ INT nWidth;
+ INT nHeight;
+ INT nX;
+ INT nY;
+ INT nHiMetricWidth; // Used by an object handler. These two fields
+ INT nHiMetricHeight; // always correspond to nWidth and nHeight.
+ VERSION version;
+ CHAR szName[10]; // "Object nn"
+} NATIVE, FAR *LPNATIVE;
+
+
+// Object structure
+
+/* Ordinarily, an OBJ structure would not contain native data. Rather, it
+ would contain a pointer (or some other reference) to the native data.
+ This method would allow multiple objects containing the same native data.
+ Each OBJ structure would be created on the fly when some portion of the
+ document was to be made into an object. Each OBJ structure would have
+ only one LPOLECLIENT, which would be passed in to DocGetObject.
+*/
+
+typedef struct
+{
+ OLEOBJECT oleobject; // This must be the first field so that an
+ // LPOLEOBJECT can be cast to a LPOBJ.
+ HANDLE hObj; // A circular handle to this structure,
+ // used to delete this structure.
+ LPOLECLIENT lpoleclient[clpoleclient];
+ // Clients associated with the object.
+ // The array is NULL terminated.
+ HWND hwnd; // The object's own window
+ ATOM aName; // Unique identifier for each object within a doc
+ HPALETTE hpal; // Logical palette to use in drawing object
+ NATIVE native; // Object data in native format
+} OBJ, FAR *LPOBJ ;
+
+typedef struct {
+ CHAR *pClassName;
+ CHAR *pFileSpec;
+ CHAR *pHumanReadable;
+ CHAR *pExeName;
+} CLASS_STRINGS;
+
+
+
+/* Defines */
+
+// The name of the application, used in message boxes and title bars.
+#define szAppName "Server Demo10"
+
+// THe class name in the registration database.
+#define szClassName "SrvrDemo10"
+
+// Used to check for "-Embedding" on command line.
+#define szEmbeddingFlag "Embedding"
+
+// Maximum length of a fully-qualified pathname.
+#define cchFilenameMax 256
+
+// Maximum number of HBRUSHes.
+#define chbrMax 9
+
+// Number of extra bytes in the window structure for an object
+#define cbWindExtra 4
+
+// Offset (in the extra space) of the pointer to the object
+#define ibLpobj 0
+
+
+
+/* Global variable declarations. (See SrvrDemo.c for descriptions.) */
+
+extern HANDLE hInst;
+extern HWND hwndMain;
+extern SRVR srvrMain;
+extern DOC docMain;
+extern BOOL fDocChanged;
+extern BOOL fEmbedding;
+extern BOOL fRevokeSrvrOnSrvrRelease;
+extern BOOL fWaitingForDocRelease;
+extern BOOL fWaitingForSrvrRelease;
+extern BOOL fUnblock;
+extern CHAR szClient[];
+extern CHAR szClientDoc[];
+extern HBRUSH hbrColor[chbrMax];
+extern VERSION version;
+extern OLECLIPFORMAT cfObjectLink;
+extern OLECLIPFORMAT cfOwnerLink;
+extern OLECLIPFORMAT cfNative;
+extern OLESERVERDOCVTBL docvtbl;
+extern OLEOBJECTVTBL objvtbl;
+extern OLESERVERVTBL srvrvtbl;
+
+
+
+/* Function Prototypes */
+
+// Various functions
+
+BOOL CreateDocFromFile (LPSTR lpszDoc, LHSERVERDOC lhdoc, DOCTYPE doctype);
+BOOL CreateNewDoc (LONG lhdoc, LPSTR lpszDoc, DOCTYPE doctype);
+LPOBJ CreateNewObj (BOOL fDoc_Changed);
+VOID CutOrCopyObj (BOOL fOpIsCopy);
+VOID DestroyDoc (VOID);
+VOID DestroyObj (HWND hwnd);
+VOID DeviceToHiMetric ( LPPOINT lppt);
+VOID EmbeddingModeOff (VOID) ;
+VOID EmbeddingModeOn (VOID);
+VOID UpdateFileMenu (INT);
+VOID ErrorBox (CHAR *jwf);
+BOOL GetFileOpenFilename (LPSTR lpszFilename);
+BOOL GetFileSaveFilename (LPSTR lpszFilename);
+VOID HiMetricToDevice ( LPPOINT lppt);
+LPOBJ HwndToLpobj (HWND hwndObj);
+BOOL InitServer (HWND hwnd, HANDLE hInst);
+VOID InitVTbls (VOID);
+BOOL OpenDoc (VOID);
+VOID PaintObj (HWND hwnd);
+OLESTATUS RevokeDoc (VOID);
+VOID RevokeObj (LPOBJ lpobj);
+INT SaveChangesOption (BOOL *pfUpdateLater);
+BOOL SaveDoc (VOID);
+BOOL SaveDocAs (VOID);
+VOID SavedServerDoc (VOID);
+LPOBJ SelectedObject (VOID);
+HWND SelectedObjectWindow (VOID);
+VOID SendDocMsg (WORD wMessage );
+VOID SendObjMsg (LPOBJ lpobj, WORD wMessage);
+VOID SetTitle (LPSTR lpszDoc, BOOL bEmbedded);
+VOID SetHiMetricFields (LPOBJ lpobj);
+VOID SizeClientArea (HWND hwndMain, RECT rectReq, BOOL fFrame);
+VOID SizeObj (HWND hwnd, RECT rect, BOOL fMove);
+OLESTATUS StartRevokingServer (VOID);
+VOID Wait (BOOL *pf);
+LPSTR Abbrev (LPSTR lpsz);
+BOOL APIENTRY fnFailedUpdate (HWND, UINT, WPARAM, LONG);
+int Main(USHORT argc, CHAR **argv) ;
+
+// Window handlers
+
+BOOL APIENTRY About (HWND, UINT, WPARAM, LPARAM);
+LONG APIENTRY MainWndProc (HWND, UINT, WPARAM, LPARAM);
+LONG APIENTRY ObjWndProc (HWND, UINT, WPARAM, LPARAM);
+
+
+// Server methods
+
+OLESTATUS APIENTRY SrvrCreate (LPOLESERVER, LHSERVERDOC, OLE_LPCSTR, OLE_LPCSTR, LPOLESERVERDOC FAR *);
+OLESTATUS APIENTRY SrvrCreateFromTemplate (LPOLESERVER, LHSERVERDOC, OLE_LPCSTR, OLE_LPCSTR, OLE_LPCSTR, LPOLESERVERDOC FAR *);
+OLESTATUS APIENTRY SrvrEdit (LPOLESERVER, LHSERVERDOC, OLE_LPCSTR, OLE_LPCSTR, LPOLESERVERDOC FAR * );
+OLESTATUS APIENTRY SrvrExecute (LPOLESERVER, HANDLE);
+OLESTATUS APIENTRY SrvrExit (LPOLESERVER);
+OLESTATUS APIENTRY SrvrOpen (LPOLESERVER, LHSERVERDOC, OLE_LPCSTR, LPOLESERVERDOC FAR *);
+OLESTATUS APIENTRY SrvrRelease (LPOLESERVER);
+
+// Document methods
+
+OLESTATUS APIENTRY DocClose (LPOLESERVERDOC);
+OLESTATUS APIENTRY DocExecute (LPOLESERVERDOC, HANDLE);
+OLESTATUS APIENTRY DocGetObject (LPOLESERVERDOC, OLE_LPCSTR, LPOLEOBJECT FAR *, LPOLECLIENT);
+OLESTATUS APIENTRY DocRelease (LPOLESERVERDOC);
+OLESTATUS APIENTRY DocSave (LPOLESERVERDOC);
+OLESTATUS APIENTRY DocSetColorScheme (LPOLESERVERDOC, OLE_CONST LOGPALETTE FAR*);
+OLESTATUS APIENTRY DocSetDocDimensions (LPOLESERVERDOC, OLE_CONST RECT FAR *);
+OLESTATUS APIENTRY DocSetHostNames (LPOLESERVERDOC, OLE_LPCSTR, OLE_LPCSTR);
+
+// Object methods
+
+OLESTATUS APIENTRY ObjDoVerb (LPOLEOBJECT, UINT, BOOL, BOOL);
+OLESTATUS APIENTRY ObjGetData (LPOLEOBJECT, OLECLIPFORMAT, LPHANDLE);
+LPVOID APIENTRY ObjQueryProtocol (LPOLEOBJECT, OLE_LPCSTR);
+OLESTATUS APIENTRY ObjRelease (LPOLEOBJECT);
+OLESTATUS APIENTRY ObjSetBounds (LPOLEOBJECT, OLE_CONST RECT FAR*);
+OLESTATUS APIENTRY ObjSetColorScheme (LPOLEOBJECT, OLE_CONST LOGPALETTE FAR*);
+OLESTATUS APIENTRY ObjSetData (LPOLEOBJECT, OLECLIPFORMAT, HANDLE);
+OLESTATUS APIENTRY ObjSetTargetDevice (LPOLEOBJECT, HANDLE);
+OLESTATUS APIENTRY ObjShow (LPOLEOBJECT, BOOL);
+OLECLIPFORMAT APIENTRY ObjEnumFormats (LPOLEOBJECT, OLECLIPFORMAT);
+
diff --git a/private/oleutest/ole1/srvrdemo/srvrdemo.ico b/private/oleutest/ole1/srvrdemo/srvrdemo.ico
new file mode 100644
index 000000000..fb634e0f8
--- /dev/null
+++ b/private/oleutest/ole1/srvrdemo/srvrdemo.ico
Binary files differ
diff --git a/private/oleutest/ole1/srvrdemo/srvrdemo.rc b/private/oleutest/ole1/srvrdemo/srvrdemo.rc
new file mode 100644
index 000000000..635a637ed
--- /dev/null
+++ b/private/oleutest/ole1/srvrdemo/srvrdemo.rc
@@ -0,0 +1,74 @@
+
+#include "Windows.h"
+#include "SrvrDemo.h"
+
+DocIcon ICON SrvrDemo.Ico
+
+MainMenu MENU
+{
+ POPUP "&File"
+ {
+ MENUITEM "&New", IDM_NEW
+ MENUITEM "&Open...", IDM_OPEN
+ MENUITEM "&Save", IDM_SAVE
+ MENUITEM "Save &As...", IDM_SAVEAS
+ MENUITEM SEPARATOR
+ MENUITEM "E&xit", IDM_EXIT
+ MENUITEM SEPARATOR
+ MENUITEM "A&bout...", IDM_ABOUT
+ }
+
+ POPUP "&Edit"
+ {
+ MENUITEM "Cu&t\tShift+Del", IDM_CUT
+ MENUITEM "&Copy\tCtrl+Ins", IDM_COPY
+ MENUITEM "&Delete\tDel", IDM_DELETE
+ }
+
+ POPUP "&Color"
+ {
+ MENUITEM "&Red", IDM_RED
+ MENUITEM "&Green", IDM_GREEN
+ MENUITEM "&Blue", IDM_BLUE
+ MENUITEM "&White", IDM_WHITE
+ MENUITEM "Gr&ay", IDM_GRAY
+ MENUITEM "&Cyan", IDM_CYAN
+ MENUITEM "&Magenta", IDM_MAGENTA
+ MENUITEM "&Yellow", IDM_YELLOW
+ }
+
+ POPUP "&Object"
+ {
+ MENUITEM "&New", IDM_NEWOBJ
+ MENUITEM "Ne&xt", IDM_NEXTOBJ
+ }
+
+}
+
+Accelerators ACCELERATORS
+{
+ VK_DELETE, IDM_CUT, VIRTKEY, SHIFT
+ VK_INSERT, IDM_COPY, VIRTKEY, CONTROL
+ VK_DELETE, IDM_DELETE, VIRTKEY
+}
+
+AboutBox DIALOG 22, 17, 160, 75
+STYLE DS_MODALFRAME | WS_CAPTION | WS_SYSMENU
+CAPTION "About Server Demo"
+{
+ CTEXT "Microsoft Windows" -1, 0, 5, 160, 8
+ CTEXT "OLE 1.0 Server Test Application" -1, 0, 14, 160, 8
+ CTEXT "Version 1.0" -1, 0, 23, 160, 8
+ CTEXT "(c) Copyright Microsoft Corp. 1990 - 1992" -1, 0, 39, 160, 8
+ DEFPUSHBUTTON "OK" IDOK, 61, 59, 32, 14, WS_GROUP
+}
+
+FailedUpdate DIALOG 6, 18, 251, 63
+STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "Object Update"
+FONT 8, "Helv"
+BEGIN
+ DEFPUSHBUTTON "&Continue Editing", IDD_CONTINUEEDIT, 77, 36, 68, 14, WS_TABSTOP|WS_GROUP
+ PUSHBUTTON "Update && E&xit", IDD_UPDATEEXIT, 6, 36, 55, 14
+ LTEXT "Text", IDD_TEXT, 9, 9, 233, 20
+END
diff --git a/private/oleutest/olebind/daytona/makefile b/private/oleutest/olebind/daytona/makefile
new file mode 100644
index 000000000..1d3728d41
--- /dev/null
+++ b/private/oleutest/olebind/daytona/makefile
@@ -0,0 +1,10 @@
+############################################################################
+#
+# Copyright (C) 1992, Microsoft Corporation.
+#
+# All rights reserved.
+#
+############################################################################
+
+!include $(NTMAKEENV)\makefile.def
+
diff --git a/private/oleutest/olebind/daytona/sources b/private/oleutest/olebind/daytona/sources
new file mode 100644
index 000000000..56c9370da
--- /dev/null
+++ b/private/oleutest/olebind/daytona/sources
@@ -0,0 +1,77 @@
+!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:
+
+ Donna Liu (DonnaLi) 19-Dec-1993
+
+!ENDIF
+
+MAJORCOMP = cairole
+MINORCOMP = com
+
+#
+# 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= olebind
+
+#
+# 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
+
+DLLDEF= ..\olebind.def
+
+INCLUDES= ..\..\..\ole32\common\daytona;..\..\..\ole32\ih;..;..\..\common;..\..\..\cinc
+
+!include ..\..\daytona.inc
+
+C_DEFINES= \
+ $(C_DEFINES)
+
+
+SOURCES= \
+ ..\olebind.cxx \
+ ..\rot.cxx \
+ ..\tmoniker.cxx \
+ ..\tmalloc.cxx
+
+UMTYPE= console
+UMAPPL=
+UMTEST=
+UMLIBS= \
+ ..\..\assert\daytona\obj\*\assert.lib \
+ $(BASEDIR)\public\sdk\lib\*\ole32.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\*\crtdll.lib \
+ $(BASEDIR)\public\sdk\lib\*\uuid.lib
+
+USE_CRTDLL= 1
diff --git a/private/oleutest/olebind/dirs b/private/oleutest/olebind/dirs
new file mode 100644
index 000000000..1d0b9edbb
--- /dev/null
+++ b/private/oleutest/olebind/dirs
@@ -0,0 +1,38 @@
+!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/olebind/olebind.cxx b/private/oleutest/olebind/olebind.cxx
new file mode 100644
index 000000000..a46e8c232
--- /dev/null
+++ b/private/oleutest/olebind/olebind.cxx
@@ -0,0 +1,1154 @@
+//+---------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1993 - 1994.
+//
+// File: olebind.cxx
+//
+// Contents: Test OLE COM
+//
+// Classes:
+//
+// Functions: TestSetMoniker
+// ` DoTest
+// ConvertPath
+// CreateFile
+// CleanUpFiles
+// InitFiles
+// main
+//
+// History: 31-Dec-93 ErikGav Chicago port
+// 15-Nov-94 BruceMa Added this header
+// 15-Nov-94 BruceMa Make long file name test work on
+// Chicago
+// 11-Jan-95 BruceMa Chicago now use the NT alorithm for
+// short file names
+// 17-Jan-95 BruceMa Modify registry so olebind works on
+// Cairo when running multi-threaded
+//
+//----------------------------------------------------------------------
+
+#include <windows.h>
+#include "widewrap.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <io.h>
+
+#include <ole2.h>
+#include <com.hxx>
+#include "olebind.hxx"
+#include "tmoniker.h"
+#include <tchar.h>
+
+const char *szOleBindError = "OLEBIND - Fatal Error";
+char wszErrBuf[512];
+
+#pragma hdrstop
+
+BOOL SetRegistryThreadingModel(WCHAR *peszFile, WCHAR *pwszThreadingModel);
+BOOL ResetRegistryThreadingModel(WCHAR *pwszFile);
+
+#define FILE_SHARE_DELETE 0x00000004
+
+#define INPROC_PATH1 L"p1.ut1"
+#define INPROC_PATH2 L"p2.ut1"
+#define LOCAL_SERVER_PATH1 L"p1.ut2"
+#define LOCAL_SERVER_PATH2 L"p2.ut2"
+#define LOCAL_SERVER_PATH4 L"p2.ut4"
+
+WCHAR InprocPath1[MAX_PATH];
+WCHAR InprocPath2[MAX_PATH];
+WCHAR LocalServerPath1[MAX_PATH];
+WCHAR LocalServerPath2[MAX_PATH];
+WCHAR LocalServerPath4[MAX_PATH];
+
+#define LONG_SHORT_DIR L"\\LongDire"
+#define LONG_DIR L"\\LongDirectory"
+#define LONG_SHORT_NAME L"\\Short.Fil"
+#define LONG_LONG_NAME L"\\LongFileName.File"
+#define LONG_LONG_SHORT_EQUIV L"\\LongFi~1.Fil"
+
+WCHAR LongDir[MAX_PATH];
+WCHAR LongDirShort[MAX_PATH];
+WCHAR LongDirLong[MAX_PATH];
+WCHAR LongDirLongSe[MAX_PATH];
+
+// DON"T MODIFY THIS
+const DWORD dwRESERVED = 0l;
+
+// string version of process id
+WCHAR wszPid[10];
+
+
+int TestSetMoniker(IUnknown *punk)
+{
+ HRESULT hr;
+ XOleObject poleobject;
+ XMoniker pmk;
+ XMalloc pIMalloc;
+ XBindCtx pbc;
+
+
+ hr = punk->QueryInterface(IID_IOleObject, (void **) &poleobject);
+
+ // Create an item moniker to the object
+ hr = CreateItemMoniker(L"\\", L"1", &pmk);
+
+ TEST_FAILED_HR(FAILED(hr), "TestSetMoniker:CreateItemMoniker failed")
+
+ // Set the moniker
+ hr = poleobject->SetMoniker(OLEWHICHMK_CONTAINER, pmk);
+
+ TEST_FAILED_HR(FAILED(hr), "TestSetMoniker:SetMoniker failed")
+
+ pmk.Set(NULL);
+
+ // Get the moniker back
+ hr = poleobject->GetMoniker(OLEGETMONIKER_ONLYIFTHERE,
+ OLEWHICHMK_CONTAINER, &pmk);
+
+ TEST_FAILED_HR(FAILED(hr), "TestSetMoniker:GetMoniker failed")
+
+ // Get & Verify name is as expected
+ WCHAR *pwszName;
+
+
+ hr = CreateBindCtx(0, &pbc);
+
+ TEST_FAILED_HR(FAILED(hr),
+ "CreateBindCtx TestSetMoniker:GetDisplayName failed!")
+
+ hr = pmk->GetDisplayName(pbc, NULL, &pwszName);
+
+ TEST_FAILED_HR(FAILED(hr), "TestSetMoniker:GetDisplayName failed")
+
+ TEST_FAILED((wcscmp(pwszName, L"\\1") != 0),
+ "TestSetMoniker: Returned name mismatch!\n")
+
+ // Test OleIsRunning
+ hr = OleIsRunning(poleobject);
+
+ TEST_FAILED_HR(FAILED(hr), "OleIsRunning call failed")
+
+ // Free resources
+ hr = CoGetMalloc(MEMCTX_TASK, &pIMalloc);
+
+ TEST_FAILED_HR(FAILED(hr), "CoGetMalloc failed")
+
+ pIMalloc->Free(pwszName);
+
+ return 0;
+}
+
+static GUID CLSID_Invalid =
+ {0xfffffffe,0xffff,0xffff,{0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}};
+
+
+// prototypes for private entry points. These are here to support VB94.
+STDAPI CoGetState(IUnknown **ppUnkState);
+STDAPI CoSetState(IUnknown *pUnkState);
+
+int DoTest(
+ GUID guidToTest,
+ LPWSTR pszPath1,
+ LPWSTR pszPath2)
+{
+ XMoniker pmnk; // ptr to moniker
+ XUnknown pUnk;
+ XUnknown punk;
+ XUnknown pUnkTheSame;
+ XOleItemContainer poleitmcon;
+ XDispatch pdispatch;
+
+ XBindCtx pbc1;
+ XBindCtx pbc2;
+ XUnknown pUnkState1;
+ XUnknown pUnkState2;
+ XUnknown pUnkState3;
+ XUnknown pUnkState4;
+ XUnknown pUnkState5;
+
+ HRESULT hr;
+ DWORD grfOpt = 0;
+
+
+ // Test the private CoSetState/CoGetState APIs. We just need an
+ // IUnknown so we will use a BindCtx for this.
+
+ // test Set/Get
+ hr = CreateBindCtx(0, &pbc1);
+ TEST_FAILED_HR(FAILED(hr), "Create BindCtx 1 failed");
+ hr = pbc1->QueryInterface(IID_IUnknown, (void **)&pUnkState1);
+ TEST_FAILED_HR(FAILED(hr), "QI for IUnknown 1 failed.");
+
+ hr = CoSetState(pUnkState1);
+ TEST_FAILED_HR(hr != S_OK, "CoSetState failed.");
+
+ hr = CoGetState(&pUnkState2);
+ TEST_FAILED_HR(hr != S_OK, "CoGetState failed.");
+ if ((IUnknown *)pUnkState2 != (IUnknown *)pUnkState1)
+ TEST_FAILED(TRUE, "GetState returned wrong value.\n");
+
+
+ // test replacement
+ hr = CreateBindCtx(0, &pbc2);
+ TEST_FAILED_HR(FAILED(hr), "Create BindCtx 2 failed");
+ hr = pbc2->QueryInterface(IID_IUnknown, (void **)&pUnkState3);
+ TEST_FAILED_HR(FAILED(hr), "QI for IUnknown 2 failed.");
+
+ hr = CoSetState(pUnkState3);
+ TEST_FAILED_HR(hr != S_OK, "CoSetState failed.");
+
+ hr = CoGetState(&pUnkState4);
+ TEST_FAILED_HR(hr != S_OK, "CoGetState failed.");
+ if ((IUnknown *)pUnkState4 != (IUnknown *)pUnkState3)
+ TEST_FAILED(TRUE, "GetState returned wrong value.");
+
+
+ // test Set/Get NULL
+ hr = CoSetState(NULL);
+ TEST_FAILED_HR(hr != S_OK, "CoSetState NULL failed.");
+
+ hr = CoGetState(&pUnkState5);
+ TEST_FAILED_HR(hr != S_FALSE, "CoGetState NULL failed.");
+ if ((IUnknown *)pUnkState5 != NULL)
+ TEST_FAILED(TRUE, "GetState NULL returned wrong value.");
+
+
+
+
+ // Test for a bogus class
+ hr = CoGetClassObject(CLSID_Invalid, CLSCTX_SERVER, NULL,
+ IID_IClassFactory, (void **) &pUnk);
+
+ TEST_FAILED_HR(SUCCEEDED(hr),
+ "CoGetClassObject succeed on invalid class!");
+
+ // Bind to something that does not exist either in the registry
+ // or anywhere else.
+ hr = CreateFileMoniker(L"C:\\KKK.KKK", &pmnk);
+ hr = BindMoniker(pmnk, grfOpt, IID_IUnknown, (void **)&pUnk);
+ pmnk.Set(NULL);
+
+ TEST_FAILED_HR(SUCCEEDED(hr),
+ "Succeeded binding a moniker to a file that doesn't exist!");
+
+/*
+ * Create a file moniker to start with
+ */
+
+ hr = CreateFileMoniker(pszPath1, &pmnk);
+
+ TEST_FAILED_HR(FAILED(hr), "CreateFileMoniker Failed");
+
+ hr = BindMoniker(pmnk, grfOpt, IID_IUnknown, (void **)&pUnk);
+
+ TEST_FAILED_HR(FAILED(hr),
+ "BindMoniker to file Failed")
+
+ // Confirm bind to same object produces same object pointer
+
+ hr = BindMoniker(pmnk, grfOpt, IID_IUnknown, (void **)&pUnkTheSame);
+
+ TEST_FAILED_HR(FAILED(hr),
+ "BindMoniker to file Failed")
+#ifdef NOT_YET
+ TEST_FAILED((pUnkTheSame != pUnk), "Object pointers not ==\n")
+#endif // NOT_YET
+ pUnkTheSame.Set(NULL);
+ pmnk.Set(NULL);
+
+/*
+ * OK - we've bound to the IUnknown interface, lets
+ * QueryInterface to something more interesting (for test reasons)
+ */
+ hr = pUnk->QueryInterface(IID_IOleItemContainer,
+ (LPVOID FAR*) &poleitmcon);
+
+ TEST_FAILED_HR(FAILED(hr), "Query Interface Failed")
+
+/*
+ * Make sure we get an error when QI'ing for something the server
+ * does not support.
+ */
+ hr = pUnk->QueryInterface(IID_IDispatch,
+ (LPVOID FAR*) &pdispatch);
+
+ TEST_FAILED_HR(SUCCEEDED(hr),
+ "QueryInterface to unsupported interface")
+
+ pdispatch.Set(NULL);
+ pUnk.Set(NULL);
+
+
+/*
+ * Call get the class ID using IPersistFile
+ */
+
+ hr = poleitmcon->GetObject(L"1", 1, NULL, IID_IUnknown,
+ (void **) &punk);
+
+ TEST_FAILED_HR(FAILED(hr), "GetObject Failed")
+
+ TEST_FAILED((punk == NULL),
+ "GetObject returned a NULL for punk\n")
+
+ poleitmcon.Set(NULL);
+
+ if (TestSetMoniker(punk))
+ {
+ return 1;
+ }
+
+ hr = punk->QueryInterface(IID_IOleLink, (LPVOID FAR*) &poleitmcon);
+
+ TEST_FAILED_HR(SUCCEEDED(hr),
+ "Query Interface to invalid interface succeeded")
+
+ punk.Set(NULL);
+
+ // Do moniker tests:
+ if (TestBindCtx())
+ {
+ return TRUE;
+ }
+
+ if (TestROT(guidToTest))
+ {
+ return TRUE;
+ }
+
+ return TestMoniker(pszPath1, pszPath2);
+}
+
+// TRUE on failure
+BOOL TestPrematureDeath()
+{
+ XMoniker pmnk;
+ XUnknown pUnk;
+ HRESULT hr;
+ TCHAR tszFileName[MAX_PATH+1];
+ HANDLE hTouchFile;
+ SYSTEMTIME st1, st2;
+ FILETIME ft1, ft2;
+ LONG l;
+ DWORD dw;
+
+ ZeroMemory(&st1, sizeof(st1));
+ ZeroMemory(&st2, sizeof(st2));
+
+ hr = CreateFileMoniker(LocalServerPath4, &pmnk);
+ TEST_FAILED_HR(FAILED(hr), "CreateFileMoniker Failed")
+
+ GetSystemDirectory(tszFileName, MAX_PATH+1);
+ _tcscat(tszFileName, TEXT("\\failtst.tst"));
+
+ hTouchFile = CreateFileT(tszFileName,
+ GENERIC_READ|GENERIC_WRITE,
+ FILE_SHARE_READ|FILE_SHARE_WRITE,
+ NULL,
+ OPEN_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+ if(hTouchFile == INVALID_HANDLE_VALUE)
+ {
+ wsprintfA(&wszErrBuf[0], "Couldn't open touch file - err = %x.\n", GetLastError());
+ MessageBoxA(NULL, &wszErrBuf[0], szOleBindError, MB_OK);
+ return TRUE;
+ }
+
+ GetSystemTime(&st1);
+ WriteFile(hTouchFile, &st1, sizeof(st1), &dw, NULL);
+
+ l = GetTickCount();
+
+ // This takes awhile, so tell the user
+ printf("SCM dead server test (60 sec) started\n");
+
+ hr = BindMoniker(pmnk, 0, IID_IUnknown, (void **)&pUnk);
+
+ TEST_FAILED_HR((hr != CO_E_SERVER_EXEC_FAILURE),
+ "Unexpected hr from BindMoniker in premature death test")
+
+ // Tell the BVT guys
+ printf("SCM dead server test succeeded\n");
+
+ //
+ // The above bind should have caused fail.exe to execute and write a new
+ // time to the file as proof of execution.
+ //
+
+ SetFilePointer(hTouchFile, 0, NULL, FILE_BEGIN);
+ ReadFile(hTouchFile, &st2, sizeof(st2), &dw, NULL);
+ CloseHandle(hTouchFile);
+
+ DeleteFileT(tszFileName);
+
+ SystemTimeToFileTime(&st1, &ft1);
+ SystemTimeToFileTime(&st2, &ft2);
+ if (0 == CompareFileTime(&ft1, &ft2))
+ {
+ wsprintfA(&wszErrBuf[0], "Test not configured properly: PROGID50(fail.exe) did not run.");
+ MessageBoxA(NULL, &wszErrBuf[0], szOleBindError, MB_OK);
+ return TRUE;
+ }
+
+ if (GetTickCount() - l > 2*60*1000)
+ {
+ wsprintfA(&wszErrBuf[0], "Premature death test failed: too long to detect death.");
+ MessageBoxA(NULL, &wszErrBuf[0], szOleBindError, MB_OK);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+char * ConvertPath(LPWSTR pwsz)
+{
+ static char szPath[MAX_PATH];
+ wcstombs(szPath, pwsz, wcslen(pwsz) + 1);
+ return szPath;
+}
+
+int CreateFile(LPWSTR pwszPath)
+{
+ // Try to create the file
+ int fh = _creat(ConvertPath(pwszPath), _S_IWRITE|S_IREAD);
+
+ // Did file create fail?
+ if (fh != -1)
+ {
+ // Write some data to file -- makes sure docfile won't delete
+ // the file.
+ _write(fh, "This is a test file\n", sizeof("This is a test file\n"));
+
+ // No -- then set to success and close the newly created file
+ _close(fh);
+ fh = 0;
+ }
+
+ return fh;
+}
+
+
+void CleanUpFiles(void)
+{
+ // Delete all the test files.
+ remove(ConvertPath(InprocPath1));
+ remove(ConvertPath(InprocPath2));
+ remove(ConvertPath(LocalServerPath1));
+ remove(ConvertPath(LocalServerPath2));
+ remove(ConvertPath(LocalServerPath4));
+ remove(ConvertPath(LongDirShort));
+ remove(ConvertPath(LongDirLong));
+#if !defined(_CHICAGO_)
+ RemoveDirectory(LongDir);
+#else
+ RemoveDirectory(ConvertPath(LongDir));
+#endif
+}
+
+int InitFiles(void)
+{
+ BOOL fRet;
+
+ TCHAR szCurDir[MAX_PATH];
+ TCHAR szTmpLongDir[MAX_PATH];
+ WCHAR wcCurDir[MAX_PATH];
+ WCHAR wcLong[MAX_PATH], *pwcEnd;
+
+ DWORD cCurDir = GetCurrentDirectory(MAX_PATH, szCurDir);
+
+ #ifdef UNICODE
+ wcscpy(wcCurDir, szCurDir);
+ #else
+ mbstowcs(wcCurDir, szCurDir, MAX_PATH);
+ #endif
+
+ // Is the current directory the root of a drive?
+ if (wcCurDir[cCurDir - 1] == '\\')
+ {
+ // We bring the string on char back to take into account
+ // the fact the string we will concatenate begins with a slash.
+ wcCurDir[cCurDir - 1] = 0;
+ }
+
+ // get the pid. we use the pid to identify the files for a particular
+ // run of the test (so we may run multiple instances simultaneously
+ // without interference).
+
+ DWORD dwPid = GetCurrentProcessId();
+ char szPid[9];
+ _itoa(dwPid, szPid, 16);
+ wszPid[0] = L'\\';
+#if defined(_CHICAGO_)
+ szPid[4] = '\0'; // This is an all platform bug, but zap for Chicago.
+#endif
+ mbstowcs(&wszPid[1], szPid, strlen(szPid)+1);
+
+ wcscpy(InprocPath1, wcCurDir);
+ wcscat(InprocPath1, wszPid);
+ wcscat(InprocPath1, INPROC_PATH1);
+
+ wcscpy(InprocPath2, wcCurDir);
+ wcscat(InprocPath2, wszPid);
+ wcscat(InprocPath2, INPROC_PATH2);
+
+ wcscpy(LocalServerPath1, wcCurDir);
+ wcscat(LocalServerPath1, wszPid);
+ wcscat(LocalServerPath1, LOCAL_SERVER_PATH1);
+
+ wcscpy(LocalServerPath2, wcCurDir);
+ wcscat(LocalServerPath2, wszPid);
+ wcscat(LocalServerPath2, LOCAL_SERVER_PATH2);
+
+ wcscpy(LocalServerPath4, wcCurDir);
+ wcscat(LocalServerPath4, wszPid);
+ wcscat(LocalServerPath4, LOCAL_SERVER_PATH4);
+
+ wcscpy(wcLong, wcCurDir);
+ wcscat(wcLong, LONG_DIR);
+ wcscpy(LongDir, wcLong);
+ pwcEnd = wcLong+wcslen(wcLong);
+
+ wcscpy(pwcEnd, LONG_SHORT_NAME);
+ wcscpy(LongDirShort, wcLong);
+
+ wcscpy(pwcEnd, LONG_LONG_NAME);
+ wcscpy(LongDirLong, wcLong);
+
+#ifdef _CHICAGO_
+ wcscpy(LongDirLongSe, wcCurDir);
+ wcscat(LongDirLongSe, LONG_DIR);
+
+#else
+ wcscpy(pwcEnd, LONG_LONG_SHORT_EQUIV);
+ wcscpy(LongDirLongSe, wcLong);
+#endif // _CHICAGO_
+
+ // Delete any files that exist
+ CleanUpFiles();
+
+ // Create a file for each test file needed.
+ TEST_FAILED(CreateFile(InprocPath1),
+ "Couldn't create first test file!\n");
+ TEST_FAILED(CreateFile(InprocPath2),
+ "Couldn't create second test file!\n");
+ TEST_FAILED(CreateFile(LocalServerPath1),
+ "Couldn't create third test file!\n");
+ TEST_FAILED(CreateFile(LocalServerPath2),
+ "Couldn't create fourth test file!\n");
+ TEST_FAILED(CreateFile(LocalServerPath4),
+ "Couldn't create fifth test file!\n");
+
+#if !defined(_CHICAGO_)
+ fRet = CreateDirectory(LongDir, NULL);
+#else
+ fRet = CreateDirectory(ConvertPath(LongDir), NULL);
+#endif
+ TEST_FAILED(!fRet, "Couldn't create long directory\n");
+ TEST_FAILED(CreateFile(LongDirShort),
+ "Couldn't create short file in long directory\n");
+ TEST_FAILED(CreateFile(LongDirLong),
+ "Couldn't create long file in long directory\n");
+
+ #ifdef UNICODE
+ TEST_FAILED(!GetShortPathName(LongDirLong,
+ LongDirLongSe,
+ sizeof(LongDirLongSe)),
+ "Couldn't GetShortPathname of long directory\n");
+ #else
+
+ TEST_FAILED(!GetShortPathNameT(ConvertPath(LongDirLong),
+ szCurDir,
+ sizeof(szCurDir)),
+ "Couldn't GetShortPathname of long directory\n");
+
+ mbstowcs(LongDirLongSe, szCurDir, strlen(szCurDir)+1);
+
+ #endif
+
+ return 0;
+}
+
+
+DWORD CallCoInitUninit(void *)
+{
+ // Initialize
+ HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
+
+ if (SUCCEEDED(hr))
+ {
+ // Uninitialize
+ CoUninitialize();
+ }
+
+ // Return value from function. Note that this is not really used because
+ // there is a potential race
+ return (DWORD) hr;
+}
+
+BOOL DoFreeThreadMultiInitTest(void)
+{
+ //
+ // Get an OLE object in another process
+ //
+ IClassFactory *pIClassFactory;
+
+ HRESULT hr = CoGetClassObject(
+ CLSID_AdvBnd,
+ CLSCTX_LOCAL_SERVER,
+ NULL,
+ IID_IClassFactory,
+ (void **) &pIClassFactory);
+
+ TEST_FAILED_HR((hr != NOERROR),
+ "DoFreeThreadMultiInitTest CoGetClassObject")
+
+ //
+ // Create another thread which does a matching call to
+ // CoInitialize/Uninitialize and then exits.
+ //
+
+ // Create the thread
+ DWORD dwIdUnused;
+
+ HANDLE hInitThread = CreateThread(
+ NULL, // Security - none
+ 0, // Stack - use the same as the primary thread
+ CallCoInitUninit, // Entry point for thread
+ NULL, // Parameter to the thread - not used.
+ 0, // Run this thread immediately (if not sooner).
+ &dwIdUnused); // Id of thread - not used.
+
+ // Did the create succeed?
+ TEST_FAILED_LAST_ERROR((NULL == hInitThread),
+ "DoFreeThreadMultiInitTest CreateThread")
+
+ // Wait for the thread to do its work
+ DWORD dwRes = WaitForSingleObject(hInitThread, INFINITE);
+
+ // Did something terrible happen?
+ TEST_FAILED_LAST_ERROR((WAIT_FAILED == dwRes),
+ "DoFreeThreadMultiInitTest WaitForSingleObject")
+
+ // Get the result from the thread
+ BOOL fGetExitCode = GetExitCodeThread(hInitThread, (DWORD *) &hr);
+
+ TEST_FAILED_LAST_ERROR(!fGetExitCode,
+ "DoFreeThreadMultiInitTest GetExitCodeThread")
+
+ // Free handles we no longer need
+ CloseHandle(hInitThread);
+
+ //
+ // Validate the object we originally got is still alive and well.
+ //
+ IUnknown *punk;
+
+ hr = pIClassFactory->CreateInstance(NULL, IID_IUnknown, (void **) &punk);
+
+ TEST_FAILED_HR((hr != NOERROR),
+ "DoFreeThreadMultiInitTest CoGetClassObject")
+
+ // Free the objects we got in this routine.
+ pIClassFactory->Release();
+ punk->Release();
+
+ return FALSE;
+}
+
+
+
+
+//+--------------------------------------------------------------
+// Function: Main
+//
+// Synopsis: Executes the BasicBnd test
+//
+// Effects: None
+//
+//
+// Returns: Exits with exit code 0 if success, 1 otherwise
+//
+// History: 05-Mar-92 Sarahj Created
+//
+//---------------------------------------------------------------
+
+int _cdecl main(int argc, char *argv[])
+{
+ BOOL fFailed = FALSE;
+ HRESULT hr;
+
+ if (argc > 1)
+ {
+ if (!strcmp(argv[1], "M"))
+ goto multithreading;
+ }
+
+ // BUGBUG: 1-18-95 To be implemented BruceMa
+ // Correlate the platform we're running on and the platform
+ // we built for
+
+
+ // Write thread mode to initialization file.
+ fFailed = !WriteProfileString(
+ TEXT("TestSrv"),
+ TEXT("ThreadMode"),
+ TEXT("ApartmentThreaded"));
+
+ if (fFailed)
+ {
+ wsprintfA(&wszErrBuf[0], "Failed writing TestSrv profile string.");
+ MessageBoxA(NULL, &wszErrBuf[0], szOleBindError, MB_OK);
+ goto exit_main;
+ }
+
+ fFailed = !WriteProfileString(
+ TEXT("OleSrv"),
+ TEXT("ThreadMode"),
+ TEXT("ApartmentThreaded"));
+
+ if (fFailed)
+ {
+ wsprintfA(&wszErrBuf[0], "Failed writing OleSrv profile string.");
+ MessageBoxA(NULL, &wszErrBuf[0], szOleBindError, MB_OK);
+ goto exit_main;
+ }
+
+ // Set up test files
+ fFailed = InitFiles();
+ if (fFailed)
+ {
+ goto exit_main;
+ }
+
+ // Test repeated calls to CoInitialize
+ hr = CoInitialize(NULL);
+
+ TEST_FAILED_HR(FAILED(hr), "CoInitialize Failed")
+
+ // must be called before any other OLE API
+ hr = OleInitialize(NULL);
+
+ TEST_FAILED_HR(FAILED(hr), "OleInitialize Failed")
+
+ // Call CoUnitialize and see how the rest of the program works!
+ CoUninitialize();
+
+ // Test stdmalloc
+ if (fFailed = TestStdMalloc())
+ {
+ goto exit_init;
+ }
+
+ fFailed =
+ DoTest(CLSID_BasicBnd, InprocPath1, InprocPath2);
+
+ if (fFailed)
+ {
+ printf( "\nOLE failed in Single Threaded Apartment pass.\n" );
+ goto exit_init;
+ }
+
+ printf("BasicBnd tests succeeded\n");
+
+ fFailed =
+ DoTest(CLSID_AdvBnd, LocalServerPath1, LocalServerPath1);
+
+ if (fFailed)
+ {
+ printf( "\nOLE failed in Single Threaded Apartment pass.\n" );
+ goto exit_init;
+ }
+
+ printf("AdvBnd tests succeeded\n");
+
+ if (TestPrematureDeath())
+ {
+ printf("\nOLE failed testing server premature death.\n");
+ goto exit_init;
+ }
+
+ OleUninitialize();
+
+ CleanUpFiles();
+
+multithreading:
+
+#ifdef MULTI_THREADING
+ // Run the whole thing all over again.
+
+ // Write thread mode to initialization file.
+ fFailed = !WriteProfileString(
+ TEXT("TestSrv"),
+ TEXT("ThreadMode"),
+ TEXT("ApartmentThreaded"));
+
+ if (fFailed)
+ {
+ wsprintfA(&wszErrBuf[0], "Failed writing TestSrv profile string.");
+ MessageBoxA(NULL, &wszErrBuf[0], szOleBindError, MB_OK);
+ goto exit_main;
+ }
+
+ fFailed = !WriteProfileString(
+ TEXT("OleSrv"),
+ TEXT("ThreadMode"),
+ TEXT("MultiThreaded"));
+
+ if (fFailed)
+ {
+ wsprintfA(&wszErrBuf[0], "Failed writing OleSrv profile string.");
+ MessageBoxA(NULL, &wszErrBuf[0], szOleBindError, MB_OK);
+ goto exit_main;
+ }
+
+ // Set up test files
+ if (InitFiles())
+ {
+ fFailed = TRUE;
+ goto exit_main;
+ }
+
+ // Mark the dll in the registry as "ThreadingdModel: Free"
+ if (!SetRegistryThreadingModel(InprocPath1, L"Free"))
+ {
+ wsprintfA(&wszErrBuf[0], "Failed trying to set reg ThreadingModel.");
+ MessageBoxA(NULL, &wszErrBuf[0], szOleBindError, MB_OK);
+ goto exit_main;
+ }
+
+ // Test repeated calls to CoInitialize
+ hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
+
+ TEST_FAILED_HR(FAILED(hr), "CoInitializeEx Multi Threaded Failed")
+
+ // must be called before any other OLE API
+ hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
+
+ TEST_FAILED_HR(FAILED(hr), "CoInitializeEx Multi Threaded Failed")
+
+ // Call CoUnitialize and see how the rest of the program works!
+ CoUninitialize();
+
+ // Test stdmalloc
+ if (fFailed = TestStdMalloc())
+ {
+ goto exit_init;
+ }
+
+ fFailed =
+ DoTest(CLSID_BasicBnd, InprocPath1, InprocPath2);
+ if (fFailed)
+ {
+ printf( "\nOLE failed in Multi Threaded Apartment pass.\n" );
+ goto exit_init;
+ }
+
+ fFailed =
+ DoTest(CLSID_AdvBnd, LocalServerPath1, LocalServerPath1);
+
+ if (fFailed)
+ {
+ printf( "\nOLE failed in Multi Threaded Apartment pass.\n" );
+ goto exit_init;
+ }
+
+ // Do CoInitialize/Uninitialize on second thread to make sure
+ // that other threads initialize/uninitialize do not effect
+ // the running of the test.
+ if (fFailed = DoFreeThreadMultiInitTest())
+ {
+ printf( "\nOLE failed in Multi Threaded InitTest.\n" );
+ goto exit_init;
+ }
+
+#endif // MULTI_THREADING
+
+
+exit_init:
+
+ CoUninitialize();
+
+ // Remove the dll's threading model registration
+ ResetRegistryThreadingModel(InprocPath1);
+
+
+exit_main:
+
+ CleanUpFiles();
+
+ if (!fFailed)
+ {
+ printf("\nOLE: PASSED\n");
+ }
+ else
+ {
+ printf("\nOLE: FAILED\n");
+ }
+
+ return fFailed;
+}
+
+
+
+//+--------------------------------------------------------
+//
+// Function: SetRegistryThreadingModel
+//
+// Algorithm: Set the threading model for the InprocServer32 associated
+// with the file pwszFile tp pwszThreadingModel
+//
+// History: 17-Jan-95 BruceMa Created
+//
+//---------------------------------------------------------
+BOOL SetRegistryThreadingModel(WCHAR *pwszFile, WCHAR *pwszThreadingModel)
+{
+ DWORD dwRESERVED = 0;
+ WCHAR wszExt[8];
+ HKEY hKey;
+ WCHAR wszProgId[32];
+ DWORD dwValueType;
+ WCHAR wszCLSID[64];
+ HKEY hClsidKey;
+ HKEY hInproc32Key;
+ ULONG cbValue;
+
+
+ // Strip the extension off the file name
+ int k = wcslen(pwszFile) - 1;
+ while (k > 0 && pwszFile[k] != L'.')
+ {
+ k--;
+ }
+ if (k >= 0 && pwszFile[k] == L'.')
+ {
+ for (int j = 0; pwszFile[k]; j++, k++)
+ {
+ wszExt[j] = pwszFile[k];
+ }
+ wszExt[j] = L'\0';
+ }
+ else
+ {
+ return FALSE;
+ }
+
+ // Open the key for the specified extension
+ if (RegOpenKeyEx(HKEY_CLASSES_ROOT, wszExt, dwRESERVED,
+ KEY_READ, &hKey) != ERROR_SUCCESS)
+ {
+ return FALSE;
+ }
+
+ // Read the ProgId for the extension
+ cbValue = 32;
+ if (RegQueryValueEx(hKey, NULL, NULL, &dwValueType,
+ (LPBYTE) wszProgId, &cbValue) != ERROR_SUCCESS)
+ {
+ CloseHandle(hKey);
+ return FALSE;
+ }
+
+ // Open the ProgIdKey
+ CloseHandle(hKey);
+ if (RegOpenKeyEx(HKEY_CLASSES_ROOT, wszProgId, dwRESERVED,
+ KEY_READ, &hKey) != ERROR_SUCCESS)
+ {
+ return FALSE;
+ }
+
+ // Open the associated CLSID key
+ if (RegOpenKeyEx(hKey, L"CLSID", dwRESERVED,
+ KEY_READ, &hClsidKey) != ERROR_SUCCESS)
+ {
+ CloseHandle(hKey);
+ return FALSE;
+ }
+
+ // Read the CLSID associated with the ProgId
+ cbValue = 128;
+ if (RegQueryValueEx(hClsidKey, NULL, NULL, &dwValueType,
+ (LPBYTE) wszCLSID, &cbValue) != ERROR_SUCCESS)
+ {
+ CloseHandle(hClsidKey);
+ CloseHandle(hKey);
+ return FALSE;
+ }
+
+ // Open the HKEY_CLASSES_ROOT\CLSID key
+ CloseHandle(hClsidKey);
+ CloseHandle(hKey);
+ if (RegOpenKeyEx(HKEY_CLASSES_ROOT, L"CLSID", dwRESERVED,
+ KEY_READ, &hKey) != ERROR_SUCCESS)
+ {
+ return FALSE;
+ }
+
+ // Open the key to our clsid
+ if (RegOpenKeyEx(hKey, wszCLSID, dwRESERVED,
+ KEY_READ, &hClsidKey) != ERROR_SUCCESS)
+ {
+ CloseHandle(hKey);
+ return FALSE;
+ }
+
+ // Open the InprocServer32 key
+ CloseHandle(hKey);
+ if (RegOpenKeyEx(hClsidKey, L"InprocServer32", dwRESERVED,
+ KEY_SET_VALUE, &hInproc32Key) != ERROR_SUCCESS)
+ {
+ CloseHandle(hClsidKey);
+ return FALSE;
+ }
+
+ // Set the threading model for this InprocServer32 key
+ CloseHandle(hClsidKey);
+ if (RegSetValueEx(hInproc32Key, L"ThreadingModel", dwRESERVED,
+ REG_SZ, (LPBYTE) pwszThreadingModel,
+ (wcslen(pwszThreadingModel)+1) * sizeof(WCHAR))
+ != ERROR_SUCCESS)
+ {
+ CloseHandle(hInproc32Key);
+ return FALSE;
+ }
+
+ // Close the InprocServer32 key and return success
+ CloseHandle(hInproc32Key);
+ return TRUE;
+}
+
+
+
+
+
+
+
+
+
+//+--------------------------------------------------------
+//
+// Function: ResetRegistryThreadingModel
+//
+// Algorithm: Remove the threading model for the InprocServer32 associated
+// with the file pwszFile
+//
+// History: 17-Jan-95 BruceMa Created
+//
+//---------------------------------------------------------
+BOOL ResetRegistryThreadingModel(WCHAR *pwszFile)
+{
+ DWORD dwRESERVED = 0;
+ WCHAR wszExt[8];
+ HKEY hKey;
+ WCHAR wszProgId[32];
+ DWORD dwValueType;
+ WCHAR wszCLSID[64];
+ HKEY hClsidKey;
+ HKEY hInproc32Key;
+ ULONG cbValue;
+
+
+ // Strip the extension off the file name
+ int k = wcslen(pwszFile) - 1;
+ while (k > 0 && pwszFile[k] != L'.')
+ {
+ k--;
+ }
+ if (k >= 0 && pwszFile[k] == L'.')
+ {
+ for (int j = 0; pwszFile[k]; j++, k++)
+ {
+ wszExt[j] = pwszFile[k];
+ }
+ wszExt[j] = L'\0';
+ }
+ else
+ {
+ return FALSE;
+ }
+
+ // Open the key for the specified extension
+ if (RegOpenKeyEx(HKEY_CLASSES_ROOT, wszExt, dwRESERVED,
+ KEY_READ, &hKey) != ERROR_SUCCESS)
+ {
+ return FALSE;
+ }
+
+ // Read the ProgId for the extension
+ cbValue = 32;
+ if (RegQueryValueEx(hKey, NULL, NULL, &dwValueType,
+ (LPBYTE) wszProgId, &cbValue) != ERROR_SUCCESS)
+ {
+ CloseHandle(hKey);
+ return FALSE;
+ }
+
+ // Open the ProgIdKey
+ CloseHandle(hKey);
+ if (RegOpenKeyEx(HKEY_CLASSES_ROOT, wszProgId, dwRESERVED,
+ KEY_READ, &hKey) != ERROR_SUCCESS)
+ {
+ return FALSE;
+ }
+
+ // Open the associated CLSID key
+ if (RegOpenKeyEx(hKey, L"CLSID", dwRESERVED,
+ KEY_READ, &hClsidKey) != ERROR_SUCCESS)
+ {
+ CloseHandle(hKey);
+ return FALSE;
+ }
+
+ // Read the CLSID associated with the ProgId
+ cbValue = 128;
+ if (RegQueryValueEx(hClsidKey, NULL, NULL, &dwValueType,
+ (LPBYTE) wszCLSID, &cbValue) != ERROR_SUCCESS)
+ {
+ CloseHandle(hClsidKey);
+ CloseHandle(hKey);
+ return FALSE;
+ }
+
+ // Open the HKEY_CLASSES_ROOT\CLSID key
+ CloseHandle(hClsidKey);
+ CloseHandle(hKey);
+ if (RegOpenKeyEx(HKEY_CLASSES_ROOT, L"CLSID", dwRESERVED,
+ KEY_READ, &hKey) != ERROR_SUCCESS)
+ {
+ return FALSE;
+ }
+
+ // Open the key to our clsid
+ if (RegOpenKeyEx(hKey, wszCLSID, dwRESERVED,
+ KEY_READ, &hClsidKey) != ERROR_SUCCESS)
+ {
+ CloseHandle(hKey);
+ return FALSE;
+ }
+
+ // Open the InprocServer32 key
+ CloseHandle(hKey);
+ if (RegOpenKeyEx(hClsidKey, L"InprocServer32", dwRESERVED,
+ KEY_SET_VALUE, &hInproc32Key) != ERROR_SUCCESS)
+ {
+ CloseHandle(hClsidKey);
+ return FALSE;
+ }
+
+ // Reset the threading model for this InprocServer32 key
+ CloseHandle(hClsidKey);
+ if (RegDeleteValue(hInproc32Key, TEXT("ThreadingModel")) != ERROR_SUCCESS)
+ {
+ CloseHandle(hInproc32Key);
+ return FALSE;
+ }
+
+ // Close the InprocServer32 key and return success
+ CloseHandle(hInproc32Key);
+ return TRUE;
+}
diff --git a/private/oleutest/olebind/olebind.hxx b/private/oleutest/olebind/olebind.hxx
new file mode 100644
index 000000000..9e2f54f05
--- /dev/null
+++ b/private/oleutest/olebind/olebind.hxx
@@ -0,0 +1,90 @@
+#ifndef __OLEBIND_HXX__
+#define __OLEBIND_HXX__
+
+#include <safepnt.hxx>
+
+// safe ptrs so we release interfaces in error paths
+
+SAFE_INTERFACE_PTR(XUnknown, IUnknown)
+SAFE_INTERFACE_PTR(XBindCtx, IBindCtx)
+SAFE_INTERFACE_PTR(XMoniker, IMoniker)
+SAFE_INTERFACE_PTR(XStream, IStream)
+SAFE_INTERFACE_PTR(XMalloc, IMalloc)
+SAFE_INTERFACE_PTR(XOleObject, IOleObject)
+SAFE_INTERFACE_PTR(XRunningObjectTable, IRunningObjectTable)
+SAFE_INTERFACE_PTR(XEnumMoniker, IEnumMoniker)
+SAFE_INTERFACE_PTR(XOleItemContainer, IOleItemContainer)
+SAFE_INTERFACE_PTR(XDispatch, IDispatch)
+
+
+// string version of process id
+extern WCHAR wszPid[10];
+
+
+#define LAST_RELEASE(x) \
+ { \
+ ULONG cnt = x->Release(); \
+ x.Detach(); \
+ LPSTR pname = #x; \
+ if (cnt) \
+ { \
+ printf("%s:%d %s still has refs = %ld\n", __FILE__, __LINE__, \
+ pname, cnt); \
+ } \
+ }
+
+
+#define DISPLAY_REFS(x) \
+ { \
+ x->AddRef(); \
+ ULONG cnt = x->Release(); \
+ LPSTR pname = #x; \
+ printf("%s refs = %ld\n", pname, cnt); \
+ }
+
+
+extern const char *szOleBindError;
+extern char wszErrBuf[];
+
+// Failure return macro to be used when you are not interested in an
+// HRESULT.
+#define TEST_FAILED(x, y) \
+ if (x) \
+ { \
+ wsprintfA(&wszErrBuf[0], "%s:%d %s", __FILE__, __LINE__, y); \
+ MessageBoxA(NULL, &wszErrBuf[0], szOleBindError, MB_OK); \
+ return TRUE; \
+ }
+
+// Failure return macro to be used when you have an interesting HRESULT
+// to return.
+#define TEST_FAILED_HR(x, y) \
+ if (x) \
+ { \
+ wsprintfA(&wszErrBuf[0], "%s:%d %s HRESULT = %lx", __FILE__, __LINE__, y, hr); \
+ MessageBoxA(NULL, &wszErrBuf[0], szOleBindError, MB_OK); \
+ return TRUE; \
+ }
+
+
+// Failure return macro to be used when you have an interesting HRESULT
+// to return.
+#define TEST_FAILED_LAST_ERROR(x, y) \
+ if (x) \
+ { \
+ wsprintfA(&wszErrBuf[0], "%s:%d %s Error = %lx",\
+ __FILE__, __LINE__, y, GetLastError()); \
+ MessageBoxA(NULL, &wszErrBuf[0], szOleBindError, MB_OK); \
+ return TRUE; \
+ }
+
+
+extern WCHAR LongDir[MAX_PATH];
+extern WCHAR LongDirShort[MAX_PATH];
+extern WCHAR LongDirLong[MAX_PATH];
+extern WCHAR LongDirLongSe[MAX_PATH];
+
+// Test standard IMalloc interface
+BOOL TestStdMalloc(void);
+
+#endif // __OLEBIND_HXX__
diff --git a/private/oleutest/olebind/rot.cxx b/private/oleutest/olebind/rot.cxx
new file mode 100644
index 000000000..09e021c36
--- /dev/null
+++ b/private/oleutest/olebind/rot.cxx
@@ -0,0 +1,262 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: rotut.cxx
+//
+// Contents: Unit Test for ROT
+//
+// Classes: MISSING
+//
+// Functions: MISSING
+//
+// History: 16-Oct-93 Ricksa Created
+// 31-Dec-93 ErikGav Chicago port
+//
+//--------------------------------------------------------------------------
+#include <windows.h>
+#include <ole2.h>
+#include <olebind.hxx>
+#include <stdio.h>
+
+
+class CRotTestObject : public IUnknown
+{
+public:
+ CRotTestObject(WCHAR *pwszID);
+
+ // IUnknown Interface
+ STDMETHOD(QueryInterface)(REFIID riid, void **ppv);
+
+ STDMETHOD_(ULONG, AddRef)(void);
+
+ STDMETHOD_(ULONG, Release)(void);
+
+private:
+
+ WCHAR _awcID[256];
+
+ ULONG _cRefs;
+
+};
+
+
+
+
+CRotTestObject::CRotTestObject(WCHAR *pwszID) : _cRefs(1)
+{
+ wcscpy(_awcID, pwszID);
+}
+
+
+
+
+STDMETHODIMP CRotTestObject::QueryInterface(REFIID riid, void **ppv)
+{
+ if (memcmp((void *) &riid, (void *) &IID_IUnknown, sizeof(GUID)) == 0)
+ {
+ _cRefs++;
+ *ppv = (IUnknown *) this;
+ return S_OK;
+ }
+
+ *ppv = NULL;
+ return E_NOINTERFACE;
+}
+
+
+
+STDMETHODIMP_(ULONG) CRotTestObject::AddRef(void)
+{
+ _cRefs++;
+ return (ULONG) _awcID;
+}
+
+
+
+STDMETHODIMP_(ULONG) CRotTestObject::Release(void)
+{
+ ULONG cRefs = --_cRefs;
+
+ if (cRefs == 0)
+ {
+ delete this;
+ }
+
+ return cRefs;
+}
+
+
+
+//
+// Test Running Object Table
+//
+// BUGBUG: Need to test enumerator
+BOOL TestROT(REFCLSID clsid)
+{
+ XUnknown punk2;
+ XMoniker pmk;
+ XMoniker pmk2;
+ XRunningObjectTable prot;
+ XEnumMoniker penummk;
+
+
+ HRESULT hr = GetRunningObjectTable(0, &prot);
+
+ TEST_FAILED_HR(FAILED(hr), "GetRunningObjectTable failed!")
+
+ // Make sure that we can do something on the pointer that
+ // we got back.
+ prot->AddRef();
+ prot->Release();
+
+ // Create an IUnknown pointer for the class.
+ IUnknown *punk = new CRotTestObject(L"First Test Object");
+
+ hr = CreateItemMoniker(L"\\", wszPid, &pmk2);
+
+ TEST_FAILED_HR(FAILED(hr), "CreateItemMoniker for \\Bob failed")
+
+ // Do a get object to make sure that this is not in the ROT already
+
+ hr = prot->GetObject(pmk2, &punk2);
+
+ TEST_FAILED_HR(SUCCEEDED(hr), "GetObject on nonexistent succeeded")
+
+ // Cookie for deregistering object
+ DWORD dwRegister;
+
+ hr = prot->Register(0, punk, pmk2, &dwRegister);
+
+ TEST_FAILED_HR(FAILED(hr), "Register in ROT for \\PID failed")
+
+ hr = prot->IsRunning(pmk2);
+
+ TEST_FAILED_HR((hr != S_OK),
+ "Unexpected return from IsRunning")
+
+ // Test Get Object
+ hr = prot->GetObject(pmk2, &punk2);
+
+ TEST_FAILED_HR((hr != S_OK), "Unexpected from GetObject")
+
+ // Confirm object identity
+ WCHAR *pwszID = (WCHAR *) punk2->AddRef();
+
+ TEST_FAILED_HR((wcscmp(pwszID, L"First Test Object") != 0),
+ "GetObject ID is invalid");
+
+ // Make sure pointer == original pointer
+ TEST_FAILED((punk2 != punk), "GetObject Pointers are not equal!")
+
+ // Clean up punk2 -- two releases because +1 on return and +1 on
+ // addref to get id string
+ punk2->Release();
+ punk2.Set(NULL);
+
+
+ // Test set the time
+ FILETIME filetime;
+
+ memset(&filetime, 'A', sizeof(filetime));
+
+ hr = prot->NoteChangeTime(dwRegister, &filetime);
+
+ TEST_FAILED_HR((hr != S_OK), "NoteChangeTime Failed")
+
+ // Test get the time
+ FILETIME filetime2;
+
+ hr = prot->GetTimeOfLastChange(pmk2, &filetime2);
+
+ TEST_FAILED_HR((hr != S_OK), "NoteChangeTime Failed")
+
+ TEST_FAILED((memcmp(&filetime, &filetime2, sizeof(filetime)) != 0),
+ "GetTimeOfLastChange != NoteChangeTime value")
+
+ // Enumerate all the running monikers
+
+ hr = prot->EnumRunning(&penummk);
+
+ TEST_FAILED_HR(FAILED(hr), "EnumRunning Failed")
+
+ // Cycle through running object table
+ BOOL fFound = FALSE;
+ int cIdx = 0;
+ int cOurMoniker;
+
+ while (SUCCEEDED(hr = penummk->Next(1, &pmk, NULL))
+ && (hr != S_FALSE))
+ {
+ if (pmk2->IsEqual(pmk) == S_OK)
+ {
+ fFound = TRUE;
+ cOurMoniker = cIdx;
+ }
+
+ pmk.Set(NULL);
+ cIdx++;
+ }
+
+ TEST_FAILED_HR(FAILED(hr), "ROT Moniker Enumeration ended in failure")
+
+ TEST_FAILED((!fFound), "Did not find our moniker in the table");
+
+ // Reset the pointer
+ hr = penummk->Reset();
+
+ TEST_FAILED_HR(FAILED(hr), "ROT IEnumMoniker::Reset Failed");
+
+ // Skip to our moniker
+ hr = penummk->Skip(cOurMoniker);
+
+ TEST_FAILED_HR(FAILED(hr), "ROT IEnumMoniker::Skip Failed");
+
+ // Read it from the enumerator
+ hr = penummk->Next(1, &pmk, NULL);
+
+ TEST_FAILED_HR(FAILED(hr), "ROT IEnumMoniker::Next Failed");
+
+ TEST_FAILED((pmk2->IsEqual(pmk) != S_OK),
+ "ROT IEnumMoniker::Next after skip monikers !=");
+
+ pmk.Set(NULL);
+
+ // Clean up enumerator
+ penummk.Set(NULL);
+
+ // Test duplicate registration
+ DWORD dwRegister2;
+
+ hr = prot->Register(0, punk, pmk2, &dwRegister2);
+
+ TEST_FAILED_HR((hr != MK_S_MONIKERALREADYREGISTERED),
+ "2nd Register in ROT for \\PID failed")
+
+ // Revoke non-existent object
+ DWORD dwDummy = (DWORD) &dwRegister2;
+
+ hr = prot->Revoke(dwDummy);
+
+ TEST_FAILED_HR((hr != E_INVALIDARG), "Revoke for bad item wrong result")
+
+ // Revoke the object
+ hr = prot->Revoke(dwRegister);
+
+ TEST_FAILED_HR(FAILED(hr), "Revoke of first reg in ROT failed")
+
+ // Revoke duplicate registration
+ hr = prot->Revoke(dwRegister2);
+
+ TEST_FAILED_HR(FAILED(hr), "2nd Revoke in ROT failed")
+
+ // Make sure it is no longer running
+ hr = prot->IsRunning(pmk2);
+
+ TEST_FAILED_HR((hr != S_FALSE),
+ "Revoked ROT entry unexpected error")
+
+ // If we get to here the test passed
+ return FALSE;
+}
diff --git a/private/oleutest/olebind/tmalloc.cxx b/private/oleutest/olebind/tmalloc.cxx
new file mode 100644
index 000000000..23eac30f3
--- /dev/null
+++ b/private/oleutest/olebind/tmalloc.cxx
@@ -0,0 +1,82 @@
+#include <windows.h>
+#include <stdio.h>
+#include <ole2.h>
+#include <olebind.hxx>
+
+BOOL TestStdMalloc(void)
+{
+ // Get the allocator
+ IMalloc *pIMalloc;
+ HRESULT hr = CoGetMalloc(MEMCTX_TASK, &pIMalloc);
+
+ TEST_FAILED_HR(FAILED(hr), "CoGetMalloc failed");
+
+ // Test AddRef/Release
+ ULONG cOrigRefs = pIMalloc->AddRef();
+
+#ifdef WIN32
+ // On Win32, we only guarantee that the reference count will be either
+ // zero (if we released the object) or nonzero (if we didn't)
+ TEST_FAILED((pIMalloc->Release() == 0),
+ "IMalloc: Wrong refcount");
+#else
+ TEST_FAILED((pIMalloc->Release() != cOrigRefs - 1),
+ "IMalloc: Wrong refcount");
+#endif
+
+ // Test query interface
+ IUnknown *punk;
+
+ hr = pIMalloc->QueryInterface(IID_IMalloc, (void **) &punk);
+
+ TEST_FAILED_HR(FAILED(hr), "IMalloc QueryInterface failed");
+
+ punk->Release();
+
+ // Test allocation
+ BYTE *pb = (BYTE *) pIMalloc->Alloc(2048);
+
+ // Test get size
+ TEST_FAILED((pIMalloc->GetSize(pb) < 2048), "GetSize failed");
+
+ TEST_FAILED((pb == NULL), "Alloc returned NULL");
+
+ for (int i = 0; i < 2048; i++)
+ {
+ pb[i] = 'A';
+ }
+
+ // Test reallocation to larger buffer
+ pb = (BYTE *) pIMalloc->Realloc(pb, 4096);
+
+ TEST_FAILED((pb == NULL), "Realloc larger returned NULL");
+
+ for (i = 0; i < 2048; i++)
+ {
+ TEST_FAILED((pb[i] != 'A'), "Buffer corrupt on larger realloc");
+ }
+
+ // Test reallocation to smaller buffer
+ pb = (BYTE *) pIMalloc->Realloc(pb, 990);
+
+ TEST_FAILED((pb == NULL), "Realloc smaller returned NULL");
+
+ for (i = 0; i < 990; i++)
+ {
+ TEST_FAILED((pb[i] != 'A'), "Buffer corrupt on smaller realloc");
+ }
+
+ // Test get size (size is allowed to be larger, but not smaller)
+ TEST_FAILED((pIMalloc->GetSize(pb) < 990), "GetSize failed");
+
+ // Test DidAllocate
+ TEST_FAILED((pIMalloc->DidAlloc(pb) == 0), "Didalloc failed");
+
+ // Test freeing the buffer
+ pIMalloc->Free(pb);
+
+ // Do last release
+ pIMalloc->Release();
+
+ return FALSE;
+}
diff --git a/private/oleutest/olebind/tmoniker.cxx b/private/oleutest/olebind/tmoniker.cxx
new file mode 100644
index 000000000..0652bc7b1
--- /dev/null
+++ b/private/oleutest/olebind/tmoniker.cxx
@@ -0,0 +1,798 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1993 - 1993.
+//
+// File: tmoniker.cxx
+//
+// Contents:
+//
+// Classes:
+//
+// Functions:
+//
+// History: 12-31-93 ErikGav Chicago port
+//
+//----------------------------------------------------------------------------
+
+// moniker.cxx : various tests related to monikers...
+//
+
+#pragma optimize("",off)
+#include <stdio.h>
+#include <windows.h>
+#include <ole2.h>
+#include "olebind.hxx"
+#include "tmoniker.h"
+
+STDAPI_(LPSTREAM) CreateMemStm(DWORD cb, LPHANDLE phdl);
+
+// BUGBUG: Make this test more extensive -- all operations on a
+// bind context should be verified.
+BOOL TestBindCtx( void )
+{
+ XBindCtx pbc;
+ XUnknown punk;
+ XUnknown punk2;
+
+ HRESULT hr = CreateBindCtx(0, &pbc);
+
+ TEST_FAILED_HR(FAILED(hr), "CreateBindCtx Failed")
+
+ hr = pbc->RegisterObjectParam(L"Key1", pbc);
+
+ TEST_FAILED_HR(FAILED(hr), "RegisterObjectParam Failed")
+
+ hr = pbc->GetObjectParam(L"Key1", &punk2);
+
+ TEST_FAILED_HR(FAILED(hr), "GetObjectParam Failed")
+
+ TEST_FAILED((pbc != punk2),
+ "Failure to get registered object parameter")
+
+ // BUGBUG: What do we test for here?
+ punk2.Set(NULL);
+
+ hr = pbc->GetObjectParam(L"Key2", &punk2);
+
+ TEST_FAILED_HR((hr != E_FAIL),
+ "GetObjectParam with bad key did not return an error")
+
+ TEST_FAILED((punk2 != NULL),
+ "Bad GetObjectParam did not return NULL for object")
+
+ hr = pbc->RegisterObjectParam(L"Key2", pbc);
+
+ TEST_FAILED_HR(FAILED(hr), "Second RegisterObjectParam Failed")
+
+ hr = pbc->GetObjectParam(L"Key2", &punk);
+
+ TEST_FAILED_HR(FAILED(hr), "GetObjectParam on second Failed")
+
+ TEST_FAILED((pbc != punk),
+ "Failure on second to get registered object parameter")
+
+ // BUGBUG: What do we check?
+ punk.Set(NULL);
+
+ hr = pbc->RevokeObjectParam(L"Key2");
+
+ TEST_FAILED_HR(FAILED(hr),
+ "RevokeObjectParam of Key2 Failed")
+
+ hr = pbc->GetObjectParam(L"Key2", &punk);
+
+ TEST_FAILED_HR((hr != E_FAIL),
+ "Get of revoked Key2 returned success")
+
+ TEST_FAILED((punk != NULL),
+ "Value returned on get of revoked key2")
+
+ hr = pbc->RevokeObjectParam(L"Key1");
+
+ TEST_FAILED_HR(FAILED(hr),
+ "RevokeObjectParam of Key1 Failed")
+
+ return FALSE;
+}
+
+BOOL VerifyFileMoniker(LPWSTR wcsFile)
+{
+ HRESULT hr;
+ XMoniker pmk;
+ XBindCtx pbc;
+ LPWSTR wcsDisplayName = NULL;
+
+ hr = CreateBindCtx(0,&pbc);
+ TEST_FAILED_HR(FAILED(hr), "CreateBindCtx");
+
+ hr = CreateFileMoniker(wcsFile,&pmk);
+ TEST_FAILED_HR(FAILED(hr), "CreateFileMoniker failed");
+
+ hr = pmk->GetDisplayName(pbc,NULL,&wcsDisplayName);
+ TEST_FAILED_HR(FAILED(hr), "GetDisplayName failed");
+
+ if (0 != wcscmp(wcsFile,wcsDisplayName))
+ {
+ wsprintfA(&wszErrBuf[0], "(%S) doesn't match displayname (%S)",wcsFile,wcsDisplayName);
+ MessageBoxA(NULL, &wszErrBuf[0], szOleBindError, MB_OK);
+ hr = E_FAIL;
+ }
+
+ CoTaskMemFree(wcsDisplayName);
+ return(hr);
+}
+BOOL TestMoniker(LPWSTR pszPath1, LPWSTR pszPath2)
+{
+ XUnknown pUnk;
+ XUnknown pUnk1;
+ XBindCtx pbc;
+ XMoniker pmk1;
+ XMoniker pmk2;
+ XMoniker pmk3;
+ XMoniker pmk4;
+ XMoniker pmk5;
+ XMoniker pmk6;
+ XMoniker pmkItem1;
+ XMoniker pmkItem2;
+ XMoniker pmkAnti;
+ XStream pStm;
+ XOleObject pObj;
+ XMalloc pIMalloc;
+ XMoniker pmkLong1;
+ XMoniker pmkLong2;
+ XRunningObjectTable prot;
+
+ ULONG chEaten;
+ LPWSTR szName;
+ LARGE_INTEGER large_int;
+ HRESULT hr;
+
+ //
+ // Test the dotdot eating methods
+ //
+ VerifyFileMoniker(L".");
+ VerifyFileMoniker(L"..\\");
+
+ VerifyFileMoniker(L"foo.bar");
+ VerifyFileMoniker(L".foo.bar");
+ VerifyFileMoniker(L".foo..bar");
+ VerifyFileMoniker(L"..foo.bar");
+ VerifyFileMoniker(L"..foo..bar");
+
+ VerifyFileMoniker(L"foo\\bar");
+ VerifyFileMoniker(L"foo\\.bar");
+ VerifyFileMoniker(L"foo\\..bar");
+
+ VerifyFileMoniker(L".foo\\bar");
+ VerifyFileMoniker(L".foo\\.bar");
+ VerifyFileMoniker(L".foo\\..bar");
+
+ VerifyFileMoniker(L"..foo\\bar");
+ VerifyFileMoniker(L"..foo\\.bar");
+ VerifyFileMoniker(L"..foo\\..bar");
+
+ VerifyFileMoniker(L"...foo\\bar");
+ VerifyFileMoniker(L"...foo\\.bar");
+ VerifyFileMoniker(L"...foo\\..bar");
+
+ VerifyFileMoniker(L"\\foo\\bar");
+ VerifyFileMoniker(L"\\.foo\\bar");
+ VerifyFileMoniker(L"\\..foo\\bar");
+
+ VerifyFileMoniker(L"..\\foo\\bar");
+ VerifyFileMoniker(L"..\\.foo\\bar");
+ VerifyFileMoniker(L"..\\..foo\\bar");
+
+ hr = CoGetMalloc(MEMCTX_TASK, &pIMalloc);
+
+ TEST_FAILED_HR(FAILED(hr), "CoGetMalloc failed");
+
+ hr = CreateFileMoniker(pszPath1, &pmk1);
+
+ TEST_FAILED_HR(FAILED(hr), "CreateFileMoniker for path1 failed!")
+
+ TEST_FAILED((pmk1 == NULL),
+ "CreateFileMoniker returned a null moniker ptr")
+
+ hr = CreateBindCtx(0, &pbc);
+
+ TEST_FAILED_HR(FAILED(hr),
+ "CreateBindCtx File Moniker GetDisplayName failed!")
+
+ hr = pmk1->GetDisplayName(pbc, NULL, &szName);
+
+ // release it
+ pbc.Set(NULL, FALSE);
+
+ TEST_FAILED_HR(FAILED(hr), "File Moniker GetDisplayName failed!");
+
+ // BUGBUG: The following is an inappropriate test.
+ // TEST_FAILED((lstrcmp(szName, pszPath1) != 0), "Wrong path from file mon");
+
+ // Free the path
+ pIMalloc->Free(szName);
+
+ LAST_RELEASE(pmk1)
+
+ CreateFileMoniker(pszPath1, &pmk1);
+
+ hr = CreateFileMoniker(pszPath2, &pmk6);
+
+ TEST_FAILED_HR(FAILED(hr), "CreateFileMoniker for path2 failed")
+
+ //
+ // Test Item Monikers
+ //
+ hr = CreateItemMoniker(L"\\", L"1", &pmk2);
+
+ TEST_FAILED_HR(FAILED(hr), "CreateItemMoniker 1 failed")
+
+ hr = CreateBindCtx(0, &pbc);
+
+ TEST_FAILED_HR(FAILED(hr),
+ "CreateBindCtx Item Moniker GetDisplayName failed!")
+
+ hr = pmk2->GetDisplayName(pbc, NULL, &szName);
+
+ pbc.Set(NULL);
+
+ TEST_FAILED_HR(FAILED(hr), "Item Moniker GetDisplayName failed!");
+
+ TEST_FAILED((wcscmp(szName, L"\\1") != 0), "Wrong path from item mon");
+
+ // Free the path
+ pIMalloc->Free(szName);
+
+ hr = CreateItemMoniker(L"\\", L"2", &pmk3);
+
+ TEST_FAILED_HR(FAILED(hr), "CreateItemMoniker 0 failed")
+
+ hr = pmk3->Inverse(&pmk4);
+
+ TEST_FAILED_HR(FAILED(hr), "Inverse of 0 failed")
+
+ hr = CreateBindCtx(0, &pbc);
+
+ TEST_FAILED_HR(FAILED(hr), "CreateBindCtx after inverse failed")
+
+ hr = pmk4->GetDisplayName(pbc, NULL, &szName);
+
+ TEST_FAILED_HR(FAILED(hr), "GetDisplayName on AntiMoniker failed")
+
+ TEST_FAILED((memcmp(szName, L"\\..", sizeof(L"\\..")) != 0),
+ "GetDisplayName on AntiMoniker name wrong\n")
+
+ // Free memory API allocated.
+ pIMalloc->Free(szName);
+
+ // Release interfaces we are finished with
+ LAST_RELEASE(pbc)
+ LAST_RELEASE(pmk4)
+
+ //
+ // Test composition of file moniker & item moniker
+ //
+ hr = pmk1->ComposeWith(pmk2, FALSE, &pmk4);
+
+ TEST_FAILED_HR(FAILED(hr), "ComposeWith failed")
+
+ hr = CreateBindCtx(0, &pbc);
+
+ TEST_FAILED_HR(FAILED(hr),
+ "CreateBindCtx Composite Moniker GetDisplayName failed!")
+
+ hr = pmk4->GetDisplayName(pbc, NULL, &szName);
+
+ pbc.Set(NULL);
+
+ TEST_FAILED_HR(FAILED(hr), "GetDisplayName on Composite moniker failed")
+
+ // Free memory API allocated.
+ pIMalloc->Free(szName);
+
+ Sleep(10);
+ hr = BindMoniker(pmk4, 0, IID_IUnknown, (LPVOID FAR*) &pUnk);
+
+ TEST_FAILED_HR(FAILED(hr), "BindMoniker with composed moniker failed")
+
+ TEST_FAILED((pUnk == NULL),
+ "BindMoniker with composed moniker returned NULL punk\n")
+
+ hr = pUnk->QueryInterface(IID_IOleObject, (LPVOID FAR*) &pObj);
+
+ TEST_FAILED_HR(FAILED(hr), "QI to IID_IOleObject failed")
+
+ TEST_FAILED((pObj == NULL),
+ "pObj returned from QI invalid")
+
+ hr = pmk6->ComposeWith(pmk3, FALSE, &pmk5);
+
+ TEST_FAILED_HR(FAILED(hr), "ComposedWith of pmk6 failed")
+
+ hr = BindMoniker(pmk5, 0, IID_IUnknown, (LPVOID FAR*) &pUnk1);
+
+ TEST_FAILED_HR(FAILED(hr), "BindMoniker of pmk5 failed")
+
+ hr = OleRun(pUnk1);
+
+ TEST_FAILED_HR(FAILED(hr), "OleRun call failed")
+
+ TEST_FAILED_HR(FAILED(hr), "GetObject Failed");
+
+ // Clean up objects
+ pObj.Set(NULL);
+ LAST_RELEASE(pUnk1);
+ LAST_RELEASE(pmk5);
+ LAST_RELEASE(pUnk);
+ LAST_RELEASE(pmk6);
+
+ //
+ // Test Marshal/Unmarshal Moniker
+ //
+ // Make a moniker to marshal
+ hr = pmk4->ComposeWith(pmk3, FALSE, &pmk6);
+
+ TEST_FAILED_HR(FAILED(hr), "Compose of moniker for marshal test failed");
+
+ // Create a shared memory stream for the marshaled moniker
+ hr = CreateStreamOnHGlobal(NULL, TRUE, &pStm);
+
+ TEST_FAILED((FAILED(hr)), "CreateStreamOnHGlobal")
+
+ // Marshal the interface into the stream
+ hr = CoMarshalInterface(pStm, IID_IMoniker, pmk6, 0, NULL, MSHLFLAGS_NORMAL);
+
+ TEST_FAILED_HR(FAILED(hr), "CoMarshalInterface failed")
+
+ LISet32(large_int, 0);
+ hr = pStm->Seek(large_int, STREAM_SEEK_SET, NULL);
+
+ TEST_FAILED_HR(FAILED(hr), "Seek on shared stream failed")
+
+ hr = CoUnmarshalInterface(pStm, IID_IMoniker, (LPVOID FAR*)&pmk5);
+
+ TEST_FAILED_HR(FAILED(hr), "CoUnmarshalInterface failed")
+
+ // Dump interfaces we are done with
+ LAST_RELEASE(pmk6);
+ LAST_RELEASE(pmk3);
+ LAST_RELEASE(pmk4);
+ LAST_RELEASE(pmk1);
+ LAST_RELEASE(pmk2);
+ LAST_RELEASE(pStm);
+ LAST_RELEASE(pmk5);
+
+ //
+ // Test Moniker Composition
+ //
+ // BUGBUG: Check result
+ hr = CreateFileMoniker(L"\\ole2\\test\\breadth\\servers\\ellipswt",
+ &pmk1);
+
+ TEST_FAILED_HR(FAILED(hr),
+ "First CreateFileMoniker in composition test failed")
+
+ hr = CreateFileMoniker(L"..\\..\\..\\dll\\sdemo1.exe",&pmk2);
+
+ TEST_FAILED_HR(FAILED(hr),
+ "Second CreateFileMoniker in composition test failed")
+
+ hr = pmk1->ComposeWith(pmk2, FALSE, &pmk4);
+
+ TEST_FAILED_HR(FAILED(hr), "ComposeWith of file monikers failed")
+
+ // Dump interfaces we are done with
+ LAST_RELEASE(pmk4);
+ LAST_RELEASE(pmk1);
+ LAST_RELEASE(pmk2);
+
+ //
+ // Testing file moniker CommonPrefixWith
+ //
+ // BUGBUG: Check result
+ hr = CreateFileMoniker(L"\\Ole2\\Test\\Breadth\\Servers\\Ellipswt",
+ &pmk1);
+
+ TEST_FAILED_HR(FAILED(hr),
+ "CommonPrefixWith First CreateFileMoniker failed")
+
+ hr = CreateFileMoniker(
+ L"\\ole2\\test\\breadth\\serverandthensome\\bar", &pmk2);
+
+ TEST_FAILED_HR(FAILED(hr),
+ "CommonPrefixWith second CreateFileMoniker failed")
+
+
+ hr = pmk1->CommonPrefixWith(pmk2, &pmk4);
+
+ TEST_FAILED_HR(FAILED(hr), "CommonPrefixWith failed")
+
+ hr = CreateBindCtx(0, &pbc);
+
+ TEST_FAILED_HR(FAILED(hr),
+ "CreateBindCtx CommonPrefixWith GetDisplayName failed!")
+
+ hr = pmk4->GetDisplayName(pbc, NULL, &szName);
+
+ pbc.Set(NULL);
+
+ TEST_FAILED_HR(FAILED(hr), "CommonPrefixWith: GetDisplayName failed!");
+
+ TEST_FAILED((_wcsicmp(szName, L"\\ole2\\test\\breadth") != 0),
+ "Common prefix with: Wrong Output Path\n");
+
+ // Free the path
+ pIMalloc->Free(szName);
+
+ // Dump monikers we are done with
+ LAST_RELEASE(pmk4);
+ LAST_RELEASE(pmk2);
+ LAST_RELEASE(pmk1);
+
+ //
+ // Testing file moniker RelativePathTo
+ //
+ // BUGBUG: Check result.
+ hr = CreateFileMoniker(L"\\Ole2\\Test\\Breadth\\Servers\\Ellipswt",
+ &pmk1);
+
+ TEST_FAILED_HR(FAILED(hr), "RelativePathTo first CreateFileMoniker failed")
+
+ hr = CreateFileMoniker(
+ L"\\ole2\\test\\breadth\\serverandthensome\\bar", &pmk2);
+
+ TEST_FAILED_HR(FAILED(hr),
+ "RelativePathTo Second CreateFileMoniker failed")
+
+ hr = pmk1->RelativePathTo(pmk2, &pmk4);
+
+ TEST_FAILED_HR(FAILED(hr), "RelativePathTo failed")
+
+
+ hr = CreateBindCtx(0, &pbc);
+
+ TEST_FAILED_HR(FAILED(hr),
+ "CreateBindCtx RelativePathTo GetDisplayName failed!")
+
+ hr = pmk4->GetDisplayName(pbc, NULL, &szName);
+
+ pbc.Set(NULL);
+
+ TEST_FAILED_HR(FAILED(hr), "RelativePathTo: GetDisplayName failed!");
+
+ TEST_FAILED((wcscmp(szName, L"..\\..\\serverandthensome\\bar") != 0),
+ "RelativePathTo: Wrong Output Path");
+
+ // Free the path
+ pIMalloc->Free(szName);
+
+
+ LAST_RELEASE(pmk2);
+ LAST_RELEASE(pmk1);
+ LAST_RELEASE(pmk4);
+
+ //
+ // Testing MkParseDisplayName
+ //
+ hr = CreateBindCtx(0, &pbc);
+
+ TEST_FAILED_HR(FAILED(hr), "MkParseDisplayName CreatebindCtx failed")
+
+ // make a path to the object
+ WCHAR szBuf[256];
+ int cPath1;
+ cPath1 = wcslen(pszPath1);
+ memcpy(szBuf, pszPath1, cPath1 * sizeof(WCHAR));
+ memcpy(szBuf + cPath1, L"\\1", sizeof(L"\\1"));
+
+ hr = MkParseDisplayName(pbc, szBuf, &chEaten, &pmk1);
+
+ TEST_FAILED_HR(FAILED(hr), "MkParseDisplayName failed")
+
+ LAST_RELEASE(pmk1);
+ LAST_RELEASE(pbc);
+
+ //
+ // Test Moniker IsEqual function on equivalent paths
+ // The moniker code should catch some forms of equivalent
+ // paths, but doesn't handle all of them.
+ //
+ //
+
+ hr = CreateFileMoniker(L"first",&pmk1);
+
+ TEST_FAILED_HR(FAILED(hr),
+ "First CreateFileMoniker in IsEqual test failed")
+
+ hr = CreateFileMoniker(L".\\first",&pmk2);
+
+ TEST_FAILED_HR(FAILED(hr),
+ "Second CreateFileMoniker in IsEqual test failed")
+
+ hr = CreateFileMoniker(L"..\\first",&pmk3);
+
+ TEST_FAILED_HR(FAILED(hr),
+ "Third CreateFileMoniker in IsEqual test failed")
+
+ // This moniker variation has been disabled for Cairo
+ // until the moniker code gets unified.
+#ifndef _CAIRO_
+ hr = CreateFileMoniker(L"..\\.first",&pmk4);
+
+ TEST_FAILED_HR(FAILED(hr),
+ "Fourth CreateFileMoniker in IsEqual test failed")
+#endif
+
+ hr = pmk1->IsEqual(pmk2);
+ TEST_FAILED_HR((hr != S_OK), "pmk1->IsEqual(pmk2) failed")
+
+ hr = pmk2->IsEqual(pmk3);
+ TEST_FAILED_HR((hr != S_FALSE), "pmk2->IsEqual(pmk3) failed")
+
+#ifndef _CAIRO_
+ hr = pmk3->IsEqual(pmk4);
+ TEST_FAILED_HR((hr != S_FALSE), "pmk3->IsEqual(pmk4) failed")
+
+ hr = pmk4->IsEqual(pmk4);
+ TEST_FAILED_HR((hr != S_OK), "pmk4->IsEqual(pmk4) failed")
+#endif
+
+ // Dump interfaces we are done with
+ LAST_RELEASE(pmk1);
+ LAST_RELEASE(pmk2);
+ LAST_RELEASE(pmk3);
+
+#ifndef _CAIRO_
+ LAST_RELEASE(pmk4);
+#endif
+
+ //
+ // Test IsRunning
+ //
+
+ // we make up a name based on the pid and an arbitrary string,
+ // so that the name is unique to this process.
+
+ WCHAR wszMkName[MAX_PATH];
+ wcscpy(wszMkName, L"YourStockOptionsDependOnThis");
+ wcscat(wszMkName, &wszPid[1]); // skip leading backslash
+
+ hr = CreateFileMoniker(wszMkName, &pmk1);
+
+ TEST_FAILED_HR(FAILED(hr),
+ "First CreateFileMoniker in IsRunning failed")
+
+ hr = CreateBindCtx(0, &pbc);
+ TEST_FAILED_HR(FAILED(hr),
+ "CreateBindCtx in IsRunning failed")
+
+ //
+ // We shouldn't find the moniker in the ROT
+ //
+ hr = pmk1->IsRunning(pbc,NULL,NULL);
+ TEST_FAILED_HR((hr != S_FALSE),
+ "IsRunning returns other than S_FALSE");
+
+ //
+ // The FileMoniker should ignore pmk1
+ //
+
+ hr = pmk1->IsRunning(pbc,pmk1,NULL);
+ TEST_FAILED_HR((hr != S_FALSE),
+ "IsRunning #2 returns other than S_FALSE");
+
+
+ hr = GetRunningObjectTable(0, &prot);
+
+ TEST_FAILED_HR(FAILED(hr),"IsRunning GetRunningObjectTable failed!");
+
+
+ //
+ // Just for kicks, we are going to register this moniker itself
+ // as running. We needed an IUnknown pointer here, and the moniker
+ // just happens to have one.
+ //
+
+ DWORD dwRegister;
+ DWORD dwRegister2;
+
+ hr = prot->Register(0,pmk1,pmk1,&dwRegister);
+ TEST_FAILED_HR(FAILED(hr),
+ "Register with ROT failed in IsRunning");
+
+ //
+ // We should find the moniker as running
+ //
+ hr = pmk1->IsRunning(pbc,NULL,NULL);
+ TEST_FAILED_HR((hr != S_OK),
+ "IsRunning returns other than S_OK");
+
+ hr = prot->IsRunning(pmk1);
+ TEST_FAILED_HR((hr != S_OK),
+ "IsRunning returns other than S_OK");
+
+ //
+ // Register it again, and we should get notice that it is running
+ //
+ // This test the ROT, and also test the moniker comparision
+ // functions
+ //
+
+ hr = prot->Register(0,pmk1,pmk1,&dwRegister2);
+ TEST_FAILED_HR(hr != MK_S_MONIKERALREADYREGISTERED,
+ "Register with ROT failed in IsRunning");
+
+ hr = prot->IsRunning(pmk1);
+ TEST_FAILED_HR((hr != S_OK),
+ "IsRunning #1 has returned != S_OK");
+
+ hr = prot->Revoke(dwRegister2);
+ TEST_FAILED_HR(FAILED(hr),
+ "Revoke dwRegister2 with ROT failed");
+
+ hr = prot->Revoke(dwRegister2);
+ TEST_FAILED_HR(hr == S_OK,
+ "Revoke dwRegister2 with ROT should have failed");
+
+ //
+ // It is registered twice, it should still be there from the original
+ // registration
+ //
+ hr = pmk1->IsRunning(pbc,NULL,NULL);
+ TEST_FAILED_HR((hr != S_OK),
+ "IsRunning #2 has returned != S_OK");
+
+ //
+ // Cram in a ItemMoniker to test its comparision stuff.
+ //
+ hr = CreateItemMoniker(L"!",L"KevinRo",&pmkItem1);
+ TEST_FAILED_HR(FAILED(hr),
+ "Creating Item Moniker KevinRo");
+
+ hr = CreateItemMoniker(L"!",L"SueA",&pmkItem2);
+ TEST_FAILED_HR(FAILED(hr),
+ "Creating Item Moniker SueA");
+
+ DWORD dwKevinRo;
+ DWORD dwSueA;
+
+ hr = prot->Register(0,pmkItem1,pmkItem1,&dwKevinRo);
+ TEST_FAILED_HR(FAILED(hr),
+ "Register KevinRo with ROT failed in IsRunning");
+
+ hr = prot->Register(0,pmkItem2,pmkItem2,&dwSueA);
+ TEST_FAILED_HR(FAILED(hr),
+ "Register SueA with ROT failed in IsRunning");
+
+ //
+ // Now revoke monikers
+ //
+ hr = prot->Revoke(dwRegister);
+ TEST_FAILED_HR(FAILED(hr),
+ "Revoke with ROT failed in IsRunning");
+ //
+ // We shouldn't find the moniker in the ROT
+ //
+ hr = pmk1->IsRunning(pbc,NULL,NULL);
+ TEST_FAILED_HR((hr != S_FALSE),
+ "IsRunning returns other than S_FALSE");
+
+ //
+ // Now revoke the item monikers.
+ //
+ hr = prot->Revoke(dwKevinRo);
+ TEST_FAILED_HR(FAILED(hr),
+ "Revoke with ROT failed in for KevinRo");
+
+ hr = prot->Revoke(dwSueA);
+ TEST_FAILED_HR(FAILED(hr),
+ "Revoke with ROT failed in for SueA");
+
+ //
+ // An AntiMoniker
+ //
+ hr = CreateAntiMoniker(&pmkAnti);
+ TEST_FAILED_HR(FAILED(hr),
+ "Failed creating AntiMoniker in Comparison Data Test");
+
+ DWORD dwAnti;
+
+ hr = prot->Register(0,pmkAnti,pmkAnti,&dwAnti);
+ TEST_FAILED_HR(FAILED(hr),
+ "Register Anti with ROT failed in IsRunning");
+
+ hr = prot->IsRunning(pmkAnti);
+ TEST_FAILED_HR((hr != S_OK),
+ "IsRunning pmkAnti returns other than S_OK");
+
+ //
+ // Now revoke the 'other' monikers.
+ //
+ hr = prot->Revoke(dwAnti);
+ TEST_FAILED_HR(FAILED(hr),
+ "Revoke with ROT failed in for Anti");
+
+ //
+ // Test file monikers with long file names
+ //
+
+ // Creation
+ hr = CreateFileMoniker(LongDirShort, &pmkLong1);
+
+ TEST_FAILED_HR(FAILED(hr), "CreateFileMoniker for long short failed!")
+
+ TEST_FAILED((pmkLong1 == NULL),
+ "CreateFileMoniker returned a null moniker ptr\n")
+
+ LAST_RELEASE(pmkLong1);
+
+ // Equivalence with short name version
+ hr = CreateFileMoniker(LongDirLong, &pmkLong1);
+
+ TEST_FAILED_HR(FAILED(hr), "CreateFileMoniker for long long failed!")
+
+ TEST_FAILED((pmkLong1 == NULL),
+ "CreateFileMoniker returned a null moniker ptr\n")
+
+#if 0
+ // Debug code to print out the display name to check that long
+ // names are handled correctly
+
+ hr = CreateBindCtx(0, &pbc);
+
+ TEST_FAILED_HR(FAILED(hr),
+ "CreateBindCtx File Moniker GetDisplayName failed!")
+
+ hr = pmkLong1->GetDisplayName(pbc, NULL, &szName);
+
+ // release it
+ pbc.Set(NULL, FALSE);
+
+ TEST_FAILED_HR(FAILED(hr), "File Moniker GetDisplayName failed!");
+
+ wprintf(L"Display name: '%s', %d\n", szName, wcslen(szName));
+
+ // Free the path
+ pIMalloc->Free(szName);
+#endif
+
+ hr = CreateFileMoniker(LongDirLongSe, &pmkLong2);
+
+ TEST_FAILED_HR(FAILED(hr), "CreateFileMoniker for long long se failed!")
+
+ TEST_FAILED((pmkLong2 == NULL),
+ "CreateFileMoniker returned a null moniker ptr\n")
+
+ TEST_FAILED(pmkLong1->IsEqual(pmkLong2) != S_OK,
+ "Long file monikers not equal\n");
+
+#if 0
+
+
+ // Debug code to print out the display name to check that long
+ // names are handled correctly
+
+ hr = CreateBindCtx(0, &pbc);
+
+ TEST_FAILED_HR(FAILED(hr),
+ "CreateBindCtx File Moniker GetDisplayName failed!")
+
+ hr = pmkLong2->GetDisplayName(pbc, NULL, &szName);
+
+ // release it
+ pbc.Set(NULL, FALSE);
+
+ TEST_FAILED_HR(FAILED(hr), "File Moniker GetDisplayName failed!");
+
+ wprintf(L"Display name: '%s', %d\n", szName, wcslen(szName));
+
+ // Free the path
+ pIMalloc->Free(szName);
+#endif
+
+ LAST_RELEASE(pmkLong1);
+ LAST_RELEASE(pmkLong2);
+
+ return FALSE;
+}
diff --git a/private/oleutest/olebind/tmoniker.h b/private/oleutest/olebind/tmoniker.h
new file mode 100644
index 000000000..e562cfed7
--- /dev/null
+++ b/private/oleutest/olebind/tmoniker.h
@@ -0,0 +1,10 @@
+#ifndef __TMONIKER_H__
+#define __TMONIKER_H__
+
+BOOL TestBindCtx(void);
+
+BOOL TestROT(REFCLSID clsid);
+
+BOOL TestMoniker(LPWSTR pszPath1, LPWSTR pszPath2);
+
+#endif // __TMONIKER_H__
diff --git a/private/oleutest/olebind/widewrap.cxx b/private/oleutest/olebind/widewrap.cxx
new file mode 100644
index 000000000..0787b9262
--- /dev/null
+++ b/private/oleutest/olebind/widewrap.cxx
@@ -0,0 +1,1840 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1993 - 1993.
+//
+// File: widewrap.cxx
+//
+// Contents: Unicode wrapper API, used only on Chicago
+//
+// Functions: About fifty Win32 function wrappers
+//
+// Notes: 'sz' is used instead of the "correct" hungarian 'psz'
+// throughout to enhance readability.
+//
+// Not all of every Win32 function is wrapped here. Some
+// obscurely-documented features may not be handled correctly
+// in these wrappers. Caller beware.
+//
+// These are privately exported for use by the Shell.
+//
+// History: 28-Dec-93 ErikGav Created
+// 06-14-94 KentCe Various Chicago build fixes.
+// 21-Dec-94 BruceMa Use olewcstombs + other fixes
+// 21-Feb-95 BruceMa Add support for AreFileApisANSI
+//
+//----------------------------------------------------------------------------
+
+#include <windows.h>
+#include "widewrap.h"
+
+size_t olembstowcs(WCHAR *pwsz, const char *psz, size_t cCh);
+size_t olewcstombs(char *psz, const WCHAR *pwsz , size_t cCh);
+
+inline size_t olembstowcs(WCHAR *pwsz, const char *psz, size_t cCh)
+{
+ return MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, psz, -1, pwsz, cCh);
+}
+
+inline size_t olewcstombs(char *psz, const WCHAR *pwsz , size_t cCh)
+{
+ return WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK, pwsz, -1, psz,
+ cCh, NULL, NULL);
+}
+
+#ifdef _CHICAGO_
+
+#define HFINDFILE HANDLE
+#define ERR ((char*) -1)
+
+
+//
+// BUGBUG: 9869
+//
+// The length of a Unicode string (in chars) and a DBCS string are not
+// always equal. We need to review all WideChar to MultiByte conversions
+// logic to verify that the proper result buffer size is used.
+//
+// Make the below Win95 only change to get the Win95 FE build out.
+//
+
+int UnicodeToAnsi(LPSTR sz, LPCWSTR pwsz, LONG cb)
+{
+ int ret;
+
+ ret = WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK, pwsz, -1, sz, cb, NULL, NULL);
+
+#if DBG==1
+ if (ret == -1)
+ {
+ DebugBreak();
+ }
+#endif
+
+ return ret;
+}
+
+
+int UnicodeToAnsiOem(LPSTR sz, LPCWSTR pwsz, LONG cb)
+{
+ int ret;
+
+ if (AreFileApisANSI())
+ {
+ ret = WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK, pwsz, -1, sz,
+ cb, NULL, NULL);
+ }
+ else
+ {
+ ret = WideCharToMultiByte(CP_OEMCP, WC_COMPOSITECHECK, pwsz, -1, sz,
+ cb, NULL, NULL);
+ }
+
+#if DBG==1
+ if (ret == -1)
+ {
+ DebugBreak();
+ }
+#endif
+
+ return ret;
+}
+
+
+
+#if DBG==1
+int AnsiToUnicode(LPWSTR pwsz, LPCSTR sz, LONG cb)
+{
+ int ret;
+
+ ret = olembstowcs(pwsz, sz, cb);
+
+ if (ret == -1)
+ {
+ DebugBreak();
+ }
+
+ return ret;
+}
+#else
+#define AnsiToUnicode olembstowcs
+#endif
+
+
+
+int AnsiToUnicodeOem(LPWSTR pwsz, LPCSTR sz, LONG cb)
+{
+ int ret;
+
+ if (AreFileApisANSI())
+ {
+ ret = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, sz, cb, pwsz, cb);
+ }
+ else
+ {
+ ret = MultiByteToWideChar(CP_OEMCP, MB_PRECOMPOSED, sz, cb, pwsz, cb);
+ }
+
+#if DBG==1
+ if (ret == -1)
+ {
+ DebugBreak();
+ }
+#endif
+
+ return ret;
+}
+
+
+
+
+LPSTR Convert(LPCWSTR pwsz)
+{
+ LONG len;
+ LPSTR sz = NULL;
+
+ if (pwsz == NULL)
+ goto Exit;
+
+#if DBG==1
+ // some Win32 API accept atoms in their string parameters
+#endif
+
+ len = (wcslen(pwsz) + 1) * 2;
+
+ sz = new CHAR[len];
+ if (sz==NULL)
+ {
+ sz = ERR;
+ goto Exit;
+ }
+
+ __try
+ {
+ UnicodeToAnsi(sz, pwsz, len);
+ }
+ __except(EXCEPTION_EXECUTE_HANDLER)
+ {
+#if DBG==1
+ MessageBoxA(NULL, "GP fault in unicode conversion -- caught",
+ NULL, MB_OK);
+#endif
+ if (sz)
+ delete sz;
+ sz = ERR;
+ }
+
+Exit:
+ return sz;
+}
+
+
+
+
+
+
+
+
+
+LPSTR ConvertOem(LPCWSTR pwsz)
+{
+ LONG len;
+ LPSTR sz = NULL;
+
+ if (pwsz == NULL)
+ goto Exit;
+
+#if DBG==1
+ // some Win32 API accept atoms in their string parameters
+#endif
+
+ len = (wcslen(pwsz) + 1) * 2;
+
+ sz = new CHAR[len];
+ if (sz==NULL)
+ {
+ sz = ERR;
+ goto Exit;
+ }
+
+ __try
+ {
+ UnicodeToAnsiOem(sz, pwsz, len);
+ }
+ __except(EXCEPTION_EXECUTE_HANDLER)
+ {
+#if DBG==1
+ MessageBoxA(NULL, "GP fault in unicode conversion -- caught",
+ NULL, MB_OK);
+#endif
+ if (sz)
+ delete sz;
+ sz = ERR;
+ }
+
+Exit:
+ return sz;
+}
+
+
+
+
+
+HANDLE WINAPI CreateFileX(LPCWSTR pwsz, DWORD fdwAccess, DWORD fdwShareMask,
+ LPSECURITY_ATTRIBUTES lpsa, DWORD fdwCreate, DWORD fdwAttrsAndFlags,
+ HANDLE hTemplateFile)
+{
+ #ifdef DEBUG_OUTPUT
+ OutputDebugString("CreateFile\n");
+ #endif
+
+ CHAR sz[MAX_PATH * 2];
+ UnicodeToAnsiOem(sz, pwsz, sizeof(sz));
+
+ return CreateFileA(sz, fdwAccess, fdwShareMask, lpsa, fdwCreate,
+ fdwAttrsAndFlags, hTemplateFile);
+}
+
+BOOL WINAPI DeleteFileX(LPCWSTR pwsz)
+{
+ #ifdef DEBUG_OUTPUT
+ OutputDebugString("DeleteFile\n");
+ #endif
+
+ CHAR sz[MAX_PATH * 2];
+ UnicodeToAnsi(sz, pwsz, sizeof(sz));
+
+ return DeleteFileA(sz);
+}
+
+
+LONG APIENTRY RegOpenKeyX(HKEY hKey, LPCWSTR pwszSubKey, PHKEY phkResult)
+{
+ #ifdef DEBUG_OUTPUT
+ OutputDebugString("RegOpenKey\n");
+ #endif
+
+ LONG ret;
+ LPSTR sz;
+
+ sz = Convert(pwszSubKey);
+
+ if (sz == ERR)
+ {
+ return ERROR_OUTOFMEMORY;
+ }
+
+ ret = RegOpenKeyA(hKey, sz, phkResult);
+ if (sz)
+ delete sz;
+ return ret;
+}
+
+LONG APIENTRY RegQueryValueX(HKEY hKey, LPCWSTR pwszSubKey, LPWSTR pwszValue,
+ PLONG lpcbValue)
+{
+ #ifdef DEBUG_OUTPUT
+ OutputDebugString("RegQueryValue\n");
+ #endif
+
+ LONG cb, ret;
+ LPSTR szValue = NULL;
+ LPSTR sz;
+
+ sz = Convert(pwszSubKey);
+ if (sz == ERR)
+ {
+ return ERROR_OUTOFMEMORY;
+ }
+
+ ret = RegQueryValueA(hKey, sz, NULL, &cb);
+
+ // If the caller was just asking for the size of the value, jump out
+ // now, without actually retrieving and converting the value.
+
+ if (pwszValue == NULL)
+ {
+ // Adjust size of buffer to report, to account for CHAR -> WCHAR
+ *lpcbValue = cb * sizeof(WCHAR);
+ goto Exit;
+ }
+
+
+ if (ret == ERROR_SUCCESS)
+ {
+ // If the caller was asking for the value, but allocated too small
+ // of a buffer, set the buffer size and jump out.
+
+ if (*lpcbValue < (LONG) (cb * sizeof(WCHAR)))
+ {
+ // Adjust size of buffer to report, to account for CHAR -> WCHAR
+ *lpcbValue = cb * sizeof(WCHAR);
+ ret = ERROR_MORE_DATA;
+ goto Exit;
+ }
+
+ // Otherwise, retrieve and convert the value.
+
+ szValue = new CHAR[cb];
+ if (szValue == NULL)
+ {
+ ret = ERROR_OUTOFMEMORY;
+ goto Exit;
+ }
+
+ ret = RegQueryValueA(hKey, sz, szValue, &cb);
+
+ if (ret == ERROR_SUCCESS)
+ {
+ AnsiToUnicode(pwszValue, szValue, cb);
+
+ // Adjust size of buffer to report, to account for CHAR -> WCHAR
+ *lpcbValue = cb * sizeof(WCHAR);
+ }
+ }
+
+Exit:
+ if (szValue)
+ delete szValue;
+ if (sz)
+ delete sz;
+
+ return ret;
+}
+
+LONG APIENTRY RegSetValueX(HKEY hKey, LPCWSTR lpSubKey, DWORD dwType,
+ LPCWSTR lpData, DWORD cbData)
+{
+ #ifdef DEBUG_OUTPUT
+ OutputDebugString("RegSetValue\n");
+ #endif
+
+ LPSTR szKey = NULL;
+ LPSTR szValue = NULL;
+ LONG ret = ERROR_OUTOFMEMORY;
+
+ szKey = Convert(lpSubKey);
+ if (szKey == ERR)
+ {
+ szKey = NULL;
+ goto Exit;
+ }
+
+ szValue = Convert(lpData);
+ if (szValue == ERR)
+ {
+ szValue = NULL;
+ goto Exit;
+ }
+
+ ret = RegSetValueA(hKey, szKey, dwType, szValue, cbData);
+
+Exit:
+ if (szKey)
+ delete szKey;
+ if (szValue)
+ delete szValue;
+ return ret;
+}
+
+LONG APIENTRY RegSetValueExX(HKEY hKey,
+ LPCWSTR lpSubKey,
+ DWORD dwReserved,
+ DWORD dwType,
+ LPBYTE lpData,
+ DWORD cbData)
+{
+ #ifdef DEBUG_OUTPUT
+ OutputDebugString("RegSetValueEx\n");
+ #endif
+
+ LPSTR szKey = NULL;
+ LPBYTE szValue = lpData;
+ LONG ret = ERROR_OUTOFMEMORY;
+
+ szKey = Convert(lpSubKey);
+ if (szKey == ERR)
+ {
+ szKey = NULL;
+ goto Exit;
+ }
+
+ if (dwType == REG_SZ)
+ {
+ szValue = (LPBYTE) Convert((LPWSTR)lpData);
+ }
+ if (szValue == (LPBYTE) ERR)
+ {
+ szValue = NULL;
+ goto Exit;
+ }
+
+ ret = RegSetValueExA(hKey, szKey, dwReserved, dwType, szValue, cbData);
+
+Exit:
+ if (szKey)
+ delete szKey;
+ if ((szValue != lpData) && (szValue != (LPBYTE)ERR))
+ delete szValue;
+ return ret;
+}
+
+UINT WINAPI RegisterWindowMessageX(LPCWSTR lpString)
+{
+ #ifdef DEBUG_OUTPUT
+ OutputDebugString("RegisterWindowMessage\n");
+ #endif
+
+ UINT ret;
+#if 0
+ LPSTR sz;
+
+ sz = Convert(lpString);
+ if (sz == ERR)
+ {
+ return 0;
+ }
+#else
+ // BUGBUG: CairOLE calls this from libmain -- have to use static buffer
+
+ CHAR sz[200];
+ UnicodeToAnsi(sz, lpString, sizeof(sz));
+#endif
+
+ ret = RegisterWindowMessageA(sz);
+#if 0
+ delete sz;
+#endif
+ return ret;
+}
+
+LONG
+APIENTRY
+RegOpenKeyExX (
+ HKEY hKey,
+ LPCWSTR lpSubKey,
+ DWORD ulOptions,
+ REGSAM samDesired,
+ PHKEY phkResult
+ )
+{
+ #ifdef DEBUG_OUTPUT
+ OutputDebugString("RegOpenKeyEx\n");
+ #endif
+
+ LONG ret;
+ LPSTR sz;
+
+ sz = Convert(lpSubKey);
+ if (sz == ERR)
+ {
+ return ERROR_OUTOFMEMORY;
+ }
+
+ ret = RegOpenKeyExA(hKey, sz, ulOptions, samDesired, phkResult);
+ if (sz)
+ delete sz;
+ return ret;
+}
+
+LONG
+APIENTRY
+RegQueryValueExX(
+ HKEY hKey,
+ LPWSTR lpValueName,
+ LPDWORD lpReserved,
+ LPDWORD lpType,
+ LPBYTE lpData,
+ LPDWORD lpcbData
+ )
+{
+ #ifdef DEBUG_OUTPUT
+ OutputDebugString("RegQueryValueEx\n");
+ #endif
+
+ LPBYTE lpTempBuffer;
+ DWORD dwTempType;
+ DWORD cb, cbRequired;
+ LONG ret;
+ LPSTR sz;
+ LPWSTR pwszTempWide;
+ LPSTR pszTempNarrow;
+ ULONG ulStringLength;
+
+ sz = Convert(lpValueName);
+ if (sz == ERR)
+ {
+ return ERROR_OUTOFMEMORY;
+ }
+
+ ret = RegQueryValueExA(hKey, sz, lpReserved, &dwTempType, NULL, &cb);
+
+ // If the caller was just asking for the size of the value, jump out
+ // now, without actually retrieving and converting the value.
+
+ if (lpData == NULL)
+ {
+ switch (dwTempType)
+ {
+ case REG_EXPAND_SZ:
+ case REG_MULTI_SZ:
+ case REG_SZ:
+
+ // Adjust size of buffer to report, to account for CHAR -> WCHAR
+
+ if (lpcbData != NULL)
+ *lpcbData = cb * sizeof(WCHAR);
+ break;
+
+ default:
+
+ if (lpcbData != NULL)
+ *lpcbData = cb;
+ break;
+ }
+
+ // Set the type, if required.
+ if (lpType != NULL)
+ {
+ *lpType = dwTempType;
+ }
+
+ goto Exit;
+ }
+
+
+ if (ret == ERROR_SUCCESS)
+ {
+ //
+ // Determine the size of buffer needed
+ //
+
+ switch (dwTempType)
+ {
+ case REG_EXPAND_SZ:
+ case REG_MULTI_SZ:
+ case REG_SZ:
+
+ cbRequired = cb * sizeof(WCHAR);
+ break;
+
+ default:
+
+ cbRequired = cb;
+ break;
+ }
+
+ // If the caller was asking for the value, but allocated too small
+ // of a buffer, set the buffer size and jump out.
+
+ if (lpcbData != NULL && *lpcbData < cbRequired)
+ {
+ // Adjust size of buffer to report, to account for CHAR -> WCHAR
+ *lpcbData = cbRequired;
+
+ // Set the type, if required.
+ if (lpType != NULL)
+ {
+ *lpType = dwTempType;
+ }
+
+ ret = ERROR_MORE_DATA;
+ goto Exit;
+ }
+
+ // Otherwise, retrieve and convert the value.
+
+ switch (dwTempType)
+ {
+ case REG_EXPAND_SZ:
+ case REG_MULTI_SZ:
+ case REG_SZ:
+
+ lpTempBuffer = new BYTE[cbRequired];
+ if (lpTempBuffer == NULL)
+ {
+ return ERROR_OUTOFMEMORY;
+ }
+
+ ret = RegQueryValueExA(hKey,
+ sz,
+ lpReserved,
+ &dwTempType,
+ lpTempBuffer,
+ &cb);
+
+ if (ret == ERROR_SUCCESS)
+ {
+ switch (dwTempType)
+ {
+ case REG_EXPAND_SZ:
+ case REG_SZ:
+
+ AnsiToUnicode((LPWSTR) lpData, (LPSTR) lpTempBuffer, cb);
+
+ // Adjust size of buffer to report, to account for CHAR -> WCHAR
+ *lpcbData = cbRequired;
+
+ // Set the type, if required.
+ if (lpType != NULL)
+ {
+ *lpType = dwTempType;
+ }
+ break;
+
+ case REG_MULTI_SZ:
+
+ pszTempNarrow = (LPSTR) lpTempBuffer;
+ pwszTempWide = (LPWSTR) lpData;
+
+ while (pszTempNarrow != NULL)
+ {
+ ulStringLength = strlen(pszTempNarrow) + 1;
+ AnsiToUnicode(pwszTempWide,
+ pszTempNarrow,
+ ulStringLength);
+
+ // Compiler will scale appropriately here
+ pszTempNarrow += ulStringLength;
+ pwszTempWide += ulStringLength;
+ }
+ break;
+ }
+ }
+
+ if (lpTempBuffer)
+ delete lpTempBuffer;
+
+ break;
+
+ default:
+
+ //
+ // No conversion of out parameters needed. Just call narrow
+ // version with args passed in, and return directly.
+ //
+
+ ret = RegQueryValueExA(hKey,
+ sz,
+ lpReserved,
+ lpType,
+ lpData,
+ lpcbData);
+
+ }
+ }
+
+Exit:
+ if (sz)
+ delete sz;
+ return ret;
+}
+
+
+
+ATOM
+WINAPI
+RegisterClassX(
+ CONST WNDCLASSW *lpWndClass)
+{
+ #ifdef DEBUG_OUTPUT
+ OutputDebugString("RegisterClass\n");
+ #endif
+
+ WNDCLASSA wc;
+ ATOM ret;
+ BOOL fAtom = FALSE;
+
+
+ memcpy(&wc, lpWndClass, sizeof(WNDCLASS));
+
+ wc.lpszMenuName = Convert(lpWndClass->lpszMenuName);
+ if (wc.lpszMenuName==ERR)
+ {
+ return NULL;
+ }
+
+ if (HIWORD(lpWndClass->lpszClassName) == 0)
+ {
+ wc.lpszClassName = (LPSTR) lpWndClass->lpszClassName;
+ fAtom = TRUE;
+ }
+ else
+ {
+ wc.lpszClassName = Convert(lpWndClass->lpszClassName);
+ if (wc.lpszClassName==ERR)
+ {
+ if ((LPSTR) wc.lpszMenuName)
+ delete (LPSTR) wc.lpszMenuName;
+ return NULL;
+ }
+ }
+
+ ret = RegisterClassA(&wc);
+ if ((LPSTR) wc.lpszMenuName)
+ delete (LPSTR) wc.lpszMenuName;
+ if (!fAtom) delete (LPSTR) wc.lpszClassName;
+ return ret;
+}
+
+BOOL
+WINAPI
+UnregisterClassX(
+ LPCWSTR lpClassName,
+ HINSTANCE hInstance)
+{
+ #ifdef DEBUG_OUTPUT
+ OutputDebugString("UnregisterClass\n");
+ #endif
+
+ LPSTR sz;
+ BOOL ret;
+ BOOL fAtom = FALSE;
+
+ if (HIWORD(lpClassName) == 0)
+ {
+ sz = (LPSTR) lpClassName;
+ fAtom = TRUE;
+ }
+ else
+ {
+ sz = Convert(lpClassName);
+ if (sz == ERR)
+ return FALSE;
+ }
+
+ ret = UnregisterClassA(sz, hInstance);
+ if (!fAtom) delete sz;
+ return ret;
+}
+
+HANDLE
+WINAPI
+GetPropX(
+ HWND hWnd,
+ LPCWSTR lpString)
+{
+ #ifdef DEBUG_OUTPUT
+ OutputDebugString("GetProp\n");
+ #endif
+
+ HANDLE ret;
+ LPSTR sz;
+ BOOL fAtom = FALSE;
+
+ if (HIWORD(lpString)==0)
+ {
+ fAtom = TRUE;
+ sz = (LPSTR) lpString;
+ }
+ else
+ {
+ sz = Convert(lpString);
+ if (sz == ERR)
+ return NULL;
+ }
+
+ ret = GetPropA(hWnd, sz);
+ if (!fAtom) delete sz;
+ return ret;
+}
+
+
+BOOL
+WINAPI
+SetPropX(
+ HWND hWnd,
+ LPCWSTR lpString,
+ HANDLE hData)
+{
+ #ifdef DEBUG_OUTPUT
+ OutputDebugString("SetProp\n");
+ #endif
+
+ BOOL ret;
+ LPSTR sz;
+ BOOL fAtom = FALSE;
+
+ if (HIWORD(lpString)==0)
+ {
+ sz = (LPSTR) lpString;
+ fAtom = TRUE;
+ }
+ else
+ {
+ sz = Convert(lpString);
+ if (sz == ERR)
+ return NULL;
+ }
+
+ ret = SetPropA(hWnd, sz, hData);
+ if (!fAtom) delete sz;
+ return ret;
+}
+
+
+HANDLE
+WINAPI
+RemovePropX(
+ HWND hWnd,
+ LPCWSTR lpString)
+{
+ #ifdef DEBUG_OUTPUT
+ OutputDebugString("RemoveProp\n");
+ #endif
+
+ HANDLE ret;
+ LPSTR sz;
+ BOOL fAtom = FALSE;
+
+ if (HIWORD(lpString)==0)
+ {
+ sz = (LPSTR) lpString;
+ fAtom = TRUE;
+ }
+ else
+ {
+ sz = Convert(lpString);
+ if (sz == ERR)
+ return NULL;
+ }
+
+ ret = RemovePropA(hWnd, sz);
+ if (!fAtom) delete sz;
+ return ret;
+}
+
+
+UINT
+WINAPI
+GetProfileIntX(
+ LPCWSTR lpAppName,
+ LPCWSTR lpKeyName,
+ INT nDefault
+ )
+{
+ #ifdef DEBUG_OUTPUT
+ OutputDebugString("GetProfileInt\n");
+ #endif
+
+ LPSTR szApp;
+ LPSTR szKey;
+ UINT ret;
+
+ szApp = Convert(lpAppName);
+ if (szApp==ERR)
+ {
+ return nDefault;
+ }
+
+ szKey = Convert(lpKeyName);
+ if (szApp==ERR)
+ {
+ if (szApp)
+ delete szApp;
+ return nDefault;
+ }
+
+ ret = GetProfileIntA(szApp, szKey, nDefault);
+ if (szApp)
+ delete szApp;
+ if (szKey)
+ delete szKey;
+ return ret;
+}
+
+ATOM
+WINAPI
+GlobalAddAtomX(
+ LPCWSTR lpString
+ )
+{
+ #ifdef DEBUG_OUTPUT
+ OutputDebugString("GlobalAddAtom\n");
+ #endif
+
+ ATOM ret;
+ LPSTR sz;
+
+ sz = Convert(lpString);
+ if (sz==ERR)
+ {
+ return NULL;
+ }
+
+ ret = GlobalAddAtomA(sz);
+ if (sz)
+ delete sz;
+ return ret;
+}
+
+UINT
+WINAPI
+GlobalGetAtomNameX(
+ ATOM nAtom,
+ LPWSTR pwszBuffer,
+ int nSize
+ )
+{
+ #ifdef DEBUG_OUTPUT
+ OutputDebugString("GlobalGetAtomName\n");
+ #endif
+
+ LPSTR sz;
+ UINT ret;
+
+ sz = new CHAR[nSize];
+ if (sz == NULL)
+ {
+ return 0;
+ }
+
+ ret = GlobalGetAtomNameA(nAtom, sz, nSize);
+ if (ret)
+ {
+ AnsiToUnicode(pwszBuffer, sz, lstrlenA(sz) + 1);
+ }
+ if (sz)
+ delete sz;
+ return ret;
+}
+
+
+DWORD
+WINAPI
+GetModuleFileNameX(
+ HINSTANCE hModule,
+ LPWSTR pwszFilename,
+ DWORD nSize
+ )
+{
+ #ifdef DEBUG_OUTPUT
+ OutputDebugString("GetModuleFileName\n");
+ #endif
+
+ LPSTR sz;
+ DWORD ret;
+
+ sz = new CHAR[nSize];
+ if (sz == NULL)
+ {
+ return 0;
+ }
+
+ ret = GetModuleFileNameA(hModule, sz, nSize);
+ if (ret)
+ {
+ AnsiToUnicode(pwszFilename, sz, lstrlenA(sz) + 1);
+ }
+
+ if (sz)
+ delete sz;
+ return ret;
+}
+
+
+LPWSTR
+WINAPI
+CharPrevX(
+ LPCWSTR lpszStart,
+ LPCWSTR lpszCurrent)
+{
+ #ifdef DEBUG_OUTPUT
+ OutputDebugString("CharPrev\n");
+ #endif
+
+ if (lpszCurrent == lpszStart)
+ {
+ return (LPWSTR) lpszStart;
+ }
+ else
+ {
+ return (LPWSTR) lpszCurrent - 1;
+ }
+}
+
+HFONT WINAPI CreateFontX(int a, int b, int c, int d, int e, DWORD f,
+ DWORD g, DWORD h, DWORD i, DWORD j, DWORD k,
+ DWORD l, DWORD m, LPCWSTR pwsz)
+{
+ #ifdef DEBUG_OUTPUT
+ OutputDebugString("CreateFont\n");
+ #endif
+
+ LPSTR sz;
+ HFONT ret;
+
+ sz = Convert(pwsz);
+ if (sz == ERR)
+ {
+ return NULL;
+ }
+
+ ret = CreateFontA(a,b,c,d,e,f,g,h,i,j,k,l,m,sz);
+ if (sz)
+ delete sz;
+ return ret;
+}
+
+
+HINSTANCE
+WINAPI
+LoadLibraryX(
+ LPCWSTR pwszFileName
+ )
+{
+ #ifdef DEBUG_OUTPUT
+ OutputDebugString("LoadLibrary\n");
+ #endif
+
+ HINSTANCE ret;
+ LPSTR sz;
+
+ sz = Convert(pwszFileName);
+ if (sz == ERR)
+ {
+ return NULL;
+ }
+
+ ret = LoadLibraryA(sz);
+ if (sz)
+ delete sz;
+ return ret;
+}
+
+
+HMODULE
+WINAPI
+LoadLibraryExX(
+ LPCWSTR lpLibFileName,
+ HANDLE hFile,
+ DWORD dwFlags
+ )
+{
+ #ifdef DEBUG_OUTPUT
+ OutputDebugString("LoadLibrary\n");
+ #endif
+
+ HINSTANCE ret;
+ LPSTR sz;
+
+ sz = ConvertOem(lpLibFileName);
+ if (sz == ERR)
+ {
+ return NULL;
+ }
+
+ ret = LoadLibraryExA(sz, hFile, dwFlags);
+ if (sz)
+ delete sz;
+ return ret;
+}
+
+
+
+LONG
+APIENTRY
+RegDeleteKeyX(
+ HKEY hKey,
+ LPCWSTR pwszSubKey
+ )
+{
+ #ifdef DEBUG_OUTPUT
+ OutputDebugString("RegDeleteKey\n");
+ #endif
+
+ LONG ret;
+ LPSTR sz;
+
+ sz = Convert(pwszSubKey);
+ if (sz == ERR)
+ {
+ return ERROR_OUTOFMEMORY;
+ }
+
+ ret = RegDeleteKeyA(hKey, sz);
+ if (sz)
+ delete sz;
+ return ret;
+}
+
+BOOL
+APIENTRY
+CreateProcessX(
+ LPCWSTR lpApplicationName,
+ LPWSTR lpCommandLine,
+ LPSECURITY_ATTRIBUTES lpProcessAttributes,
+ LPSECURITY_ATTRIBUTES lpThreadAttributes,
+ BOOL bInheritHandles,
+ DWORD dwCreationFlags,
+ LPVOID lpEnvironment,
+ LPCWSTR lpCurrentDirectory,
+ LPSTARTUPINFOW lpStartupInfo,
+ LPPROCESS_INFORMATION lpProcessInformation
+ )
+{
+ #ifdef DEBUG_OUTPUT
+ OutputDebugString("CreateProcess\n");
+ #endif
+
+ STARTUPINFOA si;
+ BOOL ret = FALSE;
+ LPSTR szApp = NULL;
+ LPSTR szCommand = NULL;
+ LPSTR szDir = NULL;
+
+ memcpy(&si, lpStartupInfo, sizeof(STARTUPINFO));
+
+ si.lpTitle = NULL;
+
+ si.lpDesktop = Convert(lpStartupInfo->lpDesktop);
+ if (si.lpDesktop == ERR)
+ {
+ si.lpDesktop = NULL;
+ goto Error;
+ }
+ si.lpTitle = Convert(lpStartupInfo->lpTitle);
+ if (si.lpTitle == ERR)
+ {
+ si.lpTitle = NULL;
+ goto Error;
+ }
+
+ szApp = Convert(lpApplicationName);
+ if (szApp == ERR)
+ {
+ szApp = NULL;
+ goto Error;
+ }
+ szCommand = ConvertOem(lpCommandLine);
+ if (szCommand == ERR)
+ {
+ szCommand = NULL;
+ goto Error;
+ }
+ szDir = Convert(lpCurrentDirectory);
+ if (szDir == ERR)
+ {
+ szDir = NULL;
+ goto Error;
+ }
+
+ ret = CreateProcessA(szApp, szCommand, lpProcessAttributes,
+ lpThreadAttributes, bInheritHandles, dwCreationFlags,
+ lpEnvironment, szDir, &si, lpProcessInformation);
+
+Error:
+ if (si.lpDesktop)
+ delete si.lpDesktop;
+ if (si.lpTitle)
+ delete si.lpTitle;
+
+ if (szApp)
+ delete szApp;
+ if (szCommand)
+ delete szCommand;
+ if (szDir)
+ delete szDir;
+
+ return ret;
+}
+
+LONG
+APIENTRY
+RegEnumKeyExX(
+ HKEY hKey,
+ DWORD dwIndex,
+ LPWSTR lpName,
+ LPDWORD lpcbName,
+ LPDWORD lpReserved,
+ LPWSTR lpClass,
+ LPDWORD lpcbClass,
+ PFILETIME lpftLastWriteTime
+ )
+{
+ #ifdef DEBUG_OUTPUT
+ OutputDebugString("RegEnumKeyEx\n");
+ #endif
+
+ LPSTR szName;
+ LPSTR szClass = NULL;
+ LONG ret = ERROR_OUTOFMEMORY;
+
+ szName = new CHAR[*lpcbName];
+ if (szName == NULL)
+ goto Exit;
+
+ if (lpClass != NULL)
+ {
+ szClass = new CHAR[*lpcbClass + 1];
+ if (szName == NULL)
+ goto Exit;
+ }
+
+ //
+ // Return lengths do not include zero char.
+ //
+ ret = RegEnumKeyExA(hKey, dwIndex, szName, lpcbName, lpReserved,
+ szClass, lpcbClass, lpftLastWriteTime);
+
+ if (ret == ERROR_SUCCESS)
+ {
+ AnsiToUnicode(lpName, szName, *lpcbName + 1);
+
+ if (szClass)
+ {
+ AnsiToUnicode(lpClass, szClass, *lpcbClass + 1);
+ }
+ }
+
+Exit:
+ return ret;
+}
+
+BOOL
+WINAPI
+AppendMenuX(
+ HMENU hMenu,
+ UINT uFlags,
+ UINT uIDnewItem,
+ LPCWSTR lpnewItem
+ )
+{
+ #ifdef DEBUG_OUTPUT
+ OutputDebugString("AppendMenu\n");
+ #endif
+
+ BOOL ret;
+ LPSTR sz;
+
+ if (uFlags == MF_STRING)
+ {
+ sz = Convert(lpnewItem);
+ if (sz==ERR)
+ {
+ return FALSE;
+ }
+ }
+ else
+ {
+ sz = (LPSTR) lpnewItem;
+ }
+
+ ret = AppendMenuA(hMenu, uFlags, uIDnewItem, sz);
+
+ if (uFlags == MF_STRING)
+ {
+ if (sz)
+ delete sz;
+ }
+
+ return ret;
+}
+
+HANDLE
+WINAPI
+OpenEventX(
+ DWORD dwDesiredAccess,
+ BOOL bInheritHandle,
+ LPCWSTR lpName
+ )
+{
+ #ifdef DEBUG_OUTPUT
+ OutputDebugString("OpenEvent\n");
+ #endif
+
+ LPSTR sz;
+ HANDLE ret;
+
+ sz = Convert(lpName);
+ if (sz == ERR)
+ {
+ return NULL;
+ }
+
+ ret = OpenEventA(dwDesiredAccess, bInheritHandle, sz);
+ if (sz)
+ delete sz;
+ return ret;
+}
+
+HANDLE
+WINAPI
+CreateEventX(
+ LPSECURITY_ATTRIBUTES lpEventAttributes,
+ BOOL bManualReset,
+ BOOL bInitialState,
+ LPCWSTR lpName
+ )
+{
+ #ifdef DEBUG_OUTPUT
+ OutputDebugString("CreateEvent\n");
+ #endif
+
+ LPSTR sz;
+ HANDLE ret;
+
+ sz = Convert(lpName);
+ if (sz == ERR)
+ {
+ return NULL;
+ }
+
+ ret = CreateEventA(lpEventAttributes, bManualReset, bInitialState, sz);
+ if (sz)
+ delete sz;
+ return ret;
+}
+
+UINT
+WINAPI
+GetDriveTypeX(
+ LPCWSTR lpRootPathName
+ )
+{
+ #ifdef DEBUG_OUTPUT
+ OutputDebugString("GetDriveType\n");
+ #endif
+
+ LPSTR sz;
+ UINT ret;
+
+ sz = Convert(lpRootPathName);
+ if (sz == ERR)
+ {
+ return 0;
+ }
+
+ ret = GetDriveTypeA(sz);
+ if (sz)
+ delete sz;
+ return ret;
+}
+
+DWORD
+WINAPI
+GetFileAttributesX(
+ LPCWSTR lpFileName
+ )
+{
+ #ifdef DEBUG_OUTPUT
+ OutputDebugString("GetFileAttributes\n");
+ #endif
+
+ LPSTR sz;
+ DWORD ret;
+
+ sz = ConvertOem(lpFileName);
+ if (sz == ERR)
+ return 0xFFFFFFFF;
+
+ ret = GetFileAttributesA(sz);
+ if (sz)
+ delete sz;
+ return ret;
+}
+
+LONG
+APIENTRY
+RegEnumKeyX(
+ HKEY hKey,
+ DWORD dwIndex,
+ LPWSTR lpName,
+ DWORD cbName
+ )
+{
+ #ifdef DEBUG_OUTPUT
+ OutputDebugString("RegEnumKey\n");
+ #endif
+
+ CHAR sz[MAX_PATH+1];
+ LONG ret;
+
+ //
+ // Return lengths do not include zero char.
+ //
+ ret = RegEnumKeyA(hKey, dwIndex, sz, cbName);
+ if (ret == ERROR_SUCCESS)
+ {
+ AnsiToUnicode(lpName, sz, lstrlenA(sz) + 1);
+ }
+ return ret;
+}
+
+HFINDFILE
+WINAPI
+FindFirstFileX(
+ LPCWSTR lpFileName,
+ LPWIN32_FIND_DATAW pwszFd
+ )
+{
+ #ifdef DEBUG_OUTPUT
+ OutputDebugString("FindFirstFile\n");
+ #endif
+
+ WIN32_FIND_DATAA fd;
+ CHAR sz[MAX_PATH * 2];
+ HFINDFILE ret;
+ int len = wcslen(lpFileName) + 1;
+
+ UnicodeToAnsiOem(sz, lpFileName, sizeof(sz));
+ ret = FindFirstFileA(sz, &fd);
+ if (ret != INVALID_HANDLE_VALUE)
+ {
+ memcpy(pwszFd, &fd, sizeof(FILETIME)*3 + sizeof(DWORD)*5);
+ AnsiToUnicodeOem(pwszFd->cFileName, fd.cFileName,
+ lstrlenA(fd.cFileName) + 1);
+ AnsiToUnicodeOem(pwszFd->cAlternateFileName, fd.cAlternateFileName,
+ 14);
+ }
+
+ return ret;
+}
+
+//+---------------------------------------------------------------------------
+//
+// Function: wsprintfX
+//
+// Synopsis: Nightmare string function
+//
+// Arguments: [pwszOut] --
+// [pwszFormat] --
+// [...] --
+//
+// Returns:
+//
+// History: 1-06-94 ErikGav Created
+//
+// Notes: If you're reading this, you're probably having a problem with
+// this function. Make sure that your "%s" in the format string
+// says "%ws" if you are passing wide strings.
+//
+// %s on NT means "wide string"
+// %s on Chicago means "ANSI string"
+//
+//----------------------------------------------------------------------------
+
+int WINAPIV wsprintfX(LPWSTR pwszOut, LPCWSTR pwszFormat, ...)
+{
+ #ifdef DEBUG_OUTPUT
+ OutputDebugString("wsprintf\n");
+ #endif
+
+ LPSTR szFormat;
+ LPWSTR pwszTemp = NULL;
+ int i = 0;
+
+ // Convert the format string over
+
+ szFormat = Convert(pwszFormat);
+ if (szFormat == ERR)
+ {
+ szFormat = NULL;
+ goto Exit;
+ }
+
+ // magic voodoo follows:
+ //
+ // 1. Call wvsprintf passing the varargs
+ // 2. Use the pwszOut as a temp buffer to hold the ANSI output
+ // 3. Save the returned characters
+
+ i = wvsprintfA((LPSTR) pwszOut, szFormat,
+ (LPSTR) ((BYTE*)&pwszFormat) + sizeof(pwszFormat));
+
+ // allocate a buffer for the Ansi to Unicode conversion
+
+ pwszTemp = new WCHAR[i+1];
+
+ // convert the string
+
+ AnsiToUnicode(pwszTemp, (LPSTR) pwszOut, i+1);
+
+ // copy it to the out buffer
+
+ wcsncpy(pwszOut, pwszTemp, i+1);
+
+Exit:
+ if (pwszTemp)
+ delete pwszTemp;
+ if (szFormat)
+ delete szFormat;
+ return i;
+}
+
+BOOL
+WINAPI
+GetComputerNameX(
+ LPWSTR pwszName,
+ LPDWORD lpcchBuffer
+ )
+{
+ #ifdef DEBUG_OUTPUT
+ OutputDebugString("GetComputerName\n");
+ #endif
+
+ BOOL ret;
+ LPSTR sz;
+
+ sz = new CHAR[*lpcchBuffer];
+ ret = GetComputerNameA(sz, lpcchBuffer);
+
+ if (ret)
+ {
+ AnsiToUnicode(pwszName, sz, *lpcchBuffer);
+ }
+
+ if (sz)
+ delete sz;
+ return ret;
+}
+
+DWORD
+WINAPI
+GetFullPathNameX(
+ LPCWSTR lpFileName,
+ DWORD cchBuffer,
+ LPWSTR lpPathBuffer,
+ LPWSTR *lppFilePart
+ )
+{
+ #ifdef DEBUG_OUTPUT
+ OutputDebugString("GetFullPathName\n");
+ #endif
+
+ LPSTR szFileName;
+ CHAR szPathBuffer[MAX_PATH];
+ LPSTR szFilePart;
+ DWORD ret;
+
+
+ szFileName = ConvertOem(lpFileName);
+ if (szFileName == ERR)
+ return 0;
+
+ ret = GetFullPathNameA(szFileName, cchBuffer, szPathBuffer, &szFilePart);
+
+ AnsiToUnicode(lpPathBuffer, szPathBuffer, cchBuffer);
+
+ *lppFilePart = lpPathBuffer + (szFilePart - szPathBuffer);
+
+ if (szFileName)
+ delete szFileName;
+
+ return ret;
+}
+
+
+DWORD
+WINAPI
+GetShortPathNameX(
+ LPCWSTR lpszFullPath,
+ LPWSTR lpszShortPath,
+ DWORD cchBuffer
+ )
+{
+ #ifdef DEBUG_OUTPUT
+ OutputDebugString("GetShortPathName\n");
+ #endif
+
+ LPSTR szFullPath;
+ CHAR szShortBuffer[MAX_PATH];
+ DWORD ret;
+
+
+ szFullPath = Convert(lpszFullPath);
+ if (szFullPath == ERR)
+ return 0;
+
+ if (lpszShortPath == NULL)
+ {
+ ret = GetShortPathNameA(szFullPath, NULL, cchBuffer);
+ }
+ else
+ {
+ ret = GetShortPathNameA(szFullPath, szShortBuffer, sizeof(szShortBuffer));
+
+ //
+ // Only convert the actual data, not the whole buffer.
+ //
+ if (cchBuffer > ret + 1)
+ cchBuffer = ret + 1;
+
+ AnsiToUnicode(lpszShortPath, szShortBuffer, cchBuffer);
+ }
+
+ delete szFullPath;
+
+ return ret;
+}
+
+
+DWORD
+WINAPI
+SearchPathX(
+ LPCWSTR lpPath,
+ LPCWSTR lpFileName,
+ LPCWSTR lpExtension,
+ DWORD nBufferLength,
+ LPWSTR lpBuffer,
+ LPWSTR *lpFilePart
+ )
+{
+ LPSTR lpszFileName;
+ CHAR szBuffer[MAX_PATH];
+ DWORD ret;
+
+
+ #ifdef DEBUG_OUTPUT
+ OutputDebugString("SearchPath\n");
+ #endif
+
+ lpszFileName = Convert(lpFileName);
+ if (lpszFileName == ERR)
+ return 0;
+
+ ret = SearchPathA(NULL, lpszFileName, NULL, sizeof(szBuffer), szBuffer, NULL);
+
+ AnsiToUnicode(lpBuffer, szBuffer, lstrlenA(szBuffer) + 1);
+
+ delete lpszFileName;
+
+ return ret;
+}
+
+
+ATOM
+WINAPI
+GlobalFindAtomX(
+ LPCWSTR lpString
+ )
+{
+ LPSTR lpszString;
+ ATOM retAtom;
+
+
+ #ifdef DEBUG_OUTPUT
+ OutputDebugString("GlobalFindAtom\n");
+ #endif
+
+ lpszString = Convert(lpString);
+ if (lpszString == ERR)
+ return 0;
+
+ retAtom = GlobalFindAtomA(lpszString);
+
+ delete lpszString;
+
+ return retAtom;
+}
+
+
+int
+WINAPI
+GetClassNameX(
+ HWND hWnd,
+ LPWSTR lpClassName,
+ int nMaxCount)
+{
+ LPSTR lpszClassName;
+ int ret;
+
+
+ #ifdef DEBUG_OUTPUT
+ OutputDebugString("GetClassName\n");
+ #endif
+
+ lpszClassName = Convert(lpClassName);
+ if (lpszClassName == ERR)
+ return 0;
+
+ ret = GetClassNameA(hWnd, lpszClassName, nMaxCount);
+
+ delete lpszClassName;
+
+ return ret;
+}
+
+
+int
+WINAPI
+lstrlenX(LPCWSTR lpString)
+{
+ return wcslen(lpString);
+}
+
+LPWSTR
+WINAPI
+lstrcatX(
+ LPWSTR lpString1,
+ LPCWSTR lpString2)
+{
+ return wcscat(lpString1, lpString2);
+}
+
+int
+WINAPI
+lstrcmpX(
+ LPCWSTR lpString1,
+ LPCWSTR lpString2
+ )
+{
+ return wcscmp(lpString1, lpString2);
+}
+
+int
+WINAPI
+lstrcmpiX(
+ LPCWSTR lpString1,
+ LPCWSTR lpString2
+ )
+{
+ return _wcsicmp(lpString1, lpString2);
+}
+
+LPWSTR
+WINAPI
+lstrcpyX(
+ LPWSTR lpString1,
+ LPCWSTR lpString2
+ )
+{
+ return wcscpy(lpString1, lpString2);
+}
+
+
+
+HANDLE
+WINAPI
+CreateFileMappingX(
+ HANDLE hFile,
+ LPSECURITY_ATTRIBUTES lpFileMappingAttributes,
+ DWORD flProtect,
+ DWORD dwMaximumSizeHigh,
+ DWORD dwMaximumSizeLow,
+ LPCWSTR lpName
+ )
+{
+ LPSTR lpszAName;
+ HANDLE ret;
+
+
+ #ifdef DEBUG_OUTPUT
+ OutputDebugString("CreateFileMapping\n");
+ #endif
+
+ lpszAName = Convert(lpName);
+
+ if (lpszAName == ERR)
+ {
+ return 0;
+ }
+
+ ret = CreateFileMappingA(
+ hFile,
+ lpFileMappingAttributes,
+ flProtect,
+ dwMaximumSizeHigh,
+ dwMaximumSizeLow,
+ lpszAName);
+
+ delete lpszAName;
+
+ return ret;
+}
+
+
+HANDLE
+WINAPI
+OpenFileMappingX(
+ DWORD dwDesiredAccess,
+ BOOL bInheritHandle,
+ LPCWSTR lpName
+ )
+{
+ LPSTR lpszAName;
+ HANDLE ret;
+
+
+ #ifdef DEBUG_OUTPUT
+ OutputDebugString("CreateFileMapping\n");
+ #endif
+
+ lpszAName = Convert(lpName);
+
+ if (lpszAName == ERR)
+ {
+ return 0;
+ }
+
+ ret = OpenFileMappingA(
+ dwDesiredAccess,
+ bInheritHandle,
+ lpszAName);
+
+ delete lpszAName;
+
+ return ret;
+}
+
+#endif // CHICAGO
diff --git a/private/oleutest/olebind/widewrap.h b/private/oleutest/olebind/widewrap.h
new file mode 100644
index 000000000..caa3cdcca
--- /dev/null
+++ b/private/oleutest/olebind/widewrap.h
@@ -0,0 +1,764 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1993 - 1993.
+//
+// File: widewrap.h
+//
+// Contents: Wrapper functions for Win32c API used by 32-bit OLE 2
+//
+// History: 12-27-93 ErikGav Created
+// 06-14-94 KentCe Various Chicago build fixes.
+//
+//----------------------------------------------------------------------------
+
+#ifndef _WIDEWRAP_H_
+#define _WIDEWRAP_H_
+
+#ifndef RC_INVOKED
+#pragma message ("INCLUDING WIDEWRAP.H from " __FILE__)
+#endif /* RC_INVOKED */
+
+#ifdef _CHICAGO_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#undef WNDCLASS
+#define WNDCLASS WNDCLASSW
+#define WNDCLASST WNDCLASSA
+
+#undef STARTUPINFO
+#define STARTUPINFO STARTUPINFOW
+
+#undef WIN32_FIND_DATA
+#define WIN32_FIND_DATA WIN32_FIND_DATAW
+
+HANDLE
+WINAPI
+CreateFileX(
+ LPCWSTR lpFileName,
+ DWORD dwDesiredAccess,
+ DWORD dwShareMode,
+ LPSECURITY_ATTRIBUTES lpSecurityAttributes,
+ DWORD dwCreationDisposition,
+ DWORD dwFlagsAndAttributes,
+ HANDLE hTemplateFile
+ );
+
+#undef CreateFile
+#define CreateFile CreateFileX
+#define CreateFileT CreateFileA
+
+BOOL
+WINAPI
+DeleteFileX(
+ LPCWSTR lpFileName
+ );
+
+#undef DeleteFile
+#define DeleteFile DeleteFileX
+#define DeleteFileT DeleteFileA
+
+UINT
+WINAPI
+RegisterClipboardFormatX(
+ LPCWSTR lpszFormat);
+
+#undef RegisterClipboardFormat
+#define RegisterClipboardFormat RegisterClipboardFormatX
+#define RegisterClipboardFormatT RegisterClipboardFormatA
+
+int
+WINAPI
+GetClipboardFormatNameX(
+ UINT format,
+ LPWSTR lpszFormatName,
+ int cchMaxCount);
+
+#undef GetClipboardFormatName
+#define GetClipboardFormatName GetClipboardFormatNameX
+#define GetClipboardFormatNameT GetClipboardFormatNameA
+
+LONG
+APIENTRY
+RegOpenKeyX (
+ HKEY hKey,
+ LPCWSTR lpSubKey,
+ PHKEY phkResult
+ );
+
+#undef RegOpenKey
+#define RegOpenKey RegOpenKeyX
+#define RegOpenKeyT RegOpenKeyA
+
+LONG
+APIENTRY
+RegQueryValueX (
+ HKEY hKey,
+ LPCWSTR lpSubKey,
+ LPWSTR lpValue,
+ PLONG lpcbValue
+ );
+
+#undef RegQueryValue
+#define RegQueryValue RegQueryValueX
+#define RegQueryValueT RegQueryValueA
+LONG
+APIENTRY
+RegSetValueX (
+ HKEY hKey,
+ LPCWSTR lpSubKey,
+ DWORD dwType,
+ LPCWSTR lpData,
+ DWORD cbData
+ );
+
+#undef RegSetValue
+#define RegSetValue RegSetValueX
+#define RegSetValueT RegSetValueA
+
+LONG
+APIENTRY
+RegSetValueExX (
+ HKEY hKey,
+ LPCWSTR lpSubKey,
+ DWORD dwReserved,
+ DWORD dwType,
+ LPBYTE lpData,
+ DWORD cbData
+ );
+
+#undef RegSetValueEx
+#define RegSetValueEx RegSetValueExX
+#define RegSetValueExT RegSetValueExA
+
+
+UINT
+WINAPI
+RegisterWindowMessageX(
+ LPCWSTR lpString);
+
+#undef RegisterWindowMessage
+#define RegisterWindowMessage RegisterWindowMessageX
+#define RegisterWindowMessageT RegisterWindowMessageA
+
+LONG
+APIENTRY
+RegOpenKeyExX (
+ HKEY hKey,
+ LPCWSTR lpSubKey,
+ DWORD ulOptions,
+ REGSAM samDesired,
+ PHKEY phkResult
+ );
+
+#undef RegOpenKeyEx
+#define RegOpenKeyEx RegOpenKeyExX
+#define RegOpenKeyExT RegOpenKeyExA
+
+LONG
+APIENTRY
+RegQueryValueExX (
+ HKEY hKey,
+ LPWSTR lpValueName,
+ LPDWORD lpReserved,
+ LPDWORD lpType,
+ LPBYTE lpData,
+ LPDWORD lpcbData
+ );
+
+#undef RegQueryValueEx
+#define RegQueryValueEx RegQueryValueExX
+#define RegQueryValueExT RegQueryValueExA
+
+HWND
+WINAPI
+CreateWindowExX(
+ DWORD dwExStyle,
+ LPCWSTR lpClassName,
+ LPCWSTR lpWindowName,
+ DWORD dwStyle,
+ int X,
+ int Y,
+ int nWidth,
+ int nHeight,
+ HWND hWndParent ,
+ HMENU hMenu,
+ HINSTANCE hInstance,
+ LPVOID lpParam);
+
+#undef CreateWindowEx
+#define CreateWindowEx CreateWindowExX
+#define CreateWindowExT CreateWindowExA
+
+ATOM
+WINAPI
+RegisterClassX(
+ CONST WNDCLASSW *lpWndClass);
+
+#undef RegisterClass
+#define RegisterClass RegisterClassX
+#define RegisterClassT RegisterClassA
+
+BOOL
+WINAPI
+UnregisterClassX(
+ LPCWSTR lpClassName,
+ HINSTANCE hInstance);
+
+#undef UnregisterClass
+#define UnregisterClass UnregisterClassX
+#define UnregisterClassT UnregisterClassA
+
+int WINAPIV wsprintfX(LPWSTR pwszOut, LPCWSTR pwszFormat, ...);
+
+#undef wsprintf
+#define wsprintf wsprintfX
+#define wsprintfT wsprintfA
+
+HWND
+WINAPI
+CreateWindowX(
+ LPCWSTR lpClassName,
+ LPCWSTR lpWindowName,
+ DWORD dwStyle,
+ int X,
+ int Y,
+ int nWidth,
+ int nHeight,
+ HWND hWndParent ,
+ HMENU hMenu,
+ HINSTANCE hInstance,
+ LPVOID lpParam);
+
+#undef CreateWindow
+#define CreateWindow CreateWindowX
+#define CreateWindowT CreateWindowA
+
+HANDLE
+WINAPI
+GetPropX(
+ HWND hWnd,
+ LPCWSTR lpString);
+
+#undef GetProp
+#define GetProp GetPropX
+#define GetPropT GetPropA
+
+BOOL
+WINAPI
+SetPropX(
+ HWND hWnd,
+ LPCWSTR lpString,
+ HANDLE hData);
+
+#undef SetProp
+#define SetProp SetPropX
+#define SetPropT SetPropA
+
+HANDLE
+WINAPI
+RemovePropX(
+ HWND hWnd,
+ LPCWSTR lpString);
+
+#undef RemoveProp
+#define RemoveProp RemovePropX
+#define RemovePropT RemovePropA
+
+UINT
+WINAPI
+GetProfileIntX(
+ LPCWSTR lpAppName,
+ LPCWSTR lpKeyName,
+ INT nDefault
+ );
+
+#undef GetProfileInt
+#define GetProfileInt GetProfileIntX
+#define GetProfileIntT GetProfileIntA
+
+ATOM
+WINAPI
+GlobalAddAtomX(
+ LPCWSTR lpString
+ );
+
+#undef GlobalAddAtom
+#define GlobalAddAtom GlobalAddAtomX
+#define GlobalAddAtomT GlobalAddAtomA
+
+UINT
+WINAPI
+GlobalGetAtomNameX(
+ ATOM nAtom,
+ LPWSTR lpBuffer,
+ int nSize
+ );
+
+#undef GlobalGetAtomName
+#define GlobalGetAtomName GlobalGetAtomNameX
+#define GlobalGetAtomNameT GlobalGetAtomNameA
+
+DWORD
+WINAPI
+GetModuleFileNameX(
+ HMODULE hModule,
+ LPWSTR lpFilename,
+ DWORD nSize
+ );
+
+#undef GetModuleFileName
+#define GetModuleFileName GetModuleFileNameX
+#define GetModuleFileNameT GetModuleFileNameA
+
+LPWSTR
+WINAPI
+CharPrevX(
+ LPCWSTR lpszStart,
+ LPCWSTR lpszCurrent);
+
+#undef CharPrev
+#define CharPrev CharPrevX
+#define CharPrevT CharPrevA
+
+HFONT WINAPI CreateFontX(int, int, int, int, int, DWORD,
+ DWORD, DWORD, DWORD, DWORD, DWORD,
+ DWORD, DWORD, LPCWSTR);
+#undef CreateFont
+#define CreateFont CreateFontX
+#define CreateFontT CreateFontA
+
+HMODULE
+WINAPI
+LoadLibraryX(
+ LPCWSTR lpLibFileName
+ );
+
+#undef LoadLibrary
+#define LoadLibrary LoadLibraryX
+#define LoadLibraryT LoadLibraryA
+
+HMODULE
+WINAPI
+LoadLibraryExX(
+ LPCWSTR lpLibFileName,
+ HANDLE hFile,
+ DWORD dwFlags
+ );
+
+#undef LoadLibraryEx
+#define LoadLibraryEx LoadLibraryExX
+#define LoadLibraryExT LoadLibraryExA
+
+LONG
+APIENTRY
+RegDeleteKeyX (
+ HKEY hKey,
+ LPCWSTR lpSubKey
+ );
+
+#undef RegDeleteKey
+#define RegDeleteKey RegDeleteKeyX
+#define RegDeleteKeyT RegDeleteKeyA
+
+#undef RpcStringBindingCompose
+#define RpcStringBindingCompose RpcStringBindingComposeW
+
+#undef RpcBindingFromStringBinding
+#define RpcBindingFromStringBinding RpcBindingFromStringBindingW
+
+#undef RpcStringFree
+#define RpcStringFree RpcStringFreeW
+
+BOOL
+WINAPI
+CreateProcessX(
+ LPCWSTR lpApplicationName,
+ LPWSTR lpCommandLine,
+ LPSECURITY_ATTRIBUTES lpProcessAttributes,
+ LPSECURITY_ATTRIBUTES lpThreadAttributes,
+ BOOL bInheritHandles,
+ DWORD dwCreationFlags,
+ LPVOID lpEnvironment,
+ LPCWSTR lpCurrentDirectory,
+ LPSTARTUPINFOW lpStartupInfo,
+ LPPROCESS_INFORMATION lpProcessInformation
+ );
+
+#undef CreateProcess
+#define CreateProcess CreateProcessX
+#define CreateProcessT CreateProcessA
+
+LONG
+APIENTRY
+RegEnumKeyExX (
+ HKEY hKey,
+ DWORD dwIndex,
+ LPWSTR lpName,
+ LPDWORD lpcbName,
+ LPDWORD lpReserved,
+ LPWSTR lpClass,
+ LPDWORD lpcbClass,
+ PFILETIME lpftLastWriteTime
+ );
+
+#undef RegEnumKeyEx
+#define RegEnumKeyEx RegEnumKeyExX
+#define RegEnumKeyExT RegEnumKeyExA
+
+#undef RpcServerUseProtseqEp
+#define RpcServerUseProtseqEp RpcServerUseProtseqEpW
+
+BOOL
+WINAPI
+AppendMenuX(
+ HMENU hMenu,
+ UINT uFlags,
+ UINT uIDNewItem,
+ LPCWSTR lpNewItem
+ );
+
+#undef AppendMenu
+#define AppendMenu AppendMenuX
+#define AppendMenuT AppendMenuA
+
+HANDLE
+WINAPI
+OpenEventX(
+ DWORD dwDesiredAccess,
+ BOOL bInheritHandle,
+ LPCWSTR lpName
+ );
+
+#undef OpenEvent
+#define OpenEvent OpenEventX
+#define OpenEventT OpenEventA
+
+HANDLE
+WINAPI
+CreateEventX(
+ LPSECURITY_ATTRIBUTES lpEventAttributes,
+ BOOL bManualReset,
+ BOOL bInitialState,
+ LPCWSTR lpName
+ );
+
+#undef CreateEvent
+#define CreateEvent CreateEventX
+#define CreateEventT CreateEventA
+
+UINT
+WINAPI
+GetDriveTypeX(
+ LPCWSTR lpRootPathName
+ );
+
+#undef GetDriveType
+#define GetDriveType GetDriveTypeX
+#define GetDriveTypeT GetDriveTypeA
+
+DWORD
+WINAPI
+GetFileAttributesX(
+ LPCWSTR lpFileName
+ );
+
+#undef GetFileAttributes
+#define GetFileAttributes GetFileAttributesX
+#define GetFileAttributesT GetFileAttributesA
+
+LONG
+APIENTRY
+RegEnumKeyX (
+ HKEY hKey,
+ DWORD dwIndex,
+ LPWSTR lpName,
+ DWORD cbName
+ );
+
+#undef RegEnumKey
+#define RegEnumKey RegEnumKeyX
+#define RegEnumKeyT RegEnumKeyA
+
+HANDLE
+WINAPI
+FindFirstFileX(
+ LPCWSTR lpFileName,
+ LPWIN32_FIND_DATAW lpFindFileData
+ );
+
+#undef FindFirstFile
+#define FindFirstFile FindFirstFileX
+#define FindFirstFileT FindFirstFileA
+
+#undef RegisterProtseq
+#define RegisterProtseq RegisterProtseqW
+
+#undef RpcStringBindingParse
+#define RpcStringBindingParse RpcStringBindingParseW
+
+#undef RpcNetworkIsProtseqValid
+#define RpcNetworkIsProtseqValid RpcNetworkIsProtseqValidW
+
+#undef RpcBindingToStringBinding
+#define RpcBindingToStringBinding RpcBindingToStringBindingW
+
+#undef RpcServerUseProtseq
+#define RpcServerUseProtseq RpcServerUseProtseqW
+
+BOOL
+WINAPI
+GetComputerNameX (
+ LPWSTR lpBuffer,
+ LPDWORD nSize
+ );
+
+#undef GetComputerName
+#define GetComputerName GetComputerNameX
+#define GetComputerNameT GetComputerNameA
+
+#undef Foo
+#define Foo FooW
+
+#undef Foo
+#define Foo FooW
+
+#undef Foo
+#define Foo FooW
+
+//The following force Chicago to directly use the ANSI versions
+
+#undef DefWindowProc
+#define DefWindowProc DefWindowProcA
+
+#undef CopyMetaFile // Currently str ptr is always
+#define CopyMetaFile CopyMetaFileA // null, write a wrapper if this
+ // changes
+#undef CreateMetaFile
+#define CreateMetaFile CreateMetaFileA
+
+#undef PostMessage
+#define PostMessage PostMessageA
+
+#undef SendMessage
+#define SendMessage SendMessageA
+
+#undef PeekMessage
+#define PeekMessage PeekMessageA
+
+#undef DispatchMessage
+#define DispatchMessage DispatchMessageA
+
+#undef GetWindowLong
+#define GetWindowLong GetWindowLongA
+
+#undef SetWindowLong
+#define SetWindowLong SetWindowLongA
+
+DWORD
+WINAPI
+GetShortPathNameX(
+ LPCWSTR lpszLongPath,
+ LPWSTR lpszShortPath,
+ DWORD cchBuffer
+ );
+
+#undef GetShortPathName
+#define GetShortPathName GetShortPathNameX
+#define GetShortPathNameT GetShortPathNameA
+
+DWORD
+WINAPI
+GetFullPathNameX(
+ LPCWSTR lpFileName,
+ DWORD nBufferLength,
+ LPWSTR lpBuffer,
+ LPWSTR *lpFilePart
+ );
+
+#undef GetFullPathName
+#define GetFullPathName GetFullPathNameX
+#define GetFullPathNameT GetFullPathNameA
+
+DWORD
+WINAPI
+SearchPathX(
+ LPCWSTR lpPath,
+ LPCWSTR lpFileName,
+ LPCWSTR lpExtension,
+ DWORD nBufferLength,
+ LPWSTR lpBuffer,
+ LPWSTR *lpFilePart
+ );
+
+#undef SearchPath
+#define SearchPath SearchPathX
+#define SearchPathT SearchPathA
+
+ATOM
+WINAPI
+GlobalFindAtomX(
+ LPCWSTR lpString
+ );
+
+#undef GlobalFindAtom
+#define GlobalFindAtom GlobalFindAtomX
+#define GlobalFindAtomT GlobalFindAtomA
+
+int
+WINAPI
+GetClassNameX(
+ HWND hWnd,
+ LPWSTR lpClassName,
+ int nMaxCount);
+
+#undef GetClassName
+#define GetClassName GetClassNameX
+#define GetClassNameT GetClassNameA
+
+int
+WINAPI
+lstrlenX(LPCWSTR lpString);
+
+#undef lstrlen
+#define lstrlen lstrlenX
+#define lstrlenT lstrlenA
+
+LPWSTR
+WINAPI
+lstrcatX(
+ LPWSTR lpString1,
+ LPCWSTR lpString2);
+
+#undef lstrcat
+#define lstrcat lstrcatX
+#define lstrcatT lstrcatA
+
+
+
+int
+WINAPI
+lstrcmpX(
+ LPCWSTR lpString1,
+ LPCWSTR lpString2
+ );
+
+#undef lstrcmp
+#define lstrcmp lstrcmpX
+#define lstrcmpT lstrcmpA
+
+int
+WINAPI
+lstrcmpiX(
+ LPCWSTR lpString1,
+ LPCWSTR lpString2
+ );
+
+#undef lstrcmpi
+#define lstrcmpi lstrcmpiX
+#define lstrcmpiT lstrcmpiA
+
+LPWSTR
+WINAPI
+lstrcpyX(
+ LPWSTR lpString1,
+ LPCWSTR lpString2
+ );
+
+#undef lstrcpy
+#define lstrcpy lstrcpyX
+#define lstrcpyT lstrcpyA
+
+HANDLE
+WINAPI
+CreateFileMappingX(
+ HANDLE hFile,
+ LPSECURITY_ATTRIBUTES lpFileMappingAttributes,
+ DWORD flProtect,
+ DWORD dwMaximumSizeHigh,
+ DWORD dwMaximumSizeLow,
+ LPCWSTR lpName
+ );
+
+#undef CreateFileMapping
+#define CreateFileMapping CreateFileMappingX
+#define CreateFileMappingT CreateFileMappingA
+
+HANDLE
+WINAPI
+OpenFileMappingX(
+ DWORD dwDesiredAccess,
+ BOOL bInheritHandle,
+ LPCWSTR lpName
+ );
+
+#undef OpenFileMapping
+#define OpenFileMapping OpenFileMappingX
+#define OpenFileMappingT OpenFileMappingA
+
+#ifdef __cplusplus
+}
+#endif
+
+#else
+//
+// These are the definitions for NT
+//
+#define CreateFileT CreateFileW
+#define DeleteFileT DeleteFileW
+#define RegisterClipboardFormatT RegisterClipboardFormatW
+#define GetClipboardFormatNameT GetClipboardFormatNameW
+#define RegOpenKeyT RegOpenKeyW
+#define RegQueryValueT RegQueryValueW
+#define RegSetValueT RegSetValueW
+#define RegSetValueExT RegSetValueExW
+#define RegisterWindowMessageT RegisterWindowMessageW
+#define RegOpenKeyExT RegOpenKeyExW
+#define RegQueryValueExT RegQueryValueExW
+#define CreateWindowExT CreateWindowExW
+#define RegisterClassT RegisterClassW
+#define UnregisterClassT UnregisterClassW
+#define wsprintfT wsprintfW
+#define CreateWindowT CreateWindowW
+#define GetPropT GetPropW
+#define SetPropT SetPropW
+#define RemovePropT RemovePropW
+#define GetProfileIntT GetProfileIntW
+#define GlobalAddAtomT GlobalAddAtomW
+#define GlobalGetAtomNameT GlobalGetAtomNameW
+#define GetModuleFileNameT GetModuleFileNameW
+#define CharPrevT CharPrevW
+#define CreateFontT CreateFontW
+#define LoadLibraryT LoadLibraryW
+#define LoadLibraryExT LoadLibraryExW
+#define RegDeleteKeyT RegDeleteKeyW
+#define CreateProcessT CreateProcessW
+#define RegEnumKeyExT RegEnumKeyExW
+#define AppendMenuT AppendMenuW
+#define OpenEventT OpenEventW
+#define CreateEventT CreateEventW
+#define GetDriveTypeT GetDriveTypeW
+#define GetFileAttributesT GetFileAttributesW
+#define RegEnumKeyT RegEnumKeyW
+#define FindFirstFileT FindFirstFileW
+#define GetComputerNameT GetComputerNameW
+#define GetShortPathNameT GetShortPathNameW
+#define GetFullPathNameT GetFullPathNameW
+#define SearchPathT SearchPathW
+#define GlobalFindAtomT GlobalFindAtomW
+#define GetClassNameT GetClassNameW
+#define lstrlenT lstrlenW
+#define lstrcatT lstrcatW
+#define lstrcmpT lstrcmpW
+#define lstrcmpiT lstrcmpiW
+#define lstrcpyT lstrcpyW
+#define CreateFileMappingT CreateFileMappingW
+#define OpenFileMappingT OpenFileMappingW
+#define WNDCLASST WNDCLASSW
+
+#endif // _CHICAGO_
+
+#endif // _WIDEWRAP_H_
diff --git a/private/oleutest/olebvt.bat b/private/oleutest/olebvt.bat
new file mode 100644
index 000000000..8f5e60122
--- /dev/null
+++ b/private/oleutest/olebvt.bat
@@ -0,0 +1,13 @@
+rem OLEBVT script
+
+@rem Register entries for tests
+call oleutest.bat
+%systemroot%\regedit /s oleutest.reg
+
+@rem CompObj test
+olebind
+
+@rem Storage test
+stgdrt
+
+@echo Thank you for running the OLE BVTs
diff --git a/private/oleutest/oledll2/daytona/makefile b/private/oleutest/oledll2/daytona/makefile
new file mode 100644
index 000000000..1d3728d41
--- /dev/null
+++ b/private/oleutest/oledll2/daytona/makefile
@@ -0,0 +1,10 @@
+############################################################################
+#
+# Copyright (C) 1992, Microsoft Corporation.
+#
+# All rights reserved.
+#
+############################################################################
+
+!include $(NTMAKEENV)\makefile.def
+
diff --git a/private/oleutest/oledll2/daytona/oledll2.src b/private/oleutest/oledll2/daytona/oledll2.src
new file mode 100644
index 000000000..a087a0075
--- /dev/null
+++ b/private/oleutest/oledll2/daytona/oledll2.src
@@ -0,0 +1,36 @@
+#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 oledll2
+
+DESCRIPTION 'OLEDLL2
+
+EXPORTS
+ FunctionInAnotherDLL
+
+#endif // FLAT
diff --git a/private/oleutest/oledll2/daytona/sources b/private/oleutest/oledll2/daytona/sources
new file mode 100644
index 000000000..fc15bcbe7
--- /dev/null
+++ b/private/oleutest/oledll2/daytona/sources
@@ -0,0 +1,62 @@
+!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:
+
+ Donna Liu (DonnaLi) 19-Dec-1993
+
+!ENDIF
+
+MAJORCOMP = cairole
+MINORCOMP = com
+
+TARGETNAME= oledll2
+TARGETPATH= obj
+TARGETTYPE= DYNLINK
+
+DLLDEF= obj\*\oledll2.def
+
+DLLBASE=@$(BASEDIR)\PUBLIC\SDK\LIB\coffbase.txt,usermode
+
+INCLUDES= ..\..\..\ole32\common\daytona;..\..\..\ole32\ih;..;..\..\common;..\..\..\cinc
+
+C_DEFINES= \
+ $(C_DEFINES) \
+ -DFLAT \
+ -DWIN32=100 \
+ -D_NT1X_=100 \
+ -DUNICODE \
+ -D_UNICODE \
+ -DINC_OLE2 \
+ -DNOEXCEPTIONS \
+ -DCAIROLE_DOWNLEVEL
+
+SOURCES= ..\oledll2.c
+
+DLLENTRY=_DllMainCRTStartup
+
+UMTYPE= windows
+
+TARGETLIBS = ..\..\..\ole32\common\daytona\obj\*\common.lib \
+ $(BASEDIR)\public\sdk\lib\*\uuid.lib \
+ $(BASEDIR)\public\sdk\lib\*\ole32.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\*\crtdll.lib
+
+USE_CRTDLL= 1
diff --git a/private/oleutest/oledll2/dirs b/private/oleutest/oledll2/dirs
new file mode 100644
index 000000000..1d0b9edbb
--- /dev/null
+++ b/private/oleutest/oledll2/dirs
@@ -0,0 +1,38 @@
+!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/oledll2/oledll2.c b/private/oleutest/oledll2/oledll2.c
new file mode 100644
index 000000000..f6163cae2
--- /dev/null
+++ b/private/oleutest/oledll2/oledll2.c
@@ -0,0 +1,79 @@
+//+-------------------------------------------------------------------
+//
+// File: oledll2.c
+//
+// Contents: This file contins the DLL entry points
+// LibMain
+// FunctionInAnotherDLL
+//
+// This DLL is used to to test loading of in
+// InProcServer that uses another statically linked DLL.
+// The extra DLL (OleDll2.DLL) should not be on the path
+// when the test is run. The entry point FuntionInAnotherDLL
+// is exported by OleDll2.DLL
+//
+//
+// History: 30-Jun-94 AndyH Created
+//
+//---------------------------------------------------------------------
+
+#include <windows.h>
+#include "oledll2.h"
+
+//+-------------------------------------------------------------------
+//
+// Function: LibMain
+//
+// Synopsis: Entry point to DLL - does little else
+//
+// Arguments:
+//
+// Returns: TRUE
+//
+// History: 21-Nov-92 SarahJ Created
+//
+//--------------------------------------------------------------------
+
+
+
+//
+// Entry point to DLL is traditional LibMain
+//
+
+
+BOOL _cdecl LibMain ( HINSTANCE hinst,
+ HANDLE segDS,
+ UINT cbHeapSize,
+ LPTSTR lpCmdLine)
+{
+ return TRUE;
+}
+
+
+//+-------------------------------------------------------------------
+//
+// Function: FunctionInAnotherDLL
+//
+// Synopsis: Does nothing.
+//
+// Arguments:
+//
+// Returns: TRUE
+//
+// History: 30-Jun-94 AndyH Created
+//
+//--------------------------------------------------------------------
+
+
+
+//
+// Entry point for testing statically linked DLL.
+//
+
+
+BOOL FunctionInAnotherDLL ( void )
+{
+ return TRUE;
+}
+
+
diff --git a/private/oleutest/oledll2/oledll2.h b/private/oleutest/oledll2/oledll2.h
new file mode 100644
index 000000000..65707b472
--- /dev/null
+++ b/private/oleutest/oledll2/oledll2.h
@@ -0,0 +1,27 @@
+//+-------------------------------------------------------------------
+//
+// File: oledll2.h
+//
+// Contents: This file contins the DLL entry points
+// LibMain
+// FunctionInAnotherDLL
+//
+// This DLL is used to to test loading of in
+// InProcServer that uses another statically linked DLL.
+// The extra DLL (OleDll2.DLL) should not be on the path
+// when the test is run. The entry point FuntionInAnotherDLL
+// is exported by OleDll2.DLL
+//
+//
+// History: 30-Jun-94 AndyH Created
+//
+//---------------------------------------------------------------------
+
+//
+// Entry point for testing statically linked DLL.
+//
+
+
+BOOL FunctionInAnotherDLL ( void );
+
+
diff --git a/private/oleutest/oledll2/readme b/private/oleutest/oledll2/readme
new file mode 100644
index 000000000..5d851ae11
--- /dev/null
+++ b/private/oleutest/oledll2/readme
@@ -0,0 +1,12 @@
+July 1, 1994. AndyH.
+
+This DLL build here (oledll2.dll) is statically linked by oleimpl.dll.
+Oleimpl.dll is used as an inprocserver by the OleBind test.
+Until July 1, 1994, oledll2.dll would only have loaded if it was on
+the client's path. Or: if oleimpl.dll was registered with a full
+path (C:\FOO\OLEIMPL.DLL) and OLEDLL2.DLL was in the same directory BUT
+C:\FOO wasn't on the path, the OLEIMPL.DLL would fail to load.
+
+To test the current functionality, put both OLEIMPL.DLL and OLEDLL2.DLL
+in some directoy that is not on the path. Register the full path to
+OLEIMPL.DLL and run OLEBIND.
diff --git a/private/oleutest/oleexts/daytona/makefile b/private/oleutest/oleexts/daytona/makefile
new file mode 100644
index 000000000..1d3728d41
--- /dev/null
+++ b/private/oleutest/oleexts/daytona/makefile
@@ -0,0 +1,10 @@
+############################################################################
+#
+# Copyright (C) 1992, Microsoft Corporation.
+#
+# All rights reserved.
+#
+############################################################################
+
+!include $(NTMAKEENV)\makefile.def
+
diff --git a/private/oleutest/oleexts/daytona/makefile.inc b/private/oleutest/oleexts/daytona/makefile.inc
new file mode 100644
index 000000000..2c1796f8c
--- /dev/null
+++ b/private/oleutest/oleexts/daytona/makefile.inc
@@ -0,0 +1 @@
+obj\i386\oledbg.def: oledbg.src
diff --git a/private/oleutest/oleexts/daytona/oledbg.src b/private/oleutest/oleexts/daytona/oledbg.src
new file mode 100644
index 000000000..3d2c1c40c
--- /dev/null
+++ b/private/oleutest/oleexts/daytona/oledbg.src
@@ -0,0 +1,41 @@
+LIBRARY OLEDBG
+
+DESCRIPTION 'OLE Debug NTSD Extensions'
+
+EXPORTS
+ help
+ symbol
+ dump_atom
+ dump_clsid
+ dump_clipformat
+ dump_mutexsem
+ dump_filetime
+ dump_cachelist_item
+ dump_cacheenum
+ dump_cacheenumformatetc
+ dump_cachenode
+ dump_clipdataobject
+ dump_clipenumformatetc
+ dump_daholder
+ dump_dataadvisecache
+ dump_defclassfactory
+ dump_deflink
+ dump_defobject
+ dump_emfobject
+ dump_enumfmt
+ dump_enumfmt10
+ dump_enumstatdata
+ dump_enumverb
+ dump_genobject
+ dump_membytes
+ dump_cmemstm
+ dump_mfobject
+ dump_oaholder
+ dump_olecache
+ dump_saferefcount
+ dump_threadcheck
+ dump_formatetc
+ dump_memstm
+ dump_statdata
+ dump_stgmedium
+ \ No newline at end of file
diff --git a/private/oleutest/oleexts/daytona/sources b/private/oleutest/oleexts/daytona/sources
new file mode 100644
index 000000000..9e7361655
--- /dev/null
+++ b/private/oleutest/oleexts/daytona/sources
@@ -0,0 +1,75 @@
+!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:
+ t-ScottH
+
+
+NOTE:
+
+!ENDIF
+
+DLLBASE=@$(BASEDIR)\PUBLIC\SDK\LIB\coffbase.txt,usermode
+
+MAJORCOMP=ntsd
+MINORCOMP=ntsdexts
+
+TARGETNAME=oledbg
+TARGETPATH=obj
+TARGETPATHLIB=$(BASEDIR)\public\sdk\lib
+TARGETTYPE=DYNLINK
+DLLDEF = obj\*\oledbg.def
+TARGETLIBS= \
+ $(BASEDIR)\public\sdk\lib\*\kernel32.lib \
+ $(BASEDIR)\public\sdk\lib\*\ole32.lib
+
+INCLUDES= \
+ $(BASEDIR)\private\ole32\common\daytona; \
+ $(BASEDIR)\private\ole32\ih; \
+ $(BASEDIR)\private\ole32\ole232\inc; \
+ $(BASEDIR)\private\ole32\ole232\stdimpl; \
+ $(BASEDIR)\private\ole32\ole232\clipbrd; \
+ $(BASEDIR)\private\ole32\ole232\advise; \
+ $(BASEDIR)\private\cinc; \
+ ..
+
+C_DEFINES= \
+ $(C_DEFINES) \
+ -DFLAT \
+ -DWIN32=100 \
+ -D_NT1X_=100 \
+ -DNOEXCEPTIONS \
+ -D_DEBUG \
+ -DUNICODE \
+ -D_UNICODE \
+ -DCAIROLE_DOWNLEVEL
+
+SOURCES= \
+ ..\oleexts.cpp
+
+UMTYPE=console
+
+!IF $(386)
+NTTARGETFILE0=$(DLLDEF:*=i386)
+!ENDIF
+
+!IF $(MIPS)
+NTTARGETFILE0=$(DLLDEF:*=mips)
+!ENDIF
+
+!IF $(ALPHA)
+NTTARGETFILE0=$(DLLDEF:*=alpha)
+!ENDIF
diff --git a/private/oleutest/oleexts/dirs b/private/oleutest/oleexts/dirs
new file mode 100644
index 000000000..97cb1a3ad
--- /dev/null
+++ b/private/oleutest/oleexts/dirs
@@ -0,0 +1,35 @@
+!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:
+
+ t-ScottH
+
+!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=daytona
+
+#
+# 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=
diff --git a/private/oleutest/oleexts/oleexts.cpp b/private/oleutest/oleexts/oleexts.cpp
new file mode 100644
index 000000000..aede1418e
--- /dev/null
+++ b/private/oleutest/oleexts/oleexts.cpp
@@ -0,0 +1,4562 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: oleexts.cpp
+//
+// Contents: ntsd and windbg debugger extension
+//
+// Classes: none
+//
+// Functions:
+// operator new (global)
+// operator delete (global)
+// sizeofstring
+// dprintfx
+// dump_saferefcount
+// dump_threadcheck
+//
+// History: dd-mmm-yy Author Comment
+// 02-Feb-95 t-ScottH author
+//
+//--------------------------------------------------------------------------
+
+#include <windows.h>
+#include <imagehlp.h>
+#include <ntsdexts.h>
+
+#include <le2int.h>
+#include <oaholder.h>
+#include <daholder.h>
+#include <olerem.h>
+#include <defhndlr.h>
+#include <deflink.h>
+#include <olecache.h>
+#include <cachenod.h>
+#include <clipdata.h>
+#include <mf.h>
+#include <emf.h>
+#include <gen.h>
+#include <defcf.h>
+#include <dbgdump.h>
+
+#include "oleexts.h"
+
+// structure of function pointers
+NTSD_EXTENSION_APIS ExtensionApis;
+
+//+-------------------------------------------------------------------------
+//
+// Function: operator new (global), internal
+//
+// Synopsis: allocate memory
+//
+// Effects:
+//
+// Arguments: [cb] - number of bytes to allocate
+//
+// Requires: CoTaskMemAlloc
+//
+// Returns: pointer to allocated memory
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 02-Feb-95 t-ScottH author
+//
+// Notes:
+// we define our own operator new so that we do not need to link
+// with the CRT library
+//
+// we must also define our own global operator delete
+//
+//--------------------------------------------------------------------------
+
+void * _CRTAPI1
+::operator new(unsigned int cb)
+{
+ return CoTaskMemAlloc(cb);
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: operator delete (global), internal
+//
+// Synopsis: free memory
+//
+// Effects:
+//
+// Arguments: [p] - pointer to the memory to free
+//
+// Requires: CoTaskMemFree
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm: check to see if pointer is valid
+//
+// History: dd-mmm-yy Author Comment
+// 02-Feb-95 t-ScottH author
+//
+// Notes:
+// we define our own operator delete so that we do not need
+// to link with the CRT library
+//
+// we must also define our own global operator new
+//
+//--------------------------------------------------------------------------
+
+void _CRTAPI1
+::operator delete (void *p)
+{
+ // CoTaskMemFree takes care if the pointer is NULL
+ CoTaskMemFree(p);
+ return;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: dprintfx, internal
+//
+// Synopsis: prints a formatted string in MAX_STRING_SIZE chunks
+//
+// Effects:
+//
+// Arguments: [pszString] - null terminated string
+//
+// Requires: sizeofstring to calculate length of given string
+// dprintf (NTSD Extension API)
+// MAX_STRING_SIZE
+//
+// !!!This requires the NTSD_EXTENSION_APIS global variable
+// ExtensionApis to be initialize with the function
+// pointers
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 02-Feb-95 t-ScottH author
+//
+// Notes:
+// NTSD has a limit of a 4K buffer...some of the character
+// arrays from Dump methods can be > 4K. this will
+// print a formatted string in chunks that NTSD can handle
+//
+//--------------------------------------------------------------------------
+
+#define MAX_STRING_SIZE 1000
+
+void dprintfx(char *pszString)
+{
+ char *pszFront;
+ int size;
+ char x;
+
+ for ( pszFront = pszString,
+ size = strlen(pszString);
+ size > 0;
+ pszFront += (MAX_STRING_SIZE - 1),
+ size -= (MAX_STRING_SIZE - 1 ) )
+ {
+ if ( size > (MAX_STRING_SIZE - 1) )
+ {
+ x = pszFront[MAX_STRING_SIZE - 1];
+ pszFront[MAX_STRING_SIZE - 1] = '\0';
+ dprintf("%s", pszFront);
+ pszFront[MAX_STRING_SIZE - 1] = x;
+ }
+ else
+ {
+ dprintf("%s", pszFront);
+ }
+ }
+ return;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: help, exported
+//
+// Synopsis: print help message
+//
+// Effects:
+//
+// Arguments: see DECLARE_API in oleexts.h
+//
+// Requires:
+//
+// Returns: void
+//
+// Signals:
+//
+// Modifies: ExtensionApis (global)
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 02-Feb-95 t-ScottH author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+DECLARE_API( help )
+{
+ ExtensionApis = *lpExtensionApis;
+
+ if (*args == '\0') {
+ dprintf("OLE DEBUGGER EXTENSIONS HELP:\n\n");
+ dprintf("!symbol (<address>|<symbol name>) - Returns either the symbol name or address\n");
+
+ dprintf("!dump_atom <address> - Dumps a ATOM structure\n");
+ dprintf("!dump_clsid <address> - Dumps a CLSID structure\n");
+ dprintf("!dump_clipformat <address> - Dumps a CLIPFORMAT structure\n");
+ dprintf("!dump_mutexsem <address> - Dumps a CMutexSem class\n");
+ dprintf("!dump_filetime <address> - Dumps a FILETIME structure\n");
+ dprintf("!dump_cachelist_item <address> - Dumps a CACHELIST_ITEM struct\n");
+ dprintf("!dump_cacheenum <address> - Dumps a CCacheEnum class\n");
+ dprintf("!dump_cacheenumformatetc <address> - Dumps a CCacheEnumFormatEtc class\n");
+ dprintf("!dump_cachenode <address> - Dumps a CCacheNode class\n");
+ dprintf("!dump_clipdataobject <address> - Dumps a CClipDataObject class\n");
+ dprintf("!dump_clipenumformatetc <address> - Dumps a CClipEnumFormatEtc class\n");
+ dprintf("!dump_daholder <address> - Dumps a CDAHolder class\n");
+ dprintf("!dump_dataadvisecache <address> - Dumps a CDataAdviseCache class\n");
+ dprintf("!dump_defclassfactory <address> - Dumps a CDefClassFactory class\n");
+ dprintf("!dump_deflink <address> - Dumps a CDefLink class\n");
+ dprintf("!dump_defobject <address> - Dumps a CDefObject class\n");
+ dprintf("!dump_emfobject <address> - Dumps a CEMfObject class\n");
+ dprintf("!dump_enumfmt <address> - Dumps a CEnumFmt class\n");
+ dprintf("!dump_enumfmt10 <address> - Dumps a CEnumFmt10 class\n");
+ dprintf("!dump_enumstatdata <address> - Dumps a CEnumSTATDATA class\n");
+ dprintf("!dump_enumverb <address> - Dumps a CEnumVerb class\n");
+ dprintf("!dump_membytes <address> - Dumps a CMemBytes class\n");
+ dprintf("!dump_cmemstm <address> - Dumps a CMemStm class\n");
+ dprintf("!dump_mfobject <address> - Dumps a CMfObject class\n");
+ dprintf("!dump_oaholder <address> - Dumps a COAHolder class\n");
+ dprintf("!dump_olecache <address> - Dumps a COleCache class\n");
+ dprintf("!dump_saferefcount <address> - Dumps a CSafeRefCount class\n");
+ dprintf("!dump_threadcheck <address> - Dumps a CThreadCheck class\n");
+ dprintf("!dump_formatetc <address> - Dumps a FORMATETC structure\n");
+ dprintf("!dump_memstm <address> - Dumps a MEMSTM structure\n");
+ dprintf("!dump_statdata <address> - Dumps a STATDATA structure\n");
+ dprintf("!dump_stgmedium <address> - Dumps a STGMEDIUM\n");
+ dprintf("\n");
+ }
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: symbol, exported
+//
+// Synopsis: given an address to a symbol, dumps the symbol name and offset
+// (given a symbol name, dump address and offset)
+//
+// Effects:
+//
+// Arguments: see DECLARE_API in oleexts.h
+//
+// Requires:
+//
+// Returns: void
+//
+// Signals:
+//
+// Modifies: ExtensionApis (global)
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 02-Feb-95 t-ScottH author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+DECLARE_API( symbol )
+{
+ DWORD dwAddr;
+ CHAR Symbol[64];
+ DWORD Displacement;
+
+ ExtensionApis = *lpExtensionApis;
+
+ dwAddr = GetExpression(args);
+ if ( !dwAddr ) {
+ return;
+ }
+
+ GetSymbol((LPVOID)dwAddr,(unsigned char *)Symbol,&Displacement);
+ dprintf("%s+%lx at %lx\n", Symbol, Displacement, dwAddr);
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: dump_atom, exported
+//
+// Synopsis: dumps ATOM object
+//
+// Effects:
+//
+// Arguments: see DECLARE_API in oleexts.h
+//
+// Requires:
+//
+// Returns: void
+//
+// Signals:
+//
+// Modifies: ExtensionApis (global)
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 02-Feb-95 t-ScottH author
+//
+// Notes:
+// The address of the object is passed in the arguments. This
+// address is in the debuggee's process memory. In order for
+// NTSD to view this memory, the debugger must copy the mem
+// using the WIN32 ReadProcessMemory API.
+//
+//--------------------------------------------------------------------------
+
+DECLARE_API(dump_atom)
+{
+ // set up global function pointers
+ ExtensionApis = *lpExtensionApis;
+
+ dprintf("dump_atom not implemented\n");
+
+ return;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: dump_clsid, exported
+//
+// Synopsis: dumps CLSID object
+//
+// Effects:
+//
+// Arguments: see DECLARE_API in oleexts.h
+//
+// Requires:
+//
+// Returns: void
+//
+// Signals:
+//
+// Modifies: ExtensionApis (global)
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 02-Feb-95 t-ScottH author
+//
+// Notes:
+// The address of the object is passed in the arguments. This
+// address is in the debuggee's process memory. In order for
+// NTSD to view this memory, the debugger must copy the mem
+// using the WIN32 ReadProcessMemory API.
+//
+//--------------------------------------------------------------------------
+
+DECLARE_API(dump_clsid)
+{
+ // set up global function pointers
+ ExtensionApis = *lpExtensionApis;
+
+ dprintf("dump_clsid not implemented\n");
+
+ return;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: dump_clipformat, exported
+//
+// Synopsis: dumps CLIPFORMAT object
+//
+// Effects:
+//
+// Arguments: see DECLARE_API in oleexts.h
+//
+// Requires:
+//
+// Returns: void
+//
+// Signals:
+//
+// Modifies: ExtensionApis (global)
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 02-Feb-95 t-ScottH author
+//
+// Notes:
+// The address of the object is passed in the arguments. This
+// address is in the debuggee's process memory. In order for
+// NTSD to view this memory, the debugger must copy the mem
+// using the WIN32 ReadProcessMemory API.
+//
+//--------------------------------------------------------------------------
+
+DECLARE_API(dump_clipformat)
+{
+ // set up global function pointers
+ ExtensionApis = *lpExtensionApis;
+
+ dprintf("dump_clipformat not implemented\n");
+
+ return;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: dump_mutexsem, exported
+//
+// Synopsis: dumps CMutexSem object
+//
+// Effects:
+//
+// Arguments: see DECLARE_API in oleexts.h
+//
+// Requires:
+//
+// Returns: void
+//
+// Signals:
+//
+// Modifies: ExtensionApis (global)
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 02-Feb-95 t-ScottH author
+//
+// Notes:
+// The address of the object is passed in the arguments. This
+// address is in the debuggee's process memory. In order for
+// NTSD to view this memory, the debugger must copy the mem
+// using the WIN32 ReadProcessMemory API.
+//
+//--------------------------------------------------------------------------
+
+DECLARE_API(dump_mutexsem)
+{
+ // set up global function pointers
+ ExtensionApis = *lpExtensionApis;
+
+ dprintf("dump_mutexsem not implemented\n");
+
+ return;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: dump_filetime, exported
+//
+// Synopsis: dumps FILETIME object
+//
+// Effects:
+//
+// Arguments: see DECLARE_API in oleexts.h
+//
+// Requires:
+//
+// Returns: void
+//
+// Signals:
+//
+// Modifies: ExtensionApis (global)
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 02-Feb-95 t-ScottH author
+//
+// Notes:
+// The address of the object is passed in the arguments. This
+// address is in the debuggee's process memory. In order for
+// NTSD to view this memory, the debugger must copy the mem
+// using the WIN32 ReadProcessMemory API.
+//
+//--------------------------------------------------------------------------
+
+DECLARE_API(dump_filetime)
+{
+ // set up global function pointers
+ ExtensionApis = *lpExtensionApis;
+
+ dprintf("dump_filetime not implemented\n");
+
+ return;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: dump_cachelist_item, exported
+//
+// Synopsis: dumps CACHELIST_ITEM object
+//
+// Effects:
+//
+// Arguments: see DECLARE_API in oleexts.h
+//
+// Requires:
+//
+// Returns: void
+//
+// Signals:
+//
+// Modifies: ExtensionApis (global)
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 02-Feb-95 t-ScottH author
+//
+// Notes:
+// The address of the object is passed in the arguments. This
+// address is in the debuggee's process memory. In order for
+// NTSD to view this memory, the debugger must copy the mem
+// using the WIN32 ReadProcessMemory API.
+//
+//--------------------------------------------------------------------------
+
+DECLARE_API(dump_cachelist_item)
+{
+ BOOL fError;
+ LPVOID dwAddr;
+ DWORD dwReturnedCount;
+ char *pszCacheListItem;
+ char *blockCacheListItem = NULL;
+ char *blockCacheNode = NULL;
+ char *blockPresObj = NULL;
+ char *blockPresObjAF = NULL;
+ CACHELIST_ITEM *pCacheListItem = NULL;
+ DWORD dwSizeOfPresObj;
+
+ // set up global function pointers
+ ExtensionApis = *lpExtensionApis;
+
+ // get address of object from argument string
+ dwAddr = (LPVOID)GetExpression( args );
+ if (dwAddr == 0)
+ {
+ dprintf("Failed to get Address of CACEHLIST_ITEM\n");
+ return;
+ }
+
+ // read the block of memory from the debugee's process
+ blockCacheListItem = new char[sizeof(CACHELIST_ITEM)];
+
+ fError = ReadProcessMemory(
+ hCurrentProcess,
+ dwAddr,
+ blockCacheListItem,
+ sizeof(CACHELIST_ITEM),
+ &dwReturnedCount
+ );
+
+ if (fError == FALSE)
+ {
+ dprintf("Could not read debuggee's process memory: CACHELIST_ITEM \n");
+ dprintf("at address %x\n", dwAddr);
+ dprintf("Last Error Code = %d (0x%x)\n", GetLastError(), GetLastError());
+
+ goto errRtn;
+ }
+
+ if (dwReturnedCount != sizeof(CACHELIST_ITEM))
+ {
+ dprintf("Size of process memory read != requested(CACHELIST_ITEM\n");
+
+ goto errRtn;
+ }
+
+ pCacheListItem = (CACHELIST_ITEM *)blockCacheListItem;
+
+ if (pCacheListItem->lpCacheNode != NULL)
+ {
+ blockCacheNode = new char[sizeof(CCacheNode)];
+
+ fError = ReadProcessMemory(
+ hCurrentProcess,
+ pCacheListItem->lpCacheNode,
+ blockCacheNode,
+ sizeof(CCacheNode),
+ &dwReturnedCount
+ );
+
+ if (fError == FALSE)
+ {
+ dprintf("Could not read debuggee's process memory: CCacheNode \n");
+ dprintf("at address %x\n", pCacheListItem->lpCacheNode);
+ dprintf("Last Error Code = %d (0x%x)\n", GetLastError(), GetLastError());
+
+ goto errRtn;
+ }
+
+ if (dwReturnedCount != sizeof(CCacheNode))
+ {
+ dprintf("Size of process memory read != requested (CCacheNode)\n");
+
+ goto errRtn;
+ }
+
+ pCacheListItem->lpCacheNode = (CCacheNode*)blockCacheNode;
+
+ // need to get the OlePresObjs for the CCacheNode
+ if (pCacheListItem->lpCacheNode->m_pPresObj != NULL)
+ {
+ switch (pCacheListItem->lpCacheNode->m_dwPresFlag)
+ {
+ case CN_PRESOBJ_GEN:
+ dwSizeOfPresObj = sizeof(CGenObject);
+ break;
+ case CN_PRESOBJ_MF:
+ dwSizeOfPresObj = sizeof(CMfObject);
+ break;
+ case CN_PRESOBJ_EMF:
+ dwSizeOfPresObj = sizeof(CEMfObject);
+ break;
+ default:
+ dprintf("Error: can not determine size of IOlePresObj\n");
+ return;
+ }
+
+ blockPresObj = new char[dwSizeOfPresObj];
+
+ fError = ReadProcessMemory(
+ hCurrentProcess,
+ pCacheListItem->lpCacheNode->m_pPresObj,
+ blockPresObj,
+ dwSizeOfPresObj,
+ &dwReturnedCount
+ );
+
+ if (fError == FALSE)
+ {
+ dprintf("Could not read debuggee's process memory: IOlePresObj \n");
+ dprintf("at address %x\n", pCacheListItem->lpCacheNode->m_pPresObj);
+ dprintf("Last Error Code = %d (0x%x)\n", GetLastError(), GetLastError());
+
+ goto errRtn;
+ }
+
+ if (dwReturnedCount != dwSizeOfPresObj)
+ {
+ dprintf("Size of process memory read != requested (IPresObj)\n");
+
+ goto errRtn;
+ }
+
+ pCacheListItem->lpCacheNode->m_pPresObj = (IOlePresObj *)blockPresObj;
+ }
+
+ if (pCacheListItem->lpCacheNode->m_pPresObjAfterFreeze != NULL)
+ {
+ switch (pCacheListItem->lpCacheNode->m_dwPresFlag)
+ {
+ case CN_PRESOBJ_GEN:
+ dwSizeOfPresObj = sizeof(CGenObject);
+ break;
+ case CN_PRESOBJ_MF:
+ dwSizeOfPresObj = sizeof(CMfObject);
+ break;
+ case CN_PRESOBJ_EMF:
+ dwSizeOfPresObj = sizeof(CEMfObject);
+ break;
+ default:
+ dprintf("Error: can not determine size of IOlePresObj\n");
+ return;
+ }
+
+ blockPresObjAF = new char[dwSizeOfPresObj];
+
+ fError = ReadProcessMemory(
+ hCurrentProcess,
+ pCacheListItem->lpCacheNode->m_pPresObjAfterFreeze,
+ blockPresObjAF,
+ dwSizeOfPresObj,
+ &dwReturnedCount
+ );
+
+ if (fError == FALSE)
+ {
+ dprintf("Could not read debuggee's process memory: IOlePresObj \n");
+ dprintf("at address %x\n", pCacheListItem->lpCacheNode->m_pPresObjAfterFreeze);
+ dprintf("Last Error Code = %d (0x%x)\n", GetLastError(), GetLastError());
+
+ goto errRtn;
+ }
+
+ if (dwReturnedCount != dwSizeOfPresObj)
+ {
+ dprintf("Size of process memory read != requested (IOlePresObj)\n");
+
+ goto errRtn;
+ }
+
+ pCacheListItem->lpCacheNode->m_pPresObjAfterFreeze = (IOlePresObj *)blockPresObjAF;
+ }
+ }
+
+ // dump the structure
+ pszCacheListItem = DumpCACHELIST_ITEM(pCacheListItem, NO_PREFIX, 1);
+
+ dprintf("CACHELIST_ITEM @ 0x%x\n", dwAddr);
+ dprintfx(pszCacheListItem);
+
+ CoTaskMemFree(pszCacheListItem);
+
+errRtn:
+
+ // delete the blocks and not the pointers
+ delete[] blockPresObj;
+ delete[] blockPresObjAF;
+ delete[] blockCacheNode;
+ delete[] blockCacheListItem;
+
+ return;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: dump_cacheenum, exported
+//
+// Synopsis: dumps CCacheEnum object
+//
+// Effects:
+//
+// Arguments: see DECLARE_API in oleexts.h
+//
+// Requires:
+//
+// Returns: void
+//
+// Signals:
+//
+// Modifies: ExtensionApis (global)
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 02-Feb-95 t-ScottH author
+//
+// Notes:
+// The address of the object is passed in the arguments. This
+// address is in the debuggee's process memory. In order for
+// NTSD to view this memory, the debugger must copy the mem
+// using the WIN32 ReadProcessMemory API.
+//
+//--------------------------------------------------------------------------
+
+DECLARE_API(dump_cacheenum)
+{
+ BOOL fError;
+ LPVOID dwAddr;
+ DWORD dwReturnedCount;
+ char *pszCE;
+ char *blockCE = NULL;
+ CCacheEnum *pCE = NULL;
+
+ // set up global function pointers
+ ExtensionApis = *lpExtensionApis;
+
+ // get address of object from argument string
+ dwAddr = (LPVOID)GetExpression( args );
+ if (dwAddr == 0)
+ {
+ dprintf("Failed to get Address of CCacheEnum\n");
+ return;
+ }
+
+ // read the block of memory from the debugee's process
+ blockCE = new char[sizeof(CCacheEnum)];
+
+ fError = ReadProcessMemory(
+ hCurrentProcess,
+ dwAddr,
+ blockCE,
+ sizeof(CCacheEnum),
+ &dwReturnedCount
+ );
+
+ if (fError == FALSE)
+ {
+ dprintf("Could not read debuggee's process memory: CCacheEnum \n");
+ dprintf("at address %x\n", dwAddr);
+ dprintf("Last Error Code = %d (0x%x)\n", GetLastError(), GetLastError());
+
+ goto errRtn;
+ }
+
+ if (dwReturnedCount != sizeof(CCacheEnum))
+ {
+ dprintf("Size of process memory read != requested\n");
+
+ goto errRtn;
+ }
+
+ pCE = (CCacheEnum *)blockCE;
+
+ // dump the structure
+ pszCE = DumpCCacheEnum(pCE, NO_PREFIX, 1);
+
+ dprintf("CCacheEnum @ 0x%x\n", dwAddr);
+ dprintfx(pszCE);
+
+ CoTaskMemFree(pszCE);
+
+errRtn:
+
+ // delete the blocks and not the pointers
+ delete[] blockCE;
+
+ return;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: dump_cacheenumformatetc, exported
+//
+// Synopsis: dumps CCacheEnumFormatEtc object
+//
+// Effects:
+//
+// Arguments: see DECLARE_API in oleexts.h
+//
+// Requires:
+//
+// Returns: void
+//
+// Signals:
+//
+// Modifies: ExtensionApis (global)
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 02-Feb-95 t-ScottH author
+//
+// Notes:
+// The address of the object is passed in the arguments. This
+// address is in the debuggee's process memory. In order for
+// NTSD to view this memory, the debugger must copy the mem
+// using the WIN32 ReadProcessMemory API.
+//
+//--------------------------------------------------------------------------
+
+DECLARE_API(dump_cacheenumformatetc)
+{
+ BOOL fError;
+ LPVOID dwAddr;
+ DWORD dwReturnedCount;
+ char *pszCacheEnumFormatEtc;
+ char *blockCacheEnumFormatEtc = NULL;
+ CCacheEnumFormatEtc *pCacheEnumFormatEtc = NULL;
+
+ // set up global function pointers
+ ExtensionApis = *lpExtensionApis;
+
+ // get address of object from argument string
+ dwAddr = (LPVOID)GetExpression( args );
+ if (dwAddr == 0)
+ {
+ dprintf("Failed to get Address of CCacheEnumFormatEtc\n");
+ return;
+ }
+
+ // read the block of memory from the debugee's process
+ blockCacheEnumFormatEtc = new char[sizeof(CCacheEnumFormatEtc)];
+
+ fError = ReadProcessMemory(
+ hCurrentProcess,
+ dwAddr,
+ blockCacheEnumFormatEtc,
+ sizeof(CCacheEnumFormatEtc),
+ &dwReturnedCount
+ );
+
+ if (fError == FALSE)
+ {
+ dprintf("Could not read debuggee's process memory CacheEnumFormatEtc");
+ dprintf("at address %x\n", dwAddr);
+ dprintf("Last Error Code = %d (%x)\n", GetLastError(), GetLastError());
+
+ goto errRtn;
+ }
+
+ if (dwReturnedCount != sizeof(CCacheEnumFormatEtc))
+ {
+ dprintf("Size of process memory read != requested\n");
+
+ goto errRtn;
+ }
+
+ pCacheEnumFormatEtc = (CCacheEnumFormatEtc *)blockCacheEnumFormatEtc;
+
+ // dump the structure
+ pszCacheEnumFormatEtc = DumpCCacheEnumFormatEtc(pCacheEnumFormatEtc, NO_PREFIX, 1);
+
+ dprintf("CCacheEnumFormatEtc @ 0x%x\n", dwAddr);
+ dprintfx(pszCacheEnumFormatEtc);
+
+ CoTaskMemFree(pszCacheEnumFormatEtc);
+
+errRtn:
+
+ delete[] blockCacheEnumFormatEtc;
+
+ return;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: dump_cachenode, exported
+//
+// Synopsis: dumps CCacheNode object
+//
+// Effects:
+//
+// Arguments: see DECLARE_API in oleexts.h
+//
+// Requires:
+//
+// Returns: void
+//
+// Signals:
+//
+// Modifies: ExtensionApis (global)
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 02-Feb-95 t-ScottH author
+//
+// Notes:
+// The address of the object is passed in the arguments. This
+// address is in the debuggee's process memory. In order for
+// NTSD to view this memory, the debugger must copy the mem
+// using the WIN32 ReadProcessMemory API.
+//
+//--------------------------------------------------------------------------
+
+DECLARE_API(dump_cachenode)
+{
+ BOOL fError;
+ LPVOID dwAddr;
+ DWORD dwReturnedCount = 0;
+ char *pszCacheNode = NULL;
+ char *blockCacheNode = NULL;
+ char *blockPresObj = NULL;
+ char *blockPresObjAF = NULL;
+ CCacheNode *pCacheNode = NULL;
+ DWORD dwSizeOfPresObj;
+
+ // set up global function pointers
+ ExtensionApis = *lpExtensionApis;
+
+ // get address of object from argument string
+ dwAddr = (LPVOID)GetExpression( args );
+ if (dwAddr == 0)
+ {
+ dprintf("Failed to get Address of CCacheNode\n");
+ return;
+ }
+
+ // get the CCacheNode block of mem
+ blockCacheNode = new char[sizeof(CCacheNode)];
+
+ fError = ReadProcessMemory(
+ hCurrentProcess,
+ dwAddr,
+ blockCacheNode,
+ sizeof(CCacheNode),
+ &dwReturnedCount
+ );
+
+ if (fError == FALSE)
+ {
+ dprintf("Could not read debuggee's process memory: CCacheNode \n");
+ dprintf("at address %x\n", dwAddr);
+ dprintf("Last Error Code = %d (0x%x)\n", GetLastError(), GetLastError());
+
+ goto errRtn;
+ }
+
+ if (dwReturnedCount != sizeof(CCacheNode))
+ {
+ dprintf("Size of process memory read != requested (CCacheNode)\n");
+
+ goto errRtn;
+ }
+
+ pCacheNode = (CCacheNode*)blockCacheNode;
+
+ // need to get the OlePresObjs for the CCacheNode
+ if (pCacheNode->m_pPresObj != NULL)
+ {
+ switch (pCacheNode->m_dwPresFlag)
+ {
+ case CN_PRESOBJ_GEN:
+ dwSizeOfPresObj = sizeof(CGenObject);
+ break;
+ case CN_PRESOBJ_MF:
+ dwSizeOfPresObj = sizeof(CMfObject);
+ break;
+ case CN_PRESOBJ_EMF:
+ dwSizeOfPresObj = sizeof(CEMfObject);
+ break;
+ default:
+ dprintf("Error: can not determine size of IOlePresObj\n");
+ return;
+ }
+
+ blockPresObj = new char[dwSizeOfPresObj];
+
+ fError = ReadProcessMemory(
+ hCurrentProcess,
+ pCacheNode->m_pPresObj,
+ blockPresObj,
+ dwSizeOfPresObj,
+ &dwReturnedCount
+ );
+
+ if (fError == FALSE)
+ {
+ dprintf("Could not read debuggee's process memory: IOlePresObj \n");
+ dprintf("at address %x\n", pCacheNode->m_pPresObj);
+ dprintf("Last Error Code = %d (0x%x)\n", GetLastError(), GetLastError());
+
+ goto errRtn;
+ }
+
+ if (dwReturnedCount != dwSizeOfPresObj)
+ {
+ dprintf("Size of process memory read != requested (IOlePresObj)\n");
+
+ goto errRtn;
+ }
+
+ // pass off pointer
+ pCacheNode->m_pPresObj = (IOlePresObj *)blockPresObj;
+ }
+
+ if (pCacheNode->m_pPresObjAfterFreeze != NULL)
+ {
+ switch (pCacheNode->m_dwPresFlag)
+ {
+ case CN_PRESOBJ_GEN:
+ dwSizeOfPresObj = sizeof(CGenObject);
+ break;
+ case CN_PRESOBJ_MF:
+ dwSizeOfPresObj = sizeof(CMfObject);
+ break;
+ case CN_PRESOBJ_EMF:
+ dwSizeOfPresObj = sizeof(CEMfObject);
+ break;
+ default:
+ dprintf("Error: can not determine size of IOlePresObj\n");
+ return;
+ }
+
+ blockPresObjAF = new char[dwSizeOfPresObj];
+
+ fError = ReadProcessMemory(
+ hCurrentProcess,
+ pCacheNode->m_pPresObjAfterFreeze,
+ blockPresObjAF,
+ dwSizeOfPresObj,
+ &dwReturnedCount
+ );
+
+ if (fError == FALSE)
+ {
+ dprintf("Could not read debuggee's process memory: IOlePresObj \n");
+ dprintf("at address %x\n", pCacheNode->m_pPresObjAfterFreeze);
+ dprintf("Last Error Code = %d (0x%x)\n", GetLastError(), GetLastError());
+
+ goto errRtn;
+ }
+
+ if (dwReturnedCount != dwSizeOfPresObj)
+ {
+ dprintf("Size of process memory read != requested (IOlePresObj)\n");
+
+ goto errRtn;
+ }
+
+ // pass off pointer
+ pCacheNode->m_pPresObjAfterFreeze = (IOlePresObj *)blockPresObjAF;
+ }
+
+ // dump the structure
+ pszCacheNode = DumpCCacheNode(pCacheNode, NO_PREFIX, 1);
+
+ dprintf("CCacheNode @ 0x%x\n", dwAddr);
+ dprintfx(pszCacheNode);
+
+ CoTaskMemFree(pszCacheNode);
+
+errRtn:
+
+ // delete the blocks and not the pointers
+ delete[] blockPresObj;
+ delete[] blockPresObjAF;
+ delete[] blockCacheNode;
+
+ return;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: dump_clipdataobject, exported
+//
+// Synopsis: dumps CClipDataObject object
+//
+// Effects:
+//
+// Arguments: see DECLARE_API in oleexts.h
+//
+// Requires:
+//
+// Returns: void
+//
+// Signals:
+//
+// Modifies: ExtensionApis (global)
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 02-Feb-95 t-ScottH author
+//
+// Notes:
+// The address of the object is passed in the arguments. This
+// address is in the debuggee's process memory. In order for
+// NTSD to view this memory, the debugger must copy the mem
+// using the WIN32 ReadProcessMemory API.
+//
+//--------------------------------------------------------------------------
+
+DECLARE_API(dump_clipdataobject)
+{
+ BOOL fError;
+ LPVOID dwAddr;
+ DWORD dwReturnedCount;
+ char *pszCDO;
+ char *blockCDO = NULL;
+ char *blockFE = NULL;
+ CClipDataObject *pCDO = NULL;
+
+ // set up global function pointers
+ ExtensionApis = *lpExtensionApis;
+
+ // get address of object from argument string
+ dwAddr = (LPVOID)GetExpression( args );
+ if (dwAddr == 0)
+ {
+ dprintf("Failed to get Address of CClipDataObject\n");
+ return;
+ }
+
+ // read the block of memory from the debugee's process
+ blockCDO = new char[sizeof(CClipDataObject)];
+
+ fError = ReadProcessMemory(
+ hCurrentProcess,
+ dwAddr,
+ blockCDO,
+ sizeof(CClipDataObject),
+ &dwReturnedCount
+ );
+
+ if (fError == FALSE)
+ {
+ dprintf("Could not read debuggee's process memory: CClipDataObject \n");
+ dprintf("at address %x\n", dwAddr);
+ dprintf("Last Error Code = %d (0x%x)\n", GetLastError(), GetLastError());
+
+ goto errRtn;
+ }
+
+ if (dwReturnedCount != sizeof(CClipDataObject))
+ {
+ dprintf("Size of process memory read != requested\n");
+
+ goto errRtn;
+ }
+
+ pCDO = (CClipDataObject *)blockCDO;
+
+ // read the block of mem for the FORMATETC array
+ blockFE = new char[sizeof(FORMATETC)*pCDO->m_cFormats];
+
+ fError = ReadProcessMemory(
+ hCurrentProcess,
+ pCDO->m_rgFormats,
+ blockFE,
+ sizeof(FORMATETC)*pCDO->m_cFormats,
+ &dwReturnedCount
+ );
+
+ if (fError == FALSE)
+ {
+ dprintf("Could not read debuggee's process memory: FORMATETC array \n");
+ dprintf("at address %x\n", pCDO->m_rgFormats);
+ dprintf("Last Error Code = %d (0x%x)\n", GetLastError(), GetLastError());
+
+ goto errRtn;
+ }
+
+ if (dwReturnedCount != (sizeof(FORMATETC)*pCDO->m_cFormats))
+ {
+ dprintf("Size of process memory read != requested\n");
+
+ goto errRtn;
+ }
+
+ pCDO->m_rgFormats = (FORMATETC *)blockFE;
+
+ // dump the structure
+ pszCDO = DumpCClipDataObject(pCDO, NO_PREFIX, 1);
+
+ dprintf("CClipDataObject @ 0x%x\n", dwAddr);
+ dprintfx(pszCDO);
+
+ CoTaskMemFree(pszCDO);
+
+errRtn:
+
+ // delete the blocks and not the pointers
+ delete[] blockFE;
+ delete[] blockCDO;
+
+ return;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: dump_clipenumformatetc, exported
+//
+// Synopsis: dumps CClipEnumFormatEtc object
+//
+// Effects:
+//
+// Arguments: see DECLARE_API in oleexts.h
+//
+// Requires:
+//
+// Returns: void
+//
+// Signals:
+//
+// Modifies: ExtensionApis (global)
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 02-Feb-95 t-ScottH author
+//
+// Notes:
+// The address of the object is passed in the arguments. This
+// address is in the debuggee's process memory. In order for
+// NTSD to view this memory, the debugger must copy the mem
+// using the WIN32 ReadProcessMemory API.
+//
+//--------------------------------------------------------------------------
+
+DECLARE_API(dump_clipenumformatetc)
+{
+ BOOL fError;
+ LPVOID dwAddr;
+ DWORD dwReturnedCount;
+ char *pszCEFE;
+ char *blockCEFE = NULL;
+ char *blockFE = NULL;
+ CClipEnumFormatEtc *pCEFE = NULL;
+
+ // set up global function pointers
+ ExtensionApis = *lpExtensionApis;
+
+ // get address of object from argument string
+ dwAddr = (LPVOID)GetExpression( args );
+ if (dwAddr == 0)
+ {
+ dprintf("Failed to get Address of CClipEnumFormatEtc\n");
+ return;
+ }
+
+ // read the block of memory from the debugee's process
+ blockCEFE = new char[sizeof(CClipEnumFormatEtc)];
+
+ fError = ReadProcessMemory(
+ hCurrentProcess,
+ dwAddr,
+ blockCEFE,
+ sizeof(CClipEnumFormatEtc),
+ &dwReturnedCount
+ );
+
+ if (fError == FALSE)
+ {
+ dprintf("Could not read debuggee's process memory: CClipEnumFormatEtc \n");
+ dprintf("at address %x\n", dwAddr);
+ dprintf("Last Error Code = %d (0x%x)\n", GetLastError(), GetLastError());
+
+ goto errRtn;
+ }
+
+ if (dwReturnedCount != sizeof(CClipEnumFormatEtc))
+ {
+ dprintf("Size of process memory read != requested\n");
+
+ goto errRtn;
+ }
+
+ pCEFE = (CClipEnumFormatEtc *)blockCEFE;
+
+ // read the block of mem for the FORMATETC array
+ blockFE = new char[sizeof(FORMATETC)*pCEFE->m_cTotal];
+
+ fError = ReadProcessMemory(
+ hCurrentProcess,
+ pCEFE->m_rgFormats,
+ blockFE,
+ sizeof(FORMATETC)*pCEFE->m_cTotal,
+ &dwReturnedCount
+ );
+
+ if (fError == FALSE)
+ {
+ dprintf("Could not read debuggee's process memory: FORMATETC array \n");
+ dprintf("at address %x\n", pCEFE->m_rgFormats);
+ dprintf("Last Error Code = %d (0x%x)\n", GetLastError(), GetLastError());
+
+ goto errRtn;
+ }
+
+ if (dwReturnedCount != (sizeof(FORMATETC)*pCEFE->m_cTotal))
+ {
+ dprintf("Size of process memory read != requested\n");
+
+ goto errRtn;
+ }
+
+ pCEFE->m_rgFormats = (FORMATETC *)blockFE;
+
+ // dump the structure
+ pszCEFE = DumpCClipEnumFormatEtc(pCEFE, NO_PREFIX, 1);
+
+ dprintf("CClipEnumFormatEtc @ 0x%x\n", dwAddr);
+ dprintfx(pszCEFE);
+
+ CoTaskMemFree(pszCEFE);
+
+errRtn:
+
+ // delete the blocks and not the pointers
+ delete[] blockFE;
+ delete[] blockCEFE;
+
+ return;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: dump_daholder, exported
+//
+// Synopsis: dumps CDAHolder object
+//
+// Effects:
+//
+// Arguments: see DECLARE_API in oleexts.h
+//
+// Requires:
+//
+// Returns: void
+//
+// Signals:
+//
+// Modifies: ExtensionApis (global)
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 02-Feb-95 t-ScottH author
+//
+// Notes:
+// The address of the object is passed in the arguments. This
+// address is in the debuggee's process memory. In order for
+// NTSD to view this memory, the debugger must copy the mem
+// using the WIN32 ReadProcessMemory API.
+//
+//--------------------------------------------------------------------------
+
+DECLARE_API(dump_daholder)
+{
+ DWORD dwReturnedCount;
+ BOOL fError;
+ LPVOID dwAddr;
+ char *pszDAH;
+ char *blockDAH = NULL;
+ char *blockStatDataArray = NULL;
+ CDAHolder *pDAH = NULL;
+
+ // set up global function pointers
+ ExtensionApis = *lpExtensionApis;
+
+ // get address of object from argument string
+ dwAddr = (LPVOID)GetExpression( args );
+ if (dwAddr == 0)
+ {
+ dprintf("Failed to get Address of CDAHolder\n");
+ return;
+ }
+
+ // read the block of memory from the debugee's process
+ blockDAH = new char[sizeof(CDAHolder)];
+
+ fError = ReadProcessMemory(
+ hCurrentProcess,
+ dwAddr,
+ blockDAH,
+ sizeof(CDAHolder),
+ &dwReturnedCount
+ );
+
+ if (fError == FALSE)
+ {
+ dprintf("Could not read debuggee's process memory: CDAHolder \n");
+ dprintf("at address %x\n", dwAddr);
+ dprintf("Last Error Code = %d (0x%x)\n", GetLastError(), GetLastError());
+
+ goto errRtn;
+ }
+
+ if (dwReturnedCount != sizeof(CDAHolder))
+ {
+ dprintf("Size of process memory read != requested (CDAHolder)\n");
+
+ goto errRtn;
+ }
+
+ pDAH = (CDAHolder *)blockDAH;
+
+ // read the block of mem for the STATDATA array
+ blockStatDataArray = new char[sizeof(STATDATA) * pDAH->m_iSize];
+
+ fError = ReadProcessMemory(
+ hCurrentProcess,
+ pDAH->m_pSD,
+ blockStatDataArray,
+ sizeof(STATDATA) * pDAH->m_iSize,
+ &dwReturnedCount
+ );
+
+ if (fError == FALSE)
+ {
+ dprintf("Could not read debuggee's process memory: STATDATA array \n");
+ dprintf("at address %x\n", pDAH->m_pSD);
+ dprintf("Last Error Code = %d (0x%x)\n", GetLastError(), GetLastError());
+
+ goto errRtn;
+ }
+
+ if (dwReturnedCount != (sizeof(STATDATA) * pDAH->m_iSize))
+ {
+ dprintf("Size of process memory read != requested (STATDATA array)\n");
+
+ goto errRtn;
+ }
+
+ pDAH->m_pSD = (STATDATA *)blockStatDataArray;
+
+ // dump the structure
+ pszDAH = DumpCDAHolder(pDAH, NO_PREFIX, 1);
+
+ dprintf("CDAHolder @ 0x%x\n", dwAddr);
+ dprintfx(pszDAH);
+
+ CoTaskMemFree(pszDAH);
+
+errRtn:
+
+ delete[] blockDAH;
+ delete[] blockStatDataArray;
+
+ return;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: dump_dataadvisecache, exported
+//
+// Synopsis: dumps CDataAdviseCache object
+//
+// Effects:
+//
+// Arguments: see DECLARE_API in oleexts.h
+//
+// Requires:
+//
+// Returns: void
+//
+// Signals:
+//
+// Modifies: ExtensionApis (global)
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 02-Feb-95 t-ScottH author
+//
+// Notes:
+// The address of the object is passed in the arguments. This
+// address is in the debuggee's process memory. In order for
+// NTSD to view this memory, the debugger must copy the mem
+// using the WIN32 ReadProcessMemory API.
+//
+//--------------------------------------------------------------------------
+
+DECLARE_API(dump_dataadvisecache)
+{
+ BOOL fError;
+ LPVOID dwAddr;
+ DWORD dwReturnedCount;
+ char *pszDataAdviseCache;
+ char *blockDataAdviseCache = NULL;
+ char *blockDAH = NULL;
+ CDataAdviseCache *pDataAdviseCache = NULL;
+
+ // set up global function pointers
+ ExtensionApis = *lpExtensionApis;
+
+ // get address of object from argument string
+ dwAddr = (LPVOID)GetExpression( args );
+ if (dwAddr == 0)
+ {
+ dprintf("Failed to get Address of CDataAdviseCache\n");
+ return;
+ }
+
+ // read the block of memory from the debugee's process
+ blockDataAdviseCache = new char[sizeof(CDataAdviseCache)];
+
+ fError = ReadProcessMemory(
+ hCurrentProcess,
+ dwAddr,
+ blockDataAdviseCache,
+ sizeof(CDataAdviseCache),
+ &dwReturnedCount
+ );
+
+ if (fError == FALSE)
+ {
+ dprintf("Could not read debuggee's process memory DataAdviseCache");
+ dprintf("at address %x\n", dwAddr);
+ dprintf("Last Error Code = %d (%x)\n", GetLastError(), GetLastError());
+
+ goto errRtn;
+ }
+
+ if (dwReturnedCount != sizeof(CDataAdviseCache))
+ {
+ dprintf("Size of process memory read != requested\n");
+
+ goto errRtn;
+ }
+
+ pDataAdviseCache = (CDataAdviseCache *)blockDataAdviseCache;
+
+ // get the mem for CDAHolder
+ if (pDataAdviseCache->m_pDAH != NULL)
+ {
+ blockDAH = new char[sizeof(CDAHolder)];
+
+ fError = ReadProcessMemory(
+ hCurrentProcess,
+ pDataAdviseCache->m_pDAH,
+ blockDAH,
+ sizeof(CDAHolder),
+ &dwReturnedCount
+ );
+
+ if (fError == FALSE)
+ {
+ dprintf("Could not read debuggee's process memory CDAHolder");
+ dprintf("at address %x\n", pDataAdviseCache->m_pDAH);
+ dprintf("Last Error Code = %d (%x)\n", GetLastError(), GetLastError());
+
+ goto errRtn;
+ }
+
+ if (dwReturnedCount != sizeof(CDAHolder))
+ {
+ dprintf("Size of process memory read != requested (CDAHolder)\n");
+
+ goto errRtn;
+ }
+
+ pDataAdviseCache->m_pDAH = (CDAHolder *)blockDAH;
+ }
+
+ // dump the structure
+ pszDataAdviseCache = DumpCDataAdviseCache(pDataAdviseCache, NO_PREFIX, 1);
+
+ dprintf("CDataAdviseCache @ 0x%x\n", dwAddr);
+ dprintfx(pszDataAdviseCache);
+
+ CoTaskMemFree(pszDataAdviseCache);
+
+errRtn:
+
+ delete[] blockDAH;
+ delete[] blockDataAdviseCache;
+
+ return;
+}
+//+-------------------------------------------------------------------------
+//
+// Function: dump_defclassfactory, exported
+//
+// Synopsis: dumps CDefClassFactory object
+//
+// Effects:
+//
+// Arguments: see DECLARE_API in oleexts.h
+//
+// Requires:
+//
+// Returns: void
+//
+// Signals:
+//
+// Modifies: ExtensionApis (global)
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 02-Feb-95 t-ScottH author
+//
+// Notes:
+// The address of the object is passed in the arguments. This
+// address is in the debuggee's process memory. In order for
+// NTSD to view this memory, the debugger must copy the mem
+// using the WIN32 ReadProcessMemory API.
+//
+//--------------------------------------------------------------------------
+
+DECLARE_API(dump_defclassfactory)
+{
+ BOOL fError;
+ LPVOID dwAddr;
+ DWORD dwReturnedCount;
+ char *pszDefClassFactory;
+ char *blockDefClassFactory = NULL;
+ CDefClassFactory *pDefClassFactory = NULL;
+
+ // set up global function pointers
+ ExtensionApis = *lpExtensionApis;
+
+ // get address of object from argument string
+ dwAddr = (LPVOID)GetExpression( args );
+ if (dwAddr == 0)
+ {
+ dprintf("Failed to get Address of CDefClassFactory\n");
+ return;
+ }
+
+ // read the block of memory from the debugee's process
+ blockDefClassFactory = new char[sizeof(CDefClassFactory)];
+
+ fError = ReadProcessMemory(
+ hCurrentProcess,
+ dwAddr,
+ blockDefClassFactory,
+ sizeof(CDefClassFactory),
+ &dwReturnedCount
+ );
+
+ if (fError == FALSE)
+ {
+ dprintf("Could not read debuggee's process memory DefClassFactory");
+ dprintf("at address %x\n", dwAddr);
+ dprintf("Last Error Code = %d (%x)\n", GetLastError(), GetLastError());
+
+ goto errRtn;
+ }
+
+ if (dwReturnedCount != sizeof(CDefClassFactory))
+ {
+ dprintf("Size of process memory read != requested\n");
+
+ goto errRtn;
+ }
+
+ pDefClassFactory = (CDefClassFactory *)blockDefClassFactory;
+
+ // dump the structure
+ pszDefClassFactory = DumpCDefClassFactory(pDefClassFactory, NO_PREFIX, 1);
+
+ dprintf("CDefClassFactory @ 0x%x\n", dwAddr);
+ dprintfx(pszDefClassFactory);
+
+ CoTaskMemFree(pszDefClassFactory);
+
+errRtn:
+
+ delete[] blockDefClassFactory;
+
+ return;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: dump_deflink, exported
+//
+// Synopsis: dumps CDefLink object
+//
+// Effects:
+//
+// Arguments: see DECLARE_API in oleexts.h
+//
+// Requires:
+//
+// Returns: void
+//
+// Signals:
+//
+// Modifies: ExtensionApis (global)
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 02-Feb-95 t-ScottH author
+//
+// Notes:
+// The address of the object is passed in the arguments. This
+// address is in the debuggee's process memory. In order for
+// NTSD to view this memory, the debugger must copy the mem
+// using the WIN32 ReadProcessMemory API.
+//
+//--------------------------------------------------------------------------
+
+DECLARE_API(dump_deflink)
+{
+ unsigned int ui;
+ BOOL fError;
+ LPVOID dwAddr;
+ DWORD dwReturnedCount = 0;
+ char *pszDL = NULL;
+ char *blockDefLink = NULL;
+ char *blockCOleCache = NULL;
+ char *blockDataAdvCache = NULL;
+ char *blockOAHolder = NULL;
+ char *blockpIAS = NULL;
+ char *blockDAHolder = NULL;
+ char *blockSTATDATA = NULL;
+ char *blockCACHELIST = NULL;
+ char *blockCacheNode = NULL;
+ char *blockPresObj = NULL;
+ CDefLink *pDL = NULL;
+ CDAHolder *pDAH = NULL;
+ COAHolder *pOAH = NULL;
+ DWORD dwSizeOfPresObj;
+
+ // set up global function pointers
+ ExtensionApis = *lpExtensionApis;
+
+ // get address of object from argument string
+ dwAddr = (LPVOID)GetExpression( args );
+ if (dwAddr == 0)
+ {
+ dprintf("Failed to get Address of CDefLink\n");
+ return;
+ }
+
+ // read the block of memory from the debugee's process
+ blockDefLink = new char[sizeof(CDefLink)];
+
+ fError = ReadProcessMemory(
+ hCurrentProcess,
+ dwAddr,
+ blockDefLink,
+ sizeof(CDefLink),
+ &dwReturnedCount
+ );
+
+ if (fError == FALSE)
+ {
+ dprintf("Could not read debuggee's process memory: CDefLink \n");
+ dprintf("at address %x\n", dwAddr);
+ dprintf("Last Error Code = %d (0x%x)\n", GetLastError(), GetLastError());
+
+ goto errRtn;
+ }
+
+ if (dwReturnedCount != sizeof(CDefLink))
+ {
+ dprintf("Size of process memory read != requested (CDefLink)\n");
+
+ goto errRtn;
+ }
+
+ pDL = (CDefLink *)blockDefLink;
+
+ // we need to NULL the monikers since we can't use GetDisplayName in this process
+ pDL->m_pMonikerAbs = NULL;
+ pDL->m_pMonikerRel = NULL;
+
+ // get the block of mem for the COAHolder
+ if (pDL->m_pCOAHolder != NULL)
+ {
+ blockOAHolder = new char[sizeof(COAHolder)];
+
+ fError = ReadProcessMemory(
+ hCurrentProcess,
+ pDL->m_pCOAHolder,
+ blockOAHolder,
+ sizeof(COAHolder),
+ &dwReturnedCount
+ );
+
+ if (fError == FALSE)
+ {
+ dprintf("Could not read debuggee's process memory: COAHolder \n");
+ dprintf("at address %x\n", pDL->m_pCOAHolder);
+ dprintf("Last Error Code = %d (0x%x)\n", GetLastError(), GetLastError());
+
+ goto errRtn;
+ }
+
+ if (dwReturnedCount != sizeof(COAHolder))
+ {
+ dprintf("Size of process memory read != requested (COAHolder)\n");
+
+ goto errRtn;
+ }
+
+ pDL->m_pCOAHolder = (COAHolder *)blockOAHolder;
+ pOAH = (COAHolder *)blockOAHolder;
+
+ // need to copy the array of IAdviseSink pointers
+ if (pOAH->m_iSize > 0)
+ {
+ blockpIAS = new char[pOAH->m_iSize * sizeof(IAdviseSink *)];
+
+ fError = ReadProcessMemory(
+ hCurrentProcess,
+ pOAH->m_ppIAS,
+ blockpIAS,
+ sizeof(IAdviseSink *) * pOAH->m_iSize,
+ &dwReturnedCount
+ );
+
+ if (fError == FALSE)
+ {
+ dprintf("Could not read debuggee's process memory: IAdviseSink Array \n");
+ dprintf("at address %x\n", pOAH->m_ppIAS);
+ dprintf("Last Error Code = %d (0x%x)\n", GetLastError(), GetLastError());
+
+ goto errRtn;
+ }
+
+ if (dwReturnedCount != (sizeof(IAdviseSink *) * pOAH->m_iSize))
+ {
+ dprintf("Size of process memory read != requested(IAdviseSink Array)\n");
+
+ goto errRtn;
+ }
+
+ pOAH->m_ppIAS = (IAdviseSink **)blockpIAS;
+ }
+ }
+
+ // get block of mem for CDataAdviseCache (only if m_pDataAdvCache != NULL)
+ if (pDL->m_pDataAdvCache != NULL)
+ {
+ blockDataAdvCache = new char[sizeof(CDataAdviseCache)];
+
+ fError = ReadProcessMemory(
+ hCurrentProcess,
+ pDL->m_pDataAdvCache,
+ blockDataAdvCache,
+ sizeof(CDataAdviseCache),
+ &dwReturnedCount
+ );
+
+ if (fError == FALSE)
+ {
+ dprintf("Could not read debuggee's process memory: CDataAdviseCache \n");
+ dprintf("at address %x\n", pDL->m_pDataAdvCache);
+ dprintf("Last Error Code = %d (0x%x)\n", GetLastError(), GetLastError());
+
+ goto errRtn;
+ }
+
+ if (dwReturnedCount != sizeof(CDataAdviseCache))
+ {
+ dprintf("Size of process memory read != requested (CDataAdviseCache)\n");
+
+ goto errRtn;
+ }
+
+ pDL->m_pDataAdvCache = (CDataAdviseCache *)blockDataAdvCache;
+
+ if (pDL->m_pDataAdvCache->m_pDAH != NULL)
+ {
+ blockDAHolder = new char[sizeof(CDAHolder)];
+
+ fError = ReadProcessMemory(
+ hCurrentProcess,
+ pDL->m_pDataAdvCache->m_pDAH,
+ blockDAHolder,
+ sizeof(CDAHolder),
+ &dwReturnedCount
+ );
+
+ if (fError == FALSE)
+ {
+ dprintf("Could not read debuggee's process memory: CDAHolder \n");
+ dprintf("at address %x\n", pDL->m_pDataAdvCache->m_pDAH);
+ dprintf("Last Error Code = %d (0x%x)\n", GetLastError(), GetLastError());
+
+ goto errRtn;
+ }
+
+ if (dwReturnedCount != sizeof(CDAHolder))
+ {
+ dprintf("Size of process memory read != requested (CDAHolder)\n");
+
+ goto errRtn;
+ }
+
+ pDL->m_pDataAdvCache->m_pDAH = (IDataAdviseHolder *)blockDAHolder;
+ pDAH = (CDAHolder *)blockDAHolder;
+
+ if (pDAH->m_pSD != NULL)
+ {
+ blockSTATDATA = new char[sizeof(STATDATA)*pDAH->m_iSize];
+
+ fError = ReadProcessMemory(
+ hCurrentProcess,
+ pDAH->m_pSD,
+ blockSTATDATA,
+ sizeof(STATDATA)*pDAH->m_iSize,
+ &dwReturnedCount
+ );
+
+ if (fError == FALSE)
+ {
+ dprintf("Could not read debuggee's process memory: STATDATA \n");
+ dprintf("at address %x\n", pDAH->m_pSD);
+ dprintf("Last Error Code = %d (0x%x)\n", GetLastError(), GetLastError());
+
+ goto errRtn;
+ }
+
+ if (dwReturnedCount != (sizeof(STATDATA)*pDAH->m_iSize))
+ {
+ dprintf("Size of process memory read != requested (STATDATA)\n");
+
+ goto errRtn;
+ }
+
+ pDAH->m_pSD = (STATDATA *)blockSTATDATA;
+ }
+ }
+ }
+
+ // get block of mem for COleCache (only if m_pCOleCache != NULL)
+ if (pDL->m_pCOleCache != NULL)
+ {
+ blockCOleCache = new char[sizeof(COleCache)];
+
+ fError = ReadProcessMemory(
+ hCurrentProcess,
+ pDL->m_pCOleCache,
+ blockCOleCache,
+ sizeof(COleCache),
+ &dwReturnedCount
+ );
+
+ if (fError == FALSE)
+ {
+ dprintf("Could not read debuggee's process memory: COleCache \n");
+ dprintf("at address %x\n", pDL->m_pCOleCache);
+ dprintf("Last Error Code = %d (0x%x)\n", GetLastError(), GetLastError());
+
+ goto errRtn;
+ }
+
+ if (dwReturnedCount != sizeof(COleCache))
+ {
+ dprintf("Size of process memory read != requested (COleCache)\n");
+
+ goto errRtn;
+ }
+
+ pDL->m_pCOleCache = (COleCache *)blockCOleCache;
+
+ // get block of mem for CACHELIST
+ if (pDL->m_pCOleCache->m_pCacheList != NULL)
+ {
+ blockCACHELIST = new char[sizeof(CACHELIST_ITEM) * pDL->m_pCOleCache->m_uCacheNodeMax];
+
+ fError = ReadProcessMemory(
+ hCurrentProcess,
+ pDL->m_pCOleCache->m_pCacheList,
+ blockCACHELIST,
+ sizeof(CACHELIST_ITEM) * pDL->m_pCOleCache->m_uCacheNodeMax,
+ &dwReturnedCount
+ );
+
+ if (fError == FALSE)
+ {
+ dprintf("Could not read debuggee's process memory: CACHELIST \n");
+ dprintf("at address %x\n", pDL->m_pCOleCache->m_pCacheList);
+ dprintf("Last Error Code = %d (0x%x)\n", GetLastError(), GetLastError());
+
+ goto errRtn;
+ }
+
+ if (dwReturnedCount != (sizeof(CACHELIST_ITEM) * pDL->m_pCOleCache->m_uCacheNodeMax))
+ {
+ dprintf("Size of process memory read != requestedi (CACHELIST)\n");
+
+ goto errRtn;
+ }
+
+ pDL->m_pCOleCache->m_pCacheList = (LPCACHELIST) blockCACHELIST;
+ }
+
+ // need to copy the memory of the CCacheNode's in the CACHELIST
+ for (ui = 0; ui < pDL->m_pCOleCache->m_uCacheNodeMax; ui++)
+ {
+ if (pDL->m_pCOleCache->m_pCacheList[ui].lpCacheNode != NULL)
+ {
+ blockCacheNode = new char[sizeof(CCacheNode)];
+
+ fError = ReadProcessMemory(
+ hCurrentProcess,
+ pDL->m_pCOleCache->m_pCacheList[ui].lpCacheNode,
+ blockCacheNode,
+ sizeof(CCacheNode),
+ &dwReturnedCount
+ );
+
+ if (fError == FALSE)
+ {
+ dprintf("Could not read debuggee's process memory: CCacheNode \n");
+ dprintf("at address %x\n", pDL->m_pCOleCache->m_pCacheList[ui].lpCacheNode);
+ dprintf("Last Error Code = %d (0x%x)\n", GetLastError(), GetLastError());
+
+ goto errRtn;
+ }
+
+ if (dwReturnedCount != sizeof(CCacheNode))
+ {
+ dprintf("Size of process memory read != requested (CCacheNode)\n");
+
+ goto errRtn;
+ }
+
+ // pass off pointer
+ pDL->m_pCOleCache->m_pCacheList[ui].lpCacheNode = (CCacheNode*)blockCacheNode;
+ blockCacheNode = NULL;
+
+ // need to get the OlePresObjs for the CCacheNode
+ if (pDL->m_pCOleCache->m_pCacheList[ui].lpCacheNode->m_pPresObj != NULL)
+ {
+ switch (pDL->m_pCOleCache->m_pCacheList[ui].lpCacheNode->m_dwPresFlag)
+ {
+ case CN_PRESOBJ_GEN:
+ dwSizeOfPresObj = sizeof(CGenObject);
+ break;
+ case CN_PRESOBJ_MF:
+ dwSizeOfPresObj = sizeof(CMfObject);
+ break;
+ case CN_PRESOBJ_EMF:
+ dwSizeOfPresObj = sizeof(CEMfObject);
+ break;
+ default:
+ dprintf("Error: can not determine size of IOlePresObj\n");
+ return;
+ }
+
+ blockPresObj = new char[dwSizeOfPresObj];
+
+ fError = ReadProcessMemory(
+ hCurrentProcess,
+ pDL->m_pCOleCache->m_pCacheList[ui].lpCacheNode->m_pPresObj,
+ blockPresObj,
+ dwSizeOfPresObj,
+ &dwReturnedCount
+ );
+
+ if (fError == FALSE)
+ {
+ dprintf("Could not read debuggee's process memory: IOlePresObj \n");
+ dprintf("at address %x\n", pDL->m_pCOleCache->m_pCacheList[ui].lpCacheNode->m_pPresObj);
+ dprintf("Last Error Code = %d (0x%x)\n", GetLastError(), GetLastError());
+
+ goto errRtn;
+ }
+
+ if (dwReturnedCount != dwSizeOfPresObj)
+ {
+ dprintf("Size of process memory read != requested (IOlePresObj)\n");
+
+ goto errRtn;
+ }
+
+ // pass off pointer
+ pDL->m_pCOleCache->m_pCacheList[ui].lpCacheNode->m_pPresObj = (IOlePresObj *)blockPresObj;
+ blockPresObj = NULL;
+ }
+
+ if (pDL->m_pCOleCache->m_pCacheList[ui].lpCacheNode->m_pPresObjAfterFreeze != NULL)
+ {
+ switch (pDL->m_pCOleCache->m_pCacheList[ui].lpCacheNode->m_dwPresFlag)
+ {
+ case CN_PRESOBJ_GEN:
+ dwSizeOfPresObj = sizeof(CGenObject);
+ break;
+ case CN_PRESOBJ_MF:
+ dwSizeOfPresObj = sizeof(CMfObject);
+ break;
+ case CN_PRESOBJ_EMF:
+ dwSizeOfPresObj = sizeof(CEMfObject);
+ break;
+ default:
+ dprintf("Error: can not determine size of IOlePresObj\n");
+ return;
+ }
+
+ blockPresObj = new char[dwSizeOfPresObj];
+
+ fError = ReadProcessMemory(
+ hCurrentProcess,
+ pDL->m_pCOleCache->m_pCacheList[ui].lpCacheNode->m_pPresObjAfterFreeze,
+ blockPresObj,
+ dwSizeOfPresObj,
+ &dwReturnedCount
+ );
+
+ if (fError == FALSE)
+ {
+ dprintf("Could not read debuggee's process memory: IOlePresObj \n");
+ dprintf("at address %x\n", pDL->m_pCOleCache->m_pCacheList[ui].lpCacheNode->m_pPresObjAfterFreeze);
+ dprintf("Last Error Code = %d (0x%x)\n", GetLastError(), GetLastError());
+
+ goto errRtn;
+ }
+
+ if (dwReturnedCount != dwSizeOfPresObj)
+ {
+ dprintf("Size of process memory read != requested (IOlePresObj)\n");
+
+ goto errRtn;
+ }
+
+ // pass off pointer
+ pDL->m_pCOleCache->m_pCacheList[ui].lpCacheNode->m_pPresObjAfterFreeze = (IOlePresObj *)blockPresObj;
+ blockPresObj = NULL;
+ }
+ }
+ }
+ }
+
+ // dump the structure
+ pszDL = DumpCDefLink(pDL, NO_PREFIX, 1);
+
+ dprintf("CDefLink @ 0x%x\n", dwAddr);
+ dprintfx(pszDL);
+
+ CoTaskMemFree(pszDL);
+
+errRtn:
+
+ // delete the blocks and not the pointers
+ if ( (pDL != NULL)&&(blockCACHELIST != NULL)&&(blockCOleCache != NULL) )
+ {
+ for (ui = 0; ui < pDL->m_pCOleCache->m_uCacheNodeMax; ui++)
+ {
+ if (pDL->m_pCOleCache->m_pCacheList[ui].lpCacheNode != NULL)
+ {
+ delete[] ((char *)pDL->m_pCOleCache->m_pCacheList[ui].lpCacheNode->m_pPresObj);
+ delete[] ((char *)pDL->m_pCOleCache->m_pCacheList[ui].lpCacheNode->m_pPresObjAfterFreeze);
+ delete[] ((char *)pDL->m_pCOleCache->m_pCacheList[ui].lpCacheNode);
+ }
+ }
+ }
+ delete[] blockCACHELIST;
+ delete[] blockCOleCache;
+ delete[] blockDAHolder;
+ delete[] blockSTATDATA;
+ delete[] blockDataAdvCache;
+ delete[] blockpIAS;
+ delete[] blockOAHolder;
+ delete[] blockDefLink;
+
+ return;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: dump_defobject, exported
+//
+// Synopsis: dumps CDefObject object
+//
+// Effects:
+//
+// Arguments: see DECLARE_API in oleexts.h
+//
+// Requires:
+//
+// Returns: void
+//
+// Signals:
+//
+// Modifies: ExtensionApis (global)
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 02-Feb-95 t-ScottH author
+//
+// Notes:
+// The address of the object is passed in the arguments. This
+// address is in the debuggee's process memory. In order for
+// NTSD to view this memory, the debugger must copy the mem
+// using the WIN32 ReadProcessMemory API.
+//
+//--------------------------------------------------------------------------
+
+DECLARE_API(dump_defobject)
+{
+ unsigned int ui;
+ BOOL fError;
+ LPVOID dwAddr;
+ DWORD dwReturnedCount = 0;
+ char *pszDO = NULL;
+ char *blockDefObject = NULL;
+ char *blockCOleCache = NULL;
+ char *blockDataAdvCache = NULL;
+ char *blockOAHolder = NULL;
+ char *blockpIAS = NULL;
+ char *blockDAHolder = NULL;
+ char *blockSTATDATA = NULL;
+ char *blockCACHELIST = NULL;
+ char *blockCacheNode = NULL;
+ char *blockPresObj = NULL;
+ CDefObject *pDO = NULL;
+ CDAHolder *pDAH = NULL;
+ COAHolder *pOAH = NULL;
+ DWORD dwSizeOfPresObj;
+
+ // set up global function pointers
+ ExtensionApis = *lpExtensionApis;
+
+ // get address of object from argument string
+ dwAddr = (LPVOID)GetExpression( args );
+ if (dwAddr == 0)
+ {
+ dprintf("Failed to get Address of CDefObject\n");
+ return;
+ }
+
+ // read the block of memory from the debugee's process
+ blockDefObject = new char[sizeof(CDefObject)];
+
+ fError = ReadProcessMemory(
+ hCurrentProcess,
+ dwAddr,
+ blockDefObject,
+ sizeof(CDefObject),
+ &dwReturnedCount
+ );
+
+ if (fError == FALSE)
+ {
+ dprintf("Could not read debuggee's process memory: CDefObject \n");
+ dprintf("at address %x\n", dwAddr);
+ dprintf("Last Error Code = %d (0x%x)\n", GetLastError(), GetLastError());
+
+ goto errRtn;
+ }
+
+ if (dwReturnedCount != sizeof(CDefObject))
+ {
+ dprintf("Size of process memory read != requested (CDefObject)\n");
+
+ goto errRtn;
+ }
+
+ pDO = (CDefObject *)blockDefObject;
+
+ // get the block of mem for the COAHolder
+ if (pDO->m_pOAHolder != NULL)
+ {
+ blockOAHolder = new char[sizeof(COAHolder)];
+
+ fError = ReadProcessMemory(
+ hCurrentProcess,
+ pDO->m_pOAHolder,
+ blockOAHolder,
+ sizeof(COAHolder),
+ &dwReturnedCount
+ );
+
+ if (fError == FALSE)
+ {
+ dprintf("Could not read debuggee's process memory: COAHolder \n");
+ dprintf("at address %x\n", pDO->m_pOAHolder);
+ dprintf("Last Error Code = %d (0x%x)\n", GetLastError(), GetLastError());
+
+ goto errRtn;
+ }
+
+ if (dwReturnedCount != sizeof(COAHolder))
+ {
+ dprintf("Size of process memory read != requested (COAHolder)\n");
+
+ goto errRtn;
+ }
+
+ pDO->m_pOAHolder = (COAHolder *)blockOAHolder;
+ pOAH = (COAHolder *)blockOAHolder;
+
+ // need to copy the array of IAdviseSink pointers
+ if (pOAH->m_iSize > 0)
+ {
+ blockpIAS = new char[pOAH->m_iSize * sizeof(IAdviseSink *)];
+
+ fError = ReadProcessMemory(
+ hCurrentProcess,
+ pOAH->m_ppIAS,
+ blockpIAS,
+ sizeof(IAdviseSink *) * pOAH->m_iSize,
+ &dwReturnedCount
+ );
+
+ if (fError == FALSE)
+ {
+ dprintf("Could not read debuggee's process memory: IAdviseSink Array \n");
+ dprintf("at address %x\n", pOAH->m_ppIAS);
+ dprintf("Last Error Code = %d (0x%x)\n", GetLastError(), GetLastError());
+
+ goto errRtn;
+ }
+
+ if (dwReturnedCount != (sizeof(IAdviseSink *) * pOAH->m_iSize))
+ {
+ dprintf("Size of process memory read != requested(IAdviseSink Array)\n");
+
+ goto errRtn;
+ }
+
+ pOAH->m_ppIAS = (IAdviseSink **)blockpIAS;
+ }
+ }
+
+ // get block of mem for CDataAdviseCache (only if m_pDataAdvCache != NULL)
+ if (pDO->m_pDataAdvCache != NULL)
+ {
+ blockDataAdvCache = new char[sizeof(CDataAdviseCache)];
+
+ fError = ReadProcessMemory(
+ hCurrentProcess,
+ pDO->m_pDataAdvCache,
+ blockDataAdvCache,
+ sizeof(CDataAdviseCache),
+ &dwReturnedCount
+ );
+
+ if (fError == FALSE)
+ {
+ dprintf("Could not read debuggee's process memory: CDataAdviseCache \n");
+ dprintf("at address %x\n", pDO->m_pDataAdvCache);
+ dprintf("Last Error Code = %d (0x%x)\n", GetLastError(), GetLastError());
+
+ goto errRtn;
+ }
+
+ if (dwReturnedCount != sizeof(CDataAdviseCache))
+ {
+ dprintf("Size of process memory read != requested (CDataAdviseCache)\n");
+
+ goto errRtn;
+ }
+
+ pDO->m_pDataAdvCache = (CDataAdviseCache *)blockDataAdvCache;
+
+ // get the mem for CDAHolder
+ if (pDO->m_pDataAdvCache->m_pDAH != NULL)
+ {
+ blockDAHolder = new char[sizeof(CDAHolder)];
+
+ fError = ReadProcessMemory(
+ hCurrentProcess,
+ pDO->m_pDataAdvCache->m_pDAH,
+ blockDAHolder,
+ sizeof(CDAHolder),
+ &dwReturnedCount
+ );
+
+ if (fError == FALSE)
+ {
+ dprintf("Could not read debuggee's process memory: CDAHolder \n");
+ dprintf("at address %x\n", pDO->m_pDataAdvCache->m_pDAH);
+ dprintf("Last Error Code = %d (0x%x)\n", GetLastError(), GetLastError());
+
+ goto errRtn;
+ }
+
+ if (dwReturnedCount != sizeof(CDAHolder))
+ {
+ dprintf("Size of process memory read != requested (CDAHolder)\n");
+
+ goto errRtn;
+ }
+
+ pDO->m_pDataAdvCache->m_pDAH = (IDataAdviseHolder *)blockDAHolder;
+ pDAH = (CDAHolder *)blockDAHolder;
+
+ // get the STATDATA array
+ if (pDAH->m_pSD != NULL)
+ {
+ blockSTATDATA = new char[sizeof(STATDATA)*pDAH->m_iSize];
+
+ fError = ReadProcessMemory(
+ hCurrentProcess,
+ pDAH->m_pSD,
+ blockSTATDATA,
+ sizeof(STATDATA)*pDAH->m_iSize,
+ &dwReturnedCount
+ );
+
+ if (fError == FALSE)
+ {
+ dprintf("Could not read debuggee's process memory: STATDATA \n");
+ dprintf("at address %x\n", pDAH->m_pSD);
+ dprintf("Last Error Code = %d (0x%x)\n", GetLastError(), GetLastError());
+
+ goto errRtn;
+ }
+
+ if (dwReturnedCount != (sizeof(STATDATA)*pDAH->m_iSize))
+ {
+ dprintf("Size of process memory read != requested (STATDATA)\n");
+
+ goto errRtn;
+ }
+
+ pDAH->m_pSD = (STATDATA *)blockSTATDATA;
+ }
+ }
+ }
+
+ // get block of mem for COleCache (only if m_pCOleCache != NULL)
+ if (pDO->m_pCOleCache != NULL)
+ {
+ blockCOleCache = new char[sizeof(COleCache)];
+
+ fError = ReadProcessMemory(
+ hCurrentProcess,
+ pDO->m_pCOleCache,
+ blockCOleCache,
+ sizeof(COleCache),
+ &dwReturnedCount
+ );
+
+ if (fError == FALSE)
+ {
+ dprintf("Could not read debuggee's process memory: COleCache \n");
+ dprintf("at address %x\n", pDO->m_pCOleCache);
+ dprintf("Last Error Code = %d (0x%x)\n", GetLastError(), GetLastError());
+
+ goto errRtn;
+ }
+
+ if (dwReturnedCount != sizeof(COleCache))
+ {
+ dprintf("Size of process memory read != requested (COleCache)\n");
+
+ goto errRtn;
+ }
+
+ pDO->m_pCOleCache = (COleCache *)blockCOleCache;
+
+ // get block of mem for CACHELIST
+ if (pDO->m_pCOleCache->m_pCacheList != NULL)
+ {
+ blockCACHELIST = new char[sizeof(CACHELIST_ITEM) * pDO->m_pCOleCache->m_uCacheNodeMax];
+
+ fError = ReadProcessMemory(
+ hCurrentProcess,
+ pDO->m_pCOleCache->m_pCacheList,
+ blockCACHELIST,
+ sizeof(CACHELIST_ITEM) * pDO->m_pCOleCache->m_uCacheNodeMax,
+ &dwReturnedCount
+ );
+
+ if (fError == FALSE)
+ {
+ dprintf("Could not read debuggee's process memory: CACHELIST \n");
+ dprintf("at address %x\n", pDO->m_pCOleCache->m_pCacheList);
+ dprintf("Last Error Code = %d (0x%x)\n", GetLastError(), GetLastError());
+
+ goto errRtn;
+ }
+
+ if (dwReturnedCount != (sizeof(CACHELIST_ITEM) * pDO->m_pCOleCache->m_uCacheNodeMax))
+ {
+ dprintf("Size of process memory read != requested(CACHELIST_ITEM\n");
+
+ goto errRtn;
+ }
+
+ pDO->m_pCOleCache->m_pCacheList = (LPCACHELIST) blockCACHELIST;
+ }
+
+ // need to copy the memory of the CCacheNode's in the CACHELIST
+ for (ui = 0; ui < pDO->m_pCOleCache->m_uCacheNodeMax; ui++)
+ {
+ if (pDO->m_pCOleCache->m_pCacheList[ui].lpCacheNode != NULL)
+ {
+ blockCacheNode = new char[sizeof(CCacheNode)];
+
+ fError = ReadProcessMemory(
+ hCurrentProcess,
+ pDO->m_pCOleCache->m_pCacheList[ui].lpCacheNode,
+ blockCacheNode,
+ sizeof(CCacheNode),
+ &dwReturnedCount
+ );
+
+ if (fError == FALSE)
+ {
+ dprintf("Could not read debuggee's process memory: CCacheNode \n");
+ dprintf("at address %x\n", pDO->m_pCOleCache->m_pCacheList[ui].lpCacheNode);
+ dprintf("Last Error Code = %d (0x%x)\n", GetLastError(), GetLastError());
+
+ goto errRtn;
+ }
+
+ if (dwReturnedCount != sizeof(CCacheNode))
+ {
+ dprintf("Size of process memory read != requested (CCacheNode)\n");
+
+ goto errRtn;
+ }
+
+ // pass off pointer
+ pDO->m_pCOleCache->m_pCacheList[ui].lpCacheNode = (CCacheNode*)blockCacheNode;
+ blockCacheNode = NULL;
+
+ // need to get the OlePresObjs for the CCacheNode
+ if (pDO->m_pCOleCache->m_pCacheList[ui].lpCacheNode->m_pPresObj != NULL)
+ {
+ switch (pDO->m_pCOleCache->m_pCacheList[ui].lpCacheNode->m_dwPresFlag)
+ {
+ case CN_PRESOBJ_GEN:
+ dwSizeOfPresObj = sizeof(CGenObject);
+ break;
+ case CN_PRESOBJ_MF:
+ dwSizeOfPresObj = sizeof(CMfObject);
+ break;
+ case CN_PRESOBJ_EMF:
+ dwSizeOfPresObj = sizeof(CEMfObject);
+ break;
+ default:
+ dprintf("Error: can not determine size of IOlePresObj\n");
+ return;
+ }
+
+ blockPresObj = new char[dwSizeOfPresObj];
+
+ fError = ReadProcessMemory(
+ hCurrentProcess,
+ pDO->m_pCOleCache->m_pCacheList[ui].lpCacheNode->m_pPresObj,
+ blockPresObj,
+ dwSizeOfPresObj,
+ &dwReturnedCount
+ );
+
+ if (fError == FALSE)
+ {
+ dprintf("Could not read debuggee's process memory: IOlePresObj \n");
+ dprintf("at address %x\n", pDO->m_pCOleCache->m_pCacheList[ui].lpCacheNode->m_pPresObj);
+ dprintf("Last Error Code = %d (0x%x)\n", GetLastError(), GetLastError());
+
+ goto errRtn;
+ }
+
+ if (dwReturnedCount != dwSizeOfPresObj)
+ {
+ dprintf("Size of process memory read != requested (IOlePresObj)\n");
+
+ goto errRtn;
+ }
+
+ // pass off pointer
+ pDO->m_pCOleCache->m_pCacheList[ui].lpCacheNode->m_pPresObj = (IOlePresObj *)blockPresObj;
+ blockPresObj = NULL;
+ }
+
+ if (pDO->m_pCOleCache->m_pCacheList[ui].lpCacheNode->m_pPresObjAfterFreeze != NULL)
+ {
+ switch (pDO->m_pCOleCache->m_pCacheList[ui].lpCacheNode->m_dwPresFlag)
+ {
+ case CN_PRESOBJ_GEN:
+ dwSizeOfPresObj = sizeof(CGenObject);
+ break;
+ case CN_PRESOBJ_MF:
+ dwSizeOfPresObj = sizeof(CMfObject);
+ break;
+ case CN_PRESOBJ_EMF:
+ dwSizeOfPresObj = sizeof(CEMfObject);
+ break;
+ default:
+ dprintf("Error: can not determine size of IOlePresObj\n");
+ return;
+ }
+
+ blockPresObj = new char[dwSizeOfPresObj];
+
+ fError = ReadProcessMemory(
+ hCurrentProcess,
+ pDO->m_pCOleCache->m_pCacheList[ui].lpCacheNode->m_pPresObjAfterFreeze,
+ blockPresObj,
+ dwSizeOfPresObj,
+ &dwReturnedCount
+ );
+
+ if (fError == FALSE)
+ {
+ dprintf("Could not read debuggee's process memory: IOlePresObj \n");
+ dprintf("at address %x\n", pDO->m_pCOleCache->m_pCacheList[ui].lpCacheNode->m_pPresObjAfterFreeze);
+ dprintf("Last Error Code = %d (0x%x)\n", GetLastError(), GetLastError());
+
+ goto errRtn;
+ }
+
+ if (dwReturnedCount != dwSizeOfPresObj)
+ {
+ dprintf("Size of process memory read != requested (IOlePresObj)\n");
+
+ goto errRtn;
+ }
+
+ // pass off pointer
+ pDO->m_pCOleCache->m_pCacheList[ui].lpCacheNode->m_pPresObjAfterFreeze = (IOlePresObj *)blockPresObj;
+ blockPresObj = NULL;
+ }
+ }
+ }
+ }
+
+ // dump the structure
+ pszDO = DumpCDefObject(pDO, NO_PREFIX, 1);
+
+ dprintf("CDefObject @ 0x%x\n", dwAddr);
+ dprintfx(pszDO);
+
+ CoTaskMemFree(pszDO);
+
+errRtn:
+
+ // delete the blocks and not the pointers
+ if ( (pDO != NULL)&&(blockCACHELIST != NULL)&&(blockCOleCache != NULL) )
+ {
+ for (ui = 0; ui < pDO->m_pCOleCache->m_uCacheNodeMax; ui++)
+ {
+ if (pDO->m_pCOleCache->m_pCacheList[ui].lpCacheNode != NULL)
+ {
+ delete[] ((char *)pDO->m_pCOleCache->m_pCacheList[ui].lpCacheNode->m_pPresObj);
+ delete[] ((char *)pDO->m_pCOleCache->m_pCacheList[ui].lpCacheNode->m_pPresObjAfterFreeze);
+ delete[] ((char *)pDO->m_pCOleCache->m_pCacheList[ui].lpCacheNode);
+ }
+ }
+ }
+ delete[] blockCACHELIST;
+ delete[] blockCOleCache;
+ delete[] blockDAHolder;
+ delete[] blockSTATDATA;
+ delete[] blockDataAdvCache;
+ delete[] blockpIAS;
+ delete[] blockOAHolder;
+ delete[] blockDefObject;
+
+ return;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: dump_emfobject, exported
+//
+// Synopsis: dumps CEMfObject object
+//
+// Effects:
+//
+// Arguments: see DECLARE_API in oleexts.h
+//
+// Requires:
+//
+// Returns: void
+//
+// Signals:
+//
+// Modifies: ExtensionApis (global)
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 02-Feb-95 t-ScottH author
+//
+// Notes:
+// The address of the object is passed in the arguments. This
+// address is in the debuggee's process memory. In order for
+// NTSD to view this memory, the debugger must copy the mem
+// using the WIN32 ReadProcessMemory API.
+//
+//--------------------------------------------------------------------------
+
+DECLARE_API(dump_emfobject)
+{
+ BOOL fError;
+ LPVOID dwAddr;
+ DWORD dwReturnedCount;
+ char *pszEMfObject;
+ char *blockEMfObject = NULL;
+ CEMfObject *pEMfObject = NULL;
+
+ // set up global function pointers
+ ExtensionApis = *lpExtensionApis;
+
+ // get address of object from argument string
+ dwAddr = (LPVOID)GetExpression( args );
+ if (dwAddr == 0)
+ {
+ dprintf("Failed to get Address of CEMfObject\n");
+ return;
+ }
+
+ // read the block of memory from the debugee's process
+ blockEMfObject = new char[sizeof(CEMfObject)];
+
+ fError = ReadProcessMemory(
+ hCurrentProcess,
+ dwAddr,
+ blockEMfObject,
+ sizeof(CEMfObject),
+ &dwReturnedCount
+ );
+
+ if (fError == FALSE)
+ {
+ dprintf("Could not read debuggee's process memory EMfObject");
+ dprintf("at address %x\n", dwAddr);
+ dprintf("Last Error Code = %d (%x)\n", GetLastError(), GetLastError());
+
+ goto errRtn;
+ }
+
+ if (dwReturnedCount != sizeof(CEMfObject))
+ {
+ dprintf("Size of process memory read != requested\n");
+
+ goto errRtn;
+ }
+
+ pEMfObject = (CEMfObject *)blockEMfObject;
+
+ // dump the structure
+ pszEMfObject = DumpCEMfObject(pEMfObject, NO_PREFIX, 1);
+
+ dprintf("CEMfObject @ 0x%x\n", dwAddr);
+ dprintfx(pszEMfObject);
+
+ CoTaskMemFree(pszEMfObject);
+
+errRtn:
+
+ delete[] blockEMfObject;
+
+ return;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: dump_enumfmt, exported
+//
+// Synopsis: dumps CEnumFmt object
+//
+// Effects:
+//
+// Arguments: see DECLARE_API in oleexts.h
+//
+// Requires:
+//
+// Returns: void
+//
+// Signals:
+//
+// Modifies: ExtensionApis (global)
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 02-Feb-95 t-ScottH author
+//
+// Notes:
+// The address of the object is passed in the arguments. This
+// address is in the debuggee's process memory. In order for
+// NTSD to view this memory, the debugger must copy the mem
+// using the WIN32 ReadProcessMemory API.
+//
+//--------------------------------------------------------------------------
+
+DECLARE_API(dump_enumfmt)
+{
+ // set up global function pointers
+ ExtensionApis = *lpExtensionApis;
+
+ dprintf("dump_enumfmt not implemented\n");
+
+ return;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: dump_enumfmt10, exported
+//
+// Synopsis: dumps CEnumFmt10 object
+//
+// Effects:
+//
+// Arguments: see DECLARE_API in oleexts.h
+//
+// Requires:
+//
+// Returns: void
+//
+// Signals:
+//
+// Modifies: ExtensionApis (global)
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 02-Feb-95 t-ScottH author
+//
+// Notes:
+// The address of the object is passed in the arguments. This
+// address is in the debuggee's process memory. In order for
+// NTSD to view this memory, the debugger must copy the mem
+// using the WIN32 ReadProcessMemory API.
+//
+//--------------------------------------------------------------------------
+
+DECLARE_API(dump_enumfmt10)
+{
+ // set up global function pointers
+ ExtensionApis = *lpExtensionApis;
+
+ dprintf("dump_enumfmt10 not implemented\n");
+
+ return;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: dump_enumstatdata, exported
+//
+// Synopsis: dumps CEnumSTATDATA object
+//
+// Effects:
+//
+// Arguments: see DECLARE_API in oleexts.h
+//
+// Requires:
+//
+// Returns: void
+//
+// Signals:
+//
+// Modifies: ExtensionApis (global)
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 02-Feb-95 t-ScottH author
+//
+// Notes:
+// The address of the object is passed in the arguments. This
+// address is in the debuggee's process memory. In order for
+// NTSD to view this memory, the debugger must copy the mem
+// using the WIN32 ReadProcessMemory API.
+//
+//--------------------------------------------------------------------------
+
+DECLARE_API(dump_enumstatdata)
+{
+ DWORD dwReturnedCount;
+ BOOL fError;
+ LPVOID dwAddr;
+ char *pszESD;
+ char *blockEnumStatData = NULL;
+ char *blockDAH = NULL;
+ char *blockStatDataArray = NULL;
+ CEnumSTATDATA *pESD = NULL;
+
+ // set up global function pointers
+ ExtensionApis = *lpExtensionApis;
+
+ // get address of object from argument string
+ dwAddr = (LPVOID)GetExpression( args );
+ if (dwAddr == 0)
+ {
+ dprintf("Failed to get Address of CEnumSTATDATA\n");
+ return;
+ }
+
+ // read the mem for the CEnumSTATDATA
+ blockEnumStatData = new char[sizeof(CEnumSTATDATA)];
+
+ fError = ReadProcessMemory(
+ hCurrentProcess,
+ dwAddr,
+ blockEnumStatData,
+ sizeof(CEnumSTATDATA),
+ &dwReturnedCount
+ );
+
+ if (fError == FALSE)
+ {
+ dprintf("Could not read debuggee's process memory: CEnumSTATDATA \n");
+ dprintf("at address %x\n", dwAddr);
+ dprintf("Last Error Code = %d (0x%x)\n", GetLastError(), GetLastError());
+
+ goto errRtn;
+ }
+
+ if (dwReturnedCount != sizeof(CEnumSTATDATA))
+ {
+ dprintf("Size of process memory read != requested (CEnumSTATDATA)\n");
+
+ goto errRtn;
+ }
+
+ pESD = (CEnumSTATDATA *)blockEnumStatData;
+
+ // read the block of memory for the CDAHolder
+ if (pESD->m_pHolder != NULL)
+ {
+ blockDAH = new char[sizeof(CDAHolder)];
+
+ fError = ReadProcessMemory(
+ hCurrentProcess,
+ pESD->m_pHolder,
+ blockDAH,
+ sizeof(CDAHolder),
+ &dwReturnedCount
+ );
+
+ if (fError == FALSE)
+ {
+ dprintf("Could not read debuggee's process memory: CDAHolder \n");
+ dprintf("at address %x\n", pESD->m_pHolder);
+ dprintf("Last Error Code = %d (0x%x)\n", GetLastError(), GetLastError());
+
+ goto errRtn;
+ }
+
+ if (dwReturnedCount != sizeof(CDAHolder))
+ {
+ dprintf("Size of process memory read != requested (CDAHolder)\n");
+
+ goto errRtn;
+ }
+
+ pESD->m_pHolder = (CDAHolder *)blockDAH;
+
+ // read the block of mem for the STATDATA array
+ if (pESD->m_pHolder->m_pSD != NULL)
+ {
+ blockStatDataArray = new char[sizeof(STATDATA) * pESD->m_pHolder->m_iSize];
+
+ fError = ReadProcessMemory(
+ hCurrentProcess,
+ pESD->m_pHolder->m_pSD,
+ blockStatDataArray,
+ sizeof(STATDATA) * pESD->m_pHolder->m_iSize,
+ &dwReturnedCount
+ );
+
+ if (fError == FALSE)
+ {
+ dprintf("Could not read debuggee's process memory: STATDATA array \n");
+ dprintf("at address %x\n", pESD->m_pHolder->m_pSD);
+ dprintf("Last Error Code = %d (0x%x)\n", GetLastError(), GetLastError());
+
+ goto errRtn;
+ }
+
+ if (dwReturnedCount != (sizeof(STATDATA) * pESD->m_pHolder->m_iSize))
+ {
+ dprintf("Size of process memory read != requested (STATDATA array)\n");
+
+ goto errRtn;
+ }
+
+ pESD->m_pHolder->m_pSD = (STATDATA *)blockStatDataArray;
+ }
+ }
+
+ // dump the structure
+ pszESD = DumpCEnumSTATDATA(pESD, NO_PREFIX, 1);
+
+ dprintf("CEnumSTATDATA @ 0x%x\n", dwAddr);
+ dprintfx(pszESD);
+
+ CoTaskMemFree(pszESD);
+
+errRtn:
+
+ delete[] blockEnumStatData;
+ delete[] blockDAH;
+ delete[] blockStatDataArray;
+
+ return;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: dump_enumverb, exported
+//
+// Synopsis: dumps CEnumVerb object
+//
+// Effects:
+//
+// Arguments: see DECLARE_API in oleexts.h
+//
+// Requires:
+//
+// Returns: void
+//
+// Signals:
+//
+// Modifies: ExtensionApis (global)
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 02-Feb-95 t-ScottH author
+//
+// Notes:
+// The address of the object is passed in the arguments. This
+// address is in the debuggee's process memory. In order for
+// NTSD to view this memory, the debugger must copy the mem
+// using the WIN32 ReadProcessMemory API.
+//
+//--------------------------------------------------------------------------
+
+DECLARE_API(dump_enumverb)
+{
+ // set up global function pointers
+ ExtensionApis = *lpExtensionApis;
+
+ dprintf("dump_enumverb not implemented\n");
+
+ return;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: dump_genobject, exported
+//
+// Synopsis: dumps CGenObject object
+//
+// Effects:
+//
+// Arguments: see DECLARE_API in oleexts.h
+//
+// Requires:
+//
+// Returns: void
+//
+// Signals:
+//
+// Modifies: ExtensionApis (global)
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 02-Feb-95 t-ScottH author
+//
+// Notes:
+// The address of the object is passed in the arguments. This
+// address is in the debuggee's process memory. In order for
+// NTSD to view this memory, the debugger must copy the mem
+// using the WIN32 ReadProcessMemory API.
+//
+//--------------------------------------------------------------------------
+
+DECLARE_API(dump_genobject)
+{
+ BOOL fError;
+ LPVOID dwAddr;
+ DWORD dwReturnedCount;
+ char *pszGenObject;
+ char *blockGenObject = NULL;
+ CGenObject *pGenObject = NULL;
+
+ // set up global function pointers
+ ExtensionApis = *lpExtensionApis;
+
+ // get address of object from argument string
+ dwAddr = (LPVOID)GetExpression( args );
+ if (dwAddr == 0)
+ {
+ dprintf("Failed to get Address of CGenObject\n");
+ return;
+ }
+
+ // read the block of memory from the debugee's process
+ blockGenObject = new char[sizeof(CGenObject)];
+
+ fError = ReadProcessMemory(
+ hCurrentProcess,
+ dwAddr,
+ blockGenObject,
+ sizeof(CGenObject),
+ &dwReturnedCount
+ );
+
+ if (fError == FALSE)
+ {
+ dprintf("Could not read debuggee's process memory GenObject");
+ dprintf("at address %x\n", dwAddr);
+ dprintf("Last Error Code = %d (%x)\n", GetLastError(), GetLastError());
+
+ goto errRtn;
+ }
+
+ if (dwReturnedCount != sizeof(CGenObject))
+ {
+ dprintf("Size of process memory read != requested\n");
+
+ goto errRtn;
+ }
+
+ pGenObject = (CGenObject *)blockGenObject;
+
+ // dump the structure
+ pszGenObject = DumpCGenObject(pGenObject, NO_PREFIX, 1);
+
+ dprintf("CGenObject @ 0x%x\n", dwAddr);
+ dprintfx(pszGenObject);
+
+ CoTaskMemFree(pszGenObject);
+
+errRtn:
+
+ delete[] blockGenObject;
+
+ return;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: dump_membytes, exported
+//
+// Synopsis: dumps CMemBytes object
+//
+// Effects:
+//
+// Arguments: see DECLARE_API in oleexts.h
+//
+// Requires:
+//
+// Returns: void
+//
+// Signals:
+//
+// Modifies: ExtensionApis (global)
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 02-Feb-95 t-ScottH author
+//
+// Notes:
+// The address of the object is passed in the arguments. This
+// address is in the debuggee's process memory. In order for
+// NTSD to view this memory, the debugger must copy the mem
+// using the WIN32 ReadProcessMemory API.
+//
+//--------------------------------------------------------------------------
+
+DECLARE_API(dump_membytes)
+{
+ BOOL fError;
+ LPVOID dwAddr;
+ DWORD dwReturnedCount;
+ char *pszMB;
+ char *blockMB = NULL;
+ CMemBytes *pMB = NULL;
+ char *blockMEMSTM = NULL;
+
+ // set up global function pointers
+ ExtensionApis = *lpExtensionApis;
+
+ // get address of object from argument string
+ dwAddr = (LPVOID)GetExpression( args );
+ if (dwAddr == 0)
+ {
+ dprintf("Failed to get Address of CMemBytes\n");
+ return;
+ }
+
+ // read the block of memory from the debugee's process
+ blockMB = new char[sizeof(CMemBytes)];
+
+ fError = ReadProcessMemory(
+ hCurrentProcess,
+ dwAddr,
+ blockMB,
+ sizeof(CMemBytes),
+ &dwReturnedCount
+ );
+
+ if (fError == FALSE)
+ {
+ dprintf("Could not read debuggee's process memory: CMemBytes \n");
+ dprintf("at address %x\n", dwAddr);
+ dprintf("Last Error Code = %d (0x%x)\n", GetLastError(), GetLastError());
+
+ goto errRtn;
+ }
+
+ if (dwReturnedCount != sizeof(CMemBytes))
+ {
+ dprintf("Size of process memory read != requested(CMemBytes)\n");
+
+ goto errRtn;
+ }
+
+ pMB = (CMemBytes *)blockMB;
+
+ // copy the MEMSTM structure
+ if (pMB->m_pData != NULL)
+ {
+ blockMEMSTM = new char[sizeof(MEMSTM)];
+
+ fError = ReadProcessMemory(
+ hCurrentProcess,
+ pMB->m_pData,
+ blockMEMSTM,
+ sizeof(MEMSTM),
+ &dwReturnedCount
+ );
+
+ if (fError == FALSE)
+ {
+ dprintf("Could not read debuggee's process memory: MEMSTM \n");
+ dprintf("at address %x\n", pMB->m_pData);
+ dprintf("Last Error Code = %d (0x%x)\n", GetLastError(), GetLastError());
+
+ goto errRtn;
+ }
+
+ if (dwReturnedCount != sizeof(MEMSTM))
+ {
+ dprintf("Size of process memory read != requested(MEMSTM)\n");
+
+ goto errRtn;
+ }
+
+ pMB->m_pData = (MEMSTM *)blockMEMSTM;
+ }
+
+ // dump the structure
+ pszMB = DumpCMemBytes(pMB, NO_PREFIX, 1);
+
+ dprintf("CMemBytes @ 0x%x\n", dwAddr);
+ dprintfx(pszMB);
+
+ CoTaskMemFree(pszMB);
+
+errRtn:
+
+ // delete the blocks and not the pointers
+ delete[] blockMB;
+ delete[] blockMEMSTM;
+
+ return;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: dump_cmemstm, exported
+//
+// Synopsis: dumps CMemStm object
+//
+// Effects:
+//
+// Arguments: see DECLARE_API in oleexts.h
+//
+// Requires:
+//
+// Returns: void
+//
+// Signals:
+//
+// Modifies: ExtensionApis (global)
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 02-Feb-95 t-ScottH author
+//
+// Notes:
+// The address of the object is passed in the arguments. This
+// address is in the debuggee's process memory. In order for
+// NTSD to view this memory, the debugger must copy the mem
+// using the WIN32 ReadProcessMemory API.
+//
+//--------------------------------------------------------------------------
+
+DECLARE_API(dump_cmemstm)
+{
+ BOOL fError;
+ LPVOID dwAddr;
+ DWORD dwReturnedCount;
+ char *pszMS;
+ char *blockMS = NULL;
+ CMemStm *pMS = NULL;
+ char *blockMEMSTM = NULL;
+
+ // set up global function pointers
+ ExtensionApis = *lpExtensionApis;
+
+ // get address of object from argument string
+ dwAddr = (LPVOID)GetExpression( args );
+ if (dwAddr == 0)
+ {
+ dprintf("Failed to get Address of CMemStm\n");
+ return;
+ }
+
+ // read the block of memory from the debugee's process
+ blockMS = new char[sizeof(CMemStm)];
+
+ fError = ReadProcessMemory(
+ hCurrentProcess,
+ dwAddr,
+ blockMS,
+ sizeof(CMemStm),
+ &dwReturnedCount
+ );
+
+ if (fError == FALSE)
+ {
+ dprintf("Could not read debuggee's process memory: CMemStm \n");
+ dprintf("at address %x\n", dwAddr);
+ dprintf("Last Error Code = %d (0x%x)\n", GetLastError(), GetLastError());
+
+ goto errRtn;
+ }
+
+ if (dwReturnedCount != sizeof(CMemStm))
+ {
+ dprintf("Size of process memory read != requested(CMemStm)\n");
+
+ goto errRtn;
+ }
+
+ pMS = (CMemStm *)blockMS;
+
+ // copy the MEMSTM structure
+ if (pMS->m_pData != NULL)
+ {
+ blockMEMSTM = new char[sizeof(MEMSTM)];
+
+ fError = ReadProcessMemory(
+ hCurrentProcess,
+ pMS->m_pData,
+ blockMEMSTM,
+ sizeof(MEMSTM),
+ &dwReturnedCount
+ );
+
+ if (fError == FALSE)
+ {
+ dprintf("Could not read debuggee's process memory: MEMSTM \n");
+ dprintf("at address %x\n", pMS->m_pData);
+ dprintf("Last Error Code = %d (0x%x)\n", GetLastError(), GetLastError());
+
+ goto errRtn;
+ }
+
+ if (dwReturnedCount != sizeof(MEMSTM))
+ {
+ dprintf("Size of process memory read != requested(MEMSTM)\n");
+
+ goto errRtn;
+ }
+
+ pMS->m_pData = (MEMSTM *)blockMEMSTM;
+ }
+
+ // dump the structure
+ pszMS = DumpCMemStm(pMS, NO_PREFIX, 1);
+
+ dprintf("CMemStm @ 0x%x\n", dwAddr);
+ dprintfx(pszMS);
+
+ CoTaskMemFree(pszMS);
+
+errRtn:
+
+ // delete the blocks and not the pointers
+ delete[] blockMS;
+ delete[] blockMEMSTM;
+
+ return;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: dump_mfobject, exported
+//
+// Synopsis: dumps CMfObject object
+//
+// Effects:
+//
+// Arguments: see DECLARE_API in oleexts.h
+//
+// Requires:
+//
+// Returns: void
+//
+// Signals:
+//
+// Modifies: ExtensionApis (global)
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 02-Feb-95 t-ScottH author
+//
+// Notes:
+// The address of the object is passed in the arguments. This
+// address is in the debuggee's process memory. In order for
+// NTSD to view this memory, the debugger must copy the mem
+// using the WIN32 ReadProcessMemory API.
+//
+//--------------------------------------------------------------------------
+
+DECLARE_API(dump_mfobject)
+{
+ BOOL fError;
+ LPVOID dwAddr;
+ DWORD dwReturnedCount;
+ char *pszMfObject;
+ char *blockMfObject = NULL;
+ CMfObject *pMfObject = NULL;
+
+ // set up global function pointers
+ ExtensionApis = *lpExtensionApis;
+
+ // get address of object from argument string
+ dwAddr = (LPVOID)GetExpression( args );
+ if (dwAddr == 0)
+ {
+ dprintf("Failed to get Address of CMfObject\n");
+ return;
+ }
+
+ // read the block of memory from the debugee's process
+ blockMfObject = new char[sizeof(CMfObject)];
+
+ fError = ReadProcessMemory(
+ hCurrentProcess,
+ dwAddr,
+ blockMfObject,
+ sizeof(CMfObject),
+ &dwReturnedCount
+ );
+
+ if (fError == FALSE)
+ {
+ dprintf("Could not read debuggee's process memory MfObject");
+ dprintf("at address %x\n", dwAddr);
+ dprintf("Last Error Code = %d (%x)\n", GetLastError(), GetLastError());
+
+ goto errRtn;
+ }
+
+ if (dwReturnedCount != sizeof(CMfObject))
+ {
+ dprintf("Size of process memory read != requested\n");
+
+ goto errRtn;
+ }
+
+ pMfObject = (CMfObject *)blockMfObject;
+
+ // dump the structure
+ pszMfObject = DumpCMfObject(pMfObject, NO_PREFIX, 1);
+
+ dprintf("CMfObject @ 0x%x\n", dwAddr);
+ dprintfx(pszMfObject);
+
+ CoTaskMemFree(pszMfObject);
+
+errRtn:
+
+ delete[] blockMfObject;
+
+ return;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: dump_oaholder, exported
+//
+// Synopsis: dumps COAHolder object
+//
+// Effects:
+//
+// Arguments: see DECLARE_API in oleexts.h
+//
+// Requires:
+//
+// Returns: void
+//
+// Signals:
+//
+// Modifies: ExtensionApis (global)
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 02-Feb-95 t-ScottH author
+//
+// Notes:
+// The address of the object is passed in the arguments. This
+// address is in the debuggee's process memory. In order for
+// NTSD to view this memory, the debugger must copy the mem
+// using the WIN32 ReadProcessMemory API.
+//
+//--------------------------------------------------------------------------
+
+DECLARE_API(dump_oaholder)
+{
+ BOOL fError;
+ LPVOID dwAddr;
+ DWORD dwReturnedCount;
+ char *pszOAH;
+ char *blockOAH = NULL;
+ char *blockpIAS = NULL;
+ COAHolder *pOAH = NULL;
+
+ // set up global function pointers
+ ExtensionApis = *lpExtensionApis;
+
+ // get address of object from argument string
+ dwAddr = (LPVOID)GetExpression( args );
+ if (dwAddr == 0)
+ {
+ dprintf("Failed to get Address of COAHolder\n");
+ return;
+ }
+
+ // read the block of memory from the debugee's process
+ blockOAH = new char[sizeof(COAHolder)];
+
+ fError = ReadProcessMemory(
+ hCurrentProcess,
+ dwAddr,
+ blockOAH,
+ sizeof(COAHolder),
+ &dwReturnedCount
+ );
+
+ if (fError == FALSE)
+ {
+ dprintf("Could not read debuggee's process memory: COAHolder \n");
+ dprintf("at address %x\n", dwAddr);
+ dprintf("Last Error Code = %d (0x%x)\n", GetLastError(), GetLastError());
+
+ goto errRtn;
+ }
+
+ if (dwReturnedCount != sizeof(COAHolder))
+ {
+ dprintf("Size of process memory read != requested\n");
+
+ goto errRtn;
+ }
+
+ pOAH = (COAHolder *)blockOAH;
+
+ // need to copy the array of IAdviseSink pointers
+ if (pOAH->m_iSize > 0)
+ {
+ blockpIAS = new char[pOAH->m_iSize * sizeof(IAdviseSink *)];
+
+ fError = ReadProcessMemory(
+ hCurrentProcess,
+ pOAH->m_ppIAS,
+ blockpIAS,
+ sizeof(IAdviseSink *) * pOAH->m_iSize,
+ &dwReturnedCount
+ );
+
+ if (fError == FALSE)
+ {
+ dprintf("Could not read debuggee's process memory: IAdviseSink Array \n");
+ dprintf("at address %x\n", pOAH->m_ppIAS);
+ dprintf("Last Error Code = %d (0x%x)\n", GetLastError(), GetLastError());
+
+ goto errRtn;
+ }
+
+ if (dwReturnedCount != (sizeof(IAdviseSink *) * pOAH->m_iSize))
+ {
+ dprintf("Size of process memory read != requested\n");
+
+ goto errRtn;
+ }
+
+ pOAH->m_ppIAS = (IAdviseSink **)blockpIAS;
+ }
+
+ // dump the structure
+ pszOAH = DumpCOAHolder(pOAH, NO_PREFIX, 1);
+
+ dprintf("COAHolder @ 0x%x\n", dwAddr);
+ dprintfx(pszOAH);
+
+ CoTaskMemFree(pszOAH);
+
+errRtn:
+
+ // delete the blocks and not the pointers
+ delete[] blockOAH;
+ delete[] blockpIAS;
+
+ return;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: dump_olecache, exported
+//
+// Synopsis: dumps COleCache object
+//
+// Effects:
+//
+// Arguments: see DECLARE_API in oleexts.h
+//
+// Requires:
+//
+// Returns: void
+//
+// Signals:
+//
+// Modifies: ExtensionApis (global)
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 02-Feb-95 t-ScottH author
+//
+// Notes:
+// The address of the object is passed in the arguments. This
+// address is in the debuggee's process memory. In order for
+// NTSD to view this memory, the debugger must copy the mem
+// using the WIN32 ReadProcessMemory API.
+//
+//--------------------------------------------------------------------------
+
+DECLARE_API(dump_olecache)
+{
+ unsigned int ui;
+ BOOL fError;
+ LPVOID dwAddr;
+ DWORD dwReturnedCount;
+ char *pszOC;
+ char *blockOC = NULL;
+ COleCache *pOC = NULL;
+ char *blockCCacheEnum = NULL;
+ char *blockCACHELIST = NULL;
+ char *blockCacheNode = NULL;
+ char *blockPresObj = NULL;
+ DWORD dwSizeOfPresObj;
+
+ // set up global function pointers
+ ExtensionApis = *lpExtensionApis;
+
+ // get address of object from argument string
+ dwAddr = (LPVOID)GetExpression( args );
+ if (dwAddr == 0)
+ {
+ dprintf("Failed to get Address of COleCache\n");
+ return;
+ }
+
+ // read the block of memory from the debugee's process
+ blockOC = new char[sizeof(COleCache)];
+
+ fError = ReadProcessMemory(
+ hCurrentProcess,
+ dwAddr,
+ blockOC,
+ sizeof(COleCache),
+ &dwReturnedCount
+ );
+
+ if (fError == FALSE)
+ {
+ dprintf("Could not read debuggee's process memory: COleCache \n");
+ dprintf("at address %x\n", dwAddr);
+ dprintf("Last Error Code = %d (0x%x)\n", GetLastError(), GetLastError());
+
+ goto errRtn;
+ }
+
+ if (dwReturnedCount != sizeof(COleCache))
+ {
+ dprintf("Size of process memory read != requested (COleCache)\n");
+
+ goto errRtn;
+ }
+
+ pOC = (COleCache *)blockOC;
+
+ // get block of mem for CCacheEnum (only if m_pCacheEnum != NULL)
+ if (pOC->m_pCacheEnum != NULL)
+ {
+ blockCCacheEnum = new char[sizeof(CCacheEnum)];
+
+ fError = ReadProcessMemory(
+ hCurrentProcess,
+ pOC->m_pCacheEnum,
+ blockCCacheEnum,
+ sizeof(CCacheEnum),
+ &dwReturnedCount
+ );
+
+ if (fError == FALSE)
+ {
+ dprintf("Could not read debuggee's process memory: CCacheEnum \n");
+ dprintf("at address %x\n", pOC->m_pCacheEnum);
+ dprintf("Last Error Code = %d (0x%x)\n", GetLastError(), GetLastError());
+
+ goto errRtn;
+ }
+
+ if (dwReturnedCount != sizeof(CCacheEnum))
+ {
+ dprintf("Size of process memory read != requested (CCacheEnum)\n");
+
+ goto errRtn;
+ }
+
+ pOC->m_pCacheEnum = (CCacheEnum *)blockCCacheEnum;
+ }
+
+ // get block of mem for CACHELIST
+ if (pOC->m_pCacheList != NULL)
+ {
+ blockCACHELIST = new char[sizeof(CACHELIST_ITEM) * pOC->m_uCacheNodeMax];
+
+ fError = ReadProcessMemory(
+ hCurrentProcess,
+ pOC->m_pCacheList,
+ blockCACHELIST,
+ sizeof(CACHELIST_ITEM) * pOC->m_uCacheNodeMax,
+ &dwReturnedCount
+ );
+
+ if (fError == FALSE)
+ {
+ dprintf("Could not read debuggee's process memory: CACHELIST \n");
+ dprintf("at address %x\n", pOC->m_pCacheList);
+ dprintf("Last Error Code = %d (0x%x)\n", GetLastError(), GetLastError());
+
+ goto errRtn;
+ }
+
+ if (dwReturnedCount != (sizeof(CACHELIST_ITEM) * pOC->m_uCacheNodeMax))
+ {
+ dprintf("Size of process memory read != requested\n");
+
+ goto errRtn;
+ }
+
+ pOC->m_pCacheList = (LPCACHELIST) blockCACHELIST;
+ }
+
+ // need to copy the memory of the CCacheNode's in the CACHELIST
+ for (ui = 0; ui < pOC->m_uCacheNodeMax; ui++)
+ {
+ if (pOC->m_pCacheList[ui].lpCacheNode != NULL)
+ {
+ blockCacheNode = new char[sizeof(CCacheNode)];
+
+ fError = ReadProcessMemory(
+ hCurrentProcess,
+ pOC->m_pCacheList[ui].lpCacheNode,
+ blockCacheNode,
+ sizeof(CCacheNode),
+ &dwReturnedCount
+ );
+
+ if (fError == FALSE)
+ {
+ dprintf("Could not read debuggee's process memory: CCacheNode \n");
+ dprintf("at address %x\n", pOC->m_pCacheList[ui].lpCacheNode);
+ dprintf("Last Error Code = %d (0x%x)\n", GetLastError(), GetLastError());
+
+ goto errRtn;
+ }
+
+ if (dwReturnedCount != sizeof(CCacheNode))
+ {
+ dprintf("Size of process memory read != requested (CCacheNode)\n");
+
+ goto errRtn;
+ }
+
+ // pass off pointer
+ pOC->m_pCacheList[ui].lpCacheNode = (CCacheNode*)blockCacheNode;
+ blockCacheNode = NULL;
+
+ // need to get the OlePresObjs for the CCacheNode
+ if (pOC->m_pCacheList[ui].lpCacheNode->m_pPresObj != NULL)
+ {
+ switch (pOC->m_pCacheList[ui].lpCacheNode->m_dwPresFlag)
+ {
+ case CN_PRESOBJ_GEN:
+ dwSizeOfPresObj = sizeof(CGenObject);
+ break;
+ case CN_PRESOBJ_MF:
+ dwSizeOfPresObj = sizeof(CMfObject);
+ break;
+ case CN_PRESOBJ_EMF:
+ dwSizeOfPresObj = sizeof(CEMfObject);
+ break;
+ default:
+ dprintf("Error: can not determine size of IOlePresObj\n");
+ return;
+ }
+
+ blockPresObj = new char[dwSizeOfPresObj];
+
+ fError = ReadProcessMemory(
+ hCurrentProcess,
+ pOC->m_pCacheList[ui].lpCacheNode->m_pPresObj,
+ blockPresObj,
+ dwSizeOfPresObj,
+ &dwReturnedCount
+ );
+
+ if (fError == FALSE)
+ {
+ dprintf("Could not read debuggee's process memory: IOlePresObj \n");
+ dprintf("at address %x\n", pOC->m_pCacheList[ui].lpCacheNode->m_pPresObj);
+ dprintf("Last Error Code = %d (0x%x)\n", GetLastError(), GetLastError());
+
+ goto errRtn;
+ }
+
+ if (dwReturnedCount != dwSizeOfPresObj)
+ {
+ dprintf("Size of process memory read != requested (IOlePresObj)\n");
+
+ goto errRtn;
+ }
+
+ // pass off pointer
+ pOC->m_pCacheList[ui].lpCacheNode->m_pPresObj = (IOlePresObj *)blockPresObj;
+ blockPresObj = NULL;
+ }
+
+ if (pOC->m_pCacheList[ui].lpCacheNode->m_pPresObjAfterFreeze != NULL)
+ {
+ switch (pOC->m_pCacheList[ui].lpCacheNode->m_dwPresFlag)
+ {
+ case CN_PRESOBJ_GEN:
+ dwSizeOfPresObj = sizeof(CGenObject);
+ break;
+ case CN_PRESOBJ_MF:
+ dwSizeOfPresObj = sizeof(CMfObject);
+ break;
+ case CN_PRESOBJ_EMF:
+ dwSizeOfPresObj = sizeof(CEMfObject);
+ break;
+ default:
+ dprintf("Error: can not determine size of IOlePresObj\n");
+ return;
+ }
+
+ blockPresObj = new char[dwSizeOfPresObj];
+
+ fError = ReadProcessMemory(
+ hCurrentProcess,
+ pOC->m_pCacheList[ui].lpCacheNode->m_pPresObjAfterFreeze,
+ blockPresObj,
+ dwSizeOfPresObj,
+ &dwReturnedCount
+ );
+
+ if (fError == FALSE)
+ {
+ dprintf("Could not read debuggee's process memory: IOlePresObj \n");
+ dprintf("at address %x\n", pOC->m_pCacheList[ui].lpCacheNode->m_pPresObjAfterFreeze);
+ dprintf("Last Error Code = %d (0x%x)\n", GetLastError(), GetLastError());
+
+ goto errRtn;
+ }
+
+ if (dwReturnedCount != dwSizeOfPresObj)
+ {
+ dprintf("Size of process memory read != requested (IOlePresObj)\n");
+
+ goto errRtn;
+ }
+
+ // pass off pointer
+ pOC->m_pCacheList[ui].lpCacheNode->m_pPresObjAfterFreeze = (IOlePresObj *)blockPresObj;
+ blockPresObj = NULL;
+ }
+ }
+ }
+
+ // dump the structure
+ pszOC = DumpCOleCache(pOC, NO_PREFIX, 1);
+
+ dprintf("COleCache @ 0x%x\n", dwAddr);
+ dprintfx(pszOC);
+
+ CoTaskMemFree(pszOC);
+
+errRtn:
+
+ // delete the blocks and not the pointers
+ if ( (pOC != NULL) && (blockCACHELIST != NULL))
+ {
+ for (ui = 0; ui < pOC->m_uCacheNodeMax; ui++)
+ {
+ if (pOC->m_pCacheList[ui].lpCacheNode != NULL)
+ {
+ delete[] ((char *)pOC->m_pCacheList[ui].lpCacheNode->m_pPresObj);
+ delete[] ((char *)pOC->m_pCacheList[ui].lpCacheNode->m_pPresObjAfterFreeze);
+ delete[] ((char *)pOC->m_pCacheList[ui].lpCacheNode);
+ }
+ }
+ }
+ delete[] blockCACHELIST;
+ delete[] blockCCacheEnum;
+ delete[] blockOC;
+
+ return;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: dump_saferefcount, exported
+//
+// Synopsis: dumps CSafeRefCount object
+//
+// Effects:
+//
+// Arguments: see DECLARE_API in oleexts.h
+//
+// Requires:
+//
+// Returns: void
+//
+// Signals:
+//
+// Modifies: ExtensionApis (global)
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 02-Feb-95 t-ScottH author
+//
+// Notes:
+// The address of the object is passed in the arguments. This
+// address is in the debuggee's process memory. In order for
+// NTSD to view this memory, the debugger must copy the mem
+// using the WIN32 ReadProcessMemory API.
+//
+//--------------------------------------------------------------------------
+
+DECLARE_API( dump_saferefcount )
+{
+ BOOL fError;
+ LPVOID dwAddr;
+ DWORD dwReturnedCount;
+ char *pszSRC;
+ char *blockSRC = NULL;
+ CSafeRefCount *pSRC = NULL;
+
+ // set up global function pointers
+ ExtensionApis = *lpExtensionApis;
+
+ // get address of object from argument string
+ dwAddr = (LPVOID)GetExpression( args );
+ if (dwAddr == 0)
+ {
+ dprintf("Failed to get Address of CSafeRefCount\n");
+ return;
+ }
+
+ // read the block of memory from the debugee's process
+ blockSRC = new char[sizeof(CSafeRefCount)];
+
+ fError = ReadProcessMemory(
+ hCurrentProcess,
+ dwAddr,
+ blockSRC,
+ sizeof(CSafeRefCount),
+ &dwReturnedCount
+ );
+
+ if (fError == FALSE)
+ {
+ dprintf("Could not read debuggee's process memory \n");
+ dprintf("at address %x\n", dwAddr);
+ dprintf("Last Error Code = %d (%x)\n", GetLastError(), GetLastError());
+
+ goto errRtn;
+ }
+
+ if (dwReturnedCount != sizeof(CSafeRefCount))
+ {
+ dprintf("Size of process memory read != requested\n");
+
+ goto errRtn;
+ }
+
+ pSRC = (CSafeRefCount *)blockSRC;
+
+ // dump the structure
+ pszSRC = DumpCSafeRefCount(pSRC, NO_PREFIX, 1);
+
+ dprintf("CSafeRefCount @ 0x%x\n", dwAddr);
+ dprintfx(pszSRC);
+
+ CoTaskMemFree(pszSRC);
+
+errRtn:
+
+ delete[] blockSRC;
+
+ return;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: dump_threadcheck, exported
+//
+// Synopsis: dumps CThreadCheck object
+//
+// Effects:
+//
+// Arguments: see DECLARE_API in oleexts.h
+//
+// Requires:
+//
+// Returns: void
+//
+// Signals:
+//
+// Modifies: ExtensionApis (global)
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 02-Feb-95 t-ScottH author
+//
+// Notes:
+// The address of the object is passed in the arguments. This
+// address is in the debuggee's process memory. In order for
+// NTSD to view this memory, the debugger must copy the mem
+// using the WIN32 ReadProcessMemory API.
+//
+//--------------------------------------------------------------------------
+
+DECLARE_API(dump_threadcheck)
+{
+ DWORD dwReturnedCount;
+ BOOL fError;
+ LPVOID dwAddr;
+ char *pszTC;
+ char *blockTC = NULL;
+ CThreadCheck *pTC = NULL;
+
+ // set up global function pointers
+ ExtensionApis = *lpExtensionApis;
+
+ // get address of object from argument string
+ dwAddr = (LPVOID)GetExpression( args );
+ if (dwAddr == 0)
+ {
+ dprintf("Failed to get Address of CThreadCheck\n");
+ return;
+ }
+
+ // read the block of memory from the debugee's process
+ blockTC = new char[sizeof(CThreadCheck)];
+
+ fError = ReadProcessMemory(
+ hCurrentProcess,
+ dwAddr,
+ blockTC,
+ sizeof(CThreadCheck),
+ &dwReturnedCount
+ );
+
+ if (fError == FALSE)
+ {
+ dprintf("Could not read debuggee's process memory \n");
+ dprintf("at address %x\n", dwAddr);
+ dprintf("Last Error Code = %d (0x%x)\n", GetLastError(), GetLastError());
+
+ goto errRtn;
+ }
+
+ if (dwReturnedCount != sizeof(CThreadCheck))
+ {
+ dprintf("Size of process memory read != requested\n");
+
+ goto errRtn;
+ }
+
+ pTC = (CThreadCheck *)blockTC;
+
+ // dump the structure
+ pszTC = DumpCThreadCheck(pTC, NO_PREFIX, 1);
+
+ dprintf("CThreadCheck @ 0x%x\n", dwAddr);
+ dprintfx(pszTC);
+
+ CoTaskMemFree(pszTC);
+
+errRtn:
+
+ delete[] blockTC;
+
+ return;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: dump_formatetc, exported
+//
+// Synopsis: dumps FORMATETC object
+//
+// Effects:
+//
+// Arguments: see DECLARE_API in oleexts.h
+//
+// Requires:
+//
+// Returns: void
+//
+// Signals:
+//
+// Modifies: ExtensionApis (global)
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 02-Feb-95 t-ScottH author
+//
+// Notes:
+// The address of the object is passed in the arguments. This
+// address is in the debuggee's process memory. In order for
+// NTSD to view this memory, the debugger must copy the mem
+// using the WIN32 ReadProcessMemory API.
+//
+//--------------------------------------------------------------------------
+
+DECLARE_API(dump_formatetc)
+{
+ BOOL fError;
+ LPVOID dwAddr;
+ DWORD dwReturnedCount;
+ char *pszFE;
+ char *blockFE = NULL;
+ FORMATETC *pFE = NULL;
+
+ // set up global function pointers
+ ExtensionApis = *lpExtensionApis;
+
+ // get address of object from argument string
+ dwAddr = (LPVOID)GetExpression( args );
+ if (dwAddr == 0)
+ {
+ dprintf("Failed to get Address of FORMATETC\n");
+ return;
+ }
+
+ // read the block of memory from the debugee's process
+ blockFE = new char[sizeof(FORMATETC)];
+
+ fError = ReadProcessMemory(
+ hCurrentProcess,
+ dwAddr,
+ blockFE,
+ sizeof(FORMATETC),
+ &dwReturnedCount
+ );
+
+ if (fError == FALSE)
+ {
+ dprintf("Could not read debuggee's process memory: FORMATETC \n");
+ dprintf("at address %x\n", dwAddr);
+ dprintf("Last Error Code = %d (0x%x)\n", GetLastError(), GetLastError());
+
+ goto errRtn;
+ }
+
+ if (dwReturnedCount != sizeof(FORMATETC))
+ {
+ dprintf("Size of process memory read != requested\n");
+
+ goto errRtn;
+ }
+
+ pFE = (FORMATETC *)blockFE;
+
+ // dump the structure
+ pszFE = DumpFORMATETC(pFE, NO_PREFIX, 1);
+
+ dprintf("FORMATETC @ 0x%x\n", dwAddr);
+ dprintfx(pszFE);
+
+ CoTaskMemFree(pszFE);
+
+errRtn:
+
+ // delete the blocks and not the pointers
+ delete[] blockFE;
+
+ return;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: dump_memstm, exported
+//
+// Synopsis: dumps MEMSTM object
+//
+// Effects:
+//
+// Arguments: see DECLARE_API in oleexts.h
+//
+// Requires:
+//
+// Returns: void
+//
+// Signals:
+//
+// Modifies: ExtensionApis (global)
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 02-Feb-95 t-ScottH author
+//
+// Notes:
+// The address of the object is passed in the arguments. This
+// address is in the debuggee's process memory. In order for
+// NTSD to view this memory, the debugger must copy the mem
+// using the WIN32 ReadProcessMemory API.
+//
+//--------------------------------------------------------------------------
+
+DECLARE_API(dump_memstm)
+{
+ BOOL fError;
+ LPVOID dwAddr;
+ DWORD dwReturnedCount;
+ char *pszMS;
+ char *blockMS = NULL;
+ MEMSTM *pMS = NULL;
+
+ // set up global function pointers
+ ExtensionApis = *lpExtensionApis;
+
+ // get address of object from argument string
+ dwAddr = (LPVOID)GetExpression( args );
+ if (dwAddr == 0)
+ {
+ dprintf("Failed to get Address of MEMSTM\n");
+ return;
+ }
+
+ // read the block of memory from the debugee's process
+ blockMS = new char[sizeof(MEMSTM)];
+
+ fError = ReadProcessMemory(
+ hCurrentProcess,
+ dwAddr,
+ blockMS,
+ sizeof(MEMSTM),
+ &dwReturnedCount
+ );
+
+ if (fError == FALSE)
+ {
+ dprintf("Could not read debuggee's process memory: MEMSTM \n");
+ dprintf("at address %x\n", dwAddr);
+ dprintf("Last Error Code = %d (0x%x)\n", GetLastError(), GetLastError());
+
+ goto errRtn;
+ }
+
+ if (dwReturnedCount != sizeof(MEMSTM))
+ {
+ dprintf("Size of process memory read != requested\n");
+
+ goto errRtn;
+ }
+
+ pMS = (MEMSTM *)blockMS;
+
+ // dump the structure
+ pszMS = DumpMEMSTM(pMS, NO_PREFIX, 1);
+
+ dprintf("MEMSTM @ 0x%x\n", dwAddr);
+ dprintfx(pszMS);
+
+ CoTaskMemFree(pszMS);
+
+errRtn:
+
+ // delete the blocks and not the pointers
+ delete[] blockMS;
+
+ return;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: dump_statdata, exported
+//
+// Synopsis: dumps STATDATA object
+//
+// Effects:
+//
+// Arguments: see DECLARE_API in oleexts.h
+//
+// Requires:
+//
+// Returns: void
+//
+// Signals:
+//
+// Modifies: ExtensionApis (global)
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 02-Feb-95 t-ScottH author
+//
+// Notes:
+// The address of the object is passed in the arguments. This
+// address is in the debuggee's process memory. In order for
+// NTSD to view this memory, the debugger must copy the mem
+// using the WIN32 ReadProcessMemory API.
+//
+//--------------------------------------------------------------------------
+
+DECLARE_API(dump_statdata)
+{
+ BOOL fError;
+ LPVOID dwAddr;
+ DWORD dwReturnedCount;
+ char *pszSD;
+ char *blockSD = NULL;
+ STATDATA *pSD = NULL;
+
+ // set up global function pointers
+ ExtensionApis = *lpExtensionApis;
+
+ // get address of object from argument string
+ dwAddr = (LPVOID)GetExpression( args );
+ if (dwAddr == 0)
+ {
+ dprintf("Failed to get Address of STATDATA\n");
+ return;
+ }
+
+ // read the block of memory from the debugee's process
+ blockSD = new char[sizeof(STATDATA)];
+
+ fError = ReadProcessMemory(
+ hCurrentProcess,
+ dwAddr,
+ blockSD,
+ sizeof(STATDATA),
+ &dwReturnedCount
+ );
+
+ if (fError == FALSE)
+ {
+ dprintf("Could not read debuggee's process memory: STATDATA \n");
+ dprintf("at address %x\n", dwAddr);
+ dprintf("Last Error Code = %d (0x%x)\n", GetLastError(), GetLastError());
+
+ goto errRtn;
+ }
+
+ if (dwReturnedCount != sizeof(STATDATA))
+ {
+ dprintf("Size of process memory read != requested\n");
+
+ goto errRtn;
+ }
+
+ pSD = (STATDATA *)blockSD;
+
+ // dump the structure
+ pszSD = DumpSTATDATA(pSD, NO_PREFIX, 1);
+
+ dprintf("STATDATA @ 0x%x\n", dwAddr);
+ dprintfx(pszSD);
+
+ CoTaskMemFree(pszSD);
+
+errRtn:
+
+ // delete the blocks and not the pointers
+ delete[] blockSD;
+
+ return;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: dump_stgmedium, exported
+//
+// Synopsis: dumps STGMEDIUM object
+//
+// Effects:
+//
+// Arguments: see DECLARE_API in oleexts.h
+//
+// Requires:
+//
+// Returns: void
+//
+// Signals:
+//
+// Modifies: ExtensionApis (global)
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 02-Feb-95 t-ScottH author
+//
+// Notes:
+// The address of the object is passed in the arguments. This
+// address is in the debuggee's process memory. In order for
+// NTSD to view this memory, the debugger must copy the mem
+// using the WIN32 ReadProcessMemory API.
+//
+//--------------------------------------------------------------------------
+
+DECLARE_API(dump_stgmedium)
+{
+ BOOL fError;
+ LPVOID dwAddr;
+ DWORD dwReturnedCount;
+ char *pszSTGMEDIUM;
+ char *blockSTGMEDIUM = NULL;
+ STGMEDIUM *pSTGMEDIUM = NULL;
+
+ // set up global function pointers
+ ExtensionApis = *lpExtensionApis;
+
+ // get address of object from argument string
+ dwAddr = (LPVOID)GetExpression( args );
+ if (dwAddr == 0)
+ {
+ dprintf("Failed to get Address of STGMEDIUM\n");
+ return;
+ }
+
+ // read the block of memory from the debugee's process
+ blockSTGMEDIUM = new char[sizeof(STGMEDIUM)];
+
+ fError = ReadProcessMemory(
+ hCurrentProcess,
+ dwAddr,
+ blockSTGMEDIUM,
+ sizeof(STGMEDIUM),
+ &dwReturnedCount
+ );
+
+ if (fError == FALSE)
+ {
+ dprintf("Could not read debuggee's process memory STGMEDIUM");
+ dprintf("at address %x\n", dwAddr);
+ dprintf("Last Error Code = %d (%x)\n", GetLastError(), GetLastError());
+
+ goto errRtn;
+ }
+
+ if (dwReturnedCount != sizeof(STGMEDIUM))
+ {
+ dprintf("Size of process memory read != requested\n");
+
+ goto errRtn;
+ }
+
+ pSTGMEDIUM = (STGMEDIUM *)blockSTGMEDIUM;
+
+ // dump the structure
+ pszSTGMEDIUM = DumpSTGMEDIUM(pSTGMEDIUM, NO_PREFIX, 1);
+
+ dprintf("STGMEDIUM @ 0x%x\n", dwAddr);
+ dprintfx(pszSTGMEDIUM);
+
+ CoTaskMemFree(pszSTGMEDIUM);
+
+errRtn:
+
+ delete[] blockSTGMEDIUM;
+
+ return;
+}
diff --git a/private/oleutest/oleexts/oleexts.h b/private/oleutest/oleexts/oleexts.h
new file mode 100644
index 000000000..519747f58
--- /dev/null
+++ b/private/oleutest/oleexts/oleexts.h
@@ -0,0 +1,107 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: oleexts.h
+//
+// Contents: macros useful for OLE debugger extensions
+//
+// Classes: none
+//
+// Functions: macros for: dprintf
+// GetExpression
+// GetSymbol
+// Disassm
+// CheckControlC
+// DECLARE_API(...)
+//
+// History: dd-mmm-yy Author Comment
+// 02-Feb-95 t-ScottH author
+//
+//--------------------------------------------------------------------------
+
+#ifndef _OLEEXTS_H_
+#define _OLEEXTS_H_
+
+//
+// NTSD_EXTENSION_APIS defined in ntsdexts.h
+//
+// typedef struct _NTSD_EXTENSION_APIS {
+// DWORD nSize;
+// PNTSD_OUTPUT_ROUTINE lpOutputRoutine;
+// PNTSD_GET_EXPRESSION lpGetExpressionRoutine;
+// PNTSD_GET_SYMBOL lpGetSymbolRoutine;
+// PNTSD_DISASM lpDisasmRoutine
+// PNTSD_CHECK_CONTROL_C lpCheckControlCRoutine;
+// }; NTSD_EXTENSION_APIS, *PNTSD_EXTENSION_APIS
+//
+// the following macros assume global: NTSD_EXTENSION_APIS ExtensionApis
+
+// formatted print like CRT printf
+// void dprintf(char *format [, argument] ...);
+#define dprintf (ExtensionApis.lpOutputRoutine)
+
+// returns value of expression
+// DWORD GetExpression(char *expression);
+#define GetExpression (ExtensionApis.lpGetExpressionRoutine)
+
+// locates the nearest symbol
+// void GetSymbol(LPVOID address, PUCHAR buffer, LPDWORD lpdwDisplacement);
+#define GetSymbol (ExtensionApis.lpGetSymbolRoutine)
+
+// Disassembles an instruction
+// DWORD Disassm(LPDWORD lpdwOffset, LPSTR lpBuffer, BOOL fShowEffectiveAddress);
+#define Disassm (ExtensionApis.lpGetDisasmRoutine)
+
+// did user press CTRL+C
+// BOOL CheckControlC(void);
+#define CheckControlC (ExtensionApis.lpCheckControlCRoutine)
+
+//+-------------------------------------------------------------------------
+//
+// Function Macro: DECLARE_API(...)
+//
+// Synopsis: definition for an NTSD debugger extension function
+//
+// Effects:
+//
+// Arguments: [hCurrentProcess] - Handle to current process
+// [hCurrentThread] - Handle to current thread
+// [dwCurrentPc] - Copy of the program counter
+// [lpExtenisonApis] - pointer to NTSD_EXTENSION_APIS
+// (structure function pointers for NTSD)
+// [args] - a string of arguments from NTSD cmd line
+//
+// Requires:
+//
+// Returns: void
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 02-Feb-95 t-ScottH author
+//
+// Notes:
+// we use a function macro for defining our debugger extensions
+// functions to allow for easy extensibility
+//
+// !!!function names MUST be lower case!!!
+//
+//--------------------------------------------------------------------------
+
+#define DECLARE_API(s) \
+ VOID \
+ s( \
+ HANDLE hCurrentProcess, \
+ HANDLE hCurrentThread, \
+ DWORD dwCurrentPc, \
+ PNTSD_EXTENSION_APIS lpExtensionApis, \
+ LPSTR args \
+ )
+
+#endif // _OLEEXTS_H_
diff --git a/private/oleutest/oletest/app.cpp b/private/oleutest/oletest/app.cpp
new file mode 100644
index 000000000..7df1829b4
--- /dev/null
+++ b/private/oleutest/oletest/app.cpp
@@ -0,0 +1,65 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: app.cpp
+//
+// Contents: implementation of OleTestApp class methods
+//
+// Classes:
+//
+// Functions:
+//
+// History: dd-mmm-yy Author Comment
+// 06-Feb-94 alexgo author
+//
+//--------------------------------------------------------------------------
+
+#include "oletest.h"
+
+//+-------------------------------------------------------------------------
+//
+// Member: OleTestApp::Reset
+//
+// Synopsis: clears internal variables in the OleTestApp instance
+//
+// Effects:
+//
+// Arguments: void
+//
+// Requires:
+//
+// Returns: void
+//
+// Signals:
+//
+// Modifies:
+//
+// Derivation:
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 06-Feb-94 alexgo author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+void OleTestApp::Reset(void)
+{
+ int i;
+
+ m_message = NULL;
+ m_wparam = NULL;
+ m_lparam = NULL;
+
+ for( i = 0; i < (sizeof(m_rgTesthwnd)/sizeof(m_rgTesthwnd[0])); i++ )
+ {
+ m_rgTesthwnd[i] = NULL;
+ }
+
+ m_Temp = NULL;
+}
+
diff --git a/private/oleutest/oletest/app.h b/private/oleutest/oletest/app.h
new file mode 100644
index 000000000..f74806008
--- /dev/null
+++ b/private/oleutest/oletest/app.h
@@ -0,0 +1,70 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: app.h
+//
+// Contents: The class declaration of OleTestApp class..
+//
+// Classes: OleTestApp
+//
+// History: dd-mmm-yy Author Comment
+// 06-Feb-93 alexgo author
+//
+//--------------------------------------------------------------------------
+
+#ifndef _APP_H
+#define _APP_H
+
+//+-------------------------------------------------------------------------
+//
+// Class: OleTestApp
+//
+// Purpose: Stores all global app data for the oletest driver app
+// (such as the to-do stack).
+//
+// History: dd-mmm-yy Author Comment
+// 06-Feb-93 alexgo author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+class OleTestApp
+{
+public:
+ // driver information
+ HINSTANCE m_hinst;
+ HWND m_hwndMain;
+ HWND m_hwndEdit;
+ TaskStack m_TaskStack;
+ BOOL m_fInteractive; //if TRUE, then we should not
+ //shut down when tests are
+ //completed.
+
+ LPSTR m_pszDebuggerOption;
+ FILE * m_fpLog;
+
+ // set to TRUE when a test fails, reset after WM_TESTSCOMPLETED
+ BOOL m_fGotErrors;
+
+ // information on running test apps
+ void Reset(void); //zeros all the data below.
+
+ UINT m_message;
+ WPARAM m_wparam;
+ LPARAM m_lparam;
+
+ // variables that test routines may modify.
+ HWND m_rgTesthwnd[10];
+ void * m_Temp; //temporary dumping ground for
+ //data that spans callback functions.
+};
+
+// declaration for the global instance of OleTestApp
+
+extern OleTestApp vApp;
+
+
+#endif
diff --git a/private/oleutest/oletest/appwin.h b/private/oleutest/oletest/appwin.h
new file mode 100644
index 000000000..2b4e05e27
--- /dev/null
+++ b/private/oleutest/oletest/appwin.h
@@ -0,0 +1,34 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: appwin.h
+//
+// Contents: constants for the menu items and so forth
+//
+// Classes:
+//
+// Functions:
+//
+// History: dd-mmm-yy Author Comment
+// 06-Feb-94 alexgo author
+//
+//
+//--------------------------------------------------------------------------
+
+#ifndef _APPWIN_H
+#define _APPWIN_H
+
+#define IDM_EXIT 100
+#define IDM_COPY 103
+#define IDM_SAVE 104
+#define IDM_RUN_BASE 200
+
+#define IDD_ASSERTIONFAILURE 101
+
+#define IDC_EDIT 1003
+#define IDB_BREAK 1004
+
+#endif //!_APPWIN_H
+
diff --git a/private/oleutest/oletest/assert.cpp b/private/oleutest/oletest/assert.cpp
new file mode 100644
index 000000000..94077c2a1
--- /dev/null
+++ b/private/oleutest/oletest/assert.cpp
@@ -0,0 +1,177 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: assert.cpp
+//
+// Contents: Assertion handling code for OleTest
+//
+// Classes:
+//
+// Functions: OleTestAssert
+// DlgAssertProc
+//
+// History: dd-mmm-yy Author Comment
+// 09-Dec-94 MikeW author
+//
+//--------------------------------------------------------------------------
+
+#include "oletest.h"
+#include "appwin.h"
+
+//+-------------------------------------------------------------------------
+//
+// Function: OleTestAssert
+//
+// Synopsis: Reports assertion failures to the user
+//
+// Effects:
+//
+// Arguments: [pszMessage] -- the assertion message
+// [pszFile] -- the file it occured in
+// [uLine] -- the line it occured at
+//
+// Requires:
+//
+// Returns: void
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm: Format the message and then put up a dialog box for the user.
+// They can then choose to abort the test, break to the debugger,
+// or ignore the assertion.
+//
+// History: dd-mmm-yy Author Comment
+// 09-Dec-94 MikeW author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+void OleTestAssert(char *pszMessage, char *pszFile, UINT uLine)
+{
+ char szErrorMessage[3 * 80]; // room for 3 lines of info
+ int cch;
+ int nAction;
+
+ OutputDebugString("OleTest -- Assertion Failure\r\n");
+
+ //
+ // format the message
+ //
+
+ cch = _snprintf(szErrorMessage,
+ sizeof(szErrorMessage),
+ "%s\r\nIn file: %s\r\nAt line: %u",
+ pszMessage,
+ pszFile,
+ uLine);
+
+ if (cch < 0)
+ {
+ //
+ // the whole assertion message doesn't fit in the buffer so
+ // just worry about the file name and line number
+ //
+
+ OutputDebugString(pszMessage); // send original text to the debugger
+ OutputDebugString("\r\n");
+
+ _snprintf(szErrorMessage,
+ sizeof(szErrorMessage),
+ "In file: %s\r\nAt line: %d",
+ pszFile,
+ uLine);
+
+ szErrorMessage[sizeof(szErrorMessage) - 1] = '\0'; // just in case
+ }
+
+ OutputDebugString(szErrorMessage);
+ OutputDebugString("\r\n");
+
+ nAction = DialogBoxParam(vApp.m_hinst, // get the users choice
+ MAKEINTRESOURCE(IDD_ASSERTIONFAILURE),
+ vApp.m_hwndMain,
+ DlgAssertProc,
+ (LPARAM) szErrorMessage);
+
+ switch (nAction)
+ {
+ case IDABORT: // abort the test
+ RaiseException(E_ABORT, 0, 0, NULL);
+
+ case IDB_BREAK: // break into the debugger
+ DebugBreak();
+ break;
+
+ case IDIGNORE: // ignore the assertion
+ break;
+
+ default: // whoops
+ RaiseException(E_UNEXPECTED, 0, 0, NULL);
+ }
+}
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: DlgAssertProc
+//
+// Synopsis: Window procedure for the assertion dialog box
+//
+// Effects:
+//
+// Arguments: [hWnd] -- dialog window
+// [uMsg] -- message
+// [wParam] -- wParam
+// [lParam] -- lParam (for INITDIALOG it points to assert text)
+//
+// Requires:
+//
+// Returns: BOOL
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm: Just wait for a button to be pressed
+//
+// History: dd-mmm-yy Author Comment
+// 09-Dec-94 MikeW author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+BOOL CALLBACK DlgAssertProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ switch (uMsg)
+ {
+ case WM_INITDIALOG:
+ DeleteMenu(GetSystemMenu(hWnd, FALSE), SC_CLOSE, MF_BYCOMMAND);
+ DrawMenuBar(hWnd);
+
+ SetDlgItemText(hWnd, IDC_EDIT, (LPCSTR) lParam);
+
+ return TRUE;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case IDABORT:
+ case IDB_BREAK:
+ case IDIGNORE:
+ EndDialog(hWnd, LOWORD(wParam));
+ return TRUE;
+
+ default:
+ return FALSE;
+ }
+
+ default:
+ return FALSE;
+ }
+}
diff --git a/private/oleutest/oletest/assert.h b/private/oleutest/oletest/assert.h
new file mode 100644
index 000000000..72be6231a
--- /dev/null
+++ b/private/oleutest/oletest/assert.h
@@ -0,0 +1,33 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: assert.h
+//
+// Contents: Declaraions of assert
+//
+// Classes:
+//
+// History: dd-mmm-yy Author Comment
+// 09-Dec-94 MikeW author
+//
+//--------------------------------------------------------------------------
+
+#ifndef _ASSERT_H_
+#define _ASSERT_H_
+
+//
+// Misc prototypes
+//
+BOOL CALLBACK DlgAssertProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+void OleTestAssert(char *, char *, UINT);
+
+//
+// Assertion macros
+//
+#define Assert(x) assert(x)
+#define assert(x) {if (!(x)) OleTestAssert(#x, __FILE__, __LINE__);}
+#define AssertSz(x, exp) {if (!(x)) OleTestAssert(exp, __FILE__, __LINE__);}
+
+#endif //_ASSERT_H_
diff --git a/private/oleutest/oletest/attest.cpp b/private/oleutest/oletest/attest.cpp
new file mode 100644
index 000000000..ca095139a
--- /dev/null
+++ b/private/oleutest/oletest/attest.cpp
@@ -0,0 +1,1352 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: attest.cpp
+//
+// Contents: upper layer tests to test the apartment thread model
+//
+// Classes: CBareFactory
+// CATTestIPtrs
+//
+// Functions:
+// ATTest
+// CreateEHelperQuery
+// LinkObjectQuery
+// GetClipboardQuery
+// CreateEHTest
+// LinkObjectTest
+// GetClipboardTest
+// OleLinkMethods
+// OleObjectMethods
+// PersistStorageMethods
+// DataObjectMethods
+// RunnableObjectMethods
+// ViewObject2Methods
+// OleCache2Methods
+// ExternalConnectionsMethods
+// CHECK_FOR_THREAD_ERROR (macro)
+//
+// History: dd-mmm-yy Author Comment
+// 04-Jan-95 t-ScottH author
+//
+//--------------------------------------------------------------------------
+
+#include "oletest.h"
+#include "attest.h"
+
+#include "initguid.h"
+DEFINE_GUID(CLSID_SimpSvr,
+ 0xBCF6D4A0,
+ 0xBE8C,
+ 0x1068,
+ 0xB6,
+ 0xD4,
+ 0x00,
+ 0xDD,
+ 0x01,
+ 0x0C,
+ 0x05,
+ 0x09);
+
+DEFINE_GUID(CLSID_StdOleLink,
+ 0x00000300,
+ 0,
+ 0,
+ 0xC0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0x46);
+
+//+-------------------------------------------------------------------------
+//
+// Member: CATTestIPtrs::CATTestIPtrs(), public
+//
+// Synopsis: constructor
+//
+// Effects:
+//
+// Arguments: none
+//
+// Requires:
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Derivation:
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 12-Jan-95 t-ScottH author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+CATTestIPtrs::CATTestIPtrs()
+{
+ _pOleObject = NULL;
+ _pOleCache2 = NULL;
+ _pDataObject = NULL;
+ _pPersistStorage = NULL;
+ _pRunnableObject = NULL;
+ _pViewObject2 = NULL;
+ _pExternalConnection= NULL;
+ _pOleLink = NULL;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Member: CATTestIPtrs::Reset(), public
+//
+// Synopsis: resets all pointers to NULL
+//
+// Effects: releases all objects
+//
+// Arguments: none
+//
+// Requires:
+//
+// Returns: HRESULT
+//
+// Signals:
+//
+// Modifies: releases all objects and NULLs pointer
+//
+// Derivation:
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 12-Jan-95 t-ScottH author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+STDMETHODIMP CATTestIPtrs::Reset()
+{
+ if (_pOleObject != NULL)
+ {
+ _pOleObject->Release();
+ _pOleObject = NULL;
+ }
+
+ if (_pOleCache2 != NULL)
+ {
+ _pOleCache2->Release();
+ _pOleCache2 = NULL;
+ }
+
+ if (_pDataObject != NULL)
+ {
+ _pDataObject->Release();
+ _pDataObject = NULL;
+ }
+
+ if (_pPersistStorage != NULL)
+ {
+ _pPersistStorage->Release();
+ _pPersistStorage = NULL;
+ }
+
+ if (_pRunnableObject != NULL)
+ {
+ _pRunnableObject->Release();
+ _pRunnableObject = NULL;
+ }
+
+ if (_pViewObject2 != NULL)
+ {
+ _pViewObject2->Release();
+ _pViewObject2 = NULL;
+ }
+
+ if (_pExternalConnection != NULL)
+ {
+ _pExternalConnection->Release();
+ _pExternalConnection = NULL;
+ }
+
+ if (_pOleLink != NULL)
+ {
+ _pOleLink->Release();
+ _pOleLink = NULL;
+ }
+
+ return NOERROR;
+}
+
+
+//+-------------------------------------------------------------------------
+//
+// Member: CBareFactory::CBareFactory, public
+//
+// Synopsis: constructor for the class factory
+//
+// Effects:
+//
+// Arguments: none
+//
+// Returns: void
+//
+// Modifies: initializes _cRefs
+//
+// Derivation: IClassFactory
+//
+// History: dd-mmm-yy Author Comment
+// 11-Jan-95 t-ScottH author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+CBareFactory::CBareFactory()
+{
+ _cRefs = 1;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Member: CBareFactory::QueryInterface, public
+//
+// Synopsis: only IUnknown and IClassFactory are supported
+//
+// Effects:
+//
+// Arguments: [iid] -- the requested interface
+// [ppvObj]-- where to put the interface pointer
+//
+// Returns: HRESULT
+//
+// Modifies: ppvObj
+//
+// Derivation: IClassFactory
+//
+// History: dd-mmm-yy Author Comment
+// 11-Jan-95 t-ScottH author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+STDMETHODIMP CBareFactory::QueryInterface (REFIID iid, LPVOID FAR* ppvObj)
+{
+ if( IsEqualIID(iid, IID_IClassFactory) ||
+ IsEqualIID(iid, IID_IUnknown) )
+ {
+ *ppvObj = this;
+ AddRef();
+ return NOERROR;
+ }
+ else
+ {
+ *ppvObj = NULL;
+ return E_NOINTERFACE;
+ }
+}
+
+//+-------------------------------------------------------------------------
+//
+// Member: CBareFactory::AddRef, public
+//
+// Synopsis: increments the reference count
+//
+// Effects:
+//
+// Arguments: none
+//
+// Returns: ULONG -- the new reference count
+//
+// Modifies:
+//
+// Derivation: IClassFactory
+//
+// History: dd-mmm-yy Author Comment
+// 11-Jan-95 t-ScottH author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+STDMETHODIMP_(ULONG) CBareFactory::AddRef (void)
+{
+ _cRefs++;
+ return _cRefs;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Member: CBareFactory::Release, public
+//
+// Synopsis: decrements the reference count
+//
+// Effects: deletes object when reference count is zero
+//
+// Arguments: none
+//
+// Returns: ULONG -- the new reference count
+//
+// Modifies:
+//
+// Derivation: IClassFactory
+//
+// History: dd-mmm-yy Author Comment
+// 11-Jan-95 t-ScottH author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+STDMETHODIMP_(ULONG) CBareFactory::Release (void)
+{
+ _cRefs--;
+
+ if( _cRefs == 0 )
+ {
+ delete this;
+ return 0;
+ }
+
+ return _cRefs;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Member: CBareFactory::CreateInstance, public
+//
+// Synopsis: does nothing
+//
+// Effects:
+//
+// Arguments: [pUnkOuter] -- the controlling unknown for aggregation
+// [iid] -- the requested interface
+// [ppvObj] -- where to put the interface pointer
+//
+// Returns: HRESULT
+//
+// Modifies:
+//
+// Derivation: IClassFactory
+//
+// History: dd-mmm-yy Author Comment
+// 11-Jan-95 t-ScottH author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+STDMETHODIMP CBareFactory::CreateInstance (
+ LPUNKNOWN pUnkOuter,
+ REFIID iid,
+ LPVOID FAR* ppv)
+{
+ return E_NOTIMPL;;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Member: CBareFactory::LockServer, public
+//
+// Synopsis: does nothing
+//
+// Effects:
+//
+// Arguments: [flock] -- specifies the lock count
+//
+// Returns: HRESULT
+//
+// Modifies:
+//
+// History: dd-mmm-yy Author Comment
+// 11-Jan-95 t-ScottH author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+STDMETHODIMP CBareFactory::LockServer ( BOOL fLock )
+{
+ return NOERROR;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: CHECK_FOR_THREAD_ERROR (macro)
+//
+// Synopsis: make sure that the hresult is RPC_E_WRONG_THREAD
+//
+// Effects: exits thread if hresult != RPC_E_WRONG
+//
+// Arguments: [hresult] -- error code
+//
+// Requires:
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 09-Jan-95 t-ScottH author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+#define CHECK_FOR_THREAD_ERROR(hresult) \
+ if (hresult != RPC_E_WRONG_THREAD) \
+ { \
+ OutputString("Expected RPC_E_WRONG_THREAD but received %x.\r\n", hresult); \
+ assert(hresult == RPC_E_WRONG_THREAD); \
+ ExitThread((DWORD)E_UNEXPECTED); \
+ }
+
+// globals
+CATTestIPtrs g_IPtrs;
+
+//+-------------------------------------------------------------------------
+//
+// Function: ATTest
+//
+// Synopsis: calls the query functions to get pointers to the
+// supported interfaces
+//
+// Effects:
+//
+// Arguments: void
+//
+// Requires:
+//
+// Returns: void
+//
+// Signals:
+//
+// Modifies: globals g_IPtrs._pOleObject
+// g_IPtrs._pPersistStorage
+// g_IPtrs._pDataObject
+// g_IPtrs._pRunnableObject
+// g_IPtrs._pViewObject2
+// g_IPtrs._pOleCache2
+// g_IPtrs._pExternalConnection
+// g_IPtrs._pOleLink
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 06-Jan-95 t-ScottH author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+void ATTest(void)
+{
+ HRESULT hresult;
+
+ hresult = OleInitialize(NULL);
+ assert(hresult == S_OK);
+
+ // the functions CreateEHelperQuery, LinkObjectQuery and
+ // GetClipboardQuery return either NOERROR or E_UNEXPECTED.
+ // NOERROR is defined as 0
+ hresult = CreateEHelperQuery();
+
+ g_IPtrs.Reset();
+ hresult |= LinkObjectQuery();
+
+ g_IPtrs.Reset();
+ hresult |= GetClipboardQuery();
+
+ vApp.Reset();
+ vApp.m_wparam = (hresult == NOERROR) ? TEST_SUCCESS : TEST_FAILURE;
+ vApp.m_lparam = (LPARAM)hresult;
+ vApp.m_message = WM_TESTEND;
+
+ HandleTestEnd();
+
+ OleUninitialize();
+
+ return;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: GetClipboardQuery
+//
+// Synopsis: get a pointer to IDataObject interface, create a new thread
+// to test proper exit/error codes, wait for the thread to
+// complete and return the thread's exit code
+//
+// Effects: creates new thread
+//
+// Arguments: none
+//
+// Requires:
+//
+// Returns: HRESULT
+//
+// Signals:
+//
+// Modifies: g_IPtrs._pDataObject
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 11-Jan-95 t-ScottH author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+HRESULT GetClipboardQuery(void)
+{
+ HRESULT hresult;
+ HANDLE hTestInterfaceThread;
+ DWORD dwThreadId = 0;
+ DWORD dwThreadExitCode;
+
+ hresult = OleGetClipboard( &g_IPtrs._pDataObject );
+ assert(hresult == S_OK );
+
+ hTestInterfaceThread = CreateThread(
+ NULL, // security attributes
+ 0, // stack size (default)
+ (LPTHREAD_START_ROUTINE)&GetClipboardTest, // address of thread function
+ NULL, // arguments of thread function
+ 0, // creation flags
+ &dwThreadId ); // address of new thread ID
+
+ assert(hTestInterfaceThread != NULL); //ensure that we have a valid thread handle
+
+ // wait for the thread object so we can examine the error code
+ WaitForSingleObject(hTestInterfaceThread, INFINITE);
+
+ GetExitCodeThread(hTestInterfaceThread, &dwThreadExitCode);
+
+ hresult = (HRESULT)dwThreadExitCode;
+
+ CloseHandle(hTestInterfaceThread);
+
+ return hresult;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: LinkObjectQuery
+//
+// Synopsis: get a pointer to available interfaces, create a new thread
+// to test proper exit/error codes, wait for the thread to
+// complete and return the thread's exit code
+//
+// Effects:
+//
+// Arguments: none
+//
+// Requires:
+//
+// Returns: HRESULT
+//
+// Signals:
+//
+// Modifies: g_IPtrs._pOleObject
+// g_IPtrs._pPersistStorage
+// g_IPtrs._pDataObject
+// g_IPtrs._pRunnableObject
+// g_IPtrs._pViewObject2
+// g_IPtrs._pOleCache2
+// g_IPtrs._pOleLink
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 11-Jan-95 t-ScottH author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+HRESULT LinkObjectQuery(void)
+{
+ HRESULT hresult;
+ HANDLE hTestInterfaceThread;
+ DWORD dwThreadId = 0;
+ DWORD dwThreadExitCode;
+
+ hresult = CoCreateInstance(
+ CLSID_StdOleLink, // class ID of the object class
+ NULL, // controlling unknown fro aggregation
+ CLSCTX_INPROC, // context to run executables
+ IID_IOleObject, // the requested interface
+ (void **)&g_IPtrs._pOleObject); // where to store pointer to interface
+ assert(hresult == S_OK);
+
+
+ hresult = g_IPtrs._pOleObject->QueryInterface(IID_IPersistStorage, (void **)&g_IPtrs._pPersistStorage);
+ assert(hresult == S_OK);
+
+ hresult = g_IPtrs._pOleObject->QueryInterface(IID_IDataObject, (void **)&g_IPtrs._pDataObject);
+ assert(hresult == S_OK);
+
+ hresult = g_IPtrs._pOleObject->QueryInterface(IID_IRunnableObject, (void **)&g_IPtrs._pRunnableObject);
+ assert(hresult == S_OK);
+
+ hresult = g_IPtrs._pOleObject->QueryInterface(IID_IViewObject2, (void **)&g_IPtrs._pViewObject2);
+ assert(hresult == S_OK);
+
+ hresult = g_IPtrs._pOleObject->QueryInterface(IID_IOleCache2, (void **)&g_IPtrs._pOleCache2);
+ assert(hresult == S_OK);
+
+ hresult = g_IPtrs._pOleObject->QueryInterface(IID_IOleLink, (void **)&g_IPtrs._pOleLink);
+ assert(hresult == S_OK);
+
+ hTestInterfaceThread = CreateThread(
+ NULL, // security attributes
+ 0, // stack size (default)
+ (LPTHREAD_START_ROUTINE)&LinkObjectTest,// address of thread function
+ NULL, // arguments of thread function
+ 0, // creation flags
+ &dwThreadId ); // address of new thread ID
+
+ assert(hTestInterfaceThread != NULL); //ensure that we have a valid thread handle
+
+ // wait for the thread object so we can examine the error code
+ WaitForSingleObject(hTestInterfaceThread, INFINITE);
+
+ GetExitCodeThread(hTestInterfaceThread, &dwThreadExitCode);
+
+ hresult = (HRESULT)dwThreadExitCode;
+
+ CloseHandle(hTestInterfaceThread);
+
+ return hresult;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: CreateEHelperQuery
+//
+// Synopsis: get a pointer to available interfaces, create a new thread
+// to test proper exit/error codes, wait for the thread to
+// complete and return the thread's exit code
+//
+// Effects:
+//
+// Arguments: none
+//
+// Requires:
+//
+// Returns: HRESULT
+//
+// Signals:
+//
+// Modifies: g_IPtrs._pOleObject
+// g_IPtrs._pPersistStorage
+// g_IPtrs._pDataObject
+// g_IPtrs._pRunnableObject
+// g_IPtrs._pViewObject2
+// g_IPtrs._pOleCache2
+// g_IPtrs._pExternalConnection
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 11-Jan-95 t-ScottH author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+HRESULT CreateEHelperQuery(void)
+{
+ HRESULT hresult;
+ HANDLE hTestInterfaceThread;
+ DWORD dwThreadId = 0;
+ DWORD dwThreadExitCode;
+ CBareFactory *pCF = new CBareFactory;
+
+ // must use EMBDHLP_DELAYCREATE flag otherwise API will try pCF->CreateInstance
+ // and verify pointer. CBareFactory::CreateInstance is not implemented!
+ hresult = OleCreateEmbeddingHelper(
+ CLSID_SimpSvr, // class ID of the server
+ NULL, // controlling unknown for aggregation
+ EMBDHLP_INPROC_SERVER | EMBDHLP_DELAYCREATE,// flags
+ pCF, // pointer to server's class factory
+ IID_IOleObject, // the requested interface
+ (void **)&g_IPtrs._pOleObject ); // where to store pointer to interface
+ assert(hresult == S_OK);
+
+ hresult = g_IPtrs._pOleObject->QueryInterface(IID_IPersistStorage, (void **)&g_IPtrs._pPersistStorage);
+ assert(hresult == S_OK);
+
+ hresult = g_IPtrs._pOleObject->QueryInterface(IID_IDataObject, (void **)&g_IPtrs._pDataObject);
+ assert(hresult == S_OK);
+
+ hresult = g_IPtrs._pOleObject->QueryInterface(IID_IRunnableObject, (void **)&g_IPtrs._pRunnableObject);
+ assert(hresult == S_OK);
+
+ hresult = g_IPtrs._pOleObject->QueryInterface(IID_IViewObject2, (void **)&g_IPtrs._pViewObject2);
+ assert(hresult == S_OK);
+
+ hresult = g_IPtrs._pOleObject->QueryInterface(IID_IOleCache2, (void **)&g_IPtrs._pOleCache2);
+ assert(hresult == S_OK);
+
+ hresult = g_IPtrs._pOleObject->QueryInterface(IID_IExternalConnection, (void **)&g_IPtrs._pExternalConnection);
+ assert(hresult == S_OK);
+
+ hTestInterfaceThread = CreateThread(
+ NULL, // security attributes
+ 0, // stack size (default)
+ (LPTHREAD_START_ROUTINE)&CreateEHTest, // address of thread function
+ NULL, // arguments of thread function
+ 0, // creation flags
+ &dwThreadId ); // address of new thread ID
+
+ assert(hTestInterfaceThread != NULL); //ensure that we have a valid thread handle
+
+ // wait for the thread object so we can examine the exit/error code
+ WaitForSingleObject(hTestInterfaceThread, INFINITE);
+
+ GetExitCodeThread(hTestInterfaceThread, &dwThreadExitCode);
+
+ hresult = (HRESULT)dwThreadExitCode;
+
+ CloseHandle(hTestInterfaceThread);
+
+ pCF->Release();
+
+ return hresult;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: GetClipBoardTest
+//
+// Synopsis: calls interface method functions and exits thread
+//
+// Effects:
+//
+// Arguments: none
+//
+// Requires:
+//
+// Returns: void
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 11-Jan-95 t-ScottH author
+//
+// Notes: all the interface methods are being called from a thread
+// which is not the owner. The methods should return
+// RPC_E_WRONG_THREAD error. If an interface method does not
+// return such error message, it is asserted and the
+// thread is exited with an E_UNEXPECTED exit code.
+//
+//--------------------------------------------------------------------------
+void GetClipboardTest(void)
+{
+ DataObjectMethods();
+
+ ExitThread((DWORD)NOERROR);
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: LinkObjectTest
+//
+// Synopsis: calls interface method functions and exits thread
+//
+// Effects:
+//
+// Arguments: none
+//
+// Requires:
+//
+// Returns: void
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 11-Jan-95 t-ScottH author
+//
+// Notes: all the interface methods are being called from a thread
+// which is not the owner. The methods should return
+// RPC_E_WRONG_THREAD error. If an interface method does not
+// return such error message, it is asserted and the
+// thread is exited with an E_UNEXPECTED exit code.
+//
+//--------------------------------------------------------------------------
+void LinkObjectTest(void)
+{
+ OleObjectMethods();
+
+ PersistStorageMethods();
+
+ DataObjectMethods();
+
+ RunnableObjectMethods();
+
+ OleCache2Methods();
+
+ ViewObject2Methods();
+
+ OleLinkMethods();
+
+ ExitThread((DWORD)NOERROR);
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: CreateEHTest
+//
+// Synopsis: calls interface method functions and exits thread
+//
+// Effects:
+//
+// Arguments: none
+//
+// Requires:
+//
+// Returns: void
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 11-Jan-95 t-ScottH author
+//
+// Notes: all the interface methods are being called from a thread
+// which is not the owner. The methods should return
+// RPC_E_WRONG_THREAD error. If an interface method does not
+// return such error message, it is asserted and the
+// thread is exited with an E_UNEXPECTED exit code.
+//
+//--------------------------------------------------------------------------
+void CreateEHTest(void)
+{
+ ExternalConnectionsMethods();
+
+ OleObjectMethods();
+
+ PersistStorageMethods();
+
+ DataObjectMethods();
+
+ RunnableObjectMethods();
+
+ ViewObject2Methods();
+
+ OleCache2Methods();
+
+ ExitThread((DWORD)NOERROR);
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: OleLinkMethods
+//
+// Synopsis: Calls all public IOleLink interface methods with NULL
+// parameters.
+//
+// Effects:
+//
+// Arguments: none
+//
+// Requires:
+//
+// Returns: void
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 11-Jan-95 t-ScottH author
+//
+// Notes: The interface methods are called on the wrong thread, thus
+// an RPC_E_WRONG_THREAD error should be returned from each
+// method. If not, we assert and then exit the thread.
+//
+//--------------------------------------------------------------------------
+void OleLinkMethods(void)
+{
+ HRESULT hresult;
+
+ hresult = g_IPtrs._pOleLink->SetUpdateOptions(NULL);
+ CHECK_FOR_THREAD_ERROR(hresult);
+
+ hresult = g_IPtrs._pOleLink->GetUpdateOptions(NULL);
+ CHECK_FOR_THREAD_ERROR(hresult);
+
+ hresult = g_IPtrs._pOleLink->SetSourceMoniker(NULL, CLSID_NULL);
+ CHECK_FOR_THREAD_ERROR(hresult);
+
+ hresult = g_IPtrs._pOleLink->GetSourceMoniker(NULL);
+ CHECK_FOR_THREAD_ERROR(hresult);
+
+ hresult = g_IPtrs._pOleLink->SetSourceDisplayName(NULL);
+ CHECK_FOR_THREAD_ERROR(hresult);
+
+ hresult = g_IPtrs._pOleLink->GetSourceDisplayName(NULL);
+ CHECK_FOR_THREAD_ERROR(hresult);
+
+ hresult = g_IPtrs._pOleLink->BindToSource(NULL, NULL);
+ CHECK_FOR_THREAD_ERROR(hresult);
+
+ hresult = g_IPtrs._pOleLink->BindIfRunning();
+ CHECK_FOR_THREAD_ERROR(hresult);
+
+ hresult = g_IPtrs._pOleLink->GetBoundSource(NULL);
+ CHECK_FOR_THREAD_ERROR(hresult);
+
+ hresult = g_IPtrs._pOleLink->UnbindSource();
+ CHECK_FOR_THREAD_ERROR(hresult);
+
+ hresult = g_IPtrs._pOleLink->Update(NULL);
+ CHECK_FOR_THREAD_ERROR(hresult);
+
+ return;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: ExternalConnectionsMethods
+//
+// Synopsis: Calls all public IExternalConnection interface methods with NULL
+// parameters.
+//
+// Effects:
+//
+// Arguments: none
+//
+// Requires:
+//
+// Returns: void
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 11-Jan-95 t-ScottH author
+//
+// Notes: The interface methods are called on the wrong thread, thus
+// an RPC_E_WRONG_THREAD error should be returned from each
+// method. If not, we assert and then exit the thread.
+//
+//--------------------------------------------------------------------------
+void ExternalConnectionsMethods(void)
+{
+ HRESULT hresult;
+
+ hresult = (HRESULT)g_IPtrs._pExternalConnection->AddConnection(NULL, NULL);
+ CHECK_FOR_THREAD_ERROR(hresult);
+
+ hresult = (HRESULT)g_IPtrs._pExternalConnection->ReleaseConnection(NULL, NULL, NULL);
+ CHECK_FOR_THREAD_ERROR(hresult);
+
+ return;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: OleObjectMethods
+//
+// Synopsis: Calls all public IOleObject interface methods with NULL
+// parameters.
+//
+// Effects:
+//
+// Arguments: none
+//
+// Requires:
+//
+// Returns: void
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 11-Jan-95 t-ScottH author
+//
+// Notes: The interface methods are called on the wrong thread, thus
+// an RPC_E_WRONG_THREAD error should be returned from each
+// method. If not, we assert and then exit the thread.
+//
+//--------------------------------------------------------------------------
+void OleObjectMethods(void)
+{
+ HRESULT hresult;
+
+ hresult = g_IPtrs._pOleObject->SetClientSite(NULL);
+ CHECK_FOR_THREAD_ERROR(hresult);
+
+ hresult = g_IPtrs._pOleObject->GetClientSite(NULL);
+ CHECK_FOR_THREAD_ERROR(hresult);
+
+ hresult = g_IPtrs._pOleObject->SetHostNames(NULL, NULL);
+ CHECK_FOR_THREAD_ERROR(hresult);
+
+ hresult = g_IPtrs._pOleObject->Close(NULL);
+ CHECK_FOR_THREAD_ERROR(hresult);
+
+ hresult = g_IPtrs._pOleObject->SetMoniker(NULL, NULL);
+ CHECK_FOR_THREAD_ERROR(hresult);
+
+ hresult = g_IPtrs._pOleObject->GetMoniker(NULL, NULL, NULL);
+ CHECK_FOR_THREAD_ERROR(hresult);
+
+ hresult = g_IPtrs._pOleObject->InitFromData(NULL, NULL, NULL);
+ CHECK_FOR_THREAD_ERROR(hresult);
+
+ hresult = g_IPtrs._pOleObject->GetClipboardData(NULL, NULL);
+ CHECK_FOR_THREAD_ERROR(hresult);
+
+ hresult = g_IPtrs._pOleObject->DoVerb(NULL, NULL, NULL, NULL, NULL, NULL);
+ CHECK_FOR_THREAD_ERROR(hresult);
+
+ hresult = g_IPtrs._pOleObject->EnumVerbs(NULL);
+ CHECK_FOR_THREAD_ERROR(hresult);
+
+ hresult = g_IPtrs._pOleObject->Update();
+ CHECK_FOR_THREAD_ERROR(hresult);
+
+ hresult = g_IPtrs._pOleObject->IsUpToDate();
+ CHECK_FOR_THREAD_ERROR(hresult);
+
+ hresult = g_IPtrs._pOleObject->GetUserClassID(NULL);
+ CHECK_FOR_THREAD_ERROR(hresult);
+
+ hresult = g_IPtrs._pOleObject->GetUserType(NULL, NULL);
+ CHECK_FOR_THREAD_ERROR(hresult);
+
+ hresult = g_IPtrs._pOleObject->SetExtent(NULL, NULL);
+ CHECK_FOR_THREAD_ERROR(hresult);
+
+ hresult = g_IPtrs._pOleObject->GetExtent(NULL, NULL);
+ CHECK_FOR_THREAD_ERROR(hresult);
+
+ hresult = g_IPtrs._pOleObject->Advise(NULL, NULL);
+ CHECK_FOR_THREAD_ERROR(hresult);
+
+ hresult = g_IPtrs._pOleObject->Unadvise(NULL);
+ CHECK_FOR_THREAD_ERROR(hresult);
+
+ hresult = g_IPtrs._pOleObject->EnumAdvise(NULL);
+ CHECK_FOR_THREAD_ERROR(hresult);
+
+ hresult = g_IPtrs._pOleObject->GetMiscStatus(NULL, NULL);
+ CHECK_FOR_THREAD_ERROR(hresult);
+
+ hresult = g_IPtrs._pOleObject->SetColorScheme(NULL);
+ CHECK_FOR_THREAD_ERROR(hresult);
+
+ return;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: PersistStorageMethods
+//
+// Synopsis: Calls all public IPersistStorage interface methods with NULL
+// parameters.
+//
+// Effects:
+//
+// Arguments: none
+//
+// Requires:
+//
+// Returns: void
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 11-Jan-95 t-ScottH author
+//
+// Notes: The interface methods are called on the wrong thread, thus
+// an RPC_E_WRONG_THREAD error should be returned from each
+// method. If not, we assert and then exit the thread.
+//
+//--------------------------------------------------------------------------
+void PersistStorageMethods(void)
+{
+ HRESULT hresult;
+
+ hresult = g_IPtrs._pPersistStorage->GetClassID(NULL);
+ CHECK_FOR_THREAD_ERROR(hresult);
+
+ hresult = g_IPtrs._pPersistStorage->IsDirty();
+ CHECK_FOR_THREAD_ERROR(hresult);
+
+ hresult = g_IPtrs._pPersistStorage->InitNew(NULL);
+ CHECK_FOR_THREAD_ERROR(hresult);
+
+ hresult = g_IPtrs._pPersistStorage->Load(NULL);
+ CHECK_FOR_THREAD_ERROR(hresult);
+
+ hresult = g_IPtrs._pPersistStorage->Save(NULL, NULL);
+ CHECK_FOR_THREAD_ERROR(hresult);
+
+ hresult = g_IPtrs._pPersistStorage->SaveCompleted(NULL);
+ CHECK_FOR_THREAD_ERROR(hresult);
+
+ hresult = g_IPtrs._pPersistStorage->HandsOffStorage();
+ CHECK_FOR_THREAD_ERROR(hresult);
+
+ return;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: DataObjectMethods
+//
+// Synopsis: Calls all public IDataObject interface methods with NULL
+// parameters.
+//
+// Effects:
+//
+// Arguments: none
+//
+// Requires:
+//
+// Returns: void
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 11-Jan-95 t-ScottH author
+//
+// Notes: The interface methods are called on the wrong thread, thus
+// an RPC_E_WRONG_THREAD error should be returned from each
+// method. If not, we assert and then exit the thread.
+//
+//--------------------------------------------------------------------------
+void DataObjectMethods(void)
+{
+ HRESULT hresult;
+
+ hresult = g_IPtrs._pDataObject->GetData(NULL, NULL);
+ CHECK_FOR_THREAD_ERROR(hresult);
+
+ hresult = g_IPtrs._pDataObject->GetDataHere(NULL, NULL);
+ CHECK_FOR_THREAD_ERROR(hresult);
+
+ hresult = g_IPtrs._pDataObject->QueryGetData(NULL);
+ CHECK_FOR_THREAD_ERROR(hresult);
+
+ hresult = g_IPtrs._pDataObject->GetCanonicalFormatEtc(NULL, NULL);
+ CHECK_FOR_THREAD_ERROR(hresult);
+
+ hresult = g_IPtrs._pDataObject->SetData(NULL, NULL, NULL);
+ CHECK_FOR_THREAD_ERROR(hresult);
+
+ hresult = g_IPtrs._pDataObject->EnumFormatEtc(NULL, NULL);
+ CHECK_FOR_THREAD_ERROR(hresult);
+
+ hresult = g_IPtrs._pDataObject->DAdvise(NULL, NULL, NULL, NULL);
+ CHECK_FOR_THREAD_ERROR(hresult);
+
+ hresult = g_IPtrs._pDataObject->DUnadvise(NULL);
+ CHECK_FOR_THREAD_ERROR(hresult);
+
+ hresult = g_IPtrs._pDataObject->EnumDAdvise(NULL);
+ CHECK_FOR_THREAD_ERROR(hresult);
+
+ return;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: RunnableObjectMethods
+//
+// Synopsis: Calls all public IRunnableObject interface methods with NULL
+// parameters.
+//
+// Effects:
+//
+// Arguments: none
+//
+// Requires:
+//
+// Returns: void
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 11-Jan-95 t-ScottH author
+//
+// Notes: The interface methods are called on the wrong thread, thus
+// an RPC_E_WRONG_THREAD error should be returned from each
+// method. If not, we assert and then exit the thread.
+//
+//--------------------------------------------------------------------------
+void RunnableObjectMethods(void)
+{
+ HRESULT hresult;
+
+ hresult = g_IPtrs._pRunnableObject->GetRunningClass(NULL);
+ CHECK_FOR_THREAD_ERROR(hresult);
+
+ hresult = g_IPtrs._pRunnableObject->Run(NULL);
+ CHECK_FOR_THREAD_ERROR(hresult);
+
+ hresult = g_IPtrs._pRunnableObject->IsRunning();
+ CHECK_FOR_THREAD_ERROR(hresult);
+
+ hresult = g_IPtrs._pRunnableObject->LockRunning(NULL, NULL);
+ CHECK_FOR_THREAD_ERROR(hresult);
+
+ hresult = g_IPtrs._pRunnableObject->SetContainedObject(NULL);
+ CHECK_FOR_THREAD_ERROR(hresult);
+
+ return;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: ViewObject2Methods
+//
+// Synopsis: Calls all public IViewObject2 interface methods with NULL
+// parameters.
+//
+// Effects:
+//
+// Arguments: none
+//
+// Requires:
+//
+// Returns: void
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 11-Jan-95 t-ScottH author
+//
+// Notes: The interface methods are called on the wrong thread, thus
+// an RPC_E_WRONG_THREAD error should be returned from each
+// method. If not, we assert and then exit the thread.
+//
+//--------------------------------------------------------------------------
+void ViewObject2Methods(void)
+{
+ HRESULT hresult;
+
+ hresult = g_IPtrs._pViewObject2->Draw(NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL);
+ CHECK_FOR_THREAD_ERROR(hresult);
+
+ hresult = g_IPtrs._pViewObject2->GetColorSet(NULL, NULL, NULL, NULL, NULL, NULL);
+ CHECK_FOR_THREAD_ERROR(hresult);
+
+ hresult = g_IPtrs._pViewObject2->Freeze(NULL, NULL, NULL, NULL);
+ CHECK_FOR_THREAD_ERROR(hresult);
+
+ hresult = g_IPtrs._pViewObject2->Unfreeze(NULL);
+ CHECK_FOR_THREAD_ERROR(hresult);
+
+ hresult = g_IPtrs._pViewObject2->SetAdvise(NULL, NULL, NULL);
+ CHECK_FOR_THREAD_ERROR(hresult);
+
+ hresult = g_IPtrs._pViewObject2->GetAdvise(NULL, NULL, NULL);
+ CHECK_FOR_THREAD_ERROR(hresult);
+
+ hresult = g_IPtrs._pViewObject2->GetExtent(NULL, NULL, NULL, NULL);
+ CHECK_FOR_THREAD_ERROR(hresult);
+
+ return;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: OleCache2Methods
+//
+// Synopsis: Calls all public IOleCache2 interface methods with NULL
+// parameters.
+//
+// Effects:
+//
+// Arguments: none
+//
+// Requires:
+//
+// Returns: void
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 11-Jan-95 t-ScottH author
+//
+// Notes:
+// Notes: The interface methods are called on the wrong thread, thus
+// an RPC_E_WRONG_THREAD error should be returned from each
+// method. If not, we assert and then exit the thread.
+//
+//--------------------------------------------------------------------------
+void OleCache2Methods(void)
+{
+ HRESULT hresult;
+
+ hresult = g_IPtrs._pOleCache2->Cache(NULL, NULL, NULL);
+ CHECK_FOR_THREAD_ERROR(hresult);
+
+ hresult = g_IPtrs._pOleCache2->Uncache(NULL);
+ CHECK_FOR_THREAD_ERROR(hresult);
+
+ hresult = g_IPtrs._pOleCache2->EnumCache(NULL);
+ CHECK_FOR_THREAD_ERROR(hresult);
+
+ hresult = g_IPtrs._pOleCache2->InitCache(NULL);
+ CHECK_FOR_THREAD_ERROR(hresult);
+
+ hresult = g_IPtrs._pOleCache2->SetData(NULL, NULL, NULL);
+ CHECK_FOR_THREAD_ERROR(hresult);
+
+ hresult = g_IPtrs._pOleCache2->UpdateCache(NULL, NULL, NULL);
+ CHECK_FOR_THREAD_ERROR(hresult);
+
+ hresult = g_IPtrs._pOleCache2->DiscardCache(NULL);
+ CHECK_FOR_THREAD_ERROR(hresult);
+
+ return;
+}
diff --git a/private/oleutest/oletest/attest.h b/private/oleutest/oletest/attest.h
new file mode 100644
index 000000000..7a6c9a5a2
--- /dev/null
+++ b/private/oleutest/oletest/attest.h
@@ -0,0 +1,123 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: attest.h
+//
+// Contents: declarations for upper layer apartment thread test
+//
+// Classes: CBareFactory
+// CATTestIPtrs
+//
+// Functions:
+//
+// History: dd-mmm-yy Author Comment
+// 04-Jan-95 t-ScottH author
+//
+//--------------------------------------------------------------------------
+
+#ifndef _ATTEST_H
+#define _ATTEST_H
+
+//+-------------------------------------------------------------------------
+//
+// Class:
+//
+// Purpose:
+//
+// Interface:
+//
+// History: dd-mmm-yy Author Comment
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+class CATTestIPtrs
+{
+
+public:
+ CATTestIPtrs();
+
+ STDMETHOD(Reset)();
+
+ IOleObject *_pOleObject;
+ IOleCache2 *_pOleCache2;
+ IDataObject *_pDataObject;
+ IPersistStorage *_pPersistStorage;
+ IRunnableObject *_pRunnableObject;
+ IViewObject2 *_pViewObject2;
+ IExternalConnection *_pExternalConnection;
+ IOleLink *_pOleLink;
+};
+
+//+-------------------------------------------------------------------------
+//
+// Class: CBareFactory
+//
+// Purpose: use as a class factory which doesn't do anything in
+// OleCreateEmbeddingHelper API
+//
+// Interface: IClassFactory
+//
+// History: dd-mmm-yy Author Comment
+// 11-Jan-95 t-ScottH author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+class CBareFactory : public IClassFactory
+{
+
+public:
+ STDMETHOD(QueryInterface) (REFIID iid, LPVOID FAR* ppvObj);
+ STDMETHOD_(ULONG,AddRef) (void);
+ STDMETHOD_(ULONG,Release) (void);
+ STDMETHOD(CreateInstance) (LPUNKNOWN pUnkOuter, REFIID iid,
+ LPVOID FAR* ppv);
+ STDMETHOD(LockServer) ( BOOL fLock );
+
+ CBareFactory();
+
+private:
+ ULONG _cRefs;
+};
+
+// runs 3 test routines and returns results
+void ATTest(void);
+
+// get pointers to interfaces and creates thread to ensure
+// interface methods return RPC_E_WRONG_ERROR
+HRESULT CreateEHelperQuery(void);
+
+HRESULT LinkObjectQuery(void);
+
+HRESULT GetClipboardQuery(void);
+
+// new thread functions to try interface methods
+void LinkObjectTest(void);
+
+void CreateEHTest(void);
+
+void GetClipboardTest(void);
+
+// interface methods with NULL parameters
+void OleLinkMethods(void);
+
+void OleObjectMethods(void);
+
+void PersistStorageMethods(void);
+
+void DataObjectMethods(void);
+
+void RunnableObjectMethods(void);
+
+void ViewObject2Methods(void);
+
+void OleCache2Methods(void);
+
+void ExternalConnectionsMethods(void);
+
+#endif //!ATTEST_H
diff --git a/private/oleutest/oletest/cliptest.cpp b/private/oleutest/oletest/cliptest.cpp
new file mode 100644
index 000000000..0cb33523c
--- /dev/null
+++ b/private/oleutest/oletest/cliptest.cpp
@@ -0,0 +1,1481 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: cliptest.cpp
+//
+// Contents: Clipboard Unit tests
+//
+// Classes:
+//
+// Functions: LEClipTest1
+//
+// History: dd-mmm-yy Author Comment
+// 23-Mar-94 alexgo author
+//
+//--------------------------------------------------------------------------
+
+#include "oletest.h"
+#include "gendata.h"
+#include "genenum.h"
+#include "letest.h"
+
+SLETestInfo letiClipTest = { "cntroutl", WM_TEST1 };
+
+//
+// functions local to this file
+//
+
+void DumpClipboardFormats(FILE *fp);
+HRESULT LEOle1ClipTest2Callback( void );
+HRESULT StressOleFlushClipboard(void);
+HRESULT StressOleGetClipboard(void);
+HRESULT StressOleIsCurrentClipboard(void);
+HRESULT StressOleSetClipboard(void);
+
+
+class CClipEnumeratorTest : public CEnumeratorTest
+{
+public:
+
+ CClipEnumeratorTest(
+ IEnumFORMATETC *penum,
+ LONG clEntries,
+ HRESULT& rhr);
+
+ BOOL Verify(void *);
+};
+
+
+
+CClipEnumeratorTest::CClipEnumeratorTest(
+ IEnumFORMATETC *penum,
+ LONG clEntries,
+ HRESULT& rhr)
+ : CEnumeratorTest(penum, sizeof(FORMATETC), clEntries, rhr)
+{
+ // Header does all the work
+}
+
+
+BOOL CClipEnumeratorTest::Verify(void *)
+{
+ return TRUE;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: DumpClipboardFormats
+//
+// Synopsis: dumps the formats currently on the clipboard to a file
+//
+// Effects:
+//
+// Arguments: [fp] -- the file to print the current formats
+//
+// Requires:
+//
+// Returns: void
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 11-Aug-94 alexgo author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+void DumpClipboardFormats( FILE *fp )
+{
+ char szBuf[256];
+ UINT cf = 0;
+
+ fprintf(fp, "==================================================\n\n");
+
+ OpenClipboard(NULL);
+
+ while( (cf = EnumClipboardFormats(cf)) != 0)
+ {
+ GetClipboardFormatName(cf, szBuf, sizeof(szBuf));
+
+ fprintf(fp, "%s\n", szBuf);
+ }
+
+ fprintf(fp, "\n==================================================\n");
+
+ CloseClipboard();
+
+ return;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: LEClipTest1
+//
+// Synopsis: runs the clipboard through a series of tests
+//
+// Effects:
+//
+// Arguments: void
+//
+// Requires:
+//
+// Returns: HRESULT
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm: Tests basic OLE32 functionality of the apis:
+// OleSetClipboard
+// OleGetClipboard
+// OleIsCurrentClipboard
+// OleFlushClipboard
+// downlevel format and clipboard data object testing is *not*
+// done by this routine
+//
+// History: dd-mmm-yy Author Comment
+// 23-Mar-94 alexgo author
+// 22-Jul-94 AlexT Add OleInit/OleUninit call
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+HRESULT LEClipTest1( void )
+{
+ HRESULT hresult = NOERROR;
+ CGenDataObject *pDO;
+ ULONG cRefs;
+ IDataObject * pIDO;
+
+ pDO = new CGenDataObject;
+
+ assert(pDO);
+
+ cRefs = pDO->AddRef();
+
+ // if cRefs != 1, then somebody modified this test code; the tests
+ // below will be invalid.
+
+ assert(cRefs==1);
+
+ //
+ // Basic Tests
+ //
+
+ hresult = OleSetClipboard(pDO);
+
+ if( hresult != NOERROR )
+ {
+ OutputString("OleSetClipboard failed! (%lx)\r\n", hresult);
+ return hresult;
+ }
+
+ // the data object should have been AddRef'ed
+
+ cRefs = pDO->AddRef();
+
+ if( cRefs != 3 )
+ {
+ OutputString("Wrong reference count!! Should be 3, "
+ "was %lu\r\n", cRefs);
+ return ResultFromScode(E_FAIL);
+ }
+
+ pDO->Release();
+
+ // Calling OleInitialize & OleUninitialize should not disturb the
+ // clipboard
+
+ hresult = OleInitialize(NULL);
+ if (FAILED(hresult))
+ {
+ OutputString("LEClipTest1: OleInitialize failed - hr = %lx\n",
+ hresult);
+ return ResultFromScode(E_FAIL);
+ }
+
+ OleUninitialize();
+
+ hresult = OleGetClipboard(&pIDO);
+
+ if( hresult != NOERROR )
+ {
+ OutputString("OleGetClipboard failed! (%lx)\r\n", hresult);
+ return hresult;
+ }
+
+ if( pIDO == NULL )
+ {
+ OutputString("OleGetClipboard returned NULL IDO\r\n");
+ return ResultFromScode(E_FAIL);
+ }
+
+ // the reference count on the clipboard data object should have gone up
+ // by one (to be 2). Remember this is not our data object but
+ // the clipboard's.
+
+ cRefs = pIDO->AddRef();
+
+ if( cRefs != 2 )
+ {
+ OutputString("Wrong ref count!! Should be 2, was %lu\r\n",
+ cRefs);
+ return ResultFromScode(E_FAIL);
+ }
+
+ // Release the clipboard data object's extra add ref.
+
+ pIDO->Release();
+
+ // Release the clipboard's data object entirely.
+
+ pIDO->Release();
+
+ // the reference count on our data object should be 2 still
+
+ cRefs = pDO->AddRef();
+
+ if( cRefs != 3 )
+ {
+ OutputString("Wrong ref count!! Should be 3, was %lu\r\n",
+ cRefs);
+ return ResultFromScode(E_FAIL);
+ }
+
+ pDO->Release();
+
+ // now check to see if the we are the current clipboard
+
+ hresult = OleIsCurrentClipboard( pDO );
+
+ if( hresult != NOERROR )
+ {
+ OutputString("OleIsCurrentClipboard failed! (%lx)\r\n",
+ hresult);
+ return hresult;
+ }
+
+ // now flush the clipboard, removing the data object
+
+ hresult = OleFlushClipboard();
+
+ if( hresult != NOERROR )
+ {
+ OutputString("OleFlushClipboard failed! (%lx)\r\n", hresult);
+ return hresult;
+ }
+
+ // Flush should have released the data object (ref count should
+ // be 1)
+
+ cRefs = pDO->AddRef();
+
+ if( cRefs != 2 )
+ {
+ OutputString("Wrong ref count!! Should be 2, was %lu\r\n",
+ cRefs);
+ return ResultFromScode(E_FAIL);
+ }
+
+ pDO->Release(); // take it down to 1
+ cRefs = pDO->Release(); // should be zero now
+
+ if(cRefs != 0 )
+ {
+ OutputString("Wrong ref count on data transfer object! "
+ "Unable to delete\r\n");
+ return ResultFromScode(E_FAIL);
+ }
+
+ // if we got this far, basic clipboard tests passed
+
+ OutputString("Basic Clipboard tests passed\r\n");
+
+ // now stress individual API's
+
+ OutputString("Now stressing clipboard API's\r\n");
+
+ if( (hresult = StressOleFlushClipboard()) != NOERROR )
+ {
+ return hresult;
+ }
+
+ if( (hresult = StressOleGetClipboard()) != NOERROR )
+ {
+ return hresult;
+ }
+
+ if( (hresult = StressOleIsCurrentClipboard()) != NOERROR )
+ {
+ return hresult;
+ }
+
+ if( (hresult = StressOleSetClipboard()) != NOERROR )
+ {
+ return hresult;
+ }
+
+ OutputString("Clipoard API stress passed!\r\n");
+
+ return NOERROR;
+
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: LEClipTest2
+//
+// Synopsis: Tests the clipboard data object
+//
+// Effects:
+//
+// Arguments: void
+//
+// Requires:
+//
+// Returns: HRESULT
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 15-Apr-94 alexgo author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+HRESULT LEClipTest2( void )
+{
+ CGenDataObject * pGenData;
+ IDataObject * pDataObj;
+ HRESULT hresult;
+ IEnumFORMATETC * penum;
+ FORMATETC formatetc;
+ STGMEDIUM medium;
+ ULONG cRefs;
+
+ pGenData = new CGenDataObject();
+
+ assert(pGenData);
+
+ cRefs = pGenData->AddRef();
+
+ // ref count should be 1
+
+ assert(cRefs == 1);
+
+ hresult = OleSetClipboard(pGenData);
+
+ if( hresult != NOERROR )
+ {
+ OutputString("Clip2: OleSetClipboard failed! (%lx)\r\n",
+ hresult);
+ goto errRtn2;
+ }
+
+ hresult = OleFlushClipboard();
+
+ if( hresult != NOERROR )
+ {
+ OutputString("Clip2: OleFlushClipboard failed! (%lx)\r\n",
+ hresult);
+ goto errRtn2;
+ }
+
+ // get the fake clipboard data object
+
+ hresult = OleGetClipboard(&pDataObj);
+
+ if( hresult != NOERROR )
+ {
+ OutputString("Clip2: OleGetClipboard failed! (%lx)\r\n",
+ hresult);
+ goto errRtn2;
+ }
+
+ hresult = pDataObj->EnumFormatEtc(DATADIR_GET, &penum);
+
+ if( hresult != NOERROR )
+ {
+ OutputString("Clip2: EnumFormatEtc failed! (%lx)\r\n",
+ hresult);
+ goto errRtn;
+ }
+
+ while( penum->Next( 1, &formatetc, NULL ) == NOERROR )
+ {
+ if( formatetc.cfFormat == pGenData->m_cfTestStorage ||
+ formatetc.cfFormat == pGenData->m_cfEmbeddedObject )
+ {
+ // we should be told IStorage
+
+ if( !(formatetc.tymed & TYMED_ISTORAGE) )
+ {
+ hresult = ResultFromScode(E_FAIL);
+ OutputString("medium mismatch, ISTORAGE");
+ break;
+ }
+ }
+
+ hresult = pDataObj->GetData(&formatetc, &medium);
+
+ if( hresult != NOERROR )
+ {
+ break;
+ }
+
+ // verify the data
+
+ if( !pGenData->VerifyFormatAndMedium(&formatetc, &medium) )
+ {
+ hresult = ResultFromScode(E_FAIL);
+ OutputString("Clip2: retrieved data doesn't match! "
+ "cf == %d\r\n", formatetc.cfFormat);
+ break;
+ }
+
+ ReleaseStgMedium(&medium);
+
+ memset(&medium, 0, sizeof(STGMEDIUM));
+
+ }
+
+ {
+ CClipEnumeratorTest cet(penum, -1, hresult);
+
+ if (hresult == S_OK)
+ {
+ hresult = cet.TestAll();
+ }
+ }
+
+ penum->Release();
+
+
+errRtn:
+ pDataObj->Release();
+
+errRtn2:
+ pGenData->Release();
+
+ if( hresult == NOERROR )
+ {
+ OutputString("Clipboard data object tests Passed!\r\n");
+ }
+
+ return hresult;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: LEOle1ClipTest1
+//
+// Synopsis: Simple tests of OLE1 clipboard compatibility (copy from
+// and OLE1 server)
+//
+// Effects:
+//
+// Arguments:
+//
+// Requires:
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm: Run through 15 combinations of OLE1 support and verify
+// everything came out OK
+//
+// History: dd-mmm-yy Author Comment
+// 06-Jun-94 alexgo author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+HRESULT LEOle1ClipTest1( void )
+{
+ HRESULT hresult;
+ DWORD flags;
+ CGenDataObject * pGenData = NULL;
+ IDataObject * pDataObj = NULL;
+ IEnumFORMATETC * penum = NULL;
+ FORMATETC formatetc;
+ STGMEDIUM medium;
+
+ // we are going to take advantage of the fact that the interesting
+ // OLE1 bit flags for this test are the bottom 4 bits.
+
+ pGenData = new CGenDataObject();
+
+ assert(pGenData);
+
+ for( flags = 1; flags < 16; flags++ )
+ {
+ // test #8 is not interesting (because no ole1
+ // formats are offered on the clipboard
+
+ if( (Ole1TestFlags)flags == OLE1_OWNERLINK_PRECEDES_NATIVE )
+ {
+ continue;
+ }
+
+ // setup the OLE1 mode desired
+
+ pGenData->SetupOle1Mode((Ole1TestFlags)flags);
+
+
+ hresult = pGenData->SetOle1ToClipboard();
+
+ if( hresult != NOERROR )
+ {
+ goto errRtn;
+ }
+
+ // log the formats that are currently on the clipboard
+ DumpClipboardFormats(vApp.m_fpLog);
+
+ // get the fake clipboard data object
+
+ hresult = OleGetClipboard(&pDataObj);
+
+ if( hresult != NOERROR )
+ {
+ OutputString("Ole1Clip1: OleGetClipboard failed! "
+ "(%lx)\r\n", hresult);
+ goto errRtn;
+ }
+
+ hresult = pDataObj->EnumFormatEtc(DATADIR_GET, &penum);
+
+ if( hresult != NOERROR )
+ {
+ OutputString("Ole1Clip1: EnumFormatEtc failed! "
+ "(%lx)\r\n", hresult);
+ goto errRtn;
+ }
+
+ while( penum->Next( 1, &formatetc, NULL ) == NOERROR )
+ {
+ DumpFormatetc(&formatetc, vApp.m_fpLog);
+
+#ifdef WIN32
+ hresult = pDataObj->GetData(&formatetc, &medium);
+
+ if( hresult != NOERROR )
+ {
+ goto errRtn;
+ }
+
+ // verify the data
+
+ if( !pGenData->VerifyFormatAndMedium(&formatetc,
+ &medium) )
+ {
+ hresult = ResultFromScode(E_FAIL);
+ OutputString("Ole1Clip1: retrieved data "
+ "doesn't match! cf == %d\r\n",
+ formatetc.cfFormat);
+ goto errRtn;
+ }
+
+ ReleaseStgMedium(&medium);
+
+ memset(&medium, 0, sizeof(STGMEDIUM));
+
+#endif // WIN32
+ }
+
+ // now release everything
+
+ penum->Release();
+ penum = NULL;
+ pDataObj->Release();
+ pDataObj = NULL;
+ }
+
+errRtn:
+
+ if( penum )
+ {
+ penum->Release();
+ }
+
+ if( pDataObj )
+ {
+ pDataObj->Release();
+ }
+
+ if( pGenData )
+ {
+ pGenData->Release();
+ }
+
+ return hresult;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: LEOle1ClipTest2
+//
+// Synopsis: Tests OLE1 container support via the clipboard
+//
+// Effects:
+//
+// Arguments:
+//
+// Requires:
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm: Start cntroutl, tell it to copy a simpsvr object to the
+// clipboard. Check the clipboard to make sure OLE1 formats
+// are available.
+//
+// We do this by sheduling a function to check the clipboard
+// after we've launched the standard copy-to-clipboard
+// routines.
+//
+// History: dd-mmm-yy Author Comment
+// 16-Jun-94 alexgo author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+void LEOle1ClipTest2( void *pv )
+{
+ // this will get triggered by the return of WM_TEST1 from
+ // container outline
+
+ vApp.m_TaskStack.Push(RunApi, (void *)LEOle1ClipTest2Callback);
+
+ vApp.m_TaskStack.Push(LETest1, (void *)&letiClipTest);
+
+ // now post a message to ourselves to get things rollling
+
+ PostMessage(vApp.m_hwndMain, WM_TEST1, 0, 0);
+
+ return;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: LEOle1ClipTest2Callback
+//
+// Synopsis: checks the clipboard for OLE1 formats
+//
+// Effects:
+//
+// Arguments: [pv] -- unused
+//
+// Requires:
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 20-Aug-94 alexgo updated to cfObjectLink test
+// 16-Jun-94 alexgo author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+HRESULT LEOle1ClipTest2Callback( void )
+{
+ HRESULT hresult;
+ IDataObject * pDO;
+ IEnumFORMATETC *penum;
+ FORMATETC formatetc;
+ BOOL fGotNative = FALSE,
+ fGotOwnerLink = FALSE,
+ fGotObjectLink = FALSE;
+ UINT cfNative,
+ cfOwnerLink,
+ cfObjectLink;
+
+ cfNative = RegisterClipboardFormat("Native");
+ cfOwnerLink = RegisterClipboardFormat("OwnerLink");
+ cfObjectLink = RegisterClipboardFormat("ObjectLink");
+
+ assert(vApp.m_message == WM_TEST1);
+
+ hresult = (HRESULT)vApp.m_wparam;
+
+ if( hresult != NOERROR )
+ {
+ return hresult;
+ }
+
+ // we need to wait for cntroutl to shut down before
+ // fetching the clipboard
+
+ while( (hresult = OleGetClipboard(&pDO)) != NOERROR )
+ {
+ if( hresult != ResultFromScode(CLIPBRD_E_CANT_OPEN) )
+ {
+ return hresult;
+ }
+ }
+
+ hresult = pDO->EnumFormatEtc(DATADIR_GET, &penum);
+
+ if( hresult != NOERROR )
+ {
+ return hresult;
+ }
+
+ while( penum->Next(1, &formatetc, NULL) == NOERROR )
+ {
+ if( formatetc.cfFormat == cfNative )
+ {
+ fGotNative = TRUE;
+ }
+ else if( formatetc.cfFormat == cfOwnerLink )
+ {
+ fGotOwnerLink = TRUE;
+ }
+ else if( formatetc.cfFormat == cfObjectLink )
+ {
+ fGotObjectLink = TRUE;
+ }
+ }
+
+ penum->Release();
+ pDO->Release();
+
+ // the OLE1 container compatibility code should put
+ // OLE1 formats on the clipboard. However, they should NOT
+ // be in the enumerator since the stuff was copied from
+ // an OLE2 container.
+
+ if( (fGotNative || fGotOwnerLink || fGotObjectLink) )
+ {
+ hresult = ResultFromScode(E_FAIL);
+ return hresult;
+ }
+
+ if( IsClipboardFormatAvailable(cfNative) )
+ {
+ fGotNative = TRUE;
+ }
+
+ if( IsClipboardFormatAvailable(cfOwnerLink) )
+ {
+ fGotOwnerLink = TRUE;
+ }
+
+ if( IsClipboardFormatAvailable(cfObjectLink) )
+ {
+ fGotObjectLink = TRUE;
+ }
+
+ // NB!! only Native and OwnerLink should be on the clipboard
+ // this test puts an OLE2 *embedding* on the clipbaord, which
+ // an OLE1 container cannot link to. So ObjectLink should not
+ // be available
+
+ if( !(fGotNative && fGotOwnerLink && !fGotObjectLink) )
+ {
+ hresult = ResultFromScode(E_FAIL);
+
+ }
+
+ return hresult;
+}
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: StressOleFlushClipboard
+//
+// Synopsis:
+//
+// Effects:
+//
+// Arguments: void
+//
+// Requires:
+//
+// Returns: HRESULT
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm: stresses the following cases:
+// 1. Caller is not the clipboard owner (somebody else put
+// data on the clipboard)
+// 2. somebody else has the clipboard open
+// 3. OleFlushClipboard is called twice (second attempt should
+// not fail).
+//
+// History: dd-mmm-yy Author Comment
+// 28-Mar-94 alexgo author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+HRESULT StressOleFlushClipboard(void)
+{
+ HRESULT hresult;
+ CGenDataObject *pDO;
+ ULONG cRefs;
+
+ OutputString("Now stressing OleFlushClipboard() \r\n");
+
+ pDO = new CGenDataObject();
+
+ assert(pDO);
+
+ pDO->AddRef(); //initial count of 1
+
+ //take ownership of the clipboard
+
+ if( !OpenClipboard(vApp.m_hwndMain) )
+ {
+ OutputString("Can't OpenClipboard! \r\n");
+ return ResultFromScode(CLIPBRD_E_CANT_OPEN);
+ }
+
+ if( !EmptyClipboard() )
+ {
+ OutputString("Can't EmptyClipboard! \r\n");
+ return ResultFromScode(CLIPBRD_E_CANT_EMPTY);
+ }
+
+ if( !CloseClipboard() )
+ {
+ OutputString("Can't CloseClipboard! \r\n");
+ return ResultFromScode(CLIPBRD_E_CANT_CLOSE);
+ }
+
+ // now to flush the clipboard; we should get E_FAIL
+
+ hresult = OleFlushClipboard();
+
+ if( hresult != ResultFromScode(E_FAIL) )
+ {
+ OutputString("Unexpected hresult:(%lx)\r\n", hresult);
+ return (hresult) ? hresult : ResultFromScode(E_UNEXPECTED);
+ }
+
+ // now put something on the clipboard so we can flush it
+
+ hresult = OleSetClipboard(pDO);
+
+ if( hresult != NOERROR )
+ {
+ OutputString("OleSetClipboard failed! (%lx)\r\n", hresult);
+ return hresult;
+ }
+
+ // open the clipboard with us
+
+ if( !OpenClipboard(vApp.m_hwndMain) )
+ {
+ OutputString("Can't OpenClipboard!\r\n");
+ return ResultFromScode(CLIPBRD_E_CANT_OPEN);
+ }
+
+ // OleFlushClipboard should return with CLIPBRD_E_CANT_OPEN
+ // since another window has the clipboard open
+
+ hresult = OleFlushClipboard();
+
+ if( hresult != ResultFromScode(CLIPBRD_E_CANT_OPEN) )
+ {
+ OutputString("Unexpected hresult:(%lx)\r\n", hresult);
+ return (hresult)? hresult :ResultFromScode(E_UNEXPECTED);
+ }
+
+ cRefs = pDO->AddRef();
+
+ // cRefs should be 3 (one from beginning, one from OleSetClipboard
+ // and 1 from above. OleFlushClipboard should *not* remove the
+ // count for the above failure case)
+
+ if( cRefs != 3 )
+ {
+ OutputString("Bad ref count, was %lu, should be 3\r\n",
+ cRefs);
+ return ResultFromScode(E_FAIL);
+ }
+
+ // undo the most recent addref above
+ pDO->Release();
+
+ // close the clipboard
+
+ if( !CloseClipboard() )
+ {
+ OutputString("Can't CloseClipboard!\r\n");
+ return ResultFromScode(CLIPBRD_E_CANT_CLOSE);
+ }
+
+ // now call OleFlushClipboard for real
+
+ hresult = OleFlushClipboard();
+
+ if( hresult != NOERROR )
+ {
+ OutputString("OleFlushClipboard failed! (%lx)\r\n", hresult);
+ return hresult;
+ }
+
+ // now call it once more
+
+ hresult = OleFlushClipboard();
+
+ if( hresult != NOERROR )
+ {
+ OutputString("Second call to OleFlushClipboard should not"
+ "have failed! (%lx)\r\n", hresult);
+ return hresult;
+ }
+
+ // there should have only been 1 release from the first
+ // OleFlushClipboard call. This next release should nuke the object
+
+ cRefs = pDO->Release();
+
+ if( cRefs != 0 )
+ {
+ OutputString("Bad ref count, was %lu, should be 0\r\n", cRefs);
+ return ResultFromScode(E_FAIL);
+ }
+
+ return NOERROR;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: StressOleGetClipboard
+//
+// Synopsis:
+//
+// Effects:
+//
+// Arguments: void
+//
+// Requires:
+//
+// Returns: HRESULT
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm: tests the following cases:
+// 1. somebody else has the clipboard open
+//
+// History: dd-mmm-yy Author Comment
+// 28-Mar-94 alexgo author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+HRESULT StressOleGetClipboard(void)
+{
+ HRESULT hresult;
+ IDataObject * pIDO;
+ CGenDataObject *pDO;
+ ULONG cRefs;
+
+ OutputString("Stressing OleGetClipboard()\r\n");
+
+ pDO = new CGenDataObject();
+
+ assert(pDO);
+
+ pDO->AddRef();
+
+ hresult = OleSetClipboard(pDO);
+
+ if( hresult != NOERROR )
+ {
+ OutputString("OleSetClipboard failed! (%lx)\r\n", hresult);
+ return hresult;
+ }
+
+ if( !OpenClipboard(vApp.m_hwndMain) )
+ {
+ OutputString("Can't OpenClipboard!\r\n");
+ return ResultFromScode(CLIPBRD_E_CANT_OPEN);
+ }
+
+ hresult = OleGetClipboard(&pIDO);
+
+ if( hresult != ResultFromScode(CLIPBRD_E_CANT_OPEN) )
+ {
+ OutputString("Unexpected hresult (%lx)\r\n", hresult);
+ return (hresult) ? hresult : ResultFromScode(E_UNEXPECTED);
+ }
+
+ // the ref count should not have gone up
+
+ cRefs = pDO->AddRef();
+
+ if( cRefs != 3 )
+ {
+ OutputString("Bad ref count, was %lu, should be 3\r\n", cRefs);
+ return ResultFromScode(E_FAIL);
+ }
+
+ pDO->Release();
+
+ // now clear stuff out and go home
+
+ if( !CloseClipboard() )
+ {
+ OutputString("CloseClipboard failed!\r\n");
+ return ResultFromScode(E_FAIL);
+ }
+
+ // this should clear the clipboard
+
+ hresult = OleSetClipboard(NULL);
+
+ if( hresult != NOERROR )
+ {
+ OutputString("OleSetClipboard failed! (%lx)\r\n", hresult);
+ return hresult;
+ }
+
+ // this should be the final release on the object
+
+ cRefs = pDO->Release();
+
+ if( cRefs != 0 )
+ {
+ OutputString("Bad ref count, was %lu, should be 0\r\n", cRefs);
+ return ResultFromScode(E_FAIL);
+ }
+
+ return NOERROR;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: StressOleIsCurrentClipboard
+//
+// Synopsis:
+//
+// Effects:
+//
+// Arguments: void
+//
+// Requires:
+//
+// Returns: HRESULT
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm: tests the following cases
+// 1. the caller is not the clipboard owner
+// 2. somebody else has the clipboard open
+// 2. the data object is NULL
+// 3. the data object is not the data object put on the clipboard
+//
+// History: dd-mmm-yy Author Comment
+// 28-Mar-94 alexgo author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+HRESULT StressOleIsCurrentClipboard(void)
+{
+ HRESULT hresult;
+ CGenDataObject *pDO, *pDO2;
+ ULONG cRefs;
+
+ OutputString("Stressing OleIsCurrentClipboard()\r\n");
+
+ pDO = new CGenDataObject();
+ pDO2 = new CGenDataObject();
+
+ assert(pDO);
+ assert(pDO2);
+
+ pDO->AddRef();
+ pDO2->AddRef();
+
+ //take ownership of the clipboard
+
+ if( !OpenClipboard(vApp.m_hwndMain) )
+ {
+ OutputString("Can't OpenClipboard! \r\n");
+ return ResultFromScode(CLIPBRD_E_CANT_OPEN);
+ }
+
+ if( !EmptyClipboard() )
+ {
+ OutputString("Can't EmptyClipboard! \r\n");
+ return ResultFromScode(CLIPBRD_E_CANT_EMPTY);
+ }
+
+ if( !CloseClipboard() )
+ {
+ OutputString("Can't CloseClipboard! \r\n");
+ return ResultFromScode(CLIPBRD_E_CANT_CLOSE);
+ }
+
+ // now to flush the clipboard; we should get S_FALSE
+
+ hresult = OleIsCurrentClipboard(pDO);
+
+ if( hresult != ResultFromScode(S_FALSE) )
+ {
+ OutputString("Unexpected hresult:(%lx)\r\n", hresult);
+ return (hresult) ? hresult : ResultFromScode(E_UNEXPECTED);
+ }
+
+
+ // now set the clipboard and test w/ the clipboard open
+ // we should not fail in this case
+
+ hresult = OleSetClipboard(pDO);
+
+ if( hresult != NOERROR )
+ {
+ OutputString("OleSetClipboard failed! (%lx)\r\n", hresult);
+ return hresult;
+ }
+
+ if( !OpenClipboard(vApp.m_hwndMain) )
+ {
+ OutputString("Can't OpenClipboard!\r\n");
+ return ResultFromScode(CLIPBRD_E_CANT_OPEN);
+ }
+
+ hresult = OleIsCurrentClipboard(pDO);
+
+ if( hresult != NOERROR )
+ {
+ OutputString("Unexpected hresult (%lx)\r\n", hresult);
+ return (hresult) ? hresult : ResultFromScode(E_UNEXPECTED);
+ }
+
+ // the ref count should not have gone up
+
+ cRefs = pDO->AddRef();
+
+ if( cRefs != 3 )
+ {
+ OutputString("Bad ref count, was %lu, should be 3\r\n", cRefs);
+ return ResultFromScode(E_FAIL);
+ }
+
+ pDO->Release();
+
+ // now close the clipboard
+
+ if( !CloseClipboard() )
+ {
+ OutputString("CloseClipboard failed!\r\n");
+ return ResultFromScode(E_FAIL);
+ }
+
+ // now test for passing NULL
+
+ hresult = OleIsCurrentClipboard(NULL);
+
+ if( hresult != ResultFromScode(S_FALSE) )
+ {
+ OutputString("Unexpected hresult (%lx)\r\n", hresult);
+ return (hresult)? hresult : ResultFromScode(E_FAIL);
+ }
+
+ // now test for passign other pointer
+
+ hresult = OleIsCurrentClipboard(pDO2);
+
+ if( hresult != ResultFromScode(S_FALSE) )
+ {
+ OutputString("Unexpected hresult (%lx)\r\n", hresult);
+ return (hresult)? hresult : ResultFromScode(E_FAIL);
+ }
+
+ // now clean stuff up and go home
+
+ hresult = OleSetClipboard(NULL);
+
+ if( hresult != NOERROR )
+ {
+ OutputString("OleSetClipboard(NULL) failed!! (%lx)\r\n",
+ hresult);
+ return hresult;
+ }
+
+ cRefs = pDO->Release();
+
+ // cRefs should be 0 now
+
+ if( cRefs != 0 )
+ {
+ OutputString("Bad ref count, was %lu, should be 0\r\n", cRefs);
+ return ResultFromScode(E_FAIL);
+ }
+
+
+ pDO2->Release();
+
+ return NOERROR;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: StressOleSetClipboard
+//
+// Synopsis:
+//
+// Effects:
+//
+// Arguments: void
+//
+// Requires:
+//
+// Returns: HRESULT
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm: tests the following cases:
+// 1. somebody else has the clipboard open
+// 2. Do OleSetClipboard with data and then
+// OleSetClipboard(NULL) to clear it out
+//
+// History: dd-mmm-yy Author Comment
+// 28-Mar-94 alexgo author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+HRESULT StressOleSetClipboard(void)
+{
+ HRESULT hresult;
+ CGenDataObject *pDO;
+ ULONG cRefs;
+
+ OutputString("Stressing OleGetClipboard()\r\n");
+
+ pDO = new CGenDataObject();
+
+ assert(pDO);
+
+ pDO->AddRef();
+
+
+ if( !OpenClipboard(vApp.m_hwndMain) )
+ {
+ OutputString("Can't OpenClipboard!\r\n");
+ return ResultFromScode(CLIPBRD_E_CANT_OPEN);
+ }
+
+ hresult = OleSetClipboard(pDO);
+
+ if( hresult != ResultFromScode(CLIPBRD_E_CANT_OPEN) )
+ {
+ OutputString("Unexpected hresult (%lx)\r\n", hresult);
+ return (hresult) ? hresult : ResultFromScode(E_UNEXPECTED);
+ }
+
+ // the ref count should not have gone up
+
+ cRefs = pDO->AddRef();
+
+ if( cRefs != 2 )
+ {
+ OutputString("Bad ref count, was %lu, should be 2\r\n", cRefs);
+ return ResultFromScode(E_FAIL);
+ }
+
+ pDO->Release();
+
+ if( !CloseClipboard() )
+ {
+ OutputString("CloseClipboard failed!\r\n");
+ return ResultFromScode(E_FAIL);
+ }
+
+ // now really set the clipboard so we can try to clear it
+
+ hresult = OleSetClipboard(pDO);
+
+ if( hresult != NOERROR )
+ {
+ OutputString("OleSetClipboard failed! (%lx)\r\n", hresult);
+ return hresult;
+ }
+
+ // this should clear the clipboard
+
+ hresult = OleSetClipboard(NULL);
+
+ if( hresult != NOERROR )
+ {
+ OutputString("OleSetClipboard failed! (%lx)\r\n", hresult);
+ return hresult;
+ }
+
+ // this should be the final release on the object
+
+ cRefs = pDO->Release();
+
+ if( cRefs != 0 )
+ {
+ OutputString("Bad ref count, was %lu, should be 0\r\n", cRefs);
+ return ResultFromScode(E_FAIL);
+ }
+
+ return NOERROR;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: TestOleQueryCreateFromDataMFCHack
+//
+// Synopsis: tests the MFC hack put into OleQueryCreateFromData
+//
+// Effects:
+//
+// Arguments: void
+//
+// Requires:
+//
+// Returns: HRESULT
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm: create a data object that offers private data
+// put on the clipboard and then retrieve the clipboard data
+// object.
+// Call OleQueryCreateFromData on clipboard data object--
+// QI for IPS should not be called
+// Call OleQueryCreateFromData on generic data object
+// QI for IPS should be called
+// set EmbeddedObject on the generic data object
+// Call OleQueryCreateFromData; should return S_OK
+//
+// History: dd-mmm-yy Author Comment
+// 23-Aug-94 alexgo author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+HRESULT TestOleQueryCreateFromDataMFCHack( void )
+{
+ CGenDataObject * pgendata;
+ IDataObject * pdataobj;
+ HRESULT hresult;
+
+
+ pgendata = new CGenDataObject();
+
+ assert(pgendata);
+
+ pgendata->AddRef();
+
+ pgendata->SetDataFormats(OFFER_TESTSTORAGE);
+
+ hresult = OleSetClipboard(pgendata);
+
+ if( hresult != NOERROR )
+ {
+ return hresult;
+ }
+
+ hresult = OleGetClipboard(&pdataobj);
+
+ if( hresult != NOERROR )
+ {
+ return hresult;
+ }
+
+ hresult = OleQueryCreateFromData(pdataobj);
+
+ // for a clipboard data object, we should not call QueryInterface
+ // for IPersistStorage.
+
+
+ if( hresult != S_FALSE || pgendata->HasQIBeenCalled() == TRUE )
+ {
+ return ResultFromScode(E_FAIL);
+ }
+
+ // for other data objects, if there are no OLE2 formats, then
+ // we should call QI for IPersistStorage
+
+ hresult = OleQueryCreateFromData(pgendata);
+
+ if( hresult != S_FALSE || pgendata->HasQIBeenCalled() == FALSE )
+ {
+ return ResultFromScode(E_FAIL);
+ }
+
+ // now clear the clipboard and continue testing
+
+ pdataobj->Release();
+ hresult = OleSetClipboard(NULL);
+
+ if( hresult != NOERROR )
+ {
+ return hresult;
+ }
+
+ pgendata->SetDataFormats(OFFER_EMBEDDEDOBJECT);
+
+ hresult = OleQueryCreateFromData(pgendata);
+
+ // we just set OLE2 data on the data object. OQCFD should return
+ // S_OK
+
+ if( hresult != NOERROR )
+ {
+ return ResultFromScode(E_FAIL);
+ }
+
+ if( pgendata->Release() == 0 )
+ {
+ return NOERROR;
+ }
+ else
+ {
+ return ResultFromScode(E_FAIL);
+ }
+
+}
+
+
diff --git a/private/oleutest/oletest/cotest.h b/private/oleutest/oletest/cotest.h
new file mode 100644
index 000000000..93628a63c
--- /dev/null
+++ b/private/oleutest/oletest/cotest.h
@@ -0,0 +1,25 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: cotest.h
+//
+// Contents: declarations for all compobj test routines
+//
+// Classes:
+//
+// Functions:
+//
+// History: dd-mmm-yy Author Comment
+// 02-Nov-94 ricksa author
+//
+//--------------------------------------------------------------------------
+
+#ifndef _COTEST_H
+#define _COTEST_H
+
+HRESULT ThreadUnitTest(void);
+
+
+#endif // _COTEST_H
diff --git a/private/oleutest/oletest/dataadv.cpp b/private/oleutest/oletest/dataadv.cpp
new file mode 100644
index 000000000..90562a4bf
--- /dev/null
+++ b/private/oleutest/oletest/dataadv.cpp
@@ -0,0 +1,1432 @@
+//+------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: cliptest.cpp
+//
+// Contents: Data Advise Holder tests
+//
+// Classes: CDataAdviseTestFormatEtc
+// CTestAdviseSink
+// CTestDaHolder
+//
+// Functions: TestPrimeFirstOnlyOnceNoData
+// TestPrimeFirstOnlyOnceData
+// DoRegisterNotifyDeregister
+// TestRegisterNotifyDegister
+// TestRegisterNotifyDegisterNoData
+// TestNotifyOnStop
+// TestNotifyOnce
+// CreateMassRegistration
+// DoMassUnadvise
+// TestEnumerator
+// LEDataAdviseHolderTest
+//
+// History: dd-mmm-yy Author Comment
+// 25-May-94 ricksa author
+//
+//--------------------------------------------------------------------------
+
+#include "oletest.h"
+#include "gendata.h"
+#include "genenum.h"
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Class: CDataAdviseTestFormatEtc
+//
+// Purpose: Hold FORMATETC used by the data advise holder unit tests
+//
+// Interface: GetFormatEtc - get a pointer to the FORMATETC
+//
+// History: dd-mmm-yy Author Comment
+// 01-Jun-94 Ricksa Created
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+class CDataAdviseTestFormatEtc
+{
+public:
+ CDataAdviseTestFormatEtc(void);
+
+ FORMATETC * GetFormatEtc(void);
+
+private:
+
+ FORMATETC _formatetc;
+};
+
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Member: CDataAdviseTestFormatEtc::CDataAdviseTestFormatEtc
+//
+// Synopsis: Initialize object
+//
+// History: dd-mmm-yy Author Comment
+// 01-Jun-94 Ricksa Created
+//
+//--------------------------------------------------------------------------
+CDataAdviseTestFormatEtc::CDataAdviseTestFormatEtc(void)
+{
+ _formatetc.cfFormat = RegisterClipboardFormat("OleTest Storage Format");
+ _formatetc.ptd = NULL;
+ _formatetc.dwAspect = DVASPECT_CONTENT;
+ _formatetc.lindex = -1;
+ _formatetc.tymed = TYMED_ISTORAGE;
+}
+
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Member: CDataAdviseTestFormatEtc::GetFormatEtc
+//
+// Synopsis: Get pointer to standard format etc
+//
+// History: dd-mmm-yy Author Comment
+// 01-Jun-94 Ricksa Created
+//
+//--------------------------------------------------------------------------
+FORMATETC *CDataAdviseTestFormatEtc::GetFormatEtc(void)
+{
+ return &_formatetc;
+}
+
+
+
+
+// Global Formatec for all the data advise tests
+CDataAdviseTestFormatEtc g_datfeDaTest;
+
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Class: CTestAdviseSink
+//
+// Purpose: Advise sink used to verify data advise holder
+//
+// Interface: QueryInterface - get new interface pointer
+// AddRef - bump reference count
+// Release - decrement reference count
+// OnDataChange - data change notification
+// OnViewChange - not implemented
+// OnRename - not implemented
+// OnSave - not implemented
+// OnClose - not implemented
+// ValidOnDataChange - verify all expected data change notification
+//
+// History: dd-mmm-yy Author Comment
+// 01-Jun-94 Ricksa Created
+//
+// Notes: We only implement interface methods required for
+// test of data advise holder.
+//
+//--------------------------------------------------------------------------
+class CTestAdviseSink : public IAdviseSink
+{
+public:
+ CTestAdviseSink(CGenDataObject *pgdo);
+
+ // IUnknown methods
+ STDMETHOD(QueryInterface)(REFIID riid, LPVOID FAR* ppvObj);
+
+ STDMETHOD_(ULONG, AddRef)(void);
+
+ STDMETHOD_(ULONG, Release)(void);
+
+ // IAdviseSink methods
+ STDMETHOD_(void, OnDataChange)(FORMATETC *pFormatetc, STGMEDIUM *pStgmed);
+
+ STDMETHOD_(void, OnViewChange)(
+ DWORD dwAspect,
+ LONG lindex);
+
+ STDMETHOD_(void, OnRename)(IMoniker *pmk);
+
+ STDMETHOD_(void, OnSave)(void);
+
+ STDMETHOD_(void, OnClose)(void);
+
+ // Test methods used for verification
+ BOOL ValidOnDataChange(void);
+
+private:
+
+ LONG _lRefs;
+
+ CGenDataObject * _pgdo;
+
+ BOOL _fValidOnDataChange;
+
+};
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Member: CTestAdviseSink::CTestAdviseSink
+//
+// Synopsis: Initialize object
+//
+// Arguments: [pgdo] - generic data object
+//
+// History: dd-mmm-yy Author Comment
+// 01-Jun-94 Ricksa Created
+//
+// Notes: pgdo being NULL means we don't expect a STGMEDIUM when
+// the OnDataChange notification occurs.
+//
+//--------------------------------------------------------------------------
+CTestAdviseSink::CTestAdviseSink(CGenDataObject *pgdo)
+ : _lRefs(1), _fValidOnDataChange(FALSE)
+{
+ _pgdo = pgdo;
+}
+
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Member: CTestAdviseSink::QueryInterface
+//
+// Synopsis: Return a new interface
+//
+// Arguments: [riid] - interface id requested
+// [ppvObj] - where to put the interface
+//
+// Returns: S_OK - we are returning an interface
+// E_NOINTERFACE - we do not support the requested interface
+//
+// History: dd-mmm-yy Author Comment
+// 01-Jun-94 Ricksa Created
+//
+//--------------------------------------------------------------------------
+STDMETHODIMP CTestAdviseSink::QueryInterface(
+ REFIID riid,
+ LPVOID *ppvObj)
+{
+ if (IsEqualGUID(IID_IUnknown, riid) || IsEqualGUID(IID_IAdviseSink, riid))
+ {
+ AddRef();
+ *ppvObj = this;
+ return NOERROR;
+ }
+
+ *ppvObj = NULL;
+
+ return E_NOINTERFACE;
+}
+
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Member: CTestAdviseSink::AddRef
+//
+// Synopsis: Bump reference count
+//
+// History: dd-mmm-yy Author Comment
+// 01-Jun-94 Ricksa Created
+//
+//--------------------------------------------------------------------------
+STDMETHODIMP_(ULONG) CTestAdviseSink::AddRef(void)
+{
+ return _lRefs++;
+}
+
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Member: CTestAdviseSink::Release
+//
+// Synopsis: Decrement reference count
+//
+// History: dd-mmm-yy Author Comment
+// 01-Jun-94 Ricksa Created
+//
+//--------------------------------------------------------------------------
+STDMETHODIMP_(ULONG) CTestAdviseSink::Release(void)
+{
+ assert(_lRefs >= 1);
+
+ return --_lRefs;
+}
+
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Member: CTestAdviseSink::OnDataChange
+//
+// Synopsis: Notify of change in data
+//
+// Arguments: [pFormatetc] - FORMATETC of data
+// [pStgmed] - storage medium for data
+//
+// Algorithm: Verify that the we recieved the expected FORMATEC. Then
+// verify that we recieved the expected STGMEDIUM.
+//
+// History: dd-mmm-yy Author Comment
+// 01-Jun-94 Ricksa Created
+//
+//--------------------------------------------------------------------------
+STDMETHODIMP_(void) CTestAdviseSink::OnDataChange(
+ FORMATETC *pFormatetc,
+ STGMEDIUM *pStgmed)
+{
+ // Verify the format
+ if (memcmp(g_datfeDaTest.GetFormatEtc(), pFormatetc, sizeof(FORMATETC))
+ == 0)
+ {
+ if (_pgdo != NULL)
+ {
+ // We have a data object that we can use to verify the format
+ // so we do.
+ _fValidOnDataChange =
+ _pgdo->VerifyFormatAndMedium(pFormatetc, pStgmed);
+ }
+ // We are expecting an empty STGMEDIUM so verify that it is
+ else if ((pStgmed->tymed == TYMED_NULL)
+ && (pStgmed->pUnkForRelease == NULL))
+ {
+ _fValidOnDataChange = TRUE;
+ }
+ }
+}
+
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Member: CTestAdviseSink::OnViewChange
+//
+// Synopsis: Notify that view should change
+//
+// Arguments: [dwAspect] - specifies view of the object
+// [lindex] - which piece of view changed
+//
+// History: dd-mmm-yy Author Comment
+// 01-Jun-94 Ricksa Created
+//
+// Notes: Not supported for this object
+//
+//--------------------------------------------------------------------------
+STDMETHODIMP_(void) CTestAdviseSink::OnViewChange(
+ DWORD dwAspect,
+ LONG lindex)
+{
+ OutputString("CTestAdviseSink::OnViewChange Unexpectedly Called!\r\n");
+}
+
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Member: CTestAdviseSink::OnRename
+//
+// Synopsis: Notifies of rename operation
+//
+// History: dd-mmm-yy Author Comment
+// 01-Jun-94 Ricksa Created
+//
+// Notes: Not supported for this object
+//
+//--------------------------------------------------------------------------
+STDMETHODIMP_(void) CTestAdviseSink::OnRename(IMoniker *pmk)
+{
+ OutputString("CTestAdviseSink::OnRename Unexpectedly Called!\r\n");
+}
+
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Member: CTestAdviseSink::OnSave
+//
+// Synopsis: Notify that object was saved
+//
+// History: dd-mmm-yy Author Comment
+// 01-Jun-94 Ricksa Created
+//
+// Notes: Not supported for this object
+//
+//--------------------------------------------------------------------------
+STDMETHODIMP_(void) CTestAdviseSink::OnSave(void)
+{
+ OutputString("CTestAdviseSink::OnSave Unexpectedly Called!\r\n");
+}
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Member: CTestAdviseSink::OnClose
+//
+// Synopsis: Notify object closed
+//
+// History: dd-mmm-yy Author Comment
+// 01-Jun-94 Ricksa Created
+//
+// Notes: Not supported for this object
+//
+//--------------------------------------------------------------------------
+STDMETHODIMP_(void) CTestAdviseSink::OnClose(void)
+{
+ OutputString("CTestAdviseSink::OnClose Unexpectedly Called!\r\n");
+}
+
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Member: CTestAdviseSink::ValidOnDataChange
+//
+// Synopsis: Verify that we recieved the expected OnDataChange notification
+//
+// History: dd-mmm-yy Author Comment
+// 01-Jun-94 Ricksa Created
+//
+//--------------------------------------------------------------------------
+BOOL CTestAdviseSink::ValidOnDataChange(void)
+{
+ BOOL fResult = _fValidOnDataChange;
+ _fValidOnDataChange = FALSE;
+ return fResult;
+}
+
+
+// Preallocated structure used to mass advise registration testing
+#define MAX_REGISTER 100
+struct
+{
+ CTestAdviseSink * ptas;
+ DWORD dwConnection;
+} aMassAdvise[MAX_REGISTER];
+
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Class: CTestDaHolder
+//
+// Purpose: Test enumerator for data advise holder
+//
+// Interface: Verify - verify particular entry being enumerated
+// VerifyAllEnmerated - verify all entries were enumerated once
+//
+// History: dd-mmm-yy Author Comment
+// 01-Jun-94 Ricksa Created
+//
+//--------------------------------------------------------------------------
+class CTestDaHolder : public CEnumeratorTest
+{
+public:
+
+ CTestDaHolder(IEnumSTATDATA *penumAdvise, HRESULT& rhr);
+
+ BOOL Verify(void *);
+
+ BOOL VerifyAllEnmerated(void);
+
+ BOOL VerifyAll(void *, LONG);
+
+private:
+
+ DWORD _cdwFound[MAX_REGISTER];
+};
+
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Member: CTestDaHolder::CTestDaHolder
+//
+// Synopsis: Initialize object
+//
+// Arguments: [penumAdvise] - data advise holder enumerator
+// [rhr] - HRESULT reference thorugh which to return an error
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 01-Jun-94 Ricksa Created
+//
+//--------------------------------------------------------------------------
+CTestDaHolder::CTestDaHolder(IEnumSTATDATA *penumAdvise, HRESULT& rhr)
+ : CEnumeratorTest(penumAdvise, sizeof(STATDATA), MAX_REGISTER, rhr)
+{
+ // Zero out our table of counts
+ memset(&_cdwFound[0], 0, sizeof(_cdwFound));
+}
+
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Member: CTestDaHolder::VerifyAllEnmerated
+//
+// Synopsis: Verify all objects got enumerated
+//
+// Returns: TRUE - all objects enumerated
+// FALSE - error in enumeration
+//
+// History: dd-mmm-yy Author Comment
+// 01-Jun-94 Ricksa Created
+//
+//--------------------------------------------------------------------------
+BOOL CTestDaHolder::VerifyAllEnmerated(void)
+{
+ for (int i = 0; i < MAX_REGISTER; i++)
+ {
+ if (_cdwFound[i] != 1)
+ {
+ OutputString("Entry %d enumerated %d times\r\n", i, _cdwFound[i]);
+ return FALSE;
+ }
+
+ // Reset for another test
+ _cdwFound[i] = 0;
+ }
+
+ return TRUE;
+}
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Member: CTestDaHolder::Verify
+//
+// Synopsis: Verify an enumeration entry
+//
+// Arguments: [pvEntry] - entry enumerated
+//
+// Returns: TRUE - enumerated entry is valid
+// FALSE - obvious error in enumeration
+//
+// History: dd-mmm-yy Author Comment
+// 01-Jun-94 Ricksa Created
+//
+//--------------------------------------------------------------------------
+BOOL CTestDaHolder::Verify(void *pvEntry)
+{
+ STATDATA *pstatdata = (STATDATA *) pvEntry;
+
+ // Verify the advf field
+ if ((pstatdata->advf == 0)
+ && (memcmp(g_datfeDaTest.GetFormatEtc(), &pstatdata->formatetc,
+ sizeof(FORMATETC)) == 0))
+ {
+ // Can we find the connection?
+ for (int i = 0; i < MAX_REGISTER; i++)
+ {
+ if (pstatdata->dwConnection == aMassAdvise[i].dwConnection)
+ {
+ // Bump found count
+ _cdwFound[i]++;
+
+ // Everything is OK so tell the caller
+ return TRUE;
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Member: CTestDaHolder::VerifyAll
+//
+// Synopsis: Verify that an array of all entries is valid
+//
+// Arguments: [pvEntries] - array of enumerated data
+// [clEntries] - number of enumerated entries
+//
+// Returns: TRUE - enumerated entry is valid
+// FALSE - obvious error in enumeration
+//
+// History: dd-mmm-yy Author Comment
+// 02-Jun-94 Ricksa Created
+//
+//--------------------------------------------------------------------------
+BOOL CTestDaHolder::VerifyAll(void *pvEntries, LONG clEntries)
+{
+ // Verify that the count is as expected.
+ if (clEntries != MAX_REGISTER)
+ {
+ return FALSE;
+ }
+
+ // Verify each entry in the array is reasonable
+ STATDATA *pstatdata = (STATDATA *) pvEntries;
+
+ for (int i = 0; i < MAX_REGISTER; i++, pstatdata++)
+ {
+ if (!Verify(pstatdata))
+ {
+ return FALSE;
+ }
+ }
+
+ // Verify that each entry was only referred to once
+ return VerifyAllEnmerated();
+}
+
+
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: TestPrimeFirstOnlyOnceNoData
+//
+// Synopsis: Test one notification of
+// ADVF_NODATA | ADVF_PRIMEFIRST | ADVF_ONLYONCE
+//
+// Arguments: [pdahTest] - data advise holder we are testing
+// [pgdo] - generic data object
+//
+// Returns: NOERROR - notification was correct
+// E_FAIL - error in notification
+//
+// Algorithm: Create an test advise sink object. Register it with the
+// advise holder which should cause the notification. Verify
+// that the advise was notified and that no connection was
+// returned.
+//
+// History: dd-mmm-yy Author Comment
+// 01-Jun-94 Ricksa Created
+//
+//--------------------------------------------------------------------------
+HRESULT TestPrimeFirstOnlyOnceNoData(
+ IDataAdviseHolder *pdahTest,
+ CGenDataObject *pgdo)
+{
+ // Create an advise sink - the NULL means we don't want to validate
+ // the STGMEDIUM.
+ CTestAdviseSink tas(NULL);
+
+ DWORD dwConnection = 0;
+
+ // Register the advise
+ HRESULT hr = pdahTest->Advise(pgdo, g_datfeDaTest.GetFormatEtc(),
+ ADVF_NODATA | ADVF_PRIMEFIRST | ADVF_ONLYONCE, &tas, &dwConnection);
+
+ // Confirm that the advise is notified and in the correct state
+ if (!tas.ValidOnDataChange())
+ {
+ OutputString("TestPrimeFirstOnlyOnceNoData OnDataChange invalid!\r\n");
+ return E_FAIL;
+ }
+
+ // Make sure the advise was not registered
+ if (dwConnection != 0)
+ {
+ OutputString("TestPrimeFirstOnlyOnceNoData got Connection!\r\n");
+ return E_FAIL;
+ }
+
+ return NOERROR;
+}
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: TestPrimeFirstOnlyOnceData
+//
+// Synopsis: Test one notification of
+// ADVF_PRIMEFIRST | ADVF_ONLYONCE
+//
+// Arguments: [pdahTest] - data advise holder we are testing
+// [pgdo] - generic data object
+//
+// Returns: NOERROR - notification was correct
+// E_FAIL - error in notification
+//
+// Algorithm: Create an test advise sink object. Register it with the
+// advise holder which should cause the notification. Verify
+// that the advise was notified and that no connection was
+// returned.
+//
+// History: dd-mmm-yy Author Comment
+// 01-Jun-94 Ricksa Created
+//
+//--------------------------------------------------------------------------
+HRESULT TestPrimeFirstOnlyOnceData(
+ IDataAdviseHolder *pdahTest,
+ CGenDataObject *pgdo)
+{
+ // Create an advise sink that we can verify the STGMEDIUM
+ CTestAdviseSink tas(pgdo);
+
+ // Where to store the connection
+ DWORD dwConnection = 0;
+
+ // Register the advise
+ HRESULT hr = pdahTest->Advise(pgdo, g_datfeDaTest.GetFormatEtc(),
+ ADVF_PRIMEFIRST | ADVF_ONLYONCE, &tas, &dwConnection);
+
+ // Confirm that the advise is notified and in the correct state
+ if (!tas.ValidOnDataChange())
+ {
+ OutputString("TestPrimeFirstOnlyOnceData OnDataChange invalid!\r\n");
+ return E_FAIL;
+ }
+
+ // Make sure the advise was not registered
+ if (dwConnection != 0)
+ {
+ OutputString("TestPrimeFirstOnlyOnceData got Connection!\r\n");
+ return E_FAIL;
+ }
+
+ return NOERROR;
+}
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: DoRegisterNotifyDeregister
+//
+// Synopsis:
+//
+// Arguments: [pdahTest] - data advise holder we are testing
+// [pdo] - IDataObject interface
+// [pgdo] - generic data object
+// [advf] - advise flags to use
+// [pszCaller] - name of test
+//
+// Returns: NOERROR - notification was correct
+// E_FAIL - error in notification
+//
+// Algorithm: Create a test advise sink object. Register for an notification
+// with the data advise holder. Confirm that the prime first
+// notification worked. Confirm that the object did get
+// registered. Tell the advise holder to notify all registered
+// advises that the data changed. Confirm that the appropriate
+// notification was sent. Then deregister the advise. Do it
+// again to make sure the connection is no longer valid.
+//
+// History: dd-mmm-yy Author Comment
+// 01-Jun-94 Ricksa Created
+//
+//--------------------------------------------------------------------------
+HRESULT DoRegisterNotifyDeregister(
+ IDataAdviseHolder *pdahTest,
+ IDataObject *pdo,
+ CGenDataObject *pgdo,
+ DWORD advf,
+ char *pszCaller)
+{
+ // Create an advise sink that we can verify the STGMEDIUM
+ CTestAdviseSink tas(pgdo);
+
+ // Where to store the connection
+ DWORD dwConnection;
+
+ // Register the advise
+ HRESULT hr = pdahTest->Advise(pdo, g_datfeDaTest.GetFormatEtc(),
+ ADVF_PRIMEFIRST | advf, &tas, &dwConnection);
+
+ // Confirm that the advise is notified and in the correct state
+ if (!tas.ValidOnDataChange())
+ {
+ OutputString("%s First OnDataChange invalid!\r\n", pszCaller);
+ return E_FAIL;
+ }
+
+ // Make sure the advise is registered
+ if (dwConnection == 0)
+ {
+ OutputString("%s did not get Connection!\r\n", pszCaller);
+ return E_FAIL;
+ }
+
+ // Test regular data change
+ hr = pdahTest->SendOnDataChange(pdo, 0, 0);
+
+ if (hr != NOERROR)
+ {
+ OutputString("%s SendOnDataChange unexpected HRESULT = %lx!\r\n",
+ pszCaller, hr);
+ return E_FAIL;
+ }
+
+ // Confirm that the advise is notified and in the correct state
+ if (!tas.ValidOnDataChange())
+ {
+ OutputString("%s Second OnDataChange invalid!\r\n", pszCaller);
+ return E_FAIL;
+ }
+
+ // Test unadvise
+ hr = pdahTest->Unadvise(dwConnection);
+
+ if (hr != NOERROR)
+ {
+ OutputString("%s Unadvise unexpected HRESULT = %lx!\r\n", pszCaller, hr);
+ return E_FAIL;
+ }
+
+ // Test second unadvise on the same connection
+ hr = pdahTest->Unadvise(dwConnection);
+
+ if (hr != OLE_E_NOCONNECTION)
+ {
+ OutputString("%s Second Unadvise Bad Hresult = %lx!\r\n", pszCaller, hr);
+ return E_FAIL;
+ }
+
+ return NOERROR;
+}
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: TestRegisterNotifyDegister
+//
+// Synopsis: Test a simple register/notify/deregister sequence
+//
+// Arguments: [pdahTest] - data advise holder we are testing
+// [pgdo] - generic data object
+//
+// Returns: NOERROR - notification was correct
+// E_FAIL - error in notification
+//
+// History: dd-mmm-yy Author Comment
+// 01-Jun-94 Ricksa Created
+//
+//--------------------------------------------------------------------------
+HRESULT TestRegisterNotifyDegister(
+ IDataAdviseHolder *pdahTest,
+ CGenDataObject *pgdo)
+{
+ return DoRegisterNotifyDeregister(pdahTest, pgdo, pgdo, 0,
+ "TestRegisterNotifyDegister");
+}
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: TestRegisterNotifyDegisterNoData
+//
+// Synopsis: Test a simple register/notify/deregister sequence with
+// no data being returned.
+//
+// Arguments: [pdahTest] - data advise holder we are testing
+// [pgdo] - generic data object
+//
+// Returns: NOERROR - notification was correct
+// E_FAIL - error in notification
+//
+// History: dd-mmm-yy Author Comment
+// 01-Jun-94 Ricksa Created
+//
+//--------------------------------------------------------------------------
+HRESULT TestRegisterNotifyDegisterNoData(
+ IDataAdviseHolder *pdahTest,
+ CGenDataObject *pgdo)
+{
+ return DoRegisterNotifyDeregister(pdahTest, pgdo, NULL, ADVF_NODATA,
+ "TestRegisterNotifyDegisterNoData");
+}
+
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: TestNotifyOnStop
+//
+// Synopsis: Test a registration with a call of notify on stop
+//
+// Arguments: [pdahTest] - data advise holder we are testing
+// [pgdo] - generic data object
+//
+// Returns: NOERROR - notification was correct
+// E_FAIL - error in notification
+//
+// Algorithm: Create a test object. Register it with the advise holder.
+// Confirm that the connection was returned and that no
+// notification occurred. Then tell the data advise holder
+// to notify its registrations of a data change. Make sure
+// that the advise was correctly notified. Finally, verify
+// that we can deregister the advise and that its connection
+// becomes invalid.
+//
+// History: dd-mmm-yy Author Comment
+// 01-Jun-94 Ricksa Created
+//
+//--------------------------------------------------------------------------
+HRESULT TestNotifyOnStop(
+ IDataAdviseHolder *pdahTest,
+ CGenDataObject *pgdo)
+{
+ // Routine name for messages
+ char *pszCaller = "TestNotifyOnStop";
+
+ // Create an advise sink that we can verify the STGMEDIUM
+ CTestAdviseSink tas(pgdo);
+
+ // Where to store the connection
+ DWORD dwConnection;
+
+ // Register the advise
+ HRESULT hr = pdahTest->Advise(pgdo, g_datfeDaTest.GetFormatEtc(),
+ ADVF_DATAONSTOP, &tas, &dwConnection);
+
+ // Make sure the advise is registered
+ if (dwConnection == 0)
+ {
+ OutputString("%s did not get Connection!\r\n", pszCaller);
+ return E_FAIL;
+ }
+
+ // Confirm that the data object was not notified
+ if (tas.ValidOnDataChange())
+ {
+ OutputString("%s Registration caused notification!\r\n", pszCaller);
+ return E_FAIL;
+ }
+
+ // Test regular data change
+ hr = pdahTest->SendOnDataChange(pgdo, 0, ADVF_DATAONSTOP);
+
+ if (hr != NOERROR)
+ {
+ OutputString("%s SendOnDataChange unexpected HRESULT = %lx!\r\n",
+ pszCaller, hr);
+ return E_FAIL;
+ }
+
+ // Confirm that the advise is notified and in the correct state
+ if (!tas.ValidOnDataChange())
+ {
+ OutputString("%s Second OnDataChange invalid!\r\n", pszCaller);
+ return E_FAIL;
+ }
+
+ // Test unadvise
+ hr = pdahTest->Unadvise(dwConnection);
+
+ if (hr != NOERROR)
+ {
+ OutputString("%s Unadvise unexpected HRESULT = %lx!\r\n", pszCaller, hr);
+ return E_FAIL;
+ }
+
+ // Test second unadvise on the same connection
+ hr = pdahTest->Unadvise(dwConnection);
+
+ if (hr != OLE_E_NOCONNECTION)
+ {
+ OutputString("%s Second Unadvise Bad Hresult = %lx!\r\n", pszCaller, hr);
+ return E_FAIL;
+ }
+
+ return NOERROR;
+}
+
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: TestNotifyOnce
+//
+// Synopsis: Test a notify once advise
+//
+// Arguments: [pdahTest] - data advise holder we are testing
+// [pgdo] - generic data object
+//
+// Returns: NOERROR - notification was correct
+// E_FAIL - error in notification
+//
+// Algorithm: Create a test advise object. Register it to be advised only
+// once of a change. Confirm that we got a registration. Then
+// tell the advise holder to notify its advises of a data
+// change. Confirm that the correct notification occurred. Finally,
+// confirm that we are no longer registered with the advise
+// holder.
+//
+// History: dd-mmm-yy Author Comment
+// 01-Jun-94 Ricksa Created
+//
+//--------------------------------------------------------------------------
+HRESULT TestNotifyOnce(
+ IDataAdviseHolder *pdahTest,
+ CGenDataObject *pgdo)
+{
+ // Routine name for messages
+ char *pszCaller = "TestNotifyOnce";
+
+ // Create an advise sink that we can verify the STGMEDIUM
+ CTestAdviseSink tas(pgdo);
+
+ // Where to store the connection
+ DWORD dwConnection;
+
+ // Register the advise
+ HRESULT hr = pdahTest->Advise(pgdo, g_datfeDaTest.GetFormatEtc(),
+ ADVF_ONLYONCE, &tas, &dwConnection);
+
+ // Make sure the advise is registered
+ if (dwConnection == 0)
+ {
+ OutputString("%s did not get Connection!\r\n", pszCaller);
+ return E_FAIL;
+ }
+
+ // Test regular data change
+ hr = pdahTest->SendOnDataChange(pgdo, 0, 0);
+
+ if (hr != NOERROR)
+ {
+ OutputString("%s SendOnDataChange unexpected HRESULT = %lx!\r\n",
+ pszCaller, hr);
+ return E_FAIL;
+ }
+
+ // Confirm that the advise is notified and in the correct state
+ if (!tas.ValidOnDataChange())
+ {
+ OutputString("%s Send OnDataChange invalid!\r\n", pszCaller);
+ return E_FAIL;
+ }
+
+ // Try a second notify
+ hr = pdahTest->SendOnDataChange(pgdo, 0, 0);
+
+
+ // Confirm that the advise is *not* notified
+ if (tas.ValidOnDataChange())
+ {
+ OutputString("%s Second OnDataChange unexpectedly succeeded!\r\n",
+ pszCaller);
+ return E_FAIL;
+ }
+
+ // Test unadvise - should fail since we requested to be notified
+ // only once.
+ hr = pdahTest->Unadvise(dwConnection);
+
+ if (hr != OLE_E_NOCONNECTION)
+ {
+ OutputString("%s Second Unadvise Bad Hresult = %lx!\r\n", pszCaller, hr);
+ return E_FAIL;
+ }
+
+ return NOERROR;
+}
+
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: CreateMassRegistration
+//
+// Synopsis: Register a large number of advise objects with a holder
+//
+// Arguments: [pdahTest] - data advise holder we are testing
+// [pgdo] - generic data object
+// [pszCaller] - name of test
+//
+// Returns: NOERROR - all advises were registered
+// E_FAIL - error in registration
+//
+// Algorithm: Create a MAX_REGISTER number of test advise objects and
+// store them in the aMassAdvise array. Then register them
+// all with the input advise holder.
+//
+// History: dd-mmm-yy Author Comment
+// 01-Jun-94 Ricksa Created
+//
+//--------------------------------------------------------------------------
+HRESULT CreateMassRegistration(
+ IDataAdviseHolder *pdahTest,
+ CGenDataObject *pgdo,
+ char *pszCaller)
+{
+ // Create the advise sinks for the test for the test
+ for (int i = 0; i < MAX_REGISTER; i++)
+ {
+ aMassAdvise[i].ptas = new CTestAdviseSink(pgdo);
+
+ if (aMassAdvise[i].ptas == NULL)
+ {
+ OutputString(
+ "%s Advise create of test advise failed on %d!\r\n", pszCaller,
+ i);
+ return E_FAIL;
+ }
+
+ aMassAdvise[i].dwConnection = 0;
+ }
+
+ HRESULT hr;
+
+ // Register the advise sinks
+ for (i = 0; i < MAX_REGISTER; i++)
+ {
+ // Register the advise
+ hr = pdahTest->Advise(pgdo, g_datfeDaTest.GetFormatEtc(),
+ 0, aMassAdvise[i].ptas, &aMassAdvise[i].dwConnection);
+
+ if (hr != NOERROR)
+ {
+ OutputString(
+ "%s Advise unexpected HRESULT = %lx on %d!\r\n", pszCaller,
+ hr, i);
+ return E_FAIL;
+ }
+ }
+
+ return S_OK;
+}
+
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: DoMassUnadvise
+//
+// Synopsis: Deregister all entries in the aMassAdvise array
+//
+// Arguments: [pdahTest] - data advise holder we are testing
+// [pszCaller] - name of test
+//
+// Returns: NOERROR - deregistration worked
+// E_FAIL - error in deregistration
+//
+// Algorithm: For each entry in the aMassAdvise array, deregister it
+// from the holder. Then confirm that its connection is
+// no longer valid.
+//
+// History: dd-mmm-yy Author Comment
+// 01-Jun-94 Ricksa Created
+//
+//--------------------------------------------------------------------------
+HRESULT DoMassUnadvise(
+ IDataAdviseHolder *pdahTest,
+ char *pszCaller)
+{
+ HRESULT hr;
+
+ // Unadvise them
+ for (int i = 0; i < MAX_REGISTER; i++)
+ {
+ // Test unadvise
+ hr = pdahTest->Unadvise(aMassAdvise[i].dwConnection);
+
+ if (hr != NOERROR)
+ {
+ OutputString(
+ "%s Unadvise unexpected HRESULT = %lx on %d!\r\n", pszCaller,
+ hr, i);
+ return E_FAIL;
+ }
+
+ // Test second unadvise on the same connection
+ hr = pdahTest->Unadvise(aMassAdvise[i].dwConnection);
+
+ if (hr != OLE_E_NOCONNECTION)
+ {
+ OutputString(
+ "%s Second Unadvise Bad Hresult = %lx on %d!\r\n", pszCaller,
+ hr, i);
+ return E_FAIL;
+ }
+ }
+
+ // Delete the advise sinks for the test
+ for (i = 0; i < MAX_REGISTER; i++)
+ {
+ delete aMassAdvise[i].ptas ;
+ }
+
+ return S_OK;
+}
+
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: TestMassRegister
+//
+// Synopsis: Test registering a large number of advises with a holder
+//
+// Arguments: [pdahTest] - data advise holder we are testing
+// [pgdo] - generic data object
+//
+// Returns: NOERROR - notification was correct
+// E_FAIL - error in notification
+//
+// Algorithm: Register a large number of test advises with the data advise
+// holder. Then tell the advise holder to notify them of
+// a change. Confirm that all registered entries were notified.
+// Finally, deregister all the test advises.
+//
+// History: dd-mmm-yy Author Comment
+// 01-Jun-94 Ricksa Created
+//
+//--------------------------------------------------------------------------
+HRESULT TestMassRegister(
+ IDataAdviseHolder *pdahTest,
+ CGenDataObject *pgdo)
+{
+ char *pszCaller = "TestMassRegister";
+
+ HRESULT hr = CreateMassRegistration(pdahTest, pgdo, "TestMassRegister");
+
+ if (hr != NOERROR)
+ {
+ return hr;
+ }
+
+ // Notify them of a change
+ hr = pdahTest->SendOnDataChange(pgdo, 0, 0);
+
+ // Verify that each was notified
+ for (int i = 0; i < MAX_REGISTER; i++)
+ {
+ if (!aMassAdvise[i].ptas->ValidOnDataChange())
+ {
+ OutputString(
+ "%s OnDataChange invalid for entry %d!\r\n", pszCaller, i);
+ return E_FAIL;
+ }
+ }
+
+ // Unadvise them and free the memory
+ return DoMassUnadvise(pdahTest, "TestMassRegister");
+}
+
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: TestEnumerator
+//
+// Synopsis: Test the data advise holder enumerator
+//
+// Arguments: [pdahTest] - data advise holder we are testing
+// [pgdo] - generic data object
+//
+// Returns: NOERROR - notification was correct
+// E_FAIL - error in notification
+//
+// Algorithm: Create a large number of test advises and register them
+// with the advise holder. Get an advise enumerator. Create
+// a test enumerator object. Tell the test enumerator object
+// to enumerate all the object in the holder. Verify that
+// all objects were correctly enumerated. Then release the
+// advise holder enumerator. Finally, deregister all the
+// test advises from the advise holder.
+//
+// History: dd-mmm-yy Author Comment
+// 01-Jun-94 Ricksa Created
+//
+//--------------------------------------------------------------------------
+HRESULT TestEnumerator(
+ IDataAdviseHolder *pdahTest,
+ CGenDataObject *pgdo)
+{
+ char *pszCaller = "TestEnumerator";
+
+ // Do a mass register
+ HRESULT hr = CreateMassRegistration(pdahTest, pgdo, pszCaller);
+
+ if (hr != NOERROR)
+ {
+ return hr;
+ }
+
+ // Get an enumerator for this registration
+ IEnumSTATDATA *penumAdvise;
+
+ hr = pdahTest->EnumAdvise(&penumAdvise);
+
+ if (hr != NOERROR)
+ {
+ OutputString("%s EnumAdvise failed %lx!\r\n", pszCaller, hr);
+ return E_FAIL;
+ }
+
+ // Create a test enumerator object
+ CTestDaHolder tdh(penumAdvise, hr);
+
+ if (hr != NOERROR)
+ {
+ OutputString(
+ "%s Failed creating CTestDaHolder %lx!\r\n", pszCaller, hr);
+ return E_FAIL;
+ }
+
+ // Enmerate all 1 by 1
+ if (tdh.TestNext() != NOERROR)
+ {
+ OutputString(
+ "%s tdh.TestNext failed during enumeration\r\n", pszCaller);
+ return E_FAIL;
+ }
+
+ // Verify that all entries were enumerated
+ if (!tdh.VerifyAllEnmerated())
+ {
+ OutputString(
+ "%s tdh.VerifyAllEnmerated failed verification pass\r\n", pszCaller);
+ return E_FAIL;
+ }
+
+ // Do a test all
+ if (tdh.TestAll() != NOERROR)
+ {
+ OutputString(
+ "%s tdh.TestAll failed during enumeration\r\n", pszCaller);
+ return E_FAIL;
+ }
+
+ // Release the advise enumerator
+ if (penumAdvise->Release() != 0)
+ {
+ OutputString(
+ "%s Failed freeing advise enumerator %lx!\r\n", pszCaller, hr);
+ return E_FAIL;
+ }
+
+ // Release the registrations
+ return DoMassUnadvise(pdahTest, pszCaller);
+}
+
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: LEDataAdviseHolderTest
+//
+// Synopsis: Unit test for the data advise holder.
+//
+// Returns: NOERROR - test passed
+// E_FAIL - test failed.
+//
+// Algorithm: Create an advise holder object. Run through all the test
+// cases. Return NOERROR if they succeed or stop with the first
+// that fails.
+//
+// History: dd-mmm-yy Author Comment
+// 01-Jun-94 Ricksa Created
+//
+//--------------------------------------------------------------------------
+HRESULT LEDataAdviseHolderTest(void)
+{
+ // Create a data object for use in the test
+ CGenDataObject *pgdo = new CGenDataObject;
+
+ assert(pgdo);
+
+ // Create a data advise holder
+ IDataAdviseHolder *pdahTest;
+
+ HRESULT hr = CreateDataAdviseHolder(&pdahTest);
+
+ if (hr != NOERROR)
+ {
+ OutputString(
+ "LEDataAdviseHolderTest CreateDataAdviseHolder Faild hr = %lx", hr);
+ return hr;
+ }
+
+ // Case 1: ADVF_PRIMEFIRST & ADVF_ONLYONCE & ADVF_NODATA
+ if ((hr = TestPrimeFirstOnlyOnceNoData(pdahTest, pgdo)) != NOERROR)
+ {
+ return hr;
+ }
+
+ // Case 2: ADVF_PRIMEFIRST
+ if ((hr = TestPrimeFirstOnlyOnceNoData(pdahTest, pgdo)) != NOERROR)
+ {
+ return hr;
+ }
+
+ // Case 3: Register/Notify/Deregister
+ if ((hr = TestRegisterNotifyDegister(pdahTest, pgdo)) != NOERROR)
+ {
+ return hr;
+ }
+
+ // Case 4: Register/Notify/Deregister with no data returned
+ if ((hr = TestRegisterNotifyDegisterNoData(pdahTest, pgdo)) != NOERROR)
+ {
+ return hr;
+ }
+
+ // Case 5: Test notify on stop
+ if ((hr = TestNotifyOnStop(pdahTest, pgdo)) != NOERROR)
+ {
+ return hr;
+ }
+
+ // Case 6: Test notify only once
+ if ((hr = TestNotifyOnce(pdahTest, pgdo)) != NOERROR)
+ {
+ return hr;
+ }
+
+ // Case 7: Test mass Register/Notify/Deregister
+ if ((hr = TestMassRegister(pdahTest, pgdo)) != NOERROR)
+ {
+ return hr;
+ }
+
+ // Case 8: Test Enumerator
+ if ((hr = TestEnumerator(pdahTest, pgdo)) != NOERROR)
+ {
+ return hr;
+ }
+
+ // We are done
+ DWORD dwFinalRefs = pdahTest->Release();
+
+ if (dwFinalRefs != 0)
+ {
+ OutputString(
+ "LEDataAdviseHolderTest Final Release is = %d", dwFinalRefs);
+ return E_FAIL;
+ }
+
+ pgdo->Release();
+
+ return NOERROR;
+}
diff --git a/private/oleutest/oletest/daytona/makefile b/private/oleutest/oletest/daytona/makefile
new file mode 100644
index 000000000..1d3728d41
--- /dev/null
+++ b/private/oleutest/oletest/daytona/makefile
@@ -0,0 +1,10 @@
+############################################################################
+#
+# Copyright (C) 1992, Microsoft Corporation.
+#
+# All rights reserved.
+#
+############################################################################
+
+!include $(NTMAKEENV)\makefile.def
+
diff --git a/private/oleutest/oletest/daytona/sources b/private/oleutest/oletest/daytona/sources
new file mode 100644
index 000000000..8aa641f46
--- /dev/null
+++ b/private/oleutest/oletest/daytona/sources
@@ -0,0 +1,93 @@
+!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:
+
+ Donna Liu (DonnaLi) 19-Dec-1993
+
+!ENDIF
+
+MAJORCOMP = cairole
+MINORCOMP = com
+
+#
+# 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= oletest
+
+#
+# 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= ..;..\..\uthread;..\..\inc;..\..\common;..\..\..\ole32\common\daytona;..\..\..\ole32\ih;..\..\..\cinc
+
+C_DEFINES= \
+ $(C_DEFINES) \
+ -DFLAT \
+ -DWIN32=100 \
+ -D_NT1X_=100 \
+ -DNOEXCEPTIONS \
+ -DCAIROLE_DOWNLEVEL
+
+BLDCRT= 1
+
+SOURCES= \
+ ..\oletest.rc \
+ ..\oletest.cpp \
+ ..\stack.cpp \
+ ..\task.cpp \
+ ..\app.cpp \
+ ..\output.cpp \
+ ..\cliptest.cpp \
+ ..\gendata.cpp \
+ ..\letests.cpp \
+ ..\attest.cpp \
+ ..\genenum.cpp \
+ ..\dataadv.cpp \
+ ..\oleadv.cpp \
+ ..\uthread.cpp \
+ ..\utils.cpp \
+ ..\assert.cpp
+
+UMTYPE= windows
+UMENTRY= winmain
+UMAPPL=
+UMTEST=
+UMLIBS= \
+ ..\..\uthread\common\obj\*\common.lib \
+ $(BASEDIR)\public\sdk\lib\*\ole32.lib \
+ $(BASEDIR)\public\sdk\lib\*\comdlg32.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\*\crtdll.lib \
+ $(BASEDIR)\public\sdk\lib\*\uuid.lib
+
+USE_CRTDLL= 1
diff --git a/private/oleutest/oletest/dirs b/private/oleutest/oletest/dirs
new file mode 100644
index 000000000..71782f197
--- /dev/null
+++ b/private/oleutest/oletest/dirs
@@ -0,0 +1,38 @@
+!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/oletest/gendata.cpp b/private/oleutest/oletest/gendata.cpp
new file mode 100644
index 000000000..36c7f8d3c
--- /dev/null
+++ b/private/oleutest/oletest/gendata.cpp
@@ -0,0 +1,1930 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: gendata.cpp
+//
+// Contents: implementation of CGenDataObject
+//
+// Classes:
+//
+// Functions:
+//
+// History: dd-mmm-yy Author Comment
+// 06-Jun-94 alexgo added support for OLE1 tests
+// 24-Mar-94 alexgo author
+//
+//--------------------------------------------------------------------------
+
+#include "oletest.h"
+#include "gendata.h"
+
+static const CLSID CLSID_TestCLSID = {0xaabbccee, 0x1122, 0x3344, { 0x55, 0x66,
+ 0x77, 0x88, 0x99, 0x00, 0xaa, 0xbb }};
+
+static const char szTestString[] = "A carefully chosen test string";
+static const OLECHAR wszTestStream[] = OLESTR("TestStream");
+static const char szNativeData[] = "Ole1Test NATIVE data";
+static const char szOwnerLinkData[] = "PBrush\0foo.bmp\00 0 200 160\0\0";
+
+
+//+-------------------------------------------------------------------------
+//
+// Member: CGenDataObject::CGenDataObject
+//
+// Synopsis: constructor
+//
+// Effects:
+//
+// Arguments:
+//
+// Requires:
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Derivation:
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 06-Jun-94 alexgo added OLE1 support
+// 24-Mar-94 alexgo author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+CGenDataObject::CGenDataObject( )
+{
+ m_refs = 0;
+ m_fQICalled = FALSE;
+
+ // now set up the formats that we support
+
+ m_cfTestStorage = RegisterClipboardFormat("OleTest Storage Format");
+ m_cfEmbeddedObject = RegisterClipboardFormat("Embedded Object");
+ m_cfEmbedSource = RegisterClipboardFormat("Embed Source");
+ m_cfLinkSource = RegisterClipboardFormat("Link Source");
+ m_cfObjectDescriptor = RegisterClipboardFormat("Object Descriptor");
+ m_cfLinkSrcDescriptor = RegisterClipboardFormat("Link Source "
+ "Descriptor");
+ m_cfOwnerLink = RegisterClipboardFormat("OwnerLink");
+ m_cfNative = RegisterClipboardFormat("Native");
+ m_cfObjectLink = RegisterClipboardFormat("ObjectLink");
+
+ // now set up the array of formatetc's. SetupOle1Mode must be
+ // called if you want OLE1 formats
+
+ m_rgFormats = new FORMATETC[2];
+
+ assert(m_rgFormats);
+
+ m_rgFormats[0].cfFormat = m_cfTestStorage;
+ m_rgFormats[0].ptd = NULL;
+ m_rgFormats[0].dwAspect = DVASPECT_CONTENT;
+ m_rgFormats[0].lindex = -1;
+ m_rgFormats[0].tymed = TYMED_ISTORAGE;
+
+ m_rgFormats[1].cfFormat = m_cfEmbeddedObject;
+ m_rgFormats[1].ptd = NULL;
+ m_rgFormats[1].dwAspect = DVASPECT_CONTENT;
+ m_rgFormats[1].lindex = -1;
+ m_rgFormats[1].tymed = TYMED_ISTORAGE;
+
+ m_cFormats = 2;
+
+}
+
+//+-------------------------------------------------------------------------
+//
+// Member: CGenDataObject::QueryInterface
+//
+// Synopsis: returns requested interfaces
+//
+// Effects:
+//
+// Arguments: [riid] -- the requested interface
+// [ppvObj] -- where to put the interface pointer
+//
+// Requires:
+//
+// Returns: HRESULT
+//
+// Signals:
+//
+// Modifies:
+//
+// Derivation: IDataObject
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 24-Mar-94 alexgo author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+STDMETHODIMP CGenDataObject::QueryInterface( REFIID riid, LPVOID *ppvObj )
+{
+ HRESULT hresult = NOERROR;
+
+ m_fQICalled = TRUE;
+
+ if( IsEqualIID(riid, IID_IUnknown) ||
+ IsEqualIID(riid, IID_IDataObject) )
+ {
+ *ppvObj = this;
+ AddRef();
+ }
+ else
+ {
+ *ppvObj = NULL;
+ hresult = ResultFromScode(E_NOINTERFACE);
+ }
+
+ return hresult;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Member: CGenDataObject::AddRef
+//
+// Synopsis: increments the reference count
+//
+// Effects:
+//
+// Arguments: void
+//
+// Requires:
+//
+// Returns: ULONG-- the new reference count
+//
+// Signals:
+//
+// Modifies:
+//
+// Derivation: IDataObject
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 24-Mar-94 alexgo author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+STDMETHODIMP_(ULONG) CGenDataObject::AddRef( )
+{
+ return ++m_refs;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Member: CGenDataObject::Release
+//
+// Synopsis: decrements the reference count on the object
+//
+// Effects:
+//
+// Arguments: void
+//
+// Requires:
+//
+// Returns: ULONG -- the new reference count
+//
+// Signals:
+//
+// Modifies:
+//
+// Derivation: IDataObject
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 24-Mar-94 alexgo author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+STDMETHODIMP_(ULONG) CGenDataObject::Release( )
+{
+ ULONG cRefs;
+
+ if( (cRefs = --m_refs ) == 0 )
+ {
+ delete this;
+ }
+ return cRefs;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Member: CGenDataObject::GetData
+//
+// Synopsis: retrieves data of the specified format
+//
+// Effects:
+//
+// Arguments: [pformatetc] -- the requested format
+// [pmedium] -- where to put the data
+//
+// Requires:
+//
+// Returns: HRESULT
+//
+// Signals:
+//
+// Modifies:
+//
+// Derivation: IDataObject
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 06-Jun-94 alexgo added OLE1 support
+// 24-Mar-94 alexgo author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+STDMETHODIMP CGenDataObject::GetData( LPFORMATETC pformatetc, LPSTGMEDIUM
+ pmedium)
+{
+ HRESULT hresult = NOERROR;
+
+ if( (pformatetc->cfFormat == m_cfTestStorage ||
+ pformatetc->cfFormat == m_cfEmbeddedObject ) &&
+ (pformatetc->tymed & TYMED_ISTORAGE) )
+ {
+ pmedium->tymed = TYMED_ISTORAGE;
+ pmedium->pstg = GetTestStorage();
+ assert(pmedium->pstg);
+ }
+
+ // test for OLE1 formats
+
+ else if( pformatetc->cfFormat == m_cfOwnerLink &&
+ (m_fOle1 & OLE1_OFFER_OWNERLINK ) &&
+ (pformatetc->tymed & TYMED_HGLOBAL) )
+ {
+ pmedium->tymed = TYMED_HGLOBAL;
+ pmedium->hGlobal = GetOwnerOrObjectLink();
+ assert(pmedium->hGlobal);
+ }
+ else if( pformatetc->cfFormat == m_cfObjectLink &&
+ (m_fOle1 & OLE1_OFFER_OBJECTLINK ) &&
+ (pformatetc->tymed & TYMED_HGLOBAL) )
+ {
+ pmedium->tymed = TYMED_HGLOBAL;
+ pmedium->hGlobal = GetOwnerOrObjectLink();
+ assert(pmedium->hGlobal);
+ }
+ else if( pformatetc->cfFormat == m_cfNative &&
+ (m_fOle1 & OLE1_OFFER_NATIVE ) &&
+ (pformatetc->tymed &TYMED_HGLOBAL ) )
+ {
+ pmedium->tymed = TYMED_HGLOBAL;
+ pmedium->hGlobal = GetNativeData();
+ }
+ else
+ {
+ hresult = ResultFromScode(E_FAIL);
+ }
+
+ return hresult;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Member: CGenDataObject::GetDataHere
+//
+// Synopsis: retrieves data of the specified format
+//
+// Effects:
+//
+// Arguments: [pformatetc] -- the requested format
+// [pmedium] -- where to put the data
+//
+// Requires:
+//
+// Returns: HRESULT
+//
+// Signals:
+//
+// Modifies:
+//
+// Derivation: IDataObject
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 24-Mar-94 alexgo author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+STDMETHODIMP CGenDataObject::GetDataHere( LPFORMATETC pformatetc, LPSTGMEDIUM
+ pmedium)
+{
+ (void)pformatetc;
+ (void)pmedium;
+
+ return ResultFromScode(E_NOTIMPL);
+}
+
+//+-------------------------------------------------------------------------
+//
+// Member: CGenDataObject::QueryGetData
+//
+// Synopsis: queries whether a GetData call would succeed
+//
+// Effects:
+//
+// Arguments: [pformatetc] -- the requested format
+//
+// Requires:
+//
+// Returns: HRESULT
+//
+// Signals:
+//
+// Modifies:
+//
+// Derivation: IDataObject
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 24-Mar-94 alexgo author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+STDMETHODIMP CGenDataObject::QueryGetData( LPFORMATETC pformatetc )
+{
+ (void)pformatetc;
+
+ return ResultFromScode(E_NOTIMPL);
+}
+
+//+-------------------------------------------------------------------------
+//
+// Member: CGenDataObject::GetCanonicalFormatEtc
+//
+// Synopsis: retrieve the canonical format
+//
+// Effects:
+//
+// Arguments: [pformatetc] -- the requested format
+// [pformatetcOut] -- the canonical format
+//
+// Requires:
+//
+// Returns: HRESULT
+//
+// Signals:
+//
+// Modifies:
+//
+// Derivation: IDataObject
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 24-Mar-94 alexgo author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+STDMETHODIMP CGenDataObject::GetCanonicalFormatEtc( LPFORMATETC pformatetc,
+ LPFORMATETC pformatetcOut)
+{
+ (void)pformatetc;
+ (void)pformatetcOut;
+
+ return ResultFromScode(E_NOTIMPL);
+}
+
+//+-------------------------------------------------------------------------
+//
+// Member: CGenDataObject::SetData
+//
+// Synopsis: sets data of the specified format
+//
+// Effects:
+//
+// Arguments: [pformatetc] -- the format of the data
+// [pmedium] -- the data
+//
+// Requires:
+//
+// Returns: HRESULT
+//
+// Signals:
+//
+// Modifies:
+//
+// Derivation: IDataObject
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 24-Mar-94 alexgo author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+STDMETHODIMP CGenDataObject::SetData( LPFORMATETC pformatetc, LPSTGMEDIUM
+ pmedium, BOOL fRelease)
+{
+ (void)pformatetc;
+ (void)pmedium;
+ (void)fRelease;
+
+ return ResultFromScode(E_NOTIMPL);
+}
+
+//+-------------------------------------------------------------------------
+//
+// Member: CGenDataObject::EnumFormatEtc
+//
+// Synopsis: return an enumerator for the available data formats
+//
+// Effects:
+//
+// Arguments: [dwDirection] -- the direction (GET or SET)
+// [ppenum] -- where to put the enumerator
+//
+// Requires:
+//
+// Returns: HRESULT
+//
+// Signals:
+//
+// Modifies:
+//
+// Derivation: IDataObject
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 24-Mar-94 alexgo author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+STDMETHODIMP CGenDataObject::EnumFormatEtc( DWORD dwDirection,
+ LPENUMFORMATETC * ppenum )
+{
+ HRESULT hresult;
+
+ if( dwDirection == DATADIR_GET )
+ {
+ hresult = CGenEnumFormatEtc::Create( ppenum, m_rgFormats,
+ m_cFormats);
+ assert(hresult == NOERROR);
+
+ return hresult;
+ }
+ else
+ {
+ return ResultFromScode(E_NOTIMPL);
+ }
+}
+
+//+-------------------------------------------------------------------------
+//
+// Member: CGenDataObject::DAdvise
+//
+// Synopsis: register a data advise
+//
+// Effects:
+//
+// Arguments: [pformatetc] -- the requested format
+// [dwAdvf] -- advise flags
+// [pAdvSink] -- the advise sink
+// [pdwConnection] -- where to put the connection ID
+//
+// Requires:
+//
+// Returns: HRESULT
+//
+// Signals:
+//
+// Modifies:
+//
+// Derivation: IDataObject
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 24-Mar-94 alexgo author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+STDMETHODIMP CGenDataObject::DAdvise( LPFORMATETC pformatetc, DWORD dwAdvf,
+ IAdviseSink * pAdvSink, DWORD *pdwConnection )
+{
+ (void)pformatetc;
+ (void)dwAdvf;
+ (void)pAdvSink;
+ (void)pdwConnection;
+
+ return ResultFromScode(E_NOTIMPL);
+}
+
+//+-------------------------------------------------------------------------
+//
+// Member: CGenDataObject::DUnadvise
+//
+// Synopsis: unadvises an advise connection
+//
+// Effects:
+//
+// Arguments: [dwConnection] -- the connection to remove
+//
+// Requires:
+//
+// Returns: HRESULT
+//
+// Signals:
+//
+// Modifies:
+//
+// Derivation: IDataObject
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 24-Mar-94 alexgo author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+STDMETHODIMP CGenDataObject::DUnadvise(DWORD dwConnection)
+{
+ (void)dwConnection;
+
+ return ResultFromScode(E_NOTIMPL);
+}
+
+//+-------------------------------------------------------------------------
+//
+// Member: CGenDataObject::EnumDAdvise
+//
+// Synopsis: enumerates data advises
+//
+// Effects:
+//
+// Arguments: [ppenum] -- where to put the enumerator
+//
+// Requires:
+//
+// Returns: HRESULT
+//
+// Signals:
+//
+// Modifies:
+//
+// Derivation: IDataObject
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 24-Mar-94 alexgo author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+STDMETHODIMP CGenDataObject::EnumDAdvise( LPENUMSTATDATA *ppenum)
+{
+ (void)ppenum;
+
+ return ResultFromScode(E_NOTIMPL);
+}
+
+//+-------------------------------------------------------------------------
+//
+// Member: CGenDataObject::VerifyMedium
+//
+// Synopsis: verifies the contents of the given medium
+//
+// Effects:
+//
+// Arguments: [pmedium] -- the medium to verify
+//
+// Requires:
+//
+// Returns: BOOL
+//
+// Signals:
+//
+// Modifies:
+//
+// Derivation:
+//
+// Algorithm: For OLE1 formats, the following must be true:
+// cfEmbeddedObject:
+// must have OWNERLINK and !NATIVE
+// or OWNERLINK precedes NATIVE
+// cfEmbedSource:
+// must have NATIVE && OWNERLINK and
+// OWNERLINK must not precede NATIVE
+// cfObjectDescriptor:
+// same as EmbedSource
+// cfLinkSource:
+// must have either OBJECTLINK or
+// OWNERLINK must precede NATIVE
+// cfLinkSrcDescriptor:
+// same as LinkSource
+//
+// History: dd-mmm-yy Author Comment
+// 06-Jun-94 alexgo added OLE1 support
+// 15-Apr-94 alexgo author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+BOOL CGenDataObject::VerifyFormatAndMedium( FORMATETC *pformatetc,
+ STGMEDIUM *pmedium )
+{
+ // if any of these flags are set, then we were offering OLE1
+ // data. Do relevant tests.
+
+ if( (m_fOle1 & (OLE1_OFFER_OWNERLINK | OLE1_OFFER_OBJECTLINK |
+ OLE1_OFFER_NATIVE) ) )
+ {
+ // now do individual tests for formats
+ if( pformatetc->cfFormat == m_cfEmbedSource ||
+ pformatetc->cfFormat == m_cfObjectDescriptor)
+ {
+ if( (m_fOle1 & OLE1_OFFER_NATIVE) &&
+ (m_fOle1 & OLE1_OFFER_OWNERLINK) &&
+ !(m_fOle1 & OLE1_OWNERLINK_PRECEDES_NATIVE) )
+ {
+ return TRUE;
+ }
+ }
+ else if( pformatetc->cfFormat == m_cfLinkSource ||
+ pformatetc->cfFormat == m_cfLinkSrcDescriptor)
+ {
+ if( (m_fOle1 & OLE1_OFFER_OBJECTLINK) ||
+ ((m_fOle1 & OLE1_OFFER_OWNERLINK) &&
+ (m_fOle1 & OLE1_OFFER_NATIVE) &&
+ (m_fOle1 & OLE1_OWNERLINK_PRECEDES_NATIVE)))
+ {
+ return TRUE;
+ }
+ }
+
+ // no 'else' so we check for cfObjectDescriptor again
+ if( pformatetc->cfFormat == m_cfEmbeddedObject ||
+ pformatetc->cfFormat == m_cfObjectDescriptor )
+ {
+ if( ((m_fOle1 & OLE1_OFFER_NATIVE) &&
+ (m_fOle1 & OLE1_OFFER_OWNERLINK) &&
+ (m_fOle1 & OLE1_OWNERLINK_PRECEDES_NATIVE)) ||
+ ((m_fOle1 & OLE1_OFFER_OWNERLINK) &&
+ !(m_fOle1 & OLE1_OFFER_NATIVE)) )
+ {
+ return TRUE;
+ }
+
+ }
+
+ // fall through and do rest of testing, in case we didn't
+ // hit one of the synthesized formats.
+ }
+
+ if( pformatetc->cfFormat == m_cfTestStorage ||
+ pformatetc->cfFormat == m_cfEmbeddedObject )
+ {
+ return VerifyTestStorage( pformatetc, pmedium );
+ }
+ else if( pformatetc->cfFormat == m_cfOwnerLink ||
+ pformatetc->cfFormat == m_cfObjectLink )
+ {
+ return VerifyOwnerOrObjectLink(pformatetc, pmedium);
+ }
+ else if( pformatetc->cfFormat == m_cfNative )
+ {
+ return VerifyNativeData(pformatetc, pmedium);
+ }
+
+ return FALSE;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Member: CGenDataObject::VerifyTestStorage
+//
+// Synopsis: verifies the test storage format
+//
+// Effects:
+//
+// Arguments:
+//
+// Requires:
+//
+// Returns: BOOL
+//
+// Signals:
+//
+// Modifies:
+//
+// Derivation:
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 15-Apr-94 alexgo author; tax day :-(
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+BOOL CGenDataObject::VerifyTestStorage( FORMATETC *pformatetc,
+ STGMEDIUM *pmedium)
+{
+ IStream * pstm;
+ STATSTG statstg;
+ char szBuf[sizeof(szTestString)];
+ HRESULT hresult;
+
+ if( pmedium->tymed != TYMED_ISTORAGE )
+ {
+ //REVIEW: we may want to convert and test different
+ //mediums at a later date
+
+ return FALSE;
+ }
+
+
+ // check the class ID
+
+ pmedium->pstg->Stat(&statstg, STATFLAG_NONAME);
+
+ if( !IsEqualCLSID(statstg.clsid, CLSID_TestCLSID) )
+ {
+ OutputString("Failed CLSID check on storage in "
+ "VerifyTestStorage!!\r\n");
+ return FALSE;
+ }
+
+ // now open the test stream
+
+ hresult = pmedium->pstg->OpenStream(wszTestStream, NULL, (STGM_READ |
+ STGM_SHARE_EXCLUSIVE), 0, &pstm);
+
+ if( hresult != NOERROR )
+ {
+ OutputString("OpenStream in VerifyTestStorage failed! (%lx)"
+ "\r\n", hresult);
+ return FALSE;
+ }
+
+ hresult = pstm->Read((void *)szBuf, sizeof(szTestString), NULL);
+
+ if( hresult != NOERROR )
+ {
+ OutputString("Stream->Read failed in VerifyTestStorage (%lx)"
+ "\r\n", hresult);
+ pstm->Release();
+ return FALSE;
+ }
+
+ if( strcmp(szBuf, szTestString) != 0 )
+ {
+ OutputString("'%s' != '%s'\r\n", szBuf, szTestString);
+ return FALSE;
+ }
+
+ pstm->Release();
+
+ return TRUE;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Member: CGenDataObject::GetTestStorage (private)
+//
+// Synopsis:
+//
+// Effects:
+//
+// Arguments:
+//
+// Requires:
+//
+// Returns: a new storage
+//
+// Signals:
+//
+// Modifies:
+//
+// Derivation:
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 15-Apr-94 alexgo author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+IStorage * CGenDataObject::GetTestStorage( void )
+{
+ IStorage * pstg;
+ IStream * pstm;
+ HRESULT hresult;
+
+
+ // create the docfile
+
+ hresult = StgCreateDocfile(NULL, (STGM_READWRITE | STGM_DIRECT |
+ STGM_SHARE_EXCLUSIVE | STGM_DELETEONRELEASE), NULL,
+ &pstg);
+
+ if( hresult != NOERROR )
+ {
+ OutputString("GetTestStorage: CreateDocfile failed!! (%lx)"
+ "\r\n", hresult);
+ return NULL;
+ }
+
+ // set the class ID
+
+ hresult = pstg->SetClass(CLSID_TestCLSID);
+
+ // now create the stream
+
+ hresult = pstg->CreateStream(wszTestStream, (STGM_READWRITE |
+ STGM_SHARE_EXCLUSIVE ), 0, 0, &pstm);
+
+ if( hresult != NOERROR )
+ {
+ OutputString("GetTestStorage: CreateStream failed! (%lx)\r\n",
+ hresult);
+ pstg->Release();
+ return NULL;
+ }
+
+ hresult = pstm->Write((void *)szTestString, sizeof(szTestString),
+ NULL);
+
+ if( hresult != NOERROR )
+ {
+ OutputString("GetTestStorage: Stream->Write failed! (%lx)\r\n",
+ hresult);
+ pstm->Release();
+ pstg->Release();
+ return NULL;
+ }
+
+ pstm->Release();
+
+ return pstg;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Member: CGenDataObject::GetOwnerOrObjectLink (private)
+//
+// Synopsis: Creates either cfOwnerLink or cfObjectLink for a dummy
+// Paintbrush (ole1) object
+//
+// Effects: allocates an HGLOBAL
+//
+// Arguments: void
+//
+// Requires:
+//
+// Returns: HGLOBAL
+//
+// Signals:
+//
+// Modifies:
+//
+// Derivation:
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 06-Jun-94 alexgo author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+HGLOBAL CGenDataObject::GetOwnerOrObjectLink( void )
+{
+ HGLOBAL hglobal;
+ char *pdata;
+
+ hglobal = GlobalAlloc(GMEM_MOVEABLE, sizeof(szOwnerLinkData));
+
+ assert(hglobal);
+
+ pdata = (char *)GlobalLock(hglobal);
+
+ assert(pdata);
+
+ memcpy(pdata, szOwnerLinkData, sizeof(szOwnerLinkData));
+
+ GlobalUnlock(hglobal);
+
+ return hglobal;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Member: CGenDataObject::GetNativeData (private)
+//
+// Synopsis: Creates OLE1 Native data
+//
+// Effects: allocates an hglobal
+//
+// Arguments: void
+//
+// Requires:
+//
+// Returns: HGLOBAL
+//
+// Signals:
+//
+// Modifies:
+//
+// Derivation:
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 06-Jun-94 alexgo author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+HGLOBAL CGenDataObject::GetNativeData( void )
+{
+ HGLOBAL hglobal;
+ char *pdata;
+
+ hglobal = GlobalAlloc(GMEM_MOVEABLE, sizeof(szNativeData) + 1);
+
+ assert(hglobal);
+
+ pdata = (char *)GlobalLock(hglobal);
+
+ assert(pdata);
+
+ memcpy(pdata, szNativeData, sizeof(szNativeData)+1);
+
+ GlobalUnlock(hglobal);
+
+ return hglobal;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Member: CGenDataObject::VerifyOwnerOrObjectLink
+//
+// Synopsis: verifies that the owner or object link data is correct
+//
+// Effects:
+//
+// Arguments: [pformatetc] -- the formatetc describing the data
+// [pmedium] -- the data
+//
+// Requires: pformatetc must be for OwnerLink or ObjectLink
+//
+// Returns: BOOL
+//
+// Signals:
+//
+// Modifies:
+//
+// Derivation:
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 06-Jun-94 alexgo author
+//
+// Notes:
+// NB!!: must be expanded to cover container-side cases
+//
+//--------------------------------------------------------------------------
+
+BOOL CGenDataObject::VerifyOwnerOrObjectLink( FORMATETC *pformatetc,
+ STGMEDIUM *pmedium )
+{
+ char * pdata;
+ BOOL fRet = FALSE;
+
+
+ assert(pformatetc->cfFormat == m_cfOwnerLink ||
+ pformatetc->cfFormat == m_cfObjectLink );
+
+ // check standard stuff
+ if( !(pformatetc->tymed & TYMED_HGLOBAL ) ||
+ pformatetc->dwAspect != DVASPECT_CONTENT ||
+ pformatetc->ptd != NULL ||
+ pformatetc->lindex != -1 ||
+ pmedium->tymed != TYMED_HGLOBAL )
+ {
+ return FALSE;
+ }
+
+ // if we offered the data natively from OLE1, then
+ // check the contents.
+
+ // this conditional tests to see if the format in question
+ // was originally offered by us
+
+ if( ((m_fOle1 & OLE1_OFFER_OWNERLINK) &&
+ pformatetc->cfFormat == m_cfOwnerLink) ||
+ ((m_fOle1 & OLE1_OFFER_OBJECTLINK) &&
+ pformatetc->cfFormat == m_cfObjectLink) )
+ {
+
+ pdata = (char *)GlobalLock(pmedium->hGlobal);
+
+ if( memcmp(pdata, szOwnerLinkData,
+ sizeof(szOwnerLinkData)) == 0 )
+ {
+ fRet = TRUE;
+ }
+
+ GlobalUnlock(pmedium->hGlobal);
+ }
+ // else CHECK SYNTHESIZED OLE1 FORMATS WHEN IMPLEMENTED
+
+
+ return fRet;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Member: CGenDataObject::VerifyNativeData (private)
+//
+// Synopsis: verifies OLE1 Native data
+//
+// Effects:
+//
+// Arguments: [pformatetc] -- formatetc for the data
+// [pmedium] -- location of the native data
+//
+// Requires:
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Derivation:
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 06-Jun-95 alexgo author
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+BOOL CGenDataObject::VerifyNativeData( FORMATETC *pformatetc,
+ STGMEDIUM *pmedium )
+{
+ char * pdata;
+ BOOL fRet = FALSE;
+
+
+ assert(pformatetc->cfFormat == m_cfNative );
+
+ // check standard stuff
+ if( !(pformatetc->tymed & TYMED_HGLOBAL) ||
+ pformatetc->dwAspect != DVASPECT_CONTENT ||
+ pformatetc->ptd != NULL ||
+ pformatetc->lindex != -1 ||
+ pmedium->tymed != TYMED_HGLOBAL )
+ {
+ return FALSE;
+ }
+
+ // if we offered the data natively from OLE1, then
+ // check the contents.
+
+ // this conditional tests to see if the format in question
+ // was originally offered by us
+
+ if( (m_fOle1 & OLE1_OFFER_NATIVE) )
+ {
+
+ pdata = (char *)GlobalLock(pmedium->hGlobal);
+
+ if( memcmp(pdata, szNativeData,
+ sizeof(szNativeData)) == 0 )
+ {
+ fRet = TRUE;
+ }
+
+ GlobalUnlock(pmedium->hGlobal);
+ }
+ // else CHECK SYNTHESIZED OLE1 FORMATS WHEN IMPLEMENTED
+
+
+ return fRet;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Member: CGenDataObject::SetupOle1Mode (public)
+//
+// Synopsis: Sets the data object up for OLE1 compatibility mode
+//
+// Effects:
+//
+// Arguments: [fFlags] -- specifies various OLE1 options
+//
+// Requires:
+//
+// Returns: void
+//
+// Signals:
+//
+// Modifies:
+//
+// Derivation:
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 06-Jun-94 alexgo author
+//
+// Notes:
+// The default test information in the data object will be
+// lost by this call. Simply create a new data object if
+// it is needed again.
+//
+//--------------------------------------------------------------------------
+
+void CGenDataObject::SetupOle1Mode( Ole1TestFlags fFlags )
+{
+ DWORD count = 0, i = 0;
+ UINT cfFormats[3]; // OLE1 formats offered
+
+ if( fFlags == 0 )
+ {
+ // don't need to do anything
+ return;
+ }
+
+ // the formats we had previously
+
+ delete m_rgFormats;
+
+
+ // first figure out how many formats we need
+
+ if( (fFlags & OLE1_OFFER_NATIVE) )
+ {
+ if( !((fFlags & OLE1_OWNERLINK_PRECEDES_NATIVE) &&
+ (fFlags & OLE1_OFFER_OWNERLINK)) )
+ {
+ cfFormats[i] = m_cfNative;
+ i++;
+ }
+ count++;
+ }
+
+ if( (fFlags & OLE1_OFFER_OWNERLINK) )
+ {
+ cfFormats[i] = m_cfOwnerLink;
+ i++;
+
+ if( (fFlags & OLE1_OWNERLINK_PRECEDES_NATIVE) &&
+ (fFlags & OLE1_OFFER_NATIVE) )
+ {
+ cfFormats[i] = m_cfNative;
+ i++;
+ }
+
+ count++;
+ }
+
+ if( (fFlags & OLE1_OFFER_OBJECTLINK) )
+ {
+
+ cfFormats[i] = m_cfObjectLink;
+
+ count++;
+ }
+
+ m_rgFormats = new FORMATETC[count];
+
+ assert(m_rgFormats);
+
+ for(i = 0; i < count; i++ )
+ {
+ m_rgFormats[i].cfFormat = cfFormats[i];
+ m_rgFormats[i].ptd = NULL;
+ m_rgFormats[i].dwAspect = DVASPECT_CONTENT;
+ m_rgFormats[i].lindex = -1;
+ m_rgFormats[i].tymed = TYMED_HGLOBAL;
+ }
+
+ m_cFormats = count;
+
+ m_fOle1 = fFlags;
+
+ return;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Member: CGenDataObject::SetOle1ToClipboard
+//
+// Synopsis: stuffs available OLE1 formats to the clipboard
+//
+// Effects:
+//
+// Arguments: void
+//
+// Requires: SetOle1Mode *must* have been called
+//
+// Returns: HRESULT
+//
+// Signals:
+//
+// Modifies:
+//
+// Derivation:
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 06-Jun-94 alexgo author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+HRESULT CGenDataObject::SetOle1ToClipboard( void )
+{
+ HRESULT hresult = NOERROR;
+ DWORD i;
+ HGLOBAL hglobal;
+
+ assert((m_fOle1 & (OLE1_OFFER_OWNERLINK | OLE1_OFFER_OBJECTLINK |
+ OLE1_OFFER_NATIVE)));
+
+ if( !OpenClipboard(vApp.m_hwndMain) )
+ {
+ return ResultFromScode(CLIPBRD_E_CANT_OPEN);
+ }
+
+ if( !EmptyClipboard() )
+ {
+ CloseClipboard();
+ return ResultFromScode(CLIPBRD_E_CANT_EMPTY);
+ }
+
+ for( i = 0 ; i < m_cFormats; i++ )
+ {
+ if( m_rgFormats[i].cfFormat == m_cfNative )
+ {
+ hglobal = GetNativeData();
+ SetClipboardData(m_cfNative, hglobal);
+ }
+ else if( m_rgFormats[i].cfFormat == m_cfOwnerLink )
+ {
+ hglobal = GetOwnerOrObjectLink();
+ SetClipboardData(m_cfOwnerLink, hglobal);
+ }
+ else if( m_rgFormats[i].cfFormat == m_cfObjectLink )
+ {
+ hglobal = GetOwnerOrObjectLink();
+ SetClipboardData(m_cfObjectLink, hglobal);
+ }
+ else
+ {
+ hresult = ResultFromScode(E_UNEXPECTED);
+ }
+ }
+
+ CloseClipboard();
+
+ return hresult;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Member: CGenDataObject::HasQIBeenCalled (public)
+//
+// Synopsis: returns wether or not QueryInterface has been called on
+// this data object. Used in testing OleQueryCreateFromData
+//
+// Effects:
+//
+// Arguments: none
+//
+// Requires:
+//
+// Returns: TRUE/FALSE
+//
+// Signals:
+//
+// Modifies:
+//
+// Derivation:
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 23-Aug-94 alexgo author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+BOOL CGenDataObject::HasQIBeenCalled()
+{
+ return m_fQICalled;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Member: CGenDataObject::SetDatFormats
+//
+// Synopsis: sets the formats that the data object will offer
+//
+// Effects:
+//
+// Arguments: [fFlags] -- formats to offer
+//
+// Requires:
+//
+// Returns: void
+//
+// Signals:
+//
+// Modifies:
+//
+// Derivation:
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 23-Aug-94 alexgo author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+void CGenDataObject::SetDataFormats( DataFlags fFlags )
+{
+ DWORD cFormats = 0;
+ DWORD flags = (DWORD)fFlags;
+ DWORD i =0;
+
+ if( m_rgFormats )
+ {
+ delete m_rgFormats;
+ m_rgFormats = NULL;
+ }
+
+ if( flags == 0 )
+ {
+ return;
+ }
+
+ // count the number of formats to offer
+
+ cFormats++;
+
+ while( flags &= (flags -1) )
+ {
+ cFormats++;
+ }
+
+ m_rgFormats = new FORMATETC[cFormats];
+
+ assert(m_rgFormats);
+
+ memset(m_rgFormats, 0, sizeof(FORMATETC)*cFormats);
+
+ if( fFlags & OFFER_TESTSTORAGE )
+ {
+ m_rgFormats[i].cfFormat = m_cfTestStorage;
+ m_rgFormats[i].ptd = NULL;
+ m_rgFormats[i].dwAspect = DVASPECT_CONTENT;
+ m_rgFormats[i].lindex = -1;
+ m_rgFormats[i].tymed = TYMED_ISTORAGE;
+
+ i++;
+ }
+
+ if( fFlags & OFFER_EMBEDDEDOBJECT )
+ {
+ m_rgFormats[i].cfFormat = m_cfEmbeddedObject;
+ m_rgFormats[i].ptd = NULL;
+ m_rgFormats[i].dwAspect = DVASPECT_CONTENT;
+ m_rgFormats[i].lindex = -1;
+ m_rgFormats[i].tymed = TYMED_ISTORAGE;
+ i++;
+ }
+
+ m_cFormats = i;
+}
+
+//
+// Generic Data Object formatetc enumerator
+//
+
+//+-------------------------------------------------------------------------
+//
+// Member: CGenEnumFormatEtc::QueryInterface
+//
+// Synopsis: returns requested interfaces
+//
+// Effects:
+//
+// Arguments: [riid] -- the requested interface
+// [ppvObj] -- where to put the interface pointer
+//
+// Requires:
+//
+// Returns: HRESULT
+//
+// Signals:
+//
+// Modifies:
+//
+// Derivation: IEnumFORMATETC
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 15-Apr-94 alexgo author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+STDMETHODIMP CGenEnumFormatEtc::QueryInterface( REFIID riid, LPVOID *ppvObj )
+{
+ HRESULT hresult = NOERROR;
+
+ if( IsEqualIID(riid, IID_IUnknown) ||
+ IsEqualIID(riid, IID_IEnumFORMATETC) )
+ {
+ *ppvObj = this;
+ AddRef();
+ }
+ else
+ {
+ *ppvObj = NULL;
+ hresult = ResultFromScode(E_NOINTERFACE);
+ }
+
+ return hresult;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Member: CGenEnumFormatEtc::AddRef
+//
+// Synopsis: increments the reference count
+//
+// Effects:
+//
+// Arguments: void
+//
+// Requires:
+//
+// Returns: ULONG-- the new reference count
+//
+// Signals:
+//
+// Modifies:
+//
+// Derivation: IEnumFORMATETC
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 15-Apr-94 alexgo author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+STDMETHODIMP_(ULONG) CGenEnumFormatEtc::AddRef( )
+{
+ return ++m_refs;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Member: CGenEnumFormatEtc::Release
+//
+// Synopsis: decrements the reference count on the object
+//
+// Effects:
+//
+// Arguments: void
+//
+// Requires:
+//
+// Returns: ULONG -- the new reference count
+//
+// Signals:
+//
+// Modifies:
+//
+// Derivation: IEnumFORMATETC
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 15-Apr-94 alexgo author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+STDMETHODIMP_(ULONG) CGenEnumFormatEtc::Release( )
+{
+ ULONG cRefs;
+
+ if( (cRefs = --m_refs ) == 0 )
+ {
+ delete this;
+ }
+ return cRefs;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Member: CGenEnumFormatEtc::Next
+//
+// Synopsis: gets the next [celt] formats
+//
+// Effects:
+//
+// Arguments: [celt] -- the number of elements to fetch
+// [rgelt] -- where to put them
+// [pceltFetched] -- the number of formats actually fetched
+//
+// Requires:
+//
+// Returns: NOERROR
+//
+// Signals:
+//
+// Modifies:
+//
+// Derivation: IEnumFORMATETC
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 15-Apr-94 alexgo author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+STDMETHODIMP CGenEnumFormatEtc::Next( ULONG celt, FORMATETC *rgelt,
+ ULONG *pceltFetched)
+{
+ HRESULT hresult = NOERROR;
+ ULONG cFetched;
+
+ if( celt > m_cTotal - m_iCurrent )
+ {
+ cFetched = m_cTotal - m_iCurrent;
+ hresult = ResultFromScode(S_FALSE);
+ }
+ else
+ {
+ cFetched = celt;
+ }
+
+ memcpy( rgelt, m_rgFormats + m_iCurrent,
+ cFetched * sizeof(FORMATETC) );
+
+ m_iCurrent += cFetched;
+
+ if( pceltFetched )
+ {
+ *pceltFetched = cFetched;
+ }
+
+ return hresult;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Member: CGenEnumFormatEtc::Skip
+//
+// Synopsis: skips the next [celt] formats
+//
+// Effects:
+//
+// Arguments: [celt] -- the number of elements to skip
+//
+// Requires:
+//
+// Returns: NOERROR
+//
+// Signals:
+//
+// Modifies:
+//
+// Derivation: IEnumFORMATETC
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 15-Apr-94 alexgo author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+STDMETHODIMP CGenEnumFormatEtc::Skip( ULONG celt )
+{
+ HRESULT hresult = NOERROR;
+
+ m_iCurrent += celt;
+
+ if( m_iCurrent > m_cTotal )
+ {
+ // whoops, skipped to far ahead. Set us to the max limit.
+ m_iCurrent = m_cTotal;
+ hresult = ResultFromScode(S_FALSE);
+ }
+
+ return hresult;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Member: CGenEnumFormatEtc::Reset
+//
+// Synopsis: resets the seek pointer to zero
+//
+// Effects:
+//
+// Arguments: void
+//
+// Requires:
+//
+// Returns: NOERROR
+//
+// Signals:
+//
+// Modifies:
+//
+// Derivation: IEnumFORMATETC
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 15-Apr-94 alexgo author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+STDMETHODIMP CGenEnumFormatEtc::Reset( void )
+{
+ m_iCurrent = 0;
+
+ return NOERROR;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Member: CGenEnumFormatEtc::Clone
+//
+// Synopsis: clones the enumerator
+//
+// Effects:
+//
+// Arguments: [ppIEnum] -- where to put the cloned enumerator
+//
+// Requires:
+//
+// Returns: HRESULT
+//
+// Signals:
+//
+// Modifies:
+//
+// Derivation: IEnumFORMATETC
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 15-Apr-94 alexgo author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+STDMETHODIMP CGenEnumFormatEtc::Clone( IEnumFORMATETC **ppIEnum )
+{
+ HRESULT hresult = ResultFromScode(E_OUTOFMEMORY);
+ CGenEnumFormatEtc * pClipEnum;
+
+ *ppIEnum = NULL;
+
+ pClipEnum = new CGenEnumFormatEtc();
+
+ // ref count will be 1 and m_iCurrent will be zero.
+
+ if( pClipEnum )
+ {
+ pClipEnum->m_cTotal = m_cTotal;
+ pClipEnum->m_rgFormats = new FORMATETC[m_cTotal];
+ pClipEnum->m_iCurrent = m_iCurrent;
+
+ assert(pClipEnum->m_rgFormats);
+
+ if( pClipEnum->m_rgFormats )
+ {
+ // copy our formatetc's into the cloned enumerator's
+ // array
+ memcpy(pClipEnum->m_rgFormats, m_rgFormats,
+ m_cTotal * sizeof(FORMATETC) );
+
+ *ppIEnum = pClipEnum;
+
+ hresult = NOERROR;
+ }
+ else
+ {
+
+ delete pClipEnum;
+ }
+ }
+
+ return hresult;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Member: CGenEnumFormatEtc::CGenEnumFormatEtc, private
+//
+// Synopsis: constructor
+//
+// Effects:
+//
+// Arguments: void
+//
+// Requires:
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Derivation:
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 15-Apr-94 alexgo author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+CGenEnumFormatEtc::CGenEnumFormatEtc( void )
+{
+ m_refs = 1; // give the intial reference
+ m_rgFormats = NULL;
+ m_iCurrent = 0;
+ m_cTotal = 0;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Member: CGenEnumFormatEtc::~CGenEnumFormatEtc, private
+//
+// Synopsis: destructor
+//
+// Effects:
+//
+// Arguments: void
+//
+// Requires:
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Derivation:
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 15-Apr-94 alexgo author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+CGenEnumFormatEtc::~CGenEnumFormatEtc( void )
+{
+ if( m_rgFormats )
+ {
+ delete m_rgFormats;
+ }
+}
+
+//+-------------------------------------------------------------------------
+//
+// Member: CGenEnumFormatEtc::Create, static, public
+//
+// Synopsis: Creates a clipboard formatetc enumerator
+//
+// Effects:
+//
+// Arguments: [ppIEnum] -- where to put the enumerator
+//
+// Requires: the clipboard must be open
+//
+// Returns: HRESULT
+//
+// Signals:
+//
+// Modifies:
+//
+// Derivation:
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 15-Apr-94 alexgo author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+HRESULT CGenEnumFormatEtc::Create( IEnumFORMATETC **ppIEnum,
+ FORMATETC *prgFormats, DWORD cFormats )
+{
+ HRESULT hresult = ResultFromScode(E_OUTOFMEMORY);
+ CGenEnumFormatEtc * pClipEnum;
+
+
+ *ppIEnum = NULL;
+
+ pClipEnum = new CGenEnumFormatEtc();
+
+ assert(pClipEnum);
+
+ // now allocate memory for the array
+
+ pClipEnum->m_rgFormats = new FORMATETC[cFormats];
+
+ assert(pClipEnum->m_rgFormats);
+
+ pClipEnum->m_cTotal = cFormats;
+
+ memcpy(pClipEnum->m_rgFormats, prgFormats,
+ cFormats * sizeof(FORMATETC));
+
+ *ppIEnum = pClipEnum;
+
+ return NOERROR;
+}
+
+
diff --git a/private/oleutest/oletest/gendata.h b/private/oleutest/oletest/gendata.h
new file mode 100644
index 000000000..5a367c12e
--- /dev/null
+++ b/private/oleutest/oletest/gendata.h
@@ -0,0 +1,181 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: gendata.h
+//
+// Contents: Declaration of a generic data object.
+//
+// Classes: CGenDataObject
+//
+// Functions:
+//
+// History: dd-mmm-yy Author Comment
+// 24-Mar-94 alexgo author
+//
+//--------------------------------------------------------------------------
+
+#ifndef _GENDATA_H
+#define _GENDATA_H
+
+// flags used by OLE1 compatibilty mode
+
+typedef enum
+{
+ OLE1_OFFER_OWNERLINK = 1,
+ OLE1_OFFER_OBJECTLINK = 2,
+ OLE1_OFFER_NATIVE = 4,
+ OLE1_OWNERLINK_PRECEDES_NATIVE = 8
+} Ole1TestFlags;
+
+// more flags used to control what formats are offered
+
+typedef enum
+{
+ OFFER_TESTSTORAGE = 1,
+ OFFER_EMBEDDEDOBJECT = 2
+} DataFlags;
+
+
+//+-------------------------------------------------------------------------
+//
+// Class: CGenDataObject
+//
+// Purpose: generic data object (for clipboard data transfers, etc)
+//
+// Interface: IDataObject
+//
+// History: dd-mmm-yy Author Comment
+// 24-Mar-94 alexgo author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+class CGenDataObject : public IDataObject
+{
+public:
+ // IUnknown methods
+ STDMETHOD(QueryInterface)(REFIID riid, LPVOID FAR* ppvObj);
+ STDMETHOD_(ULONG,AddRef)(void);
+ STDMETHOD_(ULONG,Release)(void);
+
+ // IDataObject methods
+ STDMETHOD(GetData)(LPFORMATETC pformatetcIn, LPSTGMEDIUM pmedium);
+ STDMETHOD(GetDataHere)(THIS_ LPFORMATETC pformatetc,
+ LPSTGMEDIUM pmedium);
+ STDMETHOD(QueryGetData)(THIS_ LPFORMATETC pformatetc);
+ STDMETHOD(GetCanonicalFormatEtc)(LPFORMATETC pformatetc,
+ LPFORMATETC pformatetcOut);
+ STDMETHOD(SetData)(LPFORMATETC pformatetc,
+ STGMEDIUM FAR* pmedium, BOOL fRelease);
+ STDMETHOD(EnumFormatEtc)(DWORD dwDirection,
+ LPENUMFORMATETC FAR* ppenumFormatEtc);
+ STDMETHOD(DAdvise)(FORMATETC FAR* pFormatetc, DWORD advf,
+ IAdviseSink FAR* pAdvSink, DWORD FAR* pdwConnection);
+ STDMETHOD(DUnadvise)(DWORD dwConnection);
+ STDMETHOD(EnumDAdvise)(LPENUMSTATDATA FAR* ppenumAdvise);
+
+ // constructor
+ CGenDataObject();
+
+ // test functions
+
+ BOOL VerifyFormatAndMedium(FORMATETC *pformatetc, STGMEDIUM *pmedium);
+
+ // OLE1 compatibility test functions
+
+ void SetupOle1Mode( Ole1TestFlags fFlags );
+ HRESULT SetOle1ToClipboard( void );
+
+ // Used by various tests, controls what formats are offered by
+ // the data object
+
+ void SetDataFormats( DataFlags fFlags );
+
+ // Indicates whether or not QueryInterface was called. Used by
+ // OleQueryXXX tests.
+
+ BOOL HasQIBeenCalled();
+
+ // test clipboard formats
+
+ UINT m_cfTestStorage;
+ UINT m_cfEmbeddedObject;
+ UINT m_cfEmbedSource;
+ UINT m_cfObjectDescriptor;
+ UINT m_cfLinkSource;
+ UINT m_cfLinkSrcDescriptor;
+ UINT m_cfOwnerLink;
+ UINT m_cfObjectLink;
+ UINT m_cfNative;
+
+private:
+ IStorage * GetTestStorage(void);
+
+ BOOL VerifyTestStorage(FORMATETC *pformatetc,
+ STGMEDIUM *pmedium);
+
+ ULONG m_refs; // reference count
+ DWORD m_cFormats; // number of formats supported
+ FORMATETC * m_rgFormats; // the formats
+
+ // OLE1 support functions and data
+ HGLOBAL GetOwnerOrObjectLink(void);
+ HGLOBAL GetNativeData(void);
+
+ BOOL VerifyOwnerOrObjectLink( FORMATETC *pformatec,
+ STGMEDIUM *pmedium);
+ BOOL VerifyNativeData( FORMATETC *pformatetc,
+ STGMEDIUM *pmedium);
+
+ Ole1TestFlags m_fOle1; // OLE1 configuration flags
+ BOOL m_fQICalled;
+
+};
+
+//+-------------------------------------------------------------------------
+//
+// Class: CGenEnumFormatEtc
+//
+// Purpose: Enumerator for the formats available on the generic data
+// object
+//
+// Interface: IEnumFORMATETC
+//
+// History: dd-mmm-yy Author Comment
+// 15-Apr-94 alexgo author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+class CGenEnumFormatEtc :public IEnumFORMATETC
+{
+public:
+ STDMETHOD(QueryInterface)(REFIID riid, void **ppvObj);
+ STDMETHOD_(ULONG,AddRef)(void);
+ STDMETHOD_(ULONG,Release)(void);
+
+ STDMETHOD(Next) (ULONG celt, FORMATETC *rgelt,
+ ULONG *pceltFetched);
+ STDMETHOD(Skip) (ULONG celt);
+ STDMETHOD(Reset) (void);
+ STDMETHOD(Clone) (IEnumFORMATETC **ppenum);
+
+ static HRESULT Create(IEnumFORMATETC **ppIEnum, FORMATETC *prgFormats,
+ DWORD cFormats);
+
+private:
+ CGenEnumFormatEtc(); // constructor
+ ~CGenEnumFormatEtc(); // destructor
+
+ ULONG m_refs; // reference count
+ ULONG m_iCurrent; // current clipboard format
+ ULONG m_cTotal; // total number of formats
+ FORMATETC * m_rgFormats; // array of available formats
+};
+
+
+#endif // !_GENDATA_H
diff --git a/private/oleutest/oletest/genenum.cpp b/private/oleutest/oletest/genenum.cpp
new file mode 100644
index 000000000..c52cca8a5
--- /dev/null
+++ b/private/oleutest/oletest/genenum.cpp
@@ -0,0 +1,335 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: genenum.cpp
+//
+// Contents: implementation of CGenDataObject
+//
+// Classes:
+//
+// Functions:
+//
+// History: dd-mmm-yy Author Comment
+// 24-May-94 kennethm author
+//
+//--------------------------------------------------------------------------
+
+#include "oletest.h"
+#include "genenum.h"
+
+//+-------------------------------------------------------------------------
+//
+// Member: CEnumeratorTest::CEnumeratorTest
+//
+// Synopsis: Constructor
+//
+// Effects:
+//
+// Arguments: [penum] -- Enumerator Interface cast to void*
+// [ElementSize] -- Size of elements return from next
+// [ElementCount] -- Numer of elements that should be in the enumeration,
+// -1 if unknown.
+//
+// Requires:
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Derivation:
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 24-May-94 kennethm author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+CEnumeratorTest::CEnumeratorTest(
+ void *penum,
+ size_t ElementSize,
+ LONG ElementCount,
+ HRESULT& rhr)
+{
+ assert(penum);
+
+ m_pEnumTest = (IGenEnum*)penum;
+
+ m_ElementSize = ElementSize;
+ m_ElementCount = ElementCount;
+
+ rhr = m_pEnumTest->Reset();
+
+ if (rhr != S_OK)
+ {
+ OutputStr(("IEnumnX: Reset failed (%lx)\r\n", rhr));
+ }
+}
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: CEnumeratorTest::GetNext
+//
+// Synopsis: Internal Next Implementation. Does some basic checks on the
+// return values.
+//
+// Effects:
+//
+// Arguments: [celt] -- the number of items to fetch
+// [pceltFetched] -- the number of items fetched
+// [phresult] -- the return from next
+//
+// Requires:
+//
+// Returns: True if the basic tests passed, false if they didn't
+// The result of the next call itself is passed in param 3.
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm: Checks:
+// That if s_ok is returned celt and pceltFetched are ==
+// If a verify is provided it is called
+//
+// History: dd-mmm-yy Author Comment
+// 24-May-94 kennethm author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+BOOL CEnumeratorTest::GetNext( ULONG celt,
+ ULONG* pceltFetched,
+ HRESULT* phresult
+ )
+{
+ void* prgelt;
+ ULONG ul;
+ BOOL fRet = TRUE;
+
+ // Allocate memory for the return elements
+
+ prgelt = new char[m_ElementSize * celt];
+
+ assert(prgelt);
+
+ // Call next
+
+ *phresult = m_pEnumTest->Next(celt, prgelt, pceltFetched);
+
+ // If the return result is S_OK make sure the numbers match
+
+ if (*phresult == S_OK)
+ {
+ if ((pceltFetched) && (celt != *pceltFetched))
+ {
+ OutputStr(("IEnumX::Next return S_OK but celt"
+ " and pceltFetch mismatch.\r\n"));
+ return(FALSE);
+ }
+ }
+
+ // Call verify to make sure the elements are ok.
+
+ if ((*phresult == NOERROR) || (*phresult == ResultFromScode(S_FALSE)))
+ {
+ // loop through every returned element
+
+ for (ul=0; ul < *pceltFetched ; ul++)
+ {
+ if (!Verify(prgelt))
+ {
+ OutputStr(("Data elment %d returned by IEnumX::Next is bad.\r\n",
+ ul));
+
+ fRet = FALSE;
+ // we keep looping anyway just to
+ // free up resources.
+ }
+
+ // If the user supplied a cleanup function there is additional
+ // memory that needs to be freed
+
+ CleanUp(prgelt);
+ }
+
+ }
+
+ free (prgelt);
+
+ return fRet;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Method: CEnumeratorTest::TestNext
+//
+// Synopsis: Test the next enumerator methods
+//
+// Effects:
+//
+// Arguments: None.
+//
+// Requires:
+//
+// Returns: HRESULT
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 24-May-94 kennethm author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+HRESULT CEnumeratorTest::TestNext(void)
+{
+ ULONG celtFetched;
+ LONG InternalCount = 0;
+ HRESULT hresult;
+
+ // First we want to count the element by doing a next on each one.
+
+ do {
+ if (!GetNext(1, &celtFetched, &hresult))
+ {
+ return ResultFromScode(E_FAIL);
+ }
+ if (hresult == S_OK)
+ {
+ InternalCount++;
+ }
+
+ } while ( hresult == S_OK );
+
+ // If the user passed in an ammount make sure it matches what we got
+
+ if ((m_ElementCount != -1) && (InternalCount != m_ElementCount))
+ {
+ OutputStr(("IEnumX: enumerated count and passed count do not match!\r\n"));
+ return ResultFromScode(E_FAIL);
+ }
+
+ m_pEnumTest->Reset();
+
+ // Make sure we fail on ...Next(celt>1, ...,NULL)
+
+ /* BUGBUG: clipboard enumerator fails on this test
+
+ if (GetNext(2, NULL, &hresult))
+ {
+ if ((hresult == S_OK ) || (hresult == S_FALSE))
+ {
+ (("IEnumX: celt>1 pceltFetched==NULL returned S_OK\r\n"));
+ return(E_FAIL);
+ }
+ }
+ else
+ {
+ return(E_FAIL);
+ }
+
+ */
+
+ return(S_OK);
+
+}
+
+//+-------------------------------------------------------------------------
+//
+// Method: CEnumeratorTest::TestAll
+//
+// Synopsis: This function calls all the tests
+//
+// Effects:
+//
+// Arguments: None
+//
+// Requires:
+//
+// Returns: HRESULT
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 24-May-94 kennethm author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+HRESULT CEnumeratorTest::TestAll(void)
+{
+ return(TestNext());
+
+
+}
+
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Method: CEnumeratorTest::VerifyAll
+//
+// Synopsis: Verify entire array of returned results.
+//
+// Arguments: None
+//
+// Returns: HRESULT
+//
+// Algorithm: Just default to saying everything is ok
+//
+// History: dd-mmm-yy Author Comment
+// 24-May-94 ricksa author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+BOOL CEnumeratorTest::VerifyAll(void *pv, LONG cl)
+{
+ return TRUE;
+}
+
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Method: CEnumeratorTest::CleanUp
+//
+// Synopsis: Default implementation of cleanup
+//
+// Arguments: [pv] - pointer to entry enumerated
+//
+// Algorithm: If there is nothing special to free this implementation
+// can be used.
+//
+// History: dd-mmm-yy Author Comment
+// 24-May-94 ricksa author
+//
+//--------------------------------------------------------------------------
+
+void CEnumeratorTest::CleanUp(void *pv)
+{
+ return;
+}
diff --git a/private/oleutest/oletest/genenum.h b/private/oleutest/oletest/genenum.h
new file mode 100644
index 000000000..d0ea79743
--- /dev/null
+++ b/private/oleutest/oletest/genenum.h
@@ -0,0 +1,105 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: genenum.h
+//
+// Contents: Declaration of a generic enum object and test object.
+//
+// Classes: CGenEnumObject
+//
+// Functions:
+//
+// History: dd-mmm-yy Author Comment
+// 23-May-94 kennethm author! author!
+//
+//--------------------------------------------------------------------------
+
+#ifndef _GENENUM_H
+#define _GENENUM_H
+
+//
+// This macro allows the code to use a different outputstring function.
+//
+
+#define OutputStr(a) OutputString a
+
+//+-------------------------------------------------------------------------
+//
+// Class: IGenEnum
+//
+// Purpose: generic enumerator
+//
+// Interface: Abstract class
+//
+// History: dd-mmm-yy Author Comment
+// 23-May-94 kennethm author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+class IGenEnum
+{
+public:
+ STDMETHOD(QueryInterface)(REFIID riid, void **ppvObj) = 0;
+ STDMETHOD_(ULONG,AddRef)(void) = 0;
+ STDMETHOD_(ULONG,Release)(void) = 0;
+
+ STDMETHOD(Next) (ULONG celt, void *rgelt,
+ ULONG *pceltFetched) = 0;
+ STDMETHOD(Skip) (ULONG celt) = 0;
+ STDMETHOD(Reset) (void) = 0;
+ STDMETHOD(Clone) (void **ppenum) = 0;
+};
+
+//+-------------------------------------------------------------------------
+//
+// Class: CEnumeratorTest
+//
+// Purpose: enumerator test class
+//
+// Interface:
+//
+// History: dd-mmm-yy Author Comment
+// 23-May-94 kennethm author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+class CEnumeratorTest
+{
+public:
+ // Constructor
+
+ CEnumeratorTest(
+ void *penum,
+ size_t ElementSize,
+ LONG ElementCount,
+ HRESULT& rhr);
+
+ // Test for each enumerator object
+
+ HRESULT TestAll(void);
+ HRESULT TestNext(void);
+// NYI! HRESULT TestSkip(void);
+// HRESULT TestClone(void);
+// HRESULT TestRelease(void);
+
+ // For derived classes which know what we are enumerating
+ virtual BOOL Verify(void *) = 0;
+ virtual BOOL VerifyAll(void *, LONG);
+ virtual void CleanUp(void *);
+
+private:
+
+ BOOL GetNext(ULONG celt, ULONG* pceltFetched, HRESULT* phresult);
+
+ IGenEnum * m_pEnumTest;
+ size_t m_ElementSize;
+ LONG m_ElementCount;
+};
+
+#endif // !_GENENUM_H
diff --git a/private/oleutest/oletest/letest.h b/private/oleutest/oletest/letest.h
new file mode 100644
index 000000000..9ae45f9fc
--- /dev/null
+++ b/private/oleutest/oletest/letest.h
@@ -0,0 +1,49 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: letest.h
+//
+// Contents: declarations for all upper-layer test routines
+//
+// Classes:
+//
+// Functions:
+//
+// History: dd-mmm-yy Author Comment
+// 06-Feb-94 alexgo author
+//
+//--------------------------------------------------------------------------
+
+#ifndef _LETEST_H
+#define _LETEST_H
+
+struct SLETestInfo
+{
+ char *pszPgm;
+ UINT dwMsgId;
+};
+
+extern SLETestInfo letiInsertObjectTest1;
+extern SLETestInfo letiInsertObjectTest2;
+
+extern SLETestInfo letiInplaceTest1;
+
+extern SLETestInfo letiOle1Test1;
+extern SLETestInfo letiOle1Test2;
+extern SLETestInfo letiClipTest;
+
+void LETest1( void * );
+HRESULT LEClipTest1( void );
+HRESULT LEClipTest2( void );
+HRESULT LEOle1ClipTest1( void );
+void LEOle1ClipTest2( void *);
+
+HRESULT LEDataAdviseHolderTest( void );
+HRESULT LEOleAdviseHolderTest( void );
+
+HRESULT TestOleQueryCreateFromDataMFCHack( void );
+
+
+#endif //!_LETEST_H
diff --git a/private/oleutest/oletest/letests.cpp b/private/oleutest/oletest/letests.cpp
new file mode 100644
index 000000000..7f1534360
--- /dev/null
+++ b/private/oleutest/oletest/letests.cpp
@@ -0,0 +1,155 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: letests.cpp
+//
+// Contents: upper layer tests
+//
+// Classes:
+//
+// Functions: LETest1
+//
+// History: dd-mmm-yy Author Comment
+// 06-Feb-94 alexgo author
+//
+//--------------------------------------------------------------------------
+
+#include "oletest.h"
+#include "letest.h"
+
+// Test1 information
+SLETestInfo letiInsertObjectTest1 = { "simpdnd", WM_TEST1 };
+
+SLETestInfo letiInplaceTest1 = { "simpcntr", WM_TEST1 };
+SLETestInfo letiOle1Test1 = { "simpdnd", WM_TEST2 };
+
+// Test2 information
+SLETestInfo letiInsertObjectTest2 = { "spdnd16", WM_TEST1 };
+
+SLETestInfo letiOle1Test2 = { "spdnd16", WM_TEST2 };
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: LETestCallback
+//
+// Synopsis: generic callback function for running L&E tests.
+//
+// Effects:
+//
+// Arguments: pvArg -- the test message to send to the app
+//
+// Requires:
+//
+// Returns: void
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm: Create the process and wait for it to finish. The exit
+// status is then returned.
+//
+// History: dd-mmm-yy Author Comment
+// 06-Feb-94 alexgo author
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+void LETestCallback( void *pvArg )
+{
+ //the test app (simpdnd) should have just sent us a WM_TESTREG message.
+
+ assert(vApp.m_message == WM_TESTREG);
+
+ vApp.m_rgTesthwnd[0] = (HWND)vApp.m_wparam;
+
+ //now tell the app to start the requested test
+ OutputString( "Tell LETest to Start\r\n");
+
+ PostMessage(vApp.m_rgTesthwnd[0], (UINT)pvArg, 0, 0);
+
+ return;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: LETest1
+//
+// Synopsis: Runs the app specified in the argument
+//
+// Effects:
+//
+// Arguments: pvArg -- unused
+//
+// Requires:
+//
+// Returns: void
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm: Create the process and wait for it to finish. The exit
+// status is then returned.
+//
+// History: dd-mmm-yy Author Comment
+// 06-Feb-94 alexgo author
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+void LETest1( void *pvArg )
+{
+ SLETestInfo *pleti = (SLETestInfo *) pvArg;
+
+#ifdef WIN32
+
+ PROCESS_INFORMATION procinfo;
+ static STARTUPINFO startinfo; //to make it all zero
+ char szBuf[128];
+
+ //initialize the command line
+
+ sprintf(szBuf, "%s%s -driver %lu",
+ vApp.m_pszDebuggerOption,
+ pleti->pszPgm,
+ vApp.m_hwndMain);
+
+ startinfo.cb = sizeof(startinfo);
+
+ if( CreateProcess(NULL, szBuf, NULL, NULL, NULL, NULL, NULL,
+ NULL, &startinfo, &procinfo) )
+ {
+ //simpdnd launched, stuff a callback function in the stack
+ vApp.m_TaskStack.Push(LETestCallback,
+ (void *)((ULONG)pleti->dwMsgId));
+ }
+ else
+ {
+ vApp.m_wparam = TEST_FAILURE;
+ vApp.m_lparam = (LPARAM)GetLastError();
+ vApp.m_message = WM_TESTEND;
+
+ HandleTestEnd();
+ }
+
+ return;
+
+#else
+ // 16bit Version!!
+
+ vApp.m_wparam = TEST_SUCCESS;
+ vApp.m_lparam = 0;
+ vApp.m_message = WM_TESTEND;
+
+ HandleTestEnd();
+
+ return;
+
+#endif // WIN32
+
+}
diff --git a/private/oleutest/oletest/oleadv.cpp b/private/oleutest/oletest/oleadv.cpp
new file mode 100644
index 000000000..b1d408115
--- /dev/null
+++ b/private/oleutest/oletest/oleadv.cpp
@@ -0,0 +1,943 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: oleadv.cpp
+//
+// Contents: implementation of unit test for Ole Advise Holder
+//
+// Classes: CTestPretendMoniker
+// COaTestAdviseSink
+// COaTestObj
+//
+// Functions: NotifyOfChanges
+// TestSingleOleAdvise
+// TestMassOleAdvise
+// TestOleAdviseHolderEnumerator
+// LEOleAdviseHolderTest
+//
+// History: dd-mmm-yy Author Comment
+// 27-May-94 ricksa author
+//
+//--------------------------------------------------------------------------
+#include "oletest.h"
+
+
+#define MAX_OA_TO_REGISTER 100
+
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Class: CTestPretendMoniker
+//
+// Purpose: Use where we need a moniker to confirm reciept of OnRename
+//
+// Interface: QueryInterface - get a new interface
+// AddRef - add a reference
+// Release - remove a reference
+// VerifySig - verify signiture is correct
+//
+// History: dd-mmm-yy Author Comment
+// 01-Jun-94 Ricksa Created
+//
+// Notes: This only supports IUnknown
+//
+//--------------------------------------------------------------------------
+class CTestPretendMoniker : public IUnknown
+{
+public:
+ CTestPretendMoniker(void);
+
+ // IUnknown methods
+ HRESULT __stdcall QueryInterface(REFIID riid, LPVOID FAR* ppvObj);
+
+ ULONG __stdcall AddRef(void);
+
+ ULONG __stdcall Release(void);
+
+ BOOL VerifySig(void);
+
+private:
+
+ enum Sigs { SIG1 = 0x01020304, SIG2 = 0x04030201 };
+
+ LONG _lRefs;
+
+ Sigs _sig1;
+
+ Sigs _sig2;
+
+};
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Member: CTestPretendMoniker::CTestPretendMoniker
+//
+// Synopsis: Initialize object
+//
+// History: dd-mmm-yy Author Comment
+// 01-Jun-94 Ricksa Created
+//
+//--------------------------------------------------------------------------
+CTestPretendMoniker::CTestPretendMoniker(void)
+ : _lRefs(0), _sig1(SIG1), _sig2(SIG2)
+{
+ // Header does all the work
+}
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Member: CTestPretendMoniker::VerifySig
+//
+// Synopsis: Verify signiture is as expected
+//
+// History: dd-mmm-yy Author Comment
+// 01-Jun-94 Ricksa Created
+//
+//--------------------------------------------------------------------------
+BOOL CTestPretendMoniker::VerifySig(void)
+{
+ return (_sig1 == SIG1 && _sig2 == SIG2);
+}
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Member: CTestPretendMoniker::QueryInterface
+//
+// Synopsis: Return a supported interface
+//
+// Arguments: [riid] - interface id requested
+// [ppvObj] - where to put the interface
+//
+// Returns: S_OK - we are returning an interface
+// E_NOINTERFACE - we do not support the requested interface
+//
+// History: dd-mmm-yy Author Comment
+// 01-Jun-94 Ricksa Created
+//
+//--------------------------------------------------------------------------
+HRESULT __stdcall CTestPretendMoniker::QueryInterface(
+ REFIID riid,
+ LPVOID *ppvObj)
+{
+ if (IsEqualGUID(IID_IUnknown, riid) || IsEqualGUID(IID_IMoniker, riid))
+ {
+ AddRef();
+ *ppvObj = this;
+ return NOERROR;
+ }
+
+ *ppvObj = NULL;
+ return E_NOINTERFACE;
+}
+
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Member: CTestPretendMoniker::AddRef
+//
+// Synopsis: Bump reference count
+//
+// History: dd-mmm-yy Author Comment
+// 01-Jun-94 Ricksa Created
+//
+//--------------------------------------------------------------------------
+ULONG __stdcall CTestPretendMoniker::AddRef(void)
+{
+ return _lRefs++;
+}
+
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Member: CTestPretendMoniker::Release
+//
+// Synopsis: Decrement the reference count
+//
+// History: dd-mmm-yy Author Comment
+// 01-Jun-94 Ricksa Created
+//
+//--------------------------------------------------------------------------
+ULONG __stdcall CTestPretendMoniker::Release(void)
+{
+ assert(_lRefs >= 1);
+
+ return --_lRefs;
+}
+
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Class: COaTestAdviseSink
+//
+// Purpose: Advise sink for use in testing the Ole Advise Holder
+//
+// Interface: QueryInterface - get supported interface pointer
+// AddRef - bump reference count
+// Release - decrement reference count
+// OnDataChange - not implemented
+// OnViewChange - not implemented
+// OnRename - rename notification
+// OnSave - save notification
+// OnClose - close notification
+// VerifyNotifications - verify all expected notifications arrived
+//
+// History: dd-mmm-yy Author Comment
+// 01-Jun-94 Ricksa Created
+//
+// Notes: We only support parts of advise sink we need to test the
+// advise holder.
+//
+//--------------------------------------------------------------------------
+class COaTestAdviseSink : public IAdviseSink
+{
+public:
+ COaTestAdviseSink(void);
+
+ // IUnknown methods
+ HRESULT __stdcall QueryInterface(REFIID riid, LPVOID FAR* ppvObj);
+
+ ULONG __stdcall AddRef(void);
+
+ ULONG __stdcall Release(void);
+
+ // IAdviseSink methods
+ void __stdcall OnDataChange(FORMATETC *pFormatetc, STGMEDIUM *pStgmed);
+
+ void __stdcall OnViewChange(
+ DWORD dwAspect,
+ LONG lindex);
+
+ void __stdcall OnRename(IMoniker *pmk);
+
+ void __stdcall OnSave(void);
+
+ void __stdcall OnClose(void);
+
+ // Test methods used for verification
+ BOOL VerifyNotifications(void);
+
+private:
+
+ LONG _lRefs;
+
+ BOOL _fOnCloseNotify;
+
+ BOOL _fOnSaveNotify;
+
+ BOOL _fOnRenameNotify;
+};
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Member: COaTestAdviseSink::COaTestAdviseSink
+//
+// Synopsis: Initialize advise sink
+//
+// History: dd-mmm-yy Author Comment
+// 01-Jun-94 Ricksa Created
+//
+//--------------------------------------------------------------------------
+COaTestAdviseSink::COaTestAdviseSink(void)
+ : _lRefs(1), _fOnCloseNotify(FALSE), _fOnSaveNotify(FALSE),
+ _fOnRenameNotify(FALSE)
+{
+ // Header does all the work
+}
+
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Member: COaTestAdviseSink::QueryInterface
+//
+// Synopsis: Return requested interface pointer
+//
+// Arguments: [riid] - interface id requested
+// [ppvObj] - where to put the interface
+//
+// Returns: S_OK - we are returning an interface
+// E_NOINTERFACE - we do not support the requested interface
+//
+// History: dd-mmm-yy Author Comment
+// 01-Jun-94 Ricksa Created
+//
+//--------------------------------------------------------------------------
+HRESULT __stdcall COaTestAdviseSink::QueryInterface(
+ REFIID riid,
+ LPVOID *ppvObj)
+{
+ if (IsEqualGUID(IID_IUnknown, riid) || IsEqualGUID(IID_IAdviseSink, riid))
+ {
+ AddRef();
+ *ppvObj = this;
+ return NOERROR;
+ }
+
+ *ppvObj = NULL;
+ return E_NOINTERFACE;
+}
+
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Member: COaTestAdviseSink::AddRef
+//
+// Synopsis: Bump reference count
+//
+// History: dd-mmm-yy Author Comment
+// 01-Jun-94 Ricksa Created
+//
+//--------------------------------------------------------------------------
+ULONG __stdcall COaTestAdviseSink::AddRef(void)
+{
+ return _lRefs++;
+}
+
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Member: COaTestAdviseSink::Release
+//
+// Synopsis: Decrement reference count
+//
+// History: dd-mmm-yy Author Comment
+// 01-Jun-94 Ricksa Created
+//
+//--------------------------------------------------------------------------
+ULONG __stdcall COaTestAdviseSink::Release(void)
+{
+ assert(_lRefs >= 1);
+
+ return --_lRefs;
+}
+
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Member: COaTestAdviseSink::OnDataChange
+//
+// Synopsis: Notify of change in data
+//
+// Arguments: [pFormatetc] - FORMATETC of data
+// [pStgmed] - storage medium for data
+//
+// History: dd-mmm-yy Author Comment
+// 01-Jun-94 Ricksa Created
+//
+// Notes: Not supported for this object
+//
+//--------------------------------------------------------------------------
+void __stdcall COaTestAdviseSink::OnDataChange(
+ FORMATETC *pFormatetc,
+ STGMEDIUM *pStgmed)
+{
+ OutputString("COaTestAdviseSink::OnDataChange Unexpectedly Called!\r\n");
+}
+
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Member: COaTestAdviseSink::OnViewChange
+//
+// Synopsis: Notify that view should change
+//
+// Arguments: [dwAspect] - specifies view of the object
+// [lindex] - which piece of view changed
+//
+// History: dd-mmm-yy Author Comment
+// 01-Jun-94 Ricksa Created
+//
+// Notes: Not supported for this object
+//
+//--------------------------------------------------------------------------
+void __stdcall COaTestAdviseSink::OnViewChange(
+ DWORD dwAspect,
+ LONG lindex)
+{
+ OutputString("COaTestAdviseSink::OnViewChange Unexpectedly Called!\r\n");
+}
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Member: COaTestAdviseSink::OnRename
+//
+// Synopsis: Notifies of rename operation
+//
+// Arguments: [pmk] - new full name of the object
+//
+// History: dd-mmm-yy Author Comment
+// 01-Jun-94 Ricksa Created
+//
+//--------------------------------------------------------------------------
+void __stdcall COaTestAdviseSink::OnRename(IMoniker *pmk)
+{
+ // Verify that we get the pretend moniker
+ CTestPretendMoniker *ptpm = (CTestPretendMoniker *) pmk;
+
+ if (ptpm->VerifySig())
+ {
+ _fOnCloseNotify = TRUE;
+ }
+ else
+ {
+ OutputString("OnRename got a bad moniker\r\n");
+ }
+}
+
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Member: COaTestAdviseSink::OnSave
+//
+// Synopsis: Notifies that object has been saved
+//
+// History: dd-mmm-yy Author Comment
+// 01-Jun-94 Ricksa Created
+//
+//--------------------------------------------------------------------------
+void __stdcall COaTestAdviseSink::OnSave(void)
+{
+ _fOnSaveNotify = TRUE;
+}
+
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Member: COaTestAdviseSink::OnClose
+//
+// Synopsis: Notifies that object has been closed
+//
+// History: dd-mmm-yy Author Comment
+// 01-Jun-94 Ricksa Created
+//
+//--------------------------------------------------------------------------
+void __stdcall COaTestAdviseSink::OnClose(void)
+{
+ _fOnRenameNotify = TRUE;
+}
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Member: COaTestAdviseSink::VerifyNotifications
+//
+// Synopsis: Verify that we recieved expected notifications
+//
+// Returns: TRUE - we recieved expected notification
+// FALSE - we didn't receive expected notifications
+//
+// History: dd-mmm-yy Author Comment
+// 01-Jun-94 Ricksa Created
+//
+// Notes: This resets the values after returning the result
+//
+//--------------------------------------------------------------------------
+BOOL COaTestAdviseSink::VerifyNotifications(void)
+{
+ // Save the result of all the notifications
+ BOOL fResult = _fOnCloseNotify && _fOnSaveNotify && _fOnRenameNotify;
+
+ // Reset the notifications
+ _fOnCloseNotify = FALSE;
+ _fOnSaveNotify = FALSE;
+ _fOnRenameNotify = FALSE;
+
+ // Let caller know the result of the notifications
+ return fResult;
+}
+
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Class: COaTestObj
+//
+// Purpose: Provides place to keep information related to an advise
+//
+// Interface: Register - register advise with holder
+// VerifyNotified - verify that object was notified by holder
+// Revoke - revoke registration with holder
+//
+// History: dd-mmm-yy Author Comment
+// 01-Jun-94 Ricksa Created
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+class COaTestObj
+{
+public:
+ COaTestObj(void);
+
+ HRESULT Register(IOleAdviseHolder *poah, char *pszCaller);
+
+ HRESULT VerifyNotified(void);
+
+ HRESULT Revoke(void);
+
+private:
+
+ COaTestAdviseSink _otas;
+
+ DWORD _dwConnection;
+
+ IOleAdviseHolder * _poah;
+
+ char * _pszTest;
+};
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Member: COaTestObj::COaTestObj
+//
+// Synopsis: Initialize object
+//
+// History: dd-mmm-yy Author Comment
+// 01-Jun-94 Ricksa Created
+//
+//--------------------------------------------------------------------------
+COaTestObj::COaTestObj(void) : _dwConnection(0)
+{
+ // Header does all the work
+}
+
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Member: COaTestObj::Register
+//
+// Synopsis: Register advise with the holder
+//
+// Arguments: [poah] - pointer to the advise holder
+// [pszTest] - name of the test
+//
+// Returns: S_OK - registration was successful
+// E_FAIL - registration failed
+//
+// History: dd-mmm-yy Author Comment
+// 01-Jun-94 Ricksa Created
+//
+//--------------------------------------------------------------------------
+HRESULT COaTestObj::Register(IOleAdviseHolder *poah, char *pszTest)
+{
+ // Register the advise
+ HRESULT hr = poah->Advise(&_otas, &_dwConnection);
+
+ // Make sure results are sensible
+ if (hr != NOERROR)
+ {
+ OutputString("%s Registration failed hr = %lx\r\n", pszTest, hr);
+ return E_FAIL;
+ }
+
+ if (_dwConnection == 0)
+ {
+ OutputString("%s Connection not updated\r\n", pszTest);
+ return E_FAIL;
+ }
+
+ // Save these for the revoke
+ _pszTest = pszTest;
+ _poah = poah;
+
+ return NOERROR;
+}
+
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Member: COaTestObj::VerifyNotified
+//
+// Synopsis: Verify that our advise was notified of changes
+//
+// Returns: S_OK - advise was notified of changes
+// E_FAIL - object was not notified.
+//
+// History: dd-mmm-yy Author Comment
+// 01-Jun-94 Ricksa Created
+//
+//--------------------------------------------------------------------------
+HRESULT COaTestObj::VerifyNotified(void)
+{
+ if (!_otas.VerifyNotifications())
+ {
+ OutputString("%s Object not correctly notified\r\n", _pszTest);
+ return E_FAIL;
+ }
+
+ return NOERROR;
+}
+
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Member: COaTestObj::Revoke
+//
+// Synopsis: Revoke our advise registration with advise holder
+//
+// Returns: S_OK - advise was successfully deregistered
+// E_FAIL - revokation experience unexpected result
+//
+// History: dd-mmm-yy Author Comment
+// 01-Jun-94 Ricksa Created
+//
+//--------------------------------------------------------------------------
+HRESULT COaTestObj::Revoke(void)
+{
+ // Remove the advise registration
+ HRESULT hr = _poah->Unadvise(_dwConnection);
+
+ if (hr != NOERROR)
+ {
+ OutputString("%s Revoke failed hr = %lx\r\n", _pszTest, hr);
+ return E_FAIL;
+ }
+
+ // Try the unadvise one more time to make sure it took
+ hr = _poah->Unadvise(_dwConnection);
+
+ if (hr != OLE_E_NOCONNECTION)
+ {
+ OutputString("%s Second revoke bad hr = %lx\r\n", _pszTest, hr);
+ return E_FAIL;
+ }
+
+ return NOERROR;
+}
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: NotifyOfChanges
+//
+// Synopsis: Run through list of possible notifications for advise
+//
+// Arguments: [poahForTest] - advise holder we are testing
+// [pszTest] - test description
+//
+// Returns: NOERROR - all notifications reported success
+// Any Other - error occurred during notification
+//
+// History: dd-mmm-yy Author Comment
+// 01-Jun-94 Ricksa Created
+//
+// Notes: We currently only do the public notifications
+//
+//--------------------------------------------------------------------------
+HRESULT NotifyOfChanges(IOleAdviseHolder *poahForTest, char *pszTest)
+{
+ // Notify Renamed
+ CTestPretendMoniker tpm;
+
+ HRESULT hr = poahForTest->SendOnRename((IMoniker *) &tpm);
+
+ if (hr != NOERROR)
+ {
+ OutputString("%s SendOnRename failed hr = %lx\r\n", pszTest);
+ return hr;
+ }
+
+ // Notify of save
+ hr = poahForTest->SendOnSave();
+
+ if (hr != NOERROR)
+ {
+ OutputString("%s SendOnSave failed hr = %lx\r\n", pszTest);
+ return hr;
+ }
+
+ // Notify of close
+ hr = poahForTest->SendOnClose();
+
+ if (hr != NOERROR)
+ {
+ OutputString("%s SendOnClose failed hr = %lx\r\n", pszTest);
+ return hr;
+ }
+
+ return NOERROR;
+}
+
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: TestSingleOleAdvise
+//
+// Synopsis: Test advise holder with only a single advise
+//
+// Arguments: [poahForTest] - advise holder we are testing
+//
+// Returns: NOERROR - test was successfully passed
+// Any Other - test failed
+//
+// Algorithm: Create a test object. Register that test object with the
+// advise holder. Tell adviser holder to notify all its objects
+// of changes. Verify that test object was notified. Revoke
+// the registration of the test object with the advise holder.
+//
+// History: dd-mmm-yy Author Comment
+// 01-Jun-94 Ricksa Created
+//
+//--------------------------------------------------------------------------
+HRESULT TestSingleOleAdvise(IOleAdviseHolder *poahForTest)
+{
+ char *pszTest = "TestSingleOleAdvise";
+ COaTestObj oto;
+
+ // Register a single advise
+ HRESULT hr = oto.Register(poahForTest, pszTest);
+
+ if (hr != NOERROR)
+ {
+ return hr;
+ }
+
+ // Notifiy it of changes
+ hr = NotifyOfChanges(poahForTest, pszTest);
+
+ if (hr != NOERROR)
+ {
+ return hr;
+ }
+
+ // Verify that notifications occurred
+ hr = oto.VerifyNotified();
+
+ if (hr != NOERROR)
+ {
+ return hr;
+ }
+
+ // Revoke all advises
+ return oto.Revoke();
+}
+
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: TestMassOleAdvise
+//
+// Synopsis: Test registering a very large number of advises
+//
+// Arguments: [poahForTest] - advise holder we are testing
+//
+// Returns: NOERROR - test was successfully passed
+// Any Other - test failed
+//
+// Algorithm: Create a large number of test objects. Then register all
+// those with the advise holder for changes. Tell advise holder
+// to notify all its registered objects of changes. Verify that
+// each of the test objects recieved a notification. Finally,
+// revoke all the test object registrations.
+//
+// History: dd-mmm-yy Author Comment
+// 01-Jun-94 Ricksa Created
+//
+//--------------------------------------------------------------------------
+HRESULT TestMassOleAdvise(IOleAdviseHolder *poahForTest)
+{
+ char *pszTest = "TestMassOleAdviseHolder";
+
+ // Create a large number of advises
+ COaTestObj aoto[MAX_OA_TO_REGISTER];
+
+ HRESULT hr;
+
+ // Register all the advises
+ for (int i = 0; i < MAX_OA_TO_REGISTER; i++)
+ {
+ hr = aoto[i].Register(poahForTest, pszTest);
+
+ if (hr != NOERROR)
+ {
+ OutputString("%s Failed on Loop %d\r\n", pszTest, i);
+ return hr;
+ }
+ }
+
+ // Notify all the advises of changes
+ hr = NotifyOfChanges(poahForTest, pszTest);
+
+ if (hr != NOERROR)
+ {
+ return hr;
+ }
+
+ // Verify all objects were notified
+ for (i = 0; i < MAX_OA_TO_REGISTER; i++)
+ {
+ hr = aoto[i].VerifyNotified();
+
+ if (hr != NOERROR)
+ {
+ OutputString("%s Failed on Loop %d\r\n", pszTest, i);
+ return hr;
+ }
+ }
+
+ // Revoke all registrations
+ for (i = 0; i < MAX_OA_TO_REGISTER; i++)
+ {
+ hr = aoto[i].Revoke();
+
+ if (hr != NOERROR)
+ {
+ OutputString("%s Failed on Loop %d\r\n", pszTest, i);
+ return hr;
+ }
+ }
+
+ return NOERROR;
+}
+
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: TestOleAdviseHolderEnumerator
+//
+// Synopsis: Test the OLE Advise Holder enumerator
+//
+// Arguments: [poahForTest] - OLE advise holder we are testing
+//
+// Returns: NOERROR - test passed
+// Any Other - test failed
+//
+// History: dd-mmm-yy Author Comment
+// 01-Jun-94 Ricksa Created
+//
+// Notes: We currently just verify that the enumerator is not implemented
+//
+//--------------------------------------------------------------------------
+HRESULT TestOleAdviseHolderEnumerator(IOleAdviseHolder *poahForTest)
+{
+ char *pszCaller = "TestOleAdviseHolderEnumerator";
+
+ // Confirm no enumerator
+ IEnumSTATDATA *penumAdvise;
+
+ HRESULT hr = poahForTest->EnumAdvise(&penumAdvise);
+
+ if (hr != E_NOTIMPL)
+ {
+ OutputString("%s EnumAdvise Hresult = %lx\r\n", pszCaller, hr);
+ return E_FAIL;
+ }
+
+ if (penumAdvise != NULL)
+ {
+ OutputString("%s EnumAdvise returned advise not NULL\r\n", pszCaller);
+ return E_FAIL;
+ }
+
+ return NOERROR;
+}
+
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: LEOleAdviseHolderTest
+//
+// Synopsis: Unit test for advise holders
+//
+// Returns: NOERROR - test passed
+// Any Other - test failed
+//
+// Algorithm: First we verify that a large number of verification work. Then
+// we verify that a large number of registrations work. Finally,
+// we verify that the enumerator for the OLE advise holder
+// behaves as expected.
+//
+// History: dd-mmm-yy Author Comment
+// 01-Jun-94 Ricksa Created
+//
+//--------------------------------------------------------------------------
+HRESULT LEOleAdviseHolderTest(void)
+{
+ IOleAdviseHolder *poahForTest;
+
+ HRESULT hr = CreateOleAdviseHolder(&poahForTest);
+
+ // Test a single registration
+ if ((hr = TestSingleOleAdvise(poahForTest)) != NOERROR)
+ {
+ return hr;
+ }
+
+
+ // Test a large number of registrations
+ if ((hr = TestMassOleAdvise(poahForTest)) != NOERROR)
+ {
+ return hr;
+ }
+
+
+ // Test Enumerator
+ if ((hr = TestOleAdviseHolderEnumerator(poahForTest)) != NOERROR)
+ {
+ return hr;
+ }
+
+ // Release the advise holder
+ DWORD dwFinalRefs = poahForTest->Release();
+
+ if (dwFinalRefs != 0)
+ {
+ OutputString(
+ "LEOleAdviseHolderTest Final Release is = %d", dwFinalRefs);
+ return E_FAIL;
+ }
+
+ return NOERROR;
+}
diff --git a/private/oleutest/oletest/oletest.cpp b/private/oleutest/oletest/oletest.cpp
new file mode 100644
index 000000000..d3094d89a
--- /dev/null
+++ b/private/oleutest/oletest/oletest.cpp
@@ -0,0 +1,841 @@
+
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: oletest.cpp
+//
+// Contents: WinMain and the main message filter for oletest
+//
+// Classes:
+//
+// Functions: WinMain
+// InitApplication
+// InitInstance
+// MainWndProc
+//
+//
+// History: dd-mmm-yy Author Comment
+//
+//--------------------------------------------------------------------------
+
+#include "oletest.h"
+#include "appwin.h"
+
+#define MAX_WM_USER 0x7FFF
+
+// Global instance of the app class. All interesting app-wide
+// data is contained within this instance.
+
+OleTestApp vApp;
+
+
+// Constant used to identify the edit window
+
+static const int EDITID=1;
+
+//
+// Misc internal prototypes
+//
+
+void ListAllTests();
+void PrintHelp();
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: MainWndProc
+//
+// Synopsis: main window message filter
+//
+// Effects:
+//
+// Arguments: hWnd
+// message
+// wParam
+// lParam
+//
+// Requires:
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 09-Dec-94 MikeW Allow running of single tests from menu
+// 22-Mar-94 alexgo added an edit window for displaying text
+// output.
+// 07-Feb-94 alexgo author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+#ifdef WIN32
+LONG APIENTRY MainWndProc(HWND hWnd, UINT message, UINT wParam, LONG lParam)
+#else
+LONG FAR PASCAL _export MainWndProc(HWND hWnd, UINT message, WPARAM wParam,
+ LPARAM lParam)
+#endif
+
+{
+ //set global variables
+
+ if( (message > WM_USER) && (message <= MAX_WM_USER) )
+ {
+ vApp.m_message = message;
+ vApp.m_wparam = wParam;
+ vApp.m_lparam = lParam;
+ }
+
+ switch (message)
+ {
+ case WM_CREATE:
+ //create the edit window
+
+ vApp.m_hwndEdit = CreateWindow( "edit", NULL,
+ WS_CHILD | WS_VISIBLE | WS_HSCROLL |
+ WS_VSCROLL | WS_BORDER | ES_LEFT |
+ ES_MULTILINE | ES_NOHIDESEL | ES_AUTOHSCROLL |
+ ES_AUTOVSCROLL | ES_READONLY | ES_WANTRETURN,
+ 0,0,0,0,
+ hWnd,(HMENU) EDITID, vApp.m_hinst, NULL );
+
+ // Reset the error status
+
+ vApp.m_fGotErrors = FALSE;
+
+ // start the task stack running
+ // note that if we are running interactive, and no
+ // tasks were specified on the command line, nothing
+ // will happen.
+
+ PostMessage(hWnd, WM_TESTSTART, 0,0);
+ break;
+
+ case WM_SETFOCUS:
+ SetFocus(vApp.m_hwndEdit);
+ break;
+
+ case WM_SIZE:
+ MoveWindow( vApp.m_hwndEdit, 0, 0, LOWORD(lParam),
+ HIWORD(lParam), TRUE);
+ break;
+
+ case WM_DESTROY:
+ PostQuitMessage(0);
+ break;
+ case WM_TESTEND:
+ HandleTestEnd();
+ break;
+ case WM_TESTSCOMPLETED:
+ HandleTestsCompleted();
+ //if we are not in interactive mode, then
+ //quit the app.
+ if (!vApp.m_fInteractive)
+ {
+ PostQuitMessage(0);
+ }
+ else
+ {
+ //cleanup
+ vApp.Reset();
+ }
+ break;
+
+ case WM_COMMAND:
+ switch( wParam )
+ {
+ case IDM_EXIT:
+ SendMessage(hWnd, WM_CLOSE, 0, 0L);
+ break;
+ case IDM_COPY:
+ SendMessage(vApp.m_hwndEdit, WM_COPY, 0, 0L);
+ break;
+ case IDM_SAVE:
+ SaveToFile();
+ break;
+ }
+
+ //
+ // if the user picked a test, run it
+ // > 100 tests wouldn't fit on the menu anyway
+ //
+
+ if (wParam >= IDM_RUN_BASE && wParam < IDM_RUN_BASE + 100)
+ {
+ vApp.m_TaskStack.Push(&vrgTaskList[wParam - IDM_RUN_BASE]);
+ vApp.m_TaskStack.PopAndExecute(NULL);
+ }
+
+ break;
+
+ default:
+ //test to see if it's a message the driver
+ //may understand
+
+ if( (message > WM_USER) && (message <= MAX_WM_USER)
+ && (!vApp.m_TaskStack.IsEmpty()) )
+ {
+ vApp.m_TaskStack.PopAndExecute(NULL);
+ }
+ else
+ {
+ return DefWindowProc(hWnd, message, wParam,
+ lParam);
+ }
+ break;
+ }
+ return (0);
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: InitApplication
+//
+// Synopsis: initializes and registers the application class
+//
+// Effects:
+//
+// Arguments:
+//
+// Requires:
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 06-Feb-93 alexgo author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+BOOL InitApplication(HINSTANCE hInstance)
+{
+ WNDCLASS wc;
+
+ wc.style = 0;
+ wc.lpfnWndProc = (WNDPROC) MainWndProc;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = 0;
+ wc.hInstance = hInstance;
+ wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
+ wc.hCursor = LoadCursor(hInstance, IDC_ARROW);
+ wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
+ wc.lpszMenuName = "OleTestMenu";
+ wc.lpszClassName = "OleTestWClass";
+
+ return (RegisterClass(&wc));
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: InitInstance
+//
+// Synopsis: creates the app window
+//
+// Effects:
+//
+// Arguments: hInstance
+// nCmdShow
+//
+// Requires:
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 06-Feb-94 alexgo author
+// 09-Dec-94 MikeW add tests to the run menu
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+BOOL InitInstance(
+ HINSTANCE hInstance,
+ UINT nCmdShow)
+{
+ int nTask;
+ HMENU hMenu;
+
+ vApp.m_hinst = hInstance;
+
+ vApp.m_hwndMain = CreateWindow(
+ "OleTestWClass",
+ "OleTest Driver",
+ WS_OVERLAPPEDWINDOW,
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ NULL,
+ NULL,
+ hInstance,
+ NULL
+ );
+
+ if (!vApp.m_hwndMain)
+ return (FALSE);
+
+ hMenu = GetSubMenu(GetMenu(vApp.m_hwndMain), 2);
+ if (!hMenu)
+ return (FALSE);
+
+ //
+ // Add all of the tests to the "Run" menu
+ //
+
+ for (nTask = 0; vrgTaskList[nTask].szName != (LPSTR) 0; nTask++)
+ {
+ AppendMenu(hMenu,
+ MF_STRING,
+ IDM_RUN_BASE + nTask,
+ vrgTaskList[nTask].szName);
+ }
+
+ ShowWindow(vApp.m_hwndMain, nCmdShow);
+ UpdateWindow(vApp.m_hwndMain);
+ return (TRUE);
+}
+
+
+//+-------------------------------------------------------------------------
+//
+// Table: regConfig
+//
+// Synopsis: Table of registry settings required to run OleTest.
+//
+// History: dd-mmm-yy Author Comment
+// 08-Nov-94 KentCe Created.
+//
+// Notes: The registry template contains embedded "%s" to permit
+// the insertion of the full path of test binaries when the
+// registry is updated.
+//
+// The registry template is passed to wsprintf as an argument
+// so verify that changes are wsprintf safe (ie, use %% when
+// you want a single %, etc).
+//
+//--------------------------------------------------------------------------
+
+char * regConfig[] =
+{
+ ".ut1", "ProgID49",
+ ".ut2", "ProgID48",
+ ".ut3", "ProgID47",
+ ".ut4", "ProgID50",
+ "ProgID49", "test app 1",
+ "ProgID49\\CLSID", "{99999999-0000-0008-C000-000000000049}",
+ "ProgID48", "test app 2",
+ "ProgID48\\CLSID", "{99999999-0000-0008-C000-000000000048}",
+ "ProgID47", "test app 3",
+ "ProgID47\\CLSID", "{99999999-0000-0008-C000-000000000047}",
+ "ProgID50", "test app 4",
+ "ProgID50\\CLSID", "{99999999-0000-0008-C000-000000000050}",
+ "CLSID\\{00000009-0000-0008-C000-000000000047}", "BasicSrv",
+ "CLSID\\{00000009-0000-0008-C000-000000000047}\\LocalServer32", "%s\\testsrv.exe",
+ "CLSID\\{00000009-0000-0008-C000-000000000048}", "BasicBnd2",
+ "CLSID\\{00000009-0000-0008-C000-000000000048}\\LocalServer32", "%s\\olesrv.exe",
+ "CLSID\\{00000009-0000-0008-C000-000000000049}", "BasicBnd",
+ "CLSID\\{00000009-0000-0008-C000-000000000049}\\InprocServer32", "%s\\oleimpl.dll",
+ "CLSID\\{99999999-0000-0008-C000-000000000048}", "BasicBnd2",
+ "CLSID\\{99999999-0000-0008-C000-000000000048}\\LocalServer32", "%s\\olesrv.exe",
+ "CLSID\\{99999999-0000-0008-C000-000000000049}", "BasicBnd",
+ "CLSID\\{99999999-0000-0008-C000-000000000049}\\InprocServer32", "%s\\oleimpl.dll",
+ "CLSID\\{99999999-0000-0008-C000-000000000047}", "TestEmbed",
+ "CLSID\\{99999999-0000-0008-C000-000000000047}\\InprocHandler32", "ole32.dll",
+ "CLSID\\{99999999-0000-0008-C000-000000000047}\\InprocServer32", "ole32.dll",
+ "CLSID\\{99999999-0000-0008-C000-000000000047}\\LocalServer32", "%s\\testsrv.exe",
+ "CLSID\\{99999999-0000-0008-C000-000000000047}\\protocol\\StdFileEditing", "",
+ "CLSID\\{99999999-0000-0008-C000-000000000047}\\protocol\\StdFileEditing\\server", "testsrv.exe",
+ "CLSID\\{99999999-0000-0008-C000-000000000050}", "TestFail",
+ "CLSID\\{99999999-0000-0008-C000-000000000050}\\LocalServer32", "%s\\fail.exe",
+ "SIMPSVR", "Simple OLE 2.0 Server",
+ "SIMPSVR\\protocol\\StdFileEditing\\server", "simpsvr.exe",
+ "SIMPSVR\\protocol\\StdFileEditing\\verb\\0", "&Edit",
+ "SIMPSVR\\protocol\\StdFileEditing\\verb\\1", "&Open",
+ "SIMPSVR\\Insertable", "",
+ "SIMPSVR\\CLSID", "{BCF6D4A0-BE8C-1068-B6D4-00DD010C0509}",
+ "CLSID\\{BCF6D4A0-BE8C-1068-B6D4-00DD010C0509}", "Simple OLE 2.0 Server",
+ "CLSID\\{BCF6D4A0-BE8C-1068-B6D4-00DD010C0509}\\Insertable", "",
+ "CLSID\\{BCF6D4A0-BE8C-1068-B6D4-00DD010C0509}\\MiscStatus", "0",
+ "CLSID\\{BCF6D4A0-BE8C-1068-B6D4-00DD010C0509}\\DefaultIcon", "simpsvr.exe,0",
+ "CLSID\\{BCF6D4A0-BE8C-1068-B6D4-00DD010C0509}\\AuxUserType\\2", "Simple Server",
+ "CLSID\\{BCF6D4A0-BE8C-1068-B6D4-00DD010C0509}\\AuxUserType\\3", "Simple OLE 2.0 Server",
+ "CLSID\\{BCF6D4A0-BE8C-1068-B6D4-00DD010C0509}\\Verb\\0", "&Play,0,2",
+ "CLSID\\{BCF6D4A0-BE8C-1068-B6D4-00DD010C0509}\\Verb\\1", "&Open,0,2",
+ "CLSID\\{BCF6D4A0-BE8C-1068-B6D4-00DD010C0509}\\LocalServer32", "%s\\simpsvr.exe",
+ "CLSID\\{BCF6D4A0-BE8C-1068-B6D4-00DD010C0509}\\InprocHandler32", "ole32.dll",
+ "CLSID\\{BCF6D4A0-BE8C-1068-B6D4-00DD010C0509}\\ProgID", "SIMPSVR",
+ "CLSID\\{BCF6D4A0-BE8C-1068-B6D4-00DD010C0509}\\DataFormats\\GetSet\\0", "3,1,32,1",
+ ".svr", "SIMPSVR",
+ "SPSVR16", "Simple 16 Bit OLE 2.0 Server",
+ "SPSVR16\\protocol\\StdFileEditing\\server", "spsvr16.exe",
+ "SPSVR16\\protocol\\StdFileEditing\\verb\\0", "&Edit",
+ "SPSVR16\\protocol\\StdFileEditing\\verb\\1", "&Open",
+ "SPSVR16\\Insertable", "",
+ "SPSVR16\\CLSID", "{9fb878d0-6f88-101b-bc65-00000b65c7a6}",
+ "CLSID\\{9fb878d0-6f88-101b-bc65-00000b65c7a6}", "Simple 16 Bit OLE 2.0 Server",
+ "CLSID\\{9fb878d0-6f88-101b-bc65-00000b65c7a6}\\Insertable", "",
+ "CLSID\\{9fb878d0-6f88-101b-bc65-00000b65c7a6}\\MiscStatus", "0",
+ "CLSID\\{9fb878d0-6f88-101b-bc65-00000b65c7a6}\\DefaultIcon", "spsvr16.exe,0",
+ "CLSID\\{9fb878d0-6f88-101b-bc65-00000b65c7a6}\\AuxUserType\\2", "Simple Server",
+ "CLSID\\{9fb878d0-6f88-101b-bc65-00000b65c7a6}\\AuxUserType\\3", "Simple 16 Bit OLE 2.0 Server",
+ "CLSID\\{9fb878d0-6f88-101b-bc65-00000b65c7a6}\\Verb\\0", "&Play,0,2",
+ "CLSID\\{9fb878d0-6f88-101b-bc65-00000b65c7a6}\\Verb\\1", "&Open,0,2",
+ "CLSID\\{9fb878d0-6f88-101b-bc65-00000b65c7a6}\\LocalServer", "%s\\spsvr16.exe",
+ "CLSID\\{9fb878d0-6f88-101b-bc65-00000b65c7a6}\\InprocHandler", "ole2.dll",
+ "CLSID\\{9fb878d0-6f88-101b-bc65-00000b65c7a6}\\ProgID", "SPSVR16",
+ "CLSID\\{9fb878d0-6f88-101b-bc65-00000b65c7a6}\\DataFormats\\GetSet\\0", "3,1,32,1",
+ ".svr", "SPSVR16",
+ "OLEOutline", "Ole 2.0 In-Place Server Outline",
+ "OLEOutline\\CLSID", "{00000402-0000-0000-C000-000000000046}",
+ "OLEOutline\\CurVer", "OLE2ISvrOtl",
+ "OLEOutline\\CurVer\\Insertable", "",
+ "OLE2SvrOutl", "Ole 2.0 Server Sample Outline",
+ "OLE2SvrOutl\\CLSID", "{00000400-0000-0000-C000-000000000046}",
+ "OLE2SvrOutl\\Insertable", "",
+ "OLE2SvrOutl\\protocol\\StdFileEditing\\verb\\0", "&Edit",
+ "OLE2SvrOutl\\protocol\\StdFileEditing\\server", "svroutl.exe",
+ "OLE2SvrOutl\\Shell\\Print\\Command", "svroutl.exe %%1",
+ "OLE2SvrOutl\\Shell\\Open\\Command", "svroutl.exe %%1",
+ "CLSID\\{00000400-0000-0000-C000-000000000046}", "Ole 2.0 Server Sample Outline",
+ "CLSID\\{00000400-0000-0000-C000-000000000046}\\ProgID", "OLE2SvrOutl",
+ "CLSID\\{00000400-0000-0000-C000-000000000046}\\InprocHandler32", "ole32.dll",
+ "CLSID\\{00000400-0000-0000-C000-000000000046}\\LocalServer32", "%s\\svroutl.exe",
+ "CLSID\\{00000400-0000-0000-C000-000000000046}\\Verb\\0", "&Edit,0,2",
+ "CLSID\\{00000400-0000-0000-C000-000000000046}\\Insertable", "",
+ "CLSID\\{00000400-0000-0000-C000-000000000046}\\AuxUserType\\2", "Outline",
+ "CLSID\\{00000400-0000-0000-C000-000000000046}\\AuxUserType\\3", "Ole 2.0 Outline Server",
+ "CLSID\\{00000400-0000-0000-C000-000000000046}\\DefaultIcon", "svroutl.exe,0",
+ "CLSID\\{00000400-0000-0000-C000-000000000046}\\DataFormats\\DefaultFile", "Outline",
+ "CLSID\\{00000400-0000-0000-C000-000000000046}\\DataFormats\\GetSet\\0", "Outline,1,1,3",
+ "CLSID\\{00000400-0000-0000-C000-000000000046}\\DataFormats\\GetSet\\1", "1,1,1,3",
+ "CLSID\\{00000400-0000-0000-C000-000000000046}\\DataFormats\\GetSet\\2", "3,1,32,1",
+ "CLSID\\{00000402-0000-0000-C000-000000000046}\\DataFormats\\GetSet\\3", "3,4,32,1",
+ "CLSID\\{00000402-0000-0000-C000-000000000046}\\MiscStatus", "512",
+ "CLSID\\{00000400-0000-0000-C000-000000000046}\\Conversion\\Readable\\Main", "Outline",
+ "CLSID\\{00000400-0000-0000-C000-000000000046}\\Conversion\\Readwritable\\Main", "Outline",
+ "OLE2CntrOutl", "Ole 2.0 Container Sample Outline",
+ "OLE2CntrOutl\\Clsid", "{00000401-0000-0000-C000-000000000046}",
+ "OLE2CntrOutl\\Shell\\Print\\Command", "cntroutl.exe %%1",
+ "OLE2CntrOutl\\Shell\\Open\\Command", "cntroutl.exe %%1",
+ "CLSID\\{00000401-0000-0000-C000-000000000046}", "Ole 2.0 Container Sample Outline",
+ "CLSID\\{00000401-0000-0000-C000-000000000046}\\ProgID", "OLE2CntrOutl",
+ "CLSID\\{00000401-0000-0000-C000-000000000046}\\InprocHandler32", "ole32.dll",
+ "CLSID\\{00000401-0000-0000-C000-000000000046}\\LocalServer32", "%s\\cntroutl.exe",
+ "OLE2ISvrOtl", "Ole 2.0 In-Place Server Outline",
+ "OLE2ISvrOtl\\CLSID", "{00000402-0000-0000-C000-000000000046}",
+ "OLE2ISvrOtl\\Insertable", "",
+ "OLE2ISvrOtl\\protocol\\StdFileEditing\\verb\\1", "&Open",
+ "OLE2ISvrOtl\\protocol\\StdFileEditing\\verb\\0", "&Edit",
+ "OLE2ISvrOtl\\protocol\\StdFileEditing\\server", "isvrotl.exe",
+ "OLE2ISvrOtl\\Shell\\Print\\Command", "isvrotl.exe %%1",
+ "OLE2ISvrOtl\\Shell\\Open\\Command", "isvrotl.exe %%1",
+ "CLSID\\{00000402-0000-0000-C000-000000000046}", "Ole 2.0 In-Place Server Outline",
+ "CLSID\\{00000402-0000-0000-C000-000000000046}\\ProgID", "OLE2ISvrOtl",
+ "CLSID\\{00000402-0000-0000-C000-000000000046}\\ProgID", "OLE2ISvrOtl",
+ "CLSID\\{00000402-0000-0000-C000-000000000046}\\InprocHandler32", "ole32.dll",
+ "CLSID\\{00000402-0000-0000-C000-000000000046}\\LocalServer32", "%s\\isvrotl.exe",
+ "CLSID\\{00000402-0000-0000-C000-000000000046}\\Verb\\1", "&Open,0,2",
+ "CLSID\\{00000402-0000-0000-C000-000000000046}\\Verb\\0", "&Edit,0,2",
+ "CLSID\\{00000402-0000-0000-C000-000000000046}\\Insertable", "",
+ "CLSID\\{00000402-0000-0000-C000-000000000046}\\AuxUserType\\2", "Outline",
+ "CLSID\\{00000402-0000-0000-C000-000000000046}\\AuxUserType\\3", "Ole 2.0 In-Place Outline Server",
+ "CLSID\\{00000402-0000-0000-C000-000000000046}\\DefaultIcon", "isvrotl.exe,0",
+ "CLSID\\{00000402-0000-0000-C000-000000000046}\\DataFormats\\DefaultFile", "Outline",
+ "CLSID\\{00000402-0000-0000-C000-000000000046}\\DataFormats\\GetSet\\0", "Outline,1,1,3",
+ "CLSID\\{00000402-0000-0000-C000-000000000046}\\DataFormats\\GetSet\\1", "1,1,1,3",
+ "CLSID\\{00000402-0000-0000-C000-000000000046}\\DataFormats\\GetSet\\2", "3,1,32,1",
+ "CLSID\\{00000402-0000-0000-C000-000000000046}\\DataFormats\\GetSet\\3", "3,4,32,1",
+ "CLSID\\{00000402-0000-0000-C000-000000000046}\\MiscStatus", "512",
+ "CLSID\\{00000402-0000-0000-C000-000000000046}\\MiscStatus\\1", "896",
+ "CLSID\\{00000402-0000-0000-C000-000000000046}\\Conversion\\Readable\\Main", "Outline",
+ "CLSID\\{00000402-0000-0000-C000-000000000046}\\Conversion\\Readwritable\\Main", "Outline",
+ "OLE2ICtrOtl", "Ole 2.0 In-Place Container Outline",
+ "OLE2ICtrOtl\\Clsid", "{00000403-0000-0000-C000-000000000046}",
+ "OLE2ICtrOtl\\Shell\\Print\\Command", "icntrotl.exe %%1",
+ "OLE2ICtrOtl\\Shell\\Open\\Command", "icntrotl.exe %%1",
+ ".olc", "OLE2ICtrOtl",
+ "CLSID\\{00000403-0000-0000-C000-000000000046}", "Ole 2.0 In-Place Container Outline",
+ "CLSID\\{00000403-0000-0000-C000-000000000046}\\ProgID", "OLE2ICtrOtl",
+ "CLSID\\{00000403-0000-0000-C000-000000000046}\\InprocHandler32", "ole32.dll",
+ "CLSID\\{00000403-0000-0000-C000-000000000046}\\LocalServer32", "%s\\icntrotl.exe",
+ NULL
+};
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: InitializeRegistry
+//
+// Synopsis: Initialize the registry for oletest.
+//
+// Effects:
+//
+// Arguments: None.
+//
+// Requires:
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 08-Nov-94 KentCe Created.
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+void InitializeRegistry( void )
+{
+ char szBuf[MAX_PATH * 2];
+ char szPath[MAX_PATH];
+ int i;
+
+
+ //
+ // Assume all the oletest components are in the current directory.
+ //
+ if (!GetCurrentDirectory(sizeof(szPath), szPath))
+ {
+ assert(0);
+ }
+
+ //
+ // Loop thru string key/value pairs and update the registry.
+ //
+ for (i = 0; regConfig[i] != NULL; i += 2)
+ {
+ //
+ // The registry template contains embedded "%s" to permit
+ // the insertion of the full path of test binaries.
+ //
+ wsprintf(szBuf, regConfig[i+1], szPath);
+
+ if (RegSetValue(HKEY_CLASSES_ROOT, regConfig[i+0], REG_SZ,
+ szBuf, strlen(szBuf)) != ERROR_SUCCESS)
+ {
+ assert(0);
+ }
+ }
+}
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: TestSetup
+//
+// Synopsis: process the command line and setup the tests that need to
+// be run.
+//
+// Effects:
+//
+// Arguments: lpszCmdLine
+//
+// Requires:
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm: We scan the command line for the following information
+//
+// NULL or empty cmdline, assume running task 0
+// (usually run all tasks)
+// otherwise scan for n numbers, adding each to the end of
+// the stack (so the tasks are run in order).
+//
+// History: dd-mmm-yy Author Comment
+// 12-Dec-94 MikeW restructured parse algorithm, added -? & l
+// 07-Feb-94 alexgo author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+void TestSetup( LPSTR lpszCmdLine )
+{
+ LPSTR pszArg;
+ int nTest, cTests;
+
+ // initialize debugger options to nothing.
+
+ vApp.m_pszDebuggerOption = "";
+
+ //
+ // count up the number of tests available
+ //
+
+ for (cTests = 0; vrgTaskList[cTests].szName != (LPSTR) 0; cTests++)
+ {
+ ;
+ }
+
+ //
+ // make sure the registery is set up correctly.
+ //
+
+ InitializeRegistry();
+
+ //
+ // if the command line is empty, run all tests
+ // (assumed to be task 0)
+ //
+
+ pszArg = strtok(lpszCmdLine, " ");
+
+ if (NULL == pszArg)
+ {
+ vApp.m_TaskStack.Push(&vrgTaskList[0]);
+ vApp.m_fInteractive = FALSE;
+ }
+
+ //
+ // otherwise, look for options & test numbers
+ //
+
+ while (NULL != pszArg)
+ {
+ if ('-' == *pszArg)
+ {
+ while ('\0' != *(++pszArg)) // it's an option
+ {
+ switch (*pszArg)
+ {
+ case 'r': // 'r' flag is obsolete
+ break;
+
+ case 'R':
+ OutputString("Warning: 'R' flag to oletest is obsolete.\n");
+ vApp.m_fInteractive = FALSE;
+ vApp.m_TaskStack.Push(&vrgTaskList[0]);
+ break;
+
+ case 'i': // run in interactive mode
+ vApp.m_fInteractive = TRUE;
+ break;
+
+ case 'n': // start apps in debugger
+ vApp.m_fInteractive = TRUE;
+ vApp.m_pszDebuggerOption = "ntsd ";
+ break;
+
+ case 'l': // list tests & test nums
+ ListAllTests();
+ vApp.m_fInteractive = TRUE;
+ break;
+
+ case '?': // output the option list
+ PrintHelp();
+ vApp.m_fInteractive = TRUE;
+ break;
+ }
+ }
+ }
+ else // it's not a option, maybe it's a test number
+ {
+ if (isdigit(*pszArg))
+ {
+ nTest = atoi(pszArg);
+
+ if (nTest < 0 || nTest > cTests - 1)
+ {
+ OutputString("Ignoring invalid test #%d", nTest);
+ }
+ else
+ {
+ vApp.m_TaskStack.AddToEnd(&vrgTaskList[nTest]);
+ }
+ }
+ }
+
+ pszArg = strtok(NULL, " "); // fetch the next argument
+ }
+
+ vApp.m_fpLog = fopen("clip.log", "w+");
+ assert(vApp.m_fpLog);
+}
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: ListAllTests
+//
+// Synopsis: List all available tests and the corresponding test number
+//
+// Effects:
+//
+// Arguments: void
+//
+// Requires:
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm: Iterate through vrgTaskList
+//
+// History: dd-mmm-yy Author Comment
+// 12-Dec-94 MikeW author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+void ListAllTests()
+{
+ int nTask;
+
+ for (nTask = 0; vrgTaskList[nTask].szName != (LPSTR) 0; nTask++)
+ {
+ OutputString("%2d -- %s\r\n", nTask, vrgTaskList[nTask].szName);
+ }
+
+ OutputString("\r\n");
+}
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: PrintHelp
+//
+// Synopsis: Print the program options & tests
+//
+// Effects:
+//
+// Arguments: void
+//
+// Requires:
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 12-Dec-94 MikeW author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+void PrintHelp()
+{
+ OutputString("OleTest [options] [test numbers] -\r\n");
+ OutputString("\r\n");
+ OutputString(" -r - Autoregister test apps\r\n");
+ OutputString(" -R - Autoregister and Run All Tests\r\n");
+ OutputString(" -i - Run in interactive mode\r\n");
+ OutputString(" -n - Run test apps using ntsd and run interactive\r\n");
+ OutputString(" -l - List tests & test numbers and run interactive\r\n");
+ OutputString(" -? - Print this help\r\n");
+ OutputString("\r\n");
+
+ ListAllTests();
+}
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: WinMain
+//
+// Synopsis: main window procedure
+//
+// Effects:
+//
+// Arguments: hInstance
+// hPrevInstance
+// lpCmdLine
+// nCmdShow
+//
+// Requires:
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 06-Feb-94 alexgo author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+#ifdef WIN32
+int APIENTRY WinMain(
+ HINSTANCE hInstance,
+ HINSTANCE hPrevInstance,
+ LPSTR lpCmdLine,
+ int nCmdShow)
+#else
+int PASCAL WinMain(
+ HANDLE hInstance,
+ HANDLE hPrevInstance,
+ LPSTR lpCmdLine,
+ int nCmdShow)
+#endif
+
+{
+ MSG msg;
+
+ if (!hPrevInstance)
+ {
+ if (!InitApplication(hInstance))
+ {
+ return FALSE;
+ }
+ }
+
+ if (!InitInstance(hInstance, nCmdShow))
+ {
+ return FALSE;
+ }
+
+ TestSetup(lpCmdLine);
+
+ OleInitialize(NULL);
+
+ while (GetMessage(&msg, NULL, 0, 0))
+ {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+
+ OleUninitialize();
+
+ fclose(vApp.m_fpLog);
+ return (msg.wParam);
+}
diff --git a/private/oleutest/oletest/oletest.h b/private/oleutest/oletest/oletest.h
new file mode 100644
index 000000000..efdd0513d
--- /dev/null
+++ b/private/oleutest/oletest/oletest.h
@@ -0,0 +1,51 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: oletest.h
+//
+// Contents: include all other headers needed for oletest
+//
+// History: dd-mmm-yy Author Comment
+// 06-Feb-93 alexgo author
+//
+//--------------------------------------------------------------------------
+
+#ifndef _OLETEST_H
+#define _OLETEST_H
+
+//system includes
+#include <windows.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include <ole2.h>
+
+// define the OLECHAR stuff
+#ifndef WIN32
+
+#define OLECHAR char
+#define LPOLESTR LPSTR
+#define OLESTR(x) x
+
+#include <toolhelp.h>
+
+#endif // !WIN32
+
+//app includes
+#include "assert.h"
+#include "task.h"
+#include "stack.h"
+#include "app.h"
+#include "output.h"
+#include "utils.h"
+
+#include <testmess.h>
+
+#else
+ Error! Oletest.h included multiple times.
+#endif //!_OLETEST_H
diff --git a/private/oleutest/oletest/oletest.rc b/private/oleutest/oletest/oletest.rc
new file mode 100644
index 000000000..7976b33d0
--- /dev/null
+++ b/private/oleutest/oletest/oletest.rc
@@ -0,0 +1,45 @@
+
+//-----------------------------------------------------------------------------
+// This is a part of the Microsoft Source Code Samples.
+// Copyright (C) 1993 Microsoft Corporation.
+// All rights reserved.
+//
+// This source code is only intended as a supplement to
+// Microsoft Development Tools and/or WinHelp documentation.
+// See these sources for detailed information regarding the
+// Microsoft samples programs.
+//-----------------------------------------------------------------------------
+
+#include "windows.h"
+#include "appwin.h"
+
+
+OleTestMenu MENU
+BEGIN
+ POPUP "&File"
+ BEGIN
+ MENUITEM "&Save", IDM_SAVE
+ MENUITEM "&Exit", IDM_EXIT
+ END
+ POPUP "&Edit"
+ BEGIN
+ MENUITEM "&Copy", IDM_COPY
+ END
+ POPUP "&Run"
+ BEGIN
+ MENUITEM SEPARATOR
+ END
+END
+
+
+IDD_ASSERTIONFAILURE DIALOG DISCARDABLE 0, 0, 185, 92
+STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "OleTest -- Assertion Failure"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ PUSHBUTTON "&Abort Test",IDABORT,10,67,45,18
+ PUSHBUTTON "&Break",IDB_BREAK,67,67,45,18
+ PUSHBUTTON "&Ignore",IDIGNORE,124,67,45,18
+ EDITTEXT IDC_EDIT,11,9,161,46,ES_MULTILINE | ES_AUTOHSCROLL |
+ ES_READONLY
+END
diff --git a/private/oleutest/oletest/oletst16.def b/private/oleutest/oletest/oletst16.def
new file mode 100644
index 000000000..7b7dbae77
--- /dev/null
+++ b/private/oleutest/oletest/oletst16.def
@@ -0,0 +1,8 @@
+NAME OLETST16
+EXETYPE WINDOWS
+CODE PRELOAD MOVEABLE DISCARDABLE
+DATA PRELOAD MOVEABLE MULTIPLE
+HEAPSIZE 1024
+
+EXPORTS
+; ===List your explicitly exported functions here===
diff --git a/private/oleutest/oletest/oletst16.mak b/private/oleutest/oletest/oletst16.mak
new file mode 100644
index 000000000..43ec1d518
--- /dev/null
+++ b/private/oleutest/oletest/oletst16.mak
@@ -0,0 +1,236 @@
+# Microsoft Visual C++ generated build script - Do not modify
+
+PROJ = OLETST16
+DEBUG = 1
+PROGTYPE = 0
+CALLER =
+ARGS = -i 3
+DLLS =
+D_RCDEFINES = -d_DEBUG
+R_RCDEFINES = -dNDEBUG
+ORIGIN = MSVC
+ORIGIN_VER = 1.00
+PROJPATH = D:\NT\PRIVATE\OLEUTEST\OLETEST\
+USEMFC = 0
+CC = cl
+CPP = cl
+CXX = cl
+CCREATEPCHFLAG =
+CPPCREATEPCHFLAG =
+CUSEPCHFLAG =
+CPPUSEPCHFLAG =
+FIRSTC =
+FIRSTCPP = APP.CPP
+RC = rc
+CFLAGS_D_WEXE = /nologo /G2 /W3 /Zi /AL /Od /D "_DEBUG" /FR /GA /Fd"OLETST16.PDB"
+CFLAGS_R_WEXE = /nologo /W3 /AM /O1 /D "NDEBUG" /FR /GA
+LFLAGS_D_WEXE = /NOLOGO /ONERROR:NOEXE /NOD /PACKC:61440 /CO /ALIGN:16 /STACK:10240
+LFLAGS_R_WEXE = /NOLOGO /ONERROR:NOEXE /NOD /PACKC:61440 /ALIGN:16 /STACK:10240
+LIBS_D_WEXE = oldnames libw commdlg shell olecli olesvr llibcew
+LIBS_R_WEXE = oldnames libw commdlg shell olecli olesvr mlibcew
+RCFLAGS = /nologo
+RESFLAGS = /nologo
+RUNFLAGS =
+DEFFILE = OLETST16.DEF
+OBJS_EXT =
+LIBS_EXT = ..\..\..\..\MSVC\LIB\COMPOBJ.LIB ..\..\..\..\MSVC\LIB\OLE2.LIB ..\..\..\..\MSVC\LIB\STORAGE.LIB
+!if "$(DEBUG)" == "1"
+CFLAGS = $(CFLAGS_D_WEXE)
+LFLAGS = $(LFLAGS_D_WEXE)
+LIBS = $(LIBS_D_WEXE)
+MAPFILE = nul
+RCDEFINES = $(D_RCDEFINES)
+!else
+CFLAGS = $(CFLAGS_R_WEXE)
+LFLAGS = $(LFLAGS_R_WEXE)
+LIBS = $(LIBS_R_WEXE)
+MAPFILE = nul
+RCDEFINES = $(R_RCDEFINES)
+!endif
+!if [if exist MSVC.BND del MSVC.BND]
+!endif
+SBRS = APP.SBR \
+ CLIPTEST.SBR \
+ GENDATA.SBR \
+ GENENUM.SBR \
+ LETESTS.SBR \
+ OLETEST.SBR \
+ OUTPUT.SBR \
+ STACK.SBR \
+ TASK.SBR \
+ UTILS.SBR
+
+
+COMPOBJ_DEP =
+
+OLE2_DEP =
+
+STORAGE_DEP =
+
+APP_DEP = d:\nt\private\oleutest\oletest\oletest.h \
+ d:\nt\private\oleutest\oletest\task.h \
+ d:\nt\private\oleutest\oletest\stack.h \
+ d:\nt\private\oleutest\oletest\app.h \
+ d:\nt\private\oleutest\oletest\output.h \
+ d:\nt\private\oleutest\oletest\utils.h \
+ \nt\private\oleutest\inc\testmess.h
+
+
+CLIPTEST_DEP = d:\nt\private\oleutest\oletest\oletest.h \
+ d:\nt\private\oleutest\oletest\task.h \
+ d:\nt\private\oleutest\oletest\stack.h \
+ d:\nt\private\oleutest\oletest\app.h \
+ d:\nt\private\oleutest\oletest\output.h \
+ d:\nt\private\oleutest\oletest\utils.h \
+ \nt\private\oleutest\inc\testmess.h \
+ d:\nt\private\oleutest\oletest\gendata.h \
+ d:\nt\private\oleutest\oletest\genenum.h \
+ d:\nt\private\oleutest\oletest\letest.h
+
+
+GENDATA_DEP = d:\nt\private\oleutest\oletest\oletest.h \
+ d:\nt\private\oleutest\oletest\task.h \
+ d:\nt\private\oleutest\oletest\stack.h \
+ d:\nt\private\oleutest\oletest\app.h \
+ d:\nt\private\oleutest\oletest\output.h \
+ d:\nt\private\oleutest\oletest\utils.h \
+ \nt\private\oleutest\inc\testmess.h \
+ d:\nt\private\oleutest\oletest\gendata.h
+
+
+GENENUM_DEP = d:\nt\private\oleutest\oletest\oletest.h \
+ d:\nt\private\oleutest\oletest\task.h \
+ d:\nt\private\oleutest\oletest\stack.h \
+ d:\nt\private\oleutest\oletest\app.h \
+ d:\nt\private\oleutest\oletest\output.h \
+ d:\nt\private\oleutest\oletest\utils.h \
+ \nt\private\oleutest\inc\testmess.h \
+ d:\nt\private\oleutest\oletest\genenum.h
+
+
+LETESTS_DEP = d:\nt\private\oleutest\oletest\oletest.h \
+ d:\nt\private\oleutest\oletest\task.h \
+ d:\nt\private\oleutest\oletest\stack.h \
+ d:\nt\private\oleutest\oletest\app.h \
+ d:\nt\private\oleutest\oletest\output.h \
+ d:\nt\private\oleutest\oletest\utils.h \
+ \nt\private\oleutest\inc\testmess.h \
+ d:\nt\private\oleutest\oletest\letest.h
+
+
+OLETEST_DEP = d:\nt\private\oleutest\oletest\oletest.h \
+ d:\nt\private\oleutest\oletest\task.h \
+ d:\nt\private\oleutest\oletest\stack.h \
+ d:\nt\private\oleutest\oletest\app.h \
+ d:\nt\private\oleutest\oletest\output.h \
+ d:\nt\private\oleutest\oletest\utils.h \
+ \nt\private\oleutest\inc\testmess.h \
+ d:\nt\private\oleutest\oletest\appwin.h
+
+
+OUTPUT_DEP = d:\nt\private\oleutest\oletest\oletest.h \
+ d:\nt\private\oleutest\oletest\task.h \
+ d:\nt\private\oleutest\oletest\stack.h \
+ d:\nt\private\oleutest\oletest\app.h \
+ d:\nt\private\oleutest\oletest\output.h \
+ d:\nt\private\oleutest\oletest\utils.h \
+ \nt\private\oleutest\inc\testmess.h
+
+
+STACK_DEP = d:\nt\private\oleutest\oletest\oletest.h \
+ d:\nt\private\oleutest\oletest\task.h \
+ d:\nt\private\oleutest\oletest\stack.h \
+ d:\nt\private\oleutest\oletest\app.h \
+ d:\nt\private\oleutest\oletest\output.h \
+ d:\nt\private\oleutest\oletest\utils.h \
+ \nt\private\oleutest\inc\testmess.h
+
+
+TASK_DEP = d:\nt\private\oleutest\oletest\oletest.h \
+ d:\nt\private\oleutest\oletest\task.h \
+ d:\nt\private\oleutest\oletest\stack.h \
+ d:\nt\private\oleutest\oletest\app.h \
+ d:\nt\private\oleutest\oletest\output.h \
+ d:\nt\private\oleutest\oletest\utils.h \
+ \nt\private\oleutest\inc\testmess.h \
+ d:\nt\private\oleutest\oletest\letest.h
+
+
+UTILS_DEP = d:\nt\private\oleutest\oletest\oletest.h \
+ d:\nt\private\oleutest\oletest\task.h \
+ d:\nt\private\oleutest\oletest\stack.h \
+ d:\nt\private\oleutest\oletest\app.h \
+ d:\nt\private\oleutest\oletest\output.h \
+ d:\nt\private\oleutest\oletest\utils.h \
+ \nt\private\oleutest\inc\testmess.h
+
+
+all: $(PROJ).EXE $(PROJ).BSC
+
+APP.OBJ: APP.CPP $(APP_DEP)
+ $(CPP) $(CFLAGS) $(CPPCREATEPCHFLAG) /c APP.CPP
+
+CLIPTEST.OBJ: CLIPTEST.CPP $(CLIPTEST_DEP)
+ $(CPP) $(CFLAGS) $(CPPUSEPCHFLAG) /c CLIPTEST.CPP
+
+GENDATA.OBJ: GENDATA.CPP $(GENDATA_DEP)
+ $(CPP) $(CFLAGS) $(CPPUSEPCHFLAG) /c GENDATA.CPP
+
+GENENUM.OBJ: GENENUM.CPP $(GENENUM_DEP)
+ $(CPP) $(CFLAGS) $(CPPUSEPCHFLAG) /c GENENUM.CPP
+
+LETESTS.OBJ: LETESTS.CPP $(LETESTS_DEP)
+ $(CPP) $(CFLAGS) $(CPPUSEPCHFLAG) /c LETESTS.CPP
+
+OLETEST.OBJ: OLETEST.CPP $(OLETEST_DEP)
+ $(CPP) $(CFLAGS) $(CPPUSEPCHFLAG) /c OLETEST.CPP
+
+OUTPUT.OBJ: OUTPUT.CPP $(OUTPUT_DEP)
+ $(CPP) $(CFLAGS) $(CPPUSEPCHFLAG) /c OUTPUT.CPP
+
+STACK.OBJ: STACK.CPP $(STACK_DEP)
+ $(CPP) $(CFLAGS) $(CPPUSEPCHFLAG) /c STACK.CPP
+
+TASK.OBJ: TASK.CPP $(TASK_DEP)
+ $(CPP) $(CFLAGS) $(CPPUSEPCHFLAG) /c TASK.CPP
+
+UTILS.OBJ: UTILS.CPP $(UTILS_DEP)
+ $(CPP) $(CFLAGS) $(CPPUSEPCHFLAG) /c UTILS.CPP
+
+
+$(PROJ).EXE:: APP.OBJ CLIPTEST.OBJ GENDATA.OBJ GENENUM.OBJ LETESTS.OBJ OLETEST.OBJ \
+ OUTPUT.OBJ STACK.OBJ TASK.OBJ UTILS.OBJ $(OBJS_EXT) $(DEFFILE)
+ echo >NUL @<<$(PROJ).CRF
+APP.OBJ +
+CLIPTEST.OBJ +
+GENDATA.OBJ +
+GENENUM.OBJ +
+LETESTS.OBJ +
+OLETEST.OBJ +
+OUTPUT.OBJ +
+STACK.OBJ +
+TASK.OBJ +
+UTILS.OBJ +
+$(OBJS_EXT)
+$(PROJ).EXE
+$(MAPFILE)
+d:\msvc\lib\+
+d:\msvc\mfc\lib\+
+..\..\..\..\MSVC\LIB\COMPOBJ.LIB+
+..\..\..\..\MSVC\LIB\OLE2.LIB+
+..\..\..\..\MSVC\LIB\STORAGE.LIB+
+$(LIBS)
+$(DEFFILE);
+<<
+ link $(LFLAGS) @$(PROJ).CRF
+ $(RC) $(RESFLAGS) $@
+
+
+run: $(PROJ).EXE
+ $(PROJ) $(RUNFLAGS)
+
+
+$(PROJ).BSC: $(SBRS)
+ bscmake @<<
+/o$@ $(SBRS)
+<<
diff --git a/private/oleutest/oletest/output.cpp b/private/oleutest/oletest/output.cpp
new file mode 100644
index 000000000..da9ef75a9
--- /dev/null
+++ b/private/oleutest/oletest/output.cpp
@@ -0,0 +1,196 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: output.cpp
+//
+// Contents: String output functions for displaying text on the main
+// edit window
+//
+// Classes:
+//
+// Functions: OutputString
+// SaveToFile
+//
+// History: dd-mmm-yy Author Comment
+// 22-Mar-94 alexgo author
+//
+//--------------------------------------------------------------------------
+
+#include "oletest.h"
+#include <commdlg.h>
+
+#ifndef WIN32
+#include <stdarg.h>
+#endif
+
+//
+// handle to memory where the text is stored
+//
+// Please note this is really burfy (having all these globals). But for
+// the purposes of a simple driver app, it is the easiest.
+//
+static HGLOBAL hText; // handle to the Text
+static ULONG cbText;
+static ULONG iText;
+
+//+-------------------------------------------------------------------------
+//
+// Function: OutputString
+//
+// Synopsis: Dumps the string in printf format to the screen
+//
+// Effects:
+//
+// Arguments: [szFormat] -- the format string
+// [...] -- variable arguments
+//
+// Requires:
+//
+// Returns: int, the number of characters written (returned by sprintf)
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+int OutputString( char *szFormat, ... )
+{
+ LPSTR psz;
+ va_list ap;
+ int cbWritten;
+
+ va_start(ap, szFormat);
+
+ if( !hText )
+ {
+ hText = GlobalAlloc( GMEM_MOVEABLE , 2048 );
+ assert(hText);
+ cbText = 2048;
+ }
+
+ // double the size of the array if we need to
+
+ if( iText > cbText / 2 )
+ {
+ hText = GlobalReAlloc(hText, cbText * 2, GMEM_MOVEABLE );
+ assert(hText);
+ cbText *= 2;
+ }
+
+ psz = (LPSTR)GlobalLock(hText);
+
+ assert(psz);
+
+ cbWritten = wvsprintf( psz + iText, szFormat, ap);
+
+ iText += cbWritten;
+
+ va_end(ap);
+
+ SetWindowText(vApp.m_hwndEdit, psz);
+
+ GlobalUnlock(hText);
+
+
+ return cbWritten;
+
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: SaveToFile
+//
+// Synopsis: Gets a filename from the user and save the text buffer into it
+//
+// Effects:
+//
+// Arguments: void
+//
+// Requires:
+//
+// Returns: void
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 24-Mar-94 alexgo author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+void SaveToFile( void )
+{
+ char szFileName[MAX_PATH];
+ OPENFILENAME ofn;
+ static char * szFilter[] = { "Log Files (*.log)", "*.log",
+ "All Files (*.*)", "*.*", ""};
+ FILE * fp;
+ LPSTR psz;
+
+
+ memset(&ofn, 0, sizeof(OPENFILENAME));
+
+ ofn.lStructSize = sizeof(OPENFILENAME);
+ ofn.hwndOwner = vApp.m_hwndMain;
+ ofn.lpstrFilter = szFilter[0];
+ ofn.nFilterIndex = 0;
+
+ szFileName[0] = '\0';
+
+ ofn.lpstrFile = szFileName;
+ ofn.nMaxFile = MAX_PATH;
+
+ ofn.Flags = OFN_PATHMUSTEXIST | OFN_OVERWRITEPROMPT;
+
+ //
+ // Get the file
+ //
+
+ if (GetSaveFileName(&ofn) == FALSE)
+ {
+ // user hit cancel
+ return;
+ }
+
+ // the 'b' specifies binary mode, so \n --> \r\n translations are
+ // not done.
+ if( !(fp = fopen( szFileName, "wb")) )
+ {
+ MessageBox( NULL, "Can't open file!", "OleTest Driver",
+ MB_ICONEXCLAMATION );
+ return;
+ }
+
+ psz = (LPSTR)GlobalLock(hText);
+
+ assert(psz);
+
+ fwrite(psz, iText, sizeof(char), fp);
+
+ fclose(fp);
+
+ GlobalUnlock(hText);
+
+ return;
+}
+
+
+
+
+
+
+
diff --git a/private/oleutest/oletest/output.h b/private/oleutest/oletest/output.h
new file mode 100644
index 000000000..29ea30156
--- /dev/null
+++ b/private/oleutest/oletest/output.h
@@ -0,0 +1,27 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: output.h
+//
+// Contents: Declarations for String output functions.
+//
+// Classes:
+//
+// Functions: OutputInitialize()
+// OutputString()
+//
+// History: dd-mmm-yy Author Comment
+// 22-Mar-94 alexgo author
+//
+//--------------------------------------------------------------------------
+
+#ifndef _OUTPUT_H
+#define _OUTPUT_H
+
+int OutputString( char *szFormat, ... );
+void SaveToFile( void );
+
+#endif // !_OUTPUT_H
+
diff --git a/private/oleutest/oletest/stack.cpp b/private/oleutest/oletest/stack.cpp
new file mode 100644
index 000000000..4f8ccef31
--- /dev/null
+++ b/private/oleutest/oletest/stack.cpp
@@ -0,0 +1,413 @@
+//+-------------------------------------------------------------------------
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: stack.cpp
+//
+// Contents: Implementation of the TaskStack
+//
+// Classes:
+//
+// Functions:
+//
+// History: dd-mmm-yy Author Comment
+// 06-Feb-94 alexgo author
+//
+//--------------------------------------------------------------------------
+
+#include "oletest.h"
+
+//+-------------------------------------------------------------------------
+//
+// Member: TaskStack::TaskStack
+//
+// Synopsis: Constructor
+//
+// Arguments:
+//
+// Returns: void
+//
+// History: dd-mmm-yy Author Comment
+// 06-Feb-94 alexgo author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+TaskStack::TaskStack( void )
+{
+ m_pNodes = NULL;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Member: TaskStack::AddToEnd
+//
+// Synopsis: adds a function and it's argument to the bottom of the stack
+//
+// Effects:
+//
+// Arguments: ti -- the task item to add to the end of the stack
+//
+// Requires:
+//
+// Returns: void
+//
+// Signals:
+//
+// Modifies:
+//
+// Derivation:
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 06-Feb-94 alexgo author
+//
+// Notes: The task item is copied into the stack.
+//
+//--------------------------------------------------------------------------
+
+void TaskStack::AddToEnd( const TaskItem *pti )
+{
+ TaskNode **ppNode;
+ TaskNode *pNode = new TaskNode;
+
+ assert(pNode);
+
+ pNode->ti = *pti;
+ pNode->pNext = NULL;
+
+ for( ppNode = &m_pNodes; *ppNode != NULL;
+ ppNode = &(*ppNode)->pNext)
+ {
+ ;
+ }
+
+ *ppNode = pNode;
+
+ return;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Member: TaskStack::AddToEnd
+//
+// Synopsis: adds a function and it's argument to the bottom of the stack
+//
+// Effects:
+//
+// Arguments: fnCall -- the function to call
+// pvArg -- the closure argument for the function
+//
+// Requires:
+//
+// Returns: void
+//
+// Signals:
+//
+// Modifies:
+//
+// Derivation:
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 06-Feb-94 alexgo author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+void TaskStack::AddToEnd( void (*fnCall)(void *), void *pvArg)
+{
+ TaskItem ti = vzTaskItem; //clear it to zero
+
+ ti.fnCall = fnCall;
+ ti.pvArg = pvArg;
+
+ AddToEnd(&ti);
+}
+
+//+-------------------------------------------------------------------------
+//
+// Member: TaskStack::Empty
+//
+// Synopsis: Empties the stack, ignoring the function call
+//
+// Effects:
+//
+// Arguments: void
+//
+// Requires:
+//
+// Returns: NULL
+//
+// Signals:
+//
+// Modifies:
+//
+// Derivation:
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 06-Feb-94 alexgo author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+void TaskStack::Empty( void )
+{
+ while( m_pNodes )
+ {
+ Pop(NULL);
+ }
+}
+
+//+-------------------------------------------------------------------------
+//
+// Member: TaskStack::IsEmpty
+//
+// Synopsis: returns TRUE if the stack is empty, false otherwise
+//
+// Effects:
+//
+// Arguments: void
+//
+// Requires:
+//
+// Returns: TRUE/FALSE
+//
+// Signals:
+//
+// Modifies:
+//
+// Derivation:
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 06-Feb-94 alexgo author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+BOOL TaskStack::IsEmpty(void)
+{
+ if( m_pNodes )
+ {
+ return FALSE;
+ }
+ else
+ {
+ return TRUE;
+ }
+}
+
+//+-------------------------------------------------------------------------
+//
+// Member: TaskStack::Pop
+//
+// Synopsis: Pops the stack, ignoring the function call
+//
+// Effects:
+//
+// Arguments: void
+//
+// Requires:
+//
+// Returns: the task item that was popped.
+//
+// Signals:
+//
+// Modifies:
+//
+// Derivation:
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 06-Feb-94 alexgo author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+void TaskStack::Pop( TaskItem *pti )
+{
+ TaskNode *pTemp;
+
+ if( m_pNodes )
+ {
+ if( pti )
+ {
+ *pti = m_pNodes->ti;
+ }
+ pTemp = m_pNodes;
+ m_pNodes = m_pNodes->pNext;
+
+ //now free the memory
+ delete pTemp;
+ }
+
+ return;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Member: TaskStack::PopAndExecute
+//
+// Synopsis: pops the stack and executes the function call
+//
+// Effects:
+//
+// Arguments: void
+//
+// Requires:
+//
+// Returns: the task item that was popped.
+//
+// Signals:
+//
+// Modifies:
+//
+// Derivation:
+//
+// Algorithm: Pop the stack and then execute the function call
+// in the just removed stack node.
+//
+// History: dd-mmm-yy Author Comment
+// 06-Feb-94 alexgo author
+// 09-Dec-94 MikeW Added exception handling
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+void TaskStack::PopAndExecute( TaskItem *pti )
+{
+ TaskItem ti;
+
+ if( pti == NULL )
+ {
+ pti = &ti;
+ }
+
+ Pop(pti);
+
+ //if there's a function to execute, do it.
+ //if the stack is empty, Pop will return a zero-filled TaskItem
+
+ if( pti->fnCall )
+ {
+ if( pti->szName )
+ {
+ OutputString("Starting: %s\r\n", pti->szName);
+ }
+ //call the function
+
+ __try
+ {
+ (*pti->fnCall)(pti->pvArg);
+ }
+ __except ((GetExceptionCode() == E_ABORT)
+ ? EXCEPTION_EXECUTE_HANDLER
+ : EXCEPTION_CONTINUE_SEARCH)
+ {
+ //
+ // there was an assertion and the user hit abort
+ //
+
+ PostMessage(vApp.m_hwndMain, WM_TESTEND, TEST_FAILURE, 0);
+ }
+ }
+
+ return;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Member: TaskStack::Push
+//
+// Synopsis: pushes a function onto the stack
+//
+// Effects:
+//
+// Arguments: ti -- the task item to push onto the stack
+//
+// Requires:
+//
+// Returns: void
+//
+// Signals:
+//
+// Modifies:
+//
+// Derivation:
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 06-Feb-94 alexgo author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+void TaskStack::Push( const TaskItem *pti )
+{
+ TaskNode *pNode = new TaskNode;
+
+ assert(pNode);
+
+ pNode->ti = *pti;
+ pNode->pNext = m_pNodes;
+ m_pNodes = pNode;
+
+ return;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Member: TaskStack::Push
+//
+// Synopsis: pushes a function onto the stack
+//
+// Effects:
+//
+// Arguments: fnCall -- the function to call
+// pvArg -- the closure argument for the function
+//
+// Requires:
+//
+// Returns: void
+//
+// Signals:
+//
+// Modifies:
+//
+// Derivation:
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 06-Feb-94 alexgo author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+void TaskStack::Push( void (*fnCall)(void *), void * pvArg)
+{
+ TaskItem ti = vzTaskItem;
+
+ ti.fnCall = fnCall;
+ ti.pvArg = pvArg;
+
+ Push(&ti);
+
+ return;
+}
diff --git a/private/oleutest/oletest/stack.h b/private/oleutest/oletest/stack.h
new file mode 100644
index 000000000..9b7a81753
--- /dev/null
+++ b/private/oleutest/oletest/stack.h
@@ -0,0 +1,61 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: stack.h
+//
+// Contents: The class declaration of the task stack.
+//
+// Classes: TaskStack
+//
+// History: dd-mmm-yy Author Comment
+// 06-Feb-93 alexgo author
+//
+//--------------------------------------------------------------------------
+
+#ifndef _STACK_H
+#define _STACK_H
+
+typedef struct TaskNode
+{
+ TaskItem ti;
+ struct TaskNode *pNext;
+} TaskNode;
+
+//+-------------------------------------------------------------------------
+//
+// Class: TaskStack
+//
+// Purpose: Stores the task list of tests to be run.
+//
+// History: dd-mmm-yy Author Comment
+// 06-Feb-93 alexgo author
+//
+// Notes: TaskItems are passed in and returned from methods
+// as structure copies. This is done to simply memory
+// management (since the overriding design goal of the
+// driver app is simplicity over efficiency).
+//
+//--------------------------------------------------------------------------
+
+class TaskStack
+{
+public:
+ TaskStack( void ); //constructor
+
+ void AddToEnd( void (*)(void *), void *);
+ void AddToEnd( const TaskItem *);
+ void Empty(void);
+ BOOL IsEmpty(void);
+ void Pop( TaskItem * );
+ void PopAndExecute( TaskItem * );
+ void Push( void (*)(void *), void *);
+ void Push( const TaskItem *);
+
+
+private:
+ TaskNode *m_pNodes;
+};
+
+#endif //!_STACK_H
diff --git a/private/oleutest/oletest/task.cpp b/private/oleutest/oletest/task.cpp
new file mode 100644
index 000000000..1613111d2
--- /dev/null
+++ b/private/oleutest/oletest/task.cpp
@@ -0,0 +1,479 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: task.cpp
+//
+// Contents: The global task list and helper function implementations
+//
+// Classes:
+//
+// Functions: HandleTestEnd
+// RunAllTests
+// RunApp
+// RunTestOnThread
+//
+// History: dd-mmm-yy Author Comment
+// 06-Jan-95 t-scotth added apartment thread test and RunTestOnThread
+// 06-Feb-94 alexgo author
+//
+// Notes:
+// Folks adding new tests will need to insert their test
+// into the global array.
+//
+//--------------------------------------------------------------------------
+
+#include "oletest.h"
+#include "cotest.h"
+#include "letest.h"
+#include "attest.h"
+
+// global, zero'ed task item
+TaskItem vzTaskItem;
+
+// the global task list array.
+// Multi-test entries go first, followed by individual tests.
+
+#ifdef WIN32
+
+const TaskItem vrgTaskList[] =
+{
+ // the constant should be the index at which individual tests
+ // begin. RunAllTests will run every test in this list after
+ // that index.
+ { "Run All Tests", RunAllTests, (void *)2},
+ // the constant below should be the index at which individual
+ // upper layer unit tests exist. All tests at that index and
+ // beyond will be run
+ { "Run All Upper Layer Tests", RunAllTests, (void *)5 },
+ { "OleBind", RunApp, (void *)"olebind.exe"},
+ { "Threads", RunApi, (void *) ThreadUnitTest },
+ { "Storage DRT", RunApp, (void *)"stgdrt.exe"},
+ { "LE: Insert Object Test 1", LETest1, &letiInsertObjectTest1 },
+ { "LE: Clipboard Test 1", RunApi, (void *)LEClipTest1},
+ { "LE: Clipboard Test 2 (clipboard data object)", RunApi,
+ (void *)LEClipTest2 },
+ { "LE: Inplace Test 1", LETest1, &letiInplaceTest1 },
+ { "LE: Data Advise Holder Test", RunApi,
+ (void *) LEDataAdviseHolderTest},
+ { "LE: OLE Advise Holder Test", RunApi, (void *) LEOleAdviseHolderTest},
+ { "LE: OLE1 Clipboard Test 1", RunApi, (void *)LEOle1ClipTest1},
+ { "LE: Insert Object Test 2", LETest1, &letiInsertObjectTest2 },
+ { "LE: OLE1 Clipboard Test 2", LEOle1ClipTest2, NULL },
+ { "LE: OleQueryCreateFromData Test 1", RunApi,
+ (void *)TestOleQueryCreateFromDataMFCHack },
+ { "LE: Apartment Thread Test", RunTestOnThread, (void *)ATTest },
+ { 0, 0, 0 }
+};
+
+#else
+
+// Win16 tests
+
+const TaskItem vrgTaskList[] =
+{
+ // the constant should be the index at which individual tests
+ // begin. RunAllTests will run every test in this list after
+ // that index.
+ { "Run All Tests", RunAllTests, (void *)1},
+ { "LE: Clipboard Test 1", RunApi, (void *)LEClipTest1},
+ { "LE: Clipboard Test 2 (clipboard data object)", RunApi,
+ (void *)LEClipTest2 },
+ { "LE: OLE1 Clipboard Test 1", RunApi, (void *)LEOle1ClipTest1},
+ { 0, 0, 0 }
+};
+
+#endif
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: HandleTestEnd
+//
+// Synopsis: Handles processing for the WM_TESTEND message.
+//
+// Effects:
+//
+// Arguments: void
+//
+// Requires:
+//
+// Returns: void
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm: execute the next task in the task stack or sends
+// a TESTSCOMPLETED message back the message queue
+//
+// History: dd-mmm-yy Author Comment
+// 06-Feb-94 alexgo author
+// 13-Dec-94 MikeW Allow testing to continue after failures
+//
+// Notes: vApp must be initialized correctly for this function to
+// work properly.
+//
+// BUGBUG::Need to add output routines in here.
+//
+//--------------------------------------------------------------------------
+void HandleTestEnd( void )
+{
+ assert(vApp.m_message == WM_TESTEND);
+
+ switch( vApp.m_wparam )
+ {
+ case TEST_UNKNOWN:
+ //we usually get this message from a test run
+ //by RunApp (i.e. one that does not communicate
+ //with us via windows messages). We'll check
+ //the exit code and decide what to do.
+
+ if( vApp.m_lparam != 0 )
+ {
+ //presumably an error
+ OutputString("Test End, Status Unknown "
+ "( %lx )\r\n\r\n", vApp.m_lparam);
+
+ vApp.m_fGotErrors = TRUE;
+ break;
+ }
+ // otherwise we fall through to the success case.
+ case TEST_SUCCESS:
+ OutputString("Test Success ( %lx )!\r\n\r\n",
+ vApp.m_lparam);
+ break;
+
+ case TEST_FAILURE:
+ OutputString("Test FAILED! ( %lx )\r\n\r\n", vApp.m_lparam);
+ vApp.m_fGotErrors = TRUE;
+ break;
+
+ default:
+ assert(0); //we should never get here
+ break;
+ }
+
+ vApp.Reset();
+
+ //
+ // Now check to see if there are any more tests
+ //
+
+ while (!vApp.m_TaskStack.IsEmpty())
+ {
+ TaskItem ti;
+
+ vApp.m_TaskStack.Pop(&ti);
+
+ if (ti.szName != (LPSTR) 0)
+ {
+ vApp.m_TaskStack.Push(&ti);
+ break;
+ }
+ }
+
+
+ if (vApp.m_TaskStack.IsEmpty())
+ {
+ PostMessage(vApp.m_hwndMain,
+ WM_TESTSCOMPLETED,
+ vApp.m_wparam, vApp.m_lparam);
+ }
+ else
+ {
+ //if the stack is not empty, run
+ //the next task
+ PostMessage(vApp.m_hwndMain,
+ WM_TESTSTART,
+ 0, 0);
+ }
+
+ return;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: HandleTestsCompleted
+//
+// Synopsis: Handles processing for the WM_TESTSCOMPLETED message.
+//
+// Effects:
+//
+// Arguments: void
+//
+// Requires:
+//
+// Returns: void
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 06-Feb-94 alexgo author
+//
+// Notes: vApp must be initialized correctly for this function to
+// work properly.
+//
+// BUGBUG::Need to add more output routines in here.
+//
+//--------------------------------------------------------------------------
+void HandleTestsCompleted( void )
+{
+ char szBuf[128];
+
+ assert(vApp.m_message == WM_TESTSCOMPLETED);
+
+ //temporary output
+
+ switch(vApp.m_fGotErrors)
+ {
+ case FALSE:
+ OutputString("Tests PASSED!!\n");
+ break;
+ case TRUE:
+ sprintf(szBuf, "Tests FAILED, code %lx",
+ vApp.m_lparam);
+ MessageBox(vApp.m_hwndMain, szBuf, "Ole Test Driver",
+ MB_ICONEXCLAMATION | MB_OK);
+ break;
+ default:
+ assert(0);
+ }
+
+ //
+ // Reset the got error status
+ //
+
+ vApp.m_fGotErrors = FALSE;
+
+ return;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: RunAllTests
+//
+// Synopsis: Runs all the individual tests in the global list
+//
+// Effects:
+//
+// Arguments: pvArg -- the index at which individual tests
+// start in the global list.
+//
+// Requires:
+//
+// Returns: void
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 06-Feb-94 alexgo author
+//
+// Notes:
+// Tests will be run in the order they appear in the global
+// list.
+//
+//--------------------------------------------------------------------------
+
+void RunAllTests( void *pvArg )
+{
+ ULONG index = (ULONG)pvArg;
+ ULONG i;
+
+ //find the number of tasks in the list (so we can push
+ //them in reverse order).
+
+ for (i = 0; vrgTaskList[i].szName != 0; i++ )
+ {
+ ;
+ }
+
+ assert( i > 1 );
+
+ //now push the tasks onto the stack in reverse order.
+
+ for (i--; i >= index; i-- )
+ {
+ vApp.m_TaskStack.Push(vrgTaskList + i);
+ }
+
+ //start the first one.
+
+ vApp.m_TaskStack.PopAndExecute(NULL);
+
+ return;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: RunApi
+//
+// Synopsis: Runs the specified Api
+//
+// Effects:
+//
+// Arguments: [pvArg] -- the api to run
+//
+// Requires:
+//
+// Returns: void
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 23-Mar-94 alexgo author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+void RunApi( void *pvArg )
+{
+ HRESULT hresult;
+
+
+ hresult = (*((HRESULT (*)(void))pvArg))();
+
+ vApp.Reset();
+ vApp.m_wparam = (hresult == NOERROR) ? TEST_SUCCESS : TEST_FAILURE;
+ vApp.m_lparam = (LPARAM)hresult;
+ vApp.m_message = WM_TESTEND;
+
+ HandleTestEnd();
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: RunApp
+//
+// Synopsis: Runs the app specified in the argument
+//
+// Effects:
+//
+// Arguments: pvArg -- a string with the app to execute
+//
+// Requires:
+//
+// Returns: void
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm: Create the process and wait for it to finish. The exit
+// status is then returned.
+//
+// History: dd-mmm-yy Author Comment
+// 06-Feb-94 alexgo author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+void RunApp( void *pvArg )
+{
+ WPARAM wparam = 0;
+ DWORD error = 0;
+
+#ifdef WIN32
+
+ PROCESS_INFORMATION procinfo;
+ static STARTUPINFO startinfo; //to make it all zero
+
+ assert(pvArg); //should be a valid ANSI string.
+
+ startinfo.cb = sizeof(startinfo);
+
+ if( CreateProcess(NULL, (LPTSTR)pvArg, NULL, NULL, NULL, NULL, NULL,
+ NULL, &startinfo, &procinfo) )
+ {
+ //the process started, now wait for it to finish.
+ WaitForSingleObject(procinfo.hProcess, INFINITE);
+
+ //now get the return code of the process.
+
+ GetExitCodeProcess(procinfo.hProcess, &error);
+ wparam = TEST_UNKNOWN;
+ }
+ else
+ {
+ wparam = TEST_FAILURE;
+ error = GetLastError();
+ }
+
+#endif // WIN32
+
+ // since there will be no WM_TESTEND message, we must do the
+ // test end processing ourselves.
+ vApp.Reset();
+ vApp.m_wparam = wparam;
+ vApp.m_lparam = error;
+ vApp.m_message = WM_TESTEND;
+
+ HandleTestEnd();
+
+
+ return;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: RunTestOnThread
+//
+// Synopsis: creates a thread to run a test function
+//
+// Effects: creates a new thread
+//
+// Arguments: [pvArg] -- a function pointer to the test function
+//
+// Requires:
+//
+// Returns: void
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 04-Jan-95 t-ScottH author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+void RunTestOnThread(void *pvArg)
+{
+ HANDLE hMainTestThread;
+ DWORD dwThreadId = 0;
+
+ hMainTestThread = CreateThread(
+ NULL, // security attributes
+ 0, // stack size (default)
+ (LPTHREAD_START_ROUTINE)pvArg, // address of thread function
+ NULL, // arguments of thread function
+ 0, // creation flags
+ &dwThreadId ); // address of new thread ID
+
+ assert(hMainTestThread);
+
+ CloseHandle(hMainTestThread);
+
+ return;
+}
+
+
diff --git a/private/oleutest/oletest/task.h b/private/oleutest/oletest/task.h
new file mode 100644
index 000000000..ac174f06f
--- /dev/null
+++ b/private/oleutest/oletest/task.h
@@ -0,0 +1,65 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: task.h
+//
+// Contents: declarations for task-related functions and data structures
+//
+// Classes:
+//
+// Functions:
+//
+// History: dd-mmm-yy Author Comment
+// 12-Jan-95 t-ScottH added RunTestOnThread
+// 06-Feb-94 alexgo author
+//
+//--------------------------------------------------------------------------
+
+#ifndef _TASK_H
+#define _TASK_H
+
+typedef struct TaskItem
+{
+ LPSTR szName;
+ void (*fnCall)(void *);
+ void *pvArg;
+} TaskItem;
+
+// global list of all available tests
+extern const TaskItem vrgTaskList[];
+// global zero'ed task list
+extern TaskItem vzTaskItem;
+
+// generic callback function for test apps that register a window handle
+void GenericRegCallback(void *);
+
+// run the given api (which must be HRESULT api ( void ))
+void RunApi(void *);
+
+// runs the given app
+void RunApp(void *);
+
+// runs the app and inserts a callback function so the app can register
+// its window handle for communication
+void RunAppWithCallback(void *);
+
+// runs the given test by sending a message to the currently running test
+// app.
+void RunTest(void *);
+
+// runs all the tests currently built into the driver program
+void RunAllTests(void *);
+
+// run the given test function as a new thread
+void RunTestOnThread(void *pvArg);
+
+// handles the test completion message
+void HandleTestEnd(void);
+
+// handles the tests completed message
+void HandleTestsCompleted(void);
+
+#endif //!_TASK_H
+
diff --git a/private/oleutest/oletest/uthread.cpp b/private/oleutest/oletest/uthread.cpp
new file mode 100644
index 000000000..6cc78d2b2
--- /dev/null
+++ b/private/oleutest/oletest/uthread.cpp
@@ -0,0 +1,1131 @@
+//+-------------------------------------------------------------------
+//
+// File: uthread.cpp
+//
+// Contents: Unit test for various OLE threading model features
+//
+// Classes: SSTParamBlock
+// SSTParamBlock
+// SBTParamBlock
+//
+// Functions: CreateTestThread
+// VerifyTestObject
+// CheckForDllExistence
+// GetDllDirectory
+// SetRegForDll
+// SetSingleThreadRegEntry
+// SetAptThreadRegEntry
+// SetBothThreadRegEntry
+// SingleThreadTestThread
+// AptTestThread
+// BothTestThread
+// SetUpRegistry
+// TestSingleThread
+// TestAptThread
+// TestBothDll
+// TestFreeAllLibraries
+// ThreadUnitTest
+//
+// History: 31-Oct-94 Ricksa
+//
+//--------------------------------------------------------------------
+#include <windows.h>
+#include <ole2.h>
+#include <uthread.h>
+#include <cotest.h>
+
+// Test single threaded DLL - all operations s/b executed on the main thread.
+// Pointers between threads s/b different. Test loading class object from
+// different than the main thread.
+
+// Test apartment model - all operations should occur on the thread the
+// object was created on. This should also test the helper APIs. Pointers
+// between threads s/b different. This tests helper APIs.
+
+// Both model DLL. We want to make sure that the marshaling works between
+// threads so that you get the same pointer. This tests new marshal context.
+
+// Test Free Unused Libraries from non-main thread. Test FreeUnused libraries
+// from main thread.
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Class: SSTParamBlock
+//
+// Purpose: Parameter block for single threaded dll test.
+//
+// Interface:
+//
+// History: 01-Nov-92 Ricksa Created
+//
+//--------------------------------------------------------------------------
+struct SSTParamBlock
+{
+ HANDLE hEvent;
+ BOOL fResult;
+ IClassFactory * pcf;
+};
+
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Class: SSTParamBlock
+//
+// Purpose: Parameter block for apt model threaded dll test.
+//
+// Interface:
+//
+// History: 01-Nov-92 Ricksa Created
+//
+//--------------------------------------------------------------------------
+struct SATParamBlock
+{
+ HANDLE hEvent;
+ BOOL fResult;
+ IClassFactory * pcf;
+ IStream * pstrm;
+};
+
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Class: SBTParamBlock
+//
+// Purpose: Parameter block for both model dll test.
+//
+// Interface:
+//
+// History: 02-Nov-92 Ricksa Created
+//
+//--------------------------------------------------------------------------
+struct SBTParamBlock
+{
+ HANDLE hEvent;
+ BOOL fResult;
+ IClassFactory * pcf;
+ IStream * pstrm;
+};
+
+
+
+
+const TCHAR *pszRegValThreadModel = TEXT("ThreadingModel");
+const TCHAR *pszApartmentModel = TEXT("Apartment");
+const TCHAR *pszBoth = TEXT("Both");
+
+//+-------------------------------------------------------------------
+//
+// Function: ThreadWaitForEvent, private
+//
+// Synopsis: Process messages until event becomes signaled
+//
+// Arguments: [lphObject] - handle to become signaled
+//
+// History: 02-Nov-94 Ricksa Created
+//
+//--------------------------------------------------------------------
+void ThreadWaitForEvent(HANDLE hObject)
+{
+ // message loop lasts until we get a WM_QUIT message
+ // upon which we shall return from the function
+ while (TRUE)
+ {
+ // wait for any message sent or posted to this queue
+ // or for one of the passed handles to become signaled
+ DWORD result = MsgWaitForMultipleObjects(1, &hObject,
+ FALSE, INFINITE, QS_ALLINPUT);
+
+ // result tells us the type of event we have:
+ // a message or a signaled handle
+
+ // if there are one or more messages in the queue ...
+ if (result == (WAIT_OBJECT_0 + 1))
+ {
+ // block-local variable
+ MSG msg;
+
+ // read all of the messages in this next loop
+ // removing each message as we read it
+ while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
+ {
+
+ // if it's a quit message we're out of here
+ if (msg.message == WM_QUIT)
+ {
+ return;
+ }
+
+ // otherwise dispatch it
+ DispatchMessage(&msg);
+
+ }
+
+ continue;
+ }
+
+ // Event got signaled so we are done.
+ break;
+ }
+
+}
+
+
+
+//+-------------------------------------------------------------------
+//
+// Function: CreateTestThread, private
+//
+// Synopsis: Create a test thread in standard way
+//
+// Arguments: [lpStartAddr] - start routine address
+// [pvThreadArg] - argument to pass to the thread
+//
+// Returns: TRUE - Thread created successfully
+// FALSE - Thread could not be created.
+//
+// History: 02-Nov-94 Ricksa Created
+//
+//--------------------------------------------------------------------
+BOOL CreateTestThread(
+ LPTHREAD_START_ROUTINE lpStartAddr,
+ void *pvThreadArg)
+{
+ // Where to put the thread ID that we don't care about
+ DWORD dwThreadId;
+
+ // Create thread to load single threaded object
+ HANDLE hThread = CreateThread(
+ NULL, // Default security descriptor
+ 0, // Default stack
+ lpStartAddr, // Start routine
+ pvThreadArg, // Parameters to pass to the thread
+ 0, // Thread runs immediately after creation
+ &dwThreadId); // Where to return thread id (unused).
+
+ CloseHandle(hThread);
+
+ return hThread != NULL;
+}
+
+
+
+//+-------------------------------------------------------------------
+//
+// Function: VerifyTestObject, private
+//
+// Synopsis: Create a test DLL object in standard way
+//
+// Arguments: [pcf] - start routine address
+// [rclsid] - clsid to check
+//
+// Returns: TRUE - Object behaved as expected
+// FALSE - Object did not behave
+//
+// History: 02-Nov-94 Ricksa Created
+//
+//--------------------------------------------------------------------
+BOOL VerifyTestObject(
+ IClassFactory *pcf,
+ REFCLSID rclsid)
+{
+ // Result from test
+ BOOL fResult = FALSE;
+
+ // Pointer to unknown for the object
+ IUnknown *punk = NULL;
+
+ // Pointer to IPersist interface
+ IPersist *pIPersist = NULL;
+
+ // Create an instance of an object
+ if (pcf->CreateInstance(NULL, IID_IUnknown, (void **) &punk) == NOERROR)
+ {
+ // Do a QI to confirm object behaves correctly
+ if (punk->QueryInterface(IID_IPersist, (void **) &pIPersist) == NOERROR)
+ {
+ CLSID clsidTest;
+
+ // Make sure we can actually call through to the proxy object.
+ if ((pIPersist->GetClassID(&clsidTest) == NOERROR)
+ && IsEqualCLSID(clsidTest, rclsid))
+ {
+ fResult = TRUE;
+ }
+ }
+ }
+
+ if (punk != NULL)
+ {
+ punk->Release();
+ }
+
+ if (pIPersist != NULL)
+ {
+ pIPersist->Release();
+ }
+
+ return fResult;
+}
+
+
+
+
+
+//+-------------------------------------------------------------------
+//
+// Function: GetFullDllName, private
+//
+// Synopsis: Get the directory for the registration for the test.
+//
+// Arguments: [pszDllName] - DLL name
+// [pszFullDllName] - output buffer for DLL path
+//
+// Returns: TRUE - we could get the path for the DLL
+// FALSE - we couldn't figure out what to use.
+//
+// History: 31-Oct-94 Ricksa Created
+//
+// Notes:
+//
+//--------------------------------------------------------------------
+BOOL GetFullDllName(const TCHAR *pszDllName, TCHAR *pszFullDllName)
+{
+ // Use windows to tell us what DLL we would load.
+ HINSTANCE hinstDll = LoadLibraryEx(pszDllName, NULL,
+ DONT_RESOLVE_DLL_REFERENCES | LOAD_WITH_ALTERED_SEARCH_PATH);
+
+ if (hinstDll == NULL)
+ {
+ // We could not find the DLL so there isn't much purpose in
+ // continuing the test.
+ MessageBox(NULL, TEXT("LoadLibraryEx Failed!"),
+ TEXT("FATAL ERROR"), MB_OK);
+ return FALSE;
+ }
+
+ // Get the DLLs path name
+ if (!GetModuleFileName(hinstDll, pszFullDllName, MAX_PATH))
+ {
+ // How can this fail?? -- anyway we better tell someone.
+ MessageBox(NULL, TEXT("Threading Test GetModuleFileName Failed!"),
+ TEXT("FATAL ERROR"), MB_OK);
+ return FALSE;
+ }
+
+ FreeLibrary(hinstDll);
+
+ return TRUE;
+}
+
+
+
+//+-------------------------------------------------------------------
+//
+// Function: SetRegForDll, private
+//
+// Synopsis: Set registry entry for a DLL
+//
+// Arguments: [rclsid] - clsid for reg entry
+// [pszDir] - directory for DLL path
+// [pszDllName] - name to use for DLL
+// [pszThreadModel] - threading model can be NULL.
+//
+// Returns: TRUE - Registry entry set successfully.
+// FALSE - Registry entry set successfully.
+//
+// History: 01-Nov-94 Ricksa Created
+//
+//--------------------------------------------------------------------
+BOOL SetRegForDll(
+ REFCLSID rclsid,
+ const TCHAR *pszDllName,
+ const TCHAR *pszThreadModel)
+{
+ // Result returned by function
+ BOOL fResult = FALSE;
+
+ // String buffer used for various purposes
+ TCHAR aszWkBuf[MAX_PATH];
+
+ // Key to class
+ HKEY hKeyClass = NULL;
+
+ // Key to DLL entry
+ HKEY hKeyDll = NULL;
+
+ // Build clsid registry key
+ wsprintf(aszWkBuf,
+ TEXT("CLSID\\{%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}"),
+ rclsid.Data1, rclsid.Data2, rclsid.Data3,
+ rclsid.Data4[0], rclsid.Data4[1],
+ rclsid.Data4[2], rclsid.Data4[3],
+ rclsid.Data4[4], rclsid.Data4[5],
+ rclsid.Data4[6], rclsid.Data4[7]);
+
+ // Create the key for the class
+ if (ERROR_SUCCESS != RegCreateKey(HKEY_CLASSES_ROOT, aszWkBuf, &hKeyClass))
+ {
+ goto SetSingleThreadRegEntryExit;
+ }
+
+ // Create the key for the DLL
+
+ if (ERROR_SUCCESS != RegCreateKey(hKeyClass, TEXT("InprocServer32"),
+ &hKeyDll))
+ {
+ goto SetSingleThreadRegEntryExit;
+ }
+
+ // Build the DLL name
+ if (!GetFullDllName(pszDllName, &aszWkBuf[0]))
+ {
+ goto SetSingleThreadRegEntryExit;
+ }
+
+ OutputDebugString(&aszWkBuf[0]);
+
+ // Set the value for the DLL name
+ if (ERROR_SUCCESS != RegSetValue(hKeyDll, NULL, REG_SZ, aszWkBuf,
+ lstrlen(aszWkBuf)))
+ {
+ goto SetSingleThreadRegEntryExit;
+ }
+
+ // Set the threading model if there is one
+ if (pszThreadModel != NULL)
+ {
+ // Set the value for the DLL name
+ if (ERROR_SUCCESS != RegSetValueEx(hKeyDll, pszRegValThreadModel, 0,
+ REG_SZ, (const unsigned char*) pszThreadModel,
+ lstrlen(pszThreadModel) + 1))
+ {
+ goto SetSingleThreadRegEntryExit;
+ }
+ }
+
+ fResult = TRUE;
+
+SetSingleThreadRegEntryExit:
+
+ if (hKeyClass != NULL)
+ {
+ RegCloseKey(hKeyClass);
+ }
+
+ if (hKeyDll != NULL)
+ {
+ RegCloseKey(hKeyDll);
+ }
+
+ if (!fResult)
+ {
+ wsprintf(aszWkBuf, TEXT("Registry Setup For %s Failed"), pszDllName);
+
+ MessageBox(NULL, aszWkBuf, TEXT("FATAL ERROR"), MB_OK);
+ }
+
+ return fResult;
+}
+
+
+
+//+-------------------------------------------------------------------
+//
+// Function: SingleThreadTestThread, private
+//
+// Synopsis: Verify single threaded object call correctly from non
+// main thread.
+//
+// Arguments: [pvCtrlData] - control data for the thread
+//
+// Returns: 0 - interesting values returned through pvCtrlData.
+//
+// History: 31-Oct-94 Ricksa Created
+//
+//--------------------------------------------------------------------
+DWORD SingleThreadTestThread(void *pvCtrlData)
+{
+ // Data shared with main thread
+ SSTParamBlock *psstp = (SSTParamBlock *) pvCtrlData;
+
+ psstp->fResult = FALSE;
+
+ // Local class factory object.
+ IClassFactory *pcf = NULL;
+
+ // IUnknown ptrs used for multiple purposes
+ IUnknown *punk = NULL;
+
+ // Initialize thread
+ if (CoInitialize(NULL) != NOERROR)
+ {
+ goto SingleThreadTestThreadExit;
+ }
+
+ // Get the class object
+ if (CoGetClassObject(clsidSingleThreadedDll, CLSCTX_INPROC, NULL,
+ IID_IClassFactory, (void **) &pcf) != NOERROR)
+ {
+ goto SingleThreadTestThreadExit;
+ }
+
+ // Make sure main thread's ptr is not the same as this thread's ptr.
+ if (pcf == psstp->pcf)
+ {
+ goto SingleThreadTestThreadExit;
+ }
+
+ // Confirm that class object is a proxy
+ if (pcf->QueryInterface(IID_IProxyManager, (void **) &punk) == NOERROR)
+ {
+ // Verify that we can play with an object.
+ psstp->fResult = VerifyTestObject(pcf, clsidSingleThreadedDll);
+ }
+
+SingleThreadTestThreadExit:
+
+ if (pcf != NULL)
+ {
+ pcf->Release();
+ }
+
+ if (punk != NULL)
+ {
+ punk->Release();
+ }
+
+ // Exit the thread.
+ SetEvent(psstp->hEvent);
+
+ return 0;
+}
+
+
+
+
+//+-------------------------------------------------------------------
+//
+// Function: AptTestThread, private
+//
+// Synopsis: Verify apt threaded object call correctly from thread
+// if was not created on.
+//
+// Arguments: [pvCtrlData] - control data for the thread
+//
+// Returns: 0 - interesting values returned through pvCtrlData.
+//
+// History: 02-Nov-94 Ricksa Created
+//
+//--------------------------------------------------------------------
+DWORD AptTestThread(void *pvCtrlData)
+{
+ // Data shared with main thread
+ SATParamBlock *psatpb = (SATParamBlock *) pvCtrlData;
+
+ psatpb->fResult = FALSE;
+
+ // Class factory object unmarshaled from other thread.
+ IClassFactory *pcfUnmarshal = NULL;
+
+ // Class factory gotten from this thread
+ IClassFactory *pcfThisThread = NULL;
+
+ // IUnknown ptrs used for multiple purposes
+ IUnknown *punk = NULL;
+
+ // Initialize thread
+ if (CoInitialize(NULL) != NOERROR)
+ {
+ goto AptTestThreadExit;
+ }
+
+ // Get the class object from the marshaled stream
+ if (CoGetInterfaceAndReleaseStream(psatpb->pstrm, IID_IClassFactory,
+ (void **) &pcfUnmarshal) != NOERROR)
+ {
+ goto AptTestThreadExit;
+ }
+
+ // Caller doesn't have to release this now.
+ psatpb->pstrm = NULL;
+
+ // Make sure main thread's ptr is not the same as this thread's ptr.
+ if (pcfUnmarshal == psatpb->pcf)
+ {
+ goto AptTestThreadExit;
+ }
+
+ // Confirm that class object is a proxy
+ if (pcfUnmarshal->QueryInterface(IID_IProxyManager, (void **) &punk)
+ != NOERROR)
+ {
+ goto AptTestThreadExit;
+ }
+
+ // Release the interface we got back and NULL it let the exit routine
+ // known that it does not have to clean this object up.
+ punk->Release();
+ punk = NULL;
+
+ if (!VerifyTestObject(pcfUnmarshal, clsidAptThreadedDll))
+ {
+ goto AptTestThreadExit;
+ }
+
+ // Get the class factory for this thread
+ if (CoGetClassObject(clsidAptThreadedDll, CLSCTX_INPROC, NULL,
+ IID_IClassFactory, (void **) &pcfThisThread) != NOERROR)
+ {
+ goto AptTestThreadExit;
+ }
+
+ // Make sure that it isn't the same as the one we unmarshaled
+ if (pcfUnmarshal == pcfThisThread)
+ {
+ goto AptTestThreadExit;
+ }
+
+ // Make sure the one we got for this not a proxy.
+ if (pcfThisThread->QueryInterface(IID_IProxyManager, (void **) &punk)
+ != NOERROR)
+ {
+ psatpb->fResult = VerifyTestObject(pcfThisThread, clsidAptThreadedDll);
+ }
+
+AptTestThreadExit:
+
+ if (pcfUnmarshal != NULL)
+ {
+ pcfUnmarshal->Release();
+ }
+
+ if (pcfThisThread != NULL)
+ {
+ pcfThisThread->Release();
+ }
+
+ if (punk != NULL)
+ {
+ punk->Release();
+ }
+
+ // Exit the thread.
+ SetEvent(psatpb->hEvent);
+
+ return 0;
+}
+
+
+
+
+//+-------------------------------------------------------------------
+//
+// Function: BothTestThread, private
+//
+// Synopsis: Verify a DLL that supports both models is marshaled
+// correctly.
+//
+// Arguments: [pvCtrlData] - control data for the thread
+//
+// Returns: 0 - interesting values returned through pvCtrlData.
+//
+// History: 02-Nov-94 Ricksa Created
+//
+//--------------------------------------------------------------------
+DWORD BothTestThread(void *pvCtrlData)
+{
+ // Data shared with main thread
+ SBTParamBlock *psbtpb = (SBTParamBlock *) pvCtrlData;
+
+ psbtpb->fResult = FALSE;
+
+ // Class factory object unmarshaled from other thread.
+ IClassFactory *pcfUnmarshal = NULL;
+
+ // IUnknown ptrs used for multiple purposes
+ IUnknown *punk = NULL;
+ IUnknown *pIPersist = NULL;
+
+ // Initialize thread
+ if (CoInitialize(NULL) != NOERROR)
+ {
+ goto BothTestThreadExit;
+ }
+
+ // Get the class object from the marshaled stream
+ if (CoGetInterfaceAndReleaseStream(psbtpb->pstrm, IID_IClassFactory,
+ (void **) &pcfUnmarshal) != NOERROR)
+ {
+ goto BothTestThreadExit;
+ }
+
+ // Caller doesn't have to release this now.
+ psbtpb->pstrm = NULL;
+
+ // Make sure main thread's ptr is not the same as this thread's ptr.
+ if (pcfUnmarshal != psbtpb->pcf)
+ {
+ goto BothTestThreadExit;
+ }
+
+ // Confirm that class object is a proxy
+ if (pcfUnmarshal->QueryInterface(IID_IProxyManager, (void **) &punk)
+ != NOERROR)
+ {
+ // Make sure object created by the class works as expected
+ psbtpb->fResult = VerifyTestObject(pcfUnmarshal, clsidBothThreadedDll);
+ }
+
+BothTestThreadExit:
+
+ if (pcfUnmarshal != NULL)
+ {
+ pcfUnmarshal->Release();
+ }
+
+ if (punk != NULL)
+ {
+ punk->Release();
+ }
+
+ // Exit the thread.
+ SetEvent(psbtpb->hEvent);
+
+ return 0;
+}
+
+
+
+
+//+-------------------------------------------------------------------
+//
+// Function: SetUpRegistry, private
+//
+// Synopsis: Make sure registry is set up appropriately for the test
+//
+// Returns: TRUE - Registry set up successfully
+// FALSE - Registry could not be set up
+//
+// History: 31-Oct-94 Ricksa Created
+//
+//--------------------------------------------------------------------
+BOOL SetUpRegistry(void)
+{
+ BOOL fRet = FALSE;
+
+ // Update the registry with the correct information
+ fRet = SetRegForDll(clsidSingleThreadedDll, pszSingleThreadedDll, NULL)
+ && SetRegForDll(clsidAptThreadedDll, pszAptThreadedDll,
+ pszApartmentModel)
+ && SetRegForDll(clsidBothThreadedDll, pszBothThreadedDll, pszBoth);
+
+ // Give Registry a chance to get updated
+ Sleep(1000);
+
+ return fRet;
+}
+
+
+
+//+-------------------------------------------------------------------
+//
+// Function: TestSingleThread, private
+//
+// Synopsis: Driver to verify testing of single threaded behavior
+//
+// Returns: TRUE - Test Passed
+// FALSE - Test Failed
+//
+// History: 31-Oct-94 Ricksa Created
+//
+//--------------------------------------------------------------------
+BOOL TestSingleThread(void)
+{
+ // Result of test - default to FALSE.
+ BOOL fResult = FALSE;
+
+ // Create an event for test to wait for completion of test.
+ SSTParamBlock sstp;
+
+ sstp.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+
+ sstp.pcf = NULL;
+
+ if (sstp.hEvent == NULL)
+ {
+ goto TestSingleThreadExit;
+ }
+
+ // Create a class object and put in a parameter block
+ if (CoGetClassObject(clsidSingleThreadedDll, CLSCTX_INPROC, NULL,
+ IID_IClassFactory, (void **) &sstp.pcf) != NOERROR)
+ {
+ goto TestSingleThreadExit;
+ }
+
+ // Create the thread.
+ if (CreateTestThread(SingleThreadTestThread, &sstp))
+ {
+ // Wait for test to complete - ignore deadlock for now at least. The
+ // test thread is simple enough that it should not be a problem.
+ ThreadWaitForEvent(sstp.hEvent);
+
+ // Get result from thread
+ fResult = sstp.fResult;
+ }
+
+TestSingleThreadExit:
+
+ if (sstp.hEvent != NULL)
+ {
+ CloseHandle(sstp.hEvent);
+ }
+
+ if (sstp.pcf != NULL)
+ {
+ sstp.pcf->Release();
+ }
+
+ // Let user know this didn't work
+ if (!fResult)
+ {
+ MessageBox(NULL, TEXT("Single Threaded Test Failed"),
+ TEXT("FATAL ERROR"), MB_OK);
+ }
+
+ // Return results of test
+ return fResult;
+}
+
+
+
+
+
+//+-------------------------------------------------------------------
+//
+// Function: TestAptThread, private
+//
+// Synopsis: Test an apartment model object. The most important
+// aspect of this is that it tests the helper APIs.
+//
+// Returns: TRUE - Test Passed
+// FALSE - Test Failed
+//
+// History: 31-Oct-94 Ricksa Created
+//
+//--------------------------------------------------------------------
+BOOL TestAptThread(void)
+{
+ // Return result for test
+ BOOL fResult = FALSE;
+
+ // Block for passing parameters to the test thread
+ SATParamBlock satpb;
+
+ satpb.pstrm = NULL;
+ satpb.pcf = NULL;
+
+ // Create an event for test to wait for completion of test.
+ satpb.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+
+ if (satpb.hEvent == NULL)
+ {
+ goto TestAptThreadExit;
+ }
+ satpb.pcf = NULL;
+ // Create a class object and put in parameter block
+ if (CoGetClassObject(clsidAptThreadedDll, CLSCTX_INPROC, NULL,
+ IID_IClassFactory, (void **) &satpb.pcf) != NOERROR)
+ {
+ goto TestAptThreadExit;
+ }
+
+ // Create stream using helper API
+ if (CoMarshalInterThreadInterfaceInStream(IID_IClassFactory,
+ satpb.pcf, &satpb.pstrm) != NOERROR)
+ {
+ goto TestAptThreadExit;
+ }
+
+ // Create thread to do apartment model test
+ if (CreateTestThread(AptTestThread, &satpb))
+ {
+ // Wait for test to complete - ignore deadlock for now at least. The
+ // test thread is simple enough that it should not be a problem.
+ ThreadWaitForEvent(satpb.hEvent);
+
+ // Get result from thread
+ fResult = satpb.fResult;
+ }
+
+TestAptThreadExit:
+
+ // Clean up any resources
+ if (satpb.hEvent != NULL)
+ {
+ CloseHandle(satpb.hEvent);
+ }
+
+ if (satpb.pcf != NULL)
+ {
+ satpb.pcf->Release();
+ }
+
+ if (satpb.pstrm != NULL)
+ {
+ satpb.pstrm->Release();
+ }
+
+ // Let user know this didn't work
+ if (!fResult)
+ {
+ MessageBox(NULL, TEXT("Apartment Threaded Test Failed"),
+ TEXT("FATAL ERROR"), MB_OK);
+ }
+
+ // Return results of test
+ return fResult;
+}
+
+
+
+
+
+//+-------------------------------------------------------------------
+//
+// Function: TestBothDll, private
+//
+// Synopsis: Test using DLL that purports to support both free
+// threading and apt model. The most important aspect
+// of this test is that it tests the marshal context.
+//
+// Returns: TRUE - Test Passed
+// FALSE - Test Failed
+//
+// History: 31-Oct-94 Ricksa Created
+//
+//--------------------------------------------------------------------
+BOOL TestBothDll(void)
+{
+ // Return result for test
+ BOOL fResult = FALSE;
+
+ // Block for passing parameters to the test thread
+ SBTParamBlock sbtpb;
+
+ sbtpb.pstrm = NULL;
+ sbtpb.pcf = NULL;
+
+ IClassFactory *pcfFromMarshal = NULL;
+ IStream *pstmForMarshal = NULL;
+ HGLOBAL hglobForStream = NULL;
+
+ // Create an event for test to wait for completion of test.
+ sbtpb.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+
+ if (sbtpb.hEvent == NULL)
+ {
+ goto TestBothDllExit;
+ }
+
+ // Create a class object and put in parameter block
+ if (CoGetClassObject(clsidBothThreadedDll, CLSCTX_INPROC, NULL,
+ IID_IClassFactory, (void **) &sbtpb.pcf) != NOERROR)
+ {
+ goto TestBothDllExit;
+ }
+
+ // Marshal this for the local context and unmarshal it and
+ // see if we get the same result.
+
+ if ((hglobForStream = GlobalAlloc(GMEM_MOVEABLE, 100)) == NULL)
+ {
+ GetLastError();
+ goto TestBothDllExit;
+ }
+
+ if (CreateStreamOnHGlobal(hglobForStream, TRUE, &pstmForMarshal) != NOERROR)
+ {
+ goto TestBothDllExit;
+ }
+
+ if (CoMarshalInterface(pstmForMarshal, IID_IClassFactory, sbtpb.pcf,
+ MSHCTX_LOCAL, NULL, MSHLFLAGS_NORMAL) != NOERROR)
+ {
+ goto TestBothDllExit;
+ }
+
+ // Reset the stream to the begining
+ {
+ LARGE_INTEGER li;
+ LISet32(li, 0);
+ pstmForMarshal->Seek(li, STREAM_SEEK_SET, NULL);
+ }
+
+ if (CoUnmarshalInterface(pstmForMarshal, IID_IClassFactory,
+ (void **) &pcfFromMarshal) != NOERROR)
+ {
+ goto TestBothDllExit;
+ }
+
+ if (sbtpb.pcf != pcfFromMarshal)
+ {
+ goto TestBothDllExit;
+ }
+
+ // Create stream using helper API
+ if (CoMarshalInterThreadInterfaceInStream(IID_IClassFactory,
+ sbtpb.pcf, &sbtpb.pstrm) != NOERROR)
+ {
+ goto TestBothDllExit;
+ }
+
+ // Create thread to do apartment model test
+ if (CreateTestThread(BothTestThread, &sbtpb))
+ {
+ // Wait for test to complete - ignore deadlock for now at least. The
+ // test thread is simple enough that it should not be a problem.
+ WaitForSingleObject(sbtpb.hEvent, INFINITE);
+
+ // Get result from thread
+ fResult = sbtpb.fResult;
+ }
+
+TestBothDllExit:
+
+ // Clean up any resources
+ if (sbtpb.hEvent != NULL)
+ {
+ CloseHandle(sbtpb.hEvent);
+ }
+
+ if (sbtpb.pcf != NULL)
+ {
+ sbtpb.pcf->Release();
+ }
+
+ if (sbtpb.pstrm != NULL)
+ {
+ sbtpb.pstrm->Release();
+ }
+
+ if (pcfFromMarshal != NULL)
+ {
+ pcfFromMarshal->Release();
+ }
+
+ if (pstmForMarshal != NULL)
+ {
+ pstmForMarshal->Release();
+ }
+ else if (hglobForStream != NULL)
+ {
+ GlobalFree(hglobForStream);
+ }
+
+ // Let user know this didn't work
+ if (!fResult)
+ {
+ MessageBox(NULL, TEXT("Both Threaded Test Failed"),
+ TEXT("FATAL ERROR"), MB_OK);
+ }
+
+ // Return results of test
+ return fResult;
+}
+
+
+
+
+//+-------------------------------------------------------------------
+//
+// Function: TestFreeAllLibraries, private
+//
+// Synopsis: Test free from non-main thread. This is really to
+// just make sure that nothing really bad happens when
+// we do this.
+//
+// Returns: TRUE - Test Passed
+// FALSE - Test Failed
+//
+// History: 31-Oct-94 Ricksa Created
+//
+//--------------------------------------------------------------------
+BOOL TestFreeAllLibraries(void)
+{
+ CoFreeUnusedLibraries();
+
+ return TRUE;
+}
+
+
+
+
+//+-------------------------------------------------------------------
+//
+// Function: ThreadUnitTest, public
+//
+// Synopsis: Test various messaging enhancements to OLE
+//
+// Returns: TRUE - Test Passed
+// FALSE - Test Failed
+//
+// History: 31-Oct-94 Ricksa Created
+//
+//--------------------------------------------------------------------
+HRESULT ThreadUnitTest(void)
+{
+ HRESULT hr = E_FAIL;
+
+ // Make sure OLE is initialized
+ HRESULT hrInit = OleInitialize(NULL);
+
+ if (FAILED(hrInit))
+ {
+ MessageBox(NULL, TEXT("ThreadUnitTest: OleInitialize FAILED"),
+ TEXT("FATAL ERROR"), MB_OK);
+ goto ThreadUnitTestExit;
+ }
+
+ // Set up the registry
+ if (!SetUpRegistry())
+ {
+ goto ThreadUnitTestExit;
+ }
+
+ // Test Single Threaded DLL
+ if (!TestSingleThread())
+ {
+ goto ThreadUnitTestExit;
+ }
+
+ // Test an aparment model DLL
+ if (!TestAptThread())
+ {
+ goto ThreadUnitTestExit;
+ }
+
+ // Test a both DLL
+ if (!TestBothDll())
+ {
+ goto ThreadUnitTestExit;
+ }
+
+ // Test CoFreeAllLibraries
+ if (TestFreeAllLibraries())
+ {
+ hr = NOERROR;
+ }
+
+ThreadUnitTestExit:
+
+ OleUninitialize();
+
+ return hr;
+}
diff --git a/private/oleutest/oletest/utils.cpp b/private/oleutest/oletest/utils.cpp
new file mode 100644
index 000000000..57e17afff
--- /dev/null
+++ b/private/oleutest/oletest/utils.cpp
@@ -0,0 +1,133 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: utils.cpp
+//
+// Contents: various utility functions for oletest
+//
+// Classes:
+//
+// Functions: DumpFormatetc
+//
+// History: dd-mmm-yy Author Comment
+// 11-Aug-94 alexgo author
+//
+//--------------------------------------------------------------------------
+
+#include "oletest.h"
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: DumpFormatetc
+//
+// Synopsis: prints the contents of the formatetc to the given file
+//
+// Effects:
+//
+// Arguments: [pformatetc] -- the formatetc
+// [fp] -- the file pointer
+//
+// Requires:
+//
+// Returns: void
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 11-Aug-94 alexgo author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+void DumpFormatetc( FORMATETC *pformatetc, FILE *fp)
+{
+ char szBuf[256];
+
+ fprintf(fp, "\n\n");
+
+ // clipboard format
+ GetClipboardFormatName(pformatetc->cfFormat, szBuf, sizeof(szBuf));
+ fprintf(fp, "cfFormat: %s\n", szBuf);
+
+ // target device
+ fprintf(fp, "ptd: %p\n", pformatetc->ptd);
+
+ // aspect
+ if( pformatetc->dwAspect == DVASPECT_CONTENT )
+ {
+ sprintf(szBuf, "DVASPECT_CONTENT");
+ }
+ else if( pformatetc->dwAspect == DVASPECT_ICON )
+ {
+ sprintf(szBuf, "DVASPECT_ICON");
+ }
+ else if( pformatetc->dwAspect == DVASPECT_THUMBNAIL )
+ {
+ sprintf(szBuf, "DVASPECT_THUMBNAIL");
+ }
+ else if( pformatetc->dwAspect == DVASPECT_DOCPRINT )
+ {
+ sprintf(szBuf, "DVASPECT_DOCPRINT");
+ }
+ else
+ {
+ sprintf(szBuf, "UNKNOWN ASPECT");
+ }
+
+ fprintf(fp, "dwAspect: %s\n", szBuf);
+
+ // lindex
+
+ fprintf(fp, "lindex: %lx\n", pformatetc->lindex);
+
+ // medium
+
+ szBuf[0] = '\0';
+
+ if( pformatetc->tymed & TYMED_HGLOBAL )
+ {
+ strcat(szBuf, "TYMED_HGLOBAL ");
+ }
+
+ if( pformatetc->tymed & TYMED_FILE )
+ {
+ strcat(szBuf, "TYMED_FILE");
+ }
+
+ if( pformatetc->tymed & TYMED_ISTREAM )
+ {
+ strcat(szBuf, "TYMED_ISTREAM");
+ }
+
+ if( pformatetc->tymed & TYMED_ISTORAGE )
+ {
+ strcat(szBuf, "TYMED_ISTORAGE");
+ }
+
+ if( pformatetc->tymed & TYMED_GDI )
+ {
+ strcat(szBuf, "TYMED_GDI");
+ }
+
+ if( pformatetc->tymed & TYMED_MFPICT )
+ {
+ strcat(szBuf, "TYMED_MFPICT");
+ }
+
+ // TYMED_EMFPICT (not in 16bit)
+ if( (ULONG)pformatetc->tymed & (ULONG)64L )
+ {
+ strcat(szBuf, "TYMED_ENHMF");
+ }
+
+ fprintf(fp, "tymed: %s\n\n", szBuf);
+}
+
diff --git a/private/oleutest/oletest/utils.h b/private/oleutest/oletest/utils.h
new file mode 100644
index 000000000..daef95fc2
--- /dev/null
+++ b/private/oleutest/oletest/utils.h
@@ -0,0 +1,24 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: utils.h
+//
+// Contents: declarations for utility functions
+//
+// Classes:
+//
+// Functions: DumpFormatetc
+//
+// History: dd-mmm-yy Author Comment
+// 11-Aug-94 alexgo author
+//
+//--------------------------------------------------------------------------
+
+#ifndef _UTILS_H
+
+void DumpFormatetc(FORMATETC *pformatetc, FILE *fp);
+
+#endif // _UTILS_H
+
diff --git a/private/oleutest/oleutest.bat b/private/oleutest/oleutest.bat
new file mode 100644
index 000000000..05b3390cc
--- /dev/null
+++ b/private/oleutest/oleutest.bat
@@ -0,0 +1,405 @@
+@echo REGEDIT > oleutest.reg
+@rem (The above line is a quick check that we are indeed a registration script)
+@rem
+@rem ALL LINES THAT DON'T START WITH 'HKEY_CLASSES_ROOT' ARE COMMENTS.
+@rem
+@rem THIS FILE CONSISTS OF A LIST OF <key> <value> PAIRS.
+@rem THE key AND value SHOULD BE SEPERATED BY A " = " mark (note spaces).
+@rem
+@rem
+@rem
+@rem REGISTRATION INFORMATION FOR olebind test
+@rem
+@rem
+@echo HKEY_CLASSES_ROOT\.ut1 = ProgID49>> oleutest.reg
+@echo HKEY_CLASSES_ROOT\.ut2 = ProgID48>> oleutest.reg
+@echo HKEY_CLASSES_ROOT\.ut3 = ProgID47>> oleutest.reg
+@echo HKEY_CLASSES_ROOT\.ut4 = ProgID50>> oleutest.reg
+@echo HKEY_CLASSES_ROOT\ProgID49 = test app 1 >> oleutest.reg
+@echo HKEY_CLASSES_ROOT\ProgID49\CLSID = {99999999-0000-0008-C000-000000000049}>> oleutest.reg
+@echo HKEY_CLASSES_ROOT\ProgID48 = test app 2 >> oleutest.reg
+@echo HKEY_CLASSES_ROOT\ProgID48\CLSID = {99999999-0000-0008-C000-000000000048}>> oleutest.reg
+@echo HKEY_CLASSES_ROOT\ProgID47 = test app 3 >> oleutest.reg
+@echo HKEY_CLASSES_ROOT\ProgID47\CLSID = {99999999-0000-0008-C000-000000000047}>> oleutest.reg
+@echo HKEY_CLASSES_ROOT\ProgID50 = test app 4 >> oleutest.reg
+@echo HKEY_CLASSES_ROOT\ProgID50\CLSID = {99999999-0000-0008-C000-000000000050}>> oleutest.reg
+@echo HKEY_CLASSES_ROOT\CLSID>> oleutest.reg
+@echo HKEY_CLASSES_ROOT\CLSID\{00000009-0000-0008-C000-000000000047} = BasicSrv>> oleutest.reg
+@echo HKEY_CLASSES_ROOT\CLSID\{00000009-0000-0008-C000-000000000047}\LocalServer32 = %SystemRoot%\dump\testsrv.exe>> oleutest.reg
+@echo HKEY_CLASSES_ROOT\CLSID\{00000009-0000-0008-C000-000000000048} = BasicBnd2>> oleutest.reg
+@echo HKEY_CLASSES_ROOT\CLSID\{00000009-0000-0008-C000-000000000048}\LocalServer32 = %SystemRoot%\dump\olesrv.exe>> oleutest.reg
+@echo HKEY_CLASSES_ROOT\CLSID\{00000009-0000-0008-C000-000000000049} = BasicBnd>> oleutest.reg
+@echo HKEY_CLASSES_ROOT\CLSID\{00000009-0000-0008-C000-000000000049}\InprocServer32 = %SystemRoot%\dump\oleimpl.dll>> oleutest.reg
+@echo HKEY_CLASSES_ROOT\CLSID\{99999999-0000-0008-C000-000000000048} = BasicBnd2>> oleutest.reg
+@echo HKEY_CLASSES_ROOT\CLSID\{99999999-0000-0008-C000-000000000048}\LocalServer32 = %SystemRoot%\dump\olesrv.exe>> oleutest.reg
+@echo HKEY_CLASSES_ROOT\CLSID\{99999999-0000-0008-C000-000000000049} = BasicBnd>> oleutest.reg
+@echo HKEY_CLASSES_ROOT\CLSID\{99999999-0000-0008-C000-000000000049}\InprocServer32 = %SystemRoot%\dump\oleimpl.dll>> oleutest.reg
+@echo HKEY_CLASSES_ROOT\CLSID\{99999999-0000-0008-C000-000000000047} = TestEmbed>> oleutest.reg
+@echo HKEY_CLASSES_ROOT\CLSID\{99999999-0000-0008-C000-000000000047}\InprocHandler32 = ole32.dll>> oleutest.reg
+@echo HKEY_CLASSES_ROOT\CLSID\{99999999-0000-0008-C000-000000000047}\InprocServer32 = ole32.dll>> oleutest.reg
+@echo HKEY_CLASSES_ROOT\CLSID\{99999999-0000-0008-C000-000000000047}\LocalServer32 = %SystemRoot%\dump\testsrv.exe>> oleutest.reg
+@echo HKEY_CLASSES_ROOT\CLSID\{99999999-0000-0008-C000-000000000047}\protocol>> oleutest.reg
+@echo HKEY_CLASSES_ROOT\CLSID\{99999999-0000-0008-C000-000000000047}\protocol\StdFileEditing>> oleutest.reg
+@echo HKEY_CLASSES_ROOT\CLSID\{99999999-0000-0008-C000-000000000047}\protocol\StdFileEditing\server = testsrv.exe>> oleutest.reg
+@echo HKEY_CLASSES_ROOT\CLSID\{99999999-0000-0008-C000-000000000050} = TestFail>> oleutest.reg
+@echo HKEY_CLASSES_ROOT\CLSID\{99999999-0000-0008-C000-000000000050}\LocalServer32 = %SystemRoot%\dump\fail.exe>> oleutest.reg
+@rem
+@rem
+@rem REGISTRATION INFORMATION FOR simpsvr.exe
+@rem
+@rem
+@echo HKEY_CLASSES_ROOT\SIMPSVR = Simple OLE 2.0 Server>> oleutest.reg
+@echo HKEY_CLASSES_ROOT\SIMPSVR\protocol\StdFileEditing\server = simpsvr.exe>> oleutest.reg
+@echo HKEY_CLASSES_ROOT\SIMPSVR\protocol\StdFileEditing\verb\0 = ^&Edit>> oleutest.reg
+@echo HKEY_CLASSES_ROOT\SIMPSVR\protocol\StdFileEditing\verb\1 = ^&Open>> oleutest.reg
+@echo HKEY_CLASSES_ROOT\SIMPSVR\Insertable>> oleutest.reg
+@echo HKEY_CLASSES_ROOT\SIMPSVR\CLSID = {BCF6D4A0-BE8C-1068-B6D4-00DD010C0509}>> oleutest.reg
+@echo HKEY_CLASSES_ROOT\CLSID\{BCF6D4A0-BE8C-1068-B6D4-00DD010C0509} = Simple OLE 2.0 Server>> oleutest.reg
+@echo HKEY_CLASSES_ROOT\CLSID\{BCF6D4A0-BE8C-1068-B6D4-00DD010C0509}\Insertable>> oleutest.reg
+@echo HKEY_CLASSES_ROOT\CLSID\{BCF6D4A0-BE8C-1068-B6D4-00DD010C0509}\MiscStatus = 0 >> oleutest.reg
+@echo HKEY_CLASSES_ROOT\CLSID\{BCF6D4A0-BE8C-1068-B6D4-00DD010C0509}\DefaultIcon = simpsvr.exe,0 >> oleutest.reg
+@echo HKEY_CLASSES_ROOT\CLSID\{BCF6D4A0-BE8C-1068-B6D4-00DD010C0509}\AuxUserType\2 = Simple Server>> oleutest.reg
+@echo HKEY_CLASSES_ROOT\CLSID\{BCF6D4A0-BE8C-1068-B6D4-00DD010C0509}\AuxUserType\3 = Simple OLE 2.0 Server>> oleutest.reg
+@echo HKEY_CLASSES_ROOT\CLSID\{BCF6D4A0-BE8C-1068-B6D4-00DD010C0509}\Verb\0 = ^&Play,0,2 >> oleutest.reg
+@echo HKEY_CLASSES_ROOT\CLSID\{BCF6D4A0-BE8C-1068-B6D4-00DD010C0509}\Verb\1 = ^&Open,0,2 >> oleutest.reg
+@echo HKEY_CLASSES_ROOT\CLSID\{BCF6D4A0-BE8C-1068-B6D4-00DD010C0509}\LocalServer32 = %SystemRoot%\dump\simpsvr.exe>> oleutest.reg
+@echo HKEY_CLASSES_ROOT\CLSID\{BCF6D4A0-BE8C-1068-B6D4-00DD010C0509}\InprocHandler32 = ole32.dll>> oleutest.reg
+@echo HKEY_CLASSES_ROOT\CLSID\{BCF6D4A0-BE8C-1068-B6D4-00DD010C0509}\ProgID = SIMPSVR>> oleutest.reg
+@echo HKEY_CLASSES_ROOT\CLSID\{BCF6D4A0-BE8C-1068-B6D4-00DD010C0509}\DataFormats\GetSet\0 = 3,1,32,1 >> oleutest.reg
+@echo HKEY_CLASSES_ROOT\.svr = SIMPSVR>> oleutest.reg
+@rem
+@rem
+@rem REGISTRATION INFORMATION FOR spsvr16.exe
+@rem
+@echo HKEY_CLASSES_ROOT\SPSVR16 = Simple 16 Bit OLE 2.0 Server>> oleutest.reg
+@echo HKEY_CLASSES_ROOT\SPSVR16\protocol\StdFileEditing\server = spsvr16.exe>> oleutest.reg
+@echo HKEY_CLASSES_ROOT\SPSVR16\protocol\StdFileEditing\verb\0 = ^&Edit>> oleutest.reg
+@echo HKEY_CLASSES_ROOT\SPSVR16\protocol\StdFileEditing\verb\1 = ^&Open>> oleutest.reg
+@echo HKEY_CLASSES_ROOT\SPSVR16\Insertable>> oleutest.reg
+@echo HKEY_CLASSES_ROOT\SPSVR16\CLSID = {9fb878d0-6f88-101b-bc65-00000b65c7a6}>> oleutest.reg
+@echo HKEY_CLASSES_ROOT\CLSID\{9fb878d0-6f88-101b-bc65-00000b65c7a6} = Simple 16 Bit OLE 2.0 Server>> oleutest.reg
+@echo HKEY_CLASSES_ROOT\CLSID\{9fb878d0-6f88-101b-bc65-00000b65c7a6}\Insertable>> oleutest.reg
+@echo HKEY_CLASSES_ROOT\CLSID\{9fb878d0-6f88-101b-bc65-00000b65c7a6}\MiscStatus = 0 >> oleutest.reg
+@echo HKEY_CLASSES_ROOT\CLSID\{9fb878d0-6f88-101b-bc65-00000b65c7a6}\DefaultIcon = spsvr16.exe,0 >> oleutest.reg
+@echo HKEY_CLASSES_ROOT\CLSID\{9fb878d0-6f88-101b-bc65-00000b65c7a6}\AuxUserType\2 = Simple Server>> oleutest.reg
+@echo HKEY_CLASSES_ROOT\CLSID\{9fb878d0-6f88-101b-bc65-00000b65c7a6}\AuxUserType\3 = Simple 16 Bit OLE 2.0 Server>> oleutest.reg
+@echo HKEY_CLASSES_ROOT\CLSID\{9fb878d0-6f88-101b-bc65-00000b65c7a6}\Verb\0 = ^&Play,0,2 >> oleutest.reg
+@echo HKEY_CLASSES_ROOT\CLSID\{9fb878d0-6f88-101b-bc65-00000b65c7a6}\Verb\1 = ^&Open,0,2 >> oleutest.reg
+@echo HKEY_CLASSES_ROOT\CLSID\{9fb878d0-6f88-101b-bc65-00000b65c7a6}\LocalServer = %SystemRoot%\dump\spsvr16.exe>> oleutest.reg
+@echo HKEY_CLASSES_ROOT\CLSID\{9fb878d0-6f88-101b-bc65-00000b65c7a6}\InprocHandler = ole2.dll>> oleutest.reg
+@echo HKEY_CLASSES_ROOT\CLSID\{9fb878d0-6f88-101b-bc65-00000b65c7a6}\ProgID = SPSVR16>> oleutest.reg
+@echo HKEY_CLASSES_ROOT\CLSID\{9fb878d0-6f88-101b-bc65-00000b65c7a6}\DataFormats\GetSet\0 = 3,1,32,1 >> oleutest.reg
+@echo HKEY_CLASSES_ROOT\.svr = SPSVR16>> oleutest.reg
+@rem
+@rem
+@rem REGISTRATION INFORMATION FOR ALL OUTLINE SERIES APPLICATIONS
+@rem
+@rem
+@rem VERSIONLESS PROGID ROOT-KEY INFORMATION
+@rem
+@rem ISVROTL is used as the current version of an OLEOutline server
+@rem
+@echo HKEY_CLASSES_ROOT\OLEOutline = Ole 2.0 In-Place Server Outline>> oleutest.reg
+@echo HKEY_CLASSES_ROOT\OLEOutline\CLSID = {00000402-0000-0000-C000-000000000046}>> oleutest.reg
+@echo HKEY_CLASSES_ROOT\OLEOutline\CurVer = OLE2ISvrOtl>> oleutest.reg
+@echo HKEY_CLASSES_ROOT\OLEOutline\CurVer\Insertable>> oleutest.reg
+@rem
+@rem
+@rem REGISTRATION ENTRY FOR SVROUTL.EXE
+@rem
+@rem
+@rem PROGID ROOT-KEY INFORMATION
+@rem
+@echo HKEY_CLASSES_ROOT\OLE2SvrOutl = Ole 2.0 Server Sample Outline>> oleutest.reg
+@echo HKEY_CLASSES_ROOT\OLE2SvrOutl\CLSID = {00000400-0000-0000-C000-000000000046}>> oleutest.reg
+@rem
+@rem SVROUTL is marked as insertable so it appears in the InsertObject dialog
+@echo HKEY_CLASSES_ROOT\OLE2SvrOutl\Insertable>> oleutest.reg
+@rem
+@rem
+@rem OLE 1.0 COMPATIBILITY INFORMATION
+@rem
+@rem
+@echo HKEY_CLASSES_ROOT\OLE2SvrOutl\protocol\StdFileEditing\verb\0 = ^&Edit>> oleutest.reg
+@echo HKEY_CLASSES_ROOT\OLE2SvrOutl\protocol\StdFileEditing\server = svroutl.exe>> oleutest.reg
+@rem
+@rem
+@rem WINDOWS 3.1 SHELL INFORMATION
+@rem
+@rem
+@echo HKEY_CLASSES_ROOT\OLE2SvrOutl\Shell\Print\Command = svroutl.exe %%1%>> oleutest.reg
+@echo HKEY_CLASSES_ROOT\OLE2SvrOutl\Shell\Open\Command = svroutl.exe %%1%>> oleutest.reg
+@rem
+@rem
+@rem OLE 2.0 CLSID ENTRY INFORMATION
+@rem
+@rem
+@echo HKEY_CLASSES_ROOT\CLSID\{00000400-0000-0000-C000-000000000046} = Ole 2.0 Server Sample Outline>> oleutest.reg
+@echo HKEY_CLASSES_ROOT\CLSID\{00000400-0000-0000-C000-000000000046}\ProgID = OLE2SvrOutl>> oleutest.reg
+@rem
+@rem
+@rem OLE 2.0 OBJECT HANDLER/EXE INFORMATION
+@rem
+@rem
+@echo HKEY_CLASSES_ROOT\CLSID\{00000400-0000-0000-C000-000000000046}\InprocHandler32 = ole32.dll>> oleutest.reg
+@echo HKEY_CLASSES_ROOT\CLSID\{00000400-0000-0000-C000-000000000046}\LocalServer32 = %SystemRoot%\dump\svroutl.exe>> oleutest.reg
+@rem
+@rem
+@rem VERB MENU SUPPORT
+@rem
+@rem
+@rem Verb 0: "Edit", MF_UNCHECKED | MF_ENABLED, OLEVERBATTRIB_ONCONTAINERMENU
+@echo HKEY_CLASSES_ROOT\CLSID\{00000400-0000-0000-C000-000000000046}\Verb\0 = ^&Edit,0,2 >> oleutest.reg
+@rem
+@rem This class should appear in Insert New Object list
+@echo HKEY_CLASSES_ROOT\CLSID\{00000400-0000-0000-C000-000000000046}\Insertable>> oleutest.reg
+@rem
+@rem
+@rem USER TYPE NAMES
+@rem
+@rem
+@rem ShortName (NOTE: max 15 chars) = Server Outline
+@echo HKEY_CLASSES_ROOT\CLSID\{00000400-0000-0000-C000-000000000046}\AuxUserType\2 = Outline>> oleutest.reg
+@rem
+@rem AppName = Ole 2.0 Outline Server
+@rem
+@echo HKEY_CLASSES_ROOT\CLSID\{00000400-0000-0000-C000-000000000046}\AuxUserType\3 = Ole 2.0 Outline Server>> oleutest.reg
+@rem
+@rem
+@rem ICON DEFINITION
+@rem
+@rem
+@echo HKEY_CLASSES_ROOT\CLSID\{00000400-0000-0000-C000-000000000046}\DefaultIcon = svroutl.exe,0 >> oleutest.reg
+@rem
+@rem
+@rem DATA FORMATS SUPPORTED
+@rem
+@rem
+@rem Default File Format = CF_Outline
+@echo HKEY_CLASSES_ROOT\CLSID\{00000400-0000-0000-C000-000000000046}\DataFormats\DefaultFile = Outline>> oleutest.reg
+@rem
+@rem Format 0 = CF_OUTLINE, DVASPECT_CONTENT, TYMED_HGLOBAL, DATADIR_BOTH
+@echo HKEY_CLASSES_ROOT\CLSID\{00000400-0000-0000-C000-000000000046}\DataFormats\GetSet\0 = Outline,1,1,3 >> oleutest.reg
+@rem
+@rem Format 1 = CF_TEXT, DVASPECT_CONTENT, TYMED_HGLOBAL, DATADIR_BOTH
+@echo HKEY_CLASSES_ROOT\CLSID\{00000400-0000-0000-C000-000000000046}\DataFormats\GetSet\1 = 1,1,1,3 >> oleutest.reg
+@rem
+@rem Format 2 = CF_METAFILEPICT, DVASPECT_CONTENT, TYMED_MFPICT, DATADIR_GET>> oleutest.reg
+@echo HKEY_CLASSES_ROOT\CLSID\{00000400-0000-0000-C000-000000000046}\DataFormats\GetSet\2 = 3,1,32,1 >> oleutest.reg
+@rem
+@rem Format 3 = CF_METAFILEPICT, DVASPECT_ICON, TYMED_MFPICT, DATADIR_GET
+@echo HKEY_CLASSES_ROOT\CLSID\{00000402-0000-0000-C000-000000000046}\DataFormats\GetSet\3 = 3,4,32,1 >> oleutest.reg
+@rem
+@rem MISC STATUS SUPPORTED
+@rem
+@rem
+@rem DVASPECT_CONTENT = OLEMISC_RENDERINGISDEVICEINDEPENDENT
+@rem
+@echo HKEY_CLASSES_ROOT\CLSID\{00000402-0000-0000-C000-000000000046}\MiscStatus = 512>> oleutest.reg
+@rem
+@rem
+@rem CONVERSION FORMATS SUPPORTED
+@rem
+@rem
+@rem Readable Main formats: CF_OUTLINE, CF_TEXT
+@rem
+@echo HKEY_CLASSES_ROOT\CLSID\{00000400-0000-0000-C000-000000000046}\Conversion\Readable\Main = Outline>> oleutest.reg
+@echo HKEY_CLASSES_ROOT\CLSID\{00000400-0000-0000-C000-000000000046}\Conversion\Readwritable\Main = Outline>> oleutest.reg
+@rem
+@rem
+@rem
+@rem REGISTRATION ENTRY FOR CNTROUTL.EXE
+@rem
+@rem
+@rem ENTRIES FOR Ole 2.0 Container Sample Outline
+@rem
+@rem
+@rem PROGID ROOT-KEY INFORMATION
+@rem
+@rem NOTE: CNTROUTL must have a ProgID assigned for the Windows 3.1 Shell
+@rem file associations and Packager to function correctly.
+@rem
+@echo HKEY_CLASSES_ROOT\OLE2CntrOutl = Ole 2.0 Container Sample Outline>> oleutest.reg
+@echo HKEY_CLASSES_ROOT\OLE2CntrOutl\Clsid = {00000401-0000-0000-C000-000000000046}>> oleutest.reg
+@rem
+@rem
+@rem WINDOWS 3.1 SHELL INFORMATION
+@rem
+@rem
+@echo HKEY_CLASSES_ROOT\OLE2CntrOutl\Shell\Print\Command = cntroutl.exe %%1%>> oleutest.reg
+@echo HKEY_CLASSES_ROOT\OLE2CntrOutl\Shell\Open\Command = cntroutl.exe %%1%>> oleutest.reg
+@rem
+@rem
+@rem OLE 2.0 CLSID ENTRY INFORMATION
+@rem
+@rem
+@echo HKEY_CLASSES_ROOT\CLSID\{00000401-0000-0000-C000-000000000046} = Ole 2.0 Container Sample Outline>> oleutest.reg
+@echo HKEY_CLASSES_ROOT\CLSID\{00000401-0000-0000-C000-000000000046}\ProgID = OLE2CntrOutl>> oleutest.reg
+@rem
+@rem
+@rem OLE 2.0 OBJECT HANDLER/EXE INFORMATION
+@rem
+@rem
+@echo HKEY_CLASSES_ROOT\CLSID\{00000401-0000-0000-C000-000000000046}\InprocHandler32 = ole32.dll>> oleutest.reg
+@echo HKEY_CLASSES_ROOT\CLSID\{00000401-0000-0000-C000-000000000046}\LocalServer32 = %SystemRoot%\dump\cntroutl.exe>> oleutest.reg
+@rem
+@rem
+@rem REGISTRATION ENTRY FOR ISVROTL.EXE
+@rem
+@rem
+@rem PROGID ROOT-KEY INFORMATION
+@rem
+@echo HKEY_CLASSES_ROOT\OLE2ISvrOtl = Ole 2.0 In-Place Server Outline>> oleutest.reg
+@echo HKEY_CLASSES_ROOT\OLE2ISvrOtl\CLSID = {00000402-0000-0000-C000-000000000046}>> oleutest.reg
+@rem
+@rem ISVROTL is marked as insertable so it appears in the InsertObject dialog
+@rem
+@echo HKEY_CLASSES_ROOT\OLE2ISvrOtl\Insertable>> oleutest.reg
+@rem
+@rem
+@rem OLE 1.0 COMPATIBILITY INFORMATION
+@rem
+@rem
+@echo HKEY_CLASSES_ROOT\OLE2ISvrOtl\protocol\StdFileEditing\verb\1 = ^&Open>> oleutest.reg
+@echo HKEY_CLASSES_ROOT\OLE2ISvrOtl\protocol\StdFileEditing\verb\0 = ^&Edit>> oleutest.reg
+@echo HKEY_CLASSES_ROOT\OLE2ISvrOtl\protocol\StdFileEditing\server = isvrotl.exe>> oleutest.reg
+@rem
+@rem
+@rem WINDOWS 3.1 SHELL INFORMATION
+@rem
+@rem
+@echo HKEY_CLASSES_ROOT\OLE2ISvrOtl\Shell\Print\Command = isvrotl.exe %%1%>> oleutest.reg
+@echo HKEY_CLASSES_ROOT\OLE2ISvrOtl\Shell\Open\Command = isvrotl.exe %%1%>> oleutest.reg
+@rem
+@rem File extension must have ProgID as its value
+@rem HKEY_CLASSES_ROOT\.oln = OLE2ISvrOtl
+@rem
+@rem
+@rem OLE 2.0 CLSID ENTRY INFORMATION
+@rem
+@rem
+@echo HKEY_CLASSES_ROOT\CLSID\{00000402-0000-0000-C000-000000000046} = Ole 2.0 In-Place Server Outline>> oleutest.reg
+@echo HKEY_CLASSES_ROOT\CLSID\{00000402-0000-0000-C000-000000000046}\ProgID = OLE2ISvrOtl>> oleutest.reg
+@rem
+@rem
+@rem OLE 2.0 OBJECT HANDLER/EXE INFORMATION
+@rem
+@rem
+@echo HKEY_CLASSES_ROOT\CLSID\{00000402-0000-0000-C000-000000000046}\ProgID = OLE2ISvrOtl>> oleutest.reg
+@echo HKEY_CLASSES_ROOT\CLSID\{00000402-0000-0000-C000-000000000046}\InprocHandler32 = ole32.dll>> oleutest.reg
+@echo HKEY_CLASSES_ROOT\CLSID\{00000402-0000-0000-C000-000000000046}\LocalServer32 = %SystemRoot%\dump\isvrotl.exe>> oleutest.reg
+@rem
+@rem
+@rem VERB MENU SUPPORT
+@rem
+@rem
+@rem Verb 1: "Open", MF_UNCHECKED | MF_ENABLED, OLEVERBATTRIB_ONCONTAINERMENU
+@rem
+@echo HKEY_CLASSES_ROOT\CLSID\{00000402-0000-0000-C000-000000000046}\Verb\1 = ^&Open,0,2 >> oleutest.reg
+@rem
+@rem Verb 0: "Edit", MF_UNCHECKED | MF_ENABLED, OLEVERBATTRIB_ONCONTAINERMENU
+@echo HKEY_CLASSES_ROOT\CLSID\{00000402-0000-0000-C000-000000000046}\Verb\0 = ^&Edit,0,2 >> oleutest.reg
+@rem
+@rem This class should appear in Insert New Object list
+@rem
+@echo HKEY_CLASSES_ROOT\CLSID\{00000402-0000-0000-C000-000000000046}\Insertable>> oleutest.reg
+@rem
+@rem
+@rem USER TYPE NAMES
+@rem
+@rem ShortName (NOTE: recommended max 15 chars) = In-Place Outline
+@echo HKEY_CLASSES_ROOT\CLSID\{00000402-0000-0000-C000-000000000046}\AuxUserType\2 = Outline>> oleutest.reg
+@rem
+@rem AppName = Ole 2.0 In-Place Outline Server
+@rem
+@echo HKEY_CLASSES_ROOT\CLSID\{00000402-0000-0000-C000-000000000046}\AuxUserType\3 = Ole 2.0 In-Place Outline Server>> oleutest.reg
+@rem
+@rem
+@rem ICON DEFINITION
+@rem
+@rem
+@echo HKEY_CLASSES_ROOT\CLSID\{00000402-0000-0000-C000-000000000046}\DefaultIcon = isvrotl.exe,0 >> oleutest.reg
+@rem
+@rem
+@rem DATA FORMATS SUPPORTED
+@rem
+@rem
+@rem Default File Format = CF_OUTLINE
+@rem
+@echo HKEY_CLASSES_ROOT\CLSID\{00000402-0000-0000-C000-000000000046}\DataFormats\DefaultFile = Outline>> oleutest.reg
+@rem
+@rem Format 0 = CF_OUTLINE, DVASPECT_CONTENT, TYMED_HGLOBAL, DATADIR_BOTH
+@rem
+@echo HKEY_CLASSES_ROOT\CLSID\{00000402-0000-0000-C000-000000000046}\DataFormats\GetSet\0 = Outline,1,1,3 >> oleutest.reg
+@rem
+@rem Format 1 = CF_TEXT, DVASPECT_CONTENT, TYMED_HGLOBAL, DATADIR_BOTH
+@rem
+@echo HKEY_CLASSES_ROOT\CLSID\{00000402-0000-0000-C000-000000000046}\DataFormats\GetSet\1 = 1,1,1,3 >> oleutest.reg
+@rem
+@rem Format 2 = CF_METAFILEPICT, DVASPECT_CONTENT, TYMED_MFPICT, DATADIR_GET
+@echo HKEY_CLASSES_ROOT\CLSID\{00000402-0000-0000-C000-000000000046}\DataFormats\GetSet\2 = 3,1,32,1 >> oleutest.reg
+@rem
+@rem Format 3 = CF_METAFILEPICT, DVASPECT_ICON, TYMED_MFPICT, DATADIR_GET
+@echo HKEY_CLASSES_ROOT\CLSID\{00000402-0000-0000-C000-000000000046}\DataFormats\GetSet\3 = 3,4,32,1 >> oleutest.reg
+@rem
+@rem
+@rem MISC STATUS SUPPORTED
+@rem
+@rem
+@rem DVASPECT_CONTENT = OLEMISC_RENDERINGISDEVICEINDEPENDENT
+@rem
+@echo HKEY_CLASSES_ROOT\CLSID\{00000402-0000-0000-C000-000000000046}\MiscStatus = 512>> oleutest.reg
+@rem
+@rem DVASPECT_CONTENT =
+@rem OLEMISC_INSIDEOUT | OLEMISC_ACTIVATEWHENVISIBLE |
+@rem OLEMISC_RENDERINGISDEVICEINDEPENDENT
+@rem
+@echo HKEY_CLASSES_ROOT\CLSID\{00000402-0000-0000-C000-000000000046}\MiscStatus\1 = 896>> oleutest.reg
+@rem
+@rem
+@rem CONVERSION FORMATS SUPPORTED
+@rem
+@rem
+@rem Readable Main formats: CF_OUTLINE, CF_TEXT
+@rem
+@echo HKEY_CLASSES_ROOT\CLSID\{00000402-0000-0000-C000-000000000046}\Conversion\Readable\Main = Outline>> oleutest.reg
+@echo HKEY_CLASSES_ROOT\CLSID\{00000402-0000-0000-C000-000000000046}\Conversion\Readwritable\Main = Outline>> oleutest.reg
+@rem
+@rem
+@rem REGISTRATION ENTRY FOR ICNTROTL.EXE
+@rem
+@rem
+@rem ENTRIES FOR Ole 2.0 In-Place Container Outline
+@rem
+@rem
+@rem PROGID ROOT-KEY INFORMATION
+@rem
+@rem NOTE: ICNTROTL must have a ProgID assigned for the Windows 3.1 Shell
+@rem file associations and Packager to function correctly.
+@rem
+@echo HKEY_CLASSES_ROOT\OLE2ICtrOtl = Ole 2.0 In-Place Container Outline>> oleutest.reg
+@echo HKEY_CLASSES_ROOT\OLE2ICtrOtl\Clsid = {00000403-0000-0000-C000-000000000046}>> oleutest.reg
+@rem
+@rem
+@rem WINDOWS 3.1 SHELL INFORMATION
+@rem
+@rem
+@echo HKEY_CLASSES_ROOT\OLE2ICtrOtl\Shell\Print\Command = icntrotl.exe %%1%>> oleutest.reg
+@echo HKEY_CLASSES_ROOT\OLE2ICtrOtl\Shell\Open\Command = icntrotl.exe %%1%>> oleutest.reg
+@rem
+@rem File extension must have ProgID as its value
+@echo HKEY_CLASSES_ROOT\.olc = OLE2ICtrOtl>> oleutest.reg
+@rem
+@rem
+@rem OLE 2.0 CLSID ENTRY INFORMATION
+@rem
+@rem
+@echo HKEY_CLASSES_ROOT\CLSID\{00000403-0000-0000-C000-000000000046} = Ole 2.0 In-Place Container Outline>> oleutest.reg
+@echo HKEY_CLASSES_ROOT\CLSID\{00000403-0000-0000-C000-000000000046}\ProgID = OLE2ICtrOtl>> oleutest.reg
+@rem
+@rem
+@rem OLE 2.0 OBJECT HANDLER/EXE INFORMATION
+@rem
+@rem
+@echo HKEY_CLASSES_ROOT\CLSID\{00000403-0000-0000-C000-000000000046}\InprocHandler32 = ole32.dll>> oleutest.reg
+@echo HKEY_CLASSES_ROOT\CLSID\{00000403-0000-0000-C000-000000000046}\LocalServer32 = %SystemRoot%\dump\icntrotl.exe>> oleutest.reg
diff --git a/private/oleutest/perf/dirs b/private/oleutest/perf/dirs
new file mode 100644
index 000000000..c478c620d
--- /dev/null
+++ b/private/oleutest/perf/dirs
@@ -0,0 +1,41 @@
+!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:
+
+ Dean Edwards (DeanE) 11-Jan-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= \
+ idl \
+ perfuuid \
+ proxy \
+ perfsrv \
+ perfcli \
+
+#
+# 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=
+
diff --git a/private/oleutest/perf/idl/iperf.idl b/private/oleutest/perf/idl/iperf.idl
new file mode 100644
index 000000000..bb6d0affa
--- /dev/null
+++ b/private/oleutest/perf/idl/iperf.idl
@@ -0,0 +1,32 @@
+//[ IPerf_itf
+//+-------------------------------------------------------------------
+//
+// Interface: IPerf (ib)
+//
+// Purpose: Interface for manipulating performance
+//
+// History: 5-Oct-93 AlexMit Created
+//
+// Notes:
+//
+//--------------------------------------------------------------------
+
+[ object,
+ uuid(91062994-A3E7-101A-B4AC-08002B30612C),
+ pointer_default(unique) ]
+
+interface IPerf : IUnknown
+{
+ import "unknwn.idl";
+
+ HRESULT NullCall();
+
+ HRESULT HResultCall();
+
+ HRESULT GetAnotherObject( [out] IPerf **another );
+
+ HRESULT PassMoniker( IMoniker * );
+}
+
+//]
+ \ No newline at end of file
diff --git a/private/oleutest/perf/idl/makefile b/private/oleutest/perf/idl/makefile
new file mode 100644
index 000000000..510cce95d
--- /dev/null
+++ b/private/oleutest/perf/idl/makefile
@@ -0,0 +1,9 @@
+############################################################################
+#
+# Copyright (C) 1992, Microsoft Corporation.
+#
+# All rights reserved.
+#
+############################################################################
+
+!include $(NTMAKEENV)\makefile.def
diff --git a/private/oleutest/perf/idl/makefile.inc b/private/oleutest/perf/idl/makefile.inc
new file mode 100644
index 000000000..535a56369
--- /dev/null
+++ b/private/oleutest/perf/idl/makefile.inc
@@ -0,0 +1,32 @@
+CPP_CMD=cl
+
+!if $(386)
+CPP_CMD=cl386
+!endif
+
+!if $(ALPHA)
+CPP_CMD=$(ALPHA_CC)
+!endif
+
+iperf.h: iperf.idl
+ midl iperf.idl \
+ -Zp8 \
+ -I$(INCLUDES) \
+ -ms_ext \
+ -c_ext \
+ -out ..\proxy \
+ -header ..\idl\iperf.h \
+ -iid ..\perfuuid\iperf_i.c \
+ $(C_DEFINES) \
+ -cpp_cmd $(CPP_CMD) \
+ -cpp_opt "-nologo -DMIDL_PASS $(C_DEFINES) -I$(INCLUDES) -E -Tc"
+
+#
+# This target compiles all .idl files into their corresponding _?.c?? and
+# .h components
+#
+allidl: iperf.h
+
+
+clean:
+ erase iperf.h >NUL 2>NUL
diff --git a/private/oleutest/perf/idl/perf.reg b/private/oleutest/perf/idl/perf.reg
new file mode 100644
index 000000000..2a09ca044
--- /dev/null
+++ b/private/oleutest/perf/idl/perf.reg
@@ -0,0 +1,22 @@
+
+; registry entries for IPerf interface. these map the interfaces
+; to the proxy/stub code in iperf.dll
+
+
+\Registry\MACHINE\SOFTWARE\Classes\Interface\{91062994-A3E7-101A-B4AC-08002B30612C}
+ = IPerf
+\Registry\MACHINE\SOFTWARE\Classes\Interface\{91062994-A3E7-101A-B4AC-08002B30612C}\ProxyStubClsid32
+ = {91062994-A3E7-101A-B4AC-08002B30612C}
+
+\Registry\MACHINE\SOFTWARE\Classes\CLSID\{91062994-A3E7-101A-B4AC-08002B30612C}
+ = CPrxyIPerf
+\Registry\MACHINE\SOFTWARE\Classes\CLSID\{91062994-A3E7-101A-B4AC-08002B30612C}\InprocServer32
+ = iperf.dll
+
+\Registry\MACHINE\SOFTWARE\Classes\CLSID\{1AFDBB80-AA32-101A-B4AD-08002B30612C}
+ = CPerfClassFactory
+\Registry\MACHINE\SOFTWARE\Classes\CLSID\{1AFDBB80-AA32-101A-B4AD-08002B30612C}\LocalServer32
+ = perfsrv.exe
+
+
+ \ No newline at end of file
diff --git a/private/oleutest/perf/idl/sources b/private/oleutest/perf/idl/sources
new file mode 100644
index 000000000..5dff48ad5
--- /dev/null
+++ b/private/oleutest/perf/idl/sources
@@ -0,0 +1,66 @@
+!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:
+
+ Dean Edwards (DeanE) 11-Jan-1993
+
+!ENDIF
+
+MAJORCOMP = comutest
+MINORCOMP = channelperf
+
+#
+# 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= idl
+
+#
+# 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= LIBRARY
+
+INCLUDES= $(BASEDIR)\public\sdk\inc;$(BASEDIR)\private\types\compobj
+
+C_DEFINES= $(C_DEFINES)
+
+BLDCRT= 1
+
+SOURCES=
+
+UMTYPE= windows
+UMAPPL=
+UMTEST=
+UMLIBS=
+
+USE_LIBCMT=
+
+NTTARGETFILE0= allidl
+
+PRECOMPILED_INCLUDE=
+
diff --git a/private/oleutest/perf/perfcli/makefile b/private/oleutest/perf/perfcli/makefile
new file mode 100644
index 000000000..8991c0d2e
--- /dev/null
+++ b/private/oleutest/perf/perfcli/makefile
@@ -0,0 +1,20 @@
+############################################################################
+#
+# Copyright (C) 1992, Microsoft Corporation.
+#
+# All rights reserved.
+#
+############################################################################
+
+!ifdef NTMAKEENV
+
+!include $(NTMAKEENV)\makefile.def
+
+!else # NTMAKEENV
+
+default: all
+
+!include $(CAIROLE)\com\makefile
+!include $(DEPENDFILE)
+
+!endif # NTMAKEENV
diff --git a/private/oleutest/perf/perfcli/perfcli.cxx b/private/oleutest/perf/perfcli/perfcli.cxx
new file mode 100644
index 000000000..0df59c724
--- /dev/null
+++ b/private/oleutest/perf/perfcli/perfcli.cxx
@@ -0,0 +1,549 @@
+//+-------------------------------------------------------------
+//
+// File: perfcli.cxx
+//
+// Contents: First attempt at getting perfcliing to work
+//
+// This is the client side
+//
+//
+//---------------------------------------------------------------
+
+#include <windows.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <io.h>
+
+#include <ole2.h>
+#include "iperf.h"
+#include "..\perfsrv\perfsrv.hxx"
+#include <memalloc.h>
+
+#pragma hdrstop
+
+#define TEST_FILE L"\\tmp\\test"
+
+void QueryMsg( void );
+
+// These are Cairo symbols. Just define them here so I don't have to rip
+// out or conditionally compile all references to them.
+#define COINIT_MULTITHREADED 0
+#define COINIT_SINGLETHREADED 1
+
+DWORD thread_mode = COINIT_SINGLETHREADED;
+int num_objects = 1;
+int num_iterations = 1000;
+HANDLE helper_wait;
+HANDLE main_wait;
+
+ /*************************************************************************/
+int DoTest()
+{
+ IPerf **perf;
+ HRESULT result;
+ DWORD time_first;
+ DWORD waste;
+ int i;
+ int j;
+ BOOL success;
+ LARGE_INTEGER frequency;
+ LARGE_INTEGER count_first;
+ LARGE_INTEGER count_last;
+ LARGE_INTEGER dummy;
+
+ // Allocate memory to hold the object and interface pointers.
+ perf = (IPerf **) malloc( sizeof(void *) * num_objects );
+ if (perf == NULL)
+ {
+ printf( "Could not get memory.\n" );
+ return 1;
+ }
+
+ // Get a test object.
+ result = CoCreateInstance( CLSID_IPerf, NULL, CLSCTX_LOCAL_SERVER, IID_IPerf,
+ (void **) &perf[0] );
+ if (!SUCCEEDED(result))
+ {
+ printf( "Could not create instance of performance server: %x\n", result );
+ return 1;
+ }
+
+ // Create the required number of objects.
+ for (i = 1; i < num_objects; i++)
+ {
+ result = perf[0]->GetAnotherObject( &perf[i] );
+ if (!SUCCEEDED(result))
+ {
+ printf( "Could not get enough objects: 0x%x\n", result );
+ return 1;
+ }
+ perf[i]->NullCall();
+ }
+
+ // Prompt to start when the user is ready.
+ // printf( "Ready? " );
+ // gets( s );
+
+ // Compute the time spent just looping.
+ waste = GetTickCount();
+ for (i = 0; i < num_iterations; i++)
+ ;
+ waste = GetTickCount() - waste;
+
+ // Repeatedly call the first object to time it.
+ time_first = GetTickCount();
+ for (i = 0; i < num_iterations; i++)
+ perf[0]->NullCall();
+ time_first = GetTickCount() - time_first - waste;
+
+ // Print the results.
+ printf( "%d uS/Call\n", time_first*1000/num_iterations );
+
+/*
+ // Measure the same thing using the performance counter.
+ success = QueryPerformanceFrequency( &frequency );
+ if (!success)
+ {
+ printf( "Could not query performance frequency.\n" );
+ goto free;
+ }
+ success = QueryPerformanceCounter( &count_first );
+ if (!success)
+ {
+ printf( "Could not query performance counter.\n" );
+ goto free;
+ }
+ perf[0]->NullCall();
+ success = QueryPerformanceCounter( &count_last );
+ if (!success)
+ {
+ printf( "Could not query performance counter.\n" );
+ goto free;
+ }
+ if (count_last.HighPart != count_first.HighPart ||
+ frequency.HighPart != 0)
+ printf( "\n\n***** Overflow *****\n\n\n" );
+ count_last.LowPart = (count_last.LowPart - count_first.LowPart) * 1000000 /
+ frequency.LowPart;
+ printf( "\nFrequency %d\n", frequency.LowPart );
+ printf( "%d uS/Call\n", count_last.LowPart );
+
+ // How long does it take to query the performance counter?
+ success = QueryPerformanceCounter( &count_first );
+ if (!success)
+ {
+ printf( "Could not query performance counter.\n" );
+ goto free;
+ }
+ for (i = 0; i < num_iterations; i++)
+ QueryPerformanceCounter( &dummy );
+ success = QueryPerformanceCounter( &count_last );
+ if (!success)
+ {
+ printf( "Could not query performance counter.\n" );
+ goto free;
+ }
+ if (count_last.HighPart != count_first.HighPart ||
+ frequency.HighPart != 0)
+ printf( "\n\n***** Overflow *****\n\n\n" );
+ count_last.LowPart = (count_last.LowPart - count_first.LowPart) /
+ num_iterations * 1000000 / frequency.LowPart;
+ printf( "%d uS/Query\n", count_last.LowPart );
+*/
+
+ // Prompt to let the user peruse the results.
+ // printf( "Done? " );
+ // gets( s );
+
+ // Free the objects.
+free:
+ for (i = 0; i < num_objects; i++)
+ perf[i]->Release();
+ return 0;
+}
+
+ /*************************************************************************/
+void EventTest()
+{
+ DWORD time_first;
+ DWORD waste;
+ int i;
+ HANDLE helper;
+
+ // Measure how long it takes to loop.
+ waste = GetTickCount();
+ for (i = 0; i < num_iterations; i++)
+ ;
+ waste = GetTickCount() - waste;
+
+ // Measure how long it takes to get an event
+ time_first = GetTickCount();
+ for (i = 0; i < num_iterations; i++)
+ {
+ helper = CreateEvent( NULL, FALSE, FALSE, NULL );
+ if (helper == NULL)
+ {
+ printf( "Could not create event %d.\n", i );
+ return;
+ }
+ CloseHandle( helper );
+ }
+ time_first = GetTickCount() - time_first - waste;
+ printf( "%d uS/CreateEvent\n", time_first*1000/num_iterations );
+
+ // Don't bother cleaning up.
+}
+
+ /*************************************************************************/
+/* Parse the arguments. */
+BOOL parse( int argc, char *argv[] )
+{
+ int i;
+ int len;
+ TCHAR buffer[80];
+
+#if 0
+ // Look up the thread mode from the win.ini file.
+ len = GetProfileString( L"My Section", L"ThreadMode", L"MultiThreaded", buffer,
+ sizeof(buffer) );
+ if (lstrcmp(buffer, L"SingleThreaded") == 0)
+ thread_mode = COINIT_SINGLETHREADED;
+ else if (lstrcmp(buffer, L"MultiThreaded") == 0)
+ thread_mode = COINIT_MULTITHREADED;
+#endif
+
+ // Parse each item, skip the command name
+ for (i = 1; i < argc; i++)
+ {
+ if (strcmp( argv[i], "Single" ) == 0)
+ thread_mode = COINIT_SINGLETHREADED;
+ else if (strcmp( argv[i], "Multi" ) == 0)
+ thread_mode = COINIT_MULTITHREADED;
+ else if (strcmp( argv[i], "-o" ) == 0)
+ {
+ if (argv[++i] == NULL)
+ {
+ printf( "You must include an object count after the -o option.\n" );
+ return FALSE;
+ }
+ sscanf( argv[i], "%d", &num_objects );
+ }
+ else if (strcmp( argv[i], "-i" ) == 0)
+ {
+ if (argv[++i] == NULL)
+ {
+ printf( "You must include an object count after the -i option.\n" );
+ return FALSE;
+ }
+ sscanf( argv[i], "%d", &num_iterations );
+ }
+ else
+ {
+ printf( "You don't know what you are doing!\n" );
+ }
+ }
+
+ return TRUE;
+}
+
+ /*************************************************************************/
+void MarshalTest()
+{
+ HANDLE file;
+ HRESULT result;
+ IMoniker *moniker;
+ IBindCtx *bindctx;
+ WCHAR *wide_name;
+ unsigned char *name;
+ int i;
+ IPerf *perf;
+
+ // Initialize OLE.
+ result = OleInitialize(NULL);
+ if (FAILED(result))
+ {
+ printf( "Could not initialize OLE: 0x%x\n", result );
+ return;
+ }
+
+ // Create file.
+ file = CreateFile( TEST_FILE, 0, 0, NULL, CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL, NULL );
+ if (file == INVALID_HANDLE_VALUE)
+ {
+ printf( "Could not create file." );
+ return;
+ }
+
+ // Create file moniker.
+ result = CreateFileMoniker( TEST_FILE, &moniker );
+ if (FAILED(result))
+ {
+ printf( "Could not create file moniker: 0x%x\n", result );
+ return;
+ }
+
+ // Get a bind context.
+ result = CreateBindCtx( NULL, &bindctx );
+ if (FAILED(result))
+ {
+ printf( "Could not create bind context: 0x%x\n", result );
+ return;
+ }
+
+ // Display name.
+ result = moniker->GetDisplayName( bindctx, NULL, &wide_name );
+ if (FAILED(result))
+ {
+ printf( "Could not get display name: 0x%x\n", result );
+ return;
+ }
+
+ // Convert the string to ascii and print it.
+ name = (unsigned char *) wide_name;
+ i = 0;
+ while (wide_name[i] != 0)
+ name[i] = wide_name[i++];
+ name[i] = 0;
+ printf( "The moniker is called <%s>\n", name );
+
+ // Free string.
+ CoTaskMemFree( wide_name );
+
+ // Get a test object.
+ result = CoCreateInstance( CLSID_IPerf, NULL, CLSCTX_LOCAL_SERVER, IID_IPerf,
+ (void **) &perf );
+ if (!SUCCEEDED(result))
+ {
+ printf( "Could not create instance of performance server: %x\n", result );
+ return;
+ }
+
+ // Pass moniker to server.
+ result = perf->PassMoniker( moniker );
+ if (FAILED(result))
+ {
+ printf( "Could not give moniker to server: 0x%x\n", result );
+ return;
+ }
+
+ // Release everything.
+ CloseHandle( file );
+ moniker->Release();
+ bindctx->Release();
+ perf->Release();
+ OleUninitialize();
+}
+
+
+//+--------------------------------------------------------------
+// Function: Main
+//
+// Synopsis: Executes the BasicBnd test
+//
+// Effects: None
+//
+//
+// Returns: Exits with exit code 0 if success, 1 otherwise
+//
+// History: 05-Mar-92 Sarahj Created
+//
+//---------------------------------------------------------------
+
+int _cdecl main(int argc, char *argv[])
+{
+ BOOL initialized = FALSE;
+ HRESULT hresult = S_OK;
+ BOOL fFailed = FALSE;
+
+ // Parse the command line arguments.
+ if (!parse( argc, argv ))
+ return 0;
+
+ // Print the process id.
+ printf( "Hi, I am %x.\n", GetCurrentProcessId() );
+
+ // Time event creation.
+// EventTest();
+// return 1;
+
+ // Pass around monikers.
+// MarshalTest();
+
+ // Measure message queue APIs.
+// QueryMsg();
+
+
+ // Print the thread mode.
+ if (thread_mode == COINIT_SINGLETHREADED)
+ {
+ printf( "Measuring performance for the single threaded mode.\n" );
+ }
+ else
+ {
+ printf( "Measuring performance for the multithreaded mode.\n" );
+ }
+
+ // must be called before any other OLE API
+ hresult = OleInitialize(NULL);
+
+ if (FAILED(hresult))
+ {
+ printf("OleInitialize Failed with %lx\n", hresult);
+ goto exit_main;
+ }
+ initialized = TRUE;
+
+ if (fFailed = DoTest())
+ goto exit_main;
+
+/*
+ // Uninitialize and rerun in the other thread mode.
+ OleUninitialize();
+ if (thread_mode == COINIT_SINGLETHREADED)
+ thread_mode = COINIT_MULTITHREADED;
+ else
+ thread_mode = COINIT_SINGLETHREADED;
+
+ // Print the thread mode.
+ if (thread_mode == COINIT_SINGLETHREADED)
+ printf( "Measuring performance for the single threaded mode.\n" );
+ else
+ printf( "Measuring performance for the multithreaded mode.\n" );
+
+ // must be called before any other OLE API
+ hresult = OleInitialize(NULL);
+
+ if (FAILED(hresult))
+ {
+ printf("OleInitialize Failed with %lx\n", hresult);
+ goto exit_main;
+ }
+
+ if (fFailed = DoTest())
+ goto exit_main;
+*/
+
+exit_main:
+
+ if (initialized)
+ OleUninitialize();
+
+ if (!fFailed)
+ {
+ printf("\nCairole: PASSED\n");
+ }
+ else
+ {
+ printf("\nCairole: FAILED\n");
+ }
+
+ return fFailed;
+}
+
+ /*************************************************************************/
+DWORD _stdcall MsgHelper( void *param )
+{
+ int i;
+
+ // Alternately signal and wait on an event. Do it one time too many
+ // because the main thread calls once to let us get set up.
+ for (i = 0; i < num_iterations+1; i++)
+ {
+ WaitForSingleObject( helper_wait, INFINITE );
+ SetEvent( main_wait );
+ }
+
+#define must_return_a_value return 0
+ must_return_a_value;
+}
+
+ /*************************************************************************/
+void QueryMsg()
+{
+ DWORD time_first;
+ DWORD waste;
+ int i;
+ HANDLE helper;
+ DWORD thread_id;
+
+ // Create an event.
+ helper_wait = CreateEvent( NULL, FALSE, FALSE, NULL );
+ if (helper_wait == NULL)
+ {
+ printf( "Could not create event.\n" );
+ return;
+ }
+ main_wait = CreateEvent( NULL, FALSE, FALSE, NULL );
+ if (main_wait == NULL)
+ {
+ printf( "Could not create event.\n" );
+ return;
+ }
+
+ // Measure how long it takes to loop.
+ waste = GetTickCount();
+ for (i = 0; i < num_iterations; i++)
+ ;
+ waste = GetTickCount() - waste;
+
+ // Measure how long it takes to query the message queue.
+ time_first = GetTickCount();
+ for (i = 0; i < num_iterations; i++)
+ GetQueueStatus( QS_ALLINPUT );
+ time_first = GetTickCount() - time_first - waste;
+ printf( "%d uS/GetQueueStatus\n", time_first*1000/num_iterations );
+
+ // Start a thread to wake up this one.
+ helper = CreateThread( NULL, 0, MsgHelper, 0, 0,
+ &thread_id );
+ if (helper == NULL)
+ {
+ printf( "Could not create helper thread.\n" );
+ return;
+ }
+
+ // Call MsgWaitForMultipleObjects once to let the thread get started.
+ SetEvent( helper_wait );
+ MsgWaitForMultipleObjects( 1, &main_wait, FALSE,
+ INFINITE, QS_ALLINPUT );
+
+ // Measure how long it takes to call MsgWaitForMultipleObjects.
+ time_first = GetTickCount();
+ for (i = 0; i < num_iterations; i++)
+ {
+ SetEvent( helper_wait );
+ MsgWaitForMultipleObjects( 1, &main_wait, FALSE,
+ INFINITE, QS_ALLINPUT );
+ }
+ time_first = GetTickCount() - time_first - waste;
+ printf( "%d uS/MsgWaitForMultipleObjects\n", time_first*1000/num_iterations );
+
+ // Start a thread to wake up this one.
+ helper = CreateThread( NULL, 0, MsgHelper, 0, 0,
+ &thread_id );
+ if (helper == NULL)
+ {
+ printf( "Could not create helper thread.\n" );
+ return;
+ }
+
+ // Let the thread get started.
+ SetEvent( helper_wait );
+ WaitForSingleObject( main_wait, INFINITE );
+
+ // Measure how long it takes to switch threads just using events.
+ time_first = GetTickCount();
+ for (i = 0; i < num_iterations; i++)
+ {
+ SetEvent( helper_wait );
+ WaitForSingleObject( main_wait, INFINITE );
+ }
+ time_first = GetTickCount() - time_first - waste;
+ printf( "%d uS/MsgWaitForMultipleObjects\n", time_first*1000/num_iterations );
+
+ // Don't bother cleaning up.
+}
+
diff --git a/private/oleutest/perf/perfcli/sources b/private/oleutest/perf/perfcli/sources
new file mode 100644
index 000000000..1a3157b1e
--- /dev/null
+++ b/private/oleutest/perf/perfcli/sources
@@ -0,0 +1,62 @@
+
+MAJORCOMP = cairole
+MINORCOMP = com
+
+#
+# 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= perfcli
+
+#
+# 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= ..\idl;$(BASEDIR)\private\cinc
+
+C_DEFINES= \
+ $(C_DEFINES) \
+ -DFLAT \
+ -DWIN32=100 \
+ -D_NT1X_=100 \
+ -DUNICODE \
+ -D_UNICODE \
+ -DNOEXCEPTIONS \
+ -DCAIROLE_DOWNLEVEL
+
+BLDCRT= 1
+
+SOURCES= \
+ perfcli.cxx
+
+
+UMTYPE= console
+UMENTRY=
+UMAPPL=
+UMTEST=
+UMLIBS= \
+ ..\perfuuid\obj\*\perfuuid.lib \
+ $(BASEDIR)\public\sdk\lib\*\uuid.lib \
+ $(BASEDIR)\public\sdk\lib\*\ole32.lib \
+ $(BASEDIR)\public\sdk\lib\*\rpcndr.lib \
+ $(BASEDIR)\public\sdk\lib\*\rpcrt4.lib \
+ $(BASEDIR)\public\sdk\lib\*\rpcns4.lib \
+ $(BASEDIR)\public\sdk\lib\*\mpr.lib \
+ $(BASEDIR)\public\sdk\lib\*\netapi32.lib \
+ $(BASEDIR)\public\sdk\lib\*\kernel32.lib \
+ $(BASEDIR)\public\sdk\lib\*\user32.lib \
+ $(BASEDIR)\public\sdk\lib\*\advapi32.lib \
+ $(BASEDIR)\public\sdk\lib\*\libc.lib
+
diff --git a/private/oleutest/perf/perfsrv/makefile b/private/oleutest/perf/perfsrv/makefile
new file mode 100644
index 000000000..8991c0d2e
--- /dev/null
+++ b/private/oleutest/perf/perfsrv/makefile
@@ -0,0 +1,20 @@
+############################################################################
+#
+# Copyright (C) 1992, Microsoft Corporation.
+#
+# All rights reserved.
+#
+############################################################################
+
+!ifdef NTMAKEENV
+
+!include $(NTMAKEENV)\makefile.def
+
+!else # NTMAKEENV
+
+default: all
+
+!include $(CAIROLE)\com\makefile
+!include $(DEPENDFILE)
+
+!endif # NTMAKEENV
diff --git a/private/oleutest/perf/perfsrv/perfsrv.cxx b/private/oleutest/perf/perfsrv/perfsrv.cxx
new file mode 100644
index 000000000..5dfc9e188
--- /dev/null
+++ b/private/oleutest/perf/perfsrv/perfsrv.cxx
@@ -0,0 +1,475 @@
+//+-------------------------------------------------------------------
+//
+// File: perfsrv.cxx
+//
+// Contents: This file contins the DLL entry points
+// LibMain
+// DllGetClassObject (Bindings key func)
+// CPerfCF (class factory)
+// CPerf (actual class implementation)
+//
+// Classes: CPerfCF, CPerf
+//
+//
+// History: 30-Nov-92 SarahJ Created
+//
+//---------------------------------------------------------------------
+
+// Turn off ole Cairol IUnknown
+#define __IUNKNOWN_TMP__
+
+
+#include <windows.h>
+#include <ole2.h>
+#include "perfsrv.hxx"
+extern "C" {
+#include <stdio.h>
+#include <stdarg.h>
+#include "wterm.h"
+}
+
+// These are Cairo symbols. Just define them here so I don't have to rip
+// out or conditionally compile all references to them.
+#define COINIT_MULTITHREADED 0
+#define COINIT_SINGLETHREADED 1
+
+#define IDM_DEBUG 0x100
+
+// Count of objects we have instantiated. When we detect 0, we quit.
+ULONG g_cUsage = 0;
+
+const TCHAR *szAppName = L"Performance Server";
+
+HWND g_hMain;
+DWORD thread_mode = COINIT_SINGLETHREADED;
+DWORD MainThread;
+DWORD junk;
+
+
+void Display(TCHAR *pszFmt, ...)
+{
+ va_list marker;
+ TCHAR szBuffer[256];
+
+ va_start(marker, pszFmt);
+
+ int iLen = vswprintf(szBuffer, pszFmt, marker);
+
+ va_end(marker);
+
+ // Display the message on terminal window
+ SendMessage(g_hMain, WM_PRINT_LINE, iLen, (LONG) szBuffer);
+}
+
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: ProcessMenu
+//
+// Synopsis: Gets called when a WM_COMMAND message received.
+//
+// Arguments: [hWindow] - handle for the window
+// [uiMessage] - message id
+// [wParam] - word parameter
+// [lParam] - long parameter
+//
+// Returns: DefWindowProc result
+//
+// History: 06-Aug-92 Ricksa Created
+//
+//--------------------------------------------------------------------------
+long ProcessMenu(HWND hWindow, UINT uiMessage, WPARAM wParam, LPARAM lParam,
+ void *)
+{
+ if ((uiMessage == WM_SYSCOMMAND) && (wParam == IDM_DEBUG))
+ {
+ // Request for a debug breakpoint!
+ DebugBreak();
+ }
+
+
+ return (DefWindowProc(hWindow, uiMessage, wParam, lParam));
+}
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: ProcessChar
+//
+// Synopsis: Gets called when a WM_CHAR message received.
+//
+// Arguments: [hWindow] - handle for the window
+// [uiMessage] - message id
+// [wParam] - word parameter
+// [lParam] - long parameter
+//
+// Returns: DefWindowProc result
+//
+// History: 06-Aug-92 Ricksa Created
+//
+//--------------------------------------------------------------------------
+long ProcessChar(HWND hWindow, UINT uiMessage, WPARAM wParam, LPARAM lParam,
+ void *)
+{
+ return (DefWindowProc(hWindow, uiMessage, wParam, lParam));
+}
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: ProcessClose
+//
+// Synopsis: Gets called when a NC_DESTROY message received.
+//
+// Arguments: [hWindow] - handle for the window
+// [uiMessage] - message id
+// [wParam] - word parameter
+// [lParam] - long parameter
+//
+// Returns: DefWindowProc result
+//
+// History: 06-Aug-92 Ricksa Created
+//
+//--------------------------------------------------------------------------
+long ProcessClose(
+ HWND hWindow,
+ UINT uiMessage,
+ WPARAM wParam,
+ LPARAM lParam,
+ void *pvCallBackData)
+{
+ // Take default action with message
+ return (DefWindowProc(hWindow, uiMessage, wParam, lParam));
+}
+
+//+-------------------------------------------------------------------
+//
+// Function: WinMain
+//
+// Synopsis: Entry point to DLL - does little else
+//
+// Arguments:
+//
+// Returns: TRUE
+//
+// History: 21-Nov-92 SarahJ Created
+//
+//--------------------------------------------------------------------
+int WINAPI WinMain(
+ HINSTANCE hInstance,
+ HINSTANCE hPrevInstance,
+ char *lpCmdLine,
+ int nCmdShow)
+{
+ // For windows message
+ MSG msg;
+ DWORD dwRegistration;
+ int len;
+ TCHAR buffer[80];
+ MainThread = GetCurrentThreadId();
+
+ // Look up the thread mode from the win.ini file.
+#if 0
+ len = GetProfileString( L"My Section", L"ThreadMode", L"MultiThreaded", buffer,
+ sizeof(buffer) );
+ if (lstrcmp(buffer, L"SingleThreaded") == 0)
+ thread_mode = COINIT_SINGLETHREADED;
+ else if (lstrcmp(buffer, L"MultiThreaded") == 0)
+ thread_mode = COINIT_MULTITHREADED;
+#endif
+
+ // Initialize the OLE libraries
+ OleInitialize(NULL);
+
+ // Create our class factory
+ CPerfCF *perf_cf = new CPerfCF();
+
+ // Register our class with OLE
+ CoRegisterClassObject(CLSID_IPerf, perf_cf, CLSCTX_LOCAL_SERVER,
+ REGCLS_MULTIPLEUSE, &dwRegistration);
+
+ // CoRegister bumps reference count so we don't have to!
+ perf_cf->Release();
+
+ // Register the window class
+ TermRegisterClass(hInstance, (LPTSTR) szAppName,
+ (LPTSTR) szAppName, (LPTSTR) (1));
+
+ // Create the server window
+ TermCreateWindow(
+ (LPTSTR) szAppName,
+ (LPTSTR) szAppName,
+ NULL,
+ ProcessMenu,
+ ProcessChar,
+ ProcessClose,
+ SW_SHOWNORMAL,
+ &g_hMain,
+ NULL);
+
+ // Add debug option to system menu
+ HMENU hmenu = GetSystemMenu(g_hMain, FALSE);
+
+ AppendMenu(hmenu, MF_SEPARATOR, 0, NULL);
+ AppendMenu(hmenu, MF_STRING | MF_ENABLED, IDM_DEBUG, L"Debug");
+
+ // Print the process id.
+ Display( L"Hi, I am %x.\n", GetCurrentProcessId() );
+
+ // Echo the mode.
+ if (thread_mode == COINIT_SINGLETHREADED)
+ Display(L"Server running in single threaded mode.\n");
+ else
+ Display(L"Server running in multithreaded mode.\n");
+
+ // Message processing loop
+ while (GetMessage (&msg, NULL, 0, 0))
+ {
+ TranslateMessage (&msg);
+ DispatchMessage (&msg);
+ }
+
+ // Deregister out class - should release object as well
+ CoRevokeClassObject(dwRegistration);
+
+ // Tell OLE we are going away.
+ OleUninitialize();
+
+ return (msg.wParam); /* Returns the value from PostQuitMessage */
+}
+
+
+
+ /***************************************************************************/
+void CheckThread( TCHAR *name )
+{
+ if (thread_mode == COINIT_SINGLETHREADED)
+ {
+ if (GetCurrentThreadId() != MainThread)
+ goto complain;
+ }
+ else
+ {
+ if (GetCurrentThreadId() == MainThread)
+ goto complain;
+ }
+ return;
+
+complain:
+ Display( L"*********************************************************\n" );
+ Display( L"* *\n" );
+ Display( L"* Error *\n" );
+ Display( L"* *\n" );
+ Display( L"* Method called on wrong thread. *\n" );
+ Display( name );
+ Display( L"* *\n" );
+ Display( L"*********************************************************\n" );
+}
+
+ /***************************************************************************/
+STDMETHODIMP_(ULONG) CPerf::AddRef( THIS )
+{
+ CheckThread(L"STDMETHODIMP_(ULONG) CPerf::AddRef( THIS )");
+ InterlockedIncrement( (long *) &ref_count );
+ return ref_count;
+}
+
+ /***************************************************************************/
+CPerf::CPerf()
+{
+ ref_count = 1;
+ g_cUsage++;
+}
+
+ /***************************************************************************/
+CPerf::~CPerf()
+{
+ if (--g_cUsage == 0)
+ {
+ SendMessage(g_hMain, WM_TERM_WND, 0, 0);
+ }
+}
+
+ /***************************************************************************/
+STDMETHODIMP CPerf::GetAnotherObject( IPerf **another )
+{
+ CheckThread(L"STDMETHODIMP CPerf::GetAnotherObject( IPerf **another )");
+ *another = NULL;
+ CPerf *perf = new FAR CPerf();
+
+ if (perf == NULL)
+ {
+ return E_OUTOFMEMORY;
+ }
+
+ *another = perf;
+ return S_OK;
+}
+
+ /***************************************************************************/
+STDMETHODIMP CPerf::HResultCall()
+{
+ CheckThread(L"STDMETHODIMP CPerf::HResultCall()");
+ return S_OK;
+}
+
+ /***************************************************************************/
+STDMETHODIMP CPerf::NullCall()
+{
+ return S_OK;
+}
+
+ /***************************************************************************/
+STDMETHODIMP CPerf::PassMoniker( IMoniker *moniker )
+{
+ HRESULT result;
+ IBindCtx *bindctx;
+ WCHAR *wide_name;
+
+ // Get a bind context.
+ result = CreateBindCtx( NULL, &bindctx );
+ if (FAILED(result))
+ {
+ Display( L"Could not create bind context: 0x%x\n", result );
+ return E_FAIL;
+ }
+
+ // Display name.
+ result = moniker->GetDisplayName( bindctx, NULL, &wide_name );
+ if (FAILED(result))
+ {
+ Display( L"Could not get display name: 0x%x\n", result );
+ return E_FAIL;
+ }
+
+ // Display the name.
+ Display( L"The moniker is called <%s>\n", wide_name );
+
+ // Free string.
+ CoTaskMemFree( wide_name );
+
+ // Release everything.
+ moniker->Release();
+ bindctx->Release();
+ return S_OK;
+}
+
+ /***************************************************************************/
+STDMETHODIMP CPerf::QueryInterface( THIS_ REFIID riid, LPVOID FAR* ppvObj)
+{
+ CheckThread(L"STDMETHODIMP CPerf::QueryInterface( THIS_ REFIID riid, LPVOID FAR* ppvObj)" );
+ if (IsEqualIID(riid, IID_IUnknown) ||
+ IsEqualIID(riid, IID_IPerf))
+ {
+ *ppvObj = (IUnknown *) this;
+ AddRef();
+ return S_OK;
+ }
+ else
+ {
+ *ppvObj = NULL;
+ return E_NOINTERFACE;
+ }
+}
+
+ /***************************************************************************/
+STDMETHODIMP_(ULONG) CPerf::Release( THIS )
+{
+ CheckThread(L"STDMETHODIMP_(ULONG) CPerf::Release( THIS )");
+ if (InterlockedDecrement( (long*) &ref_count ) == 0)
+ {
+ delete this;
+ return 0;
+ }
+ else
+ return ref_count;
+}
+
+ /***************************************************************************/
+STDMETHODIMP_(ULONG) CPerfCF::AddRef( THIS )
+{
+ CheckThread(L"STDMETHODIMP_(ULONG) CPerfCF::AddRef( THIS )");
+ InterlockedIncrement( (long *) &ref_count );
+ return ref_count;
+}
+
+ /***************************************************************************/
+CPerfCF::CPerfCF()
+{
+ ref_count = 1;
+}
+
+ /***************************************************************************/
+CPerfCF::~CPerfCF()
+{
+}
+
+ /***************************************************************************/
+STDMETHODIMP CPerfCF::CreateInstance(
+ IUnknown FAR* pUnkOuter,
+ REFIID iidInterface,
+ void FAR* FAR* ppv)
+{
+ CheckThread(L"STDMETHODIMP CPerfCF::CreateInstance(" );
+ Display(L"CPerfCF::CreateInstance called\n");
+
+ *ppv = NULL;
+ if (pUnkOuter != NULL)
+ {
+ return E_FAIL;
+ }
+
+ if (!IsEqualIID( iidInterface, IID_IPerf ))
+ return E_NOINTERFACE;
+
+ CPerf *perf = new FAR CPerf();
+
+ if (perf == NULL)
+ {
+ return E_OUTOFMEMORY;
+ }
+
+ *ppv = perf;
+ return S_OK;
+}
+
+ /***************************************************************************/
+STDMETHODIMP CPerfCF::LockServer(BOOL fLock)
+{
+ CheckThread( L"STDMETHODIMP CPerfCF::LockServer(BOOL fLock)" );
+ return E_FAIL;
+}
+
+
+ /***************************************************************************/
+STDMETHODIMP CPerfCF::QueryInterface( THIS_ REFIID riid, LPVOID FAR* ppvObj)
+{
+ CheckThread(L"STDMETHODIMP CPerfCF::QueryInterface( THIS_ REFIID riid, LPVOID FAR* ppvObj)");
+ if (IsEqualIID(riid, IID_IUnknown) ||
+ IsEqualIID(riid, IID_IClassFactory))
+ {
+ *ppvObj = (IUnknown *) this;
+ AddRef();
+ return S_OK;
+ }
+
+ *ppvObj = NULL;
+ return E_NOINTERFACE;
+}
+
+ /***************************************************************************/
+STDMETHODIMP_(ULONG) CPerfCF::Release( THIS )
+{
+ CheckThread(L"STDMETHODIMP_(ULONG) CPerfCF::Release( THIS )");
+ if (InterlockedDecrement( (long*) &ref_count ) == 0)
+ {
+ delete this;
+ return 0;
+ }
+ else
+ return ref_count;
+}
+
+
diff --git a/private/oleutest/perf/perfsrv/perfsrv.hxx b/private/oleutest/perf/perfsrv/perfsrv.hxx
new file mode 100644
index 000000000..9926a4094
--- /dev/null
+++ b/private/oleutest/perf/perfsrv/perfsrv.hxx
@@ -0,0 +1,101 @@
+//+-------------------------------------------------------------------
+//
+// File: perfsrv.hxx
+//
+// Contents: This file contins the DLL entry points
+// LibMain
+// DllGetClassObject (Bindings key func)
+// DllCanUnloadNow
+// CBasicBndCF (class factory)
+// History: 30-Mar-92 SarahJ Created
+//
+//---------------------------------------------------------------------
+
+#ifndef __PERFSRV_H__
+#define __PERFSRV_H__
+
+#include "iperf.h"
+
+extern "C" const IID CLSID_IPerf;
+
+#define SINGLE_THREADED L"Single Threaded"
+#define MULTI_THREADED L"Multi Threaded"
+#define KEY L"SOFTWARE\\Microsoft\\PerfCli"
+
+//+-------------------------------------------------------------------
+//
+// Class: CPerfCF
+//
+// Synopsis: Class Factory for CPerf
+//
+// Methods: IUnknown - QueryInterface, AddRef, Release
+// IClassFactory - CreateInstance
+//
+// History: 21-Mar-92 SarahJ Created
+//
+//--------------------------------------------------------------------
+
+
+class FAR CPerfCF: public IClassFactory
+{
+public:
+
+ // Constructor/Destructor
+ CPerfCF();
+ ~CPerfCF();
+
+ // IUnknown
+ STDMETHODIMP QueryInterface(REFIID iid, void FAR * FAR * ppv);
+ STDMETHOD_(ULONG,AddRef) ( void );
+ STDMETHOD_(ULONG,Release) ( void );
+
+ // IClassFactory
+ STDMETHODIMP CreateInstance(
+ IUnknown FAR* pUnkOuter,
+ REFIID iidInterface,
+ void FAR* FAR* ppv);
+
+ STDMETHODIMP LockServer(BOOL fLock);
+
+private:
+
+ ULONG ref_count;
+};
+
+//+-------------------------------------------------------------------
+//
+// Class: CPerf
+//
+// Synopsis: Test class
+//
+// Methods:
+//
+// History: 21-Mar-92 SarahJ Created
+//
+//--------------------------------------------------------------------
+
+
+class FAR CPerf: public IPerf
+{
+public:
+ CPerf();
+ ~CPerf();
+
+ // IUnknown
+ STDMETHODIMP QueryInterface(REFIID iid, void FAR * FAR * ppv);
+ STDMETHOD_(ULONG,AddRef) ( void );
+ STDMETHOD_(ULONG,Release) ( void );
+
+ // IPerf
+ STDMETHOD (NullCall) ( void );
+ STDMETHOD (HResultCall) ( void );
+ STDMETHOD (GetAnotherObject) ( IPerf ** );
+ STDMETHOD (PassMoniker) ( IMoniker * );
+
+private:
+
+ ULONG ref_count;
+};
+
+
+#endif
diff --git a/private/oleutest/perf/perfsrv/sources b/private/oleutest/perf/perfsrv/sources
new file mode 100644
index 000000000..4cc1f9fd8
--- /dev/null
+++ b/private/oleutest/perf/perfsrv/sources
@@ -0,0 +1,62 @@
+
+MAJORCOMP = cairole
+MINORCOMP = com
+
+#
+# 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= perfsrv
+
+#
+# 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= ..\idl;$(BASEDIR)\private\cinc
+
+C_DEFINES= \
+ $(C_DEFINES) \
+ -DFLAT \
+ -DWIN32=100 \
+ -D_NT1X_=100 \
+ -DUNICODE \
+ -D_UNICODE \
+ -DNOEXCEPTIONS \
+ -DCAIROLE_DOWNLEVEL
+
+BLDCRT= 1
+
+SOURCES= \
+ perfsrv.cxx \
+ wterm.c
+
+
+UMTYPE= windows
+UMENTRY= winmain
+UMAPPL=
+UMTEST=
+UMLIBS= \
+ ..\perfuuid\obj\*\perfuuid.lib \
+ $(BASEDIR)\public\sdk\lib\*\uuid.lib \
+ $(BASEDIR)\public\sdk\lib\*\ole32.lib \
+ $(BASEDIR)\public\sdk\lib\*\rpcndr.lib \
+ $(BASEDIR)\public\sdk\lib\*\rpcrt4.lib \
+ $(BASEDIR)\public\sdk\lib\*\rpcns4.lib \
+ $(BASEDIR)\public\sdk\lib\*\mpr.lib \
+ $(BASEDIR)\public\sdk\lib\*\netapi32.lib \
+ $(BASEDIR)\public\sdk\lib\*\kernel32.lib \
+ $(BASEDIR)\public\sdk\lib\*\user32.lib \
+ $(BASEDIR)\public\sdk\lib\*\advapi32.lib
+
diff --git a/private/oleutest/perf/perfsrv/wterm.c b/private/oleutest/perf/perfsrv/wterm.c
new file mode 100644
index 000000000..336f1e574
--- /dev/null
+++ b/private/oleutest/perf/perfsrv/wterm.c
@@ -0,0 +1,1027 @@
+/****************************************************************************
+
+ PROGRAM: wterm.c
+
+ PURPOSE: Implementation of TermWClass Windows
+
+ FUNCTIONS:
+
+
+ COMMENTS:
+
+
+****************************************************************************/
+
+#include "windows.h"
+#include "stdlib.h"
+#include "memory.h"
+#include "wterm.h"
+
+#define MAX_ROWS 24
+#define MAX_COLS 80
+
+typedef struct WData
+{
+ // Function to execute for processing a menu
+ MFUNCP pMenuProc;
+
+ // Function to execute for processing a single character
+ CFUNCP pCharProc;
+
+ // Function to execute when window is closed (terminated)
+ TFUNCP pCloseProc;
+
+ // Pass on callback
+ void *pvCallBackData;
+
+ BOOL fGotFocus;
+
+ BOOL fCaretHidden;
+
+ // Rows on the screen
+ int cRows;
+
+ // Columns on the screen
+ int cCols;
+
+ // Row at top of screen
+ int iTopRow;
+
+ // Row at bottom of the screen
+ int iBottomRow;
+
+ // First Column on screen
+ int iFirstCol;
+
+ // Column at bottom of the screen
+ int iBottomCol;
+
+ // Row for next character
+ int iNextRow;
+
+ // Row for next column
+ int iNextCol;
+
+ // Width of character
+ int cxChar;
+
+ // Height of character
+ int cyChar;
+
+ // Memory image of screen this is treated as a circular buffer
+ TCHAR aImage[MAX_ROWS] [MAX_COLS];
+
+ // First row in circular screen buffer
+ int iBufferTop;
+} WData;
+
+static HANDLE hInst = 0;
+TCHAR BlankLine[80];
+
+static int
+row_diff(
+ int row1,
+ int row2)
+{
+ return (row2 > row1)
+ ? MAX_ROWS - (row2 - row1)
+ : row1 - row2;
+}
+
+static void
+set_vscroll_pos(
+ HWND hwnd,
+ WData *pwdata)
+{
+ if (pwdata->cRows != 0)
+ {
+ // Save a few indirections by caching cRows
+ register int cRows = pwdata->cRows;
+
+ // calculate distance bottom of screen from top of data buffer
+ register int top_from_row = row_diff(pwdata->iBottomRow,
+ pwdata->iBufferTop);
+
+ // Output position of scroll bar
+ int new_pos = 0;
+
+ if (top_from_row >= cRows)
+ {
+ // Calculate number of screens to display entire buffer
+ int screens_for_data = MAX_ROWS / cRows
+ + ((MAX_ROWS % cRows != 0) ? 1 : 0);
+
+ // Figure out which screen the row falls in
+ int screen_loc = top_from_row / cRows
+ + ((top_from_row % cRows != 0) ? 1 : 0);
+
+ // If the screen is in the last one set box to max
+ new_pos = (screen_loc == screens_for_data)
+ ? MAX_ROWS : screen_loc * cRows;
+ }
+
+ SetScrollPos(hwnd, SB_VERT, new_pos, TRUE);
+ }
+}
+
+static int
+calc_row(
+ register int row,
+ WData *pwdata)
+{
+ register int top = pwdata->iTopRow;
+ static int boopa = 0;
+
+ if (top > row)
+ boopa++;
+
+ return (row >= top) ? row - top : (MAX_ROWS - (top - row));
+}
+
+static void
+display_text(
+ HWND hwnd,
+ int row,
+ int col,
+ LPTSTR text,
+ int text_len,
+ WData *pWData)
+{
+ // Get the DC to display the text
+ HDC hdc = GetDC(hwnd);
+
+ // Select Font
+ SelectObject(hdc, GetStockObject(SYSTEM_FIXED_FONT));
+
+ // Hide caret while we are printing
+ HideCaret(hwnd);
+
+ // Update the screen
+ TextOut(hdc, (col - pWData->iFirstCol) * pWData->cxChar,
+ calc_row(row, pWData) * pWData->cyChar, text, text_len);
+
+ // Done with DC
+ ReleaseDC(hwnd, hdc);
+
+ // Put the caret back now that we are done
+ ShowCaret(hwnd);
+}
+
+static void
+display_char(
+ HWND hwnd,
+ TCHAR char_to_display,
+ WData *pWData)
+{
+ // Update image buffer
+ pWData->aImage[pWData->iNextRow][pWData->iNextCol] = char_to_display;
+
+ display_text(hwnd, pWData->iNextRow, pWData->iNextCol,
+ &char_to_display, 1, pWData);
+}
+
+static void
+do_backspace(
+ HWND hwnd,
+ WData *pWData)
+{
+ // Point to the previous character in the line
+ if (--pWData->iNextCol < 0)
+ {
+ // Can't backspace beyond the current line
+ pWData->iNextCol = 0;
+ return;
+ }
+
+ display_char(hwnd, ' ', pWData);
+
+ // Null character for repaint
+ pWData->aImage[pWData->iNextRow][pWData->iNextCol] = '\0';
+}
+
+static int
+inc_row(
+ int row,
+ int increment)
+{
+ row += increment;
+
+ if (row >= MAX_ROWS)
+ {
+ row -= MAX_ROWS;
+ }
+ else if (row < 0)
+ {
+ row += MAX_ROWS;
+ }
+
+ return row;
+}
+
+void
+inc_next_row(
+ HWND hwnd,
+ WData *pWData)
+{
+ if (pWData->iNextRow == pWData->iBottomRow)
+ {
+ // Line is at bottom -- scroll the client area one row
+ ScrollWindow(hwnd, 0, -pWData->cyChar, NULL, NULL);
+
+ // Increment the top & bottom of the screen
+ pWData->iTopRow = inc_row(pWData->iTopRow, 1);
+ pWData->iBottomRow = inc_row(pWData->iBottomRow, 1);
+ }
+
+ // Increment the row
+ pWData->iNextRow = inc_row(pWData->iNextRow, 1);
+
+ if (pWData->iNextRow == pWData->iBufferTop)
+ {
+ // Have to reset circular buffer to next
+ pWData->iBufferTop = inc_row(pWData->iBufferTop, 1);
+
+ // Reset line to nulls for repaint
+ memset(&pWData->aImage[pWData->iNextRow][0], '\0', MAX_COLS);
+ }
+
+ pWData->iNextCol = 0;
+}
+
+static void
+do_cr(
+ HWND hwnd,
+ WData *pWData)
+{
+ // Set position to next row
+ inc_next_row(hwnd, pWData);
+ pWData->iNextCol = 0;
+
+ // Make sure next character is null for repaint of line
+ pWData->aImage[pWData->iNextRow][pWData->iNextCol] = '\0';
+
+ // Update the vertical scroll bar's position
+ set_vscroll_pos(hwnd, pWData);
+}
+
+static void
+do_char(
+ HWND hwnd,
+ WPARAM wParam,
+ WData *pWData)
+{
+ display_char(hwnd, (TCHAR) wParam, pWData);
+
+ // Point to the next character in the line
+ if (++pWData->iNextCol > MAX_COLS)
+ {
+ // Handle switch to next line
+ inc_next_row(hwnd, pWData);
+ }
+}
+
+static void
+do_tab(
+ HWND hwnd,
+ WData *pWData)
+{
+ int c = pWData->iNextCol % 8;
+
+ if ((pWData->iNextCol + c) <= MAX_COLS)
+ {
+ for ( ; c; c--)
+ {
+ do_char(hwnd, ' ', pWData);
+ }
+ }
+ else
+ {
+ do_cr(hwnd, pWData);
+ }
+}
+
+static void
+EchoChar(
+ HWND hwnd,
+ WORD cRepeats,
+ WPARAM wParam,
+ WData *pWData)
+{
+ for ( ; cRepeats; cRepeats--)
+ {
+ switch (wParam)
+ {
+ // Backspace
+ case '\b':
+ do_backspace(hwnd, pWData);
+ break;
+
+ // Carriage return
+ case '\n':
+ case '\r':
+ do_cr(hwnd, pWData);
+ break;
+
+ // Tab
+ case '\t':
+ do_tab(hwnd, pWData);
+ break;
+
+ // Regular characters
+ default:
+ do_char(hwnd, wParam, pWData);
+ }
+ }
+
+ // The row is guaranteed to be on the screen because we will
+ // scroll on a CR. However, the next column for input may be
+ // beyond the window we are working in.
+ if (pWData->iNextCol > pWData->iBottomCol)
+ {
+ // We are out of the window so scroll the window one
+ // column to the right.
+ SendMessage(hwnd, WM_HSCROLL, SB_LINEDOWN, 0L);
+ }
+ else if (pWData->iNextCol < pWData->iFirstCol)
+ {
+ // We are out of the window so repaint the window using
+ // iNextCol as the first column for the screen.
+ pWData->iFirstCol = pWData->iNextCol;
+ pWData->iBottomCol = pWData->iFirstCol + pWData->cCols - 1;
+
+ // Reset scroll bar
+ SetScrollPos(hwnd, SB_HORZ, pWData->iFirstCol, TRUE);
+
+ // Tell window to update itself.
+ InvalidateRect(hwnd, NULL, TRUE);
+ UpdateWindow(hwnd);
+ }
+ else
+ {
+ // Reset Caret's position
+ SetCaretPos((pWData->iNextCol - pWData->iFirstCol) * pWData->cxChar,
+ calc_row(pWData->iNextRow, pWData) * pWData->cyChar);
+ }
+}
+
+/****************************************************************************
+
+ FUNCTION: WmCreate(HWND)
+
+ PURPOSE: Initializes control structures for a TermWClass Window
+
+ MESSAGES:
+ WM_CREATE
+
+ COMMENTS:
+
+ This prepares a window for processing character based
+ I/O. In particular it does stuff like calculate the
+ size of the window needed.
+
+****************************************************************************/
+static void
+WmCreate(
+ HWND hwnd,
+ CREATESTRUCT *pInit)
+{
+ WData *pData = (WData *) (pInit->lpCreateParams);
+ HDC hdc = GetDC(hwnd);
+ TEXTMETRIC tm;
+
+ // Store pointer to window data
+ SetWindowLong(hwnd, 0, (LONG) pData);
+
+ // Set font to system fixed font
+ SelectObject(hdc, GetStockObject(SYSTEM_FIXED_FONT));
+
+ // Calculate size of a character
+ GetTextMetrics(hdc, &tm);
+ pData->cxChar = tm.tmAveCharWidth;
+ pData->cyChar = tm.tmHeight;
+ ReleaseDC(hwnd, hdc);
+
+ // Set up vertical scroll bars
+ SetScrollRange(hwnd, SB_VERT, 0, MAX_ROWS, TRUE);
+ SetScrollPos(hwnd, SB_VERT, 0, TRUE);
+
+ // Set up horizontal scroll bars
+ SetScrollRange(hwnd, SB_HORZ, 0, MAX_COLS, TRUE);
+ SetScrollPos(hwnd, SB_HORZ, 0, TRUE);
+}
+
+/****************************************************************************
+
+ FUNCTION: WmSize(HWND, WORD, LONG)
+
+ PURPOSE: Processes a size message
+
+ MESSAGES:
+
+ COMMENTS:
+
+****************************************************************************/
+static void
+WmSize(
+ HWND hwnd,
+ WPARAM wParam,
+ LONG lParam,
+ WData *pwdata)
+{
+ // Get the new size of the window
+ int cxClient;
+ int cyClient;
+ int cRowChange = pwdata->cRows;
+ RECT rect;
+
+ // Get size of client area
+ GetClientRect(hwnd, &rect);
+
+ // Calculate size of client area
+ cxClient = rect.right - rect.left;
+ cyClient = rect.bottom - rect.top;
+
+ // Calculate size of area in rows
+ pwdata->cCols = cxClient / pwdata->cxChar;
+ pwdata->cRows = min(MAX_ROWS, cyClient / pwdata->cyChar);
+ pwdata->iBottomCol = min(pwdata->iFirstCol + pwdata->cCols, MAX_COLS);
+ cRowChange = pwdata->cRows - cRowChange;
+
+ // Keep input line toward bottom of screen
+ if (cRowChange < 0)
+ {
+ // Screen has shrunk in size.
+ if (pwdata->iNextRow != pwdata->iTopRow)
+ {
+ // Has input row moved out of screen?
+ if (row_diff(pwdata->iNextRow, pwdata->iTopRow) >= pwdata->cRows)
+ {
+ // Yes -- Calculate top new top that puts input line on
+ // the bottom.
+ pwdata->iTopRow =
+ inc_row(pwdata->iNextRow, 1 - pwdata->cRows);
+ }
+ }
+ }
+ else
+ {
+ // Screen has gotten bigger -- Display more text if possible
+ if (pwdata->iTopRow != pwdata->iBufferTop)
+ {
+ pwdata->iTopRow = inc_row(pwdata->iTopRow,
+ -(min(row_diff(pwdata->iTopRow, pwdata->iBufferTop),
+ cRowChange)));
+ }
+ }
+
+ // Calculate new bottom
+ pwdata->iBottomRow = inc_row(pwdata->iTopRow, pwdata->cRows - 1);
+
+ InvalidateRect(hwnd, NULL, TRUE);
+ UpdateWindow(hwnd);
+}
+
+static void
+WmSetFocus(
+ HWND hwnd,
+ WData *pwdata)
+{
+ // save indirections
+ register int cxchar = pwdata->cxChar;
+ register int cychar = pwdata->cyChar;
+ pwdata->fGotFocus = TRUE;
+ CreateCaret(hwnd, NULL, cxchar, cychar);
+
+ if (!pwdata->fCaretHidden)
+ {
+ SetCaretPos(pwdata->iNextCol * cxchar,
+ calc_row(pwdata->iNextRow, pwdata) * cychar);
+ }
+
+ ShowCaret(hwnd);
+}
+
+static void
+WmKillFocus(
+ HWND hwnd,
+ WData *pwdata)
+{
+ pwdata->fGotFocus = FALSE;
+
+ if (!pwdata->fCaretHidden)
+ {
+ HideCaret(hwnd);
+ }
+
+ DestroyCaret();
+}
+
+static void
+WmVscroll(
+ HWND hwnd,
+ WPARAM wParam,
+ LONG lParam,
+ WData *pwdata)
+{
+ int cVscrollInc = 0;
+ register int top_diff = row_diff(pwdata->iTopRow, pwdata->iBufferTop);
+ register int bottom_diff = MAX_ROWS - (top_diff + pwdata->cRows);
+
+ switch(wParam)
+ {
+ case SB_TOP:
+
+ if (top_diff != 0)
+ {
+ cVscrollInc = -top_diff;
+ }
+
+ break;
+
+ case SB_BOTTOM:
+
+ if (bottom_diff != 0)
+ {
+ cVscrollInc = bottom_diff;
+ }
+
+ break;
+
+ case SB_LINEUP:
+
+ if (top_diff != 0)
+ {
+ cVscrollInc = -1;
+ }
+
+ break;
+
+ case SB_LINEDOWN:
+
+ if (bottom_diff != 0)
+ {
+ cVscrollInc = 1;
+ }
+
+ break;
+
+ case SB_PAGEUP:
+
+ if (top_diff != 0)
+ {
+ cVscrollInc = - ((top_diff > pwdata->cRows)
+ ? pwdata->cRows : top_diff);
+ }
+
+ break;
+
+ case SB_PAGEDOWN:
+
+ if (bottom_diff != 0)
+ {
+ cVscrollInc = (bottom_diff > pwdata->cRows)
+ ? pwdata->cRows : bottom_diff;
+ }
+
+ break;
+
+ case SB_THUMBTRACK:
+
+ if (LOWORD(lParam) != 0)
+ {
+ cVscrollInc = LOWORD(lParam)
+ - row_diff(pwdata->iTopRow, pwdata->iBufferTop);
+ }
+ }
+
+ // Cacluate new top row
+ if (cVscrollInc != 0)
+ {
+ // Calculate new top and bottom
+ pwdata->iTopRow = inc_row(pwdata->iTopRow, cVscrollInc);
+ pwdata->iBottomRow = inc_row(pwdata->iTopRow, pwdata->cRows);
+
+ // Scroll window
+ ScrollWindow(hwnd, 0, pwdata->cyChar * cVscrollInc, NULL, NULL);
+
+ // Reset scroll bar
+ set_vscroll_pos(hwnd, pwdata);
+
+ // Tell window to update itself.
+ InvalidateRect(hwnd, NULL, TRUE);
+ UpdateWindow(hwnd);
+ }
+}
+
+static void
+WmHscroll(
+ HWND hwnd,
+ WPARAM wParam,
+ LONG lParam,
+ WData *pwdata)
+{
+ register int cHscrollInc = 0;
+
+ switch(wParam)
+ {
+ case SB_LINEUP:
+
+ cHscrollInc = -1;
+ break;
+
+ case SB_LINEDOWN:
+
+ cHscrollInc = 1;
+ break;
+
+ case SB_PAGEUP:
+
+ cHscrollInc = -8;
+ break;
+
+ case SB_PAGEDOWN:
+
+ cHscrollInc = 8;
+ break;
+
+ case SB_THUMBTRACK:
+
+ if (LOWORD(lParam) != 0)
+ {
+ cHscrollInc = LOWORD(lParam) - pwdata->iFirstCol;
+ }
+ }
+
+ if (cHscrollInc != 0)
+ {
+ // Cacluate new first column
+ register int NormalizedScrollInc = cHscrollInc + pwdata->iFirstCol;
+
+ if (NormalizedScrollInc < 0)
+ {
+ cHscrollInc = -pwdata->iFirstCol;
+ }
+ else if (NormalizedScrollInc > MAX_COLS - pwdata->cCols)
+ {
+ cHscrollInc = (MAX_COLS - pwdata->cCols) - pwdata->iFirstCol;
+ }
+
+ pwdata->iFirstCol += cHscrollInc;
+ pwdata->iBottomCol = pwdata->iFirstCol + pwdata->cCols - 1;
+
+ // Scroll window
+ ScrollWindow(hwnd, -(pwdata->cxChar * cHscrollInc), 0, NULL, NULL);
+
+ // Reset scroll bar
+ SetScrollPos(hwnd, SB_HORZ, pwdata->iFirstCol, TRUE);
+
+ // Tell window to update itself.
+ InvalidateRect(hwnd, NULL, TRUE);
+ UpdateWindow(hwnd);
+ }
+}
+
+static void
+WmPaint(
+ HWND hwnd,
+ WData *pwdata)
+{
+ PAINTSTRUCT ps;
+ HDC hdc = BeginPaint(hwnd, &ps);
+ register int row = pwdata->iTopRow;
+ register int col = pwdata->iFirstCol;
+ int bottom_row = pwdata->iBottomRow;
+ int cxChar = pwdata->cxChar;
+ int cyChar = pwdata->cyChar;
+ int y;
+
+ // Select System Font
+ SelectObject(hdc, GetStockObject(SYSTEM_FIXED_FONT));
+
+ while (TRUE)
+ {
+ int len = lstrlen(&pwdata->aImage[row][col]);
+
+ if (len != 0)
+ {
+ y = calc_row(row, pwdata) * cyChar;
+ TextOut(hdc, 0, y, &pwdata->aImage[row][col], len);
+ }
+
+ if (row == bottom_row)
+ {
+ break;
+ }
+
+ row = inc_row(row, 1);
+ }
+
+ if (pwdata->fGotFocus)
+ {
+ if ((pwdata->iNextCol >= pwdata->iFirstCol)
+ && (row_diff(pwdata->iNextRow, pwdata->iTopRow) < pwdata->cRows))
+ {
+ if (pwdata->fCaretHidden)
+ {
+ pwdata->fCaretHidden = FALSE;
+ ShowCaret(hwnd);
+ }
+
+ SetCaretPos(
+ (pwdata->iNextCol - pwdata->iFirstCol) * pwdata->cxChar,
+ calc_row(pwdata->iNextRow, pwdata) * pwdata->cyChar);
+ }
+ else
+ {
+ if (!pwdata->fCaretHidden)
+ {
+ pwdata->fCaretHidden = TRUE;
+ HideCaret(hwnd);
+ }
+ }
+ }
+
+ EndPaint(hwnd, &ps);
+}
+
+
+
+
+
+//
+// FUNCTION: WmPrintLine
+//
+// PURPOSE: Print a line on the screen.
+//
+// Note: this is a user message not an intrinsic Window's message.
+//
+void
+WmPrintLine(
+ HWND hwnd,
+ WPARAM wParam,
+ LONG lParam,
+ WData *pTermData)
+{
+ TCHAR *pBuf = (TCHAR *) lParam;
+
+ // MessageBox(hwnd, L"WmPrintLine", L"Debug", MB_OK);
+
+ // DebugBreak();
+
+ while (wParam--)
+ {
+ // Is character a lf?
+ if (*pBuf == '\n')
+ {
+ // Convert to cr since that is what this window uses
+ *pBuf = '\r';
+ }
+
+ // Write the character to the window
+ EchoChar(hwnd, 1, *pBuf++, pTermData);
+ }
+
+}
+
+//
+// FUNCTION: WmPutc
+//
+// PURPOSE: Print a single character on the screen
+//
+// Note: this is a user message not an intrinsic Window's message.
+//
+void
+WmPutc(
+ HWND hwnd,
+ WPARAM wParam,
+ WData *pTermData)
+{
+ // Is character a lf?
+ if (wParam == '\n')
+ {
+ // Convert to cr since that is what this window uses
+ wParam = '\r';
+ }
+
+ // Write the character to the window
+ EchoChar(hwnd, 1, wParam, pTermData);
+}
+
+
+/****************************************************************************
+
+ FUNCTION: TermWndProc(HWND, unsigned, WORD, LONG)
+
+ PURPOSE: Processes messages
+
+ MESSAGES:
+
+ COMMENTS:
+
+****************************************************************************/
+
+long TermWndProc(
+ HWND hWnd,
+ UINT message,
+ WPARAM wParam,
+ LPARAM lParam)
+{
+ WData *pTerm = (WData *) GetWindowLong(hWnd, 0);
+
+ switch (message)
+ {
+ case WM_CREATE:
+ WmCreate(hWnd, (CREATESTRUCT *) lParam);
+ break;
+
+ case WM_COMMAND:
+ case WM_SYSCOMMAND:
+ // Call procedure that processes the menus
+ return (*(pTerm->pMenuProc))(hWnd, message, wParam, lParam,
+ pTerm->pvCallBackData);
+
+ case WM_SIZE:
+ WmSize(hWnd, wParam, lParam, pTerm);
+ break;
+
+ case WM_SETFOCUS:
+ WmSetFocus(hWnd, pTerm);
+ break;
+
+ case WM_KILLFOCUS:
+ WmKillFocus(hWnd, pTerm);
+ break;
+
+ case WM_VSCROLL:
+ WmVscroll(hWnd, wParam, lParam, pTerm);
+ break;
+
+ case WM_HSCROLL:
+ WmHscroll(hWnd, wParam, lParam, pTerm);
+ break;
+
+ case WM_CHAR:
+ // Character message echo and put in buffer
+ return (*(pTerm->pCharProc))(hWnd, message, wParam, lParam,
+ pTerm->pvCallBackData);
+
+ case WM_PAINT:
+ WmPaint(hWnd, pTerm);
+ break;
+
+ case WM_CLOSE:
+ DestroyWindow(hWnd);
+ break;
+
+ case WM_NCDESTROY:
+ // Call close notification procedure
+ return (*(pTerm->pCloseProc))(hWnd, message, wParam, lParam,
+ pTerm->pvCallBackData);
+
+ case WM_PRINT_LINE:
+ WmPrintLine(hWnd, wParam, lParam, pTerm);
+ break;
+
+ case WM_PUTC:
+ WmPutc(hWnd, wParam, pTerm);
+ break;
+
+ case WM_DESTROY:
+ PostQuitMessage(0);
+ break;
+
+ case WM_TERM_WND:
+ DestroyWindow(hWnd);
+ break;
+
+ default: /* Passes it on if unproccessed */
+ return (DefWindowProc(hWnd, message, wParam, lParam));
+ }
+
+ return 0;
+}
+
+
+/****************************************************************************
+
+ FUNCTION: TermRegisterClass(HANDLE)
+
+ PURPOSE: Register a class for a terminal window
+
+ COMMENTS:
+
+
+****************************************************************************/
+
+BOOL TermRegisterClass(
+ HANDLE hInstance,
+ LPTSTR MenuName,
+ LPTSTR ClassName,
+ LPTSTR Icon)
+{
+ WNDCLASS wc;
+ BOOL retVal;
+
+ // Make sure blank line is blank
+ memset(BlankLine, ' ', 80);
+
+ /* Fill in window class structure with parameters that describe the */
+ /* main window. */
+
+ wc.style = 0;
+ wc.lpfnWndProc = TermWndProc;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = sizeof(WData *);
+ wc.hInstance = hInstance;
+ wc.hIcon = LoadIcon(NULL, Icon);
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wc.hbrBackground = GetStockObject(WHITE_BRUSH);
+ wc.lpszMenuName = MenuName;
+ wc.lpszClassName = ClassName;
+
+ /* Register the window class and return success/failure code. */
+ if (retVal = RegisterClass(&wc))
+ {
+ // Class got registered -- so finish set up
+ hInst = hInstance;
+ }
+
+ return retVal;
+}
+
+
+/****************************************************************************
+
+ FUNCTION: TermCreateWindow(LPWSTR, LPWSTR, HMENU, void *, void *, int)
+
+ PURPOSE: Create a window of a previously registered window class
+
+ COMMENTS:
+
+
+****************************************************************************/
+
+BOOL
+TermCreateWindow(
+ LPTSTR lpClassName,
+ LPTSTR lpWindowName,
+ HMENU hMenu,
+ MFUNCP MenuProc,
+ CFUNCP CharProc,
+ TFUNCP CloseProc,
+ int nCmdShow,
+ HWND *phNewWindow,
+ void *pvCallBackData)
+{
+ HWND hWnd; // Main window handle.
+ WData *pTermData;
+
+ // Allocate control structure for the window
+ if ((pTermData = malloc(sizeof(WData))) == NULL)
+ {
+ return FALSE;
+ }
+
+ // Set entire structure to nulls
+ memset((TCHAR *) pTermData, '\0', sizeof(WData));
+
+ // Initialize function pointers
+ pTermData->pMenuProc = MenuProc;
+ pTermData->pCharProc = CharProc;
+ pTermData->pCloseProc = CloseProc;
+
+ // Initialize callback data
+ pTermData->pvCallBackData = pvCallBackData;
+
+ // Create a main window for this application instance.
+ hWnd = CreateWindow(
+ lpClassName,
+ lpWindowName,
+ WS_OVERLAPPEDWINDOW,
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ NULL,
+ hMenu,
+ hInst,
+ (LPTSTR) pTermData
+ );
+
+ // If window could not be created, return "failure"
+
+ if (!hWnd)
+ {
+ free(pTermData);
+ return FALSE;
+ }
+
+ SetFocus(hWnd);
+
+ // Make the window visible; update its client area; and return "success"
+
+ ShowWindow(hWnd, nCmdShow);
+ UpdateWindow(hWnd);
+ *phNewWindow = hWnd;
+ return (TRUE);
+}
diff --git a/private/oleutest/perf/perfsrv/wterm.h b/private/oleutest/perf/perfsrv/wterm.h
new file mode 100644
index 000000000..4085c7d9a
--- /dev/null
+++ b/private/oleutest/perf/perfsrv/wterm.h
@@ -0,0 +1,40 @@
+#ifndef __WTERM__
+#define __WTERM__
+
+// Message to print a line on the window
+#define WM_PRINT_LINE (WM_USER + 1)
+
+// Message to print a character on the window
+#define WM_PUTC (WM_USER + 2)
+
+// Message used to terminate this window
+#define WM_TERM_WND (WM_USER + 3)
+
+//
+// Typedefs for call back functions for the window
+//
+typedef long (*MFUNCP)(HWND, UINT, WPARAM, LPARAM, void *);
+typedef long (*CFUNCP)(HWND, UINT, WPARAM, LPARAM, void *);
+typedef long (*TFUNCP)(HWND, UINT, WPARAM, LPARAM, void *);
+
+// Register the terminal window class
+BOOL TermRegisterClass(
+ HANDLE hInstance,
+ LPTSTR MenuName,
+ LPTSTR ClassName,
+ LPTSTR ICON);
+
+// Create a window for the terminal
+BOOL
+TermCreateWindow(
+ LPTSTR lpClassName,
+ LPTSTR lpWindowName,
+ HMENU hMenu,
+ MFUNCP MenuProc,
+ CFUNCP CharProc,
+ TFUNCP CloseProc,
+ int nCmdShow,
+ HWND *phNewWindow,
+ void *pvCallBackData);
+
+#endif // __WTERM__
diff --git a/private/oleutest/perf/perfuuid/makefile b/private/oleutest/perf/perfuuid/makefile
new file mode 100644
index 000000000..510cce95d
--- /dev/null
+++ b/private/oleutest/perf/perfuuid/makefile
@@ -0,0 +1,9 @@
+############################################################################
+#
+# Copyright (C) 1992, Microsoft Corporation.
+#
+# All rights reserved.
+#
+############################################################################
+
+!include $(NTMAKEENV)\makefile.def
diff --git a/private/oleutest/perf/perfuuid/perfsrvi.c b/private/oleutest/perf/perfuuid/perfsrvi.c
new file mode 100644
index 000000000..98e1ef33c
--- /dev/null
+++ b/private/oleutest/perf/perfuuid/perfsrvi.c
@@ -0,0 +1,24 @@
+#pragma warning(disable:4101) // Ignore variable not use warning
+
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: iperf_i.c
+//
+// Contents: IID_IPerf
+//
+// History: Created by Microsoft (R) MIDL Compiler Version 1.10.83
+//
+//--------------------------------------------------------------------------
+typedef struct _IID
+{
+ unsigned long x;
+ unsigned short s1;
+ unsigned short s2;
+ unsigned char c[8];
+} IID;
+
+
+const IID CLSID_IPerf = {0x1AFDBB80, 0xAA32, 0x101A, {0xB4, 0xAD, 0x08, 0x00, 0x2B, 0x30, 0x61, 0x2C}};
diff --git a/private/oleutest/perf/perfuuid/sources b/private/oleutest/perf/perfuuid/sources
new file mode 100644
index 000000000..051a17b4a
--- /dev/null
+++ b/private/oleutest/perf/perfuuid/sources
@@ -0,0 +1,68 @@
+!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:
+
+ Dean Edwards (DeanE) 11-Jan-1993
+
+!ENDIF
+
+MAJORCOMP= cairole
+MINORCOMP= com
+
+#
+# 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= perfuuid
+
+#
+# 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= LIBRARY
+
+INCLUDES= \
+ ..\.; \
+ $(BASEDIR)\public\sdk\inc; \
+ $(BASEDIR)\private\cinc
+
+C_DEFINES= $(C_DEFINES)
+
+BLDCRT= 1
+
+SOURCES= iperf_i.c \
+ perfsrvi.c
+
+UMTYPE= windows
+UMAPPL=
+UMTEST=
+UMLIBS=
+
+USE_LIBCMT= 1
+
+PRECOMPILED_INCLUDE=
+
diff --git a/private/oleutest/perf/proxy/dllentry.c b/private/oleutest/perf/proxy/dllentry.c
new file mode 100644
index 000000000..0a129f9be
--- /dev/null
+++ b/private/oleutest/perf/proxy/dllentry.c
@@ -0,0 +1,224 @@
+//+-------------------------------------------------------------------
+//
+// 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.
+// 12-23-93 TerryRu Replace LockExit, and UnLockExit
+// with critial sections for Daytona.
+// 12-28-93 TerryRu Place Regiter/DeRegister WinCommnot apis
+// Inside WIN32 endifs for Daytona builds.
+//
+//--------------------------------------------------------------------
+#include <windows.h>
+//#include <win4p.h>
+#include <process.h>
+#include <string.h>
+#include <stdlib.h>
+#include <malloc.h>
+
+
+BOOL WINAPI _CRT_INIT (HANDLE hDll, DWORD dwReason, LPVOID lpReserved);
+
+BOOL __stdcall DllEntryPoint (HANDLE hDll, DWORD dwReason, LPVOID lpReserved);
+
+BOOL _CRTAPI1 LibMain (HANDLE hDll, DWORD dwReason, LPVOID lpReserved);
+
+void _CRTAPI1 _mtdeletelocks(void);
+
+DWORD WINAPI
+GetModuleFileNameCtC(
+ HMODULE hModule,
+ LPWSTR pwszFilename,
+ DWORD nSize);
+
+#ifdef USE_CRTDLL
+
+#define _RT_ONEXIT 24
+
+/*
+ * routine in DLL to do initialization (in this case, C++ constructors)
+ */
+
+typedef void (_CRTAPI1 *PF)(void);
+
+/*
+ * pointers to initialization sections
+ */
+
+PF *__onexitbegin;
+PF *__onexitend;
+
+/*
+ * Define increment (in entries) for growing the _onexit/atexit table
+ */
+#define ONEXITTBLINCR 4
+
+static void _CRTAPI1 _onexitinit ( void );
+extern void _CRTAPI1 _initterm(PF *, PF *);
+extern void _CRTAPI1 _amsg_exit(int);
+extern void _CRTAPI1 _lockexit(void);
+extern void _CRTAPI1 _unlockexit(void);
+
+#endif
+
+// BUGBUG: defined in $(COMMON)\src\except\memory.cxx
+
+void RegisterWithCommnot(void);
+void DeRegisterWithCommnot(void);
+
+CRITICAL_SECTION __gCriticalSection;
+
+BOOL __stdcall DllEntryPoint (HANDLE hDll, DWORD dwReason, LPVOID lpReserved)
+{
+ BOOL fRc = FALSE;
+
+ switch (dwReason)
+ {
+ case DLL_PROCESS_ATTACH:
+
+#ifdef USE_CRTDLL
+ //
+ // Assumption: The run-time is sufficiantly up and running to
+ // support malloc that _onexitinit will perform.
+ //
+ _onexitinit();
+ InitializeCriticalSection(&__gCriticalSection );
+#endif
+
+ _CRT_INIT(hDll, dwReason, lpReserved);
+#if WIN32==300
+ RegisterWithCommnot();
+#endif
+
+ case DLL_THREAD_ATTACH:
+ case DLL_THREAD_DETACH:
+ fRc = LibMain (hDll, dwReason, lpReserved);
+ break;
+
+ case DLL_PROCESS_DETACH:
+ fRc = LibMain (hDll, dwReason, lpReserved);
+
+ //
+ // BUGBUG: What a hack. In order to make sure we don't kill
+ // commnot's objects while still in use (_cexit will do
+ // the atexit list processing where the compiler stores
+ // pointers to all the static destructors), test the
+ // module name. If not commnot, call _cexit().
+ // DeRegisterWithCommnot will call it for commnot...
+ //
+
+#ifdef USE_CRTDLL
+
+ {
+ wchar_t pwszModName[512];
+ GetModuleFileName(hDll, pwszModName, 512);
+
+ if (!wcswcs(wcsupr(pwszModName), L"COMMNOT"))
+ if (__onexitbegin)
+ _initterm(__onexitbegin, __onexitend);
+ }
+
+ DeleteCriticalSection( & __gCriticalSection );
+#else
+
+ {
+ wchar_t pwszModName[512];
+ GetModuleFileName(hDll, pwszModName, 512);
+
+ if (!wcswcs(wcsupr(pwszModName), L"COMMNOT"))
+ _cexit();
+ }
+
+ _mtdeletelocks();
+#endif
+#if WIN32==300
+ DeRegisterWithCommnot();
+#endif
+ break;
+ }
+
+ return(fRc);
+}
+
+#ifdef USE_CRTDLL
+
+_onexit_t _CRTAPI1 _onexit ( _onexit_t func )
+{
+ PF *p;
+
+ EnterCriticalSection( &__gCriticalSection ); /* lock the exit code */
+
+ /*
+ * First, make sure the table has room for a new entry
+ */
+ if ( _msize(__onexitbegin) <= (unsigned)((char *)__onexitend -
+ (char *)__onexitbegin) ) {
+ /*
+ * not enough room, try to grow the table
+ */
+ if ( (p = (PF *) realloc(__onexitbegin, _msize(__onexitbegin) +
+ ONEXITTBLINCR * sizeof(PF))) == NULL ) {
+ /*
+ * didn't work. don't do anything rash, just fail
+ */
+ LeaveCriticalSection(&__gCriticalSection );
+
+ return NULL;
+ }
+
+ /*
+ * update __onexitend and __onexitbegin
+ */
+
+ __onexitend = p + (__onexitend - __onexitbegin);
+ __onexitbegin = p;
+ }
+
+ /*
+ * Put the new entry into the table and update the end-of-table
+ * pointer.
+ */
+
+ *(__onexitend++) = (PF)func;
+
+ LeaveCriticalSection( &__gCriticalSection );
+
+ return func;
+
+}
+
+int _CRTAPI1 atexit ( PF func )
+{
+ return (_onexit((_onexit_t)func) == NULL) ? -1 : 0;
+}
+
+static void _CRTAPI1 _onexitinit ( void )
+{
+ if ( (__onexitbegin = (PF *)malloc(32 * sizeof(PF))) == NULL )
+ /*
+ * cannot allocate minimal required size. generate
+ * fatal runtime error.
+ */
+ _amsg_exit(_RT_ONEXIT);
+
+ *(__onexitbegin) = (PF) NULL;
+ __onexitend = __onexitbegin;
+}
+
+#endif // USE_CRTDLL
diff --git a/private/oleutest/perf/proxy/makefile b/private/oleutest/perf/proxy/makefile
new file mode 100644
index 000000000..510cce95d
--- /dev/null
+++ b/private/oleutest/perf/proxy/makefile
@@ -0,0 +1,9 @@
+############################################################################
+#
+# Copyright (C) 1992, Microsoft Corporation.
+#
+# All rights reserved.
+#
+############################################################################
+
+!include $(NTMAKEENV)\makefile.def
diff --git a/private/oleutest/perf/proxy/prxydll.def b/private/oleutest/perf/proxy/prxydll.def
new file mode 100644
index 000000000..c0feeaa0c
--- /dev/null
+++ b/private/oleutest/perf/proxy/prxydll.def
@@ -0,0 +1,9 @@
+LIBRARY IPERF
+
+DESCRIPTION 'Microsoft (R) OLE 2.0 Proxy/Stub DLL 1.00'
+
+EXPORTS
+
+ DllGetClassObject @1
+ DllCanUnloadNow @2
+
diff --git a/private/oleutest/perf/proxy/sources b/private/oleutest/perf/proxy/sources
new file mode 100644
index 000000000..2849e7bd4
--- /dev/null
+++ b/private/oleutest/perf/proxy/sources
@@ -0,0 +1,105 @@
+!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:
+
+ Dean Edwards (DeanE) 11-Jan-1993
+
+!ENDIF
+
+MAJORCOMP= comutest
+MINORCOMP= channelperf
+
+#
+# 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= iperf
+
+#
+# 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= DYNLINK
+
+#
+# This specifies the target of a release
+#
+
+DLLDEF= prxydll.def
+
+DLLBASE= @$(BASEDIR)\public\sdk\lib\coffbase.txt,ole32
+
+INCLUDES= .;\
+ ..\idl;\
+ $(BASEDIR)\public\sdk\inc; \
+ $(BASEDIR)\private\cinc; \
+ $(BASEDIR)\private\types\oleprx32\daytona
+
+
+C_DEFINES= $(C_DEFINES) \
+ -DFLAT \
+ -D_NT1X_=100 \
+ -DUNICODE \
+ -D_UNICODE \
+ -DINC_OLE2
+
+
+BLDCRT= 1
+
+SOURCES= \
+ iperf_p.cxx \
+ dlldata.c
+
+UMTYPE= windows
+#UMENTRY= _CRTDLL_INIT
+UMAPPL=
+UMTEST=
+UMLIBS=
+
+LINKLIBS= \
+ ..\perfuuid\obj\*\perfuuid.lib \
+ $(BASEDIR)\public\sdk\lib\*\uuid.lib \
+ $(BASEDIR)\public\sdk\lib\*\stdclass.lib \
+ $(BASEDIR)\public\sdk\lib\*\ole32.lib \
+ $(BASEDIR)\public\sdk\lib\*\rpcrt4.lib \
+ $(BASEDIR)\public\sdk\lib\*\kernel32.lib \
+ $(BASEDIR)\public\sdk\lib\*\libcmt.lib
+# $(BASEDIR)\public\sdk\lib\*\crtdll.lib
+
+
+#
+# We are linking with libcmt explicitly because makefile.def/build.exe
+# is so wonderful that it sets the proper -Ddefines on C_DEFINES but
+# never uses the $%#@ CRT lib when it builds the DLL... We still need
+# to set USE_LIBCMT to 1 so the proper defines are set
+#
+USE_LIBCMT= 1
+
+PRECOMPILED_INCLUDE=
+
+
+
diff --git a/private/oleutest/perf/rel.cmd b/private/oleutest/perf/rel.cmd
new file mode 100644
index 000000000..50d6f95a0
--- /dev/null
+++ b/private/oleutest/perf/rel.cmd
@@ -0,0 +1,4 @@
+copy proxy\obj\i386\iperf.dll \tmp
+copy perfsrv\obj\i386\perfsrv.exe \tmp
+copy perfcli\obj\i386\perfcli.exe \tmp
+copy idl\perf.reg \tmp
diff --git a/private/oleutest/perf16/idata/bookpart.h b/private/oleutest/perf16/idata/bookpart.h
new file mode 100644
index 000000000..0644ee46c
--- /dev/null
+++ b/private/oleutest/perf16/idata/bookpart.h
@@ -0,0 +1,48 @@
+
+
+#define SETDefFormatEtc(fe, cf, med) \
+ {\
+ (fe).cfFormat=cf;\
+ (fe).dwAspect=DVASPECT_CONTENT;\
+ (fe).ptd=NULL;\
+ (fe).tymed=med;\
+ (fe).lindex=-1;\
+ };
+
+#define DATASIZE_FROM_INDEX(i) ((i) * 1024)
+
+
+//Types that OLE2.H et. al. leave out
+#ifndef LPLPVOID
+typedef LPVOID FAR * LPLPVOID;
+#endif //LPLPVOID
+
+#ifndef PPVOID //Large model version
+typedef LPVOID * PPVOID;
+#endif //PPVOID
+
+
+EXTERN_C const GUID CDECL FAR CLSID_DataObjectTest32;
+EXTERN_C const GUID CDECL FAR CLSID_DataObjectTest16;
+
+#ifdef INIT_MY_GUIDS
+
+ EXTERN_C const GUID CDECL
+ CLSID_DataObjectTest32 = { /* ad562fd0-ac40-11ce-9d69-00aa0060f944 */
+ 0xad562fd0,
+ 0xac40,
+ 0x11ce,
+ {0x9d, 0x69, 0x00, 0xaa, 0x00, 0x60, 0xf9, 0x44}
+ };
+
+ EXTERN_C const GUID CDECL
+ CLSID_DataObjectTest16 = { /* ad562fd1-ac40-11ce-9d69-00aa0060f944 */
+ 0xad562fd1,
+ 0xac40,
+ 0x11ce,
+ {0x9d, 0x69, 0x00, 0xaa, 0x00, 0x60, 0xf9, 0x44}
+ };
+
+#endif /* INITGUID */
+
+
diff --git a/private/oleutest/perf16/idata/classids.reg b/private/oleutest/perf16/idata/classids.reg
new file mode 100644
index 000000000..5e875bd97
--- /dev/null
+++ b/private/oleutest/perf16/idata/classids.reg
@@ -0,0 +1,16 @@
+REGEDIT
+
+HKEY_CLASSES_ROOT\DataObject.Only = 32 bit Data Object For IData Test Program
+HKEY_CLASSES_ROOT\DataObject.Only\CLSID = ad562fd0-ac40-11ce-9d69-00aa0060f944}
+HKEY_CLASSES_ROOT\CLSID\{ad562fd0-ac40-11ce-9d69-00aa0060f944} = 32 bit Data Object For IData Test Program
+HKEY_CLASSES_ROOT\CLSID\{ad562fd0-ac40-11ce-9d69-00aa0060f944}\LocalServer32 = c:\nti386\nt\dump\edataobj.exe
+HKEY_CLASSES_ROOT\CLSID\{ad562fd0-ac40-11ce-9d69-00aa0060f944}\ProgID = DataObject.Only
+HKEY_CLASSES_ROOT\CLSID\{ad562fd0-ac40-11ce-9d69-00aa0060f944}\NotInsertable =
+
+HKEY_CLASSES_ROOT\DataObject.Only = 16 bit Data Object For IData Test Program
+HKEY_CLASSES_ROOT\DataObject.Only\CLSID = ad562fd1-ac40-11ce-9d69-00aa0060f944}
+HKEY_CLASSES_ROOT\CLSID\{ad562fd1-ac40-11ce-9d69-00aa0060f944} = 16 bit Data Object For IData Test Program
+HKEY_CLASSES_ROOT\CLSID\{ad562fd1-ac40-11ce-9d69-00aa0060f944}\LocalServer32 = c:\nti386\nt\dump\edatas16.exe
+HKEY_CLASSES_ROOT\CLSID\{ad562fd1-ac40-11ce-9d69-00aa0060f944}\ProgID = DataObject.Only
+HKEY_CLASSES_ROOT\CLSID\{ad562fd1-ac40-11ce-9d69-00aa0060f944}\NotInsertable =
+ \ No newline at end of file
diff --git a/private/oleutest/perf16/idata/client/datausr.cpp b/private/oleutest/perf16/idata/client/datausr.cpp
new file mode 100644
index 000000000..eec3dc697
--- /dev/null
+++ b/private/oleutest/perf16/idata/client/datausr.cpp
@@ -0,0 +1,1260 @@
+/*
+ * DATAUSER.CPP
+ * Data Object User Chapter 6
+ *
+ * Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved
+ *
+ * Kraig Brockschmidt, Software Design Engineer
+ * Microsoft Systems Developer Relations
+ *
+ * Internet : kraigb@microsoft.com
+ * Compuserve: >INTERNET:kraigb@microsoft.com
+ */
+
+
+#define INIT_MY_GUIDS
+#include "datausr.h"
+#include "perror.h"
+#include <stdio.h>
+
+#ifdef WIN32
+#define APP_TITLE TEXT("32 Bit IDataObject User")
+#else
+#define APP_TITLE TEXT("16 Bit IDataObject User")
+#endif
+
+//These are for displaying clipboard formats textually.
+static TCHAR * rgszCF[13]={TEXT("Unknown"), TEXT("CF_TEXT")
+ , TEXT("CF_BITMAP"), TEXT("CF_METAFILEPICT")
+ , TEXT("CF_SYLK"), TEXT("CF_DIF"), TEXT("CF_TIFF")
+ , TEXT("CF_OEMTEXT"), TEXT("CF_DIB")
+ , TEXT("CF_PALETTE"), TEXT("CF_PENDATA")
+ , TEXT("CF_RIFF"), TEXT("CF_WAVE")};
+
+
+static TCHAR szSuccess[] =TEXT("succeeded");
+static TCHAR szFailed[] =TEXT("failed");
+static TCHAR szExpected[] =TEXT("expected");
+static TCHAR szUnexpected[] =TEXT("unexpected!");
+
+TCHAR tcMessageBuf[4096]; // Misc use buffer for messages.
+int cKSizes[NUM_POINTS] = { 1, 2, 4, 6, 8,
+ 10, 12, 16, 20, 24,
+ 28, 32, 40, 48, 56 };
+
+/*
+ * WinMain
+ *
+ * Purpose:
+ * Main entry point of application.
+ */
+
+int PASCAL WinMain(
+ HINSTANCE hInst,
+ HINSTANCE hInstPrev,
+ LPSTR pszCmdLine,
+ int nCmdShow)
+{
+ MSG msg;
+ PAPPVARS pAV;
+
+#ifndef WIN32
+ int cMsg=96;
+
+ while (!SetMessageQueue(cMsg) && (cMsg-=8));
+#endif
+
+ pAV=new CAppVars(hInst, hInstPrev, nCmdShow);
+
+ if (NULL==pAV)
+ return -1;
+
+ if (pAV->FInit())
+ {
+ while (GetMessage(&msg, NULL, 0,0 ))
+ {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ }
+
+ delete pAV;
+ return msg.wParam;
+}
+
+
+
+
+/*
+ * DataUserWndProc
+ *
+ * Purpose:
+ * Window class procedure. Standard callback.
+ */
+
+LRESULT API_ENTRY DataUserWndProc(HWND hWnd, UINT iMsg
+ , WPARAM wParam, LPARAM lParam)
+ {
+ HRESULT hr;
+ PAPPVARS pAV;
+ HMENU hMenu;
+ FORMATETC fe;
+ WORD wID;
+ int i;
+
+ pAV=(PAPPVARS)GetWindowLong(hWnd, DATAUSERWL_STRUCTURE);
+
+ switch (iMsg)
+ {
+ case WM_NCCREATE:
+ pAV=(PAPPVARS)((LPCREATESTRUCT)lParam)->lpCreateParams;
+ SetWindowLong(hWnd, DATAUSERWL_STRUCTURE, (LONG)pAV);
+ return (DefWindowProc(hWnd, iMsg, wParam, lParam));
+
+ case WM_DESTROY:
+ PostQuitMessage(0);
+ break;
+
+ case WM_PAINT:
+ pAV->Paint();
+ break;
+
+ case WM_COMMAND:
+ SETDefFormatEtc(fe, 0, TYMED_HGLOBAL | TYMED_GDI| TYMED_MFPICT);
+
+ hMenu=GetMenu(hWnd);
+ wID=LOWORD(wParam);
+
+ if(wID >= IDM_OBJECTSETDATA && wID <= IDM_OBJECTSETDATA+64)
+ {
+ // Blast all possible SetData menu items. Some don't exist.
+ for(i=IDM_OBJECTSETDATA; i<=IDM_OBJECTSETDATA+64; i++)
+ CheckMenuItem(hMenu,i, MF_UNCHECKED);
+ CheckMenuItem(hMenu, wID, MF_CHECKED);
+
+ pAV->m_SetData_SetSize(wID-IDM_OBJECTSETDATA);
+ break;
+ }
+
+ switch (wID)
+ {
+ case IDM_USE16BITSERVER:
+ if (pAV->m_f16Bit)
+ break;
+ pAV->m_f16Bit = TRUE;
+ pAV->FReloadDataObjects(TRUE);
+ break;
+
+ case IDM_USE32BITSERVER:
+ if (!pAV->m_f16Bit)
+ break;
+ pAV->m_f16Bit = FALSE;
+ pAV->FReloadDataObjects(TRUE);
+ break;
+
+ case IDM_OBJECTQUERYGETDATA:
+ if (NULL==pAV->m_pIDataObject)
+ break;
+
+ fe.tymed=TYMED_HGLOBAL | TYMED_GDI
+ | TYMED_MFPICT;
+
+ pAV->TryQueryGetData(&fe, CF_TEXT, TRUE, 0);
+ pAV->TryQueryGetData(&fe, CF_BITMAP, TRUE, 1);
+#ifdef NOT_SIMPLE
+ pAV->TryQueryGetData(&fe, CF_DIB, FALSE, 2);
+ pAV->TryQueryGetData(&fe, CF_METAFILEPICT, TRUE, 3);
+ pAV->TryQueryGetData(&fe, CF_WAVE, FALSE, 4);
+#endif /* NOT_SIMPLE */
+ break;
+
+
+ case IDM_OBJECTGETDATA_TEXT:
+ case IDM_OBJECTGETDATA_BITMAP:
+#ifdef NOT_SIMPLE
+ case IDM_OBJECTGETDATA_METAFILEPICT:
+#endif /* NOT_SIMPLE */
+ if (pAV->m_GetData(wID) )
+ {
+ InvalidateRect(hWnd, NULL, TRUE);
+ UpdateWindow(hWnd);
+ }
+
+ if(pAV->m_fDisplayTime)
+ pAV->m_DisplayTimerResults();
+ break;
+
+ case IDM_OBJECTGETDATAHERE_TEXT:
+ case IDM_OBJECTGETDATAHERE_NULLTEXT:
+ case IDM_OBJECTGETDATAHERE_BITMAP:
+ case IDM_OBJECTGETDATAHERE_NULLBITMAP:
+ if (pAV->m_GetDataHere(wID) )
+ {
+ InvalidateRect(hWnd, NULL, TRUE);
+ UpdateWindow(hWnd);
+ }
+
+ if(pAV->m_fDisplayTime)
+ pAV->m_DisplayTimerResults();
+ break;
+
+ case IDM_OBJECTSETDATAPUNK_TEXT:
+ case IDM_OBJECTSETDATAPUNK_BITMAP:
+ pAV->m_SetData_WithPUnk(wID);
+ break;
+
+ case IDM_MEASUREMENT_1:
+ case IDM_MEASUREMENT_50:
+ case IDM_MEASUREMENT_300:
+ case IDM_MEASUREMENT_OFF:
+ case IDM_MEASUREMENT_ON:
+ case IDM_MEASUREMENT_TEST:
+ pAV->m_SetMeasurement(wID);
+ break;
+
+ case IDM_BATCH_GETDATA:
+ pAV->m_MeasureAllSizes(IDM_OBJECTGETDATA_TEXT,
+ TEXT("GetData w/HGLOBAL"),
+ NULL);
+ break;
+
+ case IDM_BATCH_GETDATAHERE:
+ pAV->m_MeasureAllSizes(IDM_OBJECTGETDATAHERE_TEXT,
+ TEXT("GetDataHere w/HGLOBAL"),
+ NULL);
+ break;
+
+ case IDM_BATCHTOFILE:
+ pAV->m_BatchToFile();
+ break;
+
+ case IDM_OBJECTEXIT:
+ PostMessage(hWnd, WM_CLOSE, 0, 0L);
+ break;
+
+#ifdef NOT_SIMPLE
+ case IDM_ADVISETEXT:
+ case IDM_ADVISEBITMAP:
+ case IDM_ADVISEMETAFILEPICT:
+ if (NULL==pAV->m_pIDataObject)
+ break;
+
+ //Terminate the old connection
+ if (0!=pAV->m_dwConn)
+ {
+ pAV->m_pIDataObject->DUnadvise(pAV
+ ->m_dwConn);
+ }
+
+ CheckMenuItem(hMenu, pAV->m_cfAdvise
+ +IDM_ADVISEMIN, MF_UNCHECKED);
+ CheckMenuItem(hMenu, wID, MF_CHECKED);
+
+ //New format is wID-IDM_ADVISEMIN
+ pAV->m_cfAdvise=(UINT)(wID-IDM_ADVISEMIN);
+ fe.cfFormat=pAV->m_cfAdvise;
+ pAV->m_pIDataObject->DAdvise(&fe, ADVF_NODATA
+ , pAV->m_pIAdviseSink, &pAV->m_dwConn);
+
+ break;
+
+ case IDM_ADVISEGETDATA:
+ pAV->m_fGetData=!pAV->m_fGetData;
+ CheckMenuItem(hMenu, wID, pAV->m_fGetData
+ ? MF_CHECKED : MF_UNCHECKED);
+ break;
+
+ case IDM_ADVISEREPAINT:
+ pAV->m_fRepaint=!pAV->m_fRepaint;
+ CheckMenuItem(hMenu, wID, pAV->m_fRepaint
+ ? MF_CHECKED : MF_UNCHECKED);
+ break;
+#endif /* NOT_SIMPLE*/
+ default:
+ break;
+ }
+ break;
+
+ default:
+ return (DefWindowProc(hWnd, iMsg, wParam, lParam));
+ }
+
+ return 0L;
+ }
+
+
+/*
+ * CAppVars::CAppVars
+ * CAppVars::~CAppVars
+ *
+ * Constructor Parameters: (from WinMain)
+ * hInst HINSTANCE of the application.
+ * hInstPrev HINSTANCE of a previous instance.
+ * nCmdShow UINT specifying how to show the app window.
+ */
+
+CAppVars::CAppVars(HINSTANCE hInst, HINSTANCE hInstPrev
+ , UINT nCmdShow)
+ {
+ m_hInst =hInst;
+ m_hInstPrev =hInstPrev;
+ m_nCmdShow =nCmdShow;
+
+ m_hWnd =NULL;
+#ifdef NOT_SIMPLE
+ m_fEXE =FALSE;
+
+ m_pIAdviseSink =NULL;
+ m_dwConn =0;
+ m_cfAdvise =0;
+ m_fGetData =FALSE;
+ m_fRepaint =FALSE;
+
+ m_pIDataSmall =NULL;
+ m_pIDataMedium=NULL;
+ m_pIDataLarge =NULL;
+#endif /* NOT_SIMPLE */
+ m_pIDataObject=NULL;
+ m_f16Bit=FALSE;
+ m_cfFormat=0;
+ m_stm.tymed=TYMED_NULL;
+ m_stm.lpszFileName=NULL; //Initializes union to NULL
+ m_stm.pUnkForRelease=NULL;
+
+ m_HereAllocCount=0; // For debugging
+
+ m_fInitialized=FALSE;
+ return;
+ }
+
+
+
+CAppVars::~CAppVars(void)
+ {
+ //This releases the data object interfaces and advises
+ FReloadDataObjects(FALSE);
+
+ ReleaseStgMedium(&m_stm);
+
+#ifdef NOT_SIMPLE
+ if (NULL!=m_pIAdviseSink)
+ m_pIAdviseSink->Release();
+#endif /* NOT_SIMPLE */
+
+ if (IsWindow(m_hWnd))
+ DestroyWindow(m_hWnd);
+
+ if (m_fInitialized)
+ CoUninitialize();
+
+ return;
+ }
+
+
+
+/*
+ * CAppVars::FInit
+ *
+ * Purpose:
+ * Initializes an CAppVars object by registering window classes,
+ * creating the main window, and doing anything else prone to
+ * failure such as calling CoInitialize. If this function fails
+ * the caller should insure that the destructor is called.
+ *
+ * Parameters:
+ * None
+ *
+ * Return Value:
+ * BOOL TRUE if successful, FALSE otherwise.
+ */
+
+BOOL CAppVars::FInit(void)
+ {
+ WNDCLASS wc;
+ DWORD dwVer;
+ BOOL fRet;
+
+ dwVer=CoBuildVersion();
+
+ if (rmm!=HIWORD(dwVer))
+ return FALSE;
+
+ if (FAILED(CoInitialize(NULL)))
+ return FALSE;
+
+ m_fInitialized=TRUE;
+
+ //Register our window classes.
+ if (!m_hInstPrev)
+ {
+ wc.style = CS_HREDRAW | CS_VREDRAW;
+ wc.lpfnWndProc = DataUserWndProc;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = CBWNDEXTRA;
+ wc.hInstance = m_hInst;
+ wc.hIcon = LoadIcon(m_hInst, TEXT("Icon"));
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
+ wc.lpszMenuName = MAKEINTRESOURCE(IDR_MENU);
+ wc.lpszClassName = TEXT("DATAUSER");
+
+ if (!RegisterClass(&wc))
+ return FALSE;
+ }
+
+ //Create the main window.
+ m_hWnd=CreateWindow(TEXT("DATAUSER"),
+ APP_TITLE,
+ WS_OVERLAPPEDWINDOW,
+ 35, 35, 350, 250,
+ NULL, NULL,
+ m_hInst, this);
+
+ if (NULL==m_hWnd)
+ return FALSE;
+
+ ShowWindow(m_hWnd, m_nCmdShow);
+ UpdateWindow(m_hWnd);
+
+ m_iDataSizeIndex=1;
+ CheckMenuItem(GetMenu(m_hWnd), IDM_OBJECTSETDATA+1, MF_CHECKED);
+ for(int i=0; i<64; i++)
+ m_hgHereBuffers[i] = NULL;
+
+ m_cIterations = 1;
+ CheckMenuItem(GetMenu(m_hWnd), IDM_MEASUREMENT_1, MF_CHECKED);
+
+ m_fDisplayTime = FALSE;
+ CheckMenuItem(GetMenu(m_hWnd), IDM_MEASUREMENT_OFF, MF_CHECKED);
+
+#ifdef NOT_SIMPLE
+ m_pIAdviseSink=new CImpIAdviseSink(this);
+
+ if (NULL==m_pIAdviseSink)
+ return FALSE;
+
+ m_pIAdviseSink->AddRef();
+
+ CheckMenuItem(GetMenu(m_hWnd), IDM_OBJECTUSEDLL, MF_CHECKED);
+ CheckMenuItem(GetMenu(m_hWnd), IDM_OBJECTDATASIZESMALL
+ , MF_CHECKED);
+#endif /* NOT_SIMPLE */
+
+ //Load the initial objects
+ fRet=FReloadDataObjects(TRUE);
+#ifdef NOT_SIMPLE
+ m_pIDataObject=m_pIDataSmall;
+#endif /* NOT_SIMPLE */
+
+ m_swTimer.m_ClassInit();
+
+ return fRet;
+ }
+
+
+/*
+ * CAppVars::FReloadDataObjects
+ *
+ * Purpose:
+ * Releases the old data objects we're holding on to and reloads
+ * the new ones from either EXE or DLL depending on m_fEXE.
+ *
+ * Parameters:
+ * fReload BOOL indicating if we are to recreate everything
+ * or just release the old ones (so we can use this
+ * from the destructor).
+ *
+ * Return Value:
+ * BOOL TRUE if there are usable objects in us now.
+ */
+
+BOOL CAppVars::FReloadDataObjects(BOOL fReload)
+ {
+ HCURSOR hCur, hCurT;
+
+ //Clean out any data we're holding
+ m_cfFormat=0;
+ ReleaseStgMedium(&m_stm);
+
+ //Turn off whatever data connection we have
+#ifdef NOT_SIMPLE
+ if (NULL!=m_pIDataObject && 0!=m_dwConn)
+ m_pIDataObject->DUnadvise(m_dwConn);
+
+ if (NULL!=m_pIDataLarge)
+ m_pIDataLarge->Release();
+
+ if (NULL!=m_pIDataMedium)
+ m_pIDataMedium->Release();
+
+ if (NULL!=m_pIDataSmall)
+ m_pIDataSmall->Release();
+#else /* IS SIMPLE */
+ if (NULL != m_pIDataObject)
+ m_pIDataObject->Release();
+#endif /* NOT_SIMPLE */
+
+ m_pIDataObject=NULL;
+ CoFreeUnusedLibraries();
+
+ //Exit if we just wanted to free.
+ if (!fReload)
+ return FALSE;
+
+
+ hCur=LoadCursor(NULL, MAKEINTRESOURCE(IDC_WAIT));
+ hCurT=SetCursor(hCur);
+ ShowCursor(TRUE);
+
+#ifdef NOT_SIMPLE
+ HRESULT hr1, hr2, hr3;
+ DWORD dwClsCtx;
+
+ dwClsCtx=(m_fEXE) ? CLSCTX_LOCAL_SERVER : CLSCTX_INPROC_SERVER;
+
+ hr1=CoCreateInstance(CLSID_DataObjectSmall, NULL, dwClsCtx
+ , IID_IDataObject, (PPVOID)&m_pIDataSmall);
+
+ hr2=CoCreateInstance(CLSID_DataObjectMedium, NULL, dwClsCtx
+ , IID_IDataObject, (PPVOID)&m_pIDataMedium);
+
+ hr3=CoCreateInstance(CLSID_DataObjectLarge, NULL, dwClsCtx
+ , IID_IDataObject, (PPVOID)&m_pIDataLarge);
+#else /* IS SIMPLE */
+ HRESULT hr;
+
+ if(m_f16Bit)
+ {
+ hr = CoCreateInstance(CLSID_DataObjectTest16,
+ NULL,
+ CLSCTX_LOCAL_SERVER,
+ IID_IDataObject,
+ (PPVOID)&m_pIDataObject);
+ }else
+ {
+ hr = CoCreateInstance(CLSID_DataObjectTest32,
+ NULL,
+ CLSCTX_LOCAL_SERVER,
+ IID_IDataObject,
+ (PPVOID)&m_pIDataObject);
+ }
+
+#endif /* NOT_SIMPLE */
+
+ ShowCursor(FALSE);
+ SetCursor(hCurT);
+
+ //If anything fails, recurse to clean up...
+#ifdef NOT_SIMPLE
+ if (FAILED(hr1) || FAILED(hr2) || FAILED(hr3))
+#else /* IS SIMPLE */
+ if (FAILED(hr))
+#endif /* NOT_SIMPLE */
+ {
+ perror_OKBox(0, TEXT("CoCreateInstance Failed: "), hr);
+ return FReloadDataObjects(FALSE);
+ }
+
+ HMENU hMenu = GetMenu(m_hWnd);
+ UINT uTempD, uTempE;
+
+ if(m_f16Bit)
+ {
+ CheckMenuItem(hMenu, IDM_USE16BITSERVER, MF_CHECKED);
+ CheckMenuItem(hMenu, IDM_USE32BITSERVER, MF_UNCHECKED);
+ }
+ else
+ {
+ CheckMenuItem(hMenu, IDM_USE16BITSERVER, MF_UNCHECKED);
+ CheckMenuItem(hMenu, IDM_USE32BITSERVER, MF_CHECKED);
+ }
+
+
+ hMenu=GetMenu(m_hWnd);
+ for(int i=IDM_OBJECTSETDATA; i<=IDM_OBJECTSETDATA+64; i++)
+ {
+ CheckMenuItem(hMenu, i, MF_UNCHECKED);
+ }
+ m_iDataSizeIndex = 1;
+ CheckMenuItem(hMenu,
+ IDM_OBJECTSETDATA + m_iDataSizeIndex,
+ MF_CHECKED);
+
+ //Reset the state of the menus for Small, no advise, no options.
+#ifdef NOT_SIMPLE
+ CheckMenuItem(hMenu, IDM_OBJECTDATASIZESMALL, MF_CHECKED);
+ CheckMenuItem(hMenu, IDM_OBJECTDATASIZEMEDIUM, MF_UNCHECKED);
+ CheckMenuItem(hMenu, IDM_OBJECTDATASIZELARGE, MF_UNCHECKED);
+
+ m_pIDataObject=m_pIDataSmall;
+ CheckMenuItem(hMenu, m_cfAdvise+IDM_ADVISEMIN, MF_UNCHECKED);
+
+ uTempE=m_fEXE ? MF_CHECKED : MF_UNCHECKED;
+ uTempD=!m_fEXE ? MF_CHECKED : MF_UNCHECKED;
+
+ CheckMenuItem(hMenu, IDM_OBJECTUSEDLL, uTempD);
+ CheckMenuItem(hMenu, IDM_OBJECTUSEEXE, uTempE);
+
+ CheckMenuItem(hMenu, IDM_ADVISEGETDATA, MF_UNCHECKED);
+ CheckMenuItem(hMenu, IDM_ADVISEREPAINT, MF_UNCHECKED);
+
+ m_fGetData=FALSE;
+ m_fRepaint=FALSE;
+
+ //Cannot request data using async advises, so disable these.
+ uTempE=m_fEXE ? MF_DISABLED | MF_GRAYED : MF_ENABLED;
+ EnableMenuItem(hMenu, IDM_ADVISEGETDATA, uTempE);
+ EnableMenuItem(hMenu, IDM_ADVISEREPAINT, uTempE);
+#endif /* NOT_SIMPLE */
+ return TRUE;
+ }
+
+
+
+/*
+ * CAppVars::TryQueryGetData
+ *
+ * Purpose:
+ * Centralized function call and output code for displaying results
+ * of various IDataObject::QueryGetData calls.
+ *
+ * Parameters:
+ * pFE LPFORMATETC to test.
+ * cf UINT specific clipboard format to stuff in pFE
+ * before calling. If zero, use whatever is
+ * already in pFE.
+ * fExpect BOOL indicating expected results
+ * y UINT line on which to print results.
+ *
+ * Return Value:
+ * None
+ */
+
+void CAppVars::TryQueryGetData(LPFORMATETC pFE, UINT cf
+ , BOOL fExpect, UINT y)
+ {
+ TCHAR szTemp[80];
+ LPTSTR psz1;
+ LPTSTR psz2;
+ UINT cch;
+ HRESULT hr;
+ HDC hDC;
+
+ if (0!=cf)
+ pFE->cfFormat=cf;
+
+ hr=m_pIDataObject->QueryGetData(pFE);
+ psz1=(NOERROR==hr) ? szSuccess : szFailed;
+ psz2=((NOERROR==hr)==fExpect) ? szExpected : szUnexpected;
+
+ hDC=GetDC(m_hWnd);
+ SetTextColor(hDC, GetSysColor(COLOR_WINDOWTEXT));
+ SetBkColor(hDC, GetSysColor(COLOR_WINDOW));
+
+ if (CF_WAVE < cf || 0==cf)
+ {
+ cch=wsprintf(szTemp, TEXT("QueryGetData on %d %s (%s).")
+ , cf, psz1, psz2);
+ }
+ else
+ {
+ cch=wsprintf(szTemp, TEXT("QueryGetData on %s %s (%s).")
+ , (LPTSTR)rgszCF[cf], psz1, psz2);
+ }
+
+ //Don't overwrite other painted display.
+ SetBkMode(hDC, TRANSPARENT);
+ TextOut(hDC, 0, 16*y, szTemp, cch);
+
+ ReleaseDC(m_hWnd, hDC);
+
+ return;
+ }
+
+
+int
+CAppVars::m_GetData(WORD wID)
+{
+ FORMATETC fe;
+ HRESULT hr;
+
+ if (NULL == m_pIDataObject)
+ return(0); // Don't redraw.
+
+ //Clean up whatever we currently have.
+ m_cfFormat = 0;
+ ReleaseStgMedium(&m_stm);
+
+ switch (wID)
+ {
+ case IDM_OBJECTGETDATA_TEXT:
+ SETDefFormatEtc(fe, CF_TEXT, TYMED_HGLOBAL);
+ break;
+
+#ifdef NOT_SIMPLE
+ case IDM_OBJECTGETDATA_BITMAP:
+ SETDefFormatEtc(fe, CF_BITMAP, TYMED_GDI);
+ break;
+
+ case IDM_OBJECTGETDATA_METAFILEPICT:
+ SETDefFormatEtc(fe, CF_METAFILEPICT, TYMED_MFPICT);
+ break;
+#endif /* NOT_SIMPLE */
+
+ default:
+ MessageBox(0,
+ TEXT("Type is Unsupported in the Client"),
+ TEXT("GetData"),
+ MB_OK);
+ return(0);
+ }
+
+ m_swTimer.m_Start();
+ HRESULT didfail = NOERROR;
+
+ for(int i=0; i<m_cIterations; i++)
+ {
+ hr = m_pIDataObject->GetData(&fe, &m_stm);
+ if (SUCCEEDED(hr))
+ {
+ // If we are just whacking off for the benchmark.
+ // Then release all but the last one we recieve.
+ if(i < m_cIterations-1)
+ ReleaseStgMedium(&m_stm);
+ }
+ else
+ didfail = hr;
+ }
+ m_swTimer.m_Stop();
+
+ if (SUCCEEDED(didfail))
+ m_cfFormat=fe.cfFormat;
+ else
+ {
+ perror_OKBox(0,
+ TEXT("GetData Failed"),
+ didfail);
+ }
+
+ return(1); // Do redraw even if it failed (draw blank).
+}
+
+
+int
+CAppVars::m_GetDataHere(WORD wID)
+{
+ FORMATETC fe;
+ HRESULT hr;
+
+ if(NULL == m_pIDataObject)
+ return(0); // Don't redraw
+
+ m_cfFormat = 0;
+
+ // Don't Release the STGMedium. We recycle them!
+
+ switch(wID)
+ {
+ case IDM_OBJECTGETDATAHERE_TEXT:
+ SETDefFormatEtc(fe, CF_TEXT, TYMED_HGLOBAL);
+ break;
+
+ case IDM_OBJECTGETDATAHERE_NULLTEXT:
+ SETDefFormatEtc(fe, CF_TEXT, TYMED_NULL);
+ break;
+
+ /* Other cases go here.... */
+
+ default:
+ MessageBox(0,
+ TEXT("Type is Unsupported in the Client"),
+ TEXT("GetDataHere"),
+ MB_OK);
+ return(0);
+ }
+
+ HGLOBAL* phg = &m_hgHereBuffers[m_iDataSizeIndex];
+ if(NULL == *phg)
+ {
+ ++m_HereAllocCount;
+ *phg = GlobalAlloc(GMEM_SHARE | GMEM_MOVEABLE,
+ DATASIZE_FROM_INDEX(m_iDataSizeIndex) );
+ if(NULL == *phg)
+ {
+ MessageBox(0,
+ TEXT("GlobalAlloc Return NULL"),
+ TEXT("Failure"),
+ MB_OK);
+ PostQuitMessage(0);
+ return(0); // Don't redraw
+ }
+ }
+
+ m_stm.hGlobal=*phg;
+ m_stm.tymed=TYMED_HGLOBAL;
+ m_stm.pUnkForRelease=NULL;
+
+ // The TYMED_NULL case tests code in olethk where it is written:
+ // "If tymed == TYMED_NULL then GetDataHere should behave like GetData."
+ // I can't find this in any manual (OLE2 or Ole). I wanted to see what
+ // good that code was. (there is also bug #15974) Aug 8th 1995 BChapman.
+
+ if (IDM_OBJECTGETDATAHERE_NULLTEXT == wID)
+ {
+ m_stm.hGlobal=NULL;
+ m_stm.tymed=TYMED_NULL;
+ }
+
+ // The other side "knows" the size of the data.
+ // (It is told via. SetData)
+
+ HRESULT didfail = NOERROR;
+ m_swTimer.m_Start();
+ for(int i=0; i<m_cIterations; i++)
+ {
+ hr = m_pIDataObject->GetDataHere(&fe, &m_stm);
+ if (FAILED(hr))
+ didfail = hr;
+ // We don't ReleaseSTGMedium because this
+ // is GetDataHere !
+ }
+ m_swTimer.m_Stop();
+
+ if (SUCCEEDED(didfail))
+ m_cfFormat=fe.cfFormat;
+ else
+ {
+ perror_OKBox(0,
+ TEXT("GetDataHere Failed"),
+ didfail);
+ }
+ return(1); // redraw (if FAILED(hr) then draw blank)
+}
+
+
+int
+CAppVars::m_SetData_SetSize(long iSizeIndex)
+{
+ FORMATETC fe;
+ HRESULT hr;
+
+ if (NULL == m_pIDataObject)
+ return 0;
+
+ SETDefFormatEtc(fe, CF_TEXT, TYMED_HGLOBAL);
+
+ m_iDataSizeIndex = iSizeIndex;
+
+ HGLOBAL hMem=GlobalAlloc(GMEM_SHARE | GMEM_MOVEABLE, sizeof(ULONG) );
+ if(NULL == hMem)
+ {
+ MessageBox(0,
+ TEXT("GlobalAlloc Return NULL"),
+ TEXT("Failure"),
+ MB_OK);
+ PostQuitMessage(0);
+ return 0;
+ }
+
+ long* pl=(long*)GlobalLock(hMem); // Lock
+ *((long*)pl) = DATASIZE_FROM_INDEX(m_iDataSizeIndex);
+ GlobalUnlock(hMem); // Unlock
+
+ m_stm.hGlobal=hMem;
+ m_stm.tymed=TYMED_HGLOBAL;
+ m_stm.pUnkForRelease=NULL;
+
+ hr = m_pIDataObject->SetData(&fe, &m_stm, FALSE); // Keep Ownership.
+ if (FAILED(hr))
+ {
+ perror_OKBox(0,
+ TEXT("SetData Failed"),
+ hr);
+ return 0;
+ }
+ return 1;;
+ // release the hMem HGLOBAL perhaps ???
+}
+
+
+int
+CAppVars::m_SetData_WithPUnk(WORD wID)
+{
+ FORMATETC fe;
+ HRESULT hr;
+
+ if(NULL == m_pIDataObject)
+ return 0;
+
+ switch(wID)
+ {
+ case IDM_OBJECTSETDATAPUNK_TEXT:
+ SETDefFormatEtc(fe, CF_TEXT, TYMED_HGLOBAL);
+ break;
+
+ /* Other cases go here.... */
+
+ default:
+ MessageBox(0,
+ TEXT("Type is Unsupported in the Client"),
+ TEXT("SetData"),
+ MB_OK);
+ return(0);
+ }
+
+ HGLOBAL hMem=GlobalAlloc( GMEM_SHARE | GMEM_MOVEABLE, sizeof(ULONG) );
+ if(NULL == hMem)
+ {
+ MessageBox(0,
+ TEXT("GlobalAlloc Return NULL"),
+ TEXT("Failure"),
+ MB_OK);
+ PostQuitMessage(0);
+ return 0;
+ }
+
+ long* pl=(long*)GlobalLock(hMem); // Lock
+ *((long*)pl) = 0xffffffff; // Use
+ GlobalUnlock(hMem); // Unlock
+
+
+ m_stm.hGlobal=hMem;
+ m_stm.tymed=TYMED_HGLOBAL;
+ hr = GetStgMedpUnkForRelease(&m_stm.pUnkForRelease);
+ if(NOERROR != hr)
+ {
+ perror_OKBox(0, TEXT("Can't get pUnk For Release"), hr);
+ }
+
+ hr = m_pIDataObject->SetData(&fe, &m_stm, TRUE); // Pass Ownership.
+ // We passed ownership so SetData took the HGLOBAL from us.
+ if (FAILED(hr))
+ {
+ perror_OKBox(0,
+ TEXT("SetData Failed"),
+ hr);
+ return 0;
+ }
+ return 1;
+}
+
+#define NUM_RUNS 5
+
+
+void
+CAppVars::m_BatchToFile()
+{
+ dataset_t dsGetDataText;
+ dataset_t dsGetDataHereText;
+
+ pm_ClearDataset(&dsGetDataText);
+ pm_ClearDataset(&dsGetDataHereText);
+
+ int iRun;
+ for(iRun=0; iRun < NUM_RUNS; iRun++)
+ {
+ m_MeasureAllSizes(IDM_OBJECTGETDATA_TEXT,
+ NULL,
+ &dsGetDataText);
+ m_MeasureAllSizes(IDM_OBJECTGETDATAHERE_TEXT,
+ NULL,
+ &dsGetDataHereText);
+ }
+
+ FILE *fp;
+ int i;
+ if(NULL == (fp = fopen(FILENAME, "w")))
+ {
+ MessageBox(0, TEXT("Cannot Open Output File"),
+ TEXT(FILENAME),
+ MB_OK | MB_ICONSTOP);
+ return;
+ }
+
+ fprintf(fp, " GetData w/ HGLOBAL GetDataHere w/ HGLOBAL\n");
+ fprintf(fp, " Size Best Worst Average Best Worst Average\n");
+ for (i=0; i<NUM_POINTS; i++)
+ {
+ fprintf(fp, "%5d\t", cKSizes[i]);
+#define PR_TIME(fp, v) (fprintf(fp, "%3lu.%03lu\t", (v)/1000, (v)%1000))
+
+ PR_TIME(fp, dsGetDataText.cBest[i]);
+ PR_TIME(fp, dsGetDataText.cWorst[i]);
+ PR_TIME(fp, dsGetDataText.cTotal[i]/NUM_RUNS);
+ PR_TIME(fp, dsGetDataHereText.cBest[i]);
+ PR_TIME(fp, dsGetDataHereText.cWorst[i]);
+ PR_TIME(fp, dsGetDataHereText.cTotal[i]/NUM_RUNS);
+ fprintf(fp, "\n");
+ }
+ fclose(fp);
+
+ MessageBox(0, TEXT("Output Written to file.dat!"),
+ TEXT("Done"), MB_OK);
+}
+
+void
+CAppVars::pm_ClearDataset(dataset_t *ds)
+{
+ int i;
+ for(i=0; i<NUM_POINTS; i++)
+ {
+ ds->cTotal[i] = 0;
+ ds->cBest[i] = 0xFFFFFFFF;
+ ds->cWorst[i] = 0;
+ }
+}
+
+
+void
+CAppVars::m_MeasureAllSizes(
+ WORD wID,
+ LPTSTR tstrTitle,
+ dataset_t *ds)
+{
+ int i;
+ ULONG cUSecs[NUM_POINTS];
+
+ // Save some state.
+ ULONG iOldDataSizeIndex = m_iDataSizeIndex;
+
+ for (i=0; i<NUM_POINTS; i++)
+ {
+ m_SetData_SetSize(cKSizes[i]);
+
+ switch(wID)
+ {
+ case IDM_OBJECTGETDATA_TEXT:
+ case IDM_OBJECTGETDATA_BITMAP:
+ m_GetData(wID);
+ break;
+
+ case IDM_OBJECTGETDATAHERE_TEXT:
+ case IDM_OBJECTGETDATAHERE_BITMAP:
+ m_GetDataHere(wID);
+ break;
+ }
+ m_swTimer.m_Read(&cUSecs[i]);
+ cUSecs[i] /= m_cIterations;
+ }
+
+ // Restore save state.
+ m_iDataSizeIndex = iOldDataSizeIndex;
+ m_SetData_SetSize(m_iDataSizeIndex);
+
+
+ // If the caller provided memory then return the data in it.
+ if(NULL != ds)
+ {
+ for (i=0; i<NUM_POINTS; i++)
+ {
+ ds->cData[i] = cUSecs[i];
+ ds->cTotal[i] += cUSecs[i];
+
+ if(ds->cBest[i] > cUSecs[i])
+ ds->cBest[i] = cUSecs[i];
+ if( ds->cWorst[i] < cUSecs[i])
+ ds->cWorst[i] = cUSecs[i];
+ }
+ }
+
+ // If the caller passed a NULL Title then no message box.
+ if(NULL == tstrTitle)
+ return;
+
+ // Render Results.
+ LPTSTR tstr = &tcMessageBuf[0];
+ for (i=0; i<NUM_POINTS; i++)
+ {
+ wsprintf(tstr, TEXT("%dK: %lu.%03lu%c"),
+ cKSizes[i], cUSecs[i]/1000, cUSecs[i]%1000,
+ (i%4==3)? TEXT('\n'):TEXT('\t') );
+ tstr += lstrlen(tstr);
+ }
+ MessageBox(0, tcMessageBuf, tstrTitle, MB_OK);
+}
+
+
+
+void
+CAppVars::m_SetMeasurement(WORD wID)
+{
+ HMENU hMenu=GetMenu(m_hWnd);
+ switch (wID)
+ {
+ case IDM_MEASUREMENT_ON:
+ m_fDisplayTime = TRUE;
+ CheckMenuItem(hMenu, IDM_MEASUREMENT_ON, MF_CHECKED);
+ CheckMenuItem(hMenu, IDM_MEASUREMENT_OFF, MF_UNCHECKED);
+ break;
+
+ case IDM_MEASUREMENT_OFF:
+ m_fDisplayTime = FALSE;
+ CheckMenuItem(hMenu, IDM_MEASUREMENT_ON, MF_UNCHECKED);
+ CheckMenuItem(hMenu, IDM_MEASUREMENT_OFF, MF_CHECKED);
+ break;
+
+
+ case IDM_MEASUREMENT_1:
+ m_cIterations = 1;
+ goto set_menu;
+ case IDM_MEASUREMENT_50:
+ m_cIterations = 50;
+ goto set_menu;
+ case IDM_MEASUREMENT_300:
+ m_cIterations = 300;
+ goto set_menu;
+set_menu:
+ CheckMenuItem(hMenu, IDM_MEASUREMENT_1, MF_UNCHECKED);
+ CheckMenuItem(hMenu, IDM_MEASUREMENT_50, MF_UNCHECKED);
+ CheckMenuItem(hMenu, IDM_MEASUREMENT_300, MF_UNCHECKED);
+ CheckMenuItem(hMenu, wID, MF_CHECKED);
+ break;
+
+
+ case IDM_MEASUREMENT_TEST:
+ m_swTimer.m_Start();
+ m_swTimer.m_Sleep(777);
+ m_swTimer.m_Stop();
+ m_DisplayTimerResults();
+ break;
+ }
+}
+
+void
+CAppVars::m_DisplayTimerResults()
+{
+ ULONG usecs;
+ m_swTimer.m_Read(&usecs);
+ usecs /= m_cIterations;
+ wprintf_OKBox(0, TEXT("MilliSeconds"),
+ TEXT("%lu.%03lu"),
+ usecs/1000, usecs%1000);
+}
+
+
+/*
+ * CAppVars::Paint
+ *
+ * Purpose:
+ * Handles WM_PAINT for the main window by drawing whatever
+ * data we have sitting in the STGMEDIUM at this time.
+ *
+ * Parameters:
+ * None
+ *
+ * Return Value:
+ * None
+ */
+
+void CAppVars::Paint(void)
+ {
+ PAINTSTRUCT ps;
+ HDC hDC;
+#ifdef NOT_SIMPLE
+ HDC hMemDC;
+ LPMETAFILEPICT pMF;
+#endif /* NOT_SIMPLE */
+ LPTSTR psz;
+ RECT rc;
+ FORMATETC fe;
+
+ GetClientRect(m_hWnd, &rc);
+
+ hDC=BeginPaint(m_hWnd, &ps);
+
+ //May need to retrieve the data with EXE objects
+#ifdef NOT_SIMPLE
+ if (m_fEXE)
+ {
+ if (TYMED_NULL==m_stm.tymed && 0!=m_cfFormat)
+ {
+ SETDefFormatEtc(fe, m_cfFormat, TYMED_HGLOBAL
+ | TYMED_MFPICT | TYMED_GDI);
+
+ if (NULL!=m_pIDataObject)
+ m_pIDataObject->GetData(&fe, &m_stm);
+ }
+ }
+#endif /* NOT_SIMPLE */
+
+ switch (m_cfFormat)
+ {
+ case CF_TEXT:
+ psz=(LPTSTR)GlobalLock(m_stm.hGlobal);
+
+ if (NULL==psz)
+ break;
+
+ SetTextColor(hDC, GetSysColor(COLOR_WINDOWTEXT));
+ SetBkColor(hDC, GetSysColor(COLOR_WINDOW));
+
+ pm_DrawText(hDC, psz, &rc, DT_LEFT | DT_WORDBREAK);
+
+ GlobalUnlock(m_stm.hGlobal);
+ break;
+
+#ifdef NOT_SIMPLE
+ case CF_BITMAP:
+ hMemDC=CreateCompatibleDC(hDC);
+
+ if (NULL!=SelectObject(hMemDC, (HGDIOBJ)m_stm.hGlobal))
+ {
+ BitBlt(hDC, 0, 0, rc.right-rc.left, rc.bottom-rc.top
+ , hMemDC, 0, 0, SRCCOPY);
+ }
+
+ DeleteDC(hMemDC);
+ break;
+
+ case CF_METAFILEPICT:
+ pMF=(LPMETAFILEPICT)GlobalLock(m_stm.hGlobal);
+
+ if (NULL==pMF)
+ break;
+
+ SetMapMode(hDC, pMF->mm);
+ SetWindowOrgEx(hDC, 0, 0, NULL);
+ SetWindowExtEx(hDC, pMF->xExt, pMF->yExt, NULL);
+
+ SetViewportExtEx(hDC, rc.right-rc.left
+ , rc.bottom-rc.top, NULL);
+
+ PlayMetaFile(hDC, pMF->hMF);
+ GlobalUnlock(m_stm.hGlobal);
+ break;
+
+#else /* IS SIMPLE */
+ case CF_BITMAP:
+ case CF_METAFILEPICT:
+ DebugBreak();
+ break;
+
+#endif /* NOT_SIMPLE */
+
+ default:
+ break;
+ }
+
+ EndPaint(m_hWnd, &ps);
+ return;
+ }
+
+
+void
+CAppVars::pm_DrawText(
+ HDC hDC,
+ LPTSTR psz,
+ RECT* prc,
+ UINT flags)
+{
+ SetTextColor(hDC, GetSysColor(COLOR_WINDOWTEXT));
+ SetBkColor(hDC, GetSysColor(COLOR_WINDOW));
+
+// If we are WIN32 and the server is 16 bits this must be ASCII.
+#ifdef WIN32
+ if(m_f16Bit)
+ DrawTextA(hDC, (char*)psz, -1, prc, flags);
+ else
+#endif
+ DrawText(hDC, psz, -1, prc, flags);
+}
diff --git a/private/oleutest/perf16/idata/client/datausr.h b/private/oleutest/perf16/idata/client/datausr.h
new file mode 100644
index 000000000..aa3f5f0a9
--- /dev/null
+++ b/private/oleutest/perf16/idata/client/datausr.h
@@ -0,0 +1,226 @@
+/*
+ * DATAUSER.H
+ * Data Object User Chapter 6
+ *
+ * Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved
+ *
+ * Kraig Brockschmidt, Software Design Engineer
+ * Microsoft Systems Developer Relations
+ *
+ * Internet : kraigb@microsoft.com
+ * Compuserve: >INTERNET:kraigb@microsoft.com
+ */
+
+
+#ifndef _DATAUSER_H_
+#define _DATAUSER_H_
+
+#include "../syshead.h"
+#include "../my3216.h"
+#include "../bookpart.h"
+#include "stpwatch.h"
+
+
+//Menu Resource ID and Commands
+#define IDR_MENU 1
+
+
+// #define IDM_OBJECTUSEDLL 100
+// #define IDM_OBJECTUSEEXE 101
+// #define IDM_OBJECTDATASIZESMALL 102
+// #define IDM_OBJECTDATASIZEMEDIUM 103
+// #define IDM_OBJECTDATASIZELARGE 104
+#define IDM_OBJECTQUERYGETDATA 105
+#define IDM_OBJECTGETDATA_TEXT 106
+#define IDM_OBJECTGETDATA_BITMAP 107
+// #define IDM_OBJECTGETDATA_METAFILEPICT 108
+#define IDM_OBJECTEXIT 109
+
+#define IDM_OBJECTGETDATAHERE_TEXT 110
+#define IDM_OBJECTGETDATAHERE_BITMAP 111
+#define IDM_OBJECTGETDATAHERE_NULLTEXT 112
+#define IDM_OBJECTGETDATAHERE_NULLBITMAP 113
+
+#define IDM_USE16BITSERVER 120
+#define IDM_USE32BITSERVER 121
+
+#define IDM_OBJECTGETCANON 122
+
+// Reserve Range..
+#define IDM_OBJECTSETDATA 400
+// ....
+// reserved through 464
+
+#define IDM_OBJECTSETDATAPUNK_TEXT 500
+#define IDM_OBJECTSETDATAPUNK_BITMAP 501
+
+
+#define IDM_MEASUREMENT_1 140
+#define IDM_MEASUREMENT_50 141
+#define IDM_MEASUREMENT_300 142
+
+#define IDM_MEASUREMENT_OFF 145
+#define IDM_MEASUREMENT_ON 146
+#define IDM_MEASUREMENT_TEST 147
+
+#define IDM_BATCHTOFILE 150
+#define IDM_BATCH_GETDATA 151
+#define IDM_BATCH_GETDATAHERE 152
+
+// #define IDM_ADVISEMIN 200
+// #define IDM_ADVISETEXT (IDM_ADVISEMIN+CF_TEXT)
+// #define IDM_ADVISEBITMAP (IDM_ADVISEMIN+CF_BITMAP)
+// #define IDM_ADVISEMETAFILEPICT (IDM_ADVISEMIN+CF_METAFILEPICT)
+// #define IDM_ADVISEGETDATA 300
+// #define IDM_ADVISEREPAINT 301
+
+
+#ifdef WIN32
+ #define API_ENTRY APIENTRY
+#else
+ #define API_ENTRY FAR PASCAL _export
+#endif
+
+//DATAUSER.CPP
+LRESULT API_ENTRY DataUserWndProc(HWND, UINT, WPARAM, LPARAM);
+
+
+class CImpIAdviseSink;
+typedef class CImpIAdviseSink *PIMPIADVISESINK;
+
+
+
+#define FILENAME "time.dat"
+#define NUM_POINTS 15
+
+typedef struct {
+ ULONG cData[NUM_POINTS];
+ ULONG cBest[NUM_POINTS];
+ ULONG cWorst[NUM_POINTS];
+ ULONG cTotal[NUM_POINTS];
+} dataset_t;
+
+
+
+
+/*
+ * Application-defined classes and types.
+ */
+
+class CAppVars
+ {
+ friend LRESULT API_ENTRY DataUserWndProc(HWND, UINT, WPARAM, LPARAM);
+
+ friend class CImpIAdviseSink;
+
+ protected:
+ HINSTANCE m_hInst; //WinMain parameters
+ HINSTANCE m_hInstPrev;
+ UINT m_nCmdShow;
+
+ HWND m_hWnd; //Main window handle
+// BOOL m_fEXE; //For tracking menu
+
+// PIMPIADVISESINK m_pIAdviseSink; //Our CImpIAdviseSink
+// DWORD m_dwConn; //Advise connection
+// UINT m_cfAdvise; //Advise format
+// BOOL m_fGetData; //GetData on data change?
+// BOOL m_fRepaint; //Repaint on data change?
+
+// LPDATAOBJECT m_pIDataSmall;
+// LPDATAOBJECT m_pIDataMedium;
+// LPDATAOBJECT m_pIDataLarge;
+
+ LPDATAOBJECT m_pIDataObject; //Current selection
+ UINT m_f16Bit;
+ UINT m_cfFormat;
+ STGMEDIUM m_stm; //Current rendering
+
+ BOOL m_fInitialized; //Did CoInitialize work?
+
+ ULONG m_iDataSizeIndex;
+ HGLOBAL m_hgHereBuffers[64];
+ BOOL m_fDisplayTime;
+ LONG m_cIterations;
+ StopWatch_cl m_swTimer;
+
+ int m_HereAllocCount; // For debugging.
+
+ public:
+ CAppVars(HINSTANCE, HINSTANCE, UINT);
+ ~CAppVars(void);
+ BOOL FInit(void);
+ BOOL FReloadDataObjects(BOOL);
+ void TryQueryGetData(LPFORMATETC, UINT, BOOL, UINT);
+ void Paint(void);
+
+ int m_GetDataHere(WORD wID);
+ int m_GetData(WORD wID);
+ int m_SetData_SetSize(long iSizeIndex);
+ int m_SetData_WithPUnk(WORD wID);
+ void m_SetMeasurement(WORD wID);
+ void m_MeasureAllSizes(WORD wID, LPTSTR title, dataset_t *);
+
+ void m_BatchToFile();
+ void m_DisplayTimerResults();
+
+ private:
+ void pm_DrawText(HDC hDc, LPTSTR psz, RECT* prc, UINT flags);
+ void pm_ClearDataset(dataset_t *);
+
+ };
+
+
+typedef CAppVars *PAPPVARS;
+
+#define CBWNDEXTRA sizeof(PAPPVARS)
+#define DATAUSERWL_STRUCTURE 0
+
+
+//This lives with the app to get OnDataChange notifications.
+
+class CImpIAdviseSink : public IAdviseSink
+ {
+ protected:
+ ULONG m_cRef;
+ PAPPVARS m_pAV;
+
+ public:
+ CImpIAdviseSink(PAPPVARS);
+ ~CImpIAdviseSink(void);
+
+ STDMETHODIMP QueryInterface(REFIID, PPVOID);
+ STDMETHODIMP_(ULONG) AddRef(void);
+ STDMETHODIMP_(ULONG) Release(void);
+
+ //We only implement OnDataChange for now.
+ STDMETHODIMP_(void) OnDataChange(LPFORMATETC, LPSTGMEDIUM);
+ STDMETHODIMP_(void) OnViewChange(DWORD, LONG);
+ STDMETHODIMP_(void) OnRename(LPMONIKER);
+ STDMETHODIMP_(void) OnSave(void);
+ STDMETHODIMP_(void) OnClose(void);
+ };
+
+
+
+//////////////////////////////////////////////////////////////////////////////
+// Storage Medium IUnknown interface for pUnkForRelease.
+//
+
+class CStgMedIf: public IUnknown {
+private:
+ ULONG m_cRef;
+public:
+ CStgMedIf();
+ STDMETHODIMP QueryInterface(REFIID, PPVOID);
+ STDMETHODIMP_(ULONG) AddRef(void);
+ STDMETHODIMP_(ULONG) Release(void);
+};
+
+//////////////////////////
+// API for getting a pUnkForRelease.
+//
+
+HRESULT GetStgMedpUnkForRelease(IUnknown **pp_unk);
+
+#endif //_DATAUSER_H_
diff --git a/private/oleutest/perf16/idata/client/datausr.ico b/private/oleutest/perf16/idata/client/datausr.ico
new file mode 100644
index 000000000..0c2fa257f
--- /dev/null
+++ b/private/oleutest/perf16/idata/client/datausr.ico
Binary files differ
diff --git a/private/oleutest/perf16/idata/client/idatausr.def b/private/oleutest/perf16/idata/client/idatausr.def
new file mode 100644
index 000000000..1ba2162d8
--- /dev/null
+++ b/private/oleutest/perf16/idata/client/idatausr.def
@@ -0,0 +1,9 @@
+NAME DATAUSER
+DESCRIPTION 'Data Object User Chapter 6 (c)1993 Microsoft Corp.'
+EXETYPE WINDOWS
+STUB 'WINSTUB.EXE'
+CODE PRELOAD MOVEABLE DISCARDABLE
+DATA PRELOAD MOVEABLE MULTIPLE
+
+HEAPSIZE 2048
+STACKSIZE 4096
diff --git a/private/oleutest/perf16/idata/client/idatausr.rc b/private/oleutest/perf16/idata/client/idatausr.rc
new file mode 100644
index 000000000..2d95453f4
--- /dev/null
+++ b/private/oleutest/perf16/idata/client/idatausr.rc
@@ -0,0 +1,120 @@
+/*
+ * DATAUSER.RC
+ * Data Object User Chapter 6
+ *
+ * Resource definitions
+ *
+ * Copyright (c)1993-1995 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 "datausr.h"
+
+
+Icon ICON "datausr.ico"
+
+
+IDR_MENU MENU MOVEABLE DISCARDABLE
+ BEGIN
+ POPUP "&Server"
+ BEGIN
+ MENUITEM "Use 16 bit server" IDM_USE16BITSERVER
+ MENUITEM "Use 32 bit server" IDM_USE32BITSERVER
+ MENUITEM SEPARATOR
+ MENUITEM "&Exit", IDM_OBJECTEXIT
+ END
+ POPUP "&IDataObject::"
+ BEGIN
+/*
+ MENUITEM "Use &DLL Object", IDM_OBJECTUSEDLL
+ MENUITEM "Use &EXE Object", IDM_OBJECTUSEEXE
+ MENUITEM SEPARATOR
+ POPUP "Data &Size"
+ BEGIN
+ MENUITEM "&Small", IDM_OBJECTDATASIZESMALL
+ MENUITEM "&Medium", IDM_OBJECTDATASIZEMEDIUM
+ MENUITEM "&Large", IDM_OBJECTDATASIZELARGE
+ END
+ */
+ POPUP "&GetData"
+ BEGIN
+ MENUITEM "&1 CF_TEXT", IDM_OBJECTGETDATA_TEXT
+ MENUITEM "&2 CF_BITMAP", IDM_OBJECTGETDATA_BITMAP
+/*
+ MENUITEM "&3 CF_METAFILEPICT", IDM_OBJECTGETDATA_METAFILEPICT
+ */
+ END
+ POPUP "GetData&Here"
+ BEGIN
+ MENUITEM "&1 CF_TEXT", IDM_OBJECTGETDATAHERE_TEXT
+ MENUITEM "&2 CF_BITMAP", IDM_OBJECTGETDATAHERE_BITMAP
+ END
+ POPUP "GetDataHere w/&Null"
+ BEGIN
+ MENUITEM "&1 CF_TEXT", IDM_OBJECTGETDATAHERE_NULLTEXT
+ MENUITEM "&2 CF_BITMAP", IDM_OBJECTGETDATAHERE_NULLBITMAP
+ END
+ MENUITEM "&QueryGetData", IDM_OBJECTQUERYGETDATA
+/*
+ MENUITEM "Get&CanonicalFormatEtc", IDM_OBJECTGETCANON
+*/
+ POPUP "(&Set Size)",
+ BEGIN
+ MENUITEM " 1K bytes" IDM_OBJECTSETDATA+1
+ MENUITEM " 2K bytes" IDM_OBJECTSETDATA+2
+ MENUITEM " 4K bytes" IDM_OBJECTSETDATA+4
+ MENUITEM " 8K bytes" IDM_OBJECTSETDATA+8
+ MENUITEM "12K bytes" IDM_OBJECTSETDATA+12
+ MENUITEM "14K bytes" IDM_OBJECTSETDATA+14
+ MENUITEM "16K bytes" IDM_OBJECTSETDATA+16
+ MENUITEM "20K bytes" IDM_OBJECTSETDATA+20
+ MENUITEM "24K bytes" IDM_OBJECTSETDATA+24
+ MENUITEM "28K bytes" IDM_OBJECTSETDATA+28
+ MENUITEM "32K bytes" IDM_OBJECTSETDATA+32
+ MENUITEM "40K bytes" IDM_OBJECTSETDATA+40
+ MENUITEM "48K bytes" IDM_OBJECTSETDATA+48
+ MENUITEM "56K bytes" IDM_OBJECTSETDATA+56
+ END
+ POPUP "SetData w/&pUnk",
+ BEGIN
+ MENUITEM "&1 CF_TEXT", IDM_OBJECTSETDATAPUNK_TEXT
+ MENUITEM "&2 CF_BITMAP", IDM_OBJECTSETDATAPUNK_BITMAP
+ END
+ END
+ POPUP "&Measurement"
+ BEGIN
+ MENUITEM "&1 Call", IDM_MEASUREMENT_1
+ MENUITEM "&50 Calls" IDM_MEASUREMENT_50
+ Menuitem "&300 Calls" IDM_MEASUREMENT_300
+ MENUITEM SEPARATOR
+ MENUITEM "Display Time O&n" IDM_MEASUREMENT_ON
+ MENUITEM "Display Time O&ff" IDM_MEASUREMENT_OFF
+ MENUITEM SEPARATOR
+ POPUP "&Batch Measurement"
+ BEGIN
+ MENUITEM "&GetData" IDM_BATCH_GETDATA
+ MENUITEM "GetData&Here" IDM_BATCH_GETDATAHERE
+ END
+ MENUITEM "Batch &To File" IDM_BATCHTOFILE
+ MENUITEM SEPARATOR
+ MENUITEM "&Test Timer" IDM_MEASUREMENT_TEST
+ END
+/*
+ POPUP "&Advise"
+ BEGIN
+ MENUITEM "&1 CF_TEXT", IDM_ADVISETEXT
+ MENUITEM "&2 CF_BITMAP", IDM_ADVISEBITMAP
+ MENUITEM "&3 CF_METAFILEPICT", IDM_ADVISEMETAFILEPICT
+ MENUITEM SEPARATOR
+ MENUITEM "&GetData on Change", IDM_ADVISEGETDATA
+ MENUITEM "&Paint on Change", IDM_ADVISEREPAINT
+ END
+ */
+ END
diff --git a/private/oleutest/perf16/idata/client/make16.inc b/private/oleutest/perf16/idata/client/make16.inc
new file mode 100644
index 000000000..ec6d94d20
--- /dev/null
+++ b/private/oleutest/perf16/idata/client/make16.inc
@@ -0,0 +1,331 @@
+# 16-bit makefile
+#
+# Copyright (c) 1991, Microsoft Corporation
+#
+# History:
+#
+# 18-Feb-1994 KevinRo
+# 24-Feb-1994 DrewB, added OBJDIR and some other niceties from win40.mk
+#
+
+.SUFFIXES:
+.SUFFIXES: .c .cxx .cpp .asm .h .inc .obj .lst
+.SUFFIXES: .sys .exe .com .map .sym .def .lib .rc .res
+
+!if "$(TARGET)" == ""
+!error TARGET must be defined
+!endif
+
+OUTNUL= 1>nul 2>nul
+
+!if "$(NTDEBUG)" != "" && "$(NTDEBUG)" != "retail"
+OBJDIR = obj16d
+!else
+OBJDIR = obj16r
+!endif
+
+# Build up lists of files to produce from sources
+
+!if "$(CFILES)" != ""
+OBJFILES = $(OBJFILES) $(CFILES:.c=.obj)
+!endif
+!if "$(CXXFILES)" != ""
+OBJFILES = $(OBJFILES) $(CXXFILES:.cxx=.obj)
+!endif
+!if "$(CPPFILES)" != ""
+OBJFILES = $(OBJFILES) $(CPPFILES:.cpp=.obj)
+!endif
+
+!if "$(ASMFILES)" != ""
+OBJFILES = $(OBJFILES) $(ASMFILES:.asm=.obj)
+!endif
+
+!if "$(RCFILES)" != ""
+RESFILES = $(RCFILES:.rc=.res)
+!endif
+
+# Replace .\ with $(OBJDIR)
+# Unfortunately we can't do this directly so we have to explicitly check
+# the value of OBJDIR
+
+!if "$(OBJDIR)" == "obj16d"
+OBJFILES = $(OBJFILES:.\=obj16d\)
+RESFILES = $(RESFILES:.\=obj16d\)
+
+!elseif "$(OBJDIR)" == "obj16r"
+OBJFILES = $(OBJFILES:.\=obj16r\)
+RESFILES = $(RESFILES:.\=obj16r\)
+
+!else
+!error Unknown OBJDIR: $(OBJDIR)
+!endif
+
+# Default target
+
+all: $(OBJDIR)\$(TARGET)
+
+# Determine target type and base name
+
+# Is it a DLL?
+TARGETBASE=$(TARGET:.dll=)
+!if "$(TARGETBASE)" != "$(TARGET)"
+TARGETTYPE=dll
+!else
+
+# Is it an EXE?
+TARGETBASE=$(TARGET:.exe=)
+! if "$(TARGETBASE)" != "$(TARGET)"
+TARGETTYPE=exe
+! else
+
+# Is it a LIB?
+TARGETBASE=$(TARGET:.lib=)
+! if "$(TARGETBASE)" != "$(TARGET)"
+TARGETTYPE=lib
+! endif
+! endif
+!endif
+
+!if "$(TARGETTYPE)" == ""
+!error Unknown target type for "$(TARGET)"
+!endif
+
+!if "$(BUILDDETAILS)" != ""
+BLDKEEP= KEEP
+!endif
+
+OLETHUNK= $(_NTDRIVE)$(_NTROOT)\private\ole32\olethunk
+OLE16= $(OLETHUNK)\ole16
+
+RCINC = $(RCINC) -i$(OLE16)\inc
+INCS = -I$(OLE16)\inc -I$(OLETHUNK)\h -I$(_NTDRIVE)$(_NTROOT)\private\cinc
+
+
+PATH = $(OLE16)\tools;$(PATH)
+LINK = link16
+RC = rc16
+CL = cl16
+IMPLIB = implib
+LIBUTIL = lib16
+MAPSYM = mapsym
+MASM = masm
+
+DEFINES = -DWOW
+
+AOBJ = -Mx -t $(DEFINES) $(INCS)
+
+!if "$(TARGETTYPE)" == "exe"
+CW16 = -GA
+!else
+CW16 = -GD
+DEFINES = $(DEFINES) -D_WINDLL
+!endif
+
+CW16 = $(CW16) -G2 -AL $(DEFINES) $(INCS) /NMSEG_CODE
+
+LFLAGS = $(LFLAGS) /nod /noe /map:0 /align:16
+
+!if "$(NTDEBUG)" != "" && "$(NTDEBUG)" != "retail"
+
+DEFINES = $(DEFINES) -DDBG=1 -DDEVL=1
+
+!if "$(NTDEBUGTYPE)" == "windbg"
+AOBJ = $(AOBJ) -Zi
+CW16 = $(CW16) /Odi /Zip /FA
+LFLAGS = $(LFLAGS) /CO
+!else
+AOBJ = $(AOBJ) -Zd
+CW16 = $(CW16) /Odi /Zd
+LFLAGS = $(LFLAGS) /LI
+!endif
+
+!else
+CW16 = $(CW16) /Os /Zp /Gs
+DEFINES = $(DEFINES) -DDBG=0 -DDEVL=1
+!endif
+
+!if "$(TARGETTYPE)" == "dll"
+W16LIBS = $(OLE16)\lib\ldllcew.lib
+!else
+!if "$(QUICKWINDOWS)" != ""
+W16LIBS = $(OLE16)\lib\llibcewq.lib
+!else
+W16LIBS = $(OLE16)\lib\llibcew.lib
+!endif
+!endif
+
+W16LIBS = $(W16LIBS) $(OLE16)\lib\libw.lib
+
+!if "$(TARGETTYPE)" == "dll" || "$(TARGETTYPE)" == "exe"
+LIBS = $(LIBS) $(W16LIBS)
+!endif
+
+.asm{$(OBJDIR)}.obj:
+ @-md $(OBJDIR) $(OUTNUL)
+ $(MASM) $(AOBJ) $*,$*;
+
+.asm.lst:
+ @-md $(OBJDIR) $(OUTNUL)
+ $(MASM) $(AOBJ) -l $*,nul,$*.lst;
+
+
+.c{$(OBJDIR)}.obj:
+ @-md $(OBJDIR) $(OUTNUL)
+ $(CL) -c -nologo @<<$*.rsp
+$(CW16: =
+)
+-Fo$*.obj
+$<
+<<$(BLDKEEP)
+
+.c.lst:
+ @-md $(OBJDIR) $(OUTNUL)
+ $(CL) -c -nologo @<<$(OBJDIR)\$*.rsp
+$(CW16: =
+)
+-Fonul
+-Fc$*.lst
+$<
+<<$(BLDKEEP)
+
+.cxx{$(OBJDIR)}.obj:
+ @-md $(OBJDIR) $(OUTNUL)
+ $(CL) -c -nologo @<<$*.rsp
+$(CW16: =
+)
+-Fo$*.obj
+-Tp$<
+<<$(BLDKEEP)
+
+.cxx.lst:
+ @-md $(OBJDIR) $(OUTNUL)
+ $(CL) -c -nologo @<<$(OBJDIR)\$*.rsp
+$(CW16: =
+)
+-Fc$*.lst
+-Fonul
+-Tp$<
+<<$(BLDKEEP)
+
+.cxx.pp:
+ @-md $(OBJDIR) $(OUTNUL)
+ $(CL) -c -nologo @<<$(OBJDIR)\$*.rsp > $*.pp
+$(CW16: =
+)
+-E
+-Fonul
+-Tp$<
+<<$(BLDKEEP)
+
+
+.cpp{$(OBJDIR)}.obj:
+ @-md $(OBJDIR) $(OUTNUL)
+ $(CL) -c -nologo @<<$*.rsp
+$(CW16: =
+)
+-Fo$*.obj
+-Tp$<
+<<$(BLDKEEP)
+
+.cpp.lst:
+ @-md $(OBJDIR) $(OUTNUL)
+ $(CL) -c -nologo @<<$(OBJDIR)\$*.rsp
+$(CW16: =
+)
+-Fc$*.lst
+-Fonul
+-Tp$<
+<<$(BLDKEEP)
+
+.cpp.pp:
+ @-md $(OBJDIR) $(OUTNUL)
+ $(CL) -c -nologo @<<$(OBJDIR)\$*.rsp > $*.pp
+$(CW16: =
+)
+-E
+-Fonul
+-Tp$<
+<<$(BLDKEEP)
+
+
+.def{$(OBJDIR)}.lib:
+ @-md $(OBJDIR) $(OUTNUL)
+ $(IMPLIB) $*.lib $<
+
+{$(OBJDIR)}.map{$(OBJDIR)}.sym:
+ @-md $(OBJDIR) $(OUTNUL)
+ $(MAPSYM) $<
+
+.rc{$(OBJDIR)}.res:
+ @-md $(OBJDIR) $(OUTNUL)
+ $(RC) -r $(RCINC) -fo $*.res $<
+
+
+cleanup:
+ if exist $(OBJDIR)\*.lrf del $(OBJDIR)\*.lrf
+ if exist $(OBJDIR)\*.obj del $(OBJDIR)\*.obj
+ if exist $(OBJDIR)\*.exe del $(OBJDIR)\*.exe
+ if exist $(OBJDIR)\*.map del $(OBJDIR)\*.map
+ if exist $(OBJDIR)\*.sym del $(OBJDIR)\*.sym
+ if exist $(OBJDIR)\*.res del $(OBJDIR)\*.res
+
+clean: cleanup
+
+!if "$(TARGETTYPE)" == "dll"
+
+$(OBJDIR)\$(TARGETBASE).lib: $(TARGETBASE).def
+
+$(OBJDIR)\$(TARGET) $(OBJDIR)\$(TARGETBASE).map: $(OBJFILES) $(RESFILES) \
+ $(TARGETBASE).def $(OBJDIR)\$(TARGETBASE).lib $(LIBS)
+ @-md $(OBJDIR) $(OUTNUL)
+ $(LINK) $(LFLAGS) @<<$(OBJDIR)\$(TARGETBASE).rsp
+$(OBJFILES: =+^
+)
+$(OBJDIR)\$(TARGET)
+$(OBJDIR)\$(TARGETBASE).map
+$(LIBS: =+^
+)
+$(TARGETBASE).def
+<<$(BLDKEEP)
+ $(MAPSYM) -o $(OBJDIR)\$(TARGETBASE).sym $(OBJDIR)\$(TARGETBASE).map
+!if "$(RCFILES)" != ""
+ $(RC) -t $(OBJDIR)\$(TARGETBASE).res $(OBJDIR)\$(TARGET)
+!endif
+
+!elseif "$(TARGETTYPE)" == "lib"
+
+$(OBJDIR)\$(TARGET): $(OBJFILES) $(LIBS)
+ @-md $(OBJDIR) $(OUTNUL)
+ -del $@ $(OUTNUL)
+ $(LIBUTIL) @<<$*.lnb
+$(OBJDIR)\$(TARGET)
+y
+$(OBJFILES: = &^
+)&
+$(LIBS: = &^
+)&
+
+$*.lls
+<<$(BLDKEEP)
+
+!elseif "$(TARGETTYPE)" == "exe"
+
+$(OBJDIR)\$(TARGET) $(OBJDIR)\$(TARGETBASE).map: $(OBJFILES) $(RESFILES) \
+ $(TARGETBASE).def $(LIBS)
+ @-md $(OBJDIR) $(OUTNUL)
+ $(LINK) $(LFLAGS) @<<$(OBJDIR)\$(TARGETBASE).rsp
+$(OBJFILES: =+^
+)
+$(OBJDIR)\$(TARGET)
+$(OBJDIR)\$(TARGETBASE).map
+$(LIBS: =+^
+)
+$(TARGETBASE).def
+<<$(BLDKEEP)
+!if "$(RCFILES)" != ""
+ $(RC) -t $(OBJDIR)\$(TARGETBASE).res $(OBJDIR)\$(TARGET)
+!endif
+ $(MAPSYM) -o $(OBJDIR)\$(TARGETBASE).sym $(OBJDIR)\$(TARGETBASE).map
+
+!endif
+ \ No newline at end of file
diff --git a/private/oleutest/perf16/idata/client/make16.mak b/private/oleutest/perf16/idata/client/make16.mak
new file mode 100644
index 000000000..f569e11e3
--- /dev/null
+++ b/private/oleutest/perf16/idata/client/make16.mak
@@ -0,0 +1,58 @@
+#//+---------------------------------------------------------------------------
+#//
+#// Microsoft Windows
+#// Copyright (C) Microsoft Corporation, 1992 - 1994.
+#//
+#// File: make16.mak
+#// Contents: make16.mak for 16 bit compile of idata test
+#//
+#// History: 06-21-95 Chapman Created
+#//
+#//----------------------------------------------------------------------------
+
+NTDEBUG=1
+
+
+default: copy_bin
+
+TARGET = idatausr.exe
+TARGETTYPE = EXE
+OLETHUNK = $(_NTDRIVE)$(_NTROOT)\private\ole32\olethunk
+
+RCINC=$(RCINC) -i..\ole2ui -i..\ole2ui\res\usa
+
+# CDEFINES= -I..\ole2ui /GEs -I..
+
+
+LFLAGS=/STACK:16384
+
+CPPFILES = \
+ .\datausr.cpp \
+ .\perror.cpp \
+ .\stgmedif.cpp \
+ .\stpwatch.cpp
+
+RCFILES = .\idatausr.rc
+
+LIBS = $(LIBS)\
+ $(OLE16)\lib\ole2.lib \
+ $(OLE16)\lib\storage.lib \
+ $(OLE16)\lib\loleuic.lib \
+ $(OLE16)\lib\compobj.lib \
+ $(OLE16)\lib\shell.lib
+
+!include make16.inc
+
+
+!if "$(NTDEBUG)" != "" && "$(NTDEBUG)" != "retail"
+LIBS = $(LIBS) $(OLETHUNK)\debnot\$(OBJDIR)\debnot.lib
+!endif
+
+
+copy_bin: all
+ copy $(OBJDIR)\idatausr.exe $(OBJDIR)\idatau16.exe
+ copy $(OBJDIR)\idatausr.sym $(OBJDIR)\idatau16.sym
+ copy $(OBJDIR)\idatausr.map $(OBJDIR)\idatau16.map
+ binplace $(OBJDIR)\idatau16.exe
+
+
diff --git a/private/oleutest/perf16/idata/client/makefile b/private/oleutest/perf16/idata/client/makefile
new file mode 100644
index 000000000..1d3728d41
--- /dev/null
+++ b/private/oleutest/perf16/idata/client/makefile
@@ -0,0 +1,10 @@
+############################################################################
+#
+# Copyright (C) 1992, Microsoft Corporation.
+#
+# All rights reserved.
+#
+############################################################################
+
+!include $(NTMAKEENV)\makefile.def
+
diff --git a/private/oleutest/perf16/idata/client/perror.cpp b/private/oleutest/perf16/idata/client/perror.cpp
new file mode 100644
index 000000000..5feec3560
--- /dev/null
+++ b/private/oleutest/perf16/idata/client/perror.cpp
@@ -0,0 +1,76 @@
+// This is functions used by both the
+// the client and the server programs
+
+#include <windows.h>
+#include <ole2.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include "perror.h"
+
+LPTSTR
+winErrorString(
+ HRESULT hrErrorCode,
+ LPTSTR sBuf,
+ int cBufSize)
+{
+#ifdef WIN32
+ FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL,
+ hrErrorCode,
+ GetSystemDefaultLangID(),
+ sBuf,
+ cBufSize,
+ NULL);
+#else
+ wsprintf(sBuf, "\"0x%08x\"\n", hrErrorCode);
+#endif // WIN32
+ return sBuf;
+}
+
+#define PBUF_LEN 200
+
+#if 0 // I'm not linking with "printf" currently.
+void
+print_error(
+ LPTSTR sMessage,
+ HRESULT hrErrorCode)
+{
+ TCHAR sBuf[PBUF_LEN];
+
+ winErrorString(hrErrorCode, sMessage, PBUF_LEN);
+#ifdef WIN32
+ printf("%s(0x%x)%s", sMessage, hrErrorCode, sBuf);
+#else
+ printf("%s%s", sMessage, sBuf);
+#endif
+}
+#endif
+
+void
+perror_OKBox(
+ HWND hwnd,
+ LPTSTR sTitle,
+ HRESULT hrErrorCode)
+{
+ TCHAR sBuf[PBUF_LEN];
+ TCHAR sBuf2[PBUF_LEN];
+
+ winErrorString(hrErrorCode, sBuf, PBUF_LEN);
+ wsprintf(sBuf2, TEXT("%s(%08x)"), sBuf, hrErrorCode);
+ MessageBox(hwnd, sBuf2, sTitle, MB_OK);
+}
+
+void
+wprintf_OKBox(
+ HWND hwnd,
+ LPTSTR sTitle,
+ LPTSTR sFormat,
+ ...)
+{
+ TCHAR sBuf[PBUF_LEN];
+ va_list vaMarker;
+
+ va_start( vaMarker, sFormat );
+ wvsprintf(sBuf, sFormat, vaMarker);
+ MessageBox(hwnd, sBuf, sTitle, MB_OK);
+}
diff --git a/private/oleutest/perf16/idata/client/perror.h b/private/oleutest/perf16/idata/client/perror.h
new file mode 100644
index 000000000..3eceb4b69
--- /dev/null
+++ b/private/oleutest/perf16/idata/client/perror.h
@@ -0,0 +1,36 @@
+#include "../my3216.h"
+
+/*
+ * winErrorString: Write the text of an HRESULT into a supplied buffer.
+ */
+LPTSTR
+winErrorString(
+ HRESULT hrErrorCode,
+ LPTSTR sBuf,
+ int cBufSize);
+
+/*
+ * print_error: Print a mesage and the text of an HRESULT .
+ */
+void
+print_error(
+ LPTSTR sMessage,
+ HRESULT hrErrorCode);
+
+/*
+ * perror_OKBox: Write the text of an HRESULT in a MessageBox.
+ */
+void
+perror_OKBox(
+ HWND hwnd,
+ LPTSTR sTitle,
+ HRESULT hrErrorCode);
+/*
+ * wprintf_OKBox: printf into a MessageBox.
+ */
+void
+wprintf_OKBox(
+ HWND hwnd,
+ LPTSTR sTitle,
+ LPTSTR sFormat,
+ ...);
diff --git a/private/oleutest/perf16/idata/client/sources b/private/oleutest/perf16/idata/client/sources
new file mode 100644
index 000000000..3d3c8e356
--- /dev/null
+++ b/private/oleutest/perf16/idata/client/sources
@@ -0,0 +1,85 @@
+!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:
+
+ Brian Chapman (BChapman) July 10th 1995.
+
+!ENDIF
+
+MAJORCOMP = cairole
+MINORCOMP = perform
+
+#
+# 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= idatausr
+
+#
+# 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= $(BASEDIR)\private\ole32\h;..\..\common
+# INCLUDES= $(INCLUDES);$(BASEDIR)\private\oleutest\balls\oleprx32\daytona
+# INCLUDES= $(INCLUDES);$(BASEDIR)\private\ole32\common\daytona;..
+# INCLUDES= $(INCLUDES);..\..\ole32\tests
+
+C_DEFINES= \
+ $(C_DEFINES) \
+ -DFLAT \
+ -DWIN32=100 \
+ -D_NT1X_=100 \
+ -DUNICODE \
+ -D_UNICODE \
+ -DNOEXCEPTIONS \
+ -DCAIROLE_DOWNLEVEL
+
+BLDCRT= 1
+
+SOURCES= \
+ datausr.cpp \
+ idatausr.rc \
+ perror.cpp \
+ stgmedif.cpp \
+ stpwatch.cpp
+
+
+UMTYPE= windows
+UMENTRY= winmain
+UMAPPL=
+UMTEST=
+UMLIBS=
+UMLIBS= \
+ $(BASEDIR)\public\sdk\lib\*\ole32.lib \
+ $(BASEDIR)\public\sdk\lib\*\comdlg32.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\*\crtdll.lib \
+ $(BASEDIR)\public\sdk\lib\*\uuid.lib
diff --git a/private/oleutest/perf16/idata/client/stgmedif.cpp b/private/oleutest/perf16/idata/client/stgmedif.cpp
new file mode 100644
index 000000000..5fb7dca7e
--- /dev/null
+++ b/private/oleutest/perf16/idata/client/stgmedif.cpp
@@ -0,0 +1,60 @@
+#include "datausr.h"
+
+HRESULT
+GetStgMedpUnkForRelease(IUnknown **pp_unk)
+{
+ CStgMedIf *p_smi = new CStgMedIf();
+ HRESULT hr = p_smi->QueryInterface(IID_IUnknown, (PPVOID)pp_unk);
+ return hr;
+}
+
+CStgMedIf::CStgMedIf()
+{
+ m_cRef = 0;
+}
+
+
+STDMETHODIMP
+CStgMedIf::QueryInterface(
+ REFIID riid,
+ LPLPVOID ppv
+)
+{
+ *ppv = NULL;
+ if (IsEqualIID(riid, IID_IUnknown))
+ {
+ *ppv = (LPVOID)this;
+ ((LPUNKNOWN)*ppv)->AddRef();
+ return NOERROR;
+ }
+ return ResultFromScode(E_NOINTERFACE);
+}
+
+
+STDMETHODIMP_(ULONG)
+CStgMedIf::AddRef(void)
+{
+ return ++m_cRef;
+}
+
+
+STDMETHODIMP_(ULONG)
+CStgMedIf::Release(void)
+{
+ ULONG cRefT;
+
+ cRefT = --m_cRef;
+
+ if (0==cRefT)
+ {
+ TCHAR chBuf[80];
+
+ wsprintf(chBuf, TEXT("Reference Count is %d"), cRefT);
+ MessageBox(0,
+ chBuf,
+ TEXT("STGMED pUnkForRelease"),
+ MB_OK);
+ delete this;
+ }
+ return cRefT;
+}
diff --git a/private/oleutest/perf16/idata/client/stpwatch.cpp b/private/oleutest/perf16/idata/client/stpwatch.cpp
new file mode 100644
index 000000000..101e9c190
--- /dev/null
+++ b/private/oleutest/perf16/idata/client/stpwatch.cpp
@@ -0,0 +1,145 @@
+#include "stpwatch.h"
+
+StopWatch_cl::StopWatch_cl()
+{
+ m_Zero();
+}
+
+ULONG StopWatch_cl::sm_TicksPerSecond;
+
+//
+// Init global/static state of the StopWatch class.
+//
+BOOL
+StopWatch_cl::m_ClassInit()
+{
+ LARGE_INTEGER liTPS;
+#ifdef WIN32
+ if(!QueryPerformanceFrequency(&liTPS) )
+ {
+ MessageBox(0,
+ TEXT("Can't read frequency"),
+ TEXT("QueryPerformanceFrequency"),
+ MB_OK);
+ return FALSE;
+ }
+ if (liTPS.HighPart != 0)
+ {
+ MessageBox(0,
+ TEXT("Ticks Per Second is to great"),
+ TEXT("QueryPerformanceFrequency"),
+ MB_OK);
+ return FALSE;
+ }
+ sm_TicksPerSecond = liTPS.LowPart;
+#else
+ sm_TicksPerSecond = 1000;
+#endif
+ return TRUE;
+}
+
+void
+StopWatch_cl::m_Zero()
+{
+ LISet32(m_liStart, 0);
+ LISet32(m_liStop, 0);
+ m_State = ZEROED;
+}
+
+
+BOOL
+StopWatch_cl::m_Start()
+{
+#ifdef WIN32
+ if(!QueryPerformanceCounter(&m_liStart))
+ {
+ MessageBox(0,
+ TEXT("Get Start Time Failure"),
+ TEXT("QueryPerformancecounter Failed"),
+ MB_OK);
+ return FALSE;
+ }
+#else
+ m_liStart.LowPart = GetTickCount();
+ m_liStart.HighPart = 0;
+#endif
+ m_State = RUNNING;
+ return TRUE;
+}
+
+// m_MeasureStop()
+// Returns microseconds per single iteration.
+//
+BOOL
+StopWatch_cl::m_Stop()
+{
+#ifdef WIN32
+ if(!QueryPerformanceCounter(&m_liStop))
+ {
+ MessageBox(0,
+ TEXT("Get Stop Time Failure"),
+ TEXT("QueryPerformancecounter Failed"),
+ MB_OK);
+ return FALSE;
+ }
+#else
+ m_liStop.LowPart = GetTickCount();
+ m_liStop.HighPart = 0;
+#endif
+ m_State = STOPPED;
+ return TRUE;
+}
+
+BOOL
+StopWatch_cl::m_Sleep(UINT msecs)
+{
+#ifdef WIN32
+ Sleep(msecs);
+#else
+ UINT start, elapsed;
+ start = GetTickCount();
+ do
+ {
+ elapsed = GetTickCount() - start;
+ } while ( msecs > elapsed );
+#endif
+ return TRUE;
+}
+
+
+//
+// Return a ULONG count of the number of Microseconds on the timer.
+// I would return LARGE_INTEGER but there doesn't seem to be facilities
+// to user them easily under 16 bit.
+//
+BOOL
+StopWatch_cl::m_Read(ULONG *p_cMicroSeconds)
+{
+ LARGE_INTEGER liTicks;
+
+ int borrow = 0;
+ if(m_liStart.LowPart > m_liStop.LowPart)
+ borrow = 1;
+ liTicks.LowPart = m_liStop.LowPart - m_liStart.LowPart;
+ liTicks.HighPart = m_liStop.HighPart - m_liStart.HighPart - borrow;
+
+ if(0 != liTicks.HighPart)
+ {
+ MessageBox(0,
+ TEXT("Time interval was too great"),
+ TEXT("Failure"),
+ MB_OK);
+ return(FALSE);
+ }
+
+ // result has units of (ticks/ loop of iterations). Where the ticks
+ // are timer specific. This will convert result into:
+ // (Milli_ticks) / (single iteration)
+
+#ifdef WIN32
+ *p_cMicroSeconds = MulDiv(liTicks.LowPart, 1000000, sm_TicksPerSecond);
+#else
+ *p_cMicroSeconds = liTicks.LowPart * 1000;
+#endif
+ return TRUE;
+}
diff --git a/private/oleutest/perf16/idata/client/stpwatch.h b/private/oleutest/perf16/idata/client/stpwatch.h
new file mode 100644
index 000000000..bcfd3faef
--- /dev/null
+++ b/private/oleutest/perf16/idata/client/stpwatch.h
@@ -0,0 +1,28 @@
+#ifndef __STOPWATCH_H
+#define __STOPWATCH_H
+
+#include "../syshead.h"
+#include "../my3216.h"
+
+class StopWatch_cl {
+ private:
+ static ULONG sm_TicksPerSecond;
+ LARGE_INTEGER m_liStart;
+ LARGE_INTEGER m_liStop;
+
+ enum em_STATES { ZEROED, RUNNING, STOPPED };
+ em_STATES m_State;
+
+ public:
+ StopWatch_cl();
+ void m_Zero();
+ BOOL m_ClassInit();
+ BOOL m_Start();
+ BOOL m_Stop();
+ BOOL m_Read(ULONG *);
+ BOOL m_ShowWindow(HWND);
+ BOOL m_Sleep(UINT);
+};
+
+#endif // __STOPWATCH_H
+
diff --git a/private/oleutest/perf16/idata/dirs b/private/oleutest/perf16/idata/dirs
new file mode 100644
index 000000000..6b22540db
--- /dev/null
+++ b/private/oleutest/perf16/idata/dirs
@@ -0,0 +1,36 @@
+!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:
+
+ Brian Chapman (BChapman) 10 July 1995
+
+!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= \
+ server \
+ client
+
+#
+# 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=
diff --git a/private/oleutest/perf16/idata/makefil0 b/private/oleutest/perf16/idata/makefil0
new file mode 100644
index 000000000..583f876af
--- /dev/null
+++ b/private/oleutest/perf16/idata/makefil0
@@ -0,0 +1,37 @@
+# 16 bit unit tests makefile
+# Copyright (c) 1994, Microsoft Corporation
+#
+# History:
+# 29-Jun-1994 TerryRu
+# 13 July 1995 BChapman Copied into the perf16\idata directory from
+# the root of the oleutest tree.
+#
+
+!INCLUDE $(NTMAKEENV)\makefile.plt
+
+MAKE=nmake /f make16.mak
+
+all:
+!if "$(PROCESSOR_ARCHITECTURE)" == "x86"
+ @echo Build_Status Build 16 bit server edatas16 under NTVDM.
+ cd server
+ $(MAKE)
+ @echo Build_Status Build 16 bit client idatau16 under NTVDM.
+ cd ..\client
+ $(MAKE)
+ cd ..
+!endif
+!IF "$(BUILDMSG)" != ""
+ @ech ; $(BUILDMSG) ;
+!ENDIF
+
+cleanup:
+!if "$(PROCESSOR_ARCHITECTURE)" == "x86"
+ cd server
+ $(MAKE) clean
+ cd ..\client
+ $(MAKE) clean
+ cd ..
+!endif
+
+clean: cleanup all
diff --git a/private/oleutest/perf16/idata/my3216.h b/private/oleutest/perf16/idata/my3216.h
new file mode 100644
index 000000000..ae1aac4b4
--- /dev/null
+++ b/private/oleutest/perf16/idata/my3216.h
@@ -0,0 +1,10 @@
+#ifndef MY3216_H
+#define MY3216_H
+
+#ifndef WIN32
+ #define lstrcmpiA lstrcmpi
+ #define TEXT(a) (a)
+ typedef TCHAR FAR * LPTSTR;
+#endif
+
+#endif // MY3216_H
diff --git a/private/oleutest/perf16/idata/readme b/private/oleutest/perf16/idata/readme
new file mode 100644
index 000000000..88fa0d831
--- /dev/null
+++ b/private/oleutest/perf16/idata/readme
@@ -0,0 +1,13 @@
+
+ July 12th 1995 BChapman
+
+This benchmark is an example taken originally from "Inside OLE 2"
+and greatly modified.
+
+It builds four programs:
+
+ idatausr 32 bit client.
+ idatau16 16 bit version of above.
+
+ edataobj 32 bit server.
+ edatas16 16 bit version of above.
diff --git a/private/oleutest/perf16/idata/server/dataobj.cpp b/private/oleutest/perf16/idata/server/dataobj.cpp
new file mode 100644
index 000000000..70d14fd3b
--- /dev/null
+++ b/private/oleutest/perf16/idata/server/dataobj.cpp
@@ -0,0 +1,146 @@
+#include "dataobj.h"
+
+extern HINSTANCE g_hInstance;
+
+DWORD g_dwID=0;
+DWORD g_foobar;
+
+CDataObject::CDataObject(
+ LPUNKNOWN pUnkOuter,
+ PFNDESTROYED pfnDestroy
+)
+{
+ m_cRef = 0;
+ m_pUnkOuter = pUnkOuter;
+ m_pfnDestroy = pfnDestroy;
+
+ m_hWndAdvise = NULL;
+ m_dwAdvFlags = ADVF_NODATA;
+
+ m_pIDataObject = NULL;
+ m_pIDataAdviseHolder = NULL;
+
+ m_cfeGet = CFORMATETCGET;
+ SETDefFormatEtc(m_rgfeGet[0], CF_TEXT, TYMED_HGLOBAL);
+
+ m_dataText = NULL;
+ m_cDataSize = DATASIZE_FROM_INDEX(1);
+
+ return;
+}
+
+CDataObject::~CDataObject(void)
+{
+ if (NULL != m_dataText)
+ delete m_dataText;
+
+ if (NULL != m_pIDataAdviseHolder)
+ m_pIDataAdviseHolder->Release();
+
+ if (NULL != m_pIDataObject)
+ delete m_pIDataObject;
+
+ if (NULL != m_hWndAdvise)
+ DestroyWindow(m_hWndAdvise);
+}
+
+BOOL
+CDataObject::FInit(void)
+{
+ LPUNKNOWN pIUnknown = (LPUNKNOWN)this;
+
+ // Create the contained "IDataObject" interface and
+ // pass it the correct containing IUnknown.
+ if (NULL != m_pUnkOuter)
+ pIUnknown = m_pUnkOuter;
+
+ m_pIDataObject = new CImpIDataObject(this, pIUnknown);
+
+ if (NULL == m_pIDataObject)
+ return FALSE;
+
+ // [ Code for "Advise Window" goes here. ]
+
+ return TRUE;
+}
+
+STDMETHODIMP
+CDataObject::QueryInterface(
+ REFIID riid,
+ LPLPVOID ppv
+)
+{
+ *ppv = NULL;
+ if (IsEqualIID(riid, IID_IUnknown))
+ *ppv = (LPVOID)this;
+
+ if (IsEqualIID(riid, IID_IDataObject))
+ *ppv = (LPVOID) m_pIDataObject;
+
+ if(NULL != *ppv)
+ {
+ ((LPUNKNOWN)*ppv)->AddRef();
+ return NOERROR;
+ }
+ return ResultFromScode(E_NOINTERFACE);
+}
+
+STDMETHODIMP_(ULONG)
+CDataObject::AddRef(void)
+{
+ return ++m_cRef;
+}
+
+STDMETHODIMP_(ULONG)
+CDataObject::Release(void)
+{
+ ULONG cRefT;
+
+ cRefT = --m_cRef;
+
+ if (0==m_cRef)
+ {
+ if (NULL != m_pfnDestroy)
+ (*m_pfnDestroy)();
+ delete this;
+ }
+ return cRefT;
+}
+
+#ifdef NOT_SIMPLE
+LRESULT APIENTRY
+AdvisorWndProc(
+ HWND hWnd,
+ UINT iMsg,
+ WPARAM wParam,
+ LPARAM lParam
+)
+{
+ PCDataObject pDO;
+
+ pDO = (PCDataObject)(GetWindowLong)(hWnd, 0);
+
+ switch (iMsg)
+ {
+ case WM_NCCREATE:
+ pDO = (PCDataObject) ((LONG)((LPCREATESTRUCT)lParam)
+ ->lpCreateParams);
+ SetWindowLong(hWnd, 0, (LONG)pDO);
+ return (DefWindowProc(hWnd, iMsg, wParam, lParam));
+
+#ifdef FINISHED
+ case WM_CLOSE:
+ // Forbid the Task Manager from closing us.
+ return 0L;
+#endif /* Finished */
+
+ case WM_COMMAND:
+ // [ Code for "Advise Window" goes here. ]
+ break;
+
+ default:
+ return (DefWindowProc(hWnd, iMsg, wParam, lParam));
+ }
+ return 0L;
+}
+#endif /* NOT_SIMPLE */
diff --git a/private/oleutest/perf16/idata/server/dataobj.h b/private/oleutest/perf16/idata/server/dataobj.h
new file mode 100644
index 000000000..aca80a698
--- /dev/null
+++ b/private/oleutest/perf16/idata/server/dataobj.h
@@ -0,0 +1,196 @@
+/*
+ * DATAOBJ.H
+ * Data Object Chapter 6
+ *
+ * Classes that implement the Data Object independent of whether
+ * we live in a DLL or EXE.
+ *
+ * Copyright (c)1993-1995 Microsoft Corporation, All Right Reserved
+ *
+ * Kraig Brockschmidt, Software Design Engineer
+ * Microsoft Systems Developer Relations
+ *
+ * Internet : kraigb@microsoft.com
+ * Compuserve: >INTERNET:kraigb@microsoft.com
+ */
+
+
+#ifndef _DATAOBJ_H_
+#define _DATAOBJ_H_
+
+#define INC_OLE2
+#include <windows.h>
+#include <ole2.h>
+
+#include "../my3216.h"
+#include "../bookpart.h"
+
+//Type for an object-destroyed callback
+typedef void (PASCAL *PFNDESTROYED)(void);
+
+
+/*
+ * The DataObject object is implemented in its own class with its
+ * own IUnknown to support aggregation. It contains one
+ * CImpIDataObject object that we use to implement the externally
+ * exposed interfaces.
+ */
+
+
+//DATAOBJ.CPP
+#ifdef NOT_SIMPLE
+LRESULT APIENTRY
+AdvisorWndProc(HWND, UINT, WPARAM, LPARAM);
+#endif /* NOT_SIMPLE */
+
+class CImpIDataObject;
+typedef class CImpIDataObject *PIMPIDATAOBJECT;
+
+
+class CDataObject : public IUnknown
+{
+ friend class CImpIDataObject;
+#ifdef NOT_SIMPLE
+ friend LRESULT APIENTRY AdvisorWndProc(HWND, UINT
+ , WPARAM, LPARAM);
+#endif /* NOT_SIMPLE */
+
+ protected:
+ ULONG m_cRef;
+ LPUNKNOWN m_pUnkOuter;
+ PFNDESTROYED m_pfnDestroy;
+
+ HWND m_hWndAdvise; //Popup with Advise menu
+ DWORD m_dwAdvFlags; //Notification flags
+
+ //Contained interface implemetation
+ PIMPIDATAOBJECT m_pIDataObject;
+
+ //Other interfaces used, implemented elsewhere
+ LPDATAADVISEHOLDER m_pIDataAdviseHolder;
+
+ //Arrays for IDataObject::EnumFormatEtc
+#define CFORMATETCGET 1
+ ULONG m_cfeGet;
+ FORMATETC m_rgfeGet[CFORMATETCGET];
+
+ LPSTR m_dataText;
+ ULONG m_cDataSize;
+
+ protected:
+ //Functions for use from IDataObject::GetData
+#define FL_MAKE_ITEM 0x01 // StgMedium item must be created.
+#define FL_USE_ITEM 0x00 // StgMedium item is allocated, use that.
+#define FL_PASS_PUNK 0x02 // put a pUnk in the StgMedium.
+ HRESULT RenderText(LPSTGMEDIUM, LPTSTR, DWORD flags);
+ HRESULT RenderBitmap(LPSTGMEDIUM);
+ HRESULT RenderMetafilePict(LPSTGMEDIUM);
+
+ public:
+ CDataObject(LPUNKNOWN, PFNDESTROYED);
+ ~CDataObject(void);
+
+ BOOL FInit(void);
+
+ //Non-delegating object IUnknown
+ STDMETHODIMP QueryInterface(REFIID, PPVOID);
+ STDMETHODIMP_(ULONG) AddRef(void);
+ STDMETHODIMP_(ULONG) Release(void);
+};
+
+typedef CDataObject *PCDataObject;
+
+
+
+/*
+ * Interface implementations for the CDataObject object.
+ */
+
+class CImpIDataObject : public IDataObject
+ {
+ private:
+ ULONG m_cRef;
+ PCDataObject m_pObj;
+ LPUNKNOWN m_pUnkOuter;
+
+ public:
+ CImpIDataObject(PCDataObject, LPUNKNOWN);
+ ~CImpIDataObject(void);
+
+ //IUnknown members that delegate to m_pUnkOuter.
+ STDMETHODIMP QueryInterface(REFIID, PPVOID);
+ STDMETHODIMP_(ULONG) AddRef(void);
+ STDMETHODIMP_(ULONG) Release(void);
+
+ //IDataObject members
+ STDMETHODIMP GetData(LPFORMATETC, LPSTGMEDIUM);
+ STDMETHODIMP GetDataHere(LPFORMATETC, LPSTGMEDIUM);
+ STDMETHODIMP QueryGetData(LPFORMATETC);
+ STDMETHODIMP GetCanonicalFormatEtc(LPFORMATETC,LPFORMATETC);
+ STDMETHODIMP SetData(LPFORMATETC, LPSTGMEDIUM, BOOL);
+ STDMETHODIMP EnumFormatEtc(DWORD, LPENUMFORMATETC *);
+ STDMETHODIMP DAdvise(LPFORMATETC, DWORD, LPADVISESINK
+ , DWORD *);
+ STDMETHODIMP DUnadvise(DWORD);
+ STDMETHODIMP EnumDAdvise(LPENUMSTATDATA *);
+ };
+
+/*
+ * IEnumFORMATETC object that is created from
+ * IDataObject::EnumFormatEtc. This object lives on its own.
+ */
+
+
+class CEnumFormatEtc : public IEnumFORMATETC
+ {
+ private:
+ ULONG m_cRef; //Object reference count
+ LPUNKNOWN m_pUnkRef; //For reference counting
+ ULONG m_iCur; //Current element.
+ ULONG m_cfe; //Number of FORMATETCs in us
+ LPFORMATETC m_prgfe; //Source of FORMATETCs
+
+ public:
+ CEnumFormatEtc(LPUNKNOWN, ULONG, LPFORMATETC);
+ ~CEnumFormatEtc(void);
+
+ //IUnknown members that delegate to m_pUnkRef.
+ STDMETHODIMP QueryInterface(REFIID, PPVOID);
+ STDMETHODIMP_(ULONG) AddRef(void);
+ STDMETHODIMP_(ULONG) Release(void);
+
+ //IEnumFORMATETC members
+ STDMETHODIMP Next(ULONG, LPFORMATETC, ULONG *);
+ STDMETHODIMP Skip(ULONG);
+ STDMETHODIMP Reset(void);
+ STDMETHODIMP Clone(IEnumFORMATETC **);
+ };
+
+
+typedef CEnumFormatEtc *PCEnumFormatEtc;
+
+//////////////////////////////////////////////////////////////////////////////
+// Storage Medium IUnknown interface for pUnkForRelease.
+//
+
+class CStgMedIf: public IUnknown {
+private:
+ ULONG m_cRef;
+ LPSTGMEDIUM m_pSTM;
+
+public:
+ CStgMedIf(LPSTGMEDIUM);
+
+ STDMETHODIMP QueryInterface(REFIID, PPVOID);
+ STDMETHODIMP_(ULONG) AddRef(void);
+ STDMETHODIMP_(ULONG) Release(void);
+};
+
+//////////////////////////
+// API for getting a pUnkForRelease.
+//
+
+HRESULT
+GetStgMedpUnkForRelease(LPSTGMEDIUM pSTM, IUnknown **pp_unk);
+
+#endif //_DATAOBJ_H_
diff --git a/private/oleutest/perf16/idata/server/edataobj.cpp b/private/oleutest/perf16/idata/server/edataobj.cpp
new file mode 100644
index 000000000..13e976269
--- /dev/null
+++ b/private/oleutest/perf16/idata/server/edataobj.cpp
@@ -0,0 +1,445 @@
+#define INIT_MY_GUIDS
+#include <ole2ver.h>
+#include "edataobj.h"
+
+
+// Count of the number of objects and number of locks.
+ULONG g_cObj=0;
+ULONG g_cLock=0;
+
+//Make window handle global so other code can cause a shutdown
+HWND g_hWnd=NULL;
+HINSTANCE g_hInst=NULL;
+
+
+/*
+ * WinMain
+ *
+ * Purpose:
+ * Main entry point of application.
+ */
+
+int PASCAL
+WinMain(
+ HINSTANCE hInst,
+ HINSTANCE hInstPrev,
+ LPSTR pszCmdLine,
+ int nCmdShow)
+{
+ MSG msg;
+ PAPPVARS pAV;
+
+#ifndef WIN32
+ int cMsg = 96;
+ while (!SetMessageQueue(cMsg) && (cMsg -= 9))
+ ;
+#endif
+ g_hInst=hInst;
+
+ pAV=new CAppVars(hInst, hInstPrev, pszCmdLine, nCmdShow);
+
+ if (NULL==pAV)
+ return -1;
+
+ if (pAV->FInit())
+ {
+ while (GetMessage(&msg, NULL, 0,0 ))
+ {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ }
+
+ delete pAV;
+ return msg.wParam;
+}
+
+
+LRESULT WINAPI
+DataObjectWndProc(
+ HWND hWnd,
+ UINT iMsg,
+ WPARAM wParam,
+ LPARAM lParam)
+{
+ switch (iMsg)
+ {
+ case WM_DESTROY:
+ PostQuitMessage(0);
+ break;
+
+ default:
+ return (DefWindowProc(hWnd, iMsg, wParam, lParam));
+ }
+
+ return 0L;
+}
+
+
+void PASCAL
+ObjectDestroyed(void)
+{
+ g_cObj--;
+
+ //No more objects and no locks, shut the app down.
+ if (0L==g_cObj && 0L==g_cLock && IsWindow(g_hWnd))
+ PostMessage(g_hWnd, WM_CLOSE, 0, 0L);
+
+ return;
+}
+
+
+CAppVars::CAppVars(
+ HINSTANCE hInst,
+ HINSTANCE hInstPrev,
+ LPSTR pszCmdLine,
+ UINT nCmdShow)
+{
+ m_hInst =hInst;
+ m_hInstPrev =hInstPrev;
+ m_pszCmdLine=pszCmdLine;
+
+ m_nCmdShow = nCmdShow;
+
+ m_hWnd=NULL;
+
+#if 0
+ for (i=0; i < DOSIZE_CSIZES; i++)
+ {
+ m_rgdwRegCO[i]=0;
+ m_rgpIClassFactory[i]=NULL;
+ }
+#else
+ m_dwRegCO = 0;
+ m_pIClassFactory = NULL;
+#endif
+
+ m_fInitialized=FALSE;
+ return;
+}
+
+
+CAppVars::~CAppVars(void)
+{
+#if 0
+ UINT i;
+
+ //Revoke and destroy the class factories of all sizes
+ for (i=0; i < DOSIZE_CSIZES; i++)
+ {
+ if (0L!=m_rgdwRegCO[i])
+ CoRevokeClassObject(m_rgdwRegCO[i]);
+
+ if (NULL!=m_rgpIClassFactory[i])
+ m_rgpIClassFactory[i]->Release();
+ }
+#else
+ if (0L != m_dwRegCO)
+ CoRevokeClassObject(m_dwRegCO);
+
+ if (NULL != m_pIClassFactory)
+ m_pIClassFactory->Release();
+#endif
+
+ if (m_fInitialized)
+ CoUninitialize();
+
+ return;
+}
+
+/*
+ * CAppVars::FInit
+ *
+ * Purpose:
+ * Initializes an CAppVars object by registering window classes,
+ * etc... If this function fails the caller should guarantee
+ * that the destructor is called.
+ *
+ * Return Value:
+ * BOOL TRUE if successful, FALSE otherwise.
+ */
+
+BOOL
+CAppVars::FInit(void)
+{
+ WNDCLASS wc;
+ HRESULT hr;
+ DWORD dwVer;
+#ifdef WIN32
+ static TCHAR szClass[] = TEXT("IdataSvr32");
+#else
+ static TCHAR szClass[] = TEXT("IdataSvr16");
+#endif
+
+ //Check command line for -Embedding
+ if (lstrcmpiA(m_pszCmdLine, "-Embedding"))
+ return FALSE;
+
+ dwVer=CoBuildVersion();
+
+ if (rmm!=HIWORD(dwVer))
+ return FALSE;
+
+ if (FAILED(CoInitialize(NULL)))
+ return FALSE;
+
+ m_fInitialized=TRUE;
+
+ if (!m_hInstPrev)
+ {
+ wc.style = CS_HREDRAW | CS_VREDRAW;
+ wc.lpfnWndProc = DataObjectWndProc;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = 0;
+ wc.hInstance = m_hInst;
+ wc.hIcon = NULL;
+ wc.hCursor = NULL;
+ wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
+ wc.lpszMenuName = NULL;
+ wc.lpszClassName = szClass;
+
+ if (!RegisterClass(&wc))
+ return FALSE;
+ }
+
+ m_hWnd=CreateWindow(szClass,
+ szClass,
+ WS_OVERLAPPEDWINDOW,
+ 135, 135, 350, 250,
+ NULL, NULL, m_hInst, NULL);
+
+ if (NULL==m_hWnd)
+ return FALSE;
+
+ g_hWnd=m_hWnd;
+
+ //ShowWindow(m_hWnd, m_nCmdShow);
+ //UpdateWindow(m_hWnd);
+
+
+#if 0
+ /*
+ * This code supplies three different classes, one for each type
+ * of data object that handles a different size of data. All the
+ * class factories share the same implementation, but their
+ * instantiations differ by the type passed in the constructor.
+ * When the class factories create objects, they pass that size
+ * to the CDataObject contstructor as well.
+ */
+
+ UINT i;
+ HRESULT hr2, hr3;
+
+ for (i=0; i < DOSIZE_CSIZES; i++)
+ {
+ m_rgpIClassFactory[i]=new CDataObjectClassFactory(i);
+
+ if (NULL==m_rgpIClassFactory[i])
+ return FALSE;
+
+ m_rgpIClassFactory[i]->AddRef();
+ }
+
+ hr=CoRegisterClassObject(CLSID_DataObjectSmall
+ , m_rgpIClassFactory[0], CLSCTX_LOCAL_SERVER
+ , REGCLS_MULTIPLEUSE, &m_rgdwRegCO[0]);
+
+ hr2=CoRegisterClassObject(CLSID_DataObjectMedium
+ , m_rgpIClassFactory[1], CLSCTX_LOCAL_SERVER
+ , REGCLS_MULTIPLEUSE, &m_rgdwRegCO[1]);
+
+ hr3=CoRegisterClassObject(CLSID_DataObjectLarge
+ , m_rgpIClassFactory[2], CLSCTX_LOCAL_SERVER
+ , REGCLS_MULTIPLEUSE, &m_rgdwRegCO[2]);
+
+ if (FAILED(hr) || FAILED(hr2) || FAILED(hr3))
+ return FALSE;
+#else
+ m_pIClassFactory = new CDataObjectClassFactory();
+ if (NULL == m_pIClassFactory)
+ return FALSE;
+ m_pIClassFactory->AddRef();
+#ifdef WIN32
+ hr = CoRegisterClassObject( CLSID_DataObjectTest32,
+ m_pIClassFactory,
+ CLSCTX_LOCAL_SERVER,
+ REGCLS_MULTIPLEUSE,
+ &m_dwRegCO );
+#else
+ hr = CoRegisterClassObject( CLSID_DataObjectTest16,
+ m_pIClassFactory,
+ CLSCTX_LOCAL_SERVER,
+ REGCLS_MULTIPLEUSE,
+ &m_dwRegCO );
+#endif // WIN32
+ if (FAILED(hr))
+ return FALSE;
+#endif
+
+ return TRUE;
+}
+
+
+/*
+ * CDataObjectClassFactory::CDataObjectClassFactory
+ * CDataObjectClassFactory::~CDataObjectClassFactory
+ *
+ * Constructor Parameters:
+ * iSize UINT specifying the data size for this class.
+ */
+
+CDataObjectClassFactory::CDataObjectClassFactory()
+{
+ m_cRef=0L;
+ return;
+}
+
+
+CDataObjectClassFactory::~CDataObjectClassFactory(void)
+{
+ return;
+}
+
+
+STDMETHODIMP
+CDataObjectClassFactory::QueryInterface(
+ REFIID riid,
+ PPVOID ppv)
+{
+ *ppv=NULL;
+
+ //Any interface on this object is the object pointer.
+#ifdef ORIGINAL_CODE_LOOKS_WRONG
+ if (IID_IUnknown==riid || IID_IClassFactory==riid)
+#else
+ if (IsEqualIID(IID_IUnknown, riid)|| IsEqualIID(IID_IClassFactory, riid))
+#endif
+ *ppv = this;
+
+ if (NULL!=*ppv)
+ {
+ ((LPUNKNOWN)*ppv)->AddRef();
+ return NOERROR;
+ }
+
+ return ResultFromScode(E_NOINTERFACE);
+}
+
+
+STDMETHODIMP_(ULONG)
+CDataObjectClassFactory::AddRef(void)
+{
+ return ++m_cRef;
+}
+
+
+STDMETHODIMP_(ULONG)
+CDataObjectClassFactory::Release(void)
+{
+ ULONG cRefT;
+
+ cRefT=--m_cRef;
+
+ if (0L==m_cRef)
+ delete this;
+
+ return cRefT;
+}
+
+
+/*
+ * CDataObjectClassFactory::CreateInstance
+ *
+ * Purpose:
+ * Instantiates a CDataObject object that supports the IDataObject
+ * and IUnknown interfaces. If the caller asks for a different
+ * interface than these two then we fail.
+ *
+ * Parameters:
+ * pUnkOuter LPUNKNOWN to the controlling IUnknown if we are
+ * being used in an aggregation.
+ * riid REFIID identifying the interface the caller
+ * desires to have for the new object.
+ * ppvObj PPVOID in which to store the desired interface
+ * pointer for the new object.
+ *
+ * Return Value:
+ * HRESULT NOERROR if successful, otherwise contains
+ * E_NOINTERFACE if we cannot support the
+ * requested interface.
+ */
+
+STDMETHODIMP
+CDataObjectClassFactory::CreateInstance(
+ LPUNKNOWN pUnkOuter,
+ REFIID riid,
+ PPVOID ppvObj)
+{
+ PCDataObject pObj;
+ HRESULT hr;
+
+ *ppvObj=NULL;
+ hr=ResultFromScode(E_OUTOFMEMORY);
+
+#ifdef ORIGINAL_CODE_LOOKS_WRONG
+ if (NULL!=pUnkOuter && IID_IUnknown!=riid)
+#else
+ if (NULL!=pUnkOuter && (! IsEqualIID(IID_IUnknown, riid) ) )
+#endif
+ return ResultFromScode(E_NOINTERFACE);
+
+ //Create the object telling it the data size to work with
+ pObj=new CDataObject(pUnkOuter, ObjectDestroyed);
+
+ if (NULL==pObj)
+ return hr;
+
+ if (pObj->FInit())
+ hr=pObj->QueryInterface(riid, ppvObj);
+
+ g_cObj++;
+
+ if (FAILED(hr))
+ {
+ delete pObj;
+ ObjectDestroyed(); //Decrements g_cObj
+ }
+
+ return hr;
+}
+
+
+/*
+ * CDataObjectClassFactory::LockServer
+ *
+ * Purpose:
+ * Increments or decrements the lock count of the serving
+ * IClassFactory object. When the number of locks goes to
+ * zero and the number of objects is zero, we shut down the
+ * application.
+ *
+ * Parameters:
+ * fLock BOOL specifying whether to increment or
+ * decrement the lock count.
+ *
+ * Return Value:
+ * HRESULT NOERROR always.
+ */
+
+STDMETHODIMP
+CDataObjectClassFactory::LockServer(
+ BOOL fLock)
+{
+ if (fLock)
+ g_cLock++;
+ else
+ {
+ g_cLock--;
+
+ //No more objects and no locks, shut the app down.
+ if (0L==g_cObj && 0L==g_cLock && IsWindow(g_hWnd))
+ PostMessage(g_hWnd, WM_CLOSE, 0, 0L);
+ }
+
+ return NOERROR;
+}
diff --git a/private/oleutest/perf16/idata/server/edataobj.def b/private/oleutest/perf16/idata/server/edataobj.def
new file mode 100644
index 000000000..36f7ec79e
--- /dev/null
+++ b/private/oleutest/perf16/idata/server/edataobj.def
@@ -0,0 +1,5 @@
+NAME EDATAOBJ
+DESCRIPTION 'Data Object EXE Chapter 6 (c)1993-1995 Microsoft Corp.'
+
+CODE PRELOAD DISCARDABLE
+DATA PRELOAD MULTIPLE
diff --git a/private/oleutest/perf16/idata/server/edataobj.h b/private/oleutest/perf16/idata/server/edataobj.h
new file mode 100644
index 000000000..ea417f303
--- /dev/null
+++ b/private/oleutest/perf16/idata/server/edataobj.h
@@ -0,0 +1,63 @@
+#ifndef _EDATAOBJ_H_
+#define _EDATAOBJ_H_
+
+#include "dataobj.h"
+
+
+//EDATAOBJ.CPP
+LRESULT WINAPI DataObjectWndProc(HWND, UINT, WPARAM, LPARAM);
+
+
+class CAppVars
+{
+ friend LRESULT WINAPI DataObjectWndProc(HWND, UINT, WPARAM, LPARAM);
+
+protected:
+ HINSTANCE m_hInst; //WinMain parameters
+ HINSTANCE m_hInstPrev;
+ LPSTR m_pszCmdLine;
+ UINT m_nCmdShow;
+
+ HWND m_hWnd; //Main window handle
+ BOOL m_fInitialized; //Did CoInitialize work?
+
+ //We have multiple classes, one for each data size.
+ // DWORD m_rgdwRegCO[DOSIZE_CSIZES];
+ // LPCLASSFACTORY m_rgpIClassFactory[DOSIZE_CSIZES];
+ DWORD m_dwRegCO;
+ LPCLASSFACTORY m_pIClassFactory;
+
+public:
+ CAppVars(HINSTANCE, HINSTANCE, LPSTR, UINT);
+ ~CAppVars(void);
+ BOOL FInit(void);
+};
+
+typedef CAppVars *PAPPVARS;
+
+void PASCAL ObjectDestroyed(void);
+
+//This class factory object creates Data Objects.
+
+class CDataObjectClassFactory : public IClassFactory
+{
+protected:
+ ULONG m_cRef;
+
+public:
+ CDataObjectClassFactory();
+ ~CDataObjectClassFactory(void);
+
+ //IUnknown members
+ STDMETHODIMP QueryInterface(REFIID, PPVOID);
+ STDMETHODIMP_(ULONG) AddRef(void);
+ STDMETHODIMP_(ULONG) Release(void);
+
+ //IClassFactory members
+ STDMETHODIMP CreateInstance(LPUNKNOWN, REFIID, PPVOID);
+ STDMETHODIMP LockServer(BOOL);
+};
+
+typedef CDataObjectClassFactory *PCDataObjectClassFactory;
+
+#endif //_EDATAOBJ_H_
diff --git a/private/oleutest/perf16/idata/server/idataobj.cpp b/private/oleutest/perf16/idata/server/idataobj.cpp
new file mode 100644
index 000000000..36a81538c
--- /dev/null
+++ b/private/oleutest/perf16/idata/server/idataobj.cpp
@@ -0,0 +1,261 @@
+#include "dataobj.h"
+#include <stdlib.h>
+
+CImpIDataObject::CImpIDataObject(
+ PCDataObject pObj,
+ LPUNKNOWN pUnkOuter
+)
+{
+ m_cRef = 0;
+ m_pObj = pObj;
+ m_pUnkOuter = pUnkOuter;
+ return;
+}
+
+
+CImpIDataObject::~CImpIDataObject(void)
+{
+ return;
+}
+
+STDMETHODIMP
+CImpIDataObject::QueryInterface(
+ REFIID riid,
+ LPLPVOID ppv
+)
+{
+ return m_pUnkOuter->QueryInterface(riid, ppv);
+}
+
+STDMETHODIMP_(ULONG)
+CImpIDataObject::AddRef(void)
+{
+ ++m_cRef;
+ return m_pUnkOuter->AddRef();
+}
+
+STDMETHODIMP_(ULONG)
+CImpIDataObject::Release(void)
+{
+ --m_cRef;
+ return m_pUnkOuter->Release();
+}
+
+STDMETHODIMP
+CImpIDataObject::GetData(
+ LPFORMATETC pFE,
+ LPSTGMEDIUM pSTM
+)
+{
+ UINT cf = pFE->cfFormat;
+
+ if (!(DVASPECT_CONTENT & pFE->dwAspect))
+ return ResultFromScode(DATA_E_FORMATETC);
+
+ switch (cf)
+ {
+ case CF_TEXT:
+ if (!(TYMED_HGLOBAL & pFE->tymed))
+ break;
+ return m_pObj->RenderText(pSTM, TEXT("Getdata"),
+ FL_MAKE_ITEM | FL_PASS_PUNK);
+
+ default:
+ break;
+ }
+ return ResultFromScode(DATA_E_FORMATETC);
+}
+
+
+
+STDMETHODIMP
+CImpIDataObject::GetDataHere(
+ LPFORMATETC pFE,
+ LPSTGMEDIUM pSTM
+)
+{
+ UINT cf = pFE->cfFormat;
+
+ if (!(DVASPECT_CONTENT & pFE->dwAspect))
+ return ResultFromScode(DATA_E_FORMATETC);
+
+ switch (cf)
+ {
+ case CF_TEXT:
+ if (!(TYMED_HGLOBAL & pFE->tymed))
+ break;
+
+ if(TYMED_NULL == pSTM->tymed)
+ return ResultFromScode(S_OK);
+
+ if(TYMED_HGLOBAL != pSTM->tymed)
+ return ResultFromScode(E_INVALIDARG);
+
+ return m_pObj->RenderText(pSTM, TEXT("GetDataHere"), FL_USE_ITEM);
+
+ default:
+ return ResultFromScode( DATA_E_FORMATETC );
+
+ }
+ return ResultFromScode(E_NOTIMPL);
+}
+
+STDMETHODIMP
+CImpIDataObject::QueryGetData(
+ LPFORMATETC pFE
+)
+{
+ UINT cf = pFE->cfFormat;
+ BOOL fRet = FALSE;
+
+ if (!(DVASPECT_CONTENT & pFE->dwAspect))
+ return ResultFromScode(DATA_E_FORMATETC);
+
+ switch (cf)
+ {
+ case CF_TEXT:
+ fRet = (BOOL) (pFE->tymed & TYMED_HGLOBAL);
+ break;
+
+ default:
+ fRet = FALSE;
+ break;
+ }
+ return fRet ? NOERROR : ResultFromScode(S_FALSE);
+}
+
+STDMETHODIMP
+CImpIDataObject::GetCanonicalFormatEtc(
+ LPFORMATETC pFEIn,
+ LPFORMATETC pFEOut
+)
+{
+ if (NULL==pFEOut)
+ return ResultFromScode(E_INVALIDARG);
+
+ pFEOut->ptd = NULL;
+ return ResultFromScode(DATA_S_SAMEFORMATETC);
+}
+
+STDMETHODIMP
+CImpIDataObject::SetData(
+ LPFORMATETC pFE,
+ STGMEDIUM FAR *pST,
+ BOOL fRelease
+)
+{
+ UINT cf = pFE->cfFormat;
+ int iArg;
+
+ if (!(DVASPECT_CONTENT & pFE->dwAspect))
+ return ResultFromScode(DATA_E_FORMATETC);
+
+ switch (cf)
+ {
+ case CF_TEXT:
+ if (!(TYMED_HGLOBAL & pFE->tymed))
+ break;
+
+ if(TYMED_HGLOBAL != pST->tymed)
+ return ResultFromScode(E_INVALIDARG);
+
+ LPTSTR psz=(LPTSTR)GlobalLock(pST->hGlobal); // Lock
+ iArg = *((long*)psz); // Use
+ GlobalUnlock(pST->hGlobal); // Unlock
+
+ if(iArg > 0)
+ {
+ m_pObj->m_cDataSize = iArg;
+ return NOERROR;
+ }
+ }
+ if(-1 == iArg && fRelease)
+ {
+ ReleaseStgMedium(pST);
+ return NOERROR;
+ }
+ return ResultFromScode(E_NOTIMPL);
+}
+
+STDMETHODIMP
+CImpIDataObject::EnumFormatEtc(
+ DWORD dwDir,
+ LPENUMFORMATETC FAR *ppEnum
+)
+{
+ switch (dwDir)
+ {
+ case DATADIR_GET:
+ *ppEnum = (LPENUMFORMATETC) new CEnumFormatEtc(
+ m_pUnkOuter,
+ m_pObj->m_cfeGet,
+ m_pObj->m_rgfeGet );
+ break;
+
+ case DATADIR_SET:
+ *ppEnum = NULL;
+ break;
+
+ default:
+ *ppEnum = NULL;
+ break;
+ }
+ if (NULL == *ppEnum)
+ return ResultFromScode(E_FAIL);
+ else
+ (*ppEnum)->AddRef();
+
+ return NOERROR;
+}
+
+STDMETHODIMP
+CImpIDataObject::DAdvise(
+ LPFORMATETC pFE,
+ DWORD dwFlags,
+ LPADVISESINK pIAdviseSink,
+ LPDWORD pdwConn
+)
+{
+ HRESULT hr;
+
+ if (NULL == m_pObj->m_pIDataAdviseHolder)
+ {
+ hr = CreateDataAdviseHolder(&m_pObj->m_pIDataAdviseHolder);
+ if(FAILED(hr))
+ return ResultFromScode(E_OUTOFMEMORY);
+ }
+ hr = m_pObj->m_pIDataAdviseHolder->Advise(
+ (LPDATAOBJECT)this,
+ pFE,
+ dwFlags,
+ pIAdviseSink,
+ pdwConn );
+ return hr;
+}
+
+STDMETHODIMP
+CImpIDataObject::DUnadvise(
+ DWORD dwConn
+)
+{
+ HRESULT hr;
+
+ if (NULL==m_pObj->m_pIDataAdviseHolder)
+ return ResultFromScode(E_FAIL);
+ hr = m_pObj->m_pIDataAdviseHolder->Unadvise(dwConn);
+ return hr;
+}
+
+STDMETHODIMP
+CImpIDataObject::EnumDAdvise(
+ LPENUMSTATDATA FAR *ppEnum
+)
+{
+ HRESULT hr;
+
+ if (NULL==m_pObj->m_pIDataAdviseHolder)
+ return ResultFromScode(E_FAIL);
+
+ hr = m_pObj->m_pIDataAdviseHolder->EnumAdvise(ppEnum);
+ return hr;
+}
diff --git a/private/oleutest/perf16/idata/server/ienumfe.cpp b/private/oleutest/perf16/idata/server/ienumfe.cpp
new file mode 100644
index 000000000..b99c777ba
--- /dev/null
+++ b/private/oleutest/perf16/idata/server/ienumfe.cpp
@@ -0,0 +1,146 @@
+#include "dataobj.h"
+
+CEnumFormatEtc::CEnumFormatEtc(
+ LPUNKNOWN pUnkRef,
+ ULONG cFE,
+ LPFORMATETC prgFE
+)
+{
+ UINT i;
+
+ m_cRef = 0;
+ m_pUnkRef = pUnkRef;
+
+ m_iCur = 0;
+ m_cfe = cFE;
+ m_prgfe = new FORMATETC[ (UINT) cFE ];
+
+ if (NULL != m_prgfe)
+ {
+ for(i=0; i<cFE; i++)
+ m_prgfe[i] = prgFE[i];
+ }
+ return;
+}
+
+CEnumFormatEtc::~CEnumFormatEtc(void)
+{
+ if (NULL != m_prgfe)
+ delete [] m_prgfe;
+ return;
+}
+
+STDMETHODIMP
+CEnumFormatEtc::QueryInterface(
+ REFIID riid,
+ LPLPVOID ppv
+)
+{
+ *ppv = NULL;
+ if(IsEqualIID(riid, IID_IUnknown)
+ || IsEqualIID(riid, IID_IEnumFORMATETC))
+ {
+ *ppv = (LPVOID) this;
+ }
+ if (NULL != *ppv)
+ {
+ ((LPUNKNOWN)*ppv)->AddRef();
+ return NOERROR;
+ }
+ return ResultFromScode(E_NOINTERFACE);
+}
+
+STDMETHODIMP_(ULONG)
+CEnumFormatEtc::AddRef(void)
+{
+ ++m_cRef;
+ m_pUnkRef->AddRef();
+ return m_cRef;
+}
+
+STDMETHODIMP_(ULONG)
+CEnumFormatEtc::Release(void)
+{
+ ULONG cRefT;
+
+ cRefT = --m_cRef;
+
+ if (0 == m_cRef)
+ delete this;
+
+ return cRefT;
+}
+
+STDMETHODIMP
+CEnumFormatEtc::Next(
+ ULONG cFE,
+ LPFORMATETC pFE,
+ ULONG FAR *pulFE
+)
+{
+ ULONG cReturn = 0L;
+
+ if (NULL == m_prgfe)
+ return ResultFromScode(S_FALSE);
+
+ if (NULL == pulFE)
+ {
+ if (1L != cFE)
+ return ResultFromScode(E_POINTER);
+ }
+ else
+ *pulFE = 0L;
+
+ if (NULL == pFE || m_iCur >= m_cfe)
+ return ResultFromScode(S_FALSE);
+
+ while ( (m_iCur < m_cfe) && (cFE > 0) )
+ {
+ *pFE++ = m_prgfe[m_iCur++];
+ ++cReturn;
+ --cFE;
+ }
+
+ if (NULL != pulFE)
+ *pulFE = cReturn;
+
+ return NOERROR;
+}
+
+STDMETHODIMP
+CEnumFormatEtc::Skip(
+ ULONG cSkip
+)
+{
+ if ( ( (m_iCur+cSkip) > m_cfe) || (NULL == m_prgfe) )
+ return ResultFromScode(S_FALSE);
+
+ m_iCur += cSkip;
+ return NOERROR;
+}
+
+STDMETHODIMP
+CEnumFormatEtc::Reset(void)
+{
+ m_iCur = 0;
+ return NOERROR;
+}
+
+STDMETHODIMP
+CEnumFormatEtc::Clone(
+ LPENUMFORMATETC FAR *ppEnum
+)
+{
+ PCEnumFormatEtc pNew;
+
+ *ppEnum = NULL;
+
+ pNew = new CEnumFormatEtc(m_pUnkRef, m_cfe, m_prgfe);
+ if (NULL == pNew)
+ return ResultFromScode(E_OUTOFMEMORY);
+ pNew->AddRef();
+ pNew->m_iCur = m_iCur;
+
+ *ppEnum = pNew;
+ return NOERROR;
+}
diff --git a/private/oleutest/perf16/idata/server/make16.inc b/private/oleutest/perf16/idata/server/make16.inc
new file mode 100644
index 000000000..ec6d94d20
--- /dev/null
+++ b/private/oleutest/perf16/idata/server/make16.inc
@@ -0,0 +1,331 @@
+# 16-bit makefile
+#
+# Copyright (c) 1991, Microsoft Corporation
+#
+# History:
+#
+# 18-Feb-1994 KevinRo
+# 24-Feb-1994 DrewB, added OBJDIR and some other niceties from win40.mk
+#
+
+.SUFFIXES:
+.SUFFIXES: .c .cxx .cpp .asm .h .inc .obj .lst
+.SUFFIXES: .sys .exe .com .map .sym .def .lib .rc .res
+
+!if "$(TARGET)" == ""
+!error TARGET must be defined
+!endif
+
+OUTNUL= 1>nul 2>nul
+
+!if "$(NTDEBUG)" != "" && "$(NTDEBUG)" != "retail"
+OBJDIR = obj16d
+!else
+OBJDIR = obj16r
+!endif
+
+# Build up lists of files to produce from sources
+
+!if "$(CFILES)" != ""
+OBJFILES = $(OBJFILES) $(CFILES:.c=.obj)
+!endif
+!if "$(CXXFILES)" != ""
+OBJFILES = $(OBJFILES) $(CXXFILES:.cxx=.obj)
+!endif
+!if "$(CPPFILES)" != ""
+OBJFILES = $(OBJFILES) $(CPPFILES:.cpp=.obj)
+!endif
+
+!if "$(ASMFILES)" != ""
+OBJFILES = $(OBJFILES) $(ASMFILES:.asm=.obj)
+!endif
+
+!if "$(RCFILES)" != ""
+RESFILES = $(RCFILES:.rc=.res)
+!endif
+
+# Replace .\ with $(OBJDIR)
+# Unfortunately we can't do this directly so we have to explicitly check
+# the value of OBJDIR
+
+!if "$(OBJDIR)" == "obj16d"
+OBJFILES = $(OBJFILES:.\=obj16d\)
+RESFILES = $(RESFILES:.\=obj16d\)
+
+!elseif "$(OBJDIR)" == "obj16r"
+OBJFILES = $(OBJFILES:.\=obj16r\)
+RESFILES = $(RESFILES:.\=obj16r\)
+
+!else
+!error Unknown OBJDIR: $(OBJDIR)
+!endif
+
+# Default target
+
+all: $(OBJDIR)\$(TARGET)
+
+# Determine target type and base name
+
+# Is it a DLL?
+TARGETBASE=$(TARGET:.dll=)
+!if "$(TARGETBASE)" != "$(TARGET)"
+TARGETTYPE=dll
+!else
+
+# Is it an EXE?
+TARGETBASE=$(TARGET:.exe=)
+! if "$(TARGETBASE)" != "$(TARGET)"
+TARGETTYPE=exe
+! else
+
+# Is it a LIB?
+TARGETBASE=$(TARGET:.lib=)
+! if "$(TARGETBASE)" != "$(TARGET)"
+TARGETTYPE=lib
+! endif
+! endif
+!endif
+
+!if "$(TARGETTYPE)" == ""
+!error Unknown target type for "$(TARGET)"
+!endif
+
+!if "$(BUILDDETAILS)" != ""
+BLDKEEP= KEEP
+!endif
+
+OLETHUNK= $(_NTDRIVE)$(_NTROOT)\private\ole32\olethunk
+OLE16= $(OLETHUNK)\ole16
+
+RCINC = $(RCINC) -i$(OLE16)\inc
+INCS = -I$(OLE16)\inc -I$(OLETHUNK)\h -I$(_NTDRIVE)$(_NTROOT)\private\cinc
+
+
+PATH = $(OLE16)\tools;$(PATH)
+LINK = link16
+RC = rc16
+CL = cl16
+IMPLIB = implib
+LIBUTIL = lib16
+MAPSYM = mapsym
+MASM = masm
+
+DEFINES = -DWOW
+
+AOBJ = -Mx -t $(DEFINES) $(INCS)
+
+!if "$(TARGETTYPE)" == "exe"
+CW16 = -GA
+!else
+CW16 = -GD
+DEFINES = $(DEFINES) -D_WINDLL
+!endif
+
+CW16 = $(CW16) -G2 -AL $(DEFINES) $(INCS) /NMSEG_CODE
+
+LFLAGS = $(LFLAGS) /nod /noe /map:0 /align:16
+
+!if "$(NTDEBUG)" != "" && "$(NTDEBUG)" != "retail"
+
+DEFINES = $(DEFINES) -DDBG=1 -DDEVL=1
+
+!if "$(NTDEBUGTYPE)" == "windbg"
+AOBJ = $(AOBJ) -Zi
+CW16 = $(CW16) /Odi /Zip /FA
+LFLAGS = $(LFLAGS) /CO
+!else
+AOBJ = $(AOBJ) -Zd
+CW16 = $(CW16) /Odi /Zd
+LFLAGS = $(LFLAGS) /LI
+!endif
+
+!else
+CW16 = $(CW16) /Os /Zp /Gs
+DEFINES = $(DEFINES) -DDBG=0 -DDEVL=1
+!endif
+
+!if "$(TARGETTYPE)" == "dll"
+W16LIBS = $(OLE16)\lib\ldllcew.lib
+!else
+!if "$(QUICKWINDOWS)" != ""
+W16LIBS = $(OLE16)\lib\llibcewq.lib
+!else
+W16LIBS = $(OLE16)\lib\llibcew.lib
+!endif
+!endif
+
+W16LIBS = $(W16LIBS) $(OLE16)\lib\libw.lib
+
+!if "$(TARGETTYPE)" == "dll" || "$(TARGETTYPE)" == "exe"
+LIBS = $(LIBS) $(W16LIBS)
+!endif
+
+.asm{$(OBJDIR)}.obj:
+ @-md $(OBJDIR) $(OUTNUL)
+ $(MASM) $(AOBJ) $*,$*;
+
+.asm.lst:
+ @-md $(OBJDIR) $(OUTNUL)
+ $(MASM) $(AOBJ) -l $*,nul,$*.lst;
+
+
+.c{$(OBJDIR)}.obj:
+ @-md $(OBJDIR) $(OUTNUL)
+ $(CL) -c -nologo @<<$*.rsp
+$(CW16: =
+)
+-Fo$*.obj
+$<
+<<$(BLDKEEP)
+
+.c.lst:
+ @-md $(OBJDIR) $(OUTNUL)
+ $(CL) -c -nologo @<<$(OBJDIR)\$*.rsp
+$(CW16: =
+)
+-Fonul
+-Fc$*.lst
+$<
+<<$(BLDKEEP)
+
+.cxx{$(OBJDIR)}.obj:
+ @-md $(OBJDIR) $(OUTNUL)
+ $(CL) -c -nologo @<<$*.rsp
+$(CW16: =
+)
+-Fo$*.obj
+-Tp$<
+<<$(BLDKEEP)
+
+.cxx.lst:
+ @-md $(OBJDIR) $(OUTNUL)
+ $(CL) -c -nologo @<<$(OBJDIR)\$*.rsp
+$(CW16: =
+)
+-Fc$*.lst
+-Fonul
+-Tp$<
+<<$(BLDKEEP)
+
+.cxx.pp:
+ @-md $(OBJDIR) $(OUTNUL)
+ $(CL) -c -nologo @<<$(OBJDIR)\$*.rsp > $*.pp
+$(CW16: =
+)
+-E
+-Fonul
+-Tp$<
+<<$(BLDKEEP)
+
+
+.cpp{$(OBJDIR)}.obj:
+ @-md $(OBJDIR) $(OUTNUL)
+ $(CL) -c -nologo @<<$*.rsp
+$(CW16: =
+)
+-Fo$*.obj
+-Tp$<
+<<$(BLDKEEP)
+
+.cpp.lst:
+ @-md $(OBJDIR) $(OUTNUL)
+ $(CL) -c -nologo @<<$(OBJDIR)\$*.rsp
+$(CW16: =
+)
+-Fc$*.lst
+-Fonul
+-Tp$<
+<<$(BLDKEEP)
+
+.cpp.pp:
+ @-md $(OBJDIR) $(OUTNUL)
+ $(CL) -c -nologo @<<$(OBJDIR)\$*.rsp > $*.pp
+$(CW16: =
+)
+-E
+-Fonul
+-Tp$<
+<<$(BLDKEEP)
+
+
+.def{$(OBJDIR)}.lib:
+ @-md $(OBJDIR) $(OUTNUL)
+ $(IMPLIB) $*.lib $<
+
+{$(OBJDIR)}.map{$(OBJDIR)}.sym:
+ @-md $(OBJDIR) $(OUTNUL)
+ $(MAPSYM) $<
+
+.rc{$(OBJDIR)}.res:
+ @-md $(OBJDIR) $(OUTNUL)
+ $(RC) -r $(RCINC) -fo $*.res $<
+
+
+cleanup:
+ if exist $(OBJDIR)\*.lrf del $(OBJDIR)\*.lrf
+ if exist $(OBJDIR)\*.obj del $(OBJDIR)\*.obj
+ if exist $(OBJDIR)\*.exe del $(OBJDIR)\*.exe
+ if exist $(OBJDIR)\*.map del $(OBJDIR)\*.map
+ if exist $(OBJDIR)\*.sym del $(OBJDIR)\*.sym
+ if exist $(OBJDIR)\*.res del $(OBJDIR)\*.res
+
+clean: cleanup
+
+!if "$(TARGETTYPE)" == "dll"
+
+$(OBJDIR)\$(TARGETBASE).lib: $(TARGETBASE).def
+
+$(OBJDIR)\$(TARGET) $(OBJDIR)\$(TARGETBASE).map: $(OBJFILES) $(RESFILES) \
+ $(TARGETBASE).def $(OBJDIR)\$(TARGETBASE).lib $(LIBS)
+ @-md $(OBJDIR) $(OUTNUL)
+ $(LINK) $(LFLAGS) @<<$(OBJDIR)\$(TARGETBASE).rsp
+$(OBJFILES: =+^
+)
+$(OBJDIR)\$(TARGET)
+$(OBJDIR)\$(TARGETBASE).map
+$(LIBS: =+^
+)
+$(TARGETBASE).def
+<<$(BLDKEEP)
+ $(MAPSYM) -o $(OBJDIR)\$(TARGETBASE).sym $(OBJDIR)\$(TARGETBASE).map
+!if "$(RCFILES)" != ""
+ $(RC) -t $(OBJDIR)\$(TARGETBASE).res $(OBJDIR)\$(TARGET)
+!endif
+
+!elseif "$(TARGETTYPE)" == "lib"
+
+$(OBJDIR)\$(TARGET): $(OBJFILES) $(LIBS)
+ @-md $(OBJDIR) $(OUTNUL)
+ -del $@ $(OUTNUL)
+ $(LIBUTIL) @<<$*.lnb
+$(OBJDIR)\$(TARGET)
+y
+$(OBJFILES: = &^
+)&
+$(LIBS: = &^
+)&
+
+$*.lls
+<<$(BLDKEEP)
+
+!elseif "$(TARGETTYPE)" == "exe"
+
+$(OBJDIR)\$(TARGET) $(OBJDIR)\$(TARGETBASE).map: $(OBJFILES) $(RESFILES) \
+ $(TARGETBASE).def $(LIBS)
+ @-md $(OBJDIR) $(OUTNUL)
+ $(LINK) $(LFLAGS) @<<$(OBJDIR)\$(TARGETBASE).rsp
+$(OBJFILES: =+^
+)
+$(OBJDIR)\$(TARGET)
+$(OBJDIR)\$(TARGETBASE).map
+$(LIBS: =+^
+)
+$(TARGETBASE).def
+<<$(BLDKEEP)
+!if "$(RCFILES)" != ""
+ $(RC) -t $(OBJDIR)\$(TARGETBASE).res $(OBJDIR)\$(TARGET)
+!endif
+ $(MAPSYM) -o $(OBJDIR)\$(TARGETBASE).sym $(OBJDIR)\$(TARGETBASE).map
+
+!endif
+ \ No newline at end of file
diff --git a/private/oleutest/perf16/idata/server/make16.mak b/private/oleutest/perf16/idata/server/make16.mak
new file mode 100644
index 000000000..7d1dbc178
--- /dev/null
+++ b/private/oleutest/perf16/idata/server/make16.mak
@@ -0,0 +1,70 @@
+#//+---------------------------------------------------------------------------
+#//
+#// Microsoft Windows
+#// Copyright (C) Microsoft Corporation, 1992 - 1994.
+#//
+#// File: make16.mak
+#// Contents: make16.mak for 16 bit compile of idatasimple test
+#//
+#// History: 06-21-95 Chapman Created
+#//
+#//----------------------------------------------------------------------------
+
+NTDEBUG=1
+
+
+default: copy_bin
+
+TARGET = edataobj.exe
+TARGETTYPE = EXE
+OLETHUNK = $(_NTDRIVE)$(_NTROOT)\private\ole32\olethunk
+
+RCINC=$(RCINC) -i..\ole2ui -i..\ole2ui\res\usa
+
+# CDEFINES= -I..\ole2ui /GEs -I..
+
+
+LFLAGS=/STACK:16384
+
+CPPFILES = \
+ .\dataobj.cpp \
+ .\idataobj.cpp \
+ .\edataobj.cpp \
+ .\ienumfe.cpp \
+ .\stgmedif.cpp \
+ .\render.cpp
+
+# RCFILES = .\spsvr16.rc
+
+LIBS = $(LIBS)\
+ $(OLE16)\lib\ole2.lib \
+ $(OLE16)\lib\storage.lib \
+ $(OLE16)\lib\loleuic.lib \
+ $(OLE16)\lib\compobj.lib \
+ $(OLE16)\lib\shell.lib
+
+!include make16.inc
+
+
+!if "$(NTDEBUG)" != "" && "$(NTDEBUG)" != "retail"
+LIBS = $(LIBS) $(OLETHUNK)\debnot\$(OBJDIR)\debnot.lib
+!endif
+
+
+copy_bin: all
+ copy $(OBJDIR)\edataobj.exe $(OBJDIR)\edatas16.exe
+ copy $(OBJDIR)\edataobj.sym $(OBJDIR)\edatas16.sym
+ copy $(OBJDIR)\edataobj.map $(OBJDIR)\edatas16.map
+ binplace $(OBJDIR)\edatas16.exe
+
+
+DATAOBJ_H=dataobj.h ..\bookpart.h
+
+$(OBJDIR)\dataobj.obj: $(DATAOBJ_H)
+$(OBJDIR)\idataobj.obj: $(DATAOBJ_H)
+$(OBJDIR)\ienumfe.obj: $(DATAOBJ_H)
+$(OBJDIR)\edataobj.obj: $(DATAOBJ_H) edataobj.h
+$(OBJDIR)\render.obj: $(DATAOBJ_H)
+$(OBJDIR)\stgmedif.obj: $(DATAOBJ_H)
+$(OBJDIR)\dataclient.h: ..\bookpart.h
+
diff --git a/private/oleutest/perf16/idata/server/makefile b/private/oleutest/perf16/idata/server/makefile
new file mode 100644
index 000000000..1d3728d41
--- /dev/null
+++ b/private/oleutest/perf16/idata/server/makefile
@@ -0,0 +1,10 @@
+############################################################################
+#
+# Copyright (C) 1992, Microsoft Corporation.
+#
+# All rights reserved.
+#
+############################################################################
+
+!include $(NTMAKEENV)\makefile.def
+
diff --git a/private/oleutest/perf16/idata/server/render.cpp b/private/oleutest/perf16/idata/server/render.cpp
new file mode 100644
index 000000000..9474be216
--- /dev/null
+++ b/private/oleutest/perf16/idata/server/render.cpp
@@ -0,0 +1,50 @@
+#include "dataobj.h"
+#include <string.h>
+
+
+
+HRESULT
+CDataObject::RenderText(
+ LPSTGMEDIUM pSTM,
+ LPTSTR lptstr,
+ DWORD flags)
+{
+ DWORD cch;
+ HGLOBAL hMem;
+ LPTSTR psz;
+ UINT i;
+
+ if(!(FL_MAKE_ITEM & flags))
+ hMem = pSTM->hGlobal;
+ else
+ hMem = GlobalAlloc(GMEM_SHARE | GMEM_MOVEABLE, m_cDataSize);
+
+ if (NULL==hMem)
+ return ResultFromScode(STG_E_MEDIUMFULL);
+
+ cch = 64 / sizeof(TCHAR);
+ psz=(LPTSTR)GlobalLock(hMem);
+
+ wsprintf(psz, TEXT("%ld:"), m_cDataSize);
+
+ for (i=lstrlen(psz); i<cch-1, '\0'!=*lptstr; i++, lptstr++)
+ *(psz+i) = *lptstr;
+
+ for ( ; i < cch-1; i++)
+ *(psz+i)=TEXT(' ') + (i % 32);
+
+ *(psz+i)=0;
+
+ GlobalUnlock(hMem);
+
+ if(FL_MAKE_ITEM & flags)
+ {
+ pSTM->hGlobal=hMem;
+ pSTM->tymed=TYMED_HGLOBAL;
+ pSTM->pUnkForRelease=NULL;
+ }
+ if(FL_PASS_PUNK & flags)
+ GetStgMedpUnkForRelease(pSTM, &pSTM->pUnkForRelease);
+
+ return NOERROR;
+}
diff --git a/private/oleutest/perf16/idata/server/sources b/private/oleutest/perf16/idata/server/sources
new file mode 100644
index 000000000..56a26f939
--- /dev/null
+++ b/private/oleutest/perf16/idata/server/sources
@@ -0,0 +1,86 @@
+!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:
+
+ Brian Chapman (BChapman) July 10th 1995.
+
+!ENDIF
+
+MAJORCOMP = cairole
+MINORCOMP = perform
+
+#
+# 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= edataobj
+
+#
+# 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= $(BASEDIR)\private\ole32\h;..\..\common
+# INCLUDES= $(INCLUDES);$(BASEDIR)\private\oleutest\balls\oleprx32\daytona
+# INCLUDES= $(INCLUDES);$(BASEDIR)\private\ole32\common\daytona;..
+# INCLUDES= $(INCLUDES);..\..\ole32\tests
+
+C_DEFINES= \
+ $(C_DEFINES) \
+ -DFLAT \
+ -DWIN32=100 \
+ -D_NT1X_=100 \
+ -DUNICODE \
+ -D_UNICODE \
+ -DNOEXCEPTIONS \
+ -DCAIROLE_DOWNLEVEL
+
+BLDCRT= 1
+
+SOURCES= \
+ edataobj.cpp \
+ dataobj.cpp \
+ idataobj.cpp \
+ ienumfe.cpp \
+ stgmedif.cpp \
+ render.cpp
+
+
+UMTYPE= windows
+UMENTRY= winmain
+UMAPPL=
+UMTEST=
+UMLIBS=
+UMLIBS= \
+ $(BASEDIR)\public\sdk\lib\*\ole32.lib \
+ $(BASEDIR)\public\sdk\lib\*\comdlg32.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\*\crtdll.lib \
+ $(BASEDIR)\public\sdk\lib\*\uuid.lib
diff --git a/private/oleutest/perf16/idata/server/stgmedif.cpp b/private/oleutest/perf16/idata/server/stgmedif.cpp
new file mode 100644
index 000000000..e05f82c5c
--- /dev/null
+++ b/private/oleutest/perf16/idata/server/stgmedif.cpp
@@ -0,0 +1,56 @@
+#include "dataobj.h"
+
+HRESULT
+GetStgMedpUnkForRelease(LPSTGMEDIUM pSTM, IUnknown **pp_unk)
+{
+ CStgMedIf *p_smi = new CStgMedIf(pSTM);
+ HRESULT hr = p_smi->QueryInterface(IID_IUnknown, (PPVOID)pp_unk);
+ return hr;
+}
+
+CStgMedIf::CStgMedIf(LPSTGMEDIUM pSTM)
+{
+ m_pSTM = pSTM;
+ m_cRef = 0;
+}
+
+
+STDMETHODIMP
+CStgMedIf::QueryInterface(
+ REFIID riid,
+ LPLPVOID ppv
+)
+{
+ *ppv = NULL;
+ if (IsEqualIID(riid, IID_IUnknown))
+ {
+ *ppv = (LPVOID)this;
+ ((LPUNKNOWN)*ppv)->AddRef();
+ return NOERROR;
+ }
+ return ResultFromScode(E_NOINTERFACE);
+}
+
+
+STDMETHODIMP_(ULONG)
+CStgMedIf::AddRef(void)
+{
+ return ++m_cRef;
+}
+
+
+STDMETHODIMP_(ULONG)
+CStgMedIf::Release(void)
+{
+ ULONG cRefT;
+
+ cRefT = --m_cRef;
+
+ if (0==m_cRef)
+ {
+ m_pSTM->pUnkForRelease = 0;
+ ReleaseStgMedium(m_pSTM);
+ delete this;
+ }
+ return cRefT;
+}
diff --git a/private/oleutest/perf16/idata/syshead.h b/private/oleutest/perf16/idata/syshead.h
new file mode 100644
index 000000000..cd0ad3308
--- /dev/null
+++ b/private/oleutest/perf16/idata/syshead.h
@@ -0,0 +1,9 @@
+#ifndef __SYSHEAD_H
+#define __SYSHEAD_H
+
+#define INC_OLE2
+#include <windows.h>
+#include <ole2.h>
+#include <ole2ver.h>
+
+#endif // __SYSHEAD_H
diff --git a/private/oleutest/perform/bmcopy.bat b/private/oleutest/perform/bmcopy.bat
new file mode 100644
index 000000000..729a65b55
--- /dev/null
+++ b/private/oleutest/perform/bmcopy.bat
@@ -0,0 +1,8 @@
+set DEST=%1
+if %.1 == . set DEST=c:\winnt\system32
+copy cairole\dll\%OBJDIR%\oletest.dll %DEST%
+copy cairole\svr\%OBJDIR%\bmtstsvr.exe %DEST%
+copy rawrpc\%OBJDIR%\rawrpc.exe %DEST%
+copy driver\%OBJDIR%\benchmrk.exe %DEST%
+copy driver\bm.ini %DEST%
+
diff --git a/private/oleutest/perform/cairo.inc b/private/oleutest/perform/cairo.inc
new file mode 100644
index 000000000..2f35a9185
--- /dev/null
+++ b/private/oleutest/perform/cairo.inc
@@ -0,0 +1,45 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ cairo.inc
+
+Abstract:
+
+ common root include file for daytona version of performance
+ project build. This gets included by all sources files under
+ this directory.
+
+!ENDIF
+
+MAJORCOMP = cairole
+MINORCOMP = perform
+
+OLEDIR= $(BASEDIR)\private\ole32
+OLEUTESTDIR= $(BASEDIR)\private\oleutest
+OLEPERFDIR= $(OLEUTESTDIR)\perform
+
+
+INCLUDES= ;..;$(OLEPERFDIR)\common;$(OLEPERFDIR)\cairole\tests
+INCLUDES= $(INCLUDES);$(OLEUTESTDIR)\balls\oleprx32\cairo
+INCLUDES= $(INCLUDES);$(OLEDIR)\ih;$(OLEDIR)\common\cairo
+
+
+C_DEFINES= \
+ $(C_DEFINES) \
+ -DFLAT \
+ -DWIN32=300 \
+ -D_CAIRO_=300 \
+ -D_NT1X_=100 \
+ -DUNICODE \
+ -D_UNICODE \
+ -DNOEXCEPTIONS \
+ -D_DCOM_ \
+ -DCOM_THREADING_SUPPORT \
+ -DOLE_THREADING_SUPPORT
+
+BLDCRT=1
+
+CAIRO_PRODUCT=1
diff --git a/private/oleutest/perform/cairole/dirs b/private/oleutest/perform/cairole/dirs
new file mode 100644
index 000000000..f6236d291
--- /dev/null
+++ b/private/oleutest/perform/cairole/dirs
@@ -0,0 +1,39 @@
+!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= \
+ tests \
+ dll \
+ svr \
+ ui \
+
+#
+# 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=
diff --git a/private/oleutest/perform/cairole/dll/daytona/makefile b/private/oleutest/perform/cairole/dll/daytona/makefile
new file mode 100644
index 000000000..1d3728d41
--- /dev/null
+++ b/private/oleutest/perform/cairole/dll/daytona/makefile
@@ -0,0 +1,10 @@
+############################################################################
+#
+# Copyright (C) 1992, Microsoft Corporation.
+#
+# All rights reserved.
+#
+############################################################################
+
+!include $(NTMAKEENV)\makefile.def
+
diff --git a/private/oleutest/perform/cairole/dll/daytona/makefile.inc b/private/oleutest/perform/cairole/dll/daytona/makefile.inc
new file mode 100644
index 000000000..34400f60b
--- /dev/null
+++ b/private/oleutest/perform/cairole/dll/daytona/makefile.inc
@@ -0,0 +1 @@
+obj\i386\oletest.def: oletest.src
diff --git a/private/oleutest/perform/cairole/dll/daytona/oletest.src b/private/oleutest/perform/cairole/dll/daytona/oletest.src
new file mode 100644
index 000000000..944533676
--- /dev/null
+++ b/private/oleutest/perform/cairole/dll/daytona/oletest.src
@@ -0,0 +1,48 @@
+#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 oleimpl
+
+DESCRIPTION 'Microsoft (R) OLE 2.0 Proxy DLL 1.00'
+
+EXPORTS
+#if defined(i386)
+
+ _DllGetClassObject@12 @1
+ DllGetClassObject=_DllGetClassObject@12
+ _DllCanUnloadNow@0 @2
+ DllCanUnloadNow=_DllCanUnloadNow@0
+
+#elif defined(_MIPS_)
+
+ DllGetClassObject @1
+ DllCanUnloadNow @2
+
+#endif // i386 - MIPS
+
+#endif // FLAT
diff --git a/private/oleutest/perform/cairole/dll/daytona/sources b/private/oleutest/perform/cairole/dll/daytona/sources
new file mode 100644
index 000000000..4a36c6ecc
--- /dev/null
+++ b/private/oleutest/perform/cairole/dll/daytona/sources
@@ -0,0 +1,81 @@
+!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.
+
+!ENDIF
+
+!include ..\..\..\daytona.inc
+
+#
+# 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= oletest
+
+#
+# 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= DYNLINK
+
+DLLDEF= obj\*\oletest.def
+DLLBASE= @$(BASEDIR)\PUBLIC\SDK\LIB\coffbase.txt,usermode
+
+INCLUDES= $(INCLUDES)
+C_DEFINES= $(C_DEFINES)
+
+SOURCES= \
+ ..\oletest.cxx \
+ ..\testdllx.cxx \
+
+UMTYPE= console
+UMAPPL=
+UMTEST=
+UMLIBS=
+
+LINKLIBS= \
+ ..\..\tests\daytona\obj\*\bmtests.lib \
+ $(OLEDIR)\common\daytona\obj\*\common.lib \
+ $(OLEUTESTDIR)\balls\oleprx32\uuid\daytona\obj\*\uuid.lib \
+ $(BASEDIR)\public\sdk\lib\*\uuid.lib \
+ $(BASEDIR)\public\sdk\lib\*\ole32.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\*\crtdll.lib
+
+USE_CRTDLL= 1
+
+!IF $(386)
+NTTARGETFILE0=$(DLLDEF:*=i386)
+!ENDIF
+
+!IF $(MIPS)
+NTTARGETFILE0=$(DLLDEF:*=mips)
+!ENDIF
+
+!IF $(ALPHA)
+NTTARGETFILE0=$(DLLDEF:*=alpha)
+!ENDIF
diff --git a/private/oleutest/perform/cairole/dll/dirs b/private/oleutest/perform/cairole/dll/dirs
new file mode 100644
index 000000000..2084bae88
--- /dev/null
+++ b/private/oleutest/perform/cairole/dll/dirs
@@ -0,0 +1,38 @@
+!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/perform/cairole/dll/makefile b/private/oleutest/perform/cairole/dll/makefile
new file mode 100644
index 000000000..7f4951e2a
--- /dev/null
+++ b/private/oleutest/perform/cairole/dll/makefile
@@ -0,0 +1,25 @@
+############################################################################
+#
+# Copyright (C) 1992, Microsoft Corporation.
+#
+# All rights reserved.
+#
+############################################################################
+
+!ifdef NTMAKEENV
+
+# We need to do the following so that build will stop reading from the
+# pipe.
+
+all :
+ echo $(BUILDMSG)
+
+clean : all
+
+!else # NTMAKEENV
+
+!include $(CAIROLE)\com\makefile
+
+!include $(DEPENDFILE)
+
+!endif # NTMAKEENV
diff --git a/private/oleutest/perform/cairole/dll/oletest.cxx b/private/oleutest/perform/cairole/dll/oletest.cxx
new file mode 100644
index 000000000..8af4705f9
--- /dev/null
+++ b/private/oleutest/perform/cairole/dll/oletest.cxx
@@ -0,0 +1,130 @@
+//-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1993.
+//
+// File: oletest.cxx
+//
+// Contents: Simple OLE test object
+//
+// Classes: COleTestClass
+//
+// Functions:
+//
+// History: 1-July-93 t-martig Created
+//
+//--------------------------------------------------------------------------
+
+
+#include <oletest.hxx>
+
+
+
+ULONG objCount = 0, lockCount = 0;
+COleTestClassFactory theFactory;
+
+
+COleTestClass::COleTestClass ()
+{
+ refCount = 1;
+ objCount++;
+}
+
+
+
+COleTestClass::~COleTestClass ()
+{
+ objCount--;
+}
+
+
+
+SCODE COleTestClass::QueryInterface (THIS_ REFIID riid, LPVOID FAR* ppvObj)
+{
+ if (IsEqualIID (riid, IID_IUnknown))
+ *ppvObj = (LPVOID FAR)(IUnknown*)this;
+ else
+ {
+ *ppvObj = NULL;
+ return E_NOINTERFACE;
+ }
+
+ AddRef();
+ return S_OK;
+}
+
+
+
+ULONG COleTestClass::AddRef (THIS)
+{
+ return (refCount++);
+}
+
+
+ULONG COleTestClass::Release (THIS)
+{
+ refCount--;
+ if (refCount == 0)
+ {
+ delete this;
+ return 0;
+ }
+ return refCount;
+}
+
+
+
+
+SCODE COleTestClassFactory::QueryInterface (THIS_ REFIID riid, LPVOID FAR* ppvObj)
+{
+ if (IsEqualIID (riid, IID_IUnknown))
+ *ppvObj = (LPVOID FAR)(IUnknown*)this;
+ else
+ {
+ if (IsEqualIID (riid, IID_IClassFactory))
+ *ppvObj = (LPVOID FAR)(IClassFactory*)this;
+ else
+ {
+ *ppvObj = NULL;
+ return E_NOINTERFACE;
+ }
+ }
+ return S_OK;
+}
+
+
+
+ULONG COleTestClassFactory::AddRef (THIS)
+{
+ return 1;
+}
+
+
+ULONG COleTestClassFactory::Release (THIS)
+{
+ return 1;
+}
+
+
+SCODE COleTestClassFactory::CreateInstance (THIS_ LPUNKNOWN pUnkOuter,
+ REFIID riid, LPVOID FAR* ppvObject)
+{
+ *ppvObject = (LPVOID FAR*)(IStream*)new COleTestClass;
+ return S_OK;
+}
+
+
+
+SCODE COleTestClassFactory::LockServer (THIS_ BOOL fLock)
+{
+ if (fLock)
+ lockCount++;
+ else
+ lockCount--;
+
+ return S_OK;
+}
+
+
+
+
diff --git a/private/oleutest/perform/cairole/dll/oletest.def b/private/oleutest/perform/cairole/dll/oletest.def
new file mode 100644
index 000000000..5e081fb45
--- /dev/null
+++ b/private/oleutest/perform/cairole/dll/oletest.def
@@ -0,0 +1,38 @@
+#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 oletest
+
+DESCRIPTION 'Microsoft (R) OLE 2.0 Proxy DLL 1.00'
+
+EXPORTS
+
+ DllGetClassObject
+ DllCanUnloadNow
+
+#endif // FLAT
diff --git a/private/oleutest/perform/cairole/dll/testdllx.cxx b/private/oleutest/perform/cairole/dll/testdllx.cxx
new file mode 100644
index 000000000..d0c60ab75
--- /dev/null
+++ b/private/oleutest/perform/cairole/dll/testdllx.cxx
@@ -0,0 +1,49 @@
+//-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1993.
+//
+// File: testdllx.cxx
+//
+// Contents: DLL extensions
+//
+// Classes:
+//
+// Functions: DllGetClassObject
+// DllCanUnloadNow
+//
+// History: 1-July-93 t-martig Created
+//
+//--------------------------------------------------------------------------
+
+
+#include "oletest.hxx"
+
+
+extern ULONG objCount, lockCount;
+extern COleTestClassFactory theFactory;
+
+
+STDAPI DllGetClassObject (REFCLSID classId, REFIID riid, VOID **ppv)
+{
+ if (IsEqualGUID (classId, CLSID_COleTestClass))
+ return theFactory.QueryInterface (riid, ppv);
+ return E_UNEXPECTED;
+}
+
+
+
+STDAPI DllCanUnloadNow ()
+{
+ return (objCount==0 && lockCount==0) ? S_OK : E_UNEXPECTED;
+}
+
+
+extern "C"
+BOOL _cdecl LibMain (HINSTANCE hDll, DWORD dwReason, LPVOID lpReserved)
+{
+ return TRUE;
+}
+
+
+
diff --git a/private/oleutest/perform/cairole/makefile b/private/oleutest/perform/cairole/makefile
new file mode 100644
index 000000000..7f4951e2a
--- /dev/null
+++ b/private/oleutest/perform/cairole/makefile
@@ -0,0 +1,25 @@
+############################################################################
+#
+# Copyright (C) 1992, Microsoft Corporation.
+#
+# All rights reserved.
+#
+############################################################################
+
+!ifdef NTMAKEENV
+
+# We need to do the following so that build will stop reading from the
+# pipe.
+
+all :
+ echo $(BUILDMSG)
+
+clean : all
+
+!else # NTMAKEENV
+
+!include $(CAIROLE)\com\makefile
+
+!include $(DEPENDFILE)
+
+!endif # NTMAKEENV
diff --git a/private/oleutest/perform/cairole/svr/bmtstsvr.cxx b/private/oleutest/perform/cairole/svr/bmtstsvr.cxx
new file mode 100644
index 000000000..a77de4965
--- /dev/null
+++ b/private/oleutest/perform/cairole/svr/bmtstsvr.cxx
@@ -0,0 +1,52 @@
+//-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1993.
+//
+// File: bmtstsvr.cxx
+//
+// Contents: Test server for benchmark test
+//
+// Classes:
+//
+// Functions: WinMain
+//
+// History: 1-July-93 t-martig Created
+//
+//--------------------------------------------------------------------------
+
+
+#include <oletest.hxx>
+
+
+extern COleTestClassFactory theFactory;
+extern ULONG objCount, lockCount;
+
+
+int APIENTRY WinMain(
+ HINSTANCE hInstance,
+ HINSTANCE hPrevInstance,
+ LPSTR lpCmdLine,
+ int nCmdShow
+ )
+{
+ DWORD reg;
+ objCount = lockCount = 0;
+
+ OleInitialize (NULL);
+ CoRegisterClassObject (CLSID_COleTestClass, (IClassFactory *)&theFactory,
+ CLSCTX_LOCAL_SERVER,0, &reg);
+
+ while (objCount==0 && lockCount==0)
+ Sleep (1000);
+ while (objCount || lockCount)
+ {
+ Sleep (3000);
+ }
+
+ CoRevokeClassObject (reg);
+
+ OleUninitialize ();
+
+ return 0;
+}
diff --git a/private/oleutest/perform/cairole/svr/daytona/makefile b/private/oleutest/perform/cairole/svr/daytona/makefile
new file mode 100644
index 000000000..1d3728d41
--- /dev/null
+++ b/private/oleutest/perform/cairole/svr/daytona/makefile
@@ -0,0 +1,10 @@
+############################################################################
+#
+# Copyright (C) 1992, Microsoft Corporation.
+#
+# All rights reserved.
+#
+############################################################################
+
+!include $(NTMAKEENV)\makefile.def
+
diff --git a/private/oleutest/perform/cairole/svr/daytona/sources b/private/oleutest/perform/cairole/svr/daytona/sources
new file mode 100644
index 000000000..8dd90ceb0
--- /dev/null
+++ b/private/oleutest/perform/cairole/svr/daytona/sources
@@ -0,0 +1,68 @@
+!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.
+
+!ENDIF
+
+!include ..\..\..\daytona.inc
+
+#
+# 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= bmtstsvr
+
+#
+# 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= $(INCLUDES)
+C_DEFINES= $(C_DEFINES)
+
+SOURCES= \
+ ..\bmtstsvr.cxx
+
+UMTYPE= windows
+UMENTRY= winmain
+UMAPPL=
+UMTEST=
+UMLIBS=
+
+LINKLIBS= \
+ ..\..\dll\daytona\obj\*\oletest.obj \
+ ..\..\tests\daytona\obj\*\bmguid.obj \
+ ..\..\tests\daytona\obj\*\bmtests.lib \
+ $(OLEDIR)\common\daytona\obj\*\common.lib \
+ $(OLEUTESTDIR)\balls\oleprx32\uuid\daytona\obj\*\uuid.lib \
+ $(BASEDIR)\public\sdk\lib\*\uuid.lib \
+ $(BASEDIR)\public\sdk\lib\*\ole32.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\*\crtdll.lib
+
+USE_CRTDLL= 1
diff --git a/private/oleutest/perform/cairole/svr/dirs b/private/oleutest/perform/cairole/svr/dirs
new file mode 100644
index 000000000..2084bae88
--- /dev/null
+++ b/private/oleutest/perform/cairole/svr/dirs
@@ -0,0 +1,38 @@
+!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/perform/cairole/svr/makefile b/private/oleutest/perform/cairole/svr/makefile
new file mode 100644
index 000000000..7f4951e2a
--- /dev/null
+++ b/private/oleutest/perform/cairole/svr/makefile
@@ -0,0 +1,25 @@
+############################################################################
+#
+# Copyright (C) 1992, Microsoft Corporation.
+#
+# All rights reserved.
+#
+############################################################################
+
+!ifdef NTMAKEENV
+
+# We need to do the following so that build will stop reading from the
+# pipe.
+
+all :
+ echo $(BUILDMSG)
+
+clean : all
+
+!else # NTMAKEENV
+
+!include $(CAIROLE)\com\makefile
+
+!include $(DEPENDFILE)
+
+!endif # NTMAKEENV
diff --git a/private/oleutest/perform/cairole/tests/bm_activ.cxx b/private/oleutest/perform/cairole/tests/bm_activ.cxx
new file mode 100644
index 000000000..40927ddf8
--- /dev/null
+++ b/private/oleutest/perform/cairole/tests/bm_activ.cxx
@@ -0,0 +1,158 @@
+//+- -----------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1993.
+//
+// File: bm_activ.cxx
+//
+// Contents: Ole object activation test
+//
+// Classes: COleActivationTest
+//
+// History: 1-July-93 t-martig Created
+//
+//--------------------------------------------------------------------------
+#include <headers.cxx>
+#pragma hdrstop
+
+#include <bm_activ.hxx>
+#include <oletest.hxx>
+
+
+TCHAR *COleActivationTest::Name ()
+{
+ return TEXT("ObjActivation");
+}
+
+
+SCODE COleActivationTest::Setup (CTestInput *pInput)
+{
+ SCODE sc;
+
+ CTestBase::Setup(pInput);
+
+ // get iteration count
+ m_ulIterations = pInput->GetIterations(Name());
+
+ // initialize state
+ for (ULONG iCtx=0; iCtx<CNT_CLSCTX; iCtx++)
+ {
+ sc = pInput->GetGUID(&m_ClsID[iCtx], Name(), apszClsIDName[iCtx]);
+ if (FAILED(sc))
+ {
+ Log (TEXT("Setup - GetClassID failed."), sc);
+ return sc;
+ }
+
+ INIT_RESULTS(m_ulGetClassObjectTime[iCtx]);
+ INIT_RESULTS(m_ulCreateInstanceTime[iCtx]);
+ INIT_RESULTS(m_ulLoadTime[iCtx]);
+ INIT_RESULTS(m_ulPunkReleaseTime[iCtx]);
+ INIT_RESULTS(m_ulCFReleaseTime[iCtx]);
+ }
+
+ sc = InitCOM();
+ if (FAILED(sc))
+ {
+ Log (TEXT("Setup - InitCOM failed."), sc);
+ return sc;
+ }
+
+ return S_OK;
+}
+
+
+SCODE COleActivationTest::Cleanup ()
+{
+ UninitCOM();
+ return S_OK;
+}
+
+
+SCODE COleActivationTest::Run ()
+{
+ CStopWatch sw;
+ IPersistFile *pIPF = NULL;
+ IClassFactory *pICF = NULL;
+
+ for (ULONG iCtx=0; iCtx<CNT_CLSCTX; iCtx++)
+ {
+ for (ULONG iIter=0; iIter<m_ulIterations; iIter++)
+ {
+ sw.Reset ();
+ SCODE sc = CoGetClassObject(m_ClsID[iCtx], dwaClsCtx[iCtx], NULL,
+ IID_IClassFactory, (void **)&pICF);
+ m_ulGetClassObjectTime[iCtx][iIter] = sw.Read ();
+ Log (TEXT("CoGetClassObject"), sc);
+
+ if (SUCCEEDED(sc))
+ {
+ sw.Reset();
+ sc = pICF->CreateInstance(NULL, IID_IPersistFile, (void **)&pIPF);
+ m_ulCreateInstanceTime[iCtx][iIter] = sw.Read ();
+ Log (TEXT("CreateInstance"), sc);
+
+ sw.Reset();
+ pICF->Release();
+ m_ulCFReleaseTime[iCtx][iIter] = sw.Read();
+
+ if (SUCCEEDED(sc))
+ {
+ // load the data
+ sw.Reset();
+ pIPF->Load(apszPerstName[iCtx], 0);
+ m_ulLoadTime[iCtx][iIter] = sw.Read();
+
+ sw.Reset();
+ pIPF->Release ();
+ m_ulPunkReleaseTime[iCtx][iIter] = sw.Read();
+ }
+ else
+ {
+ m_ulCreateInstanceTime[iCtx][iIter] = NOTAVAIL;
+ }
+ }
+ else
+ {
+ m_ulGetClassObjectTime[iCtx][iIter] = NOTAVAIL;
+ }
+ }
+ }
+
+ return S_OK;
+}
+
+
+
+SCODE COleActivationTest::Report (CTestOutput &output)
+{
+ output.WriteSectionHeader (Name(), TEXT("CoGetClassObject"), *m_pInput);
+
+ for (ULONG iCtx=0; iCtx<CNT_CLSCTX; iCtx++)
+ {
+ output.WriteString(TEXT("\n"));
+ output.WriteClassID (&m_ClsID[iCtx]);
+ output.WriteString(apszClsCtx[iCtx]);
+ output.WriteString(TEXT("\n"));
+
+ output.WriteResults (TEXT("CoGetClassObject"), m_ulIterations,
+ m_ulGetClassObjectTime[iCtx]);
+
+ output.WriteResults (TEXT("CreateInstance "), m_ulIterations,
+ m_ulCreateInstanceTime[iCtx]);
+
+ output.WriteResults (TEXT("pICF->Release "), m_ulIterations,
+ m_ulCFReleaseTime[iCtx]);
+
+ output.WriteResults (TEXT("pIPF->Load "), m_ulIterations,
+ m_ulLoadTime[iCtx]);
+
+ output.WriteResults (TEXT("pIPF->Release "), m_ulIterations,
+ m_ulPunkReleaseTime[iCtx]);
+
+ }
+
+ return S_OK;
+}
+
+
diff --git a/private/oleutest/perform/cairole/tests/bm_activ.hxx b/private/oleutest/perform/cairole/tests/bm_activ.hxx
new file mode 100644
index 000000000..14e78a87b
--- /dev/null
+++ b/private/oleutest/perform/cairole/tests/bm_activ.hxx
@@ -0,0 +1,43 @@
+//+------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1993.
+//
+// File: bm_activ.hxx
+//
+// Contents: test class definition
+//
+// Classes: COleActivationTest
+//
+// Functions:
+//
+// History: 19-July-93 t-martig Created
+//
+//--------------------------------------------------------------------------
+
+#ifndef _BM_ACTIV_HXX_
+#define _BM_ACTIV_HXX_
+
+#include <bm_base.hxx>
+
+class COleActivationTest : public CTestBase
+{
+public:
+ virtual TCHAR *Name ();
+ virtual SCODE Setup (CTestInput *input);
+ virtual SCODE Run ();
+ virtual SCODE Report (CTestOutput &OutputFile);
+ virtual SCODE Cleanup ();
+
+private:
+ CLSID m_ClsID[CNT_CLSCTX];
+
+ ULONG m_ulIterations;
+ ULONG m_ulGetClassObjectTime[CNT_CLSCTX][TEST_MAX_ITERATIONS];
+ ULONG m_ulCreateInstanceTime[CNT_CLSCTX][TEST_MAX_ITERATIONS];
+ ULONG m_ulLoadTime[CNT_CLSCTX][TEST_MAX_ITERATIONS];
+ ULONG m_ulPunkReleaseTime[CNT_CLSCTX][TEST_MAX_ITERATIONS];
+ ULONG m_ulCFReleaseTime[CNT_CLSCTX][TEST_MAX_ITERATIONS];
+};
+
+#endif
diff --git a/private/oleutest/perform/cairole/tests/bm_alloc.cxx b/private/oleutest/perform/cairole/tests/bm_alloc.cxx
new file mode 100644
index 000000000..3fd31d034
--- /dev/null
+++ b/private/oleutest/perform/cairole/tests/bm_alloc.cxx
@@ -0,0 +1,187 @@
+//+------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1993.
+//
+// File: bm_alloc.cxx
+//
+// Contents: IMalloc test
+//
+// Classes: COleAllocTest
+//
+// History: 29-July-93 t-martig Created
+//
+//--------------------------------------------------------------------------
+#include <headers.cxx>
+#pragma hdrstop
+
+#include <bm_alloc.hxx>
+
+
+TCHAR *COleAllocTest::Name ()
+{
+ return TEXT("IMalloc");
+}
+
+
+SCODE COleAllocTest::Setup (CTestInput *pInput)
+{
+ CTestBase::Setup(pInput);
+ SCODE sc;
+
+ // Get number of iterations
+ m_ulIterations = pInput->GetIterations(Name());
+ m_ulSize = 32;
+
+ INIT_RESULTS (m_ulAllocTime);
+ INIT_RESULTS (m_ulFreeTime);
+ INIT_RESULTS (m_ulReallocTime);
+ INIT_RESULTS (m_ulGetSizeTime);
+ INIT_RESULTS (m_ulDidAllocTime);
+ INIT_RESULTS (m_ulHeapMinimizeTime);
+
+ sc = InitCOM();
+ if (FAILED(sc))
+ {
+ Log (TEXT("Setup - CoInitialize failed."), sc);
+ return sc;
+ }
+
+ // create an instance of the object to marshal
+ m_pMalloc = NULL;
+
+ sc = CoGetMalloc(MEMCTX_TASK, &m_pMalloc);
+
+ if (FAILED(sc))
+ {
+ Log (TEXT("Setup - CoGetMalloc failed"), sc);
+ return sc;
+ }
+
+ return sc;
+}
+
+
+SCODE COleAllocTest::Cleanup ()
+{
+ // release objects
+ if (m_pMalloc)
+ m_pMalloc->Release();
+
+ UninitCOM();
+ return S_OK;
+}
+
+
+SCODE COleAllocTest::Run ()
+{
+ CStopWatch sw;
+ LPVOID FAR pv;
+
+ // make the various IMalloc calls
+ for (ULONG iIter=0; iIter<m_ulIterations; iIter++)
+ {
+ sw.Reset();
+ pv = m_pMalloc->Alloc(m_ulSize);
+ m_ulAllocTime[iIter] = sw.Read();
+ Log(TEXT("IMalloc::Alloc"), (pv) ? S_OK : E_OUTOFMEMORY);
+
+ sw.Reset();
+ pv = m_pMalloc->Realloc(pv, m_ulSize*2);
+ m_ulReallocTime[iIter] = sw.Read();
+ Log(TEXT("IMalloc::Realloc"), (pv) ? S_OK : E_OUTOFMEMORY);
+
+ sw.Reset();
+ ULONG ulSize = m_pMalloc->GetSize(pv);
+ m_ulGetSizeTime[iIter] = sw.Read();
+ Log(TEXT("IMalloc::GetSize"), (ulSize > 0) ? S_OK : E_OUTOFMEMORY);
+
+ sw.Reset();
+ INT fRes = m_pMalloc->DidAlloc(pv);
+ m_ulDidAllocTime[iIter] = sw.Read();
+ Log(TEXT("IMalloc::DidAlloc"), (fRes) ? S_OK : E_OUTOFMEMORY);
+
+ sw.Reset();
+ m_pMalloc->Free(pv);
+ m_ulFreeTime[iIter] = sw.Read();
+ }
+
+ // loop through all the sizes. starting with a size of 8,
+ // we double it each time for MAX_SIZE_CNT times.
+
+ ULONG ulSize = 8;
+ for (ULONG iSize = 0; iSize <MAX_SIZE_CNT; iSize++)
+ {
+ // loop through all the number of iterations
+ for (iIter=0; iIter<m_ulIterations; iIter++)
+ {
+ VOID *pv[TEST_MAX_ITERATIONS];
+
+ sw.Reset();
+ for (ULONG iCnt=0; iCnt<iIter+1; iCnt++)
+ {
+ pv[iCnt] = m_pMalloc->Alloc(ulSize);
+ }
+ m_ulAllocSizeTime[iSize][iIter] = sw.Read();
+
+ sw.Reset();
+ for (iCnt=0; iCnt<iIter+1; iCnt++)
+ {
+ m_pMalloc->Free(pv[iCnt]);
+ }
+ m_ulFreeSizeTime[iSize][iIter] = sw.Read();
+
+ for (iCnt=0; iCnt<iIter+1; iCnt++)
+ {
+ if (pv[iCnt] == NULL)
+ {
+ Log(TEXT("IMalloc::Alloc failed."), E_OUTOFMEMORY);
+
+ // an allocation failed, correct the times
+ m_ulAllocSizeTime[iSize][iIter] = NOTAVAIL;
+ m_ulFreeSizeTime[iSize][iIter] = NOTAVAIL;
+ }
+ }
+
+
+ }
+
+ // double the allocation size
+ ulSize *= 2;
+ }
+
+ return S_OK;
+}
+
+
+SCODE COleAllocTest::Report (CTestOutput &output)
+{
+ output.WriteSectionHeader (Name(),
+ TEXT("OLE20 IMalloc MEMCTX_TASK"),
+ *m_pInput);
+
+ output.WriteString (TEXT("\n"));
+ output.WriteResults (TEXT("IMalloc->Alloc 32:"), m_ulIterations, m_ulAllocTime);
+ output.WriteResults (TEXT("IMalloc->Realloc 64:"), m_ulIterations, m_ulReallocTime);
+ output.WriteResults (TEXT("IMalloc->GetSize "), m_ulIterations, m_ulGetSizeTime);
+ output.WriteResults (TEXT("IMalloc->DidAlloc "), m_ulIterations, m_ulDidAllocTime);
+ output.WriteResults (TEXT("IMalloc->Free "), m_ulIterations, m_ulFreeTime);
+ output.WriteString (TEXT("\n"));
+
+ output.WriteString (TEXT("N consecutive allocations of the same size:\n"));
+ ULONG ulSize = 8;
+ for (ULONG iSize = 0; iSize<MAX_SIZE_CNT; iSize++)
+ {
+ // format output string containing allocation size
+ TCHAR szBuf[80];
+ wsprintf(szBuf, TEXT("IMalloc->Alloc %6d:"), ulSize);
+
+ output.WriteResults (szBuf, m_ulIterations, m_ulAllocSizeTime[iSize]);
+ output.WriteResults (TEXT("IMalloc->Free "), m_ulIterations, m_ulFreeSizeTime[iSize]);
+
+ // double the size
+ ulSize *= 2;
+ }
+
+ return S_OK;
+}
diff --git a/private/oleutest/perform/cairole/tests/bm_alloc.hxx b/private/oleutest/perform/cairole/tests/bm_alloc.hxx
new file mode 100644
index 000000000..5e519fe54
--- /dev/null
+++ b/private/oleutest/perform/cairole/tests/bm_alloc.hxx
@@ -0,0 +1,52 @@
+//+------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1993.
+//
+// File: bm_alloc.hxx
+//
+// Contents: IMalloc test class definition
+//
+// Classes: COleAllocTest
+//
+// Functions:
+//
+// History: 29-July-93 t-martig Created
+//
+//--------------------------------------------------------------------------
+
+#ifndef _BM_ALLOC_HXX_
+#define _BM_ALLOC_HXX_
+
+#include <bm_base.hxx>
+
+#define MAX_SIZE_CNT 15
+
+class COleAllocTest : public CTestBase
+{
+public:
+ virtual TCHAR *Name ();
+ virtual SCODE Setup (CTestInput *input);
+ virtual SCODE Run ();
+ virtual SCODE Report (CTestOutput &OutputFile);
+ virtual SCODE Cleanup ();
+
+private:
+ ULONG m_ulIterations;
+ ULONG m_ulSize;
+ IMalloc *m_pMalloc;
+
+ // times for the various IMalloc calls
+ ULONG m_ulAllocTime[TEST_MAX_ITERATIONS];
+ ULONG m_ulFreeTime[TEST_MAX_ITERATIONS];
+ ULONG m_ulReallocTime[TEST_MAX_ITERATIONS];
+ ULONG m_ulGetSizeTime[TEST_MAX_ITERATIONS];
+ ULONG m_ulDidAllocTime[TEST_MAX_ITERATIONS];
+ ULONG m_ulHeapMinimizeTime[TEST_MAX_ITERATIONS];
+
+ // times for allocations of various sizes
+ ULONG m_ulAllocSizeTime[MAX_SIZE_CNT][TEST_MAX_ITERATIONS];
+ ULONG m_ulFreeSizeTime[MAX_SIZE_CNT][TEST_MAX_ITERATIONS];
+};
+
+#endif
diff --git a/private/oleutest/perform/cairole/tests/bm_api.cxx b/private/oleutest/perform/cairole/tests/bm_api.cxx
new file mode 100644
index 000000000..19b5681ce
--- /dev/null
+++ b/private/oleutest/perform/cairole/tests/bm_api.cxx
@@ -0,0 +1,351 @@
+//+------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1993.
+//
+// File: bm_api.cxx
+//
+// Contents: Miscellaneous OLE API tests
+//
+// Classes: CApiTest
+//
+// History: 1-July-93 t-martig Created
+//
+//--------------------------------------------------------------------------
+#include <headers.cxx>
+#pragma hdrstop
+
+#include <bm_api.hxx>
+
+
+const GUID CLSID_Balls =
+ {0x0000013a,0x0001,0x0008,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}};
+
+const GUID CLSID_Dummy =
+ {0x00000142,0x0000,0x0008,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}};
+
+
+
+TCHAR *CApiTest::Name ()
+{
+ return TEXT("ApiTest");
+}
+
+
+SCODE CApiTest::Setup (CTestInput *pInput)
+{
+ CTestBase::Setup(pInput);
+
+ // get iteration count
+ m_ulIterations = pInput->GetIterations(Name());
+
+ // initialize timing arrays
+ INIT_RESULTS(m_ulCoBuildVersion);
+ INIT_RESULTS(m_ulOleBuildVersion);
+
+ INIT_RESULTS(m_ulCoGetCurrentProcess);
+ INIT_RESULTS(m_ulCoGetMalloc);
+
+
+ // time APIs
+
+ INIT_RESULTS(m_ulCoFileTimeNow);
+ INIT_RESULTS(m_ulCoFileTimeToDosDateTime);
+ INIT_RESULTS(m_ulCoDosDateTimeToFileTime);
+
+
+ // registry & class APIs
+
+ INIT_RESULTS(m_ulCoCreateGuid);
+ INIT_RESULTS(m_ulCoTreatAsClass);
+ INIT_RESULTS(m_ulCoGetTreatAsClass);
+ INIT_RESULTS(m_ulCoIsOle1Class);
+ INIT_RESULTS(m_ulGetClassFile);
+
+ INIT_RESULTS(m_ulStringFromCLSID);
+ INIT_RESULTS(m_ulCLSIDFromString);
+ INIT_RESULTS(m_ulProgIDFromCLSID);
+ INIT_RESULTS(m_ulStringFromIID);
+ INIT_RESULTS(m_ulIIDFromString);
+
+ INIT_RESULTS(m_ulCLSIDFromProgID);
+ INIT_RESULTS(m_ulStringFromGUID2);
+
+
+ // Get ClsID for this Ctx from the .ini file
+ CLSID ClsID;
+
+ HRESULT sc = pInput->GetGUID(&ClsID, Name(), apszClsIDName[1]);
+ if (FAILED(sc))
+ {
+ Log (TEXT("Setup - GetClassID failed."), sc);
+ return sc;
+ }
+
+ sc = InitCOM();
+ if (FAILED(sc))
+ {
+ Log (TEXT("Setup - CoInitialize failed."), sc);
+ return sc;
+ }
+
+
+ // Create an instance
+ IClassFactory *pICF = NULL;
+
+ sc = CoGetClassObject(ClsID, dwaClsCtx[1], NULL,
+ IID_IClassFactory, (void **)&pICF);
+ if (SUCCEEDED(sc))
+ {
+ IPersistFile *pIPF = NULL;
+
+ sc = pICF->CreateInstance(NULL, IID_IPersistFile,
+ (void **)&pIPF);
+ pICF->Release();
+ if (SUCCEEDED(sc))
+ {
+ // save the class instance in the storage
+ sc = pIPF->Save(apszPerstName[1], FALSE);
+ pIPF->Release();
+
+ if (FAILED(sc))
+ {
+ Log (TEXT("Setup - pIPF->Save failed."), sc);
+ }
+ }
+ else
+ {
+ Log (TEXT("Setup - CreateInstance failed"), sc);
+ }
+ }
+ else
+ {
+ Log (TEXT("Setup - CoGetClassObject failed"), sc);
+ }
+
+ return sc;
+}
+
+
+SCODE CApiTest::Cleanup ()
+{
+ UninitCOM();
+
+ // delete the file
+ CHAR szPerstName[MAX_PATH];
+ wcstombs(szPerstName, apszPerstName[1], wcslen(apszPerstName[1])+1);
+ _unlink (szPerstName);
+
+ return S_OK;
+}
+
+
+SCODE CApiTest::Run ()
+{
+ CStopWatch sw;
+ SCODE sc;
+
+ for (ULONG iIter=0; iIter<m_ulIterations; iIter++)
+ {
+ sw.Reset();
+ DWORD bldver = CoBuildVersion();
+ m_ulCoBuildVersion[iIter] = sw.Read();
+ }
+
+ for (iIter=0; iIter<m_ulIterations; iIter++)
+ {
+ sw.Reset();
+ DWORD bldver = OleBuildVersion();
+ m_ulOleBuildVersion[iIter] = sw.Read();
+ }
+
+ for (iIter=0; iIter<m_ulIterations; iIter++)
+ {
+ sw.Reset();
+ DWORD pid = CoGetCurrentProcess();
+ m_ulCoGetCurrentProcess[iIter] = sw.Read();
+ }
+
+ for (iIter=0; iIter<m_ulIterations; iIter++)
+ {
+ IMalloc *pMalloc = NULL;
+ sw.Reset();
+ sc = CoGetMalloc(MEMCTX_TASK, &pMalloc);
+ if (SUCCEEDED(sc))
+ {
+ pMalloc->Release();
+ }
+ m_ulCoGetMalloc[iIter] = sw.Read();
+ Log (TEXT("CoGetMalloc"), sc);
+ }
+
+ for (iIter=0; iIter<m_ulIterations; iIter++)
+ {
+ FILETIME ft;
+ WORD wDosDate, wDosTime;
+
+ sw.Reset();
+ sc = CoFileTimeNow(&ft);
+ m_ulCoFileTimeNow[iIter] = sw.Read();
+ Log (TEXT("CoFileTimeNow"), sc);
+
+ sw.Reset();
+ sc = CoFileTimeToDosDateTime(&ft, &wDosDate, &wDosTime);
+ m_ulCoFileTimeToDosDateTime[iIter] = sw.Read();
+ Log (TEXT("CoFileTimeToDosDateTime"), sc);
+
+ sw.Reset();
+ sc = CoDosDateTimeToFileTime(wDosDate, wDosTime, &ft);
+ m_ulCoDosDateTimeToFileTime[iIter] = sw.Read();
+ Log (TEXT("CoDosDateTimeToFileTime"), sc);
+ }
+
+
+ IMalloc *pMalloc = NULL;
+ sc = CoGetMalloc(MEMCTX_TASK, &pMalloc);
+ if (FAILED(sc))
+ {
+ return sc;
+ }
+
+ for (iIter=0; iIter<m_ulIterations; iIter++)
+ {
+ GUID Guid, GuidNew;
+ LPOLESTR pwsz = NULL;
+ OLECHAR awsz[50];
+
+ sw.Reset();
+ sc = CoCreateGuid(&Guid);
+ m_ulCoCreateGuid[iIter] = sw.Read();
+ if (FAILED(sc))
+ m_ulCoCreateGuid[iIter] = NOTAVAIL;
+
+ sw.Reset();
+ sc = CoTreatAsClass(CLSID_Dummy, Guid);
+ m_ulCoTreatAsClass[iIter] = sw.Read();
+ Log (TEXT("CoTreatAsClass"), sc);
+ if (FAILED(sc))
+ m_ulCoTreatAsClass[iIter] = NOTAVAIL;
+
+ sw.Reset();
+ sc = CoGetTreatAsClass(CLSID_Dummy, &GuidNew);
+ m_ulCoGetTreatAsClass[iIter] = sw.Read();
+ Log (TEXT("CoGetTreatAsClass"), sc);
+ if (FAILED(sc))
+ m_ulCoGetTreatAsClass[iIter] = NOTAVAIL;
+
+ sw.Reset();
+ sc = GetClassFile(apszPerstName[1], &Guid);
+ m_ulGetClassFile[iIter] = sw.Read();
+ Log (TEXT("GetClassFile"), sc);
+ if (FAILED(sc))
+ m_ulGetClassFile[iIter] = NOTAVAIL;
+
+ sw.Reset();
+ sc = StringFromCLSID(Guid, &pwsz);
+ m_ulStringFromCLSID[iIter] = sw.Read();
+ Log (TEXT("StringFromCLSID"), sc);
+ if (FAILED(sc))
+ m_ulStringFromCLSID[iIter] = NOTAVAIL;
+
+ sw.Reset();
+ sc = CLSIDFromString(pwsz, &GuidNew);
+ m_ulCLSIDFromString[iIter] = sw.Read();
+ Log (TEXT("CLSIDFromString"), sc);
+ if (FAILED(sc))
+ m_ulCLSIDFromString[iIter] = NOTAVAIL;
+
+ pMalloc->Free((void *)pwsz);
+
+
+ sw.Reset();
+ sc = StringFromIID(Guid, &pwsz);
+ m_ulStringFromIID[iIter] = sw.Read();
+ Log (TEXT("StringFromIID"), sc);
+ if (FAILED(sc))
+ m_ulStringFromIID[iIter] = NOTAVAIL;
+
+ sw.Reset();
+ sc = IIDFromString(pwsz, &GuidNew);
+ m_ulIIDFromString[iIter] = sw.Read();
+ Log (TEXT("IIDFromString"), sc);
+ if (FAILED(sc))
+ m_ulIIDFromString[iIter] = NOTAVAIL;
+
+ pMalloc->Free((void *)pwsz);
+
+ sw.Reset();
+ sc = StringFromGUID2(Guid, awsz, 50);
+ m_ulStringFromGUID2[iIter] = sw.Read();
+ Log (TEXT("StringFromGUID2"), sc);
+ if (FAILED(sc))
+ m_ulStringFromGUID2[iIter] = NOTAVAIL;
+ }
+
+
+ for (iIter=0; iIter<m_ulIterations; iIter++)
+ {
+ GUID Guid;
+ LPOLESTR pwsz = NULL;
+
+ sw.Reset();
+ sc = ProgIDFromCLSID(CLSID_Balls, &pwsz);
+ m_ulProgIDFromCLSID[iIter] = sw.Read();
+ Log (TEXT("ProgIDFromCLSID"), sc);
+ if (FAILED(sc))
+ m_ulProgIDFromCLSID[iIter] = NOTAVAIL;
+
+ sw.Reset();
+ sc = CLSIDFromProgID(pwsz, &Guid);
+ m_ulCLSIDFromProgID[iIter] = sw.Read();
+ Log (TEXT("CLSIDFromProgID"), sc);
+ if (FAILED(sc))
+ m_ulCLSIDFromProgID[iIter] = NOTAVAIL;
+
+ pMalloc->Free((void *)pwsz);
+ }
+
+ if (pMalloc)
+ pMalloc->Release();
+
+ // INIT_RESULTS(m_ulCoIsOle1Class);
+
+ return S_OK;
+}
+
+
+
+SCODE CApiTest::Report (CTestOutput &output)
+{
+ output.WriteSectionHeader (Name(), TEXT("Misc COM Apis"), *m_pInput);
+
+ output.WriteString (TEXT("\n"));
+ output.WriteResults (TEXT("CoBuildVersion "), m_ulIterations, m_ulCoBuildVersion);
+ output.WriteResults (TEXT("OleBuildVersion "), m_ulIterations, m_ulOleBuildVersion);
+ output.WriteResults (TEXT("CoGetCurrentProcess"), m_ulIterations, m_ulCoGetCurrentProcess);
+ output.WriteResults (TEXT("CoGetMalloc "), m_ulIterations, m_ulCoGetMalloc);
+ output.WriteString (TEXT("\n"));
+
+ output.WriteResults (TEXT("CoFileTimeNow "), m_ulIterations, m_ulCoFileTimeNow);
+ output.WriteResults (TEXT("CoFileTimeToDosDateTime"), m_ulIterations, m_ulCoFileTimeToDosDateTime);
+ output.WriteResults (TEXT("CoDosDateTimeToFileTime"), m_ulIterations, m_ulCoDosDateTimeToFileTime);
+ output.WriteString (TEXT("\n"));
+
+ output.WriteResults (TEXT("CoCreateGuid "), m_ulIterations, m_ulCoCreateGuid);
+ output.WriteResults (TEXT("CoTreatAsClass "), m_ulIterations, m_ulCoTreatAsClass);
+ output.WriteResults (TEXT("CoGetTreatAsClass "), m_ulIterations, m_ulCoGetTreatAsClass);
+ output.WriteResults (TEXT("CoIsOle1Class "), m_ulIterations, m_ulCoIsOle1Class);
+ output.WriteResults (TEXT("GetClassFile "), m_ulIterations, m_ulGetClassFile);
+ output.WriteString (TEXT("\n"));
+
+ output.WriteResults (TEXT("StringFromCLSID "), m_ulIterations, m_ulStringFromCLSID);
+ output.WriteResults (TEXT("CLSIDFromString "), m_ulIterations, m_ulCLSIDFromString);
+ output.WriteResults (TEXT("ProgIDFromCLSID "), m_ulIterations, m_ulProgIDFromCLSID);
+ output.WriteResults (TEXT("StringFromIID "), m_ulIterations, m_ulStringFromIID);
+ output.WriteResults (TEXT("IIDFromString "), m_ulIterations, m_ulIIDFromString);
+ output.WriteResults (TEXT("StringFromGUID2 "), m_ulIterations, m_ulStringFromGUID2);
+
+ return S_OK;
+}
+
+
diff --git a/private/oleutest/perform/cairole/tests/bm_api.hxx b/private/oleutest/perform/cairole/tests/bm_api.hxx
new file mode 100644
index 000000000..ee3391197
--- /dev/null
+++ b/private/oleutest/perform/cairole/tests/bm_api.hxx
@@ -0,0 +1,72 @@
+//+------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1993.
+//
+// File: bm_api.hxx
+//
+// Contents: test class definition
+//
+// Classes: CApiTest
+//
+// Functions:
+//
+// History: 19-July-93 t-martig Created
+//
+//--------------------------------------------------------------------------
+
+#ifndef _BM_API_HXX_
+#define _BM_API_HXX_
+
+#include <bm_base.hxx>
+
+
+class CApiTest : public CTestBase
+{
+public:
+ virtual TCHAR *Name ();
+ virtual SCODE Setup (CTestInput *input);
+ virtual SCODE Run ();
+ virtual SCODE Report (CTestOutput &OutputFile);
+ virtual SCODE Cleanup ();
+
+private:
+ ULONG m_ulIterations;
+
+ // build version APIs
+
+ ULONG m_ulCoBuildVersion[TEST_MAX_ITERATIONS];
+ ULONG m_ulOleBuildVersion[TEST_MAX_ITERATIONS];
+
+ ULONG m_ulCoGetCurrentProcess[TEST_MAX_ITERATIONS];
+
+ ULONG m_ulCoGetMalloc[TEST_MAX_ITERATIONS];
+ ULONG m_ulOleGetMalloc[TEST_MAX_ITERATIONS];
+
+
+ // time APIs
+
+ ULONG m_ulCoFileTimeNow[TEST_MAX_ITERATIONS];
+ ULONG m_ulCoFileTimeToDosDateTime[TEST_MAX_ITERATIONS];
+ ULONG m_ulCoDosDateTimeToFileTime[TEST_MAX_ITERATIONS];
+
+
+ // registry & class APIs
+
+ ULONG m_ulCoCreateGuid[TEST_MAX_ITERATIONS];
+ ULONG m_ulCoTreatAsClass[TEST_MAX_ITERATIONS];
+ ULONG m_ulCoGetTreatAsClass[TEST_MAX_ITERATIONS];
+ ULONG m_ulCoIsOle1Class[TEST_MAX_ITERATIONS];
+ ULONG m_ulGetClassFile[TEST_MAX_ITERATIONS];
+
+ ULONG m_ulStringFromCLSID[TEST_MAX_ITERATIONS];
+ ULONG m_ulCLSIDFromString[TEST_MAX_ITERATIONS];
+ ULONG m_ulProgIDFromCLSID[TEST_MAX_ITERATIONS];
+ ULONG m_ulStringFromIID[TEST_MAX_ITERATIONS];
+ ULONG m_ulIIDFromString[TEST_MAX_ITERATIONS];
+
+ ULONG m_ulCLSIDFromProgID[TEST_MAX_ITERATIONS];
+ ULONG m_ulStringFromGUID2[TEST_MAX_ITERATIONS];
+};
+
+#endif
diff --git a/private/oleutest/perform/cairole/tests/bm_cgps.cxx b/private/oleutest/perform/cairole/tests/bm_cgps.cxx
new file mode 100644
index 000000000..a0d28709b
--- /dev/null
+++ b/private/oleutest/perform/cairole/tests/bm_cgps.cxx
@@ -0,0 +1,89 @@
+//+------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1993.
+//
+// File: bm_cgps.cxx
+//
+// Contents: test CoGetPSClsid
+//
+// Classes: CCGPSTest
+//
+// History: 07-Oct-95 Rickhi Created
+//
+//--------------------------------------------------------------------------
+#include <headers.cxx>
+#pragma hdrstop
+#include <bm_cgps.hxx>
+
+
+extern const IID *iid[];
+
+
+
+TCHAR *CCGPSTest::Name ()
+{
+ return TEXT("CoGetPSClsidTest");
+}
+
+
+SCODE CCGPSTest::Setup (CTestInput *pInput)
+{
+ CTestBase::Setup(pInput);
+
+ // get iteration count
+ m_ulIterations = pInput->GetIterations(Name());
+
+ // initialize timing arrays
+ INIT_RESULTS(m_ulCoGetPSClsid);
+
+
+ SCODE sc = InitCOM();
+ if (FAILED(sc))
+ {
+ Log (TEXT("Setup - CoInitialize failed."), sc);
+ }
+
+ return sc;
+}
+
+
+SCODE CCGPSTest::Cleanup ()
+{
+ UninitCOM();
+ return S_OK;
+}
+
+
+SCODE CCGPSTest::Run ()
+{
+ CStopWatch sw;
+ CLSID clsid;
+
+ for (ULONG iIter=0; iIter<m_ulIterations; iIter++)
+ {
+ sw.Reset();
+ SCODE sc = CoGetPSClsid(*iid[iIter], &clsid);
+ m_ulCoGetPSClsid[iIter] = sw.Read();
+
+ if (FAILED(sc))
+ {
+ Log (TEXT("CoGetPSClsid failed."), sc);
+ }
+ }
+
+ return S_OK;
+}
+
+
+SCODE CCGPSTest::Report (CTestOutput &output)
+{
+ output.WriteSectionHeader (Name(), TEXT("CoGetPSClsid"), *m_pInput);
+
+ output.WriteString (TEXT("\n"));
+ output.WriteResults (TEXT("CoGetPSClsid "), m_ulIterations, m_ulCoGetPSClsid);
+
+ return S_OK;
+}
+
+
diff --git a/private/oleutest/perform/cairole/tests/bm_cgps.hxx b/private/oleutest/perform/cairole/tests/bm_cgps.hxx
new file mode 100644
index 000000000..f5d13b9f0
--- /dev/null
+++ b/private/oleutest/perform/cairole/tests/bm_cgps.hxx
@@ -0,0 +1,38 @@
+//+------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1993.
+//
+// File: bm_cgps.hxx
+//
+// Contents: test CoGetPSClsid
+//
+// Classes: CCGPSTest
+//
+// History: 07-Oct-95 Rickhi Created
+//
+//--------------------------------------------------------------------------
+#ifndef _BM_CGPS_HXX_
+#define _BM_CGPS_HXX_
+
+#include <bm_base.hxx>
+
+
+class CCGPSTest : public CTestBase
+{
+public:
+ virtual TCHAR *Name ();
+ virtual SCODE Setup (CTestInput *input);
+ virtual SCODE Run ();
+ virtual SCODE Report (CTestOutput &OutputFile);
+ virtual SCODE Cleanup ();
+
+private:
+ ULONG m_ulIterations;
+
+ // build version APIs
+
+ ULONG m_ulCoGetPSClsid[TEST_MAX_ITERATIONS];
+};
+
+#endif
diff --git a/private/oleutest/perform/cairole/tests/bm_filio.cxx b/private/oleutest/perform/cairole/tests/bm_filio.cxx
new file mode 100644
index 000000000..94667a9b5
--- /dev/null
+++ b/private/oleutest/perform/cairole/tests/bm_filio.cxx
@@ -0,0 +1,690 @@
+//+------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1994.
+//
+// File: bm_filio.cxx
+//
+// Contents: Basic File IO test
+//
+// Classes: CFileIOTest
+//
+// History: 04-Aug-94 t-vadims Created
+//
+//--------------------------------------------------------------------------
+#include <headers.cxx>
+#pragma hdrstop
+
+#include <bm_filio.hxx>
+#include <memory.h>
+
+#define DEF_DATASIZE 16384
+
+TCHAR *CFileIOTest::Name ()
+{
+ return TEXT("FileIOTest");
+}
+
+SCODE CFileIOTest::Setup (CTestInput *pInput)
+{
+ SCODE sc;
+ TCHAR pszValue[16];
+ ULONG i;
+
+ CTestBase::Setup(pInput);
+
+ // get iteration count
+ m_ulIterations = pInput->GetIterations(Name());
+
+ sc = InitCOM();
+ if (FAILED(sc))
+ {
+ Log (TEXT("Setup - CoInitialize failed."), sc);
+ return sc;
+ }
+
+ // get malloc interface for this task
+ m_piMalloc = NULL;
+ sc = CoGetMalloc(MEMCTX_TASK, &m_piMalloc);
+ if (FAILED(sc))
+ {
+ Log (TEXT("Setup - CoGetMalloc"), sc);
+ Cleanup();
+ return sc;
+ }
+
+ // get values of various paremeters from ini file
+
+ m_iStartSize = pInput->GetConfigInt(Name(), TEXT("StartSize"), 16);
+ if(m_iStartSize <= 0)
+ m_iStartSize = 16;
+
+ m_iEndSize = pInput->GetConfigInt(Name(), TEXT("EndSize"), DEF_DATASIZE);
+
+ // initialize array to be written to the file.
+ m_pbData = (BYTE *)m_piMalloc->Alloc(m_iEndSize);
+ if(m_pbData == NULL)
+ {
+ Log (TEXT("Setup - Cannot allocate memory"), E_OUTOFMEMORY);
+ Cleanup();
+ return E_OUTOFMEMORY;
+ }
+
+ for (i=0; i < m_iEndSize; i++)
+ m_pbData[i] = (BYTE)i;
+
+
+ m_iRepeatFactor = pInput->GetConfigInt(Name(), TEXT("RepeatFactor"), 1);
+
+ if (m_iRepeatFactor > MAX_REPS)
+ m_iRepeatFactor = MAX_REPS;
+
+ // Figure out how many different sizes we're going to write.
+ // and the size of the final file.
+ m_ulTotalSize = 0;
+ for(m_ulNumSizes = 0, i = m_iStartSize; i <= m_iEndSize; i *=2, m_ulNumSizes++)
+ m_ulTotalSize += i * m_iRepeatFactor;
+
+
+ if (m_iRepeatFactor * m_ulNumSizes > MAX_READS)
+ {
+ Log(TEXT("Too many different sizes and/or repeat factor is too big"), E_FAIL);
+ Cleanup();
+ return E_FAIL;
+ }
+
+ m_flStandardCreateFlags = 0;
+ // get file name to be used and values of other parameters
+ pInput->GetConfigString(Name(), TEXT("FileName"), TEXT("stgtest.bm"),
+ m_pszFile, MAX_PATH);
+
+ pInput->GetConfigString(Name(), TEXT("WriteThrough"), TEXT("OFF"), pszValue, 15);
+
+ if (lstrcmpi(pszValue, TEXT("ON")) == 0)
+ m_flStandardCreateFlags |= FILE_FLAG_WRITE_THROUGH;
+
+ pInput->GetConfigString(Name(), TEXT("AccessMode"), TEXT("NORMAL"), m_pszAccessMode, 15);
+
+ if (lstrcmpi(m_pszAccessMode, TEXT("ASYNC")) == 0)
+ {
+ m_flAccessMode = AM_ASYNC;
+ m_flStandardCreateFlags |= FILE_FLAG_OVERLAPPED;
+ }
+ else if (lstrcmpi(m_pszAccessMode, TEXT("MAPPED")) == 0)
+ {
+ m_flAccessMode = AM_MAPPED;
+ }
+ else
+ m_flAccessMode = AM_NORMAL;
+
+ pInput->GetConfigString(Name(), TEXT("Flush"), TEXT("OFF"), pszValue, 15);
+
+ if (lstrcmpi(pszValue, TEXT("ON")) == 0)
+ m_bFlush = TRUE;
+ else
+ m_bFlush = FALSE;
+
+ pInput->GetConfigString(Name(), TEXT("ReadMode"), TEXT("SEQUENTIAL"),
+ m_pszReadMode, 15);
+
+ if(lstrcmpi(m_pszReadMode, TEXT("SEQUENTIAL")) == 0)
+ m_bSequentialRead = TRUE;
+ else
+ m_bSequentialRead = FALSE;
+
+
+ InitTimings();
+
+ return S_OK;
+}
+
+
+void CFileIOTest::InitTimings()
+{
+ ULONG i;
+
+ // initialize timing arrays
+
+ INIT_RESULTS(m_ulOpenFileW);
+ INIT_RESULTS(m_ulClose1);
+ INIT_RESULTS(m_ulOpenFileR);
+ INIT_RESULTS(m_ulClose2);
+
+ ZERO_RESULTS(m_ulWriteTotal);
+ ZERO_RESULTS(m_ulReadTotal);
+ ZERO_RESULTS(m_ulSeekTotal);
+
+ INIT_RESULTS(m_ulCreateFileMappingW);
+ INIT_RESULTS(m_ulMapViewW);
+ INIT_RESULTS(m_ulCloseMap1);
+ INIT_RESULTS(m_ulUnmapView1);
+ ZERO_RESULTS(m_ulFlush1);
+
+ INIT_RESULTS(m_ulCreateFileMappingR);
+ INIT_RESULTS(m_ulMapViewR);
+ INIT_RESULTS(m_ulCloseMap2);
+ INIT_RESULTS(m_ulUnmapView2);
+ ZERO_RESULTS(m_ulFlush2);
+
+
+
+ for (i = 0; i < MAX_READS; i++)
+ {
+ INIT_RESULTS(m_ulWrite[i]);
+ INIT_RESULTS(m_ulRead[i]);
+ INIT_RESULTS(m_ulSeek[i]);
+ }
+
+ for (i = 0; i < 2; i++ )
+ ZERO_RESULTS(m_ulTotal[i]);
+
+}
+
+
+SCODE CFileIOTest::Cleanup ()
+{
+ // delete the file
+ DeleteFile (m_pszFile);
+ if(m_piMalloc)
+ {
+ if (m_pbData)
+ m_piMalloc->Free(m_pbData);
+
+ m_pbData = NULL;
+
+ m_piMalloc->Release();
+ m_piMalloc = NULL;
+
+ }
+
+ UninitCOM();
+
+ return S_OK;
+}
+
+SCODE CFileIOTest::Run ()
+{
+ CStopWatch sw;
+ ULONG iIter;
+ HANDLE hFile;
+ ULONG cb;
+ ULONG iSize;
+ ULONG i, iCount;
+ ULONG cbCurOffset;
+
+ // Async mode variables
+ OVERLAPPED ov;
+ LPOVERLAPPED lpov;
+ BOOL fRes;
+
+ // file-mapped mode variables
+ LPBYTE lpbFileData;
+ HANDLE hMap;
+
+
+ ov.Offset = 0;
+ ov.OffsetHigh = 0;
+ ov.hEvent = NULL;
+
+ if (IsAsyncMode())
+ lpov = &ov;
+ else
+ lpov = NULL;
+
+
+ // create normal file and write some data to it
+ for (iIter = 0; iIter < m_ulIterations; iIter++)
+ {
+ sw.Reset();
+ hFile = CreateFile(m_pszFile, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
+ m_flStandardCreateFlags | FILE_ATTRIBUTE_NORMAL, NULL);
+ m_ulOpenFileW[iIter] = sw.Read();
+ Log(TEXT("CreateFile for writing"),
+ (hFile != INVALID_HANDLE_VALUE) ? S_OK : E_FAIL);
+ if(hFile == INVALID_HANDLE_VALUE)
+ return E_FAIL;
+
+ if (IsMappedMode()) // create file mapping
+ {
+
+ sw.Reset();
+ hMap = CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, m_ulTotalSize, NULL);
+ m_ulCreateFileMappingW[iIter] = sw.Read();
+
+ Log(TEXT("CreateFileMapping"), (hMap != NULL) ? S_OK : E_FAIL);
+ if(hMap == NULL)
+ {
+ TCHAR szBuf[80];
+ wsprintf(szBuf, TEXT("GetLastError = %ld , FileSize = %ld"), GetLastError(), m_ulTotalSize);
+ Log(szBuf, E_FAIL);
+ CloseHandle(hFile);
+ return E_FAIL;
+ }
+
+ sw.Reset();
+ lpbFileData = (LPBYTE)MapViewOfFile(hMap, FILE_MAP_WRITE, 0, 0, 0);
+ m_ulMapViewW[iIter] = sw.Read();
+
+ Log(TEXT("MapViewOfFile"), (lpbFileData != NULL) ? S_OK : E_FAIL);
+ if(lpbFileData == NULL)
+ {
+ TCHAR szBuf[80];
+ wsprintf(szBuf, TEXT("GetLastError = %ld"), GetLastError());
+ Log(szBuf, E_FAIL);
+ CloseHandle(hMap);
+ CloseHandle(hFile);
+ return E_FAIL;
+ }
+
+ }
+
+ cbCurOffset = 0;
+ iCount = 0;
+ for (iSize = m_iStartSize ; iSize <= m_iEndSize ; iSize *= 2)
+ {
+
+ for (i = 0; i < m_iRepeatFactor; i++)
+ {
+
+ if (IsMappedMode())
+ {
+ sw.Reset();
+ memcpy(lpbFileData + cbCurOffset, m_pbData, iSize);
+ m_ulWrite[iCount][iIter] = sw.Read();
+ cb = iSize; // force correct cb for error check
+ }
+ else
+ {
+ ov.Offset = cbCurOffset;
+ sw.Reset();
+ fRes = WriteFile(hFile, (LPSTR)m_pbData, iSize, &cb, lpov);
+ m_ulWrite[iCount][iIter] = sw.Read();
+ }
+ m_ulWriteTotal[iIter] += m_ulWrite[iCount][iIter];
+
+ if (IsAsyncMode()) // if in async mode wait for result
+ {
+ if(!fRes)
+ {
+ Log(TEXT("Doing Actual Async call"), S_OK);
+ GetOverlappedResult(hFile, lpov, &cb, TRUE);
+ }
+
+ }
+
+ Log(TEXT("Writing data"), cb == iSize ? S_OK : E_FAIL);
+
+ cbCurOffset += iSize;
+ iCount++;
+ }
+ }
+ Log(TEXT("WriteFile X bytes"), S_OK );
+
+ if (IsMappedMode())
+ {
+ if (m_bFlush)
+ {
+ sw.Reset();
+ fRes = FlushViewOfFile((LPVOID) lpbFileData, 0);
+ m_ulFlush1[iIter] = sw.Read();
+ Log(TEXT("FlushViewOfFile"), fRes ? S_OK : E_FAIL);
+ }
+
+ sw.Reset();
+ fRes = UnmapViewOfFile((LPVOID) lpbFileData);
+ m_ulUnmapView1[iIter] = sw.Read();
+ Log(TEXT("UnmapViewOfFile"), fRes ? S_OK : E_FAIL);
+
+ sw.Reset();
+ CloseHandle(hMap);
+ m_ulCloseMap1[iIter] = sw.Read();
+ Log(TEXT("CloseHandle of file-mapping"), S_OK);
+ }
+ else if (m_bFlush)
+ {
+ sw.Reset();
+ fRes = FlushFileBuffers(hFile);
+ m_ulFlush1[iIter] = sw.Read();
+ Log(TEXT("FlushFileBuffers"), fRes ? S_OK : E_FAIL);
+ }
+
+ sw.Reset();
+ CloseHandle(hFile);
+ m_ulClose1[iIter] = sw.Read();
+
+ m_ulTotal[0][iIter] = m_ulOpenFileW[iIter] +
+ m_ulWriteTotal[iIter] +
+ m_ulFlush1[iIter] +
+ m_ulClose1[iIter];
+
+ if (IsMappedMode())
+ {
+ m_ulTotal[0][iIter] += m_ulCreateFileMappingW[iIter] +
+ m_ulMapViewW[iIter] +
+ m_ulUnmapView1[iIter] +
+ m_ulCloseMap1[iIter];
+ }
+
+ }
+
+ // try to read from that file
+ for (iIter = 0; iIter < m_ulIterations; iIter++)
+ {
+ sw.Reset();
+ hFile = CreateFile(m_pszFile, GENERIC_READ, 0, NULL, OPEN_EXISTING,
+ m_flStandardCreateFlags | FILE_ATTRIBUTE_NORMAL, NULL);
+ m_ulOpenFileR[iIter] = sw.Read();
+ Log(TEXT("CreateFile for reading"),
+ (hFile != INVALID_HANDLE_VALUE) ? S_OK : E_FAIL);
+ if(hFile == INVALID_HANDLE_VALUE)
+ return E_FAIL;
+
+ if (IsMappedMode()) // create file mapping
+ {
+ sw.Reset();
+ hMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
+ m_ulCreateFileMappingR[iIter] = sw.Read();
+
+ Log(TEXT("CreateFileMapping"), (hMap != NULL) ? S_OK : E_FAIL);
+ if(hMap == NULL)
+ {
+ CloseHandle(hFile);
+ return E_FAIL;
+ }
+
+ sw.Reset();
+ lpbFileData = (LPBYTE)MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0);
+ m_ulMapViewR[iIter] = sw.Read();
+
+ Log(TEXT("MapViewOfFile"), (lpbFileData != NULL) ? S_OK : E_FAIL);
+ if(lpbFileData == NULL)
+ {
+ CloseHandle(hMap);
+ CloseHandle(hFile);
+ return E_FAIL;
+ }
+
+ }
+
+ cbCurOffset = 0;
+ iCount = 0;
+
+ if (m_bSequentialRead)
+ {
+ for (iSize = m_iStartSize ; iSize <= m_iEndSize ; iSize *= 2)
+ {
+ for (i =0; i < m_iRepeatFactor; i++)
+ {
+
+ if (IsMappedMode())
+ {
+ sw.Reset();
+ memcpy(m_pbData, lpbFileData + cbCurOffset, iSize);
+ m_ulRead[iCount][iIter] = sw.Read();
+ cb = iSize; // force correct cb for error check
+ }
+ else
+ {
+ ov.Offset = cbCurOffset;
+ sw.Reset();
+ fRes = ReadFile(hFile, (LPSTR)m_pbData, iSize, &cb, lpov);
+ m_ulRead[iCount][iIter] = sw.Read();
+ }
+ m_ulReadTotal[iIter] += m_ulRead[iCount][iIter];
+
+ if (IsAsyncMode()) // in async mode wait for result
+ {
+ if(!fRes)
+ {
+ Log(TEXT("Doing Actual Async call"), S_OK);
+ GetOverlappedResult(hFile, lpov, &cb, TRUE);
+ }
+
+ }
+
+ Log(TEXT("Reading data"), cb == iSize ? S_OK : E_FAIL);
+
+ cbCurOffset += iSize;
+ iCount++;
+ }
+ }
+
+ Log(TEXT("ReadFile Sequential"), S_OK);
+ }
+ else
+ {
+ cbCurOffset = m_ulTotalSize;
+ for (iSize = m_iStartSize ; iSize <= m_iEndSize ; iSize *= 2)
+ {
+ for ( i =0; i< m_iRepeatFactor; i++)
+ {
+ cbCurOffset -= iSize;
+ ov.Offset = cbCurOffset;
+
+ if (IsNormalMode())
+ {
+ sw.Reset();
+ SetFilePointer(hFile, cbCurOffset, NULL, FILE_BEGIN);
+ m_ulSeek[iCount][iIter] = sw.Read();
+ m_ulSeekTotal[iIter] += m_ulSeek[iCount][iIter];
+ }
+
+ if (IsMappedMode())
+ {
+ sw.Reset();
+ memcpy(m_pbData, lpbFileData + cbCurOffset, iSize);
+ m_ulRead[iCount][iIter] = sw.Read();
+ cb = iSize; // force correct cb for error check.
+ }
+ else
+ {
+ sw.Reset();
+ fRes = ReadFile(hFile, (LPSTR)m_pbData, iSize, &cb, lpov);
+ m_ulRead[iCount][iIter] = sw.Read();
+ }
+ m_ulReadTotal[iIter] = m_ulRead[iCount][iIter];
+
+ if (IsAsyncMode())
+ {
+ if(!fRes)
+ {
+ Log(TEXT("Doing Actual Async call"), S_OK);
+ GetOverlappedResult(hFile, lpov, &cb, TRUE);
+ }
+ }
+ Log(TEXT("Reading data"), cb == iSize ? S_OK : E_FAIL);
+ iCount++;
+ }
+ }
+ Log(TEXT("ReadFile Random"), S_OK);
+ }
+
+
+ if (IsMappedMode())
+ {
+ if (m_bFlush)
+ {
+ sw.Reset();
+ fRes = FlushViewOfFile((LPVOID) lpbFileData, 0);
+ m_ulFlush2[iIter] = sw.Read();
+ Log(TEXT("FlushViewOfFile"), fRes ? S_OK : E_FAIL);
+ }
+
+ sw.Reset();
+ fRes = UnmapViewOfFile((LPVOID) lpbFileData);
+ m_ulUnmapView2[iIter] = sw.Read();
+ Log(TEXT("UnmapViewOfFile"), fRes ? S_OK : E_FAIL);
+
+ sw.Reset();
+ CloseHandle(hMap);
+ m_ulCloseMap2[iIter] = sw.Read();
+ Log(TEXT("CloseHandle of file-mapping"), S_OK);
+ }
+ else if ( m_bFlush)
+ {
+ sw.Reset();
+ fRes = FlushFileBuffers(hFile);
+ m_ulFlush2[iIter] = sw.Read();
+ Log(TEXT("FlushFileBuffers"), fRes ? S_OK : E_FAIL);
+ }
+
+ sw.Reset();
+ CloseHandle(hFile);
+ m_ulClose2[iIter] = sw.Read();
+ Log(TEXT("CloseHandle of File"), S_OK);
+
+ m_ulTotal[1][iIter] = m_ulOpenFileR[iIter] +
+ m_ulSeekTotal[iIter] +
+ m_ulReadTotal[iIter] +
+ m_ulFlush2[iIter] +
+ m_ulClose2[iIter];
+ if (IsMappedMode())
+ {
+ m_ulTotal[1][iIter] += m_ulCreateFileMappingR[iIter] +
+ m_ulMapViewR[iIter] +
+ m_ulUnmapView2[iIter] +
+ m_ulCloseMap2[iIter];
+ }
+ }
+
+
+ return S_OK;
+}
+
+
+SCODE CFileIOTest::Report (CTestOutput &output)
+{
+ TCHAR pszBuf[80];
+ ULONG i, iSize, iCount;
+
+ wsprintf(pszBuf, TEXT("File IO in %s Mode with %s Read/Writes"),
+ m_pszAccessMode, m_pszReadMode);
+ output.WriteSectionHeader (Name(), pszBuf, *m_pInput);
+
+ wsprintf(pszBuf, TEXT("WriteThrough is %s\n"),
+ (m_flStandardCreateFlags & FILE_FLAG_WRITE_THROUGH) ? TEXT("ON") : TEXT("OFF"));
+ output.WriteString (pszBuf);
+
+ wsprintf(pszBuf, TEXT("Flush is %s\n\n"), m_bFlush ? TEXT("ON") : TEXT("OFF"));
+ output.WriteString (pszBuf);
+
+
+ output.WriteResults (TEXT("CreateFile WRITE "), m_ulIterations,
+ m_ulOpenFileW);
+
+ if (IsMappedMode())
+ {
+ output.WriteResults(TEXT("CreateFileMapping"), m_ulIterations,
+ m_ulCreateFileMappingW);
+
+ output.WriteResults(TEXT("MapViewOfFile "), m_ulIterations,
+ m_ulMapViewW);
+ }
+
+ output.WriteString (TEXT("\n"));
+
+ iCount = 0;
+ for (iSize = m_iStartSize ; iSize <= m_iEndSize ; iSize *= 2)
+ {
+ for (i = 0; i < m_iRepeatFactor; i++)
+ {
+
+ wsprintf(pszBuf, TEXT("WriteFile %-9d"), iSize);
+
+ output.WriteResults (pszBuf, m_ulIterations, m_ulWrite[iCount]);
+ iCount++;
+ }
+ }
+
+ output.WriteResults (TEXT("Write Total "), m_ulIterations, m_ulWriteTotal);
+
+ output.WriteString (TEXT("\n"));
+
+ if (IsMappedMode())
+ {
+ if (m_bFlush)
+ output.WriteResults(TEXT("FlushViewOfFile "), m_ulIterations,
+ m_ulFlush1);
+
+ output.WriteResults(TEXT("UnmapViewOfFile "), m_ulIterations,
+ m_ulUnmapView1);
+
+ output.WriteResults(TEXT("CloseMapping "), m_ulIterations,
+ m_ulCloseMap1);
+ }
+
+ else if (m_bFlush)
+ output.WriteResults(TEXT("FlushFileBuffers "), m_ulIterations,
+ m_ulFlush1);
+
+ output.WriteResults (TEXT("CloseHandle "), m_ulIterations,
+ m_ulClose1);
+
+ output.WriteResults (TEXT("Total "), m_ulIterations,
+ m_ulTotal[0]);
+ output.WriteString (TEXT("\n\n"));
+
+ output.WriteResults (TEXT("CreateFile READ "), m_ulIterations,
+ m_ulOpenFileR);
+
+ if (IsMappedMode())
+ {
+ output.WriteResults(TEXT("CreateFileMapping"), m_ulIterations,
+ m_ulCreateFileMappingR);
+
+ output.WriteResults(TEXT("MapViewOfFile "), m_ulIterations,
+ m_ulMapViewR);
+ }
+
+ output.WriteString (TEXT("\n"));
+
+ iCount =0;
+ for (iSize = m_iStartSize ; iSize <= m_iEndSize ; iSize *= 2)
+ {
+ for (i=0; i < m_iRepeatFactor; i++)
+ {
+ if (!m_bSequentialRead && IsNormalMode())
+ {
+ wsprintf(pszBuf, TEXT("SetFilePosition %-9d"), m_iEndSize - iSize);
+ output.WriteResults (pszBuf, m_ulIterations, m_ulSeek[iCount]);
+ }
+ wsprintf(pszBuf, TEXT("ReadFile %-9d"), iSize);
+ output.WriteResults (pszBuf, m_ulIterations, m_ulRead[iCount]);
+ iCount++;
+ }
+ }
+
+ if (!m_bSequentialRead && IsNormalMode())
+ output.WriteResults (TEXT("Seek Total "), m_ulIterations, m_ulSeekTotal);
+
+ output.WriteResults (TEXT("Read Total "), m_ulIterations, m_ulReadTotal);
+
+ output.WriteString (TEXT("\n"));
+
+ if (IsMappedMode())
+ {
+ if (m_bFlush)
+ output.WriteResults(TEXT("FlushViewOfFile "), m_ulIterations,
+ m_ulFlush2);
+
+ output.WriteResults(TEXT("UnmapViewOfFile "), m_ulIterations,
+ m_ulUnmapView2);
+
+ output.WriteResults(TEXT("CloseMapping "), m_ulIterations,
+ m_ulCloseMap2);
+
+ }
+ else if ( m_bFlush)
+ output.WriteResults(TEXT("FlushFileBuffers "), m_ulIterations,
+ m_ulFlush2);
+
+ output.WriteResults (TEXT("CloseHandle "), m_ulIterations,
+ m_ulClose2);
+
+ output.WriteResults (TEXT("Total "), m_ulIterations,
+ m_ulTotal[1]);
+
+ output.WriteString (TEXT("\n"));
+
+ return S_OK;
+}
diff --git a/private/oleutest/perform/cairole/tests/bm_filio.hxx b/private/oleutest/perform/cairole/tests/bm_filio.hxx
new file mode 100644
index 000000000..da2440e02
--- /dev/null
+++ b/private/oleutest/perform/cairole/tests/bm_filio.hxx
@@ -0,0 +1,121 @@
+//+------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1993.
+//
+// File: bm_filio.hxx
+//
+// Contents: test class definition
+//
+// Classes: CFileIOTest
+//
+// Functions:
+//
+// History: 03-June-94 t-vadims Created
+//
+//--------------------------------------------------------------------------
+
+#ifndef _BM_FILIO_HXX_
+#define _BM_FILIO_HXX_
+
+#include <bm_base.hxx>
+
+#define MAX_REPS 100 // max repetions on write/read
+#define MAX_READS 100 // maximum number of total diferent reads/writes
+ // considering reps and diferent size
+
+#define AM_NORMAL 0
+#define AM_ASYNC 1
+#define AM_MAPPED 2
+
+
+class CFileIOTest : public CTestBase
+{
+public:
+ virtual TCHAR *Name ();
+ virtual SCODE Setup (CTestInput *input);
+ virtual SCODE Run ();
+ virtual SCODE Report (CTestOutput &OutputFile);
+ virtual SCODE Cleanup ();
+
+private:
+
+ inline BOOL IsAsyncMode();
+ inline BOOL IsMappedMode();
+ inline BOOL IsNormalMode();
+
+ void InitTimings();
+
+ ULONG m_ulIterations;
+
+ // Regular file read/write timings
+ ULONG m_ulOpenFileW[TEST_MAX_ITERATIONS];
+ ULONG m_ulWrite[MAX_READS][TEST_MAX_ITERATIONS];
+ ULONG m_ulWriteTotal[TEST_MAX_ITERATIONS];
+ ULONG m_ulClose1[TEST_MAX_ITERATIONS];
+
+ ULONG m_ulOpenFileR[TEST_MAX_ITERATIONS];
+ ULONG m_ulRead[MAX_READS][TEST_MAX_ITERATIONS];
+ ULONG m_ulReadTotal[TEST_MAX_ITERATIONS];
+ ULONG m_ulSeek[MAX_READS][TEST_MAX_ITERATIONS];
+ ULONG m_ulSeekTotal[TEST_MAX_ITERATIONS];
+ ULONG m_ulClose2[TEST_MAX_ITERATIONS];
+
+ //Additonal timings for file-mapped io
+ ULONG m_ulCreateFileMappingW[TEST_MAX_ITERATIONS];
+ ULONG m_ulMapViewW[TEST_MAX_ITERATIONS];
+ ULONG m_ulCloseMap1[TEST_MAX_ITERATIONS];
+ ULONG m_ulUnmapView1[TEST_MAX_ITERATIONS];
+ ULONG m_ulFlush1[TEST_MAX_ITERATIONS];
+
+ ULONG m_ulCreateFileMappingR[TEST_MAX_ITERATIONS];
+ ULONG m_ulMapViewR[TEST_MAX_ITERATIONS];
+ ULONG m_ulCloseMap2[TEST_MAX_ITERATIONS];
+ ULONG m_ulUnmapView2[TEST_MAX_ITERATIONS];
+ ULONG m_ulFlush2[TEST_MAX_ITERATIONS];
+
+ ULONG m_ulTotal[2][TEST_MAX_ITERATIONS];
+
+ BYTE *m_pbData; // data to be written to file
+
+ TCHAR m_pszFile[MAX_PATH]; // file name
+ TCHAR m_pszReadMode[15]; // read mode (RANDOM/SEQUENTIAL)
+ TCHAR m_pszAccessMode[15]; // access mode (NORMAL/ASYNC/MAPPED)
+
+
+ ULONG m_flStandardCreateFlags;// file creation flags for CreateFile
+ // (FILE_FLAG_WRITE_THROUGH or 0)
+
+ ULONG m_flAccessMode; // file acess mode AM_ASYNC, AM_MAPPED or AM_NORMAL
+
+ ULONG m_iStartSize; // start size of data to be written
+ ULONG m_iEndSize; // end size of data
+ ULONG m_ulTotalSize; // total size of the file
+ ULONG m_iRepeatFactor; // Number of writes for each size.
+ ULONG m_ulNumSizes; // number of diferent write sizes
+
+ BOOL m_bSequentialRead; // flage for Sequential and Random read
+ BOOL m_bFlush; // is flush on??
+
+
+ LPMALLOC m_piMalloc; // point to task malloc interface
+};
+
+
+inline BOOL CFileIOTest::IsAsyncMode(void)
+{
+ return (m_flAccessMode == AM_ASYNC) ;
+}
+
+
+inline BOOL CFileIOTest::IsMappedMode(void)
+{
+ return (m_flAccessMode == AM_MAPPED) ;
+}
+
+inline BOOL CFileIOTest::IsNormalMode(void)
+{
+ return (m_flAccessMode == AM_NORMAL) ;
+}
+
+#endif
diff --git a/private/oleutest/perform/cairole/tests/bm_iid.cxx b/private/oleutest/perform/cairole/tests/bm_iid.cxx
new file mode 100644
index 000000000..d7e63493c
--- /dev/null
+++ b/private/oleutest/perform/cairole/tests/bm_iid.cxx
@@ -0,0 +1,110 @@
+//+------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1993.
+//
+// File: bm_iid.cxx
+//
+// Contents: compare inline vs function call for guid compares
+//
+// Classes: CGuidCompareTest
+//
+// History: 1-July-93 t-martig Created
+//
+//--------------------------------------------------------------------------
+#include <headers.cxx>
+#pragma hdrstop
+
+#include <bm_iid.hxx>
+#include <oletest.hxx>
+
+
+TCHAR *CGuidCompareTest::Name ()
+{
+ return TEXT("GuidCompare");
+}
+
+
+SCODE CGuidCompareTest::Setup (CTestInput *pInput)
+{
+ CTestBase::Setup(pInput);
+
+ // get iteration count
+ m_ulIterations = pInput->GetIterations(Name());
+
+ // initialize state
+ INIT_RESULTS(m_ulRepFunctionNEQTime);
+ INIT_RESULTS(m_ulRepFunctionEQTime);
+ INIT_RESULTS(m_ulRepInlineNEQTime);
+ INIT_RESULTS(m_ulRepInlineEQTime);
+
+ return S_OK;
+}
+
+
+SCODE CGuidCompareTest::Cleanup ()
+{
+ return S_OK;
+}
+
+
+SCODE CGuidCompareTest::Run ()
+{
+ CStopWatch sw;
+ BOOL fRslt;
+
+ // compute times for the function version
+ for (ULONG iIter=0; iIter<m_ulIterations; iIter++)
+ {
+ sw.Reset();
+ for (ULONG j=0; j<1000; j++)
+ fRslt = IsEqualIID(IID_IUnknown, IID_IClassFactory);
+ m_ulRepFunctionNEQTime[iIter] = sw.Read();
+ }
+ for (iIter=0; iIter<m_ulIterations; iIter++)
+ {
+ sw.Reset();
+ for (ULONG j=0; j<1000; j++)
+ fRslt = IsEqualIID(IID_IUnknown, IID_IUnknown);
+ m_ulRepFunctionEQTime[iIter] = sw.Read();
+ }
+
+ // compute the time for the inline
+ for (iIter=0; iIter<m_ulIterations; iIter++)
+ {
+ sw.Reset();
+ for (ULONG j=0; j<1000; j++)
+ fRslt = !memcmp((void *)&IID_IUnknown,
+ (void *)&IID_IClassFactory, sizeof(GUID));
+ m_ulRepInlineNEQTime[iIter] = sw.Read();
+ }
+ for (iIter=0; iIter<m_ulIterations; iIter++)
+ {
+ sw.Reset();
+ for (ULONG j=0; j<1000; j++)
+ fRslt = !memcmp((void *)&IID_IUnknown,
+ (void *)&IID_IUnknown, sizeof(GUID));
+ m_ulRepInlineEQTime[iIter] = sw.Read();
+ }
+
+ return S_OK;
+}
+
+
+
+SCODE CGuidCompareTest::Report (CTestOutput &output)
+{
+ output.WriteSectionHeader (Name(), TEXT("GUID Compare"), *m_pInput);
+
+ output.WriteResults (TEXT("\nIsEqualGUID Not Equal x 1000 "),
+ m_ulIterations, m_ulRepFunctionNEQTime);
+ output.WriteResults (TEXT("\nIsEqualGUID Equal x 1000 "),
+ m_ulIterations, m_ulRepFunctionEQTime);
+
+ output.WriteResults (TEXT("memcmp Not Equal x 1000 "),
+ m_ulIterations, m_ulRepInlineNEQTime);
+ output.WriteResults (TEXT("memcmp Equal x 1000 "),
+ m_ulIterations, m_ulRepInlineEQTime);
+
+ return S_OK;
+}
diff --git a/private/oleutest/perform/cairole/tests/bm_iid.hxx b/private/oleutest/perform/cairole/tests/bm_iid.hxx
new file mode 100644
index 000000000..d4d091068
--- /dev/null
+++ b/private/oleutest/perform/cairole/tests/bm_iid.hxx
@@ -0,0 +1,42 @@
+//+------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1993.
+//
+// File: BM_IID.hxx
+//
+// Contents: test class definition
+//
+// Classes: CGuidCompareTest
+//
+// Functions:
+//
+// History: 19-July-93 t-martig Created
+//
+//--------------------------------------------------------------------------
+
+#ifndef _BM_IID_HXX_
+#define _BM_IID_HXX_
+
+#include <bm_base.hxx>
+
+class CGuidCompareTest : public CTestBase
+{
+public:
+ virtual TCHAR *Name ();
+ virtual SCODE Setup (CTestInput *input);
+ virtual SCODE Run ();
+ virtual SCODE Report (CTestOutput &OutputFile);
+ virtual SCODE Cleanup ();
+
+private:
+ ULONG m_ulIterations;
+
+ ULONG m_ulRepFunctionNEQTime[TEST_MAX_ITERATIONS];
+ ULONG m_ulRepFunctionEQTime[TEST_MAX_ITERATIONS];
+ ULONG m_ulRepInlineNEQTime[TEST_MAX_ITERATIONS];
+ ULONG m_ulRepInlineEQTime[TEST_MAX_ITERATIONS];
+
+};
+
+#endif
diff --git a/private/oleutest/perform/cairole/tests/bm_init.cxx b/private/oleutest/perform/cairole/tests/bm_init.cxx
new file mode 100644
index 000000000..b9f5107e7
--- /dev/null
+++ b/private/oleutest/perform/cairole/tests/bm_init.cxx
@@ -0,0 +1,201 @@
+//+------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1993.
+//
+// File: bm_init.cxx
+//
+// Contents: OleInitialize/OleUninitialize tests
+//
+// Classes: COleInitializeTest
+//
+// History: 1-July-93 t-martig Created
+//
+//--------------------------------------------------------------------------
+#include <headers.cxx>
+#pragma hdrstop
+
+#include <bm_init.hxx>
+#include <oletest.hxx>
+
+
+DWORD dwInitFlag = 0;
+
+TCHAR *COleInitializeTest::Name ()
+{
+ return TEXT("OleInitialize");
+}
+
+
+SCODE COleInitializeTest::Setup (CTestInput *pInput)
+{
+ CTestBase::Setup(pInput);
+
+ // get iteration count
+ m_ulIterations = pInput->GetIterations(Name());
+
+ // initialize state
+ INIT_RESULTS(m_ulOleInitializeTime);
+ INIT_RESULTS(m_ulOleUninitializeTime);
+ INIT_RESULTS(m_ulRepOleInitializeTime);
+ INIT_RESULTS(m_ulRepOleUninitializeTime);
+
+ INIT_RESULTS(m_ulCoInitializeTime);
+ INIT_RESULTS(m_ulCoUninitializeTime);
+ INIT_RESULTS(m_ulRepCoInitializeTime);
+ INIT_RESULTS(m_ulRepCoUninitializeTime);
+
+ return S_OK;
+}
+
+
+SCODE COleInitializeTest::Cleanup ()
+{
+ return S_OK;
+}
+
+
+SCODE COleInitializeTest::Run ()
+{
+ CStopWatch sw;
+ SCODE sc;
+
+ // compute times for OleInit, OleUninit.
+ for (ULONG iIter=0; iIter<m_ulIterations; iIter++)
+ {
+ sw.Reset();
+#ifdef OLE_THREADING_SUPPORT
+ sc = OleInitializeEx(NULL, dwInitFlag);
+#else
+ sc = OleInitialize(NULL);
+#endif
+ m_ulOleInitializeTime[iIter] = sw.Read();
+ Log (TEXT("OleInitialize"), sc);
+
+ if (SUCCEEDED(sc))
+ {
+ sw.Reset();
+ OleUninitialize();
+ m_ulOleUninitializeTime[iIter] = sw.Read();
+ Log (TEXT("OleUninitialize"), sc);
+ }
+ else
+ {
+ m_ulOleInitializeTime[iIter] = NOTAVAIL;
+ }
+
+ sw.Reset();
+#ifdef COM_THREADING_SUPPORT
+ sc = CoInitializeEx(NULL, dwInitFlag);
+#else
+ sc = CoInitialize(NULL);
+#endif
+ m_ulCoInitializeTime[iIter] = sw.Read();
+ Log (TEXT("CoInitialize"), sc);
+
+ if (SUCCEEDED(sc))
+ {
+ sw.Reset();
+ CoUninitialize();
+ m_ulCoUninitializeTime[iIter] = sw.Read();
+ Log (TEXT("CoUninitialize"), sc);
+ }
+ else
+ {
+ m_ulCoInitializeTime[iIter] = NOTAVAIL;
+ }
+
+ }
+
+ // first, compute times for repetitive OleInit
+ for (iIter=0; iIter<m_ulIterations; iIter++)
+ {
+ sw.Reset();
+#ifdef OLE_THREADING_SUPPORT
+ sc = OleInitializeEx(NULL, dwInitFlag);
+#else
+ sc = OleInitialize(NULL);
+#endif
+ m_ulRepOleInitializeTime[iIter] = sw.Read();
+ Log (TEXT("OleInitialize"), sc);
+
+ if (FAILED(sc))
+ {
+ m_ulRepOleInitializeTime[iIter] = NOTAVAIL;
+ }
+ }
+
+ // second, compute times for repetitive OleUninit
+ for (iIter=0; iIter<m_ulIterations; iIter++)
+ {
+ sw.Reset();
+ OleUninitialize();
+ m_ulRepOleUninitializeTime[iIter] = sw.Read();
+ Log (TEXT("OleUninitialize"), sc);
+ }
+
+
+ // first, compute times for repetitive CoInit
+ for (iIter=0; iIter<m_ulIterations; iIter++)
+ {
+ sw.Reset();
+#ifdef COM_THREADING_SUPPORT
+ sc = CoInitializeEx(NULL, dwInitFlag);
+#else
+ sc = CoInitialize(NULL);
+#endif
+ m_ulRepCoInitializeTime[iIter] = sw.Read();
+ Log (TEXT("CoInitialize"), sc);
+
+ if (FAILED(sc))
+ {
+ m_ulRepCoInitializeTime[iIter] = NOTAVAIL;
+ }
+ }
+
+ // second, compute times for repetitive CoUninit
+ for (iIter=0; iIter<m_ulIterations; iIter++)
+ {
+ sw.Reset();
+ CoUninitialize();
+ m_ulRepCoUninitializeTime[iIter] = sw.Read();
+ Log (TEXT("CoUninitialize"), sc);
+ }
+
+ return S_OK;
+}
+
+
+
+SCODE COleInitializeTest::Report (CTestOutput &output)
+{
+ output.WriteSectionHeader (Name(), TEXT("OleInitialize / OleUninitialize"), *m_pInput);
+
+ output.WriteResults (TEXT("\nOleInitialize "), m_ulIterations,
+ m_ulOleInitializeTime);
+
+ output.WriteResults (TEXT("OleUninitialize "), m_ulIterations,
+ m_ulOleUninitializeTime);
+
+ output.WriteResults (TEXT("\nRepOleInitialize "), m_ulIterations,
+ m_ulRepOleInitializeTime);
+
+ output.WriteResults (TEXT("RepOleUninitialize"), m_ulIterations,
+ m_ulRepOleUninitializeTime);
+
+ output.WriteResults (TEXT("\nCoInitialize "), m_ulIterations,
+ m_ulCoInitializeTime);
+
+ output.WriteResults (TEXT("CoUninitialize "), m_ulIterations,
+ m_ulCoUninitializeTime);
+
+ output.WriteResults (TEXT("\nRepCoInitialize "), m_ulIterations,
+ m_ulRepCoInitializeTime);
+
+ output.WriteResults (TEXT("RepCoUninitialize"), m_ulIterations,
+ m_ulRepCoUninitializeTime);
+
+ return S_OK;
+}
+
+
diff --git a/private/oleutest/perform/cairole/tests/bm_init.hxx b/private/oleutest/perform/cairole/tests/bm_init.hxx
new file mode 100644
index 000000000..d9e65e150
--- /dev/null
+++ b/private/oleutest/perform/cairole/tests/bm_init.hxx
@@ -0,0 +1,49 @@
+//+------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1993.
+//
+// File: bm_init.hxx
+//
+// Contents: test class definition
+//
+// Classes: COleInitializeTest
+//
+// History: 19-July-93 t-martig Created
+//
+//--------------------------------------------------------------------------
+#ifndef _BM_INIT_HXX_
+#define _BM_INIT_HXX_
+
+#include <bm_base.hxx>
+
+class COleInitializeTest : public CTestBase
+{
+public:
+ virtual TCHAR *Name ();
+ virtual SCODE Setup (CTestInput *input);
+ virtual SCODE Run ();
+ virtual SCODE Report (CTestOutput &OutputFile);
+ virtual SCODE Cleanup ();
+
+private:
+ ULONG m_ulIterations;
+
+ // single init the uninit times
+ ULONG m_ulOleInitializeTime[TEST_MAX_ITERATIONS];
+ ULONG m_ulOleUninitializeTime[TEST_MAX_ITERATIONS];
+
+ // repetative init, followed by repetitive uninit
+ ULONG m_ulRepOleInitializeTime[TEST_MAX_ITERATIONS];
+ ULONG m_ulRepOleUninitializeTime[TEST_MAX_ITERATIONS];
+
+ // single init the uninit times
+ ULONG m_ulCoInitializeTime[TEST_MAX_ITERATIONS];
+ ULONG m_ulCoUninitializeTime[TEST_MAX_ITERATIONS];
+
+ // repetative init, followed by repetitive uninit
+ ULONG m_ulRepCoInitializeTime[TEST_MAX_ITERATIONS];
+ ULONG m_ulRepCoUninitializeTime[TEST_MAX_ITERATIONS];
+};
+
+#endif
diff --git a/private/oleutest/perform/cairole/tests/bm_marsh.cxx b/private/oleutest/perform/cairole/tests/bm_marsh.cxx
new file mode 100644
index 000000000..23cb18b38
--- /dev/null
+++ b/private/oleutest/perform/cairole/tests/bm_marsh.cxx
@@ -0,0 +1,296 @@
+//+------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1993.
+//
+// File: bm_marsh.cxx
+//
+// Contents: Mashalling test
+//
+// Classes: COleMarshalTest
+//
+// History: 29-July-93 t-martig Created
+//
+//--------------------------------------------------------------------------
+#include <headers.cxx>
+#pragma hdrstop
+
+#include <bm_marsh.hxx>
+#include <oletest.hxx>
+
+#include <rpc.h>
+#include <rpcdce.h>
+// extern "C" RPC_STATUS UuidCreate(GUID *pguid);
+
+
+TCHAR *COleMarshalTest::Name ()
+{
+ return TEXT("Marshalling");
+}
+
+
+SCODE COleMarshalTest::Setup (CTestInput *pInput)
+{
+ SCODE sc;
+
+ for (ULONG i=0; i<REPS; i++)
+ m_pStm[i] = NULL;
+
+ CTestBase::Setup(pInput);
+
+ // Get number of iterations
+ m_ulIterations = pInput->GetIterations(Name());
+
+ // set NULL in case of error
+ for (i=0; i<m_ulIterations; i++)
+ m_punk[i] = NULL;
+
+
+ // Get custom ClsID from .ini file
+ pInput->GetClassID(&m_ClsID, Name());
+
+ // Get class activation context from .ini file
+ m_dwClsCtx = pInput->GetClassCtx(Name());
+
+ INIT_RESULTS (m_ulUuidCreateTime);
+
+ for (i=0; i<REPS; i++)
+ {
+ INIT_RESULTS (m_ulMarshalTime[i]);
+ INIT_RESULTS (m_ulUnmarshalTime[i]);
+ INIT_RESULTS (m_ulLockObjectTime[i]);
+ INIT_RESULTS (m_ulGetStdMarshalTime[i]);
+ INIT_RESULTS (m_ulGetMarshalSizeTime[i]);
+ INIT_RESULTS (m_ulDisconnectTime[i]);
+ }
+
+ sc = InitCOM();
+ if (FAILED(sc))
+ {
+ Log (TEXT("Setup - CoInitialize failed."), sc);
+ return sc;
+ }
+
+ for (i=0; i<m_ulIterations; i++)
+ {
+ // create an instance of the object to marshal
+ sc = CoCreateInstance(m_ClsID, NULL, m_dwClsCtx,
+ IID_IUnknown, (void **)&m_punk[i]);
+ if (FAILED(sc))
+ {
+ Log (TEXT("Setup - CoCreateInstance failed"), sc);
+ return sc;
+ }
+ }
+
+
+ for (i=0; i<REPS; i++)
+ {
+ // create a stream to marshal the interface into
+ SCODE sc = CreateStreamOnHGlobal(NULL, 0, &m_pStm[i]);
+ if (FAILED(sc))
+ {
+ Log (TEXT("Setup - CreateStreamOnHGlobal failed"), sc);
+ }
+ else
+ {
+ // write some data to init the stream
+ DWORD dwTemp;
+ m_pStm[i]->Write(&dwTemp, sizeof(DWORD), NULL);
+ }
+ }
+
+ return S_OK;
+}
+
+
+SCODE COleMarshalTest::Cleanup ()
+{
+ // release objects
+ for (ULONG i=0; i<m_ulIterations; i++)
+ {
+ if (m_punk[i])
+ m_punk[i]->Release();
+ }
+
+ for (i=0; i<REPS; i++)
+ {
+ if (m_pStm[i])
+ m_pStm[i]->Release();
+ }
+
+ UninitCOM();
+ return S_OK;
+}
+
+
+SCODE COleMarshalTest::Run ()
+{
+ CStopWatch sw;
+ LPVOID FAR pv;
+
+ for (ULONG iIter=0; iIter<m_ulIterations; iIter++)
+ {
+ SCODE sc[REPS];
+ ULARGE_INTEGER ulSeekStart[REPS];
+ LARGE_INTEGER libMove[REPS];
+
+ // create Uuid's
+ GUID guid;
+ sw.Reset();
+ sc[0] = UuidCreate(&guid);
+ m_ulUuidCreateTime[iIter] = sw.Read();
+ Log (TEXT("UuidCreate"), sc[0]);
+
+
+ // first, marshal the interface REPS times.
+ for (ULONG i=0; i<REPS; i++)
+ {
+ // save current stream seek pointer
+ LISet32(libMove[i], 0x00000000);
+ m_pStm[i]->Seek(libMove[i], STREAM_SEEK_CUR, &ulSeekStart[i]);
+
+ // marshal the interface into the stream
+ sw.Reset();
+ sc[i] = CoMarshalInterface(m_pStm[i], IID_IUnknown, m_punk[iIter],
+ 0, 0, MSHLFLAGS_NORMAL);
+ m_ulMarshalTime[i][iIter] = sw.Read ();
+ Log (TEXT("CoMarshalInterface"), sc[i]);
+
+ if (FAILED(sc[i]))
+ {
+ m_ulMarshalTime[i][iIter] = NOTAVAIL;
+ }
+ }
+
+
+ // now ReleaseMarshalData once
+ i = 0;
+ {
+ // set stream ptr back to the starting position
+ LISet32(libMove[i], ulSeekStart[i].LowPart);
+ m_pStm[i]->Seek(libMove[i], STREAM_SEEK_SET, &ulSeekStart[i]);
+
+ // unmarshal the interface from the stream
+ sw.Reset ();
+ sc[i] = CoReleaseMarshalData(m_pStm[i]);
+ m_ulUnmarshalTime[i][iIter] = sw.Read ();
+ Log (TEXT("CoReleaseMarshalData"), sc[i]);
+ }
+
+
+ // now UnmarshalInterface the remaining times
+ for (i=1; i<REPS; i++)
+ {
+ if (FAILED(sc[i]))
+ continue;
+
+ // set stream ptr back to the starting position
+ LISet32(libMove[i], ulSeekStart[i].LowPart);
+ m_pStm[i]->Seek(libMove[i], STREAM_SEEK_SET, &ulSeekStart[i]);
+
+ // unmarshal the interface from the stream
+ sw.Reset ();
+ sc[i] = CoUnmarshalInterface(m_pStm[i], IID_IUnknown, &pv);
+ m_ulUnmarshalTime[i][iIter] = sw.Read ();
+ Log (TEXT("CoUnmarshalInterface"), sc[i]);
+
+ if (SUCCEEDED(sc[i]))
+ {
+ ((IUnknown *)pv)->Release (); // Unmarshal called AddRef
+ }
+ else
+ {
+ m_ulUnmarshalTime[i][iIter] = NOTAVAIL;
+ }
+ }
+
+
+ // call CoLockObjectExternal
+ sw.Reset();
+ sc[0] = CoLockObjectExternal(m_punk[iIter], TRUE, FALSE);
+ m_ulLockObjectTime[0][iIter] = sw.Read();
+ Log (TEXT("CoLockObjectExternal"), sc[0]);
+
+ sw.Reset();
+ sc[1] = CoLockObjectExternal(m_punk[iIter], FALSE, FALSE);
+ m_ulLockObjectTime[1][iIter] = sw.Read();
+ Log (TEXT("CoLockObjectExternal"), sc[1]);
+
+
+ // call CoGetStdMarshal
+ IMarshal *pIM = NULL;
+ sw.Reset();
+ sc[0] = CoGetStandardMarshal(IID_IUnknown, m_punk[iIter], 0, NULL,
+ MSHLFLAGS_NORMAL, &pIM);
+ m_ulGetStdMarshalTime[0][iIter] = sw.Read();
+ Log (TEXT("CoGetStandardMarshal"), sc[0]);
+
+ sw.Reset();
+ pIM->Release();
+ m_ulGetStdMarshalTime[1][iIter] = sw.Read();
+ Log (TEXT("Release StdMarshal"), sc[1]);
+
+
+ // call CoGetMarshalSizeMax
+ ULONG ulSize = 0;
+ sw.Reset();
+ sc[0] = CoGetMarshalSizeMax(&ulSize, IID_IUnknown, m_punk[iIter],
+ 0, NULL,MSHLFLAGS_NORMAL);
+ m_ulGetMarshalSizeTime[0][iIter] = sw.Read();
+ Log (TEXT("CoGetMarshalSizeMax"), sc[0]);
+
+
+ // call CoDisconnectObject
+ sc[0] = CoLockObjectExternal(m_punk[iIter], TRUE, FALSE);
+
+ sw.Reset();
+ sc[0] = CoDisconnectObject(m_punk[iIter], 0);
+ m_ulDisconnectTime[0][iIter] = sw.Read();
+ Log (TEXT("CoDisconnectObject"), sc[0]);
+ sc[0] = CoLockObjectExternal(m_punk[iIter], FALSE, FALSE);
+ }
+
+ return S_OK;
+}
+
+
+SCODE COleMarshalTest::Report (CTestOutput &output)
+{
+ output.WriteSectionHeader (Name(),
+ TEXT("Interface Marshalling"),
+ *m_pInput);
+
+ for (ULONG iCtx=0; iCtx<1; iCtx++)
+ {
+ output.WriteString (TEXT("\n"));
+ output.WriteClassID (&m_ClsID);
+ output.WriteString (apszClsCtx[0]);
+ output.WriteString (TEXT("\n"));
+
+ output.WriteResults (TEXT("UuidCreate "), m_ulIterations, m_ulUuidCreateTime);
+ output.WriteString (TEXT("\n"));
+
+ output.WriteResults (TEXT("CoMarshalInterface 1"), m_ulIterations, m_ulMarshalTime[0]);
+ output.WriteResults (TEXT("CoMarshalInterface 2"), m_ulIterations, m_ulMarshalTime[1]);
+ output.WriteResults (TEXT("CoMarshalInterface 3"), m_ulIterations, m_ulMarshalTime[2]);
+ output.WriteString (TEXT("\n"));
+
+ output.WriteResults (TEXT("CoReleaseMarshalData 3"), m_ulIterations, m_ulUnmarshalTime[0]);
+ output.WriteResults (TEXT("CoUnmarshalInterface 2"), m_ulIterations, m_ulUnmarshalTime[1]);
+ output.WriteResults (TEXT("CoUnmarshalInterface 1"), m_ulIterations, m_ulUnmarshalTime[2]);
+ output.WriteString (TEXT("\n"));
+
+ output.WriteResults (TEXT("CoLockObjectExternal L"), m_ulIterations, m_ulLockObjectTime[0]);
+ output.WriteResults (TEXT("CoLockObjectExternal U"), m_ulIterations, m_ulLockObjectTime[1]);
+ output.WriteString (TEXT("\n"));
+
+ output.WriteResults (TEXT("CoGetStandardMarshal "), m_ulIterations, m_ulGetStdMarshalTime[0]);
+ output.WriteResults (TEXT("pIMarshal->Release "), m_ulIterations, m_ulGetStdMarshalTime[1]);
+ output.WriteString (TEXT("\n"));
+
+ output.WriteResults (TEXT("CoDisconnectObject "), m_ulIterations, m_ulDisconnectTime[0]);
+ }
+
+ return S_OK;
+}
diff --git a/private/oleutest/perform/cairole/tests/bm_marsh.hxx b/private/oleutest/perform/cairole/tests/bm_marsh.hxx
new file mode 100644
index 000000000..9045d61b8
--- /dev/null
+++ b/private/oleutest/perform/cairole/tests/bm_marsh.hxx
@@ -0,0 +1,53 @@
+//+------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1993.
+//
+// File: bm_marsh.hxx
+//
+// Contents: test class definition
+//
+// Classes: COleMarshalTest
+//
+// Functions:
+//
+// History: 29-July-93 t-martig Created
+//
+//--------------------------------------------------------------------------
+
+#ifndef _BM_MARSH_HXX_
+#define _BM_MARSH_HXX_
+
+#include <bm_base.hxx>
+
+// # times to marshal consecutively
+#define REPS 3
+
+
+class COleMarshalTest : public CTestBase
+{
+public:
+ virtual TCHAR *Name ();
+ virtual SCODE Setup (CTestInput *input);
+ virtual SCODE Run ();
+ virtual SCODE Report (CTestOutput &OutputFile);
+ virtual SCODE Cleanup ();
+
+private:
+ ULONG m_ulIterations;
+ DWORD m_dwClsCtx;
+ CLSID m_ClsID;
+
+ IUnknown *m_punk[TEST_MAX_ITERATIONS];
+ IStream *m_pStm[REPS];
+
+ ULONG m_ulUuidCreateTime[TEST_MAX_ITERATIONS];
+ ULONG m_ulMarshalTime[REPS][TEST_MAX_ITERATIONS];
+ ULONG m_ulUnmarshalTime[REPS][TEST_MAX_ITERATIONS];
+ ULONG m_ulLockObjectTime[REPS][TEST_MAX_ITERATIONS];
+ ULONG m_ulGetStdMarshalTime[REPS][TEST_MAX_ITERATIONS];
+ ULONG m_ulGetMarshalSizeTime[REPS][TEST_MAX_ITERATIONS];
+ ULONG m_ulDisconnectTime[REPS][TEST_MAX_ITERATIONS];
+};
+
+#endif
diff --git a/private/oleutest/perform/cairole/tests/bm_mrsh2.cxx b/private/oleutest/perform/cairole/tests/bm_mrsh2.cxx
new file mode 100644
index 000000000..db621217e
--- /dev/null
+++ b/private/oleutest/perform/cairole/tests/bm_mrsh2.cxx
@@ -0,0 +1,417 @@
+//+------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1993.
+//
+// File: bm_marsh.cxx
+//
+// Contents: Mashalling test
+//
+// Classes: COleMarshalTest
+//
+// History: 29-July-93 t-martig Created
+//
+//--------------------------------------------------------------------------
+#include <headers.cxx>
+#pragma hdrstop
+
+#include <bm_mrsh2.hxx>
+#include <oletest.hxx>
+#include <rpc.h>
+#include <rpcdce.h>
+
+// funciton prototype
+DWORD _stdcall FnThread2(void *param);
+
+
+ULARGE_INTEGER ulSeekStart[REPS]; // stream starts
+LARGE_INTEGER libMove[REPS];
+
+
+const IID *iid2[] = {&IID_IUnknown, &IID_IUnknown,
+ &IID_IAdviseSink, &IID_IAdviseSink,
+ &IID_IDataObject, &IID_IDataObject,
+ &IID_IOleObject, &IID_IOleObject,
+ &IID_IOleClientSite, &IID_IOleClientSite,
+ &IID_IParseDisplayName, &IID_IParseDisplayName,
+ &IID_IPersistStorage, &IID_IPersistStorage,
+ &IID_IPersistFile, &IID_IPersistFile,
+ &IID_IStorage, &IID_IStorage,
+ &IID_IOleContainer, &IID_IOleContainer,
+ &IID_IOleItemContainer, &IID_IOleItemContainer,
+ &IID_IOleInPlaceSite, &IID_IOleInPlaceActiveObject,
+ &IID_IOleInPlaceObject, &IID_IOleInPlaceUIWindow,
+ &IID_IOleInPlaceFrame, &IID_IOleWindow};
+
+
+TCHAR *COleMarshalTest2::Name ()
+{
+ return TEXT("Marshalling2");
+}
+
+SCODE COleMarshalTest2::Setup (CTestInput *pInput)
+{
+ SCODE sc;
+
+ m_hThrd = NULL;
+ m_dwTID1 = GetCurrentThreadId();
+
+ for (ULONG i=0; i<REPS; i++)
+ m_pStm[i] = NULL;
+
+ CTestBase::Setup(pInput);
+
+ // Get number of iterations
+ m_ulIterations = pInput->GetIterations(Name());
+
+ // set NULL in case of error
+ for (i=0; i<m_ulIterations; i++)
+ m_punk[i] = NULL;
+
+
+ // Get custom ClsID from .ini file
+ pInput->GetClassID(&m_ClsID, Name());
+
+ // Get class activation context from .ini file
+ m_dwClsCtx = pInput->GetClassCtx(Name());
+
+ for (i=0; i<REPS; i++)
+ {
+ INIT_RESULTS (m_ulMarshalTime[i]);
+ INIT_RESULTS (m_ulUnmarshalTime[i]);
+ INIT_RESULTS (m_ulReleaseTime[i]);
+
+ INIT_RESULTS (m_ulMarshalTime2[i]);
+ INIT_RESULTS (m_ulUnmarshalTime2[i]);
+ INIT_RESULTS (m_ulReleaseTime2[i]);
+ }
+
+ sc = InitCOM();
+ if (FAILED(sc))
+ {
+ Log (TEXT("Setup - CoInitialize failed."), sc);
+ return sc;
+ }
+
+ for (i=0; i<m_ulIterations; i++)
+ {
+ // create an instance of the object to marshal
+ sc = CoCreateInstance(m_ClsID, NULL, m_dwClsCtx,
+ IID_IUnknown, (void **)&m_punk[i]);
+ if (FAILED(sc))
+ {
+ Log (TEXT("Setup - CoCreateInstance failed"), sc);
+ return sc;
+ }
+ }
+
+
+ for (i=0; i<REPS; i++)
+ {
+ // create a stream to marshal the interface into
+ SCODE sc = CreateStreamOnHGlobal(NULL, 0, &m_pStm[i]);
+ if (FAILED(sc))
+ {
+ Log (TEXT("Setup - CreateStreamOnHGlobal failed"), sc);
+ }
+ else
+ {
+ // write some data to init the stream
+ DWORD dwTemp;
+ m_pStm[i]->Write(&dwTemp, sizeof(DWORD), NULL);
+ }
+ }
+
+ m_hThrd = CreateThread(NULL, 0, FnThread2, (void *)this, 0, &m_dwTID2);
+ if (m_hThrd == NULL)
+ {
+ Log (TEXT("Setup - CreateThread failed"), sc);
+ }
+
+ Sleep(50); // let the other thread initialize
+ return S_OK;
+}
+
+
+SCODE COleMarshalTest2::Cleanup ()
+{
+ // release objects
+ for (ULONG i=0; i<m_ulIterations; i++)
+ {
+ if (m_punk[i])
+ m_punk[i]->Release();
+ }
+
+ for (i=0; i<REPS; i++)
+ {
+ if (m_pStm[i])
+ m_pStm[i]->Release();
+ }
+
+ UninitCOM();
+
+ // close all the handles
+ CloseHandle(m_hThrd);
+
+ return S_OK;
+}
+
+DWORD _stdcall FnThread2(void *param)
+{
+ COleMarshalTest2 *pMrshlTst = (COleMarshalTest2 *)param;
+ return pMrshlTst->Run2();
+}
+
+SCODE COleMarshalTest2::Run ()
+{
+ CStopWatch sw;
+ LPVOID FAR pv[REPS];
+
+ for (ULONG iIter=0; iIter<m_ulIterations; iIter++)
+ {
+ SCODE sc[REPS];
+
+ // settle down before running
+ Sleep(100);
+
+ // first, marshal the interface REPS times.
+ for (ULONG i=0; i<REPS; i++)
+ {
+ // save current stream seek pointer
+ LISet32(libMove[i], 0x00000000);
+ m_pStm[i]->Seek(libMove[i], STREAM_SEEK_CUR, &ulSeekStart[i]);
+
+ // marshal the interface into the stream
+ sw.Reset();
+ sc[i] = CoMarshalInterface(m_pStm[i], *iid2[i], m_punk[iIter],
+ 0, 0, MSHLFLAGS_NORMAL);
+ m_ulMarshalTime[i][iIter] = sw.Read ();
+ Log (TEXT("CoMarshalInterface"), sc[i]);
+
+ if (FAILED(sc[i]))
+ {
+ m_ulMarshalTime[i][iIter] = NOTAVAIL;
+ }
+ }
+
+ // reset the stream ptrs
+ for (i=0; i<REPS; i++)
+ {
+ // set stream ptr back to the starting position
+ LISet32(libMove[i], ulSeekStart[i].LowPart);
+ m_pStm[i]->Seek(libMove[i], STREAM_SEEK_SET, &ulSeekStart[i]);
+ }
+
+
+
+ // kick the other thread alive
+ PostThreadMessage(m_dwTID2, WM_QUIT, NULL, NULL);
+
+ // enter modal loop to dispatch ORPC messages
+ MSG msg;
+ while (GetMessage(&msg, NULL, WM_NULL, WM_NULL))
+ {
+ DispatchMessage(&msg);
+ }
+
+
+
+ // reset the stream ptrs
+ for (i=0; i<REPS; i++)
+ {
+ // set stream ptr back to the starting position
+ LISet32(libMove[i], ulSeekStart[i].LowPart);
+ m_pStm[i]->Seek(libMove[i], STREAM_SEEK_SET, &ulSeekStart[i]);
+ }
+
+ Sleep(100);
+
+ // unmarshal the interface ptrs
+ for (i=0; i<REPS; i++)
+ {
+ // unmarshal the interface from the stream
+ sw.Reset ();
+ sc[i] = CoUnmarshalInterface(m_pStm[i], *iid2[i], &pv[i]);
+ m_ulUnmarshalTime2[i][iIter] = sw.Read ();
+ Log (TEXT("CoUnmarshalInterface"), sc[i]);
+ }
+
+ Sleep(100);
+
+ // release all the interface ptrs we got
+ for (i=0; i<REPS; i++)
+ {
+ if (SUCCEEDED(sc[i]))
+ {
+ sw.Reset ();
+ ((IUnknown *)pv[i])->Release ();
+ m_ulReleaseTime2[i][iIter] = sw.Read ();
+ Log (TEXT("Release"), sc[i]);
+ }
+ else
+ {
+ m_ulReleaseTime2[i][iIter] = NOTAVAIL;
+ m_ulUnmarshalTime2[i][iIter] = NOTAVAIL;
+ }
+ }
+
+ // reset the stream ptrs
+ for (i=0; i<REPS; i++)
+ {
+ // set stream ptr back to the starting position
+ LISet32(libMove[i], ulSeekStart[i].LowPart);
+ m_pStm[i]->Seek(libMove[i], STREAM_SEEK_SET, &ulSeekStart[i]);
+ }
+ }
+
+ return S_OK;
+}
+
+
+SCODE COleMarshalTest2::Run2 ()
+{
+ SCODE sc = InitCOM();
+ if (FAILED(sc))
+ {
+ Log (TEXT("Thread2 - CoInitialize failed."), sc);
+ return sc;
+ }
+
+ CStopWatch sw;
+ LPVOID FAR pv[REPS];
+
+ for (ULONG iIter=0; iIter<m_ulIterations; iIter++)
+ {
+ SCODE sc[REPS];
+
+ // enter modal loop to dispatch ORPC messages
+ MSG msg;
+ while (GetMessage(&msg, NULL, WM_NULL, WM_NULL))
+ {
+ DispatchMessage(&msg);
+ }
+
+ Sleep(100);
+
+ // UnmarshalInterface the interfaces from the stream
+ for (ULONG i=0; i<REPS; i++)
+ {
+ // unmarshal the interface from the stream
+ sw.Reset ();
+ sc[i] = CoUnmarshalInterface(m_pStm[i], *iid2[i], &pv[i]);
+ m_ulUnmarshalTime[i][iIter] = sw.Read ();
+ Log (TEXT("CoUnmarshalInterface"), sc[i]);
+ }
+
+ // now reset the stream ptrs
+ for (i=0; i<REPS; i++)
+ {
+ // set stream ptr back to the starting position
+ LISet32(libMove[i], ulSeekStart[i].LowPart);
+ m_pStm[i]->Seek(libMove[i], STREAM_SEEK_SET, &ulSeekStart[i]);
+ }
+
+ Sleep(100);
+
+ // remarshal the interface proxies
+ for (i=0; i<REPS; i++)
+ {
+ sw.Reset();
+ sc[i] = CoMarshalInterface(m_pStm[i], *iid2[i], (IUnknown *)pv[i],
+ 0, 0, MSHLFLAGS_NORMAL);
+ m_ulMarshalTime2[i][iIter] = sw.Read ();
+ Log (TEXT("CoMarshalInterface"), sc[i]);
+
+ if (FAILED(sc[i]))
+ {
+ m_ulMarshalTime2[i][iIter] = NOTAVAIL;
+ }
+ }
+
+ Sleep(100);
+
+ // release all the interface ptrs we got
+ for (i=0; i<REPS; i++)
+ {
+ if (SUCCEEDED(sc[i]))
+ {
+ sw.Reset ();
+ ((IUnknown *)pv[i])->Release ();
+ m_ulReleaseTime[i][iIter] = sw.Read ();
+ Log (TEXT("Release"), sc[i]);
+ }
+ else
+ {
+ m_ulReleaseTime[i][iIter] = NOTAVAIL;
+ m_ulUnmarshalTime[i][iIter] = NOTAVAIL;
+ }
+ }
+
+ // signal the other thread it is OK to go.
+ PostThreadMessage(m_dwTID1, WM_QUIT, NULL, NULL);
+ }
+
+ UninitCOM();
+ return S_OK;
+}
+
+
+SCODE COleMarshalTest2::Report (CTestOutput &output)
+{
+ output.WriteSectionHeader (Name(),
+ TEXT("Interface Marshalling2"),
+ *m_pInput);
+
+ for (ULONG iCtx=0; iCtx<1; iCtx++)
+ {
+ output.WriteString (TEXT("\n"));
+ output.WriteClassID (&m_ClsID);
+ output.WriteString (apszClsCtx[0]);
+ output.WriteString (TEXT("\n"));
+
+ for (ULONG i=0; i<REPS; i++)
+ {
+ output.WriteResults(TEXT("CoMarshalInterface "), m_ulIterations, m_ulMarshalTime[i]);
+ }
+ output.WriteString (TEXT("\n"));
+
+
+ for (i=0; i<REPS; i++)
+ {
+ output.WriteResults(TEXT("CoUnmarshalInterface"), m_ulIterations, m_ulUnmarshalTime[i]);
+ }
+ output.WriteString (TEXT("\n"));
+
+
+ for (i=0; i<REPS; i++)
+ {
+ output.WriteResults(TEXT("Release Interface "), m_ulIterations, m_ulReleaseTime[i]);
+ }
+ output.WriteString (TEXT("\n"));
+
+
+
+ for (i=0; i<REPS; i++)
+ {
+ output.WriteResults(TEXT("CoMarshalInterface2 "), m_ulIterations, m_ulMarshalTime2[i]);
+ }
+ output.WriteString (TEXT("\n"));
+
+
+ for (i=0; i<REPS; i++)
+ {
+ output.WriteResults(TEXT("CoUnmarshalInterface2"), m_ulIterations, m_ulUnmarshalTime2[i]);
+ }
+ output.WriteString (TEXT("\n"));
+
+
+ for (i=0; i<REPS; i++)
+ {
+ output.WriteResults(TEXT("Release Interface2 "), m_ulIterations, m_ulReleaseTime2[i]);
+ }
+ output.WriteString (TEXT("\n"));
+
+ }
+
+ return S_OK;
+}
diff --git a/private/oleutest/perform/cairole/tests/bm_mrsh2.hxx b/private/oleutest/perform/cairole/tests/bm_mrsh2.hxx
new file mode 100644
index 000000000..b13fe81ef
--- /dev/null
+++ b/private/oleutest/perform/cairole/tests/bm_mrsh2.hxx
@@ -0,0 +1,61 @@
+//+------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1993.
+//
+// File: bm_mrsh2.hxx
+//
+// Contents: test class definition
+//
+// Classes: COleMarshalTest2
+//
+// Functions:
+//
+// History: 29-July-93 t-martig Created
+//
+//--------------------------------------------------------------------------
+
+#ifndef _BM_MRSH2_HXX_
+#define _BM_MRSH2_HXX_
+
+#include <bm_base.hxx>
+
+// # times to marshal consecutively
+#undef REPS
+#define REPS 16
+
+
+class COleMarshalTest2 : public CTestBase
+{
+public:
+ virtual TCHAR *Name ();
+ virtual SCODE Setup (CTestInput *input);
+ virtual SCODE Run ();
+ virtual SCODE Report (CTestOutput &OutputFile);
+ virtual SCODE Cleanup ();
+
+ SCODE Run2();
+
+private:
+ DWORD m_dwTID1; // tid of main thread
+ DWORD m_dwTID2; // tid of worker thread
+ HANDLE m_hThrd; // handle of worker thread
+
+ ULONG m_ulIterations;
+ DWORD m_dwClsCtx;
+ CLSID m_ClsID;
+
+ IUnknown *m_punk[TEST_MAX_ITERATIONS];
+ IStream *m_pStm[REPS];
+
+ ULONG m_ulMarshalTime[REPS][TEST_MAX_ITERATIONS];
+ ULONG m_ulUnmarshalTime[REPS][TEST_MAX_ITERATIONS];
+ ULONG m_ulReleaseTime[REPS][TEST_MAX_ITERATIONS];
+
+ ULONG m_ulMarshalTime2[REPS][TEST_MAX_ITERATIONS];
+ ULONG m_ulUnmarshalTime2[REPS][TEST_MAX_ITERATIONS];
+ ULONG m_ulReleaseTime2[REPS][TEST_MAX_ITERATIONS];
+
+};
+
+#endif
diff --git a/private/oleutest/perform/cairole/tests/bm_nest.cxx b/private/oleutest/perform/cairole/tests/bm_nest.cxx
new file mode 100644
index 000000000..0ac425ac5
--- /dev/null
+++ b/private/oleutest/perform/cairole/tests/bm_nest.cxx
@@ -0,0 +1,190 @@
+//+------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1993.
+//
+// File: bm_nest.cxx
+//
+// Contents: Nested Object Rpc Method Invocation tests
+//
+// Classes: CNestTest
+//
+// History: 1-July-93 t-martig Created
+//
+//--------------------------------------------------------------------------
+#include <headers.cxx>
+#pragma hdrstop
+
+#include <bm_nest.hxx>
+#include <oletest.hxx>
+#include <tracelog.hxx>
+
+
+TCHAR *CNestTest::Name ()
+{
+ return TEXT("Nested");
+}
+
+
+SCODE CNestTest::Setup (CTestInput *pInput)
+{
+ CTestBase::Setup(pInput);
+
+ // get iteration count
+ m_ulIterations = pInput->GetIterations(Name());
+
+ // get CLSID of server
+ SCODE sc = pInput->GetGUID(&m_ClsID, Name(), TEXT("Clsid_Local"));
+ if (FAILED(sc))
+ {
+ Log (TEXT("Setup - GetClassID failed."), sc);
+ return sc;
+ }
+
+ // initialize timing arrays
+ INIT_RESULTS(m_ulNest2Time);
+ INIT_RESULTS(m_ulNest3Time);
+ INIT_RESULTS(m_ulNest4Time);
+ INIT_RESULTS(m_ulNest5Time);
+
+
+ sc = InitCOM();
+ if (FAILED(sc))
+ {
+ Log (TEXT("Setup - CoInitialize failed."), sc);
+ return sc;
+ }
+
+ m_pILoop1=NULL;
+ sc = CoCreateInstance(m_ClsID, NULL, CLSCTX_LOCAL_SERVER,
+ IID_ILoop, (void **)&m_pILoop1);
+ if (FAILED(sc))
+ {
+ Log (TEXT("Setup - CoCreateInstance of first Server failed."), sc);
+ return sc;
+ }
+
+ m_pILoop2=NULL;
+ sc = CoCreateInstance(m_ClsID, NULL, CLSCTX_LOCAL_SERVER,
+ IID_ILoop, (void **)&m_pILoop2);
+ if (FAILED(sc))
+ {
+ Log (TEXT("Setup - CoCreateInstance of second Server failed."), sc);
+ return sc;
+ }
+
+ // pass the pointers to each other
+ sc = m_pILoop1->Init(m_pILoop2);
+ if (FAILED(sc))
+ {
+ Log (TEXT("Setup - Initialization of first Server failed."), sc);
+ return sc;
+ }
+
+ sc = m_pILoop2->Init(m_pILoop1);
+ if (FAILED(sc))
+ {
+ Log (TEXT("Setup - Initialization of second Server failed."), sc);
+ return sc;
+ }
+
+
+ return S_OK;
+}
+
+
+SCODE CNestTest::Cleanup ()
+{
+ if (m_pILoop1)
+ {
+ m_pILoop1->Uninit();
+ m_pILoop1->Release();
+ }
+
+ if (m_pILoop2)
+ {
+ m_pILoop2->Uninit();
+ m_pILoop2->Release();
+ }
+
+ UninitCOM();
+ return S_OK;
+}
+
+
+SCODE CNestTest::Run ()
+{
+ CStopWatch sw;
+ SCODE sc;
+
+ //
+ // nesting 2 levels. Note we pass in 3 not 2, since the server
+ // subtracts 1 from the passed in value and then stops the nesting
+ // if the count is zero.
+ //
+ // a value of 3 represents a single nested call.
+ //
+
+ for (ULONG iIter=0; iIter<m_ulIterations; iIter++)
+ {
+ sw.Reset();
+ sc = m_pILoop1->Loop(3);
+ m_ulNest2Time[iIter] = sw.Read();
+ Log (TEXT("Loop (2)"), sc);
+ }
+
+ //
+ // nesting 3 levels
+ //
+
+ for (iIter=0; iIter<m_ulIterations; iIter++)
+ {
+ sw.Reset();
+ sc= m_pILoop1->Loop(4);
+ m_ulNest3Time[iIter] = sw.Read();
+ Log (TEXT("Loop (3)"), sc);
+ }
+
+ //
+ // nesting 4 levels
+ //
+
+ for (iIter=0; iIter<m_ulIterations; iIter++)
+ {
+ sw.Reset();
+ sc = m_pILoop1->Loop(5);
+ m_ulNest4Time[iIter] = sw.Read();
+ Log (TEXT("Loop (4)"), sc);
+ }
+
+ //
+ // nesting 5 levels
+ //
+
+ for (iIter=0; iIter<m_ulIterations; iIter++)
+ {
+ sw.Reset();
+ sc = m_pILoop1->Loop(6);
+ m_ulNest5Time[iIter] = sw.Read();
+ Log (TEXT("Loop (5)"), sc);
+ }
+
+ return S_OK;
+}
+
+
+
+SCODE CNestTest::Report (CTestOutput &output)
+{
+ output.WriteSectionHeader (Name(), TEXT("Nested ORpc Calls"), *m_pInput);
+
+ output.WriteString (TEXT("\n"));
+ output.WriteResults (TEXT("Nesting 2 "), m_ulIterations, m_ulNest2Time);
+ output.WriteResults (TEXT("Nesting 3 "), m_ulIterations, m_ulNest3Time);
+ output.WriteResults (TEXT("Nesting 4 "), m_ulIterations, m_ulNest4Time);
+ output.WriteResults (TEXT("Nesting 5 "), m_ulIterations, m_ulNest5Time);
+
+ return S_OK;
+}
+
+
diff --git a/private/oleutest/perform/cairole/tests/bm_nest.hxx b/private/oleutest/perform/cairole/tests/bm_nest.hxx
new file mode 100644
index 000000000..07900e009
--- /dev/null
+++ b/private/oleutest/perform/cairole/tests/bm_nest.hxx
@@ -0,0 +1,48 @@
+//+------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1993.
+//
+// File: bm_nest.hxx
+//
+// Contents: test class definition
+//
+// Classes: CNestTest
+//
+// Functions:
+//
+// History: 19-July-93 t-martig Created
+//
+//--------------------------------------------------------------------------
+
+#ifndef _BM_NEST_HXX_
+#define _BM_NEST_HXX_
+
+#include <bm_base.hxx>
+#include <iloop.h> // ILoop
+
+
+class CNestTest : public CTestBase
+{
+public:
+ virtual TCHAR *Name ();
+ virtual SCODE Setup (CTestInput *input);
+ virtual SCODE Run ();
+ virtual SCODE Report (CTestOutput &OutputFile);
+ virtual SCODE Cleanup ();
+
+private:
+ ULONG m_ulIterations;
+ CLSID m_ClsID;
+
+ ILoop *m_pILoop1;
+ ILoop *m_pILoop2;
+
+
+ ULONG m_ulNest2Time[TEST_MAX_ITERATIONS];
+ ULONG m_ulNest3Time[TEST_MAX_ITERATIONS];
+ ULONG m_ulNest4Time[TEST_MAX_ITERATIONS];
+ ULONG m_ulNest5Time[TEST_MAX_ITERATIONS];
+};
+
+#endif
diff --git a/private/oleutest/perform/cairole/tests/bm_noise.cxx b/private/oleutest/perform/cairole/tests/bm_noise.cxx
new file mode 100644
index 000000000..7759334ea
--- /dev/null
+++ b/private/oleutest/perform/cairole/tests/bm_noise.cxx
@@ -0,0 +1,108 @@
+//+------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1993.
+//
+// File: bm_noise.cxx
+//
+// Contents: output class for benchmark results
+//
+// Classes: CNoiseTest
+//
+// History: 30-June-93 t-martig Created
+//
+//--------------------------------------------------------------------------
+#include <headers.cxx>
+#pragma hdrstop
+
+#include <bm_noise.hxx>
+
+
+
+TCHAR *CNoiseTest::Name ()
+{
+ return TEXT("Noise Test");
+}
+
+
+SCODE CNoiseTest::Setup (CTestInput *pInput)
+{
+ CTestBase::Setup(pInput);
+
+ // get iteration count
+ m_ulIterations = pInput->GetIterations(Name(), TEST_MAX_ITERATIONS);
+ INIT_RESULTS(m_ulNoiseTime);
+ return S_OK;
+}
+
+
+SCODE CNoiseTest::Run ()
+{
+ CStopWatch sw;
+ int n;
+ FILE *pfDump;
+ char buffer[100];
+ int i;
+
+ m_ulResolution = sw.Resolution();
+
+ sw.Reset();
+ Sleep (1000);
+ m_ulSleep = sw.Read();
+
+ sw.Reset();
+ for (n=0; n<10000; n++);
+ m_ulIdle = sw.Read();
+
+ for (ULONG iIter=0; iIter<m_ulIterations; iIter++)
+ {
+ sw.Reset();
+ m_ulNoiseTime[iIter] = sw.Read();
+ }
+
+ pfDump = fopen ("C:\\DUMP.BM", "wb");
+ if (pfDump)
+ {
+ sw.Reset();
+ for (i=0; i<1000; i++)
+ fwrite (&buffer, 1, 100, pfDump);
+ m_ulDumpWrite = sw.Read();
+ fclose (pfDump);
+
+ pfDump = fopen ("C:\\DUMP.BM", "rb");
+ if (pfDump)
+ {
+ sw.Reset();
+ for (i=0; i<1000; i++)
+ fread (&buffer, 1, 100, pfDump);
+ m_ulDumpRead = sw.Read();
+ fclose (pfDump);
+ }
+ else
+ m_ulDumpRead = 0xffffffff;
+
+ _unlink ("C:\\DUMP.BM");
+ }
+ else
+ m_ulDumpWrite = 0xffffffff;
+
+ return S_OK;
+}
+
+
+
+SCODE CNoiseTest::Report (CTestOutput &output)
+{
+ output.WriteSectionHeader (Name(), NULL, *m_pInput);
+
+ output.WriteResult (TEXT("Resolution"), m_ulResolution);
+ output.WriteResult (TEXT("Sleep 1000ms"), m_ulSleep);
+ output.WriteResult (TEXT("Idle 10000 loops"), m_ulIdle);
+ output.WriteResults (TEXT("Noise"), m_ulIterations, m_ulNoiseTime);
+ output.WriteResult (TEXT("Write 100k to disk"), m_ulDumpWrite);
+ output.WriteResult (TEXT("Read 100k from disk"), m_ulDumpRead);
+
+ return S_OK;
+}
+
+
diff --git a/private/oleutest/perform/cairole/tests/bm_noise.hxx b/private/oleutest/perform/cairole/tests/bm_noise.hxx
new file mode 100644
index 000000000..3977b6599
--- /dev/null
+++ b/private/oleutest/perform/cairole/tests/bm_noise.hxx
@@ -0,0 +1,41 @@
+//+------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1993.
+//
+// File: bm_noise.hxx
+//
+// Contents: test class definition
+//
+// Classes: CNoiseTest
+//
+// Functions:
+//
+// History: 19-July-93 t-martig Created
+//
+//--------------------------------------------------------------------------
+
+#ifndef _BM_NOISE_HXX_
+#define _BM_NOISE_HXX_
+
+#include <bm_base.hxx>
+
+class CNoiseTest : public CTestBase
+{
+public:
+ virtual TCHAR *Name ();
+ virtual SCODE Setup (CTestInput *input);
+ virtual SCODE Run ();
+ virtual SCODE Report (CTestOutput &OutputFile);
+
+private:
+ ULONG m_ulIterations;
+ ULONG m_ulResolution;
+ ULONG m_ulSleep;
+ ULONG m_ulIdle;
+ ULONG m_ulNoiseTime[TEST_MAX_ITERATIONS];
+ ULONG m_ulDumpRead;
+ ULONG m_ulDumpWrite;
+};
+
+#endif
diff --git a/private/oleutest/perform/cairole/tests/bm_nstg.cxx b/private/oleutest/perform/cairole/tests/bm_nstg.cxx
new file mode 100644
index 000000000..f4a7aad0c
--- /dev/null
+++ b/private/oleutest/perform/cairole/tests/bm_nstg.cxx
@@ -0,0 +1,564 @@
+//+------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1993.
+//
+// File: bm_nstg.cxx
+//
+// Contents: Nested Storage test
+//
+// Classes: CNestedStorageTest
+//
+// History: 09-June-94 t-vadims Created
+//
+//--------------------------------------------------------------------------
+#include <headers.cxx>
+#pragma hdrstop
+
+#include <bm_nstg.hxx>
+
+#define DEF_DATASIZE 4096
+#define INFINITY 0xffffffff // max value of 32-bit ulong
+
+TCHAR *CNestedStorageTest::Name ()
+{
+ return TEXT("NestedStorageTest");
+}
+
+
+SCODE CNestedStorageTest::Setup (CTestInput *pInput)
+{
+ SCODE sc;
+ ULONG iIndex;
+ TCHAR pszBuf[15];
+
+ CTestBase::Setup(pInput);
+
+ // get iteration count
+ m_ulIterations = pInput->GetIterations(Name());
+
+ // initialize timing arrays
+ INIT_RESULTS(m_ulStgCreateDocfile);
+ INIT_RESULTS(m_ulFinalStorageCommit);
+ INIT_RESULTS(m_ulFinalStorageRelease);
+
+ for(iIndex = 0; iIndex <TEST_MAX_ITERATIONS; iIndex++)
+ {
+ m_ulCreateStorageTotal[iIndex] = 0;
+ m_ulCreateStreamTotal[iIndex] = 0;
+ m_ulStreamWriteTotal[iIndex] = 0;
+ m_ulStreamReleaseTotal[iIndex] = 0;
+ m_ulDestroyElementTotal[iIndex] = 0;
+ m_ulStorageCommitTotal[iIndex] = 0;
+ m_ulStorageReleaseTotal[iIndex] = 0;
+ m_ulTotal[iIndex] = 0;
+
+ m_ulCreateStreamMin[iIndex] = INFINITY;
+ m_ulStreamWriteMin[iIndex] = INFINITY;
+ m_ulStreamReleaseMin[iIndex] = INFINITY;
+ m_ulDestroyElementMin[iIndex] = INFINITY;
+
+ m_ulCreateStreamMax[iIndex] = 0;
+ m_ulStreamWriteMax[iIndex] = 0;
+ m_ulStreamReleaseMax[iIndex] = 0;
+ m_ulDestroyElementMax[iIndex] = 0;
+
+ for (ULONG iLevel =0; iLevel < MAX_NESTING; iLevel++)
+ {
+ m_ulStorageCommitMin[iLevel][iIndex] = INFINITY;
+ m_ulStorageReleaseMin[iLevel][iIndex] = INFINITY;
+ m_ulCreateStorageMin[iLevel][iIndex] = INFINITY;
+
+ m_ulCreateStorageMax[iLevel][iIndex] = 0;
+ m_ulStorageCommitMax[iLevel][iIndex] = 0;
+ m_ulStorageReleaseMax[iLevel][iIndex] = 0;
+ }
+ }
+
+
+
+ sc = InitCOM();
+ if (FAILED(sc))
+ {
+ Log (TEXT("Setup - CoInitialize failed."), sc);
+ return sc;
+ }
+
+ // get malloc interface for this task
+ m_piMalloc = NULL;
+ sc = CoGetMalloc(MEMCTX_TASK, &m_piMalloc);
+ if (FAILED(sc))
+ {
+ Log (TEXT("Setup - CoGetMalloc"), sc);
+ return sc;
+ }
+
+ m_cbSize = pInput->GetConfigInt(Name(), TEXT("DataSize"), DEF_DATASIZE);
+
+ // initialize array to be written to the file.
+ m_pbData = (BYTE *)m_piMalloc->Alloc(m_cbSize);
+ if(m_pbData == NULL)
+ {
+ Log (TEXT("Setup - Cannot allocate memory"), E_OUTOFMEMORY);
+ return E_OUTOFMEMORY;
+ }
+
+ for (iIndex=0; iIndex < m_cbSize; iIndex++)
+ m_pbData[iIndex] = (BYTE)iIndex;
+
+
+ // get file name to be used and values of other parameters
+ pInput->GetConfigString(Name(), TEXT("FileName"), TEXT("stgtest.bm"),
+ m_pszFile, MAX_PATH);
+#ifdef UNICODE
+ wcscpy(m_pwszFile, m_pszFile);
+#else
+ mbstowcs(m_pwszFile, m_pszFile, strlen(m_pszFile)+1);
+#endif
+
+ pInput->GetConfigString(Name(), TEXT("FileMode"), TEXT("DIRECT"), m_pszFileMode, 15);
+
+ if(lstrcmpi(m_pszFileMode, TEXT("DIRECT")) == 0)
+ m_flCreateFlags = STGM_DIRECT;
+ else
+ m_flCreateFlags = STGM_TRANSACTED;
+
+ // get the nesting factor
+ m_cNesting = pInput->GetConfigInt(Name(), TEXT("Nesting"), 3);
+
+ if(m_cNesting > MAX_NESTING)
+ m_cNesting = MAX_NESTING;
+
+ if(m_cNesting == 0)
+ m_cNesting = 1;
+
+ // get the branching factor
+ m_cBranching = pInput->GetConfigInt(Name(), TEXT("Branching"), 3);
+
+ if(m_cBranching > MAX_BRANCHING)
+ m_cBranching = MAX_BRANCHING;
+
+ if(m_cBranching == 0)
+ m_cBranching = 1;
+
+ // get the value of Delete element option
+ pInput->GetConfigString(Name(), TEXT("Delete"), TEXT("OFF"), pszBuf, 15);
+
+ if( lstrcmpi(pszBuf, TEXT("OFF")) == 0 ||
+ lstrcmpi(pszBuf, TEXT("FALSE")) == 0)
+ m_bDelete = FALSE;
+ else
+ m_bDelete = TRUE;
+
+ // now compute number of streams and storages, depeding on
+ // the nesting and branching factors. Formulas are as follows:
+ // Nesting = n;
+ // Branching = b;
+ // n
+ // Streams = b
+ //
+ // n
+ // b - 1
+ // Storages = ---------
+ // b - 1
+ //
+ // n-1
+ // b - 1
+ // ParentFactor = ---------
+ // b - 1
+ //
+ // Parent factor is used to determine the parent storage of the stream
+ //
+ m_cStreams = 1;
+ ULONG n = m_cNesting;
+ while(n-- > 0) // compute b^n
+ m_cStreams *= m_cBranching;
+
+ m_cStorages = (m_cStreams - 1) / (m_cBranching - 1);
+
+ m_cParentFactor = (m_cStreams / m_cBranching - 1) /
+ (m_cBranching - 1);
+
+
+ // allocate arrays for storages
+ m_piStorages = (LPSTORAGE *)m_piMalloc->Alloc(m_cStorages *
+ sizeof(LPSTORAGE));
+ if (m_piStorages == NULL)
+ {
+ Log(TEXT("Cannot allocate memory"), E_OUTOFMEMORY);
+ return E_OUTOFMEMORY;
+ }
+
+ return S_OK;
+}
+
+
+SCODE CNestedStorageTest::Cleanup ()
+{
+ // delete the file
+ DeleteFile (m_pszFile);
+
+ // free all memory
+ if(m_piMalloc)
+ {
+ if (m_pbData)
+ m_piMalloc->Free(m_pbData);
+
+ if (m_piStorages)
+ m_piMalloc->Free(m_piStorages);
+
+ m_piMalloc->Release();
+ m_piMalloc = NULL;
+ }
+
+ UninitCOM();
+
+ return S_OK;
+}
+
+
+// Some macros that are used only in Run() function.
+
+#define STG_PARENT(iIndex) ((iIndex - 1) / m_cBranching )
+#define STREAM_PARENT(iIndex) (iIndex / m_cBranching + m_cParentFactor )
+
+// STG_NAME and STREAM_NAME macros are very ugly, but they save
+// doing a bunch of allocations and name generation in the beginning.
+
+#define STG_NAME(iIndex) (swprintf(pwszBuf, L"Storage%d", iIndex), pwszBuf)
+#define STREAM_NAME(iIndex) (swprintf(pwszBuf, L"Stream%d", iIndex), pwszBuf)
+
+
+SCODE CNestedStorageTest::Run ()
+{
+ CStopWatch sw;
+ HRESULT hr;
+ ULONG cb;
+ ULONG iCurStream;
+ LONG iCurStg; // has to be long, not ulong, for looping down to zero.
+ LPSTREAM piStream;
+ ULONG iIter;
+ OLECHAR pwszBuf[20];
+ ULONG ulTime;
+ ULONG iLevel;
+ ULONG iParent;
+
+
+ for (iIter =0; iIter < m_ulIterations; iIter++)
+ {
+
+ sw.Reset();
+ hr = StgCreateDocfile(m_pwszFile, m_flCreateFlags | STGM_WRITE
+ | STGM_CREATE | STGM_SHARE_EXCLUSIVE, 0, &m_piStorages[0]);
+ m_ulStgCreateDocfile[iIter] = sw.Read();
+ Log(TEXT("StgCreateDocfile"), hr);
+ if (FAILED(hr))
+ return hr;
+
+ // Create a complete tree of storages
+ for (iCurStg = 1; iCurStg < (LONG)m_cStorages; iCurStg++)
+ {
+ // determine level of curent storage.
+ iLevel = 0;
+ iParent = STG_PARENT(iCurStg);
+ while(iParent > 0)
+ {
+ iParent = STG_PARENT(iParent);
+ iLevel++;
+ }
+
+ sw.Reset();
+ hr = m_piStorages[STG_PARENT(iCurStg)]->
+ CreateStorage(STG_NAME(iCurStg),
+ m_flCreateFlags | STGM_WRITE |
+ STGM_CREATE | STGM_SHARE_EXCLUSIVE,
+ 0, 0, &m_piStorages[iCurStg]);
+ ulTime = sw.Read();
+ m_ulCreateStorageTotal[iIter] += ulTime;
+
+ if(ulTime < m_ulCreateStorageMin[iLevel][iIter])
+ m_ulCreateStorageMin[iLevel][iIter] = ulTime;
+
+ if(ulTime > m_ulCreateStorageMax[iLevel][iIter])
+ m_ulCreateStorageMax[iLevel][iIter] = ulTime;
+
+ if (FAILED(hr))
+ {
+ Log(TEXT("CreateStorage"), hr);
+ return hr;
+ }
+ }
+ Log(TEXT("CreateStorage"), S_OK);
+ // For each storage in final level, open several streams,
+ // write some data to them, and release them
+ for (iCurStream = 0; iCurStream < m_cStreams; iCurStream++)
+ {
+ sw.Reset();
+ hr = m_piStorages[STREAM_PARENT(iCurStream)]->
+ CreateStream(STREAM_NAME(iCurStream),
+ STGM_DIRECT | STGM_WRITE |
+ STGM_CREATE | STGM_SHARE_EXCLUSIVE,
+ 0, 0, &piStream);
+ ulTime = sw.Read();
+ m_ulCreateStreamTotal[iIter] += ulTime;
+
+ if(ulTime < m_ulCreateStreamMin[iIter])
+ m_ulCreateStreamMin[iIter] = ulTime;
+
+ if(ulTime > m_ulCreateStreamMax[iIter])
+ m_ulCreateStreamMax[iIter] = ulTime;
+
+ if (FAILED(hr))
+ {
+ Log(TEXT("CreateStream"), hr);
+ return hr;
+ }
+
+ sw.Reset();
+ piStream->Write((LPVOID)m_pbData, m_cbSize, &cb);
+ ulTime = sw.Read();
+ m_ulStreamWriteTotal[iIter] += ulTime;
+
+ if(ulTime < m_ulStreamWriteMin[iIter])
+ m_ulStreamWriteMin[iIter] = ulTime;
+
+ if(ulTime > m_ulStreamWriteMax[iIter])
+ m_ulStreamWriteMax[iIter] = ulTime;
+
+ sw.Reset();
+ piStream->Release();
+ ulTime = sw.Read();
+ m_ulStreamReleaseTotal[iIter] += ulTime;
+
+ if(ulTime < m_ulStreamReleaseMin[iIter])
+ m_ulStreamReleaseMin[iIter] = ulTime;
+
+ if(ulTime > m_ulStreamReleaseMax[iIter])
+ m_ulStreamReleaseMax[iIter] = ulTime;
+ }
+ Log(TEXT("CreateStream"), S_OK);
+ Log(TEXT("StreamWrite"), S_OK);
+ Log(TEXT("StreamRelease"), S_OK);
+
+ if (m_bDelete)
+ {
+ // delete 1 stream from every branch.
+ for (iCurStream = 1; iCurStream < m_cStreams; iCurStream += m_cBranching)
+ {
+ sw.Reset();
+ hr = m_piStorages[STREAM_PARENT(iCurStream)]->
+ DestroyElement(STREAM_NAME(iCurStream));
+ ulTime = sw.Read();
+ m_ulDestroyElementTotal[iIter] += ulTime;
+
+ if (ulTime < m_ulDestroyElementMin[iIter])
+ m_ulDestroyElementMin[iIter] = ulTime;
+
+ if (ulTime > m_ulDestroyElementMax[iIter])
+ m_ulDestroyElementMax[iIter] = ulTime;
+
+ if (FAILED(hr))
+ {
+ Log(TEXT("DestroyElement"), hr);
+ return hr;
+ }
+ }
+ Log( TEXT("DestroyElement"), S_OK);
+
+ m_ulDestroyElementAverage[iIter] = m_ulDestroyElementTotal[iIter] /
+ (m_cStreams / m_cBranching);
+ }
+ // for each storage, do commit if in transacted mode
+ // and release the storage.
+ for (iCurStg = m_cStorages-1 ; iCurStg >= 0 ; iCurStg--)
+ {
+ // determine level of curent storage.
+ iLevel = 0;
+ iParent = STG_PARENT(iCurStg);
+ while(iParent > 0)
+ {
+ iParent = STG_PARENT(iParent);
+ iLevel++;
+ }
+
+ if (m_flCreateFlags == STGM_TRANSACTED)
+ {
+ sw.Reset();
+ m_piStorages[iCurStg]->Commit(STGC_DEFAULT);
+ ulTime = sw.Read();
+ m_ulStorageCommitTotal[iIter] += ulTime;
+
+ if (iCurStg != 0)
+ {
+ if (ulTime < m_ulStorageCommitMin[iLevel][iIter])
+ m_ulStorageCommitMin[iLevel][iIter] = ulTime;
+
+ if (ulTime > m_ulStorageCommitMax[iLevel][iIter])
+ m_ulStorageCommitMax[iLevel][iIter] = ulTime;
+ }
+ else
+ {
+ m_ulFinalStorageCommit[iIter] = ulTime;
+ }
+ }
+
+ sw.Reset();
+ m_piStorages[iCurStg]->Release();
+ ulTime = sw.Read();
+ m_ulStorageReleaseTotal[iIter] += ulTime;
+
+ if (iCurStg != 0)
+ {
+ if (ulTime < m_ulStorageReleaseMin[iLevel][iIter])
+ m_ulStorageReleaseMin[iLevel][iIter] = ulTime;
+
+ if (ulTime > m_ulStorageReleaseMax[iLevel][iIter])
+ m_ulStorageReleaseMax[iLevel][iIter] = ulTime;
+ }
+ else
+ {
+ m_ulFinalStorageRelease[iIter] = ulTime;
+ }
+ }
+
+ Log(TEXT("StorageCommit"), S_OK);
+ Log(TEXT("StorageRelease"), S_OK);
+
+
+ m_ulCreateStorageAverage[iIter] = m_ulCreateStorageTotal[iIter] / m_cStorages;
+ m_ulCreateStreamAverage[iIter] = m_ulCreateStreamTotal[iIter] / m_cStreams;
+ m_ulStreamWriteAverage[iIter] = m_ulStreamWriteTotal[iIter] / m_cStreams;
+ m_ulStreamReleaseAverage[iIter] = m_ulStreamReleaseTotal[iIter] / m_cStreams;
+ m_ulStorageCommitAverage[iIter] = m_ulStorageCommitTotal[iIter] / m_cStorages;
+ m_ulStorageReleaseAverage[iIter] = m_ulStorageReleaseTotal[iIter] / m_cStorages;
+
+ m_ulTotal[iIter] = m_ulStgCreateDocfile[iIter] +
+ m_ulCreateStorageTotal[iIter] +
+ m_ulCreateStreamTotal[iIter] +
+ m_ulStreamWriteTotal[iIter] +
+ m_ulStreamReleaseTotal[iIter] +
+ m_ulDestroyElementTotal[iIter] +
+ m_ulStorageCommitTotal[iIter] +
+ m_ulStorageReleaseTotal[iIter];
+
+ }
+
+ return S_OK;
+}
+
+
+SCODE CNestedStorageTest::Report (CTestOutput &output)
+{
+ TCHAR pszBuf[80];
+
+ wsprintf(pszBuf, TEXT("Nested Storage Test in %s Mode writing %d bytes"),
+ m_pszFileMode, m_cbSize);
+
+ output.WriteSectionHeader (Name(), pszBuf, *m_pInput);
+ output.WriteString (TEXT("\n"));
+
+ for ( ULONG iLevel = 0; iLevel < m_cNesting - 1; iLevel++)
+ {
+ wsprintf(pszBuf, TEXT("\nLevel %d\n"), iLevel + 1);
+ output.WriteString (pszBuf);
+ output.WriteResults (TEXT("CreateStorage Min"), m_ulIterations,
+ m_ulCreateStorageMin[iLevel]);
+ output.WriteResults (TEXT("CreateStorage Max"), m_ulIterations,
+ m_ulCreateStorageMax[iLevel]);
+
+ if (m_flCreateFlags == STGM_TRANSACTED)
+ {
+ output.WriteResults (TEXT("StorageCommit Min"), m_ulIterations,
+ m_ulStorageCommitMin[iLevel] );
+ output.WriteResults (TEXT("StorageCommit Max"), m_ulIterations,
+ m_ulStorageCommitMax[iLevel] );
+ }
+
+ output.WriteResults (TEXT("StorageRelease Min"), m_ulIterations,
+ m_ulStorageReleaseMin[iLevel]);
+ output.WriteResults (TEXT("StorageRelease Max"), m_ulIterations,
+ m_ulStorageReleaseMax[iLevel]);
+ }
+
+ output.WriteString (TEXT("\nOverall\n"));
+
+ output.WriteResults (TEXT("StgCreateDocfile "), m_ulIterations,
+ m_ulStgCreateDocfile);
+
+ if (m_flCreateFlags == STGM_TRANSACTED)
+ output.WriteResults (TEXT("Final Storage Commit"), m_ulIterations,
+ m_ulFinalStorageCommit);
+
+ output.WriteResults (TEXT("Final Storage Release"), m_ulIterations,
+ m_ulFinalStorageRelease);
+ output.WriteString (TEXT("\n"));
+
+ output.WriteResults (TEXT("CreateStorage Average"), m_ulIterations,
+ m_ulCreateStorageAverage );
+ output.WriteResults (TEXT("CreateStorage Total"), m_ulIterations,
+ m_ulCreateStorageTotal );
+ output.WriteString (TEXT("\n"));
+
+ output.WriteResults (TEXT("CreateStream Min"), m_ulIterations,
+ m_ulCreateStreamMin);
+ output.WriteResults (TEXT("CreateStream Max"), m_ulIterations,
+ m_ulCreateStreamMax);
+ output.WriteResults (TEXT("CreateStream Average"), m_ulIterations,
+ m_ulCreateStreamAverage);
+ output.WriteResults (TEXT("CreateStream Total"), m_ulIterations,
+ m_ulCreateStreamTotal );
+ output.WriteString (TEXT("\n"));
+
+ output.WriteResults (TEXT("StreamWrite Min"), m_ulIterations,
+ m_ulStreamWriteMin );
+ output.WriteResults (TEXT("StreamWrite Max"), m_ulIterations,
+ m_ulStreamWriteMax );
+ output.WriteResults (TEXT("StreamWrite Average"), m_ulIterations,
+ m_ulStreamWriteAverage );
+ output.WriteResults (TEXT("StreamWrite Total"), m_ulIterations,
+ m_ulStreamWriteTotal );
+ output.WriteString (TEXT("\n"));
+
+ output.WriteResults (TEXT("StreamRelease Min"), m_ulIterations,
+ m_ulStreamReleaseMin );
+ output.WriteResults (TEXT("StreamRelease Max"), m_ulIterations,
+ m_ulStreamReleaseMax );
+ output.WriteResults (TEXT("StreamRelease Average"), m_ulIterations,
+ m_ulStreamReleaseAverage );
+ output.WriteResults (TEXT("StreamRelease Total"), m_ulIterations,
+ m_ulStreamReleaseTotal );
+ output.WriteString (TEXT("\n"));
+
+ if(m_bDelete)
+ {
+ output.WriteResults (TEXT("DestroyElement Min"), m_ulIterations,
+ m_ulDestroyElementMin );
+ output.WriteResults (TEXT("DestroyElement Max"), m_ulIterations,
+ m_ulDestroyElementMax );
+ output.WriteResults (TEXT("DestroyElement Average"), m_ulIterations,
+ m_ulDestroyElementAverage );
+ output.WriteResults (TEXT("DestroyElement Total"), m_ulIterations,
+ m_ulDestroyElementTotal );
+ output.WriteString (TEXT("\n"));
+ }
+
+ if (m_flCreateFlags == STGM_TRANSACTED)
+ {
+ output.WriteResults (TEXT("StorageCommit Average"), m_ulIterations,
+ m_ulStorageCommitAverage );
+ output.WriteResults (TEXT("StorageCommit Total"), m_ulIterations,
+ m_ulStorageCommitTotal );
+ output.WriteString (TEXT("\n"));
+ }
+
+ output.WriteResults (TEXT("StorageRelease Average"), m_ulIterations,
+ m_ulStorageReleaseAverage );
+ output.WriteResults (TEXT("StorageRelease Total"), m_ulIterations,
+ m_ulStorageReleaseTotal );
+ output.WriteString (TEXT("\n"));
+
+ output.WriteResults (TEXT("Overall Total "), m_ulIterations, m_ulTotal );
+
+ return S_OK;
+}
+
diff --git a/private/oleutest/perform/cairole/tests/bm_nstg.hxx b/private/oleutest/perform/cairole/tests/bm_nstg.hxx
new file mode 100644
index 000000000..0215d12e4
--- /dev/null
+++ b/private/oleutest/perform/cairole/tests/bm_nstg.hxx
@@ -0,0 +1,111 @@
+//+------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1993.
+//
+// File: bm_nstg.hxx
+//
+// Contents: Nested storage test class definition
+//
+// Classes: CNestedStorageTest
+//
+// Functions:
+//
+// History: 09-June-94 t-vadims Created
+//
+//--------------------------------------------------------------------------
+
+#ifndef _BM_NSTG_HXX_
+#define _BM_NSTG_HXX_
+
+#include <bm_base.hxx>
+
+// Maximum allowed branching and nesting factors
+// Using both maximums at the same time is not recommended,
+// due to exponetial growth of time requirements
+#define MAX_BRANCHING 7
+#define MAX_NESTING 7
+
+class CNestedStorageTest : public CTestBase
+{
+public:
+ virtual TCHAR *Name ();
+ virtual SCODE Setup (CTestInput *input);
+ virtual SCODE Run ();
+ virtual SCODE Report (CTestOutput &OutputFile);
+ virtual SCODE Cleanup ();
+
+private:
+
+ ULONG m_ulIterations;
+
+ // timing arrays
+
+ ULONG m_ulStgCreateDocfile[TEST_MAX_ITERATIONS];
+ ULONG m_ulFinalStorageCommit[TEST_MAX_ITERATIONS];
+ ULONG m_ulFinalStorageRelease[TEST_MAX_ITERATIONS];
+
+ ULONG m_ulCreateStorageMin[MAX_NESTING][TEST_MAX_ITERATIONS];
+ ULONG m_ulCreateStorageMax[MAX_NESTING][TEST_MAX_ITERATIONS];
+ ULONG m_ulCreateStorageAverage[TEST_MAX_ITERATIONS];
+ ULONG m_ulCreateStorageTotal[TEST_MAX_ITERATIONS];
+
+ ULONG m_ulStorageReleaseMin[MAX_NESTING][TEST_MAX_ITERATIONS];
+ ULONG m_ulStorageReleaseMax[MAX_NESTING][TEST_MAX_ITERATIONS];
+ ULONG m_ulStorageReleaseAverage[TEST_MAX_ITERATIONS];
+ ULONG m_ulStorageReleaseTotal[TEST_MAX_ITERATIONS];
+
+ ULONG m_ulCreateStreamMin[TEST_MAX_ITERATIONS];
+ ULONG m_ulCreateStreamMax[TEST_MAX_ITERATIONS];
+ ULONG m_ulCreateStreamAverage[TEST_MAX_ITERATIONS];
+ ULONG m_ulCreateStreamTotal[TEST_MAX_ITERATIONS];
+
+ ULONG m_ulStreamWriteMin[TEST_MAX_ITERATIONS];
+ ULONG m_ulStreamWriteMax[TEST_MAX_ITERATIONS];
+ ULONG m_ulStreamWriteAverage[TEST_MAX_ITERATIONS];
+ ULONG m_ulStreamWriteTotal[TEST_MAX_ITERATIONS];
+
+ ULONG m_ulStreamReleaseMin[TEST_MAX_ITERATIONS];
+ ULONG m_ulStreamReleaseMax[TEST_MAX_ITERATIONS];
+ ULONG m_ulStreamReleaseAverage[TEST_MAX_ITERATIONS];
+ ULONG m_ulStreamReleaseTotal[TEST_MAX_ITERATIONS];
+
+ ULONG m_ulDestroyElementMin[TEST_MAX_ITERATIONS];
+ ULONG m_ulDestroyElementMax[TEST_MAX_ITERATIONS];
+ ULONG m_ulDestroyElementAverage[TEST_MAX_ITERATIONS];
+ ULONG m_ulDestroyElementTotal[TEST_MAX_ITERATIONS];
+
+ ULONG m_ulStorageCommitMin[MAX_NESTING][TEST_MAX_ITERATIONS];
+ ULONG m_ulStorageCommitMax[MAX_NESTING][TEST_MAX_ITERATIONS];
+ ULONG m_ulStorageCommitAverage[TEST_MAX_ITERATIONS];
+ ULONG m_ulStorageCommitTotal[TEST_MAX_ITERATIONS];
+
+
+ ULONG m_ulTotal[TEST_MAX_ITERATIONS];
+
+
+ BYTE *m_pbData; // data to be written
+
+ OLECHAR m_pwszFile[MAX_PATH]; // file name to be written for OLE
+ TCHAR m_pszFile[MAX_PATH]; // file name to be written for WIN32
+ TCHAR m_pszFileMode[15]; // file access mode (TRANSACTED / DIRECTED)
+
+ ULONG m_flCreateFlags; // Creation flag (STGM_TRANSACTED / STGM_DIRECT)
+ BOOL m_bDelete; // flag if we are to delete streams
+
+ ULONG m_cbSize; // number of bytes in data
+
+ ULONG m_cBranching; // Branching factor
+ ULONG m_cNesting; // nesting factor
+ ULONG m_cParentFactor;
+
+
+ ULONG m_cStorages; // number of storages
+ ULONG m_cStreams; // number of streams
+ LPSTORAGE *m_piStorages; // array of storages
+
+ LPMALLOC m_piMalloc; // pointer of task allocator.
+
+};
+
+#endif
diff --git a/private/oleutest/perform/cairole/tests/bm_obind.cxx b/private/oleutest/perform/cairole/tests/bm_obind.cxx
new file mode 100644
index 000000000..a68af2675
--- /dev/null
+++ b/private/oleutest/perform/cairole/tests/bm_obind.cxx
@@ -0,0 +1,197 @@
+//+------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1993.
+//
+// File: bm_obind.cxx
+//
+// Contents: Ole moniker binding test (BindToObject)
+//
+// Classes: CFileMonikerObjBindTest
+//
+// History: 9-July-93 t-martig Created
+//
+//--------------------------------------------------------------------------
+#include <headers.cxx>
+#pragma hdrstop
+
+#include <bm_obind.hxx>
+
+
+TCHAR *CFileMonikerObjBindTest::Name ()
+{
+ return TEXT("BindToObject");
+}
+
+
+SCODE CFileMonikerObjBindTest::Setup (CTestInput *pInput)
+{
+ IClassFactory *pICF = NULL;
+ IPersistFile *pIPF = NULL;
+ SCODE sc = S_OK, scRet = S_OK;
+
+
+ CTestBase::Setup(pInput);
+
+ // get the iteration count from the ini file
+ m_ulIterations = pInput->GetIterations(Name());
+
+ // for each class ctx, get the classid, and init internal state
+ for (ULONG iCtx=0; iCtx<CNT_CLSCTX; iCtx++)
+ {
+ // Get ClsID for this Ctx from the .ini file
+ sc = pInput->GetGUID(&m_ClsID[iCtx], Name(), apszClsIDName[iCtx]);
+ if (FAILED(sc))
+ {
+ Log (TEXT("Setup - GetClassID failed."), sc);
+ return sc;
+ }
+
+ INIT_RESULTS(m_ulCreateMkrTime[iCtx]);
+ INIT_RESULTS(m_ulCreateBndCtxTime[iCtx]);
+ INIT_RESULTS(m_ulBindTime[iCtx]);
+ }
+
+
+ sc = InitCOM();
+ if (FAILED(sc))
+ {
+ Log (TEXT("Setup - CoInitialize failed."), sc);
+ return sc;
+ }
+
+
+ // for each class ctx, create a persistent instance on disk
+ for (iCtx=0; iCtx<CNT_CLSCTX; iCtx++)
+ {
+ // Create an instance
+ sc = CoGetClassObject(m_ClsID[iCtx], dwaClsCtx[iCtx], NULL,
+ IID_IClassFactory, (void **)&pICF);
+ if (SUCCEEDED(sc))
+ {
+ sc = pICF->CreateInstance(NULL, IID_IPersistFile,
+ (void **)&pIPF);
+ pICF->Release();
+ if (SUCCEEDED(sc))
+ {
+ // save the class instance in the storage
+ sc = pIPF->Save(apszPerstName[iCtx], FALSE);
+ pIPF->Release();
+
+ if (FAILED(sc))
+ {
+ Log (TEXT("Setup - pIPF->Save failed."), sc);
+ scRet = sc;
+ }
+ }
+ else
+ {
+ Log (TEXT("Setup - CreateInstance failed"), sc);
+ scRet = sc;
+ }
+ }
+ else
+ {
+ Log (TEXT("Setup - CoGetClassObject failed"), sc);
+ scRet = sc;
+ }
+ }
+
+ return scRet;
+}
+
+
+SCODE CFileMonikerObjBindTest::Cleanup ()
+{
+ UninitCOM();
+
+ CHAR szPerstName[80];
+
+ // delete the persistent instances
+ for (ULONG iCtx=0; iCtx<CNT_CLSCTX; iCtx++)
+ {
+ // delete original
+ wcstombs(szPerstName, apszPerstName[iCtx],
+ wcslen(apszPerstName[iCtx])+1);
+ _unlink (szPerstName);
+ }
+
+ return S_OK;
+}
+
+
+SCODE CFileMonikerObjBindTest::Run ()
+{
+ CStopWatch sw;
+ IMoniker *pmk = NULL;
+ IBindCtx *pbc = NULL;
+ IPersistFile *pIPF = NULL;
+ SCODE sc;
+
+ // for each class context
+ for (ULONG iCtx=0; iCtx<CNT_CLSCTX; iCtx++)
+ {
+ // for each iteration
+ for (ULONG iIter=0; iIter<m_ulIterations; iIter++)
+ {
+ sw.Reset();
+ sc = CreateFileMoniker (apszPerstName[iCtx], &pmk);
+ m_ulCreateMkrTime[iCtx][iIter] = sw.Read();
+ if (Log (TEXT("CreateFileMoniker"), sc))
+ {
+ m_ulCreateMkrTime[iCtx][iIter] = NOTAVAIL;
+ }
+
+ sw.Reset();
+ sc = CreateBindCtx(0, &pbc);
+ m_ulCreateBndCtxTime[iCtx][iIter] = sw.Read();
+ if (Log (TEXT("CreateBindCtx"), sc))
+ {
+ m_ulCreateBndCtxTime[iCtx][iIter] = NOTAVAIL;
+ }
+
+ sw.Reset();
+ sc = pmk->BindToObject(pbc, NULL, IID_IPersistFile, (void**)&pIPF);
+ m_ulBindTime[iCtx][iIter]=sw.Read ();
+
+ pmk->Release();
+ pbc->Release();
+
+ if (Log (TEXT("BindToObject"), sc))
+ {
+ m_ulBindTime[iCtx][iIter] = NOTAVAIL;
+ }
+ else
+ {
+ sw.Reset();
+ pIPF->Release();
+ m_ulReleaseTime[iCtx][iIter]=sw.Read ();
+ }
+ }
+ }
+
+ return S_OK;
+}
+
+
+
+SCODE CFileMonikerObjBindTest::Report (CTestOutput &output)
+{
+ output.WriteSectionHeader (Name(), TEXT("BindToObject via FileMoniker"), *m_pInput);
+
+ // for each clsctx, write the results
+ for (ULONG iCtx=0; iCtx<CNT_CLSCTX; iCtx++)
+ {
+ output.WriteString(TEXT("\n"));
+ output.WriteClassID(&m_ClsID[iCtx]);
+ output.WriteString(apszClsCtx[iCtx]);
+ output.WriteString(TEXT("\n"));
+
+ output.WriteResults(TEXT("CreateMoniker"), m_ulIterations, m_ulCreateMkrTime[iCtx]);
+ output.WriteResults(TEXT("CreateBindCtx"), m_ulIterations, m_ulCreateBndCtxTime[iCtx]);
+ output.WriteResults(TEXT("Bind "), m_ulIterations, m_ulBindTime[iCtx]);
+ output.WriteResults(TEXT("Release "), m_ulIterations, m_ulReleaseTime[iCtx]);
+ }
+
+ return S_OK;
+}
diff --git a/private/oleutest/perform/cairole/tests/bm_obind.hxx b/private/oleutest/perform/cairole/tests/bm_obind.hxx
new file mode 100644
index 000000000..d2e36a109
--- /dev/null
+++ b/private/oleutest/perform/cairole/tests/bm_obind.hxx
@@ -0,0 +1,42 @@
+//+------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1993.
+//
+// File: bm_obind.hxx
+//
+// Contents: test class definition
+//
+// Classes: CFileMonikerObjBindTest
+//
+// Functions:
+//
+// History: 19-July-93 t-martig Created
+//
+//--------------------------------------------------------------------------
+
+#ifndef _BM_OBIND_HXX_
+#define _BM_OBIND_HXX_
+
+#include <bm_base.hxx>
+
+class CFileMonikerObjBindTest : public CTestBase
+{
+public:
+ virtual TCHAR *Name ();
+ virtual SCODE Setup (CTestInput *input);
+ virtual SCODE Run ();
+ virtual SCODE Report (CTestOutput &OutputFile);
+ virtual SCODE Cleanup ();
+
+private:
+ CLSID m_ClsID[CNT_CLSCTX];
+
+ ULONG m_ulIterations;
+ ULONG m_ulCreateMkrTime[CNT_CLSCTX][TEST_MAX_ITERATIONS];
+ ULONG m_ulCreateBndCtxTime[CNT_CLSCTX][TEST_MAX_ITERATIONS];
+ ULONG m_ulBindTime[CNT_CLSCTX][TEST_MAX_ITERATIONS];
+ ULONG m_ulReleaseTime[CNT_CLSCTX][TEST_MAX_ITERATIONS];
+};
+
+#endif
diff --git a/private/oleutest/perform/cairole/tests/bm_piact.cxx b/private/oleutest/perform/cairole/tests/bm_piact.cxx
new file mode 100644
index 000000000..8a78aeb70
--- /dev/null
+++ b/private/oleutest/perform/cairole/tests/bm_piact.cxx
@@ -0,0 +1,221 @@
+//+------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1993.
+//
+// File: bm_piact.cxx
+//
+// Contents: Persistant instance activation test
+//
+// Classes: COlePersistActivationTest
+//
+// History: 29-July-93 t-martig Created
+//
+//--------------------------------------------------------------------------
+#include <headers.cxx>
+#pragma hdrstop
+
+#include <bm_piact.hxx>
+
+
+WCHAR *COlePersistActivationTest::Name ()
+{
+ return L"PersistActivation";
+}
+
+
+SCODE COlePersistActivationTest::Setup (CTestInput *pInput)
+{
+ IPersistFile *pIPF = NULL;
+ IClassFactory *pICF = NULL;
+ SCODE sc = S_OK, scRet = S_OK;
+
+ CTestBase::Setup (pInput);
+
+ // Get number of iterations
+ m_ulIterations = pInput->GetIterations(Name());
+
+ // for each class ctx, get the classid, and init internal state
+ for (ULONG iCtx=0; iCtx<CNT_CLSCTX; iCtx++)
+ {
+ // Get ClsID for this Ctx from the .ini file
+ sc = pInput->GetGUID(&m_ClsID[iCtx], Name(), apwszClsIDName[iCtx]);
+ if (FAILED(sc))
+ {
+ Log (L"Setup - GetGUID failed", sc);
+ return sc;
+ }
+
+ INIT_RESULTS (m_ulNewTime[iCtx]);
+ INIT_RESULTS (m_ulGetTime[iCtx]);
+ }
+
+
+ sc = InitCOM();
+ if (FAILED(sc))
+ {
+ Log (TEXT("Setup - CoInitialize failed."), sc);
+ return sc;
+ }
+
+
+ // for each class ctx, create a persistent instance on disk
+ for (iCtx=0; iCtx<CNT_CLSCTX; iCtx++)
+ {
+ // Create an instance
+ sc = CoGetClassObject(m_ClsID[iCtx], dwaClsCtx[iCtx], NULL,
+ IID_IClassFactory, (void **)&pICF);
+ if (SUCCEEDED(sc))
+ {
+ sc = pICF->CreateInstance(NULL, IID_IPersistFile, (void **)&pIPF);
+ pICF->Release();
+ if (SUCCEEDED(sc))
+ {
+ // save the instance in a file
+ sc = pIPF->Save (apwszPerstName[iCtx], TRUE);
+ pIPF->Release();
+
+ if (FAILED(sc))
+ {
+ Log (L"Setup - IPersistFile::Save failed", sc);
+ scRet = sc;
+ }
+ }
+ else
+ {
+ Log (L"Setup - CreateInstance failed", sc);
+ scRet = sc;
+ }
+
+ }
+ else
+ {
+ Log (L"Setup - CoGetClassObject failed", sc);
+ scRet = sc;
+ }
+ }
+
+ // _pInput = pInput;
+ return scRet;
+}
+
+
+SCODE COlePersistActivationTest::Cleanup ()
+{
+ UninitCOM();
+
+ CHAR szPerstName[80];
+
+ // delete the persistent instances
+ for (ULONG iCtx=0; iCtx<CNT_CLSCTX; iCtx++)
+ {
+ // delete original
+ wcstombs(szPerstName, apwszPerstName[iCtx],
+ wcslen(apwszPerstName[iCtx])+1);
+ _unlink (szPerstName);
+
+ // delete new instance
+ wcstombs(szPerstName, apwszPerstNameNew[iCtx],
+ wcslen(apwszPerstNameNew[iCtx])+1);
+ _unlink (szPerstName);
+ }
+
+ return S_OK;
+}
+
+
+SCODE COlePersistActivationTest::Run ()
+{
+ CStopWatch sw;
+ IUnknown *punk = NULL;
+ SCODE sc;
+
+ for (ULONG iCtx=0; iCtx<CNT_CLSCTX; iCtx++)
+ {
+ for (ULONG iIter=0; iIter<m_ulIterations; iIter++)
+ {
+ sw.Reset();
+ sc = CoGetPersistentInstance(IID_IUnknown,
+ dwaClsCtx[iCtx],
+ STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
+ apwszPerstName[iCtx],
+ NULL,
+ CLSID_NULL,
+ NULL,
+ (void**)&punk);
+
+ m_ulGetTime[iCtx][iIter] = sw.Read();
+ Log (L"CoGetPersistentInstance", sc);
+
+ if (SUCCEEDED(sc))
+ {
+ sw.Reset();
+ punk->Release();
+ m_ulGetReleaseTime[iCtx][iIter] = sw.Read();
+ }
+ else
+ {
+ m_ulGetTime[iCtx][iIter] = NOTAVAIL;
+ }
+
+ // _pInput->Pause(IP_ITERPAUSE);
+
+ sw.Reset();
+ sc = CoNewPersistentInstance(m_ClsID[iCtx],
+ IID_IUnknown,
+ dwaClsCtx[iCtx],
+ STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
+ apwszPerstName[iCtx],
+ NULL,
+ apwszPerstNameNew[iCtx],
+ (void**)&punk);
+ m_ulNewTime[iCtx][iIter] = sw.Read();
+ Log (L"CoNewPersistentInstance", sc);
+
+ if (SUCCEEDED(sc))
+ {
+ sw.Reset();
+ punk->Release();
+ m_ulNewReleaseTime[iCtx][iIter] = sw.Read();
+ }
+ else
+ {
+ m_ulNewTime[iCtx][iIter] = NOTAVAIL;
+ }
+
+ CHAR szPerstName[80];
+ wcstombs(szPerstName, apwszPerstNameNew[iCtx],
+ wcslen(apwszPerstNameNew[iCtx])+1);
+ _unlink(szPerstName);
+
+ // _pInput->Pause(IP_ITERPAUSE);
+ }
+ }
+
+ return S_OK;
+}
+
+
+
+SCODE COlePersistActivationTest::Report (CTestOutput &output)
+{
+ output.WriteSectionHeader (Name(),
+ L"CoGetPersistentInstance / CoNewPersistentInstance",
+ *m_pInput);
+
+ // for each clsctx, write the results
+ for (ULONG iCtx=0; iCtx<CNT_CLSCTX; iCtx++)
+ {
+ output.WriteString(L"\n");
+ output.WriteClassID (&m_ClsID[iCtx]);
+ output.WriteString (apwszClsCtx[iCtx]);
+ output.WriteString(L"\n");
+
+ output.WriteResults (L"CoGetPI", m_ulIterations, m_ulGetTime[iCtx]);
+ output.WriteResults (L"Release", m_ulIterations, m_ulGetReleaseTime[iCtx]);
+ output.WriteResults (L"CoNewPI", m_ulIterations, m_ulNewTime[iCtx]);
+ output.WriteResults (L"Release", m_ulIterations, m_ulNewReleaseTime[iCtx]);
+ }
+
+ return S_OK;
+}
diff --git a/private/oleutest/perform/cairole/tests/bm_piact.hxx b/private/oleutest/perform/cairole/tests/bm_piact.hxx
new file mode 100644
index 000000000..b42a42289
--- /dev/null
+++ b/private/oleutest/perform/cairole/tests/bm_piact.hxx
@@ -0,0 +1,42 @@
+//+------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1993.
+//
+// File: bm_piact.hxx
+//
+// Contents: test class definition
+//
+// Classes: COlePersistActivationTest
+//
+// Functions:
+//
+// History: 29-July-93 t-martig Created
+//
+//--------------------------------------------------------------------------
+
+#ifndef _BM_PIACT_HXX_
+#define _BM_PIACT_HXX_
+
+#include <bm_base.hxx>
+
+class COlePersistActivationTest : public CTestBase
+{
+public:
+ virtual WCHAR *Name ();
+ virtual SCODE Setup (CTestInput *input);
+ virtual SCODE Run ();
+ virtual SCODE Report (CTestOutput &OutputFile);
+ virtual SCODE Cleanup ();
+
+private:
+ CLSID m_ClsID[CNT_CLSCTX];
+
+ ULONG m_ulIterations;
+ ULONG m_ulGetTime[CNT_CLSCTX][TEST_MAX_ITERATIONS];
+ ULONG m_ulGetReleaseTime[CNT_CLSCTX][TEST_MAX_ITERATIONS];
+ ULONG m_ulNewTime[CNT_CLSCTX][TEST_MAX_ITERATIONS];
+ ULONG m_ulNewReleaseTime[CNT_CLSCTX][TEST_MAX_ITERATIONS];
+};
+
+#endif
diff --git a/private/oleutest/perform/cairole/tests/bm_props.cxx b/private/oleutest/perform/cairole/tests/bm_props.cxx
new file mode 100644
index 000000000..4e9d915cf
--- /dev/null
+++ b/private/oleutest/perform/cairole/tests/bm_props.cxx
@@ -0,0 +1,125 @@
+//+------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1993.
+//
+// File: bm_props.cxx
+//
+// Contents: Ole properties test
+//
+// Classes: COlePropertyTest
+//
+// History: 22-July-93 t-martig Created
+//
+//--------------------------------------------------------------------------
+#include <headers.cxx>
+#pragma hdrstop
+
+#include <bm_props.hxx>
+#include <oletest.hxx>
+
+
+DEFINE_OLEGUID(CLSID_TestProp, 0x20730722, 1, 8); // CT Test GUID
+
+
+TCHAR *COlePropertyTest::Name ()
+{
+ return TEXT("Properties");
+}
+
+
+SCODE COlePropertyTest::Setup (CTestInput *pInput)
+{
+ CTestBase::Setup(pInput);
+
+ SCODE sc = InitOLE();
+ if (FAILED(sc))
+ {
+ Log (TEXT("Setup - OleInitialize failed."), sc);
+ return sc;
+ }
+
+ m_ulIterations = 0;
+ return S_OK;
+}
+
+
+SCODE COlePropertyTest::Cleanup ()
+{
+ UninitOLE();
+ return S_OK;
+}
+
+
+
+SCODE COlePropertyTest::Run ()
+{
+/**** BUGBUG: these tests currently do nothing
+
+ CStopWatch sw;
+ IStorage *pIS;
+ IDispatch *pID;
+ COleTestClass unk;
+ VARIANTARG avararg[2];
+ DISPPARAMS dispparams = {avararg, NULL, 2, 0};
+ VARIANT varResult;
+ EXCEPINFO excepinfo;
+ UINT ierr;
+
+ // Create storage
+
+ if (FAILED(StgCreateDocfile (TEXT("C:\\DUMP.BM"), STGM_CREATE |
+ STGM_DELETEONRELEASE, 0, &pIS)))
+ return E_FAIL;
+
+ sw.Reset ();
+
+ if (FAILED(CoCreatePropSetStg (pIS, CLSID_TestProp, &unk, STGM_READWRITE |
+ STGM_SHARE_EXCLUSIVE, NULL, (IUnknown**)&pID)))
+ {
+ pIS->Release ();
+ return E_FAIL;
+ }
+ ulCreate = sw.Read ();
+
+ pID->QueryInterface (IID_IDispatch, (void**)&pID);
+
+ VariantInit(avararg + 1);
+ avararg[1].vt = VT_LPWSTR;
+ avararg[1].pwszVal = L"CairOLE";
+
+ VariantInit(avararg + 0);
+ avararg[0].vt = VT_LPWSTR;
+ avararg[0].pwszVal = L"TooSlow";
+
+ sw.Reset ();
+ if (FAILED(pID->Invoke(DISPID_ADDPROP, CLSID_TestProp, 0,
+ DISPATCH_METHOD, &dispparams, &varResult, &excepinfo, &ierr)))
+ {
+ pIS->Release ();
+ return E_FAIL;
+ }
+
+ ulAdd = sw.Read ();
+ pIS->Release ();
+****/
+ return S_OK;
+}
+
+
+
+SCODE COlePropertyTest::Report (CTestOutput &output)
+{
+ output.WriteSectionHeader (Name(), TEXT("Properties"), *m_pInput);
+/**** BUGBUG: disable
+ output.WriteResult (TEXT("Create property set"), ulCreate);
+ output.WriteResult (TEXT("Add property"), ulAdd);
+ output.WriteResult (TEXT("Set property"), ulSet);
+ output.WriteResult (TEXT("Get property"), ulGet);
+ output.WriteResult (TEXT("Delete property"), ulDelete);
+****/
+ return S_OK;
+}
+
+
+
diff --git a/private/oleutest/perform/cairole/tests/bm_props.hxx b/private/oleutest/perform/cairole/tests/bm_props.hxx
new file mode 100644
index 000000000..a107eb594
--- /dev/null
+++ b/private/oleutest/perform/cairole/tests/bm_props.hxx
@@ -0,0 +1,38 @@
+//+------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1993.
+//
+// File: bm_props.hxx
+//
+// Contents: test class definition
+//
+// Classes: COlePropertyTest
+//
+// Functions:
+//
+// History: 22-July-93 t-martig Created
+//
+//--------------------------------------------------------------------------
+
+#ifndef _BM_PROPS_HXX_
+#define _BM_PROPS_HXX_
+
+#include <bm_base.hxx>
+
+class COlePropertyTest : public CTestBase
+{
+public:
+ virtual TCHAR *Name ();
+ virtual SCODE Setup (CTestInput *input);
+ virtual SCODE Run ();
+ virtual SCODE Report (CTestOutput &OutputFile);
+ virtual SCODE Cleanup ();
+
+private:
+ CLSID m_ClsID[CNT_CLSCTX];
+
+ ULONG m_ulIterations;
+};
+
+#endif
diff --git a/private/oleutest/perform/cairole/tests/bm_qi.cxx b/private/oleutest/perform/cairole/tests/bm_qi.cxx
new file mode 100644
index 000000000..0730b6e53
--- /dev/null
+++ b/private/oleutest/perform/cairole/tests/bm_qi.cxx
@@ -0,0 +1,198 @@
+//+------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1993.
+//
+// File: bm_qi.cxx
+//
+// Contents: Ole QueryInterface test
+//
+// Classes: CQueryInterfaceTest
+//
+// History: 1-July-93 t-martig Created
+//
+//--------------------------------------------------------------------------
+#include <headers.cxx>
+#pragma hdrstop
+
+#include <bm_qi.hxx>
+
+
+// this is just an array of random interface iids. The qi server object
+// answers YES to any QI, although the only valid methods on each interface
+// are the methods of IUnknown.
+//
+// the code will answer NO to the following IIDs in order to prevent
+// custom marshalling problems...
+//
+// IID_IMarshal, IID_IStdMarshalInfo, IID_IStdIdentity,
+// IID_IPersist, IID_IProxyManager
+
+const IID *iid[] = {&IID_IAdviseSink, &IID_IDataObject,
+ &IID_IOleObject, &IID_IOleClientSite,
+ &IID_IParseDisplayName, &IID_IPersistStorage,
+ &IID_IPersistFile, &IID_IStorage,
+ &IID_IOleContainer, &IID_IOleItemContainer,
+ &IID_IOleInPlaceSite, &IID_IOleInPlaceActiveObject,
+ &IID_IOleInPlaceObject, &IID_IOleInPlaceUIWindow,
+ &IID_IOleInPlaceFrame, &IID_IOleWindow};
+
+
+
+TCHAR *CQueryInterfaceTest::Name ()
+{
+ return TEXT("QueryInterface");
+}
+
+
+SCODE CQueryInterfaceTest::Setup (CTestInput *pInput)
+{
+ SCODE sc;
+
+ CTestBase::Setup(pInput);
+
+ // get iteration count
+ m_ulIterations = pInput->GetIterations(Name());
+
+ // initialize state
+ for (ULONG iCtx=0; iCtx<CNT_CLSCTX; iCtx++)
+ {
+ sc = pInput->GetGUID(&m_ClsID[iCtx], Name(), apszClsIDName[iCtx]);
+ if (FAILED(sc))
+ {
+ Log (TEXT("Setup - GetClassID failed."), sc);
+ return sc;
+ }
+
+ INIT_RESULTS(m_ulQueryInterfaceSameTime[iCtx]);
+ INIT_RESULTS(m_ulPunkReleaseSameTime[iCtx]);
+ INIT_RESULTS(m_ulQueryInterfaceNewTime[iCtx]);
+ INIT_RESULTS(m_ulPunkReleaseNewTime[iCtx]);
+
+ _pUnk[iCtx] = NULL;
+ }
+
+ sc = InitCOM();
+ if (FAILED(sc))
+ {
+ Log (TEXT("Setup - CoInitialize failed."), sc);
+ return sc;
+ }
+
+ // create an instance of each qi server object
+ for (iCtx=0; iCtx<CNT_CLSCTX; iCtx++)
+ {
+ sc = CoCreateInstance(m_ClsID[iCtx], NULL, dwaClsCtx[iCtx],
+ IID_IUnknown, (void **)&_pUnk[iCtx]);
+
+ if (FAILED(sc))
+ {
+ Log (TEXT("Setup - CoCreateInstance failed"), sc);
+ }
+ }
+
+ return S_OK;
+}
+
+
+SCODE CQueryInterfaceTest::Cleanup ()
+{
+ for (ULONG iCtx=0; iCtx<CNT_CLSCTX; iCtx++)
+ {
+ if (_pUnk[iCtx])
+ {
+ _pUnk[iCtx]->Release();
+ }
+ }
+
+ UninitCOM();
+ return S_OK;
+}
+
+
+SCODE CQueryInterfaceTest::Run ()
+{
+ CStopWatch sw;
+ IUnknown *pUnk = NULL;
+
+
+ for (ULONG iCtx=0; iCtx<CNT_CLSCTX; iCtx++)
+ {
+ if (!_pUnk[iCtx])
+ continue;
+
+ // same interface each time, releasing after each query
+ for (ULONG iIter=0; iIter<m_ulIterations; iIter++)
+ {
+ sw.Reset ();
+ SCODE sc = _pUnk[iCtx]->QueryInterface(IID_IStorage, (void **)&pUnk);
+ m_ulQueryInterfaceSameTime[iCtx][iIter] = sw.Read ();
+ Log (TEXT("QueryInterface"), sc);
+
+ if (SUCCEEDED(sc))
+ {
+ sw.Reset();
+ pUnk->Release ();
+ m_ulPunkReleaseSameTime[iCtx][iIter] = sw.Read();
+ }
+ else
+ {
+ m_ulPunkReleaseSameTime[iCtx][iIter] = NOTAVAIL;
+ }
+ }
+
+ // different interface each time, releasing after each query
+ for (iIter=0; iIter<m_ulIterations; iIter++)
+ {
+ sw.Reset ();
+ SCODE sc = _pUnk[iCtx]->QueryInterface(*(iid[iIter]), (void **)&pUnk);
+ m_ulQueryInterfaceNewTime[iCtx][iIter] = sw.Read ();
+ Log (TEXT("QueryInterface"), sc);
+
+ if (SUCCEEDED(sc))
+ {
+ sw.Reset();
+ pUnk->Release ();
+ m_ulPunkReleaseNewTime[iCtx][iIter] = sw.Read();
+ }
+ else
+ {
+ m_ulPunkReleaseNewTime[iCtx][iIter] = NOTAVAIL;
+ }
+ }
+
+ }
+
+ return S_OK;
+}
+
+
+
+SCODE CQueryInterfaceTest::Report (CTestOutput &output)
+{
+ output.WriteSectionHeader (Name(), TEXT("QueryInterface"), *m_pInput);
+
+ for (ULONG iCtx=0; iCtx<CNT_CLSCTX; iCtx++)
+ {
+ output.WriteString(TEXT("\n"));
+ output.WriteClassID (&m_ClsID[iCtx]);
+ output.WriteString(apszClsCtx[iCtx]);
+ output.WriteString(TEXT("\n"));
+
+ output.WriteResults (TEXT("QuerySameInterface"), m_ulIterations,
+ m_ulQueryInterfaceSameTime[iCtx]);
+
+ output.WriteResults (TEXT("Release "), m_ulIterations,
+ m_ulPunkReleaseSameTime[iCtx]);
+
+ output.WriteResults (TEXT("QueryNewInterface "), m_ulIterations,
+ m_ulQueryInterfaceNewTime[iCtx]);
+
+ output.WriteResults (TEXT("Release "), m_ulIterations,
+ m_ulPunkReleaseNewTime[iCtx]);
+ }
+
+ return S_OK;
+}
+
+
diff --git a/private/oleutest/perform/cairole/tests/bm_qi.hxx b/private/oleutest/perform/cairole/tests/bm_qi.hxx
new file mode 100644
index 000000000..5084beeb7
--- /dev/null
+++ b/private/oleutest/perform/cairole/tests/bm_qi.hxx
@@ -0,0 +1,44 @@
+//+------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1993.
+//
+// File: bm_qi.hxx
+//
+// Contents: test class definition
+//
+// Classes: CQueryInterfaceTest
+//
+// Functions:
+//
+// History: 19-July-93 t-martig Created
+//
+//--------------------------------------------------------------------------
+
+#ifndef _BM_QI_HXX_
+#define _BM_QI_HXX_
+
+#include <bm_base.hxx>
+
+class CQueryInterfaceTest : public CTestBase
+{
+public:
+ virtual TCHAR *Name ();
+ virtual SCODE Setup (CTestInput *input);
+ virtual SCODE Run ();
+ virtual SCODE Report (CTestOutput &OutputFile);
+ virtual SCODE Cleanup ();
+
+private:
+ CLSID m_ClsID[CNT_CLSCTX];
+ IUnknown *_pUnk[CNT_CLSCTX];
+
+ ULONG m_ulIterations;
+ ULONG m_ulQueryInterfaceSameTime[CNT_CLSCTX][TEST_MAX_ITERATIONS];
+ ULONG m_ulPunkReleaseSameTime[CNT_CLSCTX][TEST_MAX_ITERATIONS];
+ ULONG m_ulQueryInterfaceNewTime[CNT_CLSCTX][TEST_MAX_ITERATIONS];
+ ULONG m_ulPunkReleaseNewTime[CNT_CLSCTX][TEST_MAX_ITERATIONS];
+
+};
+
+#endif
diff --git a/private/oleutest/perform/cairole/tests/bm_regis.cxx b/private/oleutest/perform/cairole/tests/bm_regis.cxx
new file mode 100644
index 000000000..c177f4904
--- /dev/null
+++ b/private/oleutest/perform/cairole/tests/bm_regis.cxx
@@ -0,0 +1,175 @@
+//+------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1993.
+//
+// File: bm_regis.cxx
+//
+// Contents: Ole object registration test
+//
+// Classes: COleRegistrationTest
+//
+// History: 12-July-93 t-martig Created
+//
+//--------------------------------------------------------------------------
+#include <headers.cxx>
+#pragma hdrstop
+
+#include <bm_regis.hxx>
+#include <oletest.hxx>
+
+extern COleTestClassFactory theFactory;
+
+
+const CLSID *apClsid[] = {&CLSID_COleTestClass1,
+ &CLSID_COleTestClass2,
+ &CLSID_COleTestClass3,
+ &CLSID_COleTestClass4,
+ &CLSID_COleTestClass5,
+ &CLSID_COleTestClass6,
+ &CLSID_COleTestClass7,
+ &CLSID_COleTestClass8};
+
+
+TCHAR *COleRegistrationTest::Name ()
+{
+ return TEXT("ObjRegistration");
+}
+
+
+SCODE COleRegistrationTest::Setup (CTestInput *pInput)
+{
+ HRESULT sc;
+
+ CTestBase::Setup(pInput);
+
+ // get the iteration count
+ m_ulIterations = pInput->GetIterations(Name());
+
+ // for the inproc case. load a class factory object to register.
+ // this is temporary to fix a problem (ambiguity) in inproc
+ // registration.
+
+ sc = pInput->GetGUID(&m_Clsid[0], Name(), apszClsIDName[0]);
+ if (FAILED(sc))
+ {
+ Log (TEXT("Setup - GetClassID failed."), sc);
+ return sc;
+ }
+
+ sc = pInput->GetGUID(&m_Clsid[1], Name(), apszClsIDName[1]);
+ if (FAILED(sc))
+ {
+ Log (TEXT("Setup - GetClassID failed."), sc);
+ return sc;
+ }
+
+ sc = InitCOM();
+ if (FAILED(sc))
+ {
+ Log (TEXT("Setup - CoInitialize failed."), sc);
+ return sc;
+ }
+
+ // get the class factory
+ sc = CoGetClassObject(m_Clsid[0], dwaClsCtx[0], NULL,
+ IID_IClassFactory, (void **)&m_apICF[0]);
+ if (FAILED(sc))
+ {
+ Log (TEXT("Setup - CoGetClassObject failed."), sc);
+ return sc;
+ }
+
+
+ // for local server, register an internal class.
+ m_apICF[1] = (IClassFactory *)&theFactory;
+
+ // init internal state
+ for (ULONG iCtx=0; iCtx<CNT_CLSCTX; iCtx++)
+ {
+ INIT_RESULTS(m_ulRegisterCtx[iCtx]);
+ INIT_RESULTS(m_ulRevokeCtx[iCtx]);
+ }
+
+ // _pInput = pInput;
+ return S_OK;
+}
+
+
+SCODE COleRegistrationTest::Cleanup ()
+{
+ m_apICF[0]->Release();
+
+ UninitCOM();
+
+ return S_OK;
+}
+
+SCODE COleRegistrationTest::Run ()
+{
+ CStopWatch sw;
+ DWORD dwReg;
+
+ for (ULONG iCtx=0; iCtx<CNT_CLSCTX; iCtx++)
+ {
+ for (ULONG iIter=0; iIter<m_ulIterations; iIter++)
+ {
+ sw.Reset ();
+ SCODE sc = CoRegisterClassObject(m_Clsid[iCtx],
+ m_apICF[iCtx],
+ dwaClsCtx[iCtx],
+ REGCLS_MULTIPLEUSE, &dwReg);
+ m_ulRegisterCtx[iCtx][iIter] = sw.Read ();
+ Log (TEXT("CoRegisterClassObject"),sc);
+
+ // NOTE: Revoke has different behaviour depending on
+ // whether single use or multiuse is specified in the
+ // registration.
+
+ if (SUCCEEDED(sc))
+ {
+ // Revoke
+ sw.Reset ();
+ sc = CoRevokeClassObject(dwReg);
+ m_ulRevokeCtx[iCtx][iIter] = sw.Read();
+ if (Log (TEXT("CoRevokeClassObject"), sc))
+ m_ulRevokeCtx[iCtx][iIter] = NOTAVAIL;
+ }
+ else
+ {
+ m_ulRegisterCtx[iCtx][iIter] = NOTAVAIL;
+ }
+
+ // _pInput->Pause(IP_ITERPAUSE);
+ }
+ }
+
+ return S_OK;
+}
+
+
+
+SCODE COleRegistrationTest::Report (CTestOutput &output)
+{
+ output.WriteSectionHeader (Name(),
+ TEXT("CoRegisterClassObject / CoRevokeClassObject"), *m_pInput);
+
+ for (ULONG iCtx=0; iCtx<CNT_CLSCTX; iCtx++)
+ {
+ output.WriteString (TEXT("\n"));
+ output.WriteClassID(&m_Clsid[iCtx]);
+ output.WriteString (apszClsCtx[iCtx]);
+ output.WriteString (TEXT("\n"));
+
+ output.WriteResults (TEXT("Register"), m_ulIterations,
+ m_ulRegisterCtx[iCtx]);
+
+ output.WriteResults (TEXT("Revoke "), m_ulIterations,
+ m_ulRevokeCtx[iCtx]);
+ }
+
+ return S_OK;
+}
+
+
+
diff --git a/private/oleutest/perform/cairole/tests/bm_regis.hxx b/private/oleutest/perform/cairole/tests/bm_regis.hxx
new file mode 100644
index 000000000..949dfea0a
--- /dev/null
+++ b/private/oleutest/perform/cairole/tests/bm_regis.hxx
@@ -0,0 +1,41 @@
+//+------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1993.
+//
+// File: bm_regis.hxx
+//
+// Contents: test class definition
+//
+// Classes: COleRegistrationTest
+//
+// Functions:
+//
+// History: 19-July-93 t-martig Created
+//
+//--------------------------------------------------------------------------
+
+#ifndef _BM_REGIS_HXX_
+#define _BM_REGIS_HXX_
+
+#include <bm_base.hxx>
+
+class COleRegistrationTest : public CTestBase
+{
+public:
+ virtual TCHAR *Name ();
+ virtual SCODE Setup (CTestInput *input);
+ virtual SCODE Run ();
+ virtual SCODE Report (CTestOutput &OutputFile);
+ virtual SCODE Cleanup ();
+
+private:
+ ULONG m_ulIterations;
+ CLSID m_Clsid[CNT_CLSCTX];
+ IClassFactory *m_apICF[CNT_CLSCTX];
+
+ ULONG m_ulRegisterCtx[CNT_CLSCTX][TEST_MAX_ITERATIONS];
+ ULONG m_ulRevokeCtx[CNT_CLSCTX][TEST_MAX_ITERATIONS];
+};
+
+#endif
diff --git a/private/oleutest/perform/cairole/tests/bm_rot.cxx b/private/oleutest/perform/cairole/tests/bm_rot.cxx
new file mode 100644
index 000000000..2b7f17d78
--- /dev/null
+++ b/private/oleutest/perform/cairole/tests/bm_rot.cxx
@@ -0,0 +1,366 @@
+//+------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1993.
+//
+// File: bm_rot.cxx
+//
+// Contents: Ole running object table test (ROT)
+//
+// Classes: CROTTest
+//
+// History: 9-July-93 t-martig Created
+//
+//--------------------------------------------------------------------------
+#include <headers.cxx>
+#pragma hdrstop
+
+#include <bm_rot.hxx>
+#include <cact.hxx> // CTestAct
+
+
+// function used by CTestAct. need not do anything for our usage.
+void GlobalRefs(BOOL fAdd)
+{
+}
+
+
+TCHAR *CROTTest::Name ()
+{
+ return TEXT("ROT");
+}
+
+
+SCODE CROTTest::Setup (CTestInput *pInput)
+{
+ IClassFactory *pICF = NULL;
+ IPersistFile *pIPF = NULL;
+ SCODE sc = S_OK, scRet = S_OK;
+
+
+ CTestBase::Setup(pInput);
+
+ // get the iteration count from the ini file
+ m_ulIterations = pInput->GetIterations(Name());
+ m_ulEntries = 1;
+
+ // for each class ctx, get the classid, and init internal state
+ for (ULONG iCtx=0; iCtx<CNT_CLSCTX; iCtx++)
+ {
+ // Get ClsID for this Ctx from the .ini file
+ sc = pInput->GetGUID(&m_ClsID[iCtx], Name(), apszClsIDName[iCtx]);
+ if (FAILED(sc))
+ {
+ Log (TEXT("Setup - GetClassID failed."), sc);
+ return sc;
+ }
+
+ INIT_RESULTS(m_ulGetROTTime[iCtx]);
+ INIT_RESULTS(m_ulReleaseTime[iCtx]);
+ INIT_RESULTS(m_ulRegisterTime[iCtx]);
+ INIT_RESULTS(m_ulRevokeTime[iCtx]);
+ INIT_RESULTS(m_ulNoteChangeTime[iCtx]);
+ INIT_RESULTS(m_ulGetChangeTime[iCtx]);
+ INIT_RESULTS(m_ulIsRunningTime[iCtx]);
+ INIT_RESULTS(m_ulGetObjectTime[iCtx]);
+ INIT_RESULTS(m_ulEnumRunningTime[iCtx]);
+ }
+
+
+ sc = InitCOM();
+ if (FAILED(sc))
+ {
+ Log (TEXT("Setup - CoInitialize failed."), sc);
+ return sc;
+ }
+
+
+ // for each class ctx, create a persistent instance on disk
+ for (iCtx=0; iCtx<CNT_CLSCTX; iCtx++)
+ {
+ m_punkObj[iCtx] = NULL;
+ m_pmkObj[iCtx] = NULL;
+
+ if (dwaClsCtx[iCtx] == CLSCTX_INPROC_SERVER)
+ {
+ // create an inprocess instance
+ m_punkObj[iCtx] = (IPersistFile *) new CTestAct(m_ClsID[iCtx]);
+ sc = (m_punkObj[iCtx] != NULL) ? S_OK : E_OUTOFMEMORY;
+ }
+ else
+ {
+ // Create an instance
+ sc = CoCreateInstance(m_ClsID[iCtx], NULL, dwaClsCtx[iCtx],
+ IID_IUnknown, (void **)&m_punkObj[iCtx]);
+ }
+
+ if (SUCCEEDED(sc))
+ {
+ // Create a moniker
+ sc = CreateFileMoniker(apszPerstName[iCtx], &m_pmkObj[iCtx]);
+
+ if (SUCCEEDED(sc))
+ {
+ // get the IPersistFile interface
+ IPersistFile *pIPF = NULL;
+
+ sc = m_punkObj[iCtx]->QueryInterface(IID_IPersistFile,
+ (void **)&pIPF);
+
+ if (SUCCEEDED(sc))
+ {
+ // save the class instance in the file.
+ // NOTE: we assume the server's implementation of
+ // this method does not do any ROT operations. We
+ // know this to be true of CTestAct.
+
+ sc = pIPF->Save(apszPerstName[iCtx], FALSE);
+ pIPF->Release();
+
+ if (FAILED(sc))
+ {
+ Log (TEXT("Setup - pIPF->Save failed."), sc);
+ scRet = sc;
+ }
+ }
+ else
+ {
+ Log (TEXT("Setup - QueryInterface failed"), sc);
+ scRet = sc;
+ }
+ }
+ else
+ {
+ Log (TEXT("Setup - CreateFileMoniker failed"), sc);
+ scRet = sc;
+ }
+ }
+ else
+ {
+ Log (TEXT("Setup - CreateInstance failed"), sc);
+ scRet = sc;
+ }
+ }
+
+ if (FAILED(scRet))
+ {
+ Cleanup();
+ }
+
+ return scRet;
+}
+
+
+SCODE CROTTest::Cleanup ()
+{
+ CHAR szPerstName[80];
+
+ // delete the persistent instances
+ for (ULONG iCtx=0; iCtx<CNT_CLSCTX; iCtx++)
+ {
+ // delete files
+ wcstombs(szPerstName, apszPerstName[iCtx],
+ wcslen(apszPerstName[iCtx])+1);
+ _unlink (szPerstName);
+
+ if (m_punkObj[iCtx])
+ m_punkObj[iCtx]->Release();
+
+ if (m_pmkObj[iCtx])
+ m_pmkObj[iCtx]->Release();
+ }
+
+
+ UninitCOM();
+ return S_OK;
+}
+
+
+SCODE CROTTest::Run ()
+{
+ IRunningObjectTable *pROT = NULL;
+ CStopWatch sw;
+ SCODE sc;
+
+
+ // do the server side ROT operations.
+ // this makes sense only for inprocess objects.
+
+ ULONG iCtx=0;
+ {
+ // for each iteration
+ for (ULONG iIter=0; iIter<m_ulIterations; iIter++)
+ {
+ sw.Reset();
+ sc = GetRunningObjectTable(NULL, &pROT);
+ m_ulGetROTTime[iCtx][iIter] = sw.Read();
+ if (Log (TEXT("GetRunningObjectTable"), sc))
+ {
+ m_ulGetROTTime[iCtx][iIter] = NOTAVAIL;
+ }
+
+ DWORD dwRegister = 0;
+
+ sw.Reset();
+ sc = pROT->Register(0, m_punkObj[iCtx], m_pmkObj[iCtx], &dwRegister);
+ m_ulRegisterTime[iCtx][iIter] = sw.Read();
+ if (Log (TEXT("pROT->Register"), sc))
+ {
+ m_ulRegisterTime[iCtx][iIter] = NOTAVAIL;
+ }
+
+
+ FILETIME ft;
+ SYSTEMTIME st;
+
+ GetSystemTime(&st);
+ SystemTimeToFileTime(&st, &ft);
+
+ sw.Reset();
+ sc = pROT->NoteChangeTime(dwRegister, &ft);
+ m_ulNoteChangeTime[iCtx][iIter]=sw.Read ();
+ if (Log (TEXT("pROT->NoteChangeTime"), sc))
+ {
+ m_ulNoteChangeTime[iCtx][iIter] = NOTAVAIL;
+ }
+
+
+ sw.Reset();
+ sc = pROT->Revoke(dwRegister);
+ m_ulRevokeTime[iCtx][iIter] = sw.Read();
+ if (Log (TEXT("pROT->Revoke"), sc))
+ {
+ m_ulRevokeTime[iCtx][iIter] = NOTAVAIL;
+ }
+
+
+ sw.Reset();
+ pROT->Release();
+ m_ulReleaseTime[iCtx][iIter]=sw.Read ();
+ pROT = NULL;
+ if (Log (TEXT("pROT->Release"), sc))
+ {
+ m_ulReleaseTime[iCtx][iIter] = NOTAVAIL;
+ }
+ }
+ }
+
+
+ // do the client side ROT operations
+ // this makes sense for both class contexts
+
+ pROT = NULL;
+ sc = GetRunningObjectTable(NULL, &pROT);
+ if (Log (TEXT("GetRunningObjectTable"), sc))
+ {
+ return sc;
+ }
+
+
+ for (iCtx=0; iCtx<CNT_CLSCTX; iCtx++)
+ {
+ // put the object into the loaded state. this will cause it to
+ // register itself in the ROT.
+ IPersistFile *pIPF = NULL;
+
+ sc = m_punkObj[iCtx]->QueryInterface(IID_IPersistFile, (void **)&pIPF);
+ if (SUCCEEDED(sc))
+ {
+ pIPF->Load(apszPerstName[iCtx], STGM_READ | STGM_SHARE_DENY_NONE);
+ pIPF->Release();
+ }
+
+ // for each iteration
+ for (ULONG iIter=0; iIter<m_ulIterations; iIter++)
+ {
+ IEnumMoniker *pEnumMk = NULL;
+
+ sw.Reset();
+ sc = pROT->EnumRunning(&pEnumMk);
+ m_ulEnumRunningTime[iCtx][iIter] = sw.Read();
+ if (Log (TEXT("pROT->EnumRunning"), sc))
+ {
+ m_ulEnumRunningTime[iCtx][iIter] = NOTAVAIL;
+ }
+
+ if (pEnumMk)
+ {
+ pEnumMk->Release();
+ }
+
+
+ sw.Reset();
+ sc = pROT->IsRunning(m_pmkObj[iCtx]);
+ m_ulIsRunningTime[iCtx][iIter] = sw.Read();
+ if (Log (TEXT("pROT->IsRunning"), sc))
+ {
+ m_ulIsRunningTime[iCtx][iIter] = NOTAVAIL;
+ }
+
+
+ FILETIME ft;
+
+ sw.Reset();
+ sc = pROT->GetTimeOfLastChange(m_pmkObj[iCtx], &ft);
+ m_ulGetChangeTime[iCtx][iIter]=sw.Read ();
+ if (Log (TEXT("pROT->GetTimeOfLastChange"), sc))
+ {
+ m_ulGetChangeTime[iCtx][iIter] = NOTAVAIL;
+ }
+
+
+ IUnknown *pUnk = NULL;
+
+ sw.Reset();
+ sc = pROT->GetObject(m_pmkObj[iCtx], &pUnk);
+ m_ulGetObjectTime[iCtx][iIter]=sw.Read ();
+ if (Log (TEXT("pROT->GetObject"), sc))
+ {
+ m_ulGetObjectTime[iCtx][iIter] = NOTAVAIL;
+ }
+
+ if (pUnk)
+ {
+ pUnk->Release();
+ }
+ }
+ }
+
+ return S_OK;
+}
+
+
+
+SCODE CROTTest::Report (CTestOutput &output)
+{
+ output.WriteSectionHeader (Name(), TEXT("RunningObjectTable"), *m_pInput);
+
+ // write out the server side results
+ ULONG iCtx=0;
+ output.WriteString(TEXT("\nServer Side\n\n"));
+ output.WriteResults(TEXT("GetRunningObjTbl"), m_ulIterations, m_ulGetROTTime[iCtx]);
+ output.WriteResults(TEXT("Register "), m_ulIterations, m_ulRegisterTime[iCtx]);
+ output.WriteResults(TEXT("NoteChangeTime "), m_ulIterations, m_ulNoteChangeTime[iCtx]);
+ output.WriteResults(TEXT("Revoke "), m_ulIterations, m_ulRevokeTime[iCtx]);
+ output.WriteResults(TEXT("pROT->Release "), m_ulIterations, m_ulReleaseTime[iCtx]);
+
+
+ // write out the client side results
+ output.WriteString(TEXT("\nClient Side\n"));
+
+ // for each clsctx, write the results
+ for (iCtx=0; iCtx<CNT_CLSCTX; iCtx++)
+ {
+ output.WriteString(TEXT("\n"));
+ output.WriteClassID(&m_ClsID[iCtx]);
+ output.WriteString(apszClsCtx[iCtx]);
+ output.WriteString(TEXT("\n"));
+
+ output.WriteResults(TEXT("EnumRunning "), m_ulIterations, m_ulEnumRunningTime[iCtx]);
+ output.WriteResults(TEXT("IsRunning "), m_ulIterations, m_ulIsRunningTime[iCtx]);
+ output.WriteResults(TEXT("GetChangeTime "), m_ulIterations, m_ulGetChangeTime[iCtx]);
+ output.WriteResults(TEXT("GetObject "), m_ulIterations, m_ulGetObjectTime[iCtx]);
+ }
+
+ return S_OK;
+}
diff --git a/private/oleutest/perform/cairole/tests/bm_rot.hxx b/private/oleutest/perform/cairole/tests/bm_rot.hxx
new file mode 100644
index 000000000..98ec92d77
--- /dev/null
+++ b/private/oleutest/perform/cairole/tests/bm_rot.hxx
@@ -0,0 +1,55 @@
+//+------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1993.
+//
+// File: bm_rot.hxx
+//
+// Contents: test class definition
+//
+// Classes: CROTTest
+//
+// Functions:
+//
+// History: 19-July-93 t-martig Created
+//
+//--------------------------------------------------------------------------
+
+#ifndef _BM_ROT_HXX_
+#define _BM_ROT_HXX_
+
+#include <bm_base.hxx>
+
+class CROTTest : public CTestBase
+{
+public:
+ virtual TCHAR *Name ();
+ virtual SCODE Setup (CTestInput *input);
+ virtual SCODE Run ();
+ virtual SCODE Report (CTestOutput &OutputFile);
+ virtual SCODE Cleanup ();
+
+private:
+ CLSID m_ClsID[CNT_CLSCTX];
+ IUnknown *m_punkObj[CNT_CLSCTX];
+ IMoniker *m_pmkObj[CNT_CLSCTX];
+
+
+ ULONG m_ulIterations; // # times to repeat the test
+ ULONG m_ulEntries; // entries to put in the table
+
+ ULONG m_ulGetROTTime[CNT_CLSCTX][TEST_MAX_ITERATIONS];
+ ULONG m_ulReleaseTime[CNT_CLSCTX][TEST_MAX_ITERATIONS];
+
+ ULONG m_ulRegisterTime[CNT_CLSCTX][TEST_MAX_ITERATIONS];
+ ULONG m_ulRevokeTime[CNT_CLSCTX][TEST_MAX_ITERATIONS];
+
+ ULONG m_ulNoteChangeTime[CNT_CLSCTX][TEST_MAX_ITERATIONS];
+ ULONG m_ulGetChangeTime[CNT_CLSCTX][TEST_MAX_ITERATIONS];
+
+ ULONG m_ulIsRunningTime[CNT_CLSCTX][TEST_MAX_ITERATIONS];
+ ULONG m_ulEnumRunningTime[CNT_CLSCTX][TEST_MAX_ITERATIONS];
+ ULONG m_ulGetObjectTime[CNT_CLSCTX][TEST_MAX_ITERATIONS];
+};
+
+#endif // _BM_ROT_HXX_
diff --git a/private/oleutest/perform/cairole/tests/bm_rpc.cxx b/private/oleutest/perform/cairole/tests/bm_rpc.cxx
new file mode 100644
index 000000000..ab7f9f8c8
--- /dev/null
+++ b/private/oleutest/perform/cairole/tests/bm_rpc.cxx
@@ -0,0 +1,427 @@
+//+------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1993.
+//
+// File: bm_rpc.cxx
+//
+// Contents: Rpc Method Invocation tests
+//
+// Classes: CRpcTest
+//
+// History: 1-July-93 t-martig Created
+//
+//--------------------------------------------------------------------------
+#include <headers.cxx>
+#pragma hdrstop
+
+#include <bm_rpc.hxx>
+#include <oletest.hxx>
+#include <tracelog.hxx>
+
+
+TCHAR *CRpcTest::Name ()
+{
+ return TEXT("RpcTest");
+}
+
+
+SCODE CRpcTest::Setup (CTestInput *pInput)
+{
+ CTestBase::Setup(pInput);
+
+ SCODE sc = pInput->GetGUID(&m_ClsID, Name(), TEXT("Clsid_Local"));
+ if (FAILED(sc))
+ {
+ Log (TEXT("Setup - GetClassID failed."), sc);
+ return sc;
+ }
+
+ // get flag indicating whether to keep all values or
+ // only average values.
+ TCHAR szAverage[5];
+ pInput->GetConfigString(Name(), TEXT("Average"), TEXT("Y"),
+ szAverage, sizeof(szAverage)/sizeof(TCHAR));
+ if (szAverage[0] == 'n' || szAverage[0] == 'N')
+ m_fAverage = FALSE;
+ else
+ m_fAverage = TRUE;
+
+ // get iteration count
+ if (m_fAverage)
+ m_ulIterations = pInput->GetRealIterations(Name());
+ else
+ m_ulIterations = pInput->GetIterations(Name());
+
+ // initialize timing arrays
+ INIT_RESULTS(m_ulVoidTime);
+ INIT_RESULTS(m_ulVoidRCTime);
+
+ INIT_RESULTS(m_ulDwordInTime);
+ INIT_RESULTS(m_ulDwordOutTime);
+ INIT_RESULTS(m_ulDwordInOutTime);
+
+ INIT_RESULTS(m_ulStringInTime);
+ INIT_RESULTS(m_ulStringOutTime);
+ INIT_RESULTS(m_ulStringInOutTime);
+
+ INIT_RESULTS(m_ulGuidInTime);
+ INIT_RESULTS(m_ulGuidOutTime);
+
+ INIT_RESULTS(m_ulIUnknownInprocInTime);
+ INIT_RESULTS(m_ulIUnknownInprocOutTime);
+ INIT_RESULTS(m_ulIUnknownLocalInTime);
+ INIT_RESULTS(m_ulIUnknownLocalOutTime);
+
+ INIT_RESULTS(m_ulIUnknownKeepInTime);
+ INIT_RESULTS(m_ulIUnknownKeepOutTime);
+
+ INIT_RESULTS(m_ulInterfaceInprocInTime);
+ INIT_RESULTS(m_ulInterfaceLocalInTime);
+
+
+ sc = InitCOM();
+ if (FAILED(sc))
+ {
+ Log (TEXT("Setup - CoInitialize failed."), sc);
+ return sc;
+ }
+
+ m_pRPC=NULL;
+ sc = CoCreateInstance(m_ClsID, NULL, CLSCTX_LOCAL_SERVER,
+ IID_IRpcTest, (void **)&m_pRPC);
+ if (FAILED(sc))
+ {
+ Log (TEXT("Setup - CoCreateInstance IRpcTest failed."), sc);
+ return sc;
+ }
+
+
+ // get the inprocess object for the IUnknown marshalling test
+ sc = pInput->GetGUID(&m_ClsID, Name(), TEXT("Clsid_Inproc"));
+ if (FAILED(sc))
+ {
+ Log (TEXT("Setup - GetClassID Inproc failed."), sc);
+ return sc;
+ }
+
+ m_punkInproc = NULL;
+ sc = CoCreateInstance(m_ClsID, NULL, CLSCTX_INPROC_SERVER,
+ IID_IUnknown, (void **)&m_punkInproc);
+ if (FAILED(sc))
+ {
+ Log (TEXT("Setup - CoCreateInstance IUnknown Inproc failed."), sc);
+ return sc;
+ }
+
+
+ // get the out of process object for the IUnknown marshalling test
+
+ m_punkLocal = NULL;
+ sc = CoCreateInstance(m_ClsID, NULL, CLSCTX_LOCAL_SERVER,
+ IID_IUnknown, (void **)&m_punkLocal);
+ if (FAILED(sc))
+ {
+ Log (TEXT("Setup - CoCreateInstance IUnknown LocalSrv failed."), sc);
+ return sc;
+ }
+
+ return S_OK;
+}
+
+
+SCODE CRpcTest::Cleanup ()
+{
+ if (m_pRPC)
+ m_pRPC->Release();
+
+ if (m_punkInproc)
+ m_punkInproc->Release();
+
+ if (m_punkLocal)
+ m_punkLocal->Release();
+
+ UninitCOM();
+ return S_OK;
+}
+
+
+SCODE CRpcTest::Run ()
+{
+ CStopWatch sw;
+ SCODE sc;
+ ULONG iIter;
+
+ //
+ // void passing tests
+ //
+
+ // STARTTRACE("CRpcTest");
+
+ ResetAverage( m_fAverage, sw );
+ for (iIter=0; iIter<m_ulIterations; iIter++)
+ {
+ // TRACECALL(TRACE_APP, "m_pRPC->Void()");
+
+ ResetNotAverage( m_fAverage, sw );
+ m_pRPC->Void();
+ ReadNotAverage( m_fAverage, sw, m_ulVoidTime[iIter] );
+ }
+ ReadAverage( m_fAverage, sw, m_ulVoidTime[0], m_ulIterations );
+
+ // STOPTRACE("CRpcTest");
+
+
+ ResetAverage( m_fAverage, sw );
+ for (iIter=0; iIter<m_ulIterations; iIter++)
+ {
+ // TRACECALL(TRACE_APP, "m_pRPC->VoidRC()");
+
+ ResetNotAverage( m_fAverage, sw );
+ sc = m_pRPC->VoidRC();
+ ReadNotAverage( m_fAverage, sw, m_ulVoidRCTime[iIter] );
+ }
+ ReadAverage( m_fAverage, sw, m_ulVoidRCTime[0], m_ulIterations );
+
+ //
+ // dword passing tests
+ //
+
+ DWORD dwTmp = 1;
+ ResetAverage( m_fAverage, sw );
+ for (iIter=0; iIter<m_ulIterations; iIter++)
+ {
+ ResetNotAverage( m_fAverage, sw );
+ sc = m_pRPC->DwordIn(dwTmp);
+ ReadNotAverage( m_fAverage, sw, m_ulDwordInTime[iIter] );
+ }
+ ReadAverage( m_fAverage, sw, m_ulDwordInTime[0], m_ulIterations );
+
+ ResetAverage( m_fAverage, sw );
+ for (iIter=0; iIter<m_ulIterations; iIter++)
+ {
+ ResetNotAverage( m_fAverage, sw );
+ sc = m_pRPC->DwordOut(&dwTmp);
+ ReadNotAverage( m_fAverage, sw, m_ulDwordOutTime[iIter] );
+ }
+ ReadAverage( m_fAverage, sw, m_ulDwordOutTime[0], m_ulIterations );
+
+ ResetAverage( m_fAverage, sw );
+ for (iIter=0; iIter<m_ulIterations; iIter++)
+ {
+ ResetNotAverage( m_fAverage, sw );
+ sc = m_pRPC->DwordInOut(&dwTmp);
+ ReadNotAverage( m_fAverage, sw, m_ulDwordInOutTime[iIter] );
+ }
+ ReadAverage( m_fAverage, sw, m_ulDwordInOutTime[0], m_ulIterations );
+
+ //
+ // string passing tests
+ //
+
+ OLECHAR wszHello[] = L"C:\\FOOFOO\\FOOBAR\\FOOBAK\\FOOBAZ\\FOOTYPICAL\\PATH\\HELLO";
+ ResetAverage( m_fAverage, sw );
+ for (iIter=0; iIter<m_ulIterations; iIter++)
+ {
+ ResetNotAverage( m_fAverage, sw );
+ sc = m_pRPC->StringIn(wszHello);
+ ReadNotAverage( m_fAverage, sw, m_ulStringInTime[iIter] );
+ }
+ ReadAverage( m_fAverage, sw, m_ulStringInTime[0], m_ulIterations );
+
+ LPOLESTR pwszOut = NULL;
+#ifdef STRINGOUT
+ ResetAverage( m_fAverage, sw );
+ for (iIter=0; iIter<m_ulIterations; iIter++)
+ {
+ pwszOut = NULL;
+ ResetNotAverage( m_fAverage, sw );
+ sc = m_pRPC->StringOut(&pwszOut);
+ ReadNotAverage( m_fAverage, sw, m_ulStringOutTime[iIter] );
+ }
+ ReadAverage( m_fAverage, sw, m_ulStringOutTime[0], m_ulIterations );
+#endif
+ pwszOut = wszHello;
+ ResetAverage( m_fAverage, sw );
+ for (iIter=0; iIter<m_ulIterations; iIter++)
+ {
+ ResetNotAverage( m_fAverage, sw );
+ sc = m_pRPC->StringInOut(pwszOut);
+ ReadNotAverage( m_fAverage, sw, m_ulStringInOutTime[iIter] );
+ }
+ ReadAverage( m_fAverage, sw, m_ulStringInOutTime[0], m_ulIterations );
+
+ //
+ // guid passing tests
+ //
+
+ ResetAverage( m_fAverage, sw );
+ for (iIter=0; iIter<m_ulIterations; iIter++)
+ {
+ ResetNotAverage( m_fAverage, sw );
+ sc = m_pRPC->GuidIn(IID_IRpcTest);
+ ReadNotAverage( m_fAverage, sw, m_ulGuidInTime[iIter] );
+ }
+ ReadAverage( m_fAverage, sw, m_ulGuidInTime[0], m_ulIterations );
+
+ GUID guid;
+ ResetAverage( m_fAverage, sw );
+ for (iIter=0; iIter<m_ulIterations; iIter++)
+ {
+ ResetNotAverage( m_fAverage, sw );
+ sc = m_pRPC->GuidOut(&guid);
+ ReadNotAverage( m_fAverage, sw, m_ulGuidOutTime[iIter] );
+ }
+ ReadAverage( m_fAverage, sw, m_ulGuidOutTime[0], m_ulIterations );
+
+
+ //
+ // IUnknown passing tests
+ //
+
+ ResetAverage( m_fAverage, sw );
+ for (iIter=0; iIter<m_ulIterations; iIter++)
+ {
+ ResetNotAverage( m_fAverage, sw );
+ sc = m_pRPC->IUnknownIn(m_punkInproc);
+ ReadNotAverage( m_fAverage, sw, m_ulIUnknownInprocInTime[iIter] );
+ }
+ ReadAverage( m_fAverage, sw, m_ulIUnknownInprocInTime[0], m_ulIterations );
+
+ ResetAverage( m_fAverage, sw );
+ for (iIter=0; iIter<m_ulIterations; iIter++)
+ {
+ ResetNotAverage( m_fAverage, sw );
+ sc = m_pRPC->IUnknownIn(m_punkLocal);
+ ReadNotAverage( m_fAverage, sw, m_ulIUnknownLocalInTime[iIter] );
+ }
+ ReadAverage( m_fAverage, sw, m_ulIUnknownLocalInTime[0], m_ulIterations );
+
+ IUnknown *punk = NULL;
+ ResetAverage( m_fAverage, sw );
+ for (iIter=0; iIter<m_ulIterations; iIter++)
+ {
+ ResetNotAverage( m_fAverage, sw );
+ sc = m_pRPC->IUnknownOut(&punk);
+ punk->Release();
+ punk = NULL;
+ ReadNotAverage( m_fAverage, sw, m_ulIUnknownInprocOutTime[iIter] );
+ }
+ ReadAverage( m_fAverage, sw, m_ulIUnknownInprocOutTime[0], m_ulIterations );
+
+ //
+ // interface passing tests
+ //
+
+#ifdef NOTYET
+
+ IStream *pIStm = NULL;
+ sc = m_punkInproc->QueryInterface(IID_IStream, (void **)&pIStm);
+ if (SUCCEEDED(sc) && pIStm)
+ {
+ ResetAverage( m_fAverage, sw );
+ for (iIter=0; iIter<m_ulIterations; iIter++)
+ {
+ ResetNotAverage( m_fAverage, sw );
+ sc = m_pRPC->InterfaceIn(IID_IStream, pIStm);
+ ReadNotAverage( m_fAverage, sw, m_ulInterfaceInprocInTime[iIter] );
+ }
+ ReadAverage( m_fAverage, sw, m_ulInterfaceInprocInTime[0], m_ulIterations );
+ pIStm->Release();
+ }
+
+ pIStm = NULL;
+ sc = m_punkLocal->QueryInterface(IID_IStream, (void **)&pIStm);
+ if (SUCCEEDED(sc) && pIStm)
+ {
+ ResetAverage( m_fAverage, sw );
+ for (iIter=0; iIter<m_ulIterations; iIter++)
+ {
+ ResetNotAverage( m_fAverage, sw );
+ sc = m_pRPC->InterfaceIn(IID_IStream, pIStm);
+ ReadNotAverage( m_fAverage, sw, m_ulInterfaceLocalInTime[iIter] );
+ }
+ ReadAverage( m_fAverage, sw, m_ulInterfaceLocalInTime[0], m_ulIterations );
+ pIStm->Release();
+ }
+#endif
+
+
+ return S_OK;
+}
+
+
+
+SCODE CRpcTest::Report (CTestOutput &output)
+{
+ if (m_fAverage)
+ {
+ output.WriteSectionHeader (Name(), TEXT("Object Rpc"), *m_pInput);
+
+ output.WriteString (TEXT("\n"));
+ output.WriteString (TEXT("Average times\n"));
+ output.WriteString (TEXT("\n"));
+ output.WriteResult (TEXT("Void "), m_ulVoidTime[0]);
+ output.WriteResult (TEXT("VoidRC "), m_ulVoidRCTime[0]);
+
+ output.WriteResult (TEXT("DwordIn "), m_ulDwordInTime[0]);
+ output.WriteResult (TEXT("DwordOut "), m_ulDwordOutTime[0]);
+ output.WriteResult (TEXT("DwordInOut "), m_ulDwordInOutTime[0]);
+
+ output.WriteResult (TEXT("StringIn "), m_ulStringInTime[0]);
+#ifdef STRINGOUT
+ output.WriteResult (TEXT("StringOut "), m_ulStringOutTime[0]);
+#endif
+ output.WriteResult (TEXT("StringInOut "), m_ulStringInOutTime[0]);
+
+ output.WriteResult (TEXT("GuidIn "), m_ulGuidInTime[0]);
+ output.WriteResult (TEXT("GuidOut "), m_ulGuidOutTime[0]);
+
+ output.WriteResult (TEXT("IUnknownIp "), m_ulIUnknownInprocInTime[0]);
+ output.WriteResult (TEXT("IUnknownLcl "), m_ulIUnknownLocalInTime[0]);
+ output.WriteResult (TEXT("IUnknownOut "), m_ulIUnknownInprocOutTime[0]);
+ // output.WriteResult (TEXT("IUnknownKpIn "), m_ulIUnknownKeepInTime[0]);
+ // output.WriteResult (TEXT("IUnknownKpOut"), m_ulIUnknownKeepOutTime[0]);
+
+#ifdef NOTYET
+ output.WriteResult (TEXT("InterfaceIn "), m_ulInterfaceInprocInTime[0]);
+ output.WriteResult (TEXT("InterfaceLcl"), m_ulInterfaceLocalInTime[0]);
+#endif
+ }
+ else
+ {
+ output.WriteSectionHeader (Name(), TEXT("Object Rpc"), *m_pInput);
+ output.WriteString (TEXT("\n"));
+
+ output.WriteResults (TEXT("Void "), m_ulIterations, m_ulVoidTime);
+ output.WriteResults (TEXT("VoidRC "), m_ulIterations, m_ulVoidRCTime);
+
+ output.WriteResults (TEXT("DwordIn "), m_ulIterations, m_ulDwordInTime);
+ output.WriteResults (TEXT("DwordOut "), m_ulIterations, m_ulDwordOutTime);
+ output.WriteResults (TEXT("DwordInOut "), m_ulIterations, m_ulDwordInOutTime);
+
+ output.WriteResults (TEXT("StringIn "), m_ulIterations, m_ulStringInTime);
+#ifdef STRINGOUT
+ output.WriteResults (TEXT("StringOut "), m_ulIterations, m_ulStringOutTime);
+#endif
+ output.WriteResults (TEXT("StringInOut "), m_ulIterations, m_ulStringInOutTime);
+
+ output.WriteResults (TEXT("GuidIn "), m_ulIterations, m_ulGuidInTime);
+ output.WriteResults (TEXT("GuidOut "), m_ulIterations, m_ulGuidOutTime);
+
+ output.WriteResults (TEXT("IUnknownIp "), m_ulIterations, m_ulIUnknownInprocInTime);
+ output.WriteResults (TEXT("IUnknownLcl "), m_ulIterations, m_ulIUnknownLocalInTime);
+ output.WriteResults (TEXT("IUnknownOut "), m_ulIterations, m_ulIUnknownInprocOutTime);
+ // output.WriteResults (TEXT("IUnknownKpIn "), m_ulIterations, m_ulIUnknownKeepInTime);
+ // output.WriteResults (TEXT("IUnknownKpOut"), m_ulIterations, m_ulIUnknownKeepOutTime);
+
+#ifdef NOTYET
+ output.WriteResults (TEXT("InterfaceIn "), m_ulIterations, m_ulInterfaceInprocInTime);
+ output.WriteResults (TEXT("InterfaceLcl"), m_ulIterations, m_ulInterfaceLocalInTime);
+#endif
+ }
+
+ return S_OK;
+}
+
+
diff --git a/private/oleutest/perform/cairole/tests/bm_rpc.hxx b/private/oleutest/perform/cairole/tests/bm_rpc.hxx
new file mode 100644
index 000000000..1569f70bf
--- /dev/null
+++ b/private/oleutest/perform/cairole/tests/bm_rpc.hxx
@@ -0,0 +1,71 @@
+//+------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1993.
+//
+// File: bm_rpc.hxx
+//
+// Contents: test class definition
+//
+// Classes: CRpcTest
+//
+// Functions:
+//
+// History: 19-July-93 t-martig Created
+//
+//--------------------------------------------------------------------------
+
+#ifndef _BM_RPC_HXX_
+#define _BM_RPC_HXX_
+
+#include <bm_base.hxx>
+#include <rpctst.h> // IRpcTest
+
+
+class CRpcTest : public CTestBase
+{
+public:
+ virtual TCHAR *Name ();
+ virtual SCODE Setup (CTestInput *input);
+ virtual SCODE Run ();
+ virtual SCODE Report (CTestOutput &OutputFile);
+ virtual SCODE Cleanup ();
+
+private:
+ ULONG m_ulIterations;
+ BOOL m_fAverage;
+
+ IRpcTest *m_pRPC;
+ CLSID m_ClsID;
+
+ IUnknown *m_punkInproc;
+ IUnknown *m_punkLocal;
+
+ ULONG m_ulVoidTime[TEST_MAX_ITERATIONS];
+ ULONG m_ulVoidRCTime[TEST_MAX_ITERATIONS];
+
+ ULONG m_ulDwordInTime[TEST_MAX_ITERATIONS];
+ ULONG m_ulDwordOutTime[TEST_MAX_ITERATIONS];
+ ULONG m_ulDwordInOutTime[TEST_MAX_ITERATIONS];
+
+ ULONG m_ulStringInTime[TEST_MAX_ITERATIONS];
+ ULONG m_ulStringOutTime[TEST_MAX_ITERATIONS];
+ ULONG m_ulStringInOutTime[TEST_MAX_ITERATIONS];
+
+ ULONG m_ulGuidInTime[TEST_MAX_ITERATIONS];
+ ULONG m_ulGuidOutTime[TEST_MAX_ITERATIONS];
+
+ ULONG m_ulIUnknownInprocInTime[TEST_MAX_ITERATIONS];
+ ULONG m_ulIUnknownInprocOutTime[TEST_MAX_ITERATIONS];
+ ULONG m_ulIUnknownLocalInTime[TEST_MAX_ITERATIONS];
+ ULONG m_ulIUnknownLocalOutTime[TEST_MAX_ITERATIONS];
+
+ ULONG m_ulIUnknownKeepInTime[TEST_MAX_ITERATIONS];
+ ULONG m_ulIUnknownKeepOutTime[TEST_MAX_ITERATIONS];
+
+ ULONG m_ulInterfaceInprocInTime[TEST_MAX_ITERATIONS];
+ ULONG m_ulInterfaceLocalInTime[TEST_MAX_ITERATIONS];
+
+};
+
+#endif
diff --git a/private/oleutest/perform/cairole/tests/bm_rpc2.cxx b/private/oleutest/perform/cairole/tests/bm_rpc2.cxx
new file mode 100644
index 000000000..d68a738b2
--- /dev/null
+++ b/private/oleutest/perform/cairole/tests/bm_rpc2.cxx
@@ -0,0 +1,311 @@
+//+------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1993.
+//
+// File: bm_rpc2.cxx
+//
+// Contents: ORPC Method Invocation tests
+//
+// Classes: CRpcTest22
+//
+// History: 08-08-95 Rickhi Created
+//
+//--------------------------------------------------------------------------
+#include <headers.cxx>
+#pragma hdrstop
+
+#include <bm_rpc2.hxx>
+#include <stream.hxx>
+#include <oletest.hxx>
+#include <tracelog.hxx>
+#include <cqi.hxx>
+
+
+TCHAR *CRpcTest2::Name ()
+{
+ return TEXT("RpcTest2");
+}
+
+
+SCODE CRpcTest2::Setup (CTestInput *pInput)
+{
+ CTestBase::Setup(pInput);
+
+ SCODE sc = pInput->GetGUID(&m_ClsID, Name(), TEXT("Clsid_Local"));
+ if (FAILED(sc))
+ {
+ Log (TEXT("Setup - GetClassID failed."), sc);
+ return sc;
+ }
+
+ // get iteration count
+ m_ulIterations = pInput->GetIterations(Name());
+
+ // initialize timing arrays
+ INIT_RESULTS(m_ulNULLTime);
+
+ INIT_RESULTS(m_ulIUnknownBestInTime);
+ INIT_RESULTS(m_ulIUnknownWorstInTime);
+
+ INIT_RESULTS(m_ulIUnknownBestOutTime);
+ INIT_RESULTS(m_ulIUnknownWorstOutTime);
+
+
+ m_pRPC = NULL;
+ m_pStm = NULL;
+
+ // get the stream of data to unmarshal from the file.
+ TCHAR szFile[MAX_PATH];
+ pInput->GetConfigString(Name(), TEXT("File"), TEXT(" "),
+ szFile, sizeof(szFile)/sizeof(TCHAR));
+
+ if (!wcscmp(szFile,L" "))
+ {
+ sc = E_INVALIDARG;
+ Log (TEXT("Setup - Get FileName failed."), sc);
+ return sc;
+ }
+
+ // now make a stream on file
+ m_pStm = (IStream *) new CStreamOnFile(szFile, sc, TRUE);
+
+ if (FAILED(sc))
+ {
+ Log (TEXT("Setup - new CStreamOnFile failed."), sc);
+ return sc;
+ }
+
+ m_punkInproc = (IUnknown *) new CQI(CLSID_QI);
+
+ return S_OK;
+}
+
+
+SCODE CRpcTest2::Cleanup ()
+{
+ if (m_pRPC)
+ m_pRPC->Release();
+
+ if (m_punkInproc)
+ m_punkInproc->Release();
+
+ return S_OK;
+}
+
+SCODE CRpcTest2::PrepareForRun()
+{
+ SCODE sc = InitCOM();
+
+ if (FAILED(sc))
+ {
+ Log (TEXT("Setup - CoInitialize failed."), sc);
+ return sc;
+ }
+
+ // get the interface to call on
+
+ // reset the stream to the beginning
+ LARGE_INTEGER libMove;
+ LISet32(libMove, 0x00000000);
+ m_pStm->Seek(libMove, STREAM_SEEK_SET, NULL);
+
+ // unmarshal the interface
+ sc = CoUnmarshalInterface(m_pStm, IID_IRpcTest, (void **)&m_pRPC);
+
+ if (FAILED(sc))
+ {
+ Log (TEXT("PrepareForRun - CoUnmarshalInteface failed."), sc);
+ UninitCOM();
+ }
+
+ Sleep(500);
+ return sc;
+}
+
+void CRpcTest2::CleanupFromRun()
+{
+ if (m_pRPC)
+ {
+ m_pRPC->Release();
+ m_pRPC = NULL;
+ }
+
+ UninitCOM();
+
+ Sleep(500);
+}
+
+
+SCODE CRpcTest2::Run ()
+{
+ CStopWatch sw;
+ SCODE sc;
+ ULONG iIter;
+
+ //
+ // NULL call tests
+ //
+
+ if (FAILED(sc = PrepareForRun()))
+ {
+ return sc;
+ }
+
+ Sleep(2000);
+
+ for (iIter=0; iIter<TEST_MAX_ITERATIONS_PRIVATE; iIter++)
+ {
+ sw.Reset();
+ m_pRPC->Void();
+ m_ulNULLTime[iIter] = sw.Read();
+ }
+
+ CleanupFromRun();
+
+
+
+
+ //
+ // IUnknown [in] Best Case - The other side already has
+ // the interface we are passing in.
+ //
+
+ if (FAILED(sc = PrepareForRun()))
+ {
+ return sc;
+ }
+
+ // give the other side the interface to keep
+ sc = m_pRPC->IUnknownInKeep(m_punkInproc);
+
+
+ for (iIter=0; iIter<m_ulIterations; iIter++)
+ {
+ sw.Reset();
+ sc = m_pRPC->IUnknownIn(m_punkInproc);
+ m_ulIUnknownBestInTime[iIter] = sw.Read();
+ }
+
+ sc = m_pRPC->IUnknownInRelease();
+
+ CleanupFromRun();
+
+
+
+
+
+ //
+ // IUnknown [out] Best Case - We already have the interface being
+ // passed back to us.
+ //
+
+ if (FAILED(sc = PrepareForRun()))
+ {
+ return sc;
+ }
+
+ // get the interface from the other side, and hang onto it.
+ IUnknown *punkOut = NULL;
+ sc = m_pRPC->IUnknownOut(&punkOut);
+
+
+ for (iIter=0; iIter<m_ulIterations; iIter++)
+ {
+ IUnknown *punkOut2 = NULL;
+
+ sw.Reset();
+ sc = m_pRPC->IUnknownOut(&punkOut2);
+ m_ulIUnknownBestOutTime[iIter] = sw.Read();
+
+ if (SUCCEEDED(sc))
+ {
+ // release 1 reference
+ punkOut2->Release();
+ }
+ }
+
+ // release the ptr we are holding, should be final release.
+ punkOut->Release();
+
+ CleanupFromRun();
+
+
+
+
+
+ //
+ // IUnknown [in] Worst Case - the other side does not have
+ // the interface we are passing in, nor have we ever marshaled
+ // an interface before in this process. The other side does not
+ // keep the interface we hand it. We loop several times, each time
+ // we do OleInit, OleUninit.
+ //
+
+ for (iIter=0; iIter<m_ulIterations; iIter++)
+ {
+ if (FAILED(sc = PrepareForRun()))
+ {
+ return sc;
+ }
+
+ sw.Reset();
+ sc = m_pRPC->IUnknownIn(m_punkInproc);
+ m_ulIUnknownWorstInTime[iIter] = sw.Read();
+
+ CleanupFromRun();
+ }
+
+
+
+
+
+ //
+ // IUnknown [out] Worst Case - the other side is giving us a brand
+ // new object, that it has never marshaled before. We do not hold onto
+ // the interface. We loop several times, each time
+ // we do OleInit, OleUninit.
+ //
+
+ for (iIter=0; iIter<m_ulIterations; iIter++)
+ {
+ if (FAILED(sc = PrepareForRun()))
+ {
+ return sc;
+ }
+
+ sw.Reset();
+
+ // BUGBUG sc = m_pRPC->IUnknownNewOut(&punkOut);
+ sc = m_pRPC->IUnknownOut(&punkOut);
+
+ m_ulIUnknownWorstOutTime[iIter] = sw.Read();
+
+ if (SUCCEEDED(sc))
+ {
+ punkOut->Release();
+ }
+
+ CleanupFromRun();
+ }
+
+ return S_OK;
+}
+
+
+SCODE CRpcTest2::Report (CTestOutput &output)
+{
+ output.WriteSectionHeader (Name(), TEXT("Object Rpc2"), *m_pInput);
+
+ output.WriteString(TEXT("\n"));
+
+ output.WriteResults(TEXT("NULL "), TEST_MAX_ITERATIONS_PRIVATE, m_ulNULLTime);
+ output.WriteResults(TEXT("IUnknown In Best "), m_ulIterations, m_ulIUnknownBestInTime);
+ output.WriteResults(TEXT("IUnknown In Worst"), m_ulIterations, m_ulIUnknownWorstInTime);
+ output.WriteResults(TEXT("IUnknown Out Best "), m_ulIterations, m_ulIUnknownBestOutTime);
+ output.WriteResults(TEXT("IUnknown Out Worst"), m_ulIterations, m_ulIUnknownWorstOutTime);
+
+ return S_OK;
+}
+
+
diff --git a/private/oleutest/perform/cairole/tests/bm_rpc2.hxx b/private/oleutest/perform/cairole/tests/bm_rpc2.hxx
new file mode 100644
index 000000000..ab0f41ffc
--- /dev/null
+++ b/private/oleutest/perform/cairole/tests/bm_rpc2.hxx
@@ -0,0 +1,57 @@
+//+------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1993.
+//
+// File: bm_rpc2.hxx
+//
+// Contents: ORPC test class definition
+//
+// Classes: CRpcTest2
+//
+// Functions:
+//
+// History: 08-08-95 Rickhi Created
+//
+//--------------------------------------------------------------------------
+#ifndef _BM_RPC2_HXX_
+#define _BM_RPC2_HXX_
+
+#include <bm_base.hxx>
+#include <rpctst.h> // IRpcTest
+
+#define TEST_MAX_ITERATIONS_PRIVATE 10
+
+class CRpcTest2 : public CTestBase
+{
+public:
+ virtual TCHAR *Name ();
+ virtual SCODE Setup (CTestInput *input);
+ virtual SCODE Run ();
+ virtual SCODE Report (CTestOutput &OutputFile);
+ virtual SCODE Cleanup ();
+
+private:
+
+ SCODE PrepareForRun();
+ void CleanupFromRun();
+
+ ULONG m_ulIterations;
+ DWORD m_InitFlag; // flag to OleInit
+
+ IStream *m_pStm;
+ IRpcTest *m_pRPC;
+ CLSID m_ClsID;
+
+ IUnknown *m_punkInproc;
+
+ ULONG m_ulNULLTime[TEST_MAX_ITERATIONS_PRIVATE];
+
+ ULONG m_ulIUnknownBestInTime[TEST_MAX_ITERATIONS_PRIVATE];
+ ULONG m_ulIUnknownWorstInTime[TEST_MAX_ITERATIONS_PRIVATE];
+
+ ULONG m_ulIUnknownBestOutTime[TEST_MAX_ITERATIONS_PRIVATE];
+ ULONG m_ulIUnknownWorstOutTime[TEST_MAX_ITERATIONS_PRIVATE];
+};
+
+#endif // _BM_RPC2_HXX_
diff --git a/private/oleutest/perform/cairole/tests/bm_rrpc.cxx b/private/oleutest/perform/cairole/tests/bm_rrpc.cxx
new file mode 100644
index 000000000..80cbf54ee
--- /dev/null
+++ b/private/oleutest/perform/cairole/tests/bm_rrpc.cxx
@@ -0,0 +1,500 @@
+//+------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1993.
+//
+// File: bm_rrpc.cxx
+//
+// Contents: Raw Rpc function call tests
+//
+// Classes: CRawRpc
+//
+// History: 1-Jul-93 t-martig Created
+// 2-Feb-94 rickhi Modified from above for Raw Rpc
+//
+//--------------------------------------------------------------------------
+
+#include <headers.cxx>
+#pragma hdrstop
+
+#include <bm_rrpc.hxx>
+
+
+HRESULT StartServer(BOOL _fDebug, LPTSTR _pszPath);
+
+
+extern "C" const GUID IID_IRawRpc;
+
+
+TCHAR *CRawRpc::Name ()
+{
+ return TEXT("RawRpc");
+}
+
+
+SCODE CRawRpc::Setup (CTestInput *pInput)
+{
+ CTestBase::Setup(pInput);
+
+ // get flag indicating whether to keep all values or
+ // only average values.
+ TCHAR szAverage[5];
+ pInput->GetConfigString(Name(), TEXT("Average"), TEXT("Y"),
+ szAverage, sizeof(szAverage)/sizeof(TCHAR));
+ if (szAverage[0] == 'n' || szAverage[0] == 'N')
+ m_fAverage = FALSE;
+ else
+ m_fAverage = TRUE;
+
+ // get iteration count
+ if (m_fAverage)
+ m_ulIterations = pInput->GetRealIterations(Name());
+ else
+ m_ulIterations = pInput->GetIterations(Name());
+ m_pszStringBinding = NULL;
+ m_hRpc = NULL;
+
+ // initialize timing arrays
+ INIT_RESULTS(m_ulVoidTime);
+ INIT_RESULTS(m_ulVoidRCTime);
+
+ INIT_RESULTS(m_ulDwordInTime);
+ INIT_RESULTS(m_ulDwordOutTime);
+ INIT_RESULTS(m_ulDwordInOutTime);
+
+ INIT_RESULTS(m_ulStringInTime);
+ INIT_RESULTS(m_ulStringOutTime);
+ INIT_RESULTS(m_ulStringInOutTime);
+
+ INIT_RESULTS(m_ulGuidInTime);
+ INIT_RESULTS(m_ulGuidOutTime);
+
+
+
+ // get the server exe name and debug flag out of the ini file, then
+ // start the server and wait for it.
+
+ TCHAR szServer[15];
+ pInput->GetConfigString(Name(), TEXT("Server"), TEXT("rawrpc.exe"),
+ szServer, sizeof(szServer)/sizeof(TCHAR));
+
+ // get input
+ TCHAR szValue[40];
+
+ pInput->GetConfigString(Name(), TEXT("Debug"), TEXT("N"),
+ szValue, sizeof(szValue)/sizeof(TCHAR));
+
+ BOOL fDebug = !lstrcmpi(szValue, TEXT("Y"));
+
+ DWORD dwTimeout = pInput->GetConfigInt(Name(), TEXT("Timeout"), 60000);
+
+ HANDLE hEvent = CreateEvent(NULL, TRUE, FALSE,
+ TEXT("OleBenchRawRpcServerStarted"));
+ if (NULL == hEvent)
+ {
+ Log (TEXT("Setup - Event Creation failed."), GetLastError());
+ return E_FAIL;
+ }
+
+ // start the server application and wait for it.
+ HRESULT sc = StartServer(fDebug, szServer);
+
+ if (FAILED(sc))
+ {
+ Log (TEXT("Setup - Start Server failed."), sc);
+ CloseHandle(hEvent);
+ return sc;
+ }
+
+
+ if (WAIT_OBJECT_0 != WaitForSingleObject(hEvent, dwTimeout))
+ {
+ Log (TEXT("Setup - Server never signaled."), GetLastError());
+ CloseHandle(hEvent);
+ return E_FAIL;
+ }
+ CloseHandle(hEvent);
+
+ // bind to the server application
+ TCHAR szProtseq[20];
+ TCHAR szNetworkAddr[20];
+
+ pInput->GetConfigString(Name(), TEXT("Protseq"),
+#ifdef USE_MSWMSG
+ TEXT("mswmsg"),
+#else
+ TEXT("ncalrpc"),
+#endif
+ szProtseq, 20);
+
+ pInput->GetConfigString(Name(), TEXT("NetworkAddr"), TEXT(""),
+ szNetworkAddr, 20);
+
+ LPTSTR pszEndPoint = TEXT("99999.99999");
+ RPC_STATUS rc;
+
+#ifdef UNICODE
+ rc = RpcStringBindingCompose(NULL,
+ szProtseq,
+ szNetworkAddr,
+ pszEndPoint,
+ NULL,
+ &m_pszStringBinding);
+#else
+ //
+ // Can't just use TCHAR here because RpcString*() take unsigned
+ // chars
+ //
+ rc = RpcStringBindingCompose(NULL,
+ (unsigned char *)szProtseq,
+ (unsigned char *)szNetworkAddr,
+ (unsigned char *)pszEndPoint,
+ NULL,
+ (unsigned char **)&m_pszStringBinding);
+#endif
+ if (rc != S_OK)
+ {
+ Log(TEXT("Setup - RpcStringBindingCompose failed."), rc);
+ return rc;
+ }
+
+#ifdef UNICODE
+ rc = RpcBindingFromStringBinding(m_pszStringBinding, &m_hRpc);
+#else
+ rc = RpcBindingFromStringBinding((unsigned char *)m_pszStringBinding,
+ &m_hRpc);
+#endif
+
+ if (rc != S_OK)
+ {
+ Log(TEXT("Setup - RpcBindingFromStringBinding failed."), rc);
+ return rc;
+ }
+
+ // all done.
+ return S_OK;
+}
+
+
+SCODE CRawRpc::Cleanup ()
+{
+ if (m_hRpc)
+ {
+ RpcBindingFree(&m_hRpc);
+ }
+
+ if (m_pszStringBinding)
+ {
+#ifdef UNICODE
+ RpcStringFree(&m_pszStringBinding);
+#else
+ RpcStringFree((unsigned char **)&m_pszStringBinding);
+#endif
+ }
+
+ return S_OK;
+}
+
+
+SCODE CRawRpc::Run ()
+{
+ CStopWatch sw;
+ SCODE sc;
+ ULONG iIter;
+
+ //
+ // void passing tests
+ //
+
+ ResetAverage( m_fAverage, sw );
+ for (iIter=0; iIter<m_ulIterations; iIter++)
+ {
+ ResetNotAverage( m_fAverage, sw );
+ Void(m_hRpc);
+ ReadNotAverage( m_fAverage, sw, m_ulVoidTime[iIter] );
+ }
+ ReadAverage( m_fAverage, sw, m_ulVoidTime[0], m_ulIterations );
+
+ ResetAverage( m_fAverage, sw );
+ for (iIter=0; iIter<m_ulIterations; iIter++)
+ {
+ ResetNotAverage( m_fAverage, sw );
+ sc = VoidRC(m_hRpc);
+ ReadNotAverage( m_fAverage, sw, m_ulVoidRCTime[iIter] );
+ }
+ ReadAverage( m_fAverage, sw, m_ulVoidRCTime[0], m_ulIterations );
+
+ //
+ // dword passing tests
+ //
+
+ DWORD dwTmp = 1;
+ ResetAverage( m_fAverage, sw );
+ for (iIter=0; iIter<m_ulIterations; iIter++)
+ {
+ ResetNotAverage( m_fAverage, sw );
+ sc = DwordIn(m_hRpc, dwTmp);
+ ReadNotAverage( m_fAverage, sw, m_ulDwordInTime[iIter] );
+ }
+ ReadAverage( m_fAverage, sw, m_ulDwordInTime[0], m_ulIterations );
+
+ ResetAverage( m_fAverage, sw );
+ for (iIter=0; iIter<m_ulIterations; iIter++)
+ {
+ ResetNotAverage( m_fAverage, sw );
+ sc = DwordOut(m_hRpc, &dwTmp);
+ ReadNotAverage( m_fAverage, sw, m_ulDwordOutTime[iIter] );
+ }
+ ReadAverage( m_fAverage, sw, m_ulDwordOutTime[0], m_ulIterations );
+
+ ResetAverage( m_fAverage, sw );
+ for (iIter=0; iIter<m_ulIterations; iIter++)
+ {
+ ResetNotAverage( m_fAverage, sw );
+ sc = DwordInOut(m_hRpc, &dwTmp);
+ ReadNotAverage( m_fAverage, sw, m_ulDwordInOutTime[iIter] );
+ }
+ ReadAverage( m_fAverage, sw, m_ulDwordInOutTime[0], m_ulIterations );
+
+ //
+ // string passing tests
+ //
+
+ WCHAR szHello[] = L"C:\\FOOFOO\\FOOBAR\\FOOBAK\\FOOBAZ\\FOOTYPICAL\\PATH\\HELLO";
+ ResetAverage( m_fAverage, sw );
+ for (iIter=0; iIter<m_ulIterations; iIter++)
+ {
+ ResetNotAverage( m_fAverage, sw );
+ sc = StringIn(m_hRpc, szHello);
+ ReadNotAverage( m_fAverage, sw, m_ulStringInTime[iIter] );
+ }
+ ReadAverage( m_fAverage, sw, m_ulStringInTime[0], m_ulIterations );
+
+ LPWSTR pwszOut = NULL;
+#ifdef STRINGOUT
+ ResetAverage( m_fAverage, sw );
+ for (iIter=0; iIter<m_ulIterations; iIter++)
+ {
+ ResetNotAverage( m_fAverage, sw );
+ pwszOut = NULL;
+ sc = StringOut(m_hRpc, &pwszOut);
+ ReadNotAverage( m_fAverage, sw, m_ulStringOutTime[iIter] );
+ }
+ ReadAverage( m_fAverage, sw, m_ulStringOutTime[0], m_ulIterations );
+#endif
+ pwszOut = szHello;
+ ResetAverage( m_fAverage, sw );
+ for (iIter=0; iIter<m_ulIterations; iIter++)
+ {
+ ResetNotAverage( m_fAverage, sw );
+ sc = StringInOut(m_hRpc, pwszOut);
+ ReadNotAverage( m_fAverage, sw, m_ulStringInOutTime[iIter] );
+ }
+ ReadAverage( m_fAverage, sw, m_ulStringInOutTime[0], m_ulIterations );
+
+
+ //
+ // guid passing tests
+ //
+
+ ResetAverage( m_fAverage, sw );
+ for (iIter=0; iIter<m_ulIterations; iIter++)
+ {
+ ResetNotAverage( m_fAverage, sw );
+ sc = GuidIn(m_hRpc, IID_IRawRpc);
+ ReadNotAverage( m_fAverage, sw, m_ulGuidInTime[iIter] );
+ }
+ ReadAverage( m_fAverage, sw, m_ulGuidInTime[0], m_ulIterations );
+
+ GUID guid;
+ ResetAverage( m_fAverage, sw );
+ for (iIter=0; iIter<m_ulIterations; iIter++)
+ {
+ ResetNotAverage( m_fAverage, sw );
+ sc = GuidOut(m_hRpc, &guid);
+ ReadNotAverage( m_fAverage, sw, m_ulGuidOutTime[iIter] );
+ }
+ ReadAverage( m_fAverage, sw, m_ulGuidOutTime[0], m_ulIterations );
+
+ // tell the server to quit.
+ sc = Quit(m_hRpc);
+
+ return S_OK;
+}
+
+
+
+SCODE CRawRpc::Report (CTestOutput &output)
+{
+ output.WriteSectionHeader (Name(), TEXT("Raw Rpc"), *m_pInput);
+
+ if (m_fAverage)
+ {
+ output.WriteString (TEXT("\n"));
+ output.WriteString (TEXT("Average Times\n"));
+ output.WriteString (TEXT("\n"));
+ output.WriteResult (TEXT("Void "), m_ulVoidTime[0]);
+ output.WriteResult (TEXT("VoidRC "), m_ulVoidRCTime[0]);
+
+ output.WriteResult (TEXT("DwordIn "), m_ulDwordInTime[0]);
+ output.WriteResult (TEXT("DwordOut "), m_ulDwordOutTime[0]);
+ output.WriteResult (TEXT("DwordInOut "), m_ulDwordInOutTime[0]);
+
+ output.WriteResult (TEXT("StringIn "), m_ulStringInTime[0]);
+#ifdef STRINGOUT
+ output.WriteResult (TEXT("StringOut "), m_ulStringOutTime[0]);
+#endif
+ output.WriteResult (TEXT("StringInOut "), m_ulStringInOutTime[0]);
+
+ output.WriteResult (TEXT("GuidIn "), m_ulGuidInTime[0]);
+ output.WriteResult (TEXT("GuidOut "), m_ulGuidOutTime[0]);
+
+ }
+ else
+ {
+
+ output.WriteString (TEXT("\n"));
+ output.WriteResults (TEXT("Void "), m_ulIterations, m_ulVoidTime);
+ output.WriteResults (TEXT("VoidRC "), m_ulIterations, m_ulVoidRCTime);
+
+ output.WriteResults (TEXT("DwordIn "), m_ulIterations, m_ulDwordInTime);
+ output.WriteResults (TEXT("DwordOut "), m_ulIterations, m_ulDwordOutTime);
+ output.WriteResults (TEXT("DwordInOut "), m_ulIterations, m_ulDwordInOutTime);
+
+ output.WriteResults (TEXT("StringIn "), m_ulIterations, m_ulStringInTime);
+#ifdef STRINGOUT
+ output.WriteResults (TEXT("StringOut "), m_ulIterations, m_ulStringOutTime);
+#endif
+ output.WriteResults (TEXT("StringInOut "), m_ulIterations, m_ulStringInOutTime);
+
+ output.WriteResults (TEXT("GuidIn "), m_ulIterations, m_ulGuidInTime);
+ output.WriteResults (TEXT("GuidOut "), m_ulIterations, m_ulGuidOutTime);
+ }
+
+ return S_OK;
+}
+
+
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: StartServer
+//
+// Synopsis: Start an Rpc server process
+//
+// Arguments: [_fDebug] - start in a debugger or not
+// [_pwszPath] - name of server process
+//
+// Returns: S_OK - Server started
+// S_FALSE - server is already starting
+// CO_E_SERVER_EXEC_FAILURE
+//
+// Algorithm:
+//
+// History: 21-Apr-93 Ricksa Created
+// 04-Jan-94 Ricksa Modified for class starting sync.
+//
+//--------------------------------------------------------------------------
+HRESULT StartServer(BOOL _fDebug, LPTSTR _pszPath)
+{
+ // Where we put the command line
+ TCHAR aszTmpCmdLine[MAX_PATH];
+ TCHAR *pszTmpCmdLine = aszTmpCmdLine;
+
+ if (_fDebug)
+ {
+ HKEY hKey;
+ DWORD dwType;
+ DWORD cbData = sizeof(aszTmpCmdLine)/sizeof(TCHAR);
+
+ ULONG rc = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
+ TEXT("SOFTWARE\\Microsoft\\scm"),
+ 0,
+ KEY_READ,
+ &hKey);
+
+ if (rc == ERROR_SUCCESS)
+ {
+ // copy the debugger info into the command line
+
+ rc = RegQueryValueEx(hKey, TEXT("Debugger"), 0, &dwType,
+ (LPBYTE)pszTmpCmdLine, &cbData);
+
+ if (rc == ERROR_SUCCESS && dwType == REG_SZ)
+ {
+ ULONG ulLen = cbData / sizeof(TCHAR);
+ pszTmpCmdLine += ulLen;
+ aszTmpCmdLine[ulLen-1] = TEXT(' '); // whitespace
+ }
+
+ RegCloseKey(hKey);
+ }
+ }
+
+#ifdef NOTYET // following code does not compile!
+ #ifndef CAIROLE_DOWNLEVEL
+ if (acWinFormat[0] == 0)
+ {
+ TCHAR acWinDir[MAX_PATH];
+
+ UINT cWinDir = GetSystemDirectory(acWinDir, sizeof(acWinDir)/sizeof(TCHAR));
+
+ Win4Assert(cWinDir && "GetWindowsDir failed!");
+
+ wsprintf(acWinFormat, TEXT("%s%s"), acWinDir, TEXT("\\%s %s"));
+ }
+
+
+ // We make all paths relative to the windows directory unless
+ // the path is absolute.
+ wsprintf(pszTmpCmdLine,
+ (_pszPath[1] != TEXT(':')) ? acWinFormat : TEXT("%s %s"),
+ _pwszPath,
+ TEXT("-Embedding"));
+#else
+#endif // CAIROLE_DOWNLEVEL
+
+#endif // NOTYET
+
+ // Just use the current path to find the server.
+ wsprintf(pszTmpCmdLine, TEXT("%s %s"), _pszPath, TEXT("-Embedding"));
+
+ // Process info for create process
+ PROCESS_INFORMATION procinfo;
+
+ // build the win32 startup info structure
+ STARTUPINFO startupinfo;
+ startupinfo.cb = sizeof(STARTUPINFO);
+ startupinfo.lpReserved = NULL;
+ startupinfo.lpDesktop = NULL;
+ startupinfo.lpTitle = _pszPath;
+ startupinfo.dwX = 40;
+ startupinfo.dwY = 40;
+ startupinfo.dwXSize = 80;
+ startupinfo.dwYSize = 40;
+ startupinfo.dwFlags = 0;
+ startupinfo.wShowWindow = SW_SHOWNORMAL;
+ startupinfo.cbReserved2 = 0;
+ startupinfo.lpReserved2 = NULL;
+
+ if (!CreateProcess( NULL, // application name
+ aszTmpCmdLine, // command line
+ NULL, // process sec attributes
+ NULL, // thread sec attributes
+ FALSE, // dont inherit handles
+ CREATE_NEW_CONSOLE,// creation flags
+ NULL, // use same enviroment block
+ NULL, // use same directory
+ &startupinfo, // no startup info
+ &procinfo)) // proc info returned
+ {
+ return CO_E_SERVER_EXEC_FAILURE;
+ }
+
+ CloseHandle(procinfo.hProcess);
+ CloseHandle(procinfo.hThread);
+
+ return S_OK;
+}
diff --git a/private/oleutest/perform/cairole/tests/bm_rrpc.hxx b/private/oleutest/perform/cairole/tests/bm_rrpc.hxx
new file mode 100644
index 000000000..e20d1579d
--- /dev/null
+++ b/private/oleutest/perform/cairole/tests/bm_rrpc.hxx
@@ -0,0 +1,57 @@
+//+------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1993.
+//
+// File: bm_rrpc.hxx
+//
+// Contents: test class definition
+//
+// Classes: CRawRpc
+//
+// Functions:
+//
+// History: 19-July-93 t-martig Created
+//
+//--------------------------------------------------------------------------
+
+#ifndef _BM_RAWRPC_HXX_
+#define _BM_RAWRPC_HXX_
+
+#include <bm_base.hxx>
+#include <rawrpc.h> // IRpcTest
+
+
+class CRawRpc : public CTestBase
+{
+public:
+ virtual TCHAR *Name ();
+ virtual SCODE Setup (CTestInput *input);
+ virtual SCODE Run ();
+ virtual SCODE Report (CTestOutput &OutputFile);
+ virtual SCODE Cleanup ();
+
+private:
+ LPTSTR m_pszStringBinding;
+ handle_t m_hRpc;
+
+ ULONG m_ulIterations;
+ BOOL m_fAverage;
+
+ ULONG m_ulVoidTime[TEST_MAX_ITERATIONS];
+ ULONG m_ulVoidRCTime[TEST_MAX_ITERATIONS];
+
+ ULONG m_ulDwordInTime[TEST_MAX_ITERATIONS];
+ ULONG m_ulDwordOutTime[TEST_MAX_ITERATIONS];
+ ULONG m_ulDwordInOutTime[TEST_MAX_ITERATIONS];
+
+ ULONG m_ulStringInTime[TEST_MAX_ITERATIONS];
+ ULONG m_ulStringOutTime[TEST_MAX_ITERATIONS];
+ ULONG m_ulStringInOutTime[TEST_MAX_ITERATIONS];
+
+ ULONG m_ulGuidInTime[TEST_MAX_ITERATIONS];
+ ULONG m_ulGuidOutTime[TEST_MAX_ITERATIONS];
+
+};
+
+#endif
diff --git a/private/oleutest/perform/cairole/tests/bm_sbind.cxx b/private/oleutest/perform/cairole/tests/bm_sbind.cxx
new file mode 100644
index 000000000..e8e84faba
--- /dev/null
+++ b/private/oleutest/perform/cairole/tests/bm_sbind.cxx
@@ -0,0 +1,222 @@
+//+------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1993.
+//
+// File: bm_sbind.cxx
+//
+// Contents: Ole moniker binding test (BindToObject)
+//
+// Classes: CFileMonikerStorageBindTest
+//
+// History: 9-July-93 t-martig Created
+//
+//--------------------------------------------------------------------------
+#include <headers.cxx>
+#pragma hdrstop
+
+#include <bm_sbind.hxx>
+
+
+TCHAR *CFileMonikerStorageBindTest::Name ()
+{
+ return TEXT("BindToStorage");
+}
+
+
+SCODE CFileMonikerStorageBindTest::Setup (CTestInput *pInput)
+{
+ IClassFactory *pICF = NULL;
+ IStorage *pStg = NULL;
+ IPersistStorage *pIPS = NULL;
+ SCODE sc;
+
+ CTestBase::Setup(pInput);
+
+ // get the iteration count from the ini file
+ m_ulIterations = pInput->GetIterations(Name());
+
+ // for each class ctx, get the classid, and init internal state
+ for (ULONG iCtx=0; iCtx<CNT_CLSCTX; iCtx++)
+ {
+ // Get ClsID for this Ctx from the .ini file
+ sc = pInput->GetGUID(&m_ClsID[iCtx], Name(), apszClsIDName[iCtx]);
+ if (FAILED(sc))
+ {
+ Log (TEXT("Setup - GetClassID failed."), sc);
+ return sc;
+ }
+
+ INIT_RESULTS(m_ulCreateMkrTime[iCtx]);
+ INIT_RESULTS(m_ulCreateBndCtxTime[iCtx]);
+ INIT_RESULTS(m_ulBindTime[iCtx]);
+ }
+
+ sc = InitCOM();
+ if (FAILED(sc))
+ {
+ Log (TEXT("Setup - CoInitialize failed."), sc);
+ return sc;
+ }
+
+ // for each class ctx, create a persistent instance on disk
+ for (iCtx=0; iCtx<CNT_CLSCTX; iCtx++)
+ {
+ // Create an instance
+ sc = CoGetClassObject(m_ClsID[iCtx], dwaClsCtx[iCtx], NULL,
+ IID_IClassFactory, (void **)&pICF);
+ if (SUCCEEDED(sc))
+ {
+ sc = pICF->CreateInstance(NULL, IID_IPersistStorage,
+ (void **)&pIPS);
+ pICF->Release();
+ if (SUCCEEDED(sc))
+ {
+ // create instance of the storage
+ sc = StgCreateDocfile(apszPerstName[iCtx],
+ STGM_READWRITE | STGM_CREATE |
+ STGM_SHARE_EXCLUSIVE,
+ 0, &pStg);
+ if (SUCCEEDED(sc))
+ {
+ // save the class instance in the storage
+ sc = pIPS->Save(pStg, FALSE);
+ pStg->Release();
+
+ if (FAILED(sc))
+ {
+ Log (TEXT("Setup - pIPS->Save failed."), sc);
+ }
+ }
+ else
+ {
+ Log (TEXT("Setup - StgCreateDocfile failed."), sc);
+ }
+
+ pIPS->Release();
+ }
+ else
+ {
+ Log (TEXT("Setup - CreateInstance failed"), sc);
+ }
+ }
+ else
+ {
+ Log (TEXT("Setup - CoGetClassObject failed"), sc);
+ }
+ }
+
+ return S_OK;
+}
+
+
+SCODE CFileMonikerStorageBindTest::Cleanup ()
+{
+ UninitCOM();
+
+ CHAR szPerstName[80];
+
+ // delete the persistent instances
+ for (ULONG iCtx=0; iCtx<CNT_CLSCTX; iCtx++)
+ {
+ // delete original
+ wcstombs(szPerstName, apszPerstName[iCtx],
+ wcslen(apszPerstName[iCtx])+1);
+ _unlink(szPerstName);
+ }
+
+ return S_OK;
+}
+
+
+SCODE CFileMonikerStorageBindTest::Run ()
+{
+ CStopWatch sw;
+ IMoniker *pmk = NULL;
+ IBindCtx *pbc = NULL;
+ IStorage *pStg = NULL;
+ SCODE sc;
+
+ // for each class context
+ for (ULONG iCtx=0; iCtx<CNT_CLSCTX; iCtx++)
+ {
+ // for each iteration
+ for (ULONG iIter=0; iIter<m_ulIterations; iIter++)
+ {
+ sw.Reset();
+ sc = CreateFileMoniker (apszPerstName[iCtx], &pmk);
+ m_ulCreateMkrTime[iCtx][iIter] = sw.Read();
+
+ if (!Log (TEXT("CreateFileMoniker"), sc))
+ {
+ BIND_OPTS bindopts;
+ bindopts.cbStruct = sizeof(BIND_OPTS);
+
+ sw.Reset();
+ sc = CreateBindCtx(0, &pbc);
+ if (SUCCEEDED(sc))
+ {
+ sc = pbc->GetBindOptions(&bindopts);
+ bindopts.grfMode |= STGM_SHARE_EXCLUSIVE | STGM_DIRECT;
+ sc = pbc->SetBindOptions(&bindopts);
+ }
+ m_ulCreateBndCtxTime[iCtx][iIter] = sw.Read();
+
+ if (!Log (TEXT("CreateBindCtx"), sc))
+ {
+ sw.Reset();
+ sc = pmk->BindToStorage(pbc, NULL, IID_IStorage, (void**)&pStg);
+ m_ulBindTime[iCtx][iIter]=sw.Read();
+
+ if (!Log (TEXT("BindToStorage"), sc))
+ {
+ sw.Reset();
+ pStg->Release();
+ m_ulReleaseTime[iCtx][iIter]=sw.Read();
+ }
+ else
+ {
+ m_ulBindTime[iCtx][iIter] = NOTAVAIL;
+ }
+
+ pbc->Release();
+ }
+ else
+ {
+ m_ulCreateBndCtxTime[iCtx][iIter] = NOTAVAIL;
+ }
+
+ pmk->Release();
+ }
+ else
+ {
+ m_ulCreateMkrTime[iCtx][iIter] = NOTAVAIL;
+ }
+ }
+ }
+
+ return S_OK;
+}
+
+
+
+SCODE CFileMonikerStorageBindTest::Report (CTestOutput &output)
+{
+ output.WriteSectionHeader (Name(), TEXT("BindToStorage via FileMoniker"), *m_pInput);
+
+ // for each clsctx, write the results
+ for (ULONG iCtx=0; iCtx<CNT_CLSCTX; iCtx++)
+ {
+ output.WriteString(TEXT("\n"));
+ output.WriteClassID(&m_ClsID[iCtx]);
+ output.WriteString(apszClsCtx[iCtx]);
+ output.WriteString(TEXT("\n"));
+
+ output.WriteResults(TEXT("CreateMoniker"), m_ulIterations, m_ulCreateMkrTime[iCtx]);
+ output.WriteResults(TEXT("CreateBindCtx"), m_ulIterations, m_ulCreateBndCtxTime[iCtx]);
+ output.WriteResults(TEXT("Bind "), m_ulIterations, m_ulBindTime[iCtx]);
+ output.WriteResults(TEXT("Release "), m_ulIterations, m_ulReleaseTime[iCtx]);
+ }
+
+ return S_OK;
+}
diff --git a/private/oleutest/perform/cairole/tests/bm_sbind.hxx b/private/oleutest/perform/cairole/tests/bm_sbind.hxx
new file mode 100644
index 000000000..e31b6aafa
--- /dev/null
+++ b/private/oleutest/perform/cairole/tests/bm_sbind.hxx
@@ -0,0 +1,42 @@
+//+------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1993.
+//
+// File: bm_sbind.hxx
+//
+// Contents: test class definition
+//
+// Classes: CFileMonikerStorageBindTest
+//
+// Functions:
+//
+// History: 19-July-93 t-martig Created
+//
+//--------------------------------------------------------------------------
+
+#ifndef _BM_SBIND_HXX_
+#define _BM_SBIND_HXX_
+
+#include <bm_base.hxx>
+
+class CFileMonikerStorageBindTest : public CTestBase
+{
+public:
+ virtual TCHAR *Name ();
+ virtual SCODE Setup (CTestInput *input);
+ virtual SCODE Run ();
+ virtual SCODE Report (CTestOutput &OutputFile);
+ virtual SCODE Cleanup ();
+
+private:
+ CLSID m_ClsID[CNT_CLSCTX];
+
+ ULONG m_ulIterations;
+ ULONG m_ulCreateMkrTime[CNT_CLSCTX][TEST_MAX_ITERATIONS];
+ ULONG m_ulCreateBndCtxTime[CNT_CLSCTX][TEST_MAX_ITERATIONS];
+ ULONG m_ulBindTime[CNT_CLSCTX][TEST_MAX_ITERATIONS];
+ ULONG m_ulReleaseTime[CNT_CLSCTX][TEST_MAX_ITERATIONS];
+};
+
+#endif
diff --git a/private/oleutest/perform/cairole/tests/bm_stg.cxx b/private/oleutest/perform/cairole/tests/bm_stg.cxx
new file mode 100644
index 000000000..c0a49348e
--- /dev/null
+++ b/private/oleutest/perform/cairole/tests/bm_stg.cxx
@@ -0,0 +1,624 @@
+//+------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1993.
+//
+// File: bm_stg.cxx
+//
+// Contents: Basic Storage test
+//
+// Classes: CStorageTest
+//
+// History: 7-June-94 t-vadims Created
+//
+//--------------------------------------------------------------------------
+#include <headers.cxx>
+#pragma hdrstop
+
+#include <bm_stg.hxx>
+
+#define DEF_DATASIZE 16384
+
+//#define TIME_FILEIO // define this macro to do timing of ole32.dll internal file io
+ // requires special ole32.dll
+
+#ifdef TIME_FILEIO
+#include <extimeio.hxx>
+#endif
+
+TCHAR *CStorageTest::Name ()
+{
+ return TEXT("StorageTest");
+}
+
+
+SCODE CStorageTest::Setup (CTestInput *pInput)
+{
+ SCODE sc;
+ TCHAR pszValue[16];
+ ULONG i;
+
+ CTestBase::Setup(pInput);
+
+ // get iteration count
+ m_ulIterations = pInput->GetIterations(Name());
+
+ sc = InitCOM();
+ if (FAILED(sc))
+ {
+ Log (TEXT("Setup - CoInitialize failed."), sc);
+ return sc;
+ }
+
+ // get malloc interface for this task
+ m_piMalloc = NULL;
+ sc = CoGetMalloc(MEMCTX_TASK, &m_piMalloc);
+ if (FAILED(sc))
+ {
+ Log (TEXT("Setup - CoGetMalloc"), sc);
+ Cleanup();
+ return sc;
+ }
+
+ // get values of various paremeters from ini file
+
+ m_iStartSize = pInput->GetConfigInt(Name(), TEXT("StartSize"), 16);
+ if(m_iStartSize <= 0)
+ m_iStartSize = 16;
+
+ m_iEndSize = pInput->GetConfigInt(Name(), TEXT("EndSize"), DEF_DATASIZE);
+
+ // initialize array to be written to the file.
+ m_pbData = (BYTE *)m_piMalloc->Alloc(m_iEndSize);
+ if(m_pbData == NULL)
+ {
+ Log (TEXT("Setup - Cannot allocate memory"), E_OUTOFMEMORY);
+ Cleanup();
+ return E_OUTOFMEMORY;
+ }
+
+ for (i=0; i < m_iEndSize; i++)
+ m_pbData[i] = (BYTE)i;
+
+
+ m_iRepeatFactor = pInput->GetConfigInt(Name(), TEXT("RepeatFactor"), 1);
+
+ if (m_iRepeatFactor > MAX_REPS)
+ m_iRepeatFactor = MAX_REPS;
+
+ // Figure out how many different sizes we're going to write.
+ // and the size of the final file.
+ m_ulTotalSize = 0;
+ for(m_ulNumSizes = 0, i = m_iStartSize; i <= m_iEndSize; i *=2, m_ulNumSizes++)
+ m_ulTotalSize += i * m_iRepeatFactor;
+
+
+ if (m_iRepeatFactor * m_ulNumSizes > MAX_READS)
+ {
+ Log(TEXT("Too many different sizes and/or repeat factor is too big"), E_FAIL);
+ Cleanup();
+ return E_FAIL;
+ }
+
+ m_flStgCreateFlags = 0;
+ // get file name to be used and values of other parameters
+ pInput->GetConfigString(Name(), TEXT("FileName"), TEXT("stgtest.bm"),
+ m_pszFile, MAX_PATH);
+#ifdef UNICODE
+ wcscpy(m_pwszFile, m_pszFile);
+#else
+ mbstowcs(m_pwszFile, m_pszFile, strlen(m_pszFile)+1);
+#endif
+
+ pInput->GetConfigString(Name(), TEXT("FileMode"), TEXT("DIRECT"),
+ m_pszFileMode, 15);
+
+ if(lstrcmpi(m_pszFileMode, TEXT("DIRECT")) == 0)
+ m_flStgCreateFlags |= STGM_DIRECT;
+ else
+ m_flStgCreateFlags |= STGM_TRANSACTED;
+
+
+ pInput->GetConfigString(Name(), TEXT("SetSize"), TEXT("OFF"), pszValue, 15);
+
+ if (lstrcmpi(pszValue, TEXT("ON")) == 0)
+ m_bDoSetSize = TRUE;
+ else
+ m_bDoSetSize = FALSE;
+
+ pInput->GetConfigString(Name(), TEXT("ReadMode"), TEXT("SEQUENTIAL"),
+ m_pszReadMode, 15);
+
+ if(lstrcmpi(m_pszReadMode, TEXT("SEQUENTIAL")) == 0)
+ m_bSequentialRead = TRUE;
+ else
+ m_bSequentialRead = FALSE;
+
+
+ InitTimings();
+
+ return S_OK;
+}
+
+
+void CStorageTest::InitTimings()
+{
+ ULONG i;
+
+ // initialize timing arrays
+
+ INIT_RESULTS(m_ulIsStorageFileYES);
+ INIT_RESULTS(m_ulIsStorageFileNO);
+ INIT_RESULTS(m_ulStgOpenStorageDRFAIL);
+
+
+ INIT_RESULTS(m_ulStgCreateDocfile);
+ INIT_RESULTS(m_ulCreateStream);
+ ZERO_RESULTS(m_ulSetSize);
+ INIT_RESULTS(m_ulStreamRelease1);
+ ZERO_RESULTS(m_ulStorageCommit);
+ INIT_RESULTS(m_ulStorageRelease1);
+
+ INIT_RESULTS(m_ulStgOpenStorage);
+ INIT_RESULTS(m_ulOpenStream);
+ INIT_RESULTS(m_ulStreamRelease2);
+ INIT_RESULTS(m_ulStorageRelease2);
+
+ ZERO_RESULTS(m_ulStreamWriteTotal);
+ ZERO_RESULTS(m_ulStreamReadTotal);
+ ZERO_RESULTS(m_ulStreamSeekTotal);
+
+
+ for (i = 0; i < MAX_READS; i++)
+ {
+ INIT_RESULTS(m_ulStreamWrite[i]);
+ INIT_RESULTS(m_ulStreamRead[i]);
+ INIT_RESULTS(m_ulStreamSeek[i]);
+#ifdef TIME_FILEIO
+ INIT_RESULTS(m_ulActualWrite[i]);
+ INIT_RESULTS(m_ulActualRead[i]);
+#endif
+ }
+
+#ifdef TIME_FILEIO
+ INIT_RESULTS(m_ulActualFlush1);
+ INIT_RESULTS(m_ulActualFlush2);
+ INIT_RESULTS(m_ulActualCommitW);
+#endif
+
+ for (i = 0; i < 2; i++ )
+ ZERO_RESULTS(m_ulTotal[i]);
+
+}
+
+
+SCODE CStorageTest::Cleanup ()
+{
+ // delete the file
+ DeleteFile (m_pszFile);
+ if(m_piMalloc)
+ {
+ if (m_pbData)
+ m_piMalloc->Free(m_pbData);
+
+ m_pbData = NULL;
+
+ m_piMalloc->Release();
+ m_piMalloc = NULL;
+
+ }
+
+ UninitCOM();
+
+ return S_OK;
+}
+
+
+SCODE CStorageTest::Run ()
+{
+ CStopWatch sw;
+ HRESULT hr;
+ LPSTORAGE piStorage;
+ LPSTREAM piStream;
+ ULONG cb;
+ ULONG iIter;
+ ULONG iSize;
+ ULONG i, iCount;
+ ULARGE_INTEGER li;
+
+#ifdef TIME_FILEIO
+ ULONG ulTempTime;
+#endif
+ //Create and then write to docfile in selected mode
+ for (iIter=0; iIter<m_ulIterations; iIter++)
+ {
+ sw.Reset();
+ hr = StgCreateDocfile(m_pwszFile, m_flStgCreateFlags | STGM_WRITE
+ | STGM_CREATE | STGM_SHARE_EXCLUSIVE, 0, &piStorage);
+ m_ulStgCreateDocfile[iIter] = sw.Read();
+ Log(TEXT("StgCreateDocfile for writing"), hr);
+ if(FAILED(hr))
+ return hr;
+
+ sw.Reset();
+ hr = piStorage->CreateStream(L"CONTENTS", STGM_DIRECT |
+ STGM_CREATE | STGM_WRITE | STGM_SHARE_EXCLUSIVE,
+ 0, 0, &piStream);
+ m_ulCreateStream[iIter] = sw.Read();
+ Log(TEXT("CreateStream"), hr);
+
+
+ if (m_bDoSetSize)
+ {
+ ULISet32(li, m_ulTotalSize);
+ sw.Reset();
+ hr = piStream->SetSize(li);
+ m_ulSetSize[iIter] = sw.Read();
+ Log(TEXT("IStream::SetSize"), hr);
+ }
+
+#ifdef TIME_FILEIO
+ // reset all timings
+ GetFlushTiming(NULL, TRUE);
+ GetWriteTiming(NULL, TRUE);
+ GetReadTiming(NULL, TRUE);
+ GetSetFileTiming(NULL, TRUE);
+#endif
+ iCount = 0;
+ for ( iSize = m_iStartSize ; iSize <= m_iEndSize ; iSize *= 2)
+ {
+ for ( i = 0; i < m_iRepeatFactor; i++)
+ {
+ sw.Reset();
+ hr = piStream->Write((LPVOID)m_pbData, iSize, &cb);
+ m_ulStreamWrite[iCount][iIter] = sw.Read();
+ m_ulStreamWriteTotal[iIter] += m_ulStreamWrite[iCount][iIter];
+#ifdef TIME_FILEIO
+ GetWriteTiming(&m_ulActualWrite[iCount][iIter], TRUE);
+ GetSetFileTiming(&ulTempTime, TRUE);
+ m_ulActualWrite[iCount][iIter] += ulTempTime;
+#endif
+ iCount++;
+ }
+ }
+ Log(TEXT("IStream->Write X bytes"), hr);
+
+
+ sw.Reset();
+ piStream->Release();
+ m_ulStreamRelease1[iIter] = sw.Read();
+
+ if(m_flStgCreateFlags == STGM_TRANSACTED)
+ {
+ sw.Reset();
+ piStorage->Commit(STGC_DEFAULT);
+ m_ulStorageCommit[iIter] = sw.Read();
+ }
+
+ sw.Reset();
+ piStorage->Release();
+ m_ulStorageRelease1[iIter] = sw.Read();
+#ifdef TIME_FILEIO
+ GetFlushTiming(&m_ulActualFlush1[iIter], TRUE);
+ GetWriteTiming(&m_ulActualCommitW[iIter], TRUE);
+#endif
+
+ m_ulTotal[0][iIter] = m_ulStgCreateDocfile[iIter] +
+ m_ulCreateStream[iIter] +
+ m_ulSetSize[iIter] +
+ m_ulStreamWriteTotal[iIter] +
+ m_ulStreamRelease1[iIter] +
+ m_ulStorageCommit[iIter] +
+ m_ulStorageRelease1[iIter];
+ }
+
+
+ // now try reading from the file.
+ for (iIter=0; iIter<m_ulIterations; iIter++)
+ {
+ sw.Reset();
+ hr = StgOpenStorage(m_pwszFile, NULL, m_flStgCreateFlags | STGM_READ
+ | STGM_SHARE_EXCLUSIVE, NULL, 0, &piStorage);
+ m_ulStgOpenStorage[iIter] = sw.Read();
+ Log(TEXT("StgOpenStorage for reading"), hr);
+
+ sw.Reset();
+ hr = piStorage->OpenStream(L"CONTENTS", NULL, STGM_DIRECT | STGM_READ
+ | STGM_SHARE_EXCLUSIVE, 0, &piStream);
+ m_ulOpenStream[iIter] = sw.Read();
+ Log(TEXT("IStorage->OpenStream"), hr);
+
+
+#ifdef TIME_FILEIO
+ GetReadTiming(NULL, TRUE);
+ GetSetFileTiming(NULL, TRUE);
+#endif
+
+ iCount = 0;
+ if (m_bSequentialRead)
+ {
+ for (iSize = m_iStartSize ; iSize <= m_iEndSize ; iSize *= 2)
+ {
+ for (i = 0; i < m_iRepeatFactor; i++)
+ {
+ sw.Reset();
+ hr = piStream->Read((LPVOID)m_pbData, iSize, &cb);
+ m_ulStreamRead[iCount][iIter] = sw.Read();
+ m_ulStreamReadTotal[iIter] += m_ulStreamRead[iCount][iIter];
+#ifdef TIME_FILEIO
+ GetReadTiming(&m_ulActualRead[iCount][iIter], TRUE);
+ GetSetFileTiming(&ulTempTime, TRUE);
+ m_ulActualRead[iCount][iIter] += ulTempTime;
+#endif
+ iCount++;
+ }
+ }
+ Log(TEXT("IStorage->Read Sequential"), hr);
+ }
+ else
+ {
+ LARGE_INTEGER liSeekSize;
+ ULONG cbCurOffset = m_ulTotalSize;
+
+ iCount = 0;
+ for (iSize = m_iStartSize ; iSize <= m_iEndSize ; iSize *= 2)
+ {
+ for ( i =0; i< m_iRepeatFactor; i++)
+ {
+ cbCurOffset -= iSize;
+ LISet32(liSeekSize, cbCurOffset);
+
+ sw.Reset();
+ hr = piStream->Seek(liSeekSize, STREAM_SEEK_SET, NULL);
+ m_ulStreamSeek[iCount][iIter] = sw.Read();
+ m_ulStreamSeekTotal[iIter] += m_ulStreamSeek[iCount][iIter];
+
+ sw.Reset();
+ hr = piStream->Read((LPVOID)m_pbData, iSize, &cb);
+ m_ulStreamRead[iCount][iIter] = sw.Read();
+ m_ulStreamReadTotal[iIter] += m_ulStreamRead[i][iIter];
+#ifdef TIME_FILEIO
+ GetReadTiming(&m_ulActualRead[iCount][iIter], TRUE);
+ GetSetFileTiming(&ulTempTime, TRUE);
+ m_ulActualRead[iCount][iIter] += ulTempTime;
+#endif
+ iCount++;
+ }
+ }
+
+ Log(TEXT("IStorage->Read Random"), hr);
+ }
+
+ sw.Reset();
+ piStream->Release();
+ m_ulStreamRelease2[iIter] = sw.Read();
+
+ sw.Reset();
+ piStorage->Release();
+ m_ulStorageRelease2[iIter] = sw.Read();
+
+#ifdef TIME_FILEIO
+ GetFlushTiming(&m_ulActualFlush2[iIter], TRUE);
+#endif
+
+ m_ulTotal[1][iIter] = m_ulStgOpenStorage[iIter] +
+ m_ulOpenStream[iIter] +
+ m_ulStreamSeekTotal[iIter] +
+ m_ulStreamReadTotal[iIter] +
+ m_ulStreamRelease2[iIter] +
+ m_ulStorageRelease2[iIter];
+ }
+
+
+ // test if its a storage file (should be yes).
+ for (iIter=0; iIter<m_ulIterations; iIter++)
+ {
+ sw.Reset();
+ hr = StgIsStorageFile(m_pwszFile);
+ m_ulIsStorageFileYES[iIter] = sw.Read();
+ Log(TEXT("StgIsStorageFile on storage file"), hr);
+ }
+
+ // create a non-storage file and check if it is storage file
+ HANDLE hFile = CreateFile(m_pszFile, GENERIC_READ | GENERIC_WRITE, 0, NULL,
+ CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+ if (hFile == INVALID_HANDLE_VALUE)
+ {
+ Log(TEXT("Creation of non storage file"), E_FAIL);
+ return E_FAIL;
+ }
+ WriteFile(hFile, (LPSTR)m_pbData, m_iEndSize, &cb, NULL);
+ CloseHandle(hFile);
+
+ for (iIter=0; iIter<m_ulIterations; iIter++)
+ {
+ LPSTORAGE piStorage;
+
+ sw.Reset();
+ hr = StgIsStorageFile(m_pwszFile);
+ m_ulIsStorageFileNO[iIter] = sw.Read();
+ Log(TEXT("StgIsStorageFile on Non-storage file"),
+ (hr != S_OK) ? S_OK : E_FAIL);
+
+ sw.Reset();
+ hr =StgOpenStorage(m_pwszFile, NULL, STGM_DIRECT | STGM_READ
+ | STGM_SHARE_EXCLUSIVE, NULL, 0, &piStorage);
+ m_ulStgOpenStorageDRFAIL[iIter] = sw.Read();
+ Log(TEXT("StgOpenStorage on Non-storage file"),
+ (hr != S_OK) ? S_OK : E_FAIL);
+ }
+
+
+
+ return S_OK;
+}
+
+
+
+SCODE CStorageTest::Report (CTestOutput &output)
+{
+ TCHAR pszBuf[80];
+ ULONG i, iSize, iCount;
+#ifdef TIME_FILEIO
+ ULONG ulActualTotal[TEST_MAX_ITERATIONS];
+#endif
+
+ wsprintf(pszBuf, TEXT("Storage Test in %s Mode with %s Read/Writes"),
+ m_pszFileMode, m_pszReadMode);
+
+ output.WriteSectionHeader (Name(), pszBuf, *m_pInput);
+
+ wsprintf(pszBuf, TEXT("SetSize is %s\n\n"), m_bDoSetSize ? TEXT("ON") : TEXT("OFF"));
+ output.WriteString (pszBuf);
+
+ output.WriteResults (TEXT("IsStorageFile - YES"), m_ulIterations,
+ m_ulIsStorageFileYES);
+ output.WriteResults (TEXT("IsStorageFile - NO "), m_ulIterations,
+ m_ulIsStorageFileNO);
+ output.WriteResults (TEXT("StgOpenStorage D/R/FAIL"), m_ulIterations,
+ m_ulStgOpenStorageDRFAIL);
+ output.WriteString (TEXT("\n"));
+
+
+ output.WriteResults (TEXT("StgCreateDocfile "), m_ulIterations,
+ m_ulStgCreateDocfile);
+ output.WriteResults (TEXT("CreateStream "), m_ulIterations,
+ m_ulCreateStream);
+
+ output.WriteString (TEXT("\n"));
+
+ if (m_bDoSetSize)
+ output.WriteResults (TEXT("Stream SetSize "), m_ulIterations,
+ m_ulSetSize);
+
+#ifdef TIME_FILEIO
+ ZERO_RESULTS(ulActualTotal);
+#endif
+
+ iCount = 0;
+ for (iSize = m_iStartSize ; iSize <= m_iEndSize ; iSize *= 2)
+ {
+ for (i = 0; i < m_iRepeatFactor; i++)
+ {
+ wsprintf(pszBuf, TEXT("StreamWrite %-9d"), iSize);
+
+ output.WriteResults (pszBuf, m_ulIterations, m_ulStreamWrite[iCount]);
+
+#ifdef TIME_FILEIO
+ output.WriteResults (TEXT("Disk-hit time "), m_ulIterations, m_ulActualWrite[iCount]);
+
+ for ( ULONG xx = 0; xx < m_ulIterations; xx++)
+ ulActualTotal[xx] += m_ulActualWrite[iCount][xx];
+#endif
+ iCount++;
+ }
+
+ }
+
+ output.WriteResults (TEXT("StreamWrite Total "), m_ulIterations,
+ m_ulStreamWriteTotal);
+#ifdef TIME_FILEIO
+
+ output.WriteResults (TEXT("Actual Write Total "), m_ulIterations,
+ ulActualTotal);
+
+#endif
+
+
+
+ output.WriteString (TEXT("\n"));
+
+ output.WriteResults (TEXT("StreamRelease "), m_ulIterations,
+ m_ulStreamRelease1);
+
+ if (m_flStgCreateFlags == STGM_TRANSACTED)
+ {
+ output.WriteResults (TEXT("StorageCommit "), m_ulIterations,
+ m_ulStorageCommit);
+
+#ifdef TIME_FILEIO
+ output.WriteResults (TEXT("Disk hit time "), m_ulIterations,
+ m_ulActualCommitW);
+#endif
+ }
+
+ output.WriteResults (TEXT("StorageRelease "), m_ulIterations,
+ m_ulStorageRelease1);
+
+#ifdef TIME_FILEIO
+ output.WriteResults (TEXT("Actual Flush time "), m_ulIterations,
+ m_ulActualFlush1);
+#endif
+
+ output.WriteResults (TEXT("Total "), m_ulIterations,
+ m_ulTotal[0]);
+ output.WriteString (TEXT("\n\n"));
+
+ output.WriteResults (TEXT("StgOpenStorage "), m_ulIterations,
+ m_ulStgOpenStorage);
+ output.WriteResults (TEXT("OpenStream "), m_ulIterations,
+ m_ulOpenStream);
+
+ output.WriteString (TEXT("\n"));
+
+#ifdef TIME_FILEIO
+ ZERO_RESULTS(ulActualTotal);
+#endif
+
+ iCount = 0;
+ for (iSize = m_iStartSize ; iSize <= m_iEndSize ; iSize *= 2)
+ {
+ for (i = 0; i < m_iRepeatFactor; i++)
+ {
+ if (!m_bSequentialRead)
+ {
+ wsprintf(pszBuf, TEXT("StreamSeek %-9d"), m_iEndSize - iSize);
+ output.WriteResults (pszBuf, m_ulIterations, m_ulStreamSeek[iCount]);
+ }
+
+ wsprintf(pszBuf, TEXT("StreamRead %-9d"), iSize);
+ output.WriteResults (pszBuf, m_ulIterations, m_ulStreamRead[iCount]);
+
+#ifdef TIME_FILEIO
+ output.WriteResults (TEXT("Disk-hit time "), m_ulIterations, m_ulActualRead[iCount]);
+
+ for ( ULONG xx = 0; xx < m_ulIterations; xx++)
+ ulActualTotal[xx] += m_ulActualRead[iCount][xx];
+#endif
+ iCount++;
+ }
+ }
+
+ if (!m_bSequentialRead)
+ output.WriteResults (TEXT("StreamSeek Total "), m_ulIterations,
+ m_ulStreamSeekTotal);
+
+ output.WriteResults (TEXT("StreamRead Total "), m_ulIterations,
+ m_ulStreamReadTotal);
+
+
+#ifdef TIME_FILEIO
+ output.WriteResults (TEXT("Actual Read Total "), m_ulIterations,
+ ulActualTotal);
+#endif
+
+
+ output.WriteString (TEXT("\n"));
+
+ output.WriteResults (TEXT("StreamRelease "), m_ulIterations,
+ m_ulStreamRelease2);
+ output.WriteResults (TEXT("StorageRelease "), m_ulIterations,
+ m_ulStorageRelease2);
+#ifdef TIME_FILEIO
+ output.WriteResults (TEXT("Actual Flush time "), m_ulIterations,
+ m_ulActualFlush2);
+#endif
+
+ output.WriteResults (TEXT("Total "), m_ulIterations,
+ m_ulTotal[1]);
+ output.WriteString (TEXT("\n"));
+
+ return S_OK;
+}
+
+
diff --git a/private/oleutest/perform/cairole/tests/bm_stg.hxx b/private/oleutest/perform/cairole/tests/bm_stg.hxx
new file mode 100644
index 000000000..e685c2c4f
--- /dev/null
+++ b/private/oleutest/perform/cairole/tests/bm_stg.hxx
@@ -0,0 +1,100 @@
+//+------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1993.
+//
+// File: bm_stg.hxx
+//
+// Contents: test class definition
+//
+// Classes: CStorageTest
+//
+// Functions:
+//
+// History: 03-June-94 t-vadims Created
+//
+//--------------------------------------------------------------------------
+
+#ifndef _BM_STG_HXX_
+#define _BM_STG_HXX_
+
+#include <bm_base.hxx>
+
+#define MAX_REPS 100 // max repetions on write/read
+#define MAX_READS 100 // maximum number of total diferent reads/writes
+ // considering reps and diferent size
+
+
+class CStorageTest : public CTestBase
+{
+public:
+ virtual TCHAR *Name ();
+ virtual SCODE Setup (CTestInput *input);
+ virtual SCODE Run ();
+ virtual SCODE Report (CTestOutput &OutputFile);
+ virtual SCODE Cleanup ();
+
+private:
+
+ void InitTimings();
+
+ ULONG m_ulIterations;
+
+ // general storage API timings
+
+ ULONG m_ulIsStorageFileYES[TEST_MAX_ITERATIONS];
+ ULONG m_ulIsStorageFileNO[TEST_MAX_ITERATIONS];
+ ULONG m_ulStgOpenStorageDRFAIL[TEST_MAX_ITERATIONS];
+
+
+ // Storage file read/write timings
+ ULONG m_ulStgCreateDocfile[TEST_MAX_ITERATIONS];
+ ULONG m_ulCreateStream[TEST_MAX_ITERATIONS];
+ ULONG m_ulSetSize[TEST_MAX_ITERATIONS];
+ ULONG m_ulStreamWrite[MAX_READS][TEST_MAX_ITERATIONS];
+ ULONG m_ulStreamWriteTotal[TEST_MAX_ITERATIONS];
+ ULONG m_ulStreamRelease1[TEST_MAX_ITERATIONS];
+ ULONG m_ulStorageCommit[TEST_MAX_ITERATIONS];
+ ULONG m_ulStorageRelease1[TEST_MAX_ITERATIONS];
+
+ ULONG m_ulStgOpenStorage[TEST_MAX_ITERATIONS];
+ ULONG m_ulOpenStream[TEST_MAX_ITERATIONS];
+ ULONG m_ulStreamRead[MAX_READS][TEST_MAX_ITERATIONS];
+ ULONG m_ulStreamReadTotal[TEST_MAX_ITERATIONS];
+ ULONG m_ulStreamSeek[MAX_READS][TEST_MAX_ITERATIONS];
+ ULONG m_ulStreamSeekTotal[TEST_MAX_ITERATIONS];
+ ULONG m_ulStreamRelease2[TEST_MAX_ITERATIONS];
+ ULONG m_ulStorageRelease2[TEST_MAX_ITERATIONS];
+
+ // timings for my special ole32.dll with internal timing
+ ULONG m_ulActualWrite[MAX_READS][TEST_MAX_ITERATIONS];
+ ULONG m_ulActualRead[MAX_READS][TEST_MAX_ITERATIONS];
+ ULONG m_ulActualFlush1[TEST_MAX_ITERATIONS];
+ ULONG m_ulActualFlush2[TEST_MAX_ITERATIONS];
+ ULONG m_ulActualCommitW[TEST_MAX_ITERATIONS];
+
+ ULONG m_ulTotal[2][TEST_MAX_ITERATIONS];
+
+ BYTE *m_pbData; // data to be written to file
+
+ OLECHAR m_pwszFile[MAX_PATH]; // file name for ole
+ TCHAR m_pszFile[MAX_PATH]; // file name for WIN32
+ TCHAR m_pszFileMode[15]; // file access mode (TRANSACTED/DIRECTED)
+ TCHAR m_pszReadMode[15]; // read mode (RANDOM/SEQUENTIAL)
+
+ ULONG m_flStgCreateFlags; // file creation flags for StgCreateDocfile
+ // (STGM_TRANSACTED or STGM_DIRECT)
+
+ ULONG m_iStartSize; // start size of data to be written
+ ULONG m_iEndSize; // end size of data
+ ULONG m_ulTotalSize; // total size of the file
+ ULONG m_iRepeatFactor; // Number of writes for each size.
+ ULONG m_ulNumSizes; // number of diferent write sizes
+
+ BOOL m_bSequentialRead; // flage for Sequential and Random read
+ BOOL m_bDoSetSize;
+
+ LPMALLOC m_piMalloc; // point to task malloc interface
+};
+
+#endif
diff --git a/private/oleutest/perform/cairole/tests/bmguid.cxx b/private/oleutest/perform/cairole/tests/bmguid.cxx
new file mode 100644
index 000000000..b116ecd03
--- /dev/null
+++ b/private/oleutest/perform/cairole/tests/bmguid.cxx
@@ -0,0 +1,44 @@
+//-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1993.
+//
+// File: bmguid.cxx
+//
+// Contents: OLE test guids
+//
+// Classes:
+//
+// Functions:
+//
+// History: 12-August-93 t-martig Created
+//
+//--------------------------------------------------------------------------
+
+#include <headers.cxx>
+#pragma hdrstop
+
+#include <oletest.hxx>
+
+const GUID CLSID_COleTestClass =
+ {0x20730701,0x0001,0x0008,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}};
+const GUID CLSID_COleTestClass1 =
+ {0x20730711,0x0001,0x0008,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}};
+const GUID CLSID_COleTestClass2 =
+ {0x20730712,0x0001,0x0008,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}};
+const GUID CLSID_COleTestClass3 =
+ {0x20730713,0x0001,0x0008,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}};
+const GUID CLSID_COleTestClass4 =
+ {0x20730714,0x0001,0x0008,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}};
+const GUID CLSID_COleTestClass5 =
+ {0x20730715,0x0001,0x0008,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}};
+const GUID CLSID_COleTestClass6 =
+ {0x20730716,0x0001,0x0008,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}};
+const GUID CLSID_COleTestClass7 =
+ {0x20730717,0x0001,0x0008,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}};
+const GUID CLSID_COleTestClass8 =
+ {0x20730718,0x0001,0x0008,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}};
+
+
+const GUID CLSID_TestProp =
+ {0x20730722,0x0001,0x0008,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}};
diff --git a/private/oleutest/perform/cairole/tests/bmp_stg.cxx b/private/oleutest/perform/cairole/tests/bmp_stg.cxx
new file mode 100644
index 000000000..acfdf9e5d
--- /dev/null
+++ b/private/oleutest/perform/cairole/tests/bmp_stg.cxx
@@ -0,0 +1,471 @@
+//+------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1993.
+//
+// File: bmp_stg.cxx
+//
+// Contents: Generic Storage parser based test
+//
+// Classes: CStorageParserTest, CStorageParser
+//
+// Functions:
+//
+// History: 15-June-94 t-vadims Created
+//
+//--------------------------------------------------------------------------
+
+#include <headers.cxx>
+#pragma hdrstop
+
+#include <valid.h>
+#include <tchar.h>
+#include <bmp_stg.hxx>
+
+//+------------------------------------------------------------------------
+//
+// Class: CStorageParserTest
+//
+// Functions:
+//
+// History: 15-June-94 t-vadims Created
+//
+//--------------------------------------------------------------------------
+
+SCODE CStorageParserTest::SetParserObject ()
+{
+ m_pParser = new CStorageParser;
+ return S_OK;
+}
+
+
+SCODE CStorageParserTest::DeleteParserObject ()
+{
+ delete m_pParser;
+ return S_OK;
+}
+
+
+TCHAR* CStorageParserTest::Name ()
+{
+ return TEXT("StorageParserTest");
+}
+
+
+TCHAR *CStorageParserTest::SectionHeader()
+{
+ return TEXT("Storage test from log");
+}
+
+
+
+//+------------------------------------------------------------------------
+//
+// Class: CStorageParser
+//
+// Functions:
+//
+// History: 15-June-94 t-vadims Created
+//
+//--------------------------------------------------------------------------
+
+#define STATE_OFFSET 10 // location of "In"/"Out" in log string
+#define NAME_OFFSET 14 // location of command name in log string
+
+#define MAX_NAME 50
+
+#define DEF_ARRAYSIZE 10
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CStorageParser::Setup, public
+//
+// Synopsis: Makes all neccessary initializations.
+//
+// History: 16-June-94 t-vadims Created
+//
+//--------------------------------------------------------------------
+SCODE CStorageParser::Setup (CTestInput *pInput)
+{
+ SCODE sc;
+
+
+ sc = CoGetMalloc(MEMCTX_TASK, &m_piMalloc);
+ if (FAILED(sc))
+ return sc;
+
+ m_iStreamCount = 0;
+ m_iStreamArraySize = DEF_ARRAYSIZE;
+ m_aulStreamID = (ULONG *)m_piMalloc->Alloc(m_iStreamArraySize *
+ sizeof(ULONG));
+ m_apStreams = (LPSTREAM *)m_piMalloc->Alloc(m_iStreamArraySize *
+ sizeof(LPSTREAM));
+
+ m_iStorageCount = 0;
+ m_iStorageArraySize = DEF_ARRAYSIZE;
+ m_aulStorageID = (ULONG *)m_piMalloc->Alloc(m_iStorageArraySize *
+ sizeof(ULONG));
+ m_apStorages = (LPSTORAGE *)m_piMalloc->Alloc(m_iStorageArraySize *
+ sizeof(LPSTORAGE));
+
+ m_iInstrCount = 0;
+ m_iInstrArraySize = DEF_ARRAYSIZE;
+ m_apInstrData = (LPINSTRDATA *)m_piMalloc->Alloc(m_iInstrArraySize *
+ sizeof(LPINSTRDATA));
+
+
+ m_bGotFirstPart = FALSE;
+
+ if (m_apInstrData == NULL || m_aulStorageID == NULL ||
+ m_apStorages == NULL || m_aulStreamID == NULL ||
+ m_apStreams == NULL )
+ {
+ Cleanup();
+ Log(TEXT("Setup can't allocate memory"), E_OUTOFMEMORY);
+ return E_OUTOFMEMORY;
+ }
+
+ return S_OK;
+}
+
+//+-------------------------------------------------------------------
+//
+// Member: CStorageParser::Cleanup, public
+//
+// Synopsis: Makes all neccessary cleanup
+//
+// History: 16-June-94 t-vadims Created
+//
+//--------------------------------------------------------------------
+SCODE CStorageParser::Cleanup ()
+{
+ /* do any neccessary clean up */
+ if(m_piMalloc)
+ {
+ if (m_aulStreamID)
+ m_piMalloc->Free(m_aulStreamID);
+ if (m_apStreams)
+ m_piMalloc->Free(m_apStreams);
+ if (m_aulStorageID)
+ m_piMalloc->Free(m_aulStorageID);
+ if (m_apStorages)
+ m_piMalloc->Free(m_apStorages);
+
+
+ for (ULONG i = 0; i < m_iInstrCount; i++)
+ delete m_apInstrData[i];
+
+ if (m_apInstrData)
+ m_piMalloc->Free(m_apInstrData);
+
+ m_piMalloc->Release();
+ m_piMalloc = NULL;
+ }
+ return S_OK;
+}
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CStorageParser::AddInstruction, public
+//
+// Synopsis: Parse new instruction and add it to array if it is valid
+//
+// Return: ID of instruction
+//
+// History: 16-June-94 t-vadims Created
+//
+//--------------------------------------------------------------------
+ULONG CStorageParser::AddInstruction(LPTSTR pszFirstPart, LPTSTR pszSecondPart)
+{
+ ULONG ulInstrID;
+ SCODE sc;
+
+ TCHAR szInstrName[MAX_NAME];
+ TCHAR szSecondName[MAX_NAME];
+
+ if (_tcsncmp(pszFirstPart + STATE_OFFSET, TEXT("In"), 2) != 0)
+ return INVALID_INSTRUCTION;
+
+ if (_tcsncmp(pszSecondPart + STATE_OFFSET, TEXT("Out"), 3) != 0)
+ return INVALID_INSTRUCTION;
+
+
+ // check if the same instruction name;
+ GetInstructionName(szInstrName, pszFirstPart);
+ GetInstructionName(szSecondName, pszSecondPart);
+
+ if(_tcscmp(szInstrName, szSecondName) != 0)
+ return INVALID_INSTRUCTION;
+
+
+ // determine the instruction
+ ulInstrID = INVALID_INSTRUCTION;
+ for (ULONG i = 0; i < m_iMaxInstruction; i++)
+ if (_tcscmp(szInstrName, m_aInstructions[i].szLogName) == 0)
+ {
+ ulInstrID = i;
+ break;
+ }
+
+ if(ulInstrID == INVALID_INSTRUCTION)
+ return INVALID_INSTRUCTION;
+
+ // fill appropriate structure fields
+ SInstrData *pInstrData = new SInstrData;
+ pInstrData->ulInstrID = ulInstrID;
+
+ sc = (this->*m_aInstructions[ulInstrID].Parse)(pInstrData,
+ pszFirstPart,
+ pszSecondPart);
+
+ if (FAILED(sc))
+ {
+ delete pInstrData;
+ return INVALID_INSTRUCTION;
+ }
+
+ return AddNewInstrData(pInstrData);
+}
+
+//+-------------------------------------------------------------------
+//
+// Member: CStorageParser::IgnoreInstruction, private
+//
+// Synopsis: Check if this instruction should be ignored.
+//
+// History: 16-June-94 t-vadims Created
+//
+//--------------------------------------------------------------------
+BOOL CStorageParser::IgnoreInstruction(LPTSTR pszInstr)
+{
+ TCHAR szName[MAX_NAME];
+
+ // We Ignore those instructions that are completely implemented
+ // in terms of other instructions that are also logged.
+
+ GetInstructionName(szName, pszInstr);
+
+ if (_tcscmp (szName, TEXT("CExposedStream::QueryInterface")) == 0 ||
+ _tcscmp (szName, TEXT("CExposedDocFile::QueryInterface")) == 0 ||
+ _tcscmp (szName, TEXT("CExposedStream::CopyTo")) == 0 ||
+ _tcscmp (szName, TEXT("CExposedDocFile::MoveElementTo")) == 0 ||
+ _tcscmp (szName, TEXT("CExposedDocFile::CopyTo")) == 0 ||
+ _tcscmp (szName, TEXT("ExposedDocFile::CopyTo")) == 0
+ )
+ {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+//+-------------------------------------------------------------------
+//
+// Member: CStorageParser::ParseNewInstruction, public
+//
+// Synopsis: Parse new line of file, and return its id.
+//
+// History: 16-June-94 t-vadims Created
+//
+//--------------------------------------------------------------------
+ULONG CStorageParser::ParseNewInstruction(LPTSTR pszInstr)
+{
+ ULONG ulID;
+
+ if (IgnoreInstruction(pszInstr))
+ return NOT_INSTRUCTION;
+
+ if (m_bGotFirstPart)
+ {
+ // out part of instruction. We can now add it.
+ ulID = AddInstruction(m_szBuffer, pszInstr);
+ m_bGotFirstPart = FALSE;
+ }
+ else
+ {
+ // save In part of instruction, and fake CTimerBase into
+ // thinking that this wasn't an instruction.
+ _tcscpy(m_szBuffer, pszInstr);
+ ulID = NOT_INSTRUCTION;
+ m_bGotFirstPart = TRUE;
+ }
+
+ return ulID;
+}
+
+//+-------------------------------------------------------------------
+//
+// Member: CStorageParser::ExecuteInstruction, public
+//
+// Synopsis: Execute instruction with given id.
+//
+// Return: time taken to execute it.
+//
+// History: 16-June-94 t-vadims Created
+//
+//--------------------------------------------------------------------
+ULONG CStorageParser::ExecuteInstruction(ULONG ulID)
+{
+ SInstrData *pInstrData = m_apInstrData[ulID];
+
+ return (this->*m_aInstructions[pInstrData->ulInstrID].Execute)(pInstrData);
+}
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CStorageParser::InstructionName, public
+//
+// Synopsis: Return name of instruction.
+//
+// History: 16-June-94 t-vadims Created
+//
+//--------------------------------------------------------------------
+TCHAR * CStorageParser::InstructionName(ULONG ulID)
+{
+ SInstrData *pInstrData = m_apInstrData[ulID];
+
+ if (m_aInstructions[pInstrData->ulInstrID].GetName != NULL)
+ return (this->*m_aInstructions[pInstrData->ulInstrID].GetName)(pInstrData);
+ else
+ return m_aInstructions[pInstrData->ulInstrID].szPrintName;
+}
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CStorageParser::GetInstructionName, public
+//
+// Synopsis: Extract instruction name from the instruction.
+//
+// History: 16-June-94 t-vadims Created
+//
+//--------------------------------------------------------------------
+SCODE CStorageParser::GetInstructionName (LPTSTR pszName, LPTSTR pszInstruction)
+{
+ _stscanf(pszInstruction + NAME_OFFSET, TEXT("%[^(]"), pszName);
+ return S_OK;
+}
+
+//+-------------------------------------------------------------------
+//
+// Member: CStorageParser::AddNewInstrData, public
+//
+// Synopsis: Adds new instruction to instrData array.
+//
+// History: 16-June-94 t-vadims Created
+//
+//--------------------------------------------------------------------
+ULONG CStorageParser::AddNewInstrData (LPINSTRDATA pInstrData)
+{
+ if (m_iInstrCount >= m_iInstrArraySize)
+ {
+ m_iInstrArraySize *= 2;
+ m_apInstrData = (LPINSTRDATA *)m_piMalloc->Realloc(m_apInstrData,
+ m_iInstrArraySize * sizeof(LPINSTRDATA));
+ }
+
+ m_apInstrData[m_iInstrCount] = pInstrData;
+
+ return m_iInstrCount++;
+}
+
+//+-------------------------------------------------------------------
+//
+// Member: CStorageParser::FindStorageID, public
+//
+// Synopsis: finds or creates new storage, based on ID.
+//
+// History: 16-June-94 t-vadims Created
+//
+//--------------------------------------------------------------------
+ULONG CStorageParser::FindStorageID (ULONG ulStgID)
+{
+ for (ULONG i = 0; i < m_iStorageCount; i++)
+ if (m_aulStorageID[i] == ulStgID)
+ return i;
+
+ if (m_iStorageCount >= m_iStorageArraySize)
+ {
+ m_iStorageArraySize *= 2;
+ m_aulStorageID = (ULONG *)m_piMalloc->Realloc(m_aulStorageID,
+ m_iStorageArraySize * sizeof(ULONG));
+
+ m_apStorages = (LPSTORAGE *)m_piMalloc->Realloc(m_apStorages,
+ m_iStorageArraySize * sizeof(LPSTORAGE));
+
+ }
+ m_aulStorageID[m_iStorageCount] = ulStgID;
+ m_apStorages[m_iStorageCount] = NULL;
+
+ return m_iStorageCount++;
+}
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CStorageParser::FindStreamID, public
+//
+// Synopsis: finds or creates new stream, based on ID.
+//
+// History: 16-June-94 t-vadims Created
+//
+//--------------------------------------------------------------------
+ULONG CStorageParser::FindStreamID (ULONG ulStreamID)
+{
+ for (ULONG i = 0; i < m_iStreamCount; i++)
+ if (m_aulStreamID[i] == ulStreamID)
+ return i;
+
+ if (m_iStreamCount >= m_iStreamArraySize)
+ {
+ m_iStreamArraySize *=2;
+ m_aulStreamID = (ULONG *)m_piMalloc->Realloc(m_aulStreamID,
+ m_iStreamArraySize * sizeof(ULONG));
+
+ m_apStreams = (LPSTREAM *)m_piMalloc->Realloc(m_apStreams,
+ m_iStreamArraySize * sizeof(LPSTREAM));
+
+ }
+ m_aulStreamID[m_iStreamCount] = ulStreamID;
+ m_apStreams[m_iStreamCount] = NULL;
+
+ return m_iStreamCount++;
+}
+
+//+-------------------------------------------------------------------
+//
+// Members: CStorageParser::CheckThisStorageID, public
+// CStorageParser::CheckThisStreamID, public
+//
+// Synopsis: Check if storage/stream with given id can be dereferenced.
+// (must be non null).
+//
+// History: 16-June-94 t-vadims Created
+//
+//--------------------------------------------------------------------
+
+SCODE CStorageParser::CheckThisStorageID(ULONG ulStorageID)
+{
+ if(m_apStorages[ulStorageID] == NULL ||
+ ! IsValidInterface(m_apStorages[ulStorageID]))
+ {
+ Log(TEXT("Trying to dereference an unassigned Storage"), E_FAIL);
+ return E_FAIL;
+ }
+ return S_OK;
+}
+
+
+SCODE CStorageParser::CheckThisStreamID(ULONG ulStreamID)
+{
+ if(m_apStreams[ulStreamID] == NULL ||
+ ! IsValidInterface(m_apStreams[ulStreamID]))
+ {
+ Log(TEXT("Trying to dereference an unassigned Stream"), E_FAIL);
+ return E_FAIL;
+ }
+ return S_OK;
+}
diff --git a/private/oleutest/perform/cairole/tests/bmp_stg.hxx b/private/oleutest/perform/cairole/tests/bmp_stg.hxx
new file mode 100644
index 000000000..e15559154
--- /dev/null
+++ b/private/oleutest/perform/cairole/tests/bmp_stg.hxx
@@ -0,0 +1,215 @@
+//+------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1994.
+//
+// File: bmp_stg.hxx
+//
+// Contents: Generic Storage parser test
+//
+// Classes: CStorageParserTest, CStorageParser
+//
+// Functions:
+//
+// History: 15-June-94 t-vadims Created
+//
+//--------------------------------------------------------------------------
+
+#ifndef _BMP_STG_HXX_
+#define _BMP_STG_HXX_
+
+#include <bm_parse.hxx>
+
+
+
+class CStorageParserTest : public CTimerBase
+{
+public:
+ virtual SCODE SetParserObject ();
+ virtual SCODE DeleteParserObject ();
+
+ virtual TCHAR *Name ();
+ virtual TCHAR* SectionHeader ();
+};
+
+
+
+struct SInstrData;
+struct SInstrInfo;
+
+typedef SInstrData *LPINSTRDATA;
+
+
+
+class CStorageParser : public CParserBase
+{
+public:
+ virtual SCODE Setup (CTestInput *pInput);
+ virtual SCODE Cleanup ();
+
+ virtual ULONG ParseNewInstruction (LPTSTR pszNewInstruction);
+ virtual ULONG ExecuteInstruction (ULONG ulInstrID);
+ virtual TCHAR* InstructionName (ULONG ulInstrID);
+
+private:
+
+ BOOL IgnoreInstruction(LPTSTR pszInstr);
+ ULONG AddInstruction (LPTSTR pszFirstPart, LPTSTR pszSecondPart);
+ ULONG AddNewInstrData (LPINSTRDATA pInstrData);
+
+ SCODE GetInstructionName (LPTSTR pszName, LPTSTR pszInstruction);
+
+ ULONG FindStorageID (ULONG ulStgID);
+ ULONG FindStreamID (ULONG ulStrmID);
+ SCODE CheckThisStorageID (ULONG ulStgID);
+ SCODE CheckThisStreamID (ULONG ulStgID);
+
+ SCODE CheckForElementName(LPINSTRDATA pInstrData, DWORD dwType);
+
+ ULONG Execute_StgIsStorageFile(LPINSTRDATA);
+ SCODE Parse_StgIsStorageFile(LPINSTRDATA, LPTSTR, LPTSTR);
+
+ ULONG Execute_StgOpenStorage(LPINSTRDATA);
+ SCODE Parse_StgOpenStorage(LPINSTRDATA, LPTSTR, LPTSTR);
+
+ ULONG Execute_StgCreateDocFile(LPINSTRDATA);
+ SCODE Parse_StgCreateDocFile(LPINSTRDATA, LPTSTR, LPTSTR);
+
+ ULONG Execute_IStorageAddRef(LPINSTRDATA);
+ SCODE Parse_IStorageAddRef(LPINSTRDATA, LPTSTR, LPTSTR);
+
+ ULONG Execute_IStorageRelease(LPINSTRDATA);
+ SCODE Parse_IStorageRelease(LPINSTRDATA, LPTSTR, LPTSTR);
+
+ ULONG Execute_IStorageSetClass(LPINSTRDATA);
+ SCODE Parse_IStorageSetClass(LPINSTRDATA, LPTSTR, LPTSTR);
+
+ ULONG Execute_IStorageSetElementTimes(LPINSTRDATA);
+ SCODE Parse_IStorageSetElementTimes(LPINSTRDATA, LPTSTR, LPTSTR);
+
+ ULONG Execute_IStorageCommit(LPINSTRDATA);
+ SCODE Parse_IStorageCommit(LPINSTRDATA, LPTSTR, LPTSTR);
+
+ ULONG Execute_IStorageRevert(LPINSTRDATA);
+ SCODE Parse_IStorageRevert(LPINSTRDATA, LPTSTR, LPTSTR);
+
+ ULONG Execute_IStorageStat(LPINSTRDATA);
+ SCODE Parse_IStorageStat(LPINSTRDATA, LPTSTR, LPTSTR);
+
+ ULONG Execute_IStorageSetStateBits(LPINSTRDATA);
+ SCODE Parse_IStorageSetStateBits(LPINSTRDATA, LPTSTR, LPTSTR);
+
+ ULONG Execute_IStorageCreateStorage(LPINSTRDATA);
+ SCODE Parse_IStorageCreateStorage(LPINSTRDATA, LPTSTR, LPTSTR);
+
+ ULONG Execute_IStorageOpenStorage(LPINSTRDATA);
+ SCODE Parse_IStorageOpenStorage(LPINSTRDATA, LPTSTR, LPTSTR);
+
+ ULONG Execute_IStorageCreateStream(LPINSTRDATA);
+ SCODE Parse_IStorageCreateStream(LPINSTRDATA, LPTSTR, LPTSTR);
+
+ ULONG Execute_IStorageOpenStream(LPINSTRDATA);
+ SCODE Parse_IStorageOpenStream(LPINSTRDATA, LPTSTR, LPTSTR);
+
+ ULONG Execute_IStorageDestroyElement(LPINSTRDATA);
+ SCODE Parse_IStorageDestroyElement(LPINSTRDATA, LPTSTR, LPTSTR);
+
+ ULONG Execute_IStorageRenameElement(LPINSTRDATA);
+ SCODE Parse_IStorageRenameElement(LPINSTRDATA, LPTSTR, LPTSTR);
+
+ ULONG Execute_IStreamAddRef(LPINSTRDATA);
+ SCODE Parse_IStreamAddRef(LPINSTRDATA, LPTSTR, LPTSTR);
+
+ ULONG Execute_IStreamRelease(LPINSTRDATA);
+ SCODE Parse_IStreamRelease(LPINSTRDATA, LPTSTR, LPTSTR);
+
+ ULONG Execute_IStreamCommit(LPINSTRDATA);
+ SCODE Parse_IStreamCommit(LPINSTRDATA, LPTSTR, LPTSTR);
+
+ ULONG Execute_IStreamClone(LPINSTRDATA);
+ SCODE Parse_IStreamClone(LPINSTRDATA, LPTSTR, LPTSTR);
+
+ ULONG Execute_IStreamRevert(LPINSTRDATA);
+ SCODE Parse_IStreamRevert(LPINSTRDATA, LPTSTR, LPTSTR);
+
+ ULONG Execute_IStreamSetSize(LPINSTRDATA);
+ SCODE Parse_IStreamSetSize(LPINSTRDATA, LPTSTR, LPTSTR);
+
+ ULONG Execute_IStreamRead(LPINSTRDATA);
+ SCODE Parse_IStreamRead(LPINSTRDATA, LPTSTR, LPTSTR);
+ TCHAR* GetName_IStreamRead(LPINSTRDATA);
+
+ ULONG Execute_IStreamStat(LPINSTRDATA);
+ SCODE Parse_IStreamStat(LPINSTRDATA, LPTSTR, LPTSTR);
+
+ ULONG Execute_IStreamWrite(LPINSTRDATA);
+ SCODE Parse_IStreamWrite(LPINSTRDATA, LPTSTR, LPTSTR);
+ TCHAR* GetName_IStreamWrite(LPINSTRDATA);
+
+ ULONG Execute_IStreamSeek(LPINSTRDATA);
+ SCODE Parse_IStreamSeek(LPINSTRDATA, LPTSTR, LPTSTR);
+ TCHAR* GetName_IStreamSeek(LPINSTRDATA);
+
+
+ static SInstrInfo m_aInstructions[]; // All possible instructions
+ static ULONG m_iMaxInstruction; // number of instructions in above array
+
+ LPINSTRDATA *m_apInstrData; // Array of parameter data for each instruction
+ ULONG m_iInstrArraySize; // size of array
+ ULONG m_iInstrCount; // number of instructions
+
+
+ ULONG *m_aulStorageID; // array of Storage ids. (addresses from log file)
+ LPSTORAGE *m_apStorages; // array of Storages corresponding to above ids
+ ULONG m_iStorageArraySize; // Size of 2 arrays above
+ ULONG m_iStorageCount; // number of storages
+
+ ULONG *m_aulStreamID; // array of Streams ids (address from log file)
+ LPSTREAM *m_apStreams; // array of Streams corresponding to above ids
+ ULONG m_iStreamArraySize; // Size of 2 arrays above
+ ULONG m_iStreamCount; // number of storages
+
+ BOOL m_bGotFirstPart; // flag if in the middle of 2-line instructions
+ TCHAR m_szBuffer[120]; // Used as a temporary Buffer for either
+ // Copy of first line in 2-line instructions or
+ // instruction name.
+
+ LPMALLOC m_piMalloc; // task specific allocator.
+
+};
+
+
+typedef SCODE (CStorageParser::*LPPARSE)(LPINSTRDATA, LPTSTR, LPTSTR);
+typedef ULONG (CStorageParser::*LPEXECUTE)(LPINSTRDATA);
+typedef TCHAR *(CStorageParser::*LPGETNAME)(LPINSTRDATA);
+
+//
+// Structure to hold parameters for particular instruction
+//
+struct SInstrData
+{
+ ULONG ulInstrID;
+ ULONG ThisID;
+ ULONG OutID;
+ DWORD dwParam1;
+ DWORD dwParam2;
+ DWORD dwParam3;
+ OLECHAR *wszParam2;
+ OLECHAR wszParam[MAX_PATH];
+};
+
+//
+// Structure to hold info about each possible instruction
+//
+struct SInstrInfo
+{
+ TCHAR *szLogName; // name as found in log file
+ TCHAR *szPrintName; // name to be outputed
+ LPPARSE Parse; // pointer to function that would parse this instruction
+ LPEXECUTE Execute; // pointer to function that would execute this instruction
+ LPGETNAME GetName; // pointer to func returning name. Could be NULL.
+};
+
+
+
+#endif
diff --git a/private/oleutest/perform/cairole/tests/bmp_stg2.cxx b/private/oleutest/perform/cairole/tests/bmp_stg2.cxx
new file mode 100644
index 000000000..af0aefa23
--- /dev/null
+++ b/private/oleutest/perform/cairole/tests/bmp_stg2.cxx
@@ -0,0 +1,1425 @@
+//+------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1994.
+//
+// File: bmp_stg2.cxx
+//
+// Contents: Generic Storage parser based test file 2
+//
+// Classes: CStorageParser
+//
+// Functions: Parse and Execute functions for each instruction.
+//
+// History: 20-June-94 t-vadims Created
+//
+//--------------------------------------------------------------------------
+
+#include <headers.cxx>
+#pragma hdrstop
+
+#include <bmp_stg.hxx>
+#include <tchar.h>
+
+#define STGTY_ANY 0 // any storage element, stream or storage
+
+//
+// Static array of info for each instruction
+//
+SInstrInfo CStorageParser::m_aInstructions[] =
+ { { TEXT("StgIsStorageFile"),
+ TEXT("StgIsStorageFile "),
+ Parse_StgIsStorageFile,
+ Execute_StgIsStorageFile,
+ NULL },
+
+ { TEXT("StgCreateDocFile"),
+ TEXT("StgCreateDocFile "),
+ Parse_StgCreateDocFile,
+ Execute_StgCreateDocFile,
+ NULL },
+
+ { TEXT("OpenStorage"),
+ TEXT("StgOpenStorage "),
+ Parse_StgOpenStorage,
+ Execute_StgOpenStorage ,
+ NULL },
+
+ { TEXT("CExposedDocFile::AddRef"),
+ TEXT("IStorage::AddRef "),
+ Parse_IStorageAddRef,
+ Execute_IStorageAddRef ,
+ NULL },
+
+ { TEXT("CExposedDocFile::Release"),
+ TEXT("IStorage::Release "),
+ Parse_IStorageRelease,
+ Execute_IStorageRelease ,
+ NULL },
+
+ { TEXT("CExposedDocFile::Commit"),
+ TEXT("IStorage::Commit "),
+ Parse_IStorageCommit,
+ Execute_IStorageCommit ,
+ NULL },
+
+ { TEXT("CExposedDocFile::Revert"),
+ TEXT("IStorage::Revert "),
+ Parse_IStorageRelease,
+ Execute_IStorageRelease ,
+ NULL },
+
+ { TEXT("CExposedDocFile::CreateStream"),
+ TEXT("IStorage::CreateStream"),
+ Parse_IStorageCreateStream,
+ Execute_IStorageCreateStream ,
+ NULL },
+
+ { TEXT("CExposedDocFile::OpenStream"),
+ TEXT("IStorage::OpenStream "),
+ Parse_IStorageOpenStream,
+ Execute_IStorageOpenStream ,
+ NULL },
+
+ { TEXT("CExposedDocFile::CreateStorage"),
+ TEXT("IStorage::CreateStorage"),
+ Parse_IStorageCreateStorage,
+ Execute_IStorageCreateStorage ,
+ NULL },
+
+ { TEXT("CExposedDocFile::OpenStorage"),
+ TEXT("IStorage::OpenStorage"),
+ Parse_IStorageOpenStorage,
+ Execute_IStorageOpenStorage ,
+ NULL },
+
+ { TEXT("CExposedDocFile::DestroyElement"),
+ TEXT("IStorage::DestroyElement"),
+ Parse_IStorageDestroyElement,
+ Execute_IStorageDestroyElement ,
+ NULL },
+
+ { TEXT("CExposedDocFile::RenameElement"),
+ TEXT("IStorage::RenameElement"),
+ Parse_IStorageRenameElement,
+ Execute_IStorageRenameElement ,
+ NULL },
+
+ { TEXT("CExposedDocFile::SetStateBits"),
+ TEXT("IStorage::SetStateBits"),
+ Parse_IStorageSetStateBits,
+ Execute_IStorageSetStateBits ,
+ NULL },
+
+ { TEXT("CExposedDocFile::SetElementTimes"),
+ TEXT("IStorage::SetElementTimes"),
+ Parse_IStorageSetElementTimes,
+ Execute_IStorageSetElementTimes ,
+ NULL },
+
+ { TEXT("CExposedDocFile::SetClass"),
+ TEXT("IStorage::SetClass "),
+ Parse_IStorageSetClass,
+ Execute_IStorageSetClass ,
+ NULL },
+
+ { TEXT("CExposedDocFile::Stat"),
+ TEXT("IStorage::Stat "),
+ Parse_IStorageStat,
+ Execute_IStorageStat ,
+ NULL },
+
+ { TEXT("CExposedStream::AddRef"),
+ TEXT("IStream::AddRef "),
+ Parse_IStreamAddRef,
+ Execute_IStreamAddRef ,
+ NULL },
+
+ { TEXT("CExposedStream::Release"),
+ TEXT("IStream::Release "),
+ Parse_IStreamRelease,
+ Execute_IStreamRelease ,
+ NULL },
+
+ { TEXT("CExposedStream::Commit"),
+ TEXT("IStream::Commit "),
+ Parse_IStreamCommit,
+ Execute_IStreamCommit ,
+ NULL },
+
+ { TEXT("CExposedStream::Clone"),
+ TEXT("IStream::Clone "),
+ Parse_IStreamClone,
+ Execute_IStreamClone ,
+ NULL },
+
+ { TEXT("CExposedStream::Revert"),
+ TEXT("IStream::Revert "),
+ Parse_IStreamRevert,
+ Execute_IStreamRevert ,
+ NULL },
+
+ { TEXT("CExposedStream::SetSize"),
+ TEXT("IStream::SetSize "),
+ Parse_IStreamSetSize,
+ Execute_IStreamSetSize ,
+ NULL },
+
+ { TEXT("CExposedStream::Write"),
+ TEXT("IStream::Write "),
+ Parse_IStreamWrite,
+ Execute_IStreamWrite ,
+ GetName_IStreamWrite },
+
+ { TEXT("CExposedStream::Read"),
+ TEXT("IStream::Read "),
+ Parse_IStreamRead,
+ Execute_IStreamRead ,
+ GetName_IStreamRead },
+
+ { TEXT("CExposedStream::Seek"),
+ TEXT("IStream::Seek "),
+ Parse_IStreamSeek,
+ Execute_IStreamSeek ,
+ GetName_IStreamSeek },
+
+ { TEXT("CExposedStream::Stat"),
+ TEXT("IStream::Stat "),
+ Parse_IStreamStat,
+ Execute_IStreamStat ,
+ NULL }
+ };
+
+
+//
+// Number of instructions in the above array
+//
+ULONG CStorageParser::m_iMaxInstruction =
+ sizeof(CStorageParser::m_aInstructions) /
+ sizeof(CStorageParser::m_aInstructions[0]);
+
+
+//
+// Tries to find an "almost" matching name in the storage.
+// Used to get around bug of loging functions, that print a '.' instead of unprintable
+// characters.
+SCODE CStorageParser::CheckForElementName(LPINSTRDATA pInstrData, DWORD dwType)
+{
+ HRESULT hr;
+ LPENUMSTATSTG pEnum;
+ STATSTG StatStg;
+ BOOL bFound = FALSE;
+
+
+ hr = m_apStorages[pInstrData->ThisID]->EnumElements(0, NULL, 0, &pEnum);
+
+ while (!bFound && pEnum->Next(1, &StatStg, NULL) == S_OK)
+ {
+ if (StatStg.type == dwType || dwType == STGTY_ANY)
+ {
+ // if the names are the same except for the first letter, copy that letter.
+ if (wcscmp(StatStg.pwcsName + 1, pInstrData->wszParam + 1) == 0)
+ {
+ pInstrData->wszParam[0] = StatStg.pwcsName[0];
+ bFound = TRUE;
+ }
+
+ }
+ m_piMalloc->Free(StatStg.pwcsName);
+ }
+
+ pEnum->Release();
+ return bFound ? S_OK : E_FAIL;
+}
+
+
+/*
+--------::In StgIsStorageFile(stgtest.bm)
+--------::Out StgIsStorageFile(). ret == 1
+*/
+SCODE CStorageParser::Parse_StgIsStorageFile(LPINSTRDATA pInstrData,
+ LPTSTR pszPart1,
+ LPTSTR pszPart2)
+{
+#ifdef UNICODE
+ swscanf(pszPart1 + 31, L"%[^)]",pInstrData->wszParam);
+#else
+ TCHAR szName[MAX_PATH];
+ sscanf(pszPart1 + 31, "%[^)]", szName);
+ mbstowcs(pInstrData->wszParam, szName, strlen(szName)+1);
+#endif
+ return S_OK;
+}
+
+
+ULONG CStorageParser::Execute_StgIsStorageFile(LPINSTRDATA pInstrData)
+{
+ CStopWatch sw;
+ ULONG ulTime;
+ HRESULT hr;
+
+ sw.Reset();
+ hr = StgIsStorageFile(pInstrData->wszParam);
+ ulTime = sw.Read();
+
+ Log (m_aInstructions[pInstrData->ulInstrID].szPrintName, hr);
+
+ return ulTime;
+}
+
+
+/*
+--------::In OpenStorage(stgtest.bm, 00000000, 10, 00000000, 0, 0012F540, 0012F4F8)
+--------::Out OpenStorage(). *ppstgOpen == 00000000, ret == 80030050
+*/
+SCODE CStorageParser::Parse_StgOpenStorage(LPINSTRDATA pInstrData,
+ LPTSTR pszPart1,
+ LPTSTR pszPart2)
+{
+ ULONG ulStorageID;
+ TCHAR szName[MAX_PATH];
+
+ _stscanf(pszPart1 + 26, TEXT("%[^,], %*x, %lx"), szName, &pInstrData->dwParam1);
+#ifdef UNICODE
+ wcscpy(pInstrData->wszParam, szName);
+#else
+ mbstowcs(pInstrData->wszParam, szName, strlen(szName)+1);
+#endif
+ _stscanf(pszPart2 + 44, TEXT("%lx"), &ulStorageID);
+
+ pInstrData->OutID = FindStorageID(ulStorageID);
+ return S_OK;
+}
+
+
+ULONG CStorageParser::Execute_StgOpenStorage(LPINSTRDATA pInstrData)
+{
+ CStopWatch sw;
+ ULONG ulTime;
+ HRESULT hr;
+
+ sw.Reset();
+ hr = StgOpenStorage(pInstrData->wszParam, NULL, pInstrData->dwParam1,
+ NULL, 0, &m_apStorages[pInstrData->OutID]);
+ ulTime = sw.Read();
+
+ Log (m_aInstructions[pInstrData->ulInstrID].szPrintName, hr);
+
+ return ulTime;
+}
+
+
+/*
+--------::In StgCreateDocFile(stgtest.bm, 1011, 0, 0012F53C)
+--------::Out StgCreateDocFile(). *ppstgOpen == 50000A5C, ret == 0
+*/
+SCODE CStorageParser::Parse_StgCreateDocFile(LPINSTRDATA pInstrData,
+ LPTSTR pszPart1,
+ LPTSTR pszPart2)
+{
+ ULONG ulStorageID;
+ TCHAR szName[MAX_PATH];
+
+ _stscanf(pszPart1 + 31, TEXT("%[^,], %lx"),
+ szName, &pInstrData->dwParam1);
+#ifdef UNICODE
+ wcscpy(pInstrData->wszParam, szName);
+#else
+ mbstowcs(pInstrData->wszParam, szName, strlen(szName)+1);
+#endif
+ _stscanf(pszPart2 + 49, TEXT("%lx"), &ulStorageID);
+
+ pInstrData->OutID = FindStorageID(ulStorageID);
+
+ return S_OK;
+}
+
+
+ULONG CStorageParser::Execute_StgCreateDocFile(LPINSTRDATA pInstrData)
+{
+ CStopWatch sw;
+ ULONG ulTime;
+ HRESULT hr;
+ OLECHAR *pwszName;
+
+ pwszName = pInstrData->wszParam;
+
+ if (wcscmp(pwszName, L"(null)") == 0)
+ pwszName = NULL;
+
+ sw.Reset();
+ hr = StgCreateDocfile(pwszName, pInstrData->dwParam1,
+ 0, &m_apStorages[pInstrData->OutID]);
+ ulTime = sw.Read();
+
+ Log (m_aInstructions[pInstrData->ulInstrID].szPrintName, hr);
+
+ return ulTime;
+}
+
+/*
+50000A5C::In CExposedDocFile::AddRef()
+50000A5C::Out CExposedDocFile::AddRef(). ret == 0
+*/
+SCODE CStorageParser::Parse_IStorageAddRef(LPINSTRDATA pInstrData,
+ LPTSTR pszPart1,
+ LPTSTR pszPart2)
+{
+ ULONG ulStorageID;
+
+ _stscanf(pszPart1, TEXT("%lx"), &ulStorageID);
+
+ pInstrData->ThisID = FindStorageID(ulStorageID);
+ return S_OK;
+}
+
+
+ULONG CStorageParser::Execute_IStorageAddRef(LPINSTRDATA pInstrData)
+{
+ CStopWatch sw;
+ ULONG ulTime;
+
+ if (FAILED(CheckThisStorageID(pInstrData->ThisID)))
+ return TEST_FAILED;
+
+ sw.Reset();
+ m_apStorages[pInstrData->ThisID]->AddRef();
+ ulTime = sw.Read();
+
+ Log (m_aInstructions[pInstrData->ulInstrID].szPrintName, S_OK);
+
+ return ulTime;
+}
+
+
+/*
+50000A5C::In CExposedDocFile::Release()
+50000A5C::Out CExposedDocFile::Release(). ret == 0
+*/
+SCODE CStorageParser::Parse_IStorageRelease(LPINSTRDATA pInstrData,
+ LPTSTR pszPart1,
+ LPTSTR pszPart2)
+{
+ ULONG ulStorageID;
+
+ _stscanf(pszPart1, TEXT("%lx"), &ulStorageID);
+
+ pInstrData->ThisID = FindStorageID(ulStorageID);
+ return S_OK;
+}
+
+
+ULONG CStorageParser::Execute_IStorageRelease(LPINSTRDATA pInstrData)
+{
+ CStopWatch sw;
+ ULONG ulTime;
+
+ if (FAILED(CheckThisStorageID(pInstrData->ThisID)))
+ return TEST_FAILED;
+
+ sw.Reset();
+ m_apStorages[pInstrData->ThisID]->Release();
+ ulTime = sw.Read();
+
+ Log (m_aInstructions[pInstrData->ulInstrID].szPrintName, S_OK);
+
+ return ulTime;
+}
+
+/*
+50000A5C::In CExposedDocFile::Revert()
+50000A5C::Out CExposedDocFile::Revert(). ret == 0
+*/
+SCODE CStorageParser::Parse_IStorageRevert(LPINSTRDATA pInstrData,
+ LPTSTR pszPart1,
+ LPTSTR pszPart2)
+{
+ ULONG ulStorageID;
+
+ _stscanf(pszPart1, TEXT("%lx"), &ulStorageID);
+
+ pInstrData->ThisID = FindStorageID(ulStorageID);
+ return S_OK;
+}
+
+
+ULONG CStorageParser::Execute_IStorageRevert(LPINSTRDATA pInstrData)
+{
+ CStopWatch sw;
+ ULONG ulTime;
+ HRESULT hr;
+
+ if (FAILED(CheckThisStorageID(pInstrData->ThisID)))
+ return TEST_FAILED;
+
+ sw.Reset();
+ hr = m_apStorages[pInstrData->ThisID]->Revert();
+ ulTime = sw.Read();
+
+ Log (m_aInstructions[pInstrData->ulInstrID].szPrintName, hr);
+
+ return ulTime;
+}
+
+/*
+50000A5C::In CExposedDocFile::Commit(0)
+50000A5C::Out CExposedDocFile::Commit(). ret == 0
+*/
+SCODE CStorageParser::Parse_IStorageCommit(LPINSTRDATA pInstrData,
+ LPTSTR pszPart1,
+ LPTSTR pszPart2)
+{
+ ULONG ulStorageID;
+
+ _stscanf(pszPart1, TEXT("%lx"), &ulStorageID);
+ _stscanf(pszPart1 + 38, TEXT("%lx"), &pInstrData->dwParam1);
+
+ pInstrData->ThisID = FindStorageID(ulStorageID);
+ return S_OK;
+}
+
+
+ULONG CStorageParser::Execute_IStorageCommit(LPINSTRDATA pInstrData)
+{
+ CStopWatch sw;
+ ULONG ulTime;
+ HRESULT hr;
+
+ if (FAILED(CheckThisStorageID(pInstrData->ThisID)))
+ return TEST_FAILED;
+
+ sw.Reset();
+ hr = m_apStorages[pInstrData->ThisID]->Commit(pInstrData->dwParam1);
+ ulTime = sw.Read();
+
+ Log (m_aInstructions[pInstrData->ulInstrID].szPrintName, hr);
+
+ return ulTime;
+}
+
+/*
+50000A5C::In CExposedDocFile::CreateStream(CONTENTS, 1011, 0, 0, 0012F54C)
+50000A5C::Out CExposedDocFile::CreateStream(). *ppstm == 500008F4, ret == 0
+*/
+SCODE CStorageParser::Parse_IStorageCreateStream(LPINSTRDATA pInstrData,
+ LPTSTR pszPart1,
+ LPTSTR pszPart2)
+{
+ ULONG ulStreamID;
+ ULONG ulStorageID;
+ TCHAR szName[MAX_PATH];
+
+ _stscanf(pszPart1, TEXT("%lx"), &ulStorageID);
+ _stscanf(pszPart1 + 44, TEXT("%[^,], %lx"),
+ szName, &pInstrData->dwParam1);
+#ifdef UNICODE
+ wcscpy(pInstrData->wszParam, szName);
+#else
+ mbstowcs(pInstrData->wszParam, szName, strlen(szName)+1);
+#endif
+ _stscanf(pszPart2 + 58, TEXT("%lx"), &ulStreamID);
+
+ pInstrData->ThisID = FindStorageID(ulStorageID);
+ pInstrData->OutID = FindStreamID(ulStreamID);
+
+ return S_OK;
+}
+
+ULONG CStorageParser::Execute_IStorageCreateStream(LPINSTRDATA pInstrData)
+{
+ CStopWatch sw;
+ ULONG ulTime;
+ HRESULT hr;
+
+ if (FAILED(CheckThisStorageID(pInstrData->ThisID)))
+ return TEST_FAILED;
+
+ sw.Reset();
+ hr = m_apStorages[pInstrData->ThisID]->CreateStream(pInstrData->wszParam,
+ pInstrData->dwParam1,
+ 0, 0,
+ &m_apStreams[pInstrData->OutID]);
+ ulTime = sw.Read();
+
+ Log(m_aInstructions[pInstrData->ulInstrID].szPrintName, hr);
+ return ulTime;
+}
+
+
+/*
+50000A5C::In CExposedDocFile::OpenStream(CONTENTS, 0 12, 0, 0012F54C)
+50000A5C::Out CExposedDocFile::OpenStream(). *ppstm == 500008F4, ret == 0
+*/
+SCODE CStorageParser::Parse_IStorageOpenStream(LPINSTRDATA pInstrData,
+ LPTSTR pszPart1,
+ LPTSTR pszPart2)
+{
+ ULONG ulStreamID;
+ ULONG ulStorageID;
+ TCHAR szName[MAX_PATH];
+
+ _stscanf(pszPart1, TEXT("%lx"), &ulStorageID);
+ _stscanf(pszPart1 + 42, TEXT("%[^,], %*x %lx"),
+ szName, &pInstrData->dwParam1);
+#ifdef UNICODE
+ wcscpy(pInstrData->wszParam, szName);
+#else
+ mbstowcs(pInstrData->wszParam, szName, strlen(szName)+1);
+#endif
+ _stscanf(pszPart2 + 56, TEXT("%lx"), &ulStreamID);
+ _stscanf(pszPart2 + 73, TEXT("%lx"), &pInstrData->dwParam2);
+
+ pInstrData->ThisID = FindStorageID(ulStorageID);
+ pInstrData->OutID = FindStreamID(ulStreamID);
+
+ return S_OK;
+}
+
+ULONG CStorageParser::Execute_IStorageOpenStream(LPINSTRDATA pInstrData)
+{
+ CStopWatch sw;
+ ULONG ulTime;
+ HRESULT hr;
+ SCODE sc;
+
+ if (FAILED(CheckThisStorageID(pInstrData->ThisID)))
+ return TEST_FAILED;
+
+ sw.Reset();
+ hr = m_apStorages[pInstrData->ThisID]->OpenStream(pInstrData->wszParam, 0,
+ pInstrData->dwParam1, 0,
+ &m_apStreams[pInstrData->OutID]);
+ ulTime = sw.Read();
+
+ // check if we failed but script indicated succes, which means that a name could be wrong
+ if (FAILED(hr) && SUCCEEDED(pInstrData->dwParam2))
+ {
+ sc = CheckForElementName(pInstrData, STGTY_STREAM);
+ if (SUCCEEDED(sc))
+ {
+ sw.Reset();
+ hr = m_apStorages[pInstrData->ThisID]->OpenStream(pInstrData->wszParam, 0,
+ pInstrData->dwParam1, 0,
+ &m_apStreams[pInstrData->OutID]);
+ ulTime = sw.Read();
+ }
+ }
+
+ Log(m_aInstructions[pInstrData->ulInstrID].szPrintName, hr);
+ return ulTime;
+}
+
+/*
+50000A5C::In CExposedDocFile::CreateStorage(STORAGE1, 1011, 0, 0, 0012F54C)
+50000A5C::Out CExposedDocFile::CreateStorage(). *ppstm == 500008F4, ret == 0
+*/
+SCODE CStorageParser::Parse_IStorageCreateStorage(LPINSTRDATA pInstrData,
+ LPTSTR pszPart1,
+ LPTSTR pszPart2)
+{
+ ULONG ulStorageID1;
+ ULONG ulStorageID2;
+ TCHAR szName[MAX_PATH];
+
+ _stscanf(pszPart1, TEXT("%lx"), &ulStorageID1);
+ _stscanf(pszPart1 + 45, TEXT("%[^,], %lx"),
+ szName, &pInstrData->dwParam1);
+#ifdef UNICODE
+ wcscpy(pInstrData->wszParam, szName);
+#else
+ mbstowcs(pInstrData->wszParam, szName, strlen(szName)+1);
+#endif
+ _stscanf(pszPart2 + 59, TEXT("%lx"), &ulStorageID2);
+
+ pInstrData->ThisID = FindStorageID(ulStorageID1);
+ pInstrData->OutID = FindStorageID(ulStorageID2);
+
+ return S_OK;
+}
+
+ULONG CStorageParser::Execute_IStorageCreateStorage(LPINSTRDATA pInstrData)
+{
+ CStopWatch sw;
+ ULONG ulTime;
+ HRESULT hr;
+
+ if (FAILED(CheckThisStorageID(pInstrData->ThisID)))
+ return TEST_FAILED;
+
+ sw.Reset();
+ hr = m_apStorages[pInstrData->ThisID]->CreateStorage(pInstrData->wszParam,
+ pInstrData->dwParam1,
+ 0, 0,
+ &m_apStorages[pInstrData->OutID]);
+ ulTime = sw.Read();
+
+ Log(m_aInstructions[pInstrData->ulInstrID].szPrintName, hr);
+ return ulTime;
+}
+
+/*
+50000A5C::In CExposedDocFile::OpenStorage(CONTENTS, 00000000, 1011, 00000000, 0, 0012F54C)
+50000A5C::Out CExposedDocFile::OpenStorage(). *ppstm == 500008F4, ret == 0
+*/
+SCODE CStorageParser::Parse_IStorageOpenStorage(LPINSTRDATA pInstrData,
+ LPTSTR pszPart1,
+ LPTSTR pszPart2)
+{
+ ULONG ulStorageID1;
+ ULONG ulStorageID2;
+ TCHAR szName[MAX_PATH];
+
+ _stscanf(pszPart1, TEXT("%lx"), &ulStorageID1);
+ _stscanf(pszPart1 + 43, TEXT("%[^,], %*lx, %lx"),
+ szName, &pInstrData->dwParam1);
+#ifdef UNICODE
+ wcscpy(pInstrData->wszParam, szName);
+#else
+ mbstowcs(pInstrData->wszParam, szName, strlen(szName)+1);
+#endif
+ _stscanf(pszPart2 + 57, TEXT("%lx"), &ulStorageID2);
+ _stscanf(pszPart2 + 74, TEXT("%lx"), &pInstrData->dwParam2);
+
+ pInstrData->ThisID = FindStorageID(ulStorageID1);
+ pInstrData->OutID = FindStorageID(ulStorageID2);
+
+ return S_OK;
+}
+
+ULONG CStorageParser::Execute_IStorageOpenStorage(LPINSTRDATA pInstrData)
+{
+ CStopWatch sw;
+ ULONG ulTime;
+ HRESULT hr;
+ SCODE sc;
+
+ if (FAILED(CheckThisStorageID(pInstrData->ThisID)))
+ return TEST_FAILED;
+
+ sw.Reset();
+ hr = m_apStorages[pInstrData->ThisID]->OpenStorage(pInstrData->wszParam,
+ NULL,
+ pInstrData->dwParam1,
+ NULL, 0,
+ &m_apStorages[pInstrData->OutID]);
+ ulTime = sw.Read();
+
+ // check if we failed but script indicated succes, which means that a name could be wrong
+ if (FAILED(hr) && SUCCEEDED(pInstrData->dwParam2))
+ {
+ sc = CheckForElementName(pInstrData, STGTY_STORAGE);
+ if (SUCCEEDED(sc))
+ {
+ sw.Reset();
+ hr = m_apStorages[pInstrData->ThisID]->OpenStorage(pInstrData->wszParam, NULL,
+ pInstrData->dwParam1, NULL, 0,
+ &m_apStorages[pInstrData->OutID]);
+ ulTime = sw.Read();
+ }
+ }
+ Log(m_aInstructions[pInstrData->ulInstrID].szPrintName, hr);
+ return ulTime;
+}
+
+
+/*
+50000A5C::In CExposedDocFile::DestroyElement(CONTENTS)
+50000A5C::Out CExposedDocFile::DestroyElement(). ret == 0
+*/
+SCODE CStorageParser::Parse_IStorageDestroyElement(LPINSTRDATA pInstrData,
+ LPTSTR pszPart1,
+ LPTSTR pszPart2)
+{
+ ULONG ulStorageID;
+
+ _stscanf(pszPart1, TEXT("%lx"), &ulStorageID);
+#ifdef UNICODE
+ swscanf(pszPart1 + 46, L"%[^,]", pInstrData->wszParam);
+#else
+ TCHAR szName[MAX_PATH];
+ sscanf(pszPart1 + 46, "%[^,]", szName);
+ mbstowcs(pInstrData->wszParam, szName, strlen(szName)+1);
+#endif
+ _stscanf(pszPart2 + 57, TEXT("%lx"), &pInstrData->dwParam1);
+
+ pInstrData->ThisID = FindStorageID(ulStorageID);
+
+ return S_OK;
+}
+
+ULONG CStorageParser::Execute_IStorageDestroyElement(LPINSTRDATA pInstrData)
+{
+ CStopWatch sw;
+ ULONG ulTime;
+ HRESULT hr;
+ SCODE sc;
+
+ if (FAILED(CheckThisStorageID(pInstrData->ThisID)))
+ return TEST_FAILED;
+
+ sw.Reset();
+ hr = m_apStorages[pInstrData->ThisID]->DestroyElement(pInstrData->wszParam);
+ ulTime = sw.Read();
+
+ // check if we failed but script indicated succes, which means that a name could be wrong
+ if (FAILED(hr) && SUCCEEDED(pInstrData->dwParam1))
+ {
+ sc = CheckForElementName(pInstrData, STGTY_ANY);
+ if (SUCCEEDED(sc))
+ {
+ sw.Reset();
+ hr = m_apStorages[pInstrData->ThisID]->DestroyElement(pInstrData->wszParam);
+ ulTime = sw.Read();
+ }
+ }
+ Log(m_aInstructions[pInstrData->ulInstrID].szPrintName, hr);
+
+ return ulTime;
+}
+
+
+/*
+50000A5C::In CExposedDocFile::SetStateBits(%lu, %lu)
+50000A5C::Out CExposedDocFile::SetStateBits(). ret == ??
+*/
+SCODE CStorageParser::Parse_IStorageSetStateBits(LPINSTRDATA pInstrData,
+ LPTSTR pszPart1,
+ LPTSTR pszPart2)
+{
+ ULONG ulStorageID;
+
+ _stscanf(pszPart1, TEXT("%lx"), &ulStorageID);
+ _stscanf(pszPart1 + 44, TEXT("%lu, %lu"),
+ &pInstrData->dwParam1, &pInstrData->dwParam2);
+
+ pInstrData->ThisID = FindStorageID(ulStorageID);
+
+ return S_OK;
+}
+
+ULONG CStorageParser::Execute_IStorageSetStateBits(LPINSTRDATA pInstrData)
+{
+ CStopWatch sw;
+ ULONG ulTime;
+ HRESULT hr;
+
+ if (FAILED(CheckThisStorageID(pInstrData->ThisID)))
+ return TEST_FAILED;
+
+ sw.Reset();
+ hr = m_apStorages[pInstrData->ThisID]->SetStateBits(pInstrData->dwParam1, pInstrData->dwParam2);
+ ulTime = sw.Read();
+
+ Log(m_aInstructions[pInstrData->ulInstrID].szPrintName, hr);
+
+ return ulTime;
+}
+
+
+/*
+50000A5C::In CExposedDocFile::SetClass(?)
+50000A5C::Out CExposedDocFile::SetClass(). ret == ??
+*/
+SCODE CStorageParser::Parse_IStorageSetClass(LPINSTRDATA pInstrData,
+ LPTSTR pszPart1,
+ LPTSTR pszPart2)
+{
+ ULONG ulStorageID;
+
+ _stscanf(pszPart1, TEXT("%lx"), &ulStorageID);
+
+ pInstrData->ThisID = FindStorageID(ulStorageID);
+
+ return S_OK;
+}
+
+ULONG CStorageParser::Execute_IStorageSetClass(LPINSTRDATA pInstrData)
+{
+ CStopWatch sw;
+ ULONG ulTime;
+ HRESULT hr;
+static const CLSID ClsID =
+ {0x0000013a,0x0001,0x0008,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}};
+
+
+ if (FAILED(CheckThisStorageID(pInstrData->ThisID)))
+ return TEST_FAILED;
+
+ sw.Reset();
+ hr = m_apStorages[pInstrData->ThisID]->SetClass(ClsID);
+ ulTime = sw.Read();
+
+ Log(m_aInstructions[pInstrData->ulInstrID].szPrintName, hr);
+
+ return ulTime;
+}
+
+
+/*
+5000A0FC::In CExposedDocFile::SetElementTimes(contents, 0012F518, 0012F518, 00000000)
+5000A0FC::Out CExposedDocFile::SetElementTimes(). ret == 80030005
+*/
+SCODE CStorageParser::Parse_IStorageSetElementTimes(LPINSTRDATA pInstrData,
+ LPTSTR pszPart1,
+ LPTSTR pszPart2)
+{
+ ULONG ulStorageID;
+ TCHAR szName[MAX_PATH];
+
+ _stscanf(pszPart1, TEXT("%lx"), &ulStorageID);
+ _stscanf(pszPart1 + 47, TEXT("%[^,], %lx, %lx, %lx"),
+ szName, &pInstrData->dwParam1,
+ &pInstrData->dwParam2, &pInstrData->dwParam3);
+#ifdef UNICODE
+ wcscpy(pInstrData->wszParam, szName);
+#else
+ mbstowcs(pInstrData->wszParam, szName, strlen(szName)+1);
+#endif
+
+ pInstrData->ThisID = FindStorageID(ulStorageID);
+
+ return S_OK;
+}
+
+ULONG CStorageParser::Execute_IStorageSetElementTimes(LPINSTRDATA pInstrData)
+{
+ CStopWatch sw;
+ ULONG ulTime;
+ HRESULT hr;
+ FILETIME ft;
+ SYSTEMTIME st;
+ LPFILETIME pft1, pft2, pft3;
+
+ if (FAILED(CheckThisStorageID(pInstrData->ThisID)))
+ return TEST_FAILED;
+
+ // get current time
+ GetSystemTime(&st);
+ SystemTimeToFileTime(&st, &ft);
+
+ pft1 = pInstrData->dwParam1 ? &ft : NULL;
+ pft2 = pInstrData->dwParam2 ? &ft : NULL;
+ pft3 = pInstrData->dwParam3 ? &ft : NULL;
+
+ sw.Reset();
+ hr = m_apStorages[pInstrData->ThisID]->SetElementTimes(pInstrData->wszParam,
+ pft1, pft2, pft3);
+ ulTime = sw.Read();
+
+ Log(m_aInstructions[pInstrData->ulInstrID].szPrintName, hr);
+
+ return ulTime;
+}
+
+
+
+/*
+50000A5C::In CExposedDocFile::RenameElement(Name1, Name2)
+50000A5C::Out CExposedDocFile::RenameElement(). ret == ??
+*/
+SCODE CStorageParser::Parse_IStorageRenameElement(LPINSTRDATA pInstrData,
+ LPTSTR pszPart1,
+ LPTSTR pszPart2)
+{
+ ULONG ulStorageID;
+
+ pInstrData->wszParam2 = (OLECHAR *)m_piMalloc->Alloc(MAX_PATH * sizeof(OLECHAR));
+ if (pInstrData->wszParam2 == NULL)
+ {
+ Log(TEXT("Can't allocate memory in for RenameElement"), E_OUTOFMEMORY);
+ return E_FAIL;
+ }
+ _stscanf(pszPart1, TEXT("%lx"), &ulStorageID);
+#ifdef UNICODE
+ swscanf(pszPart1 + 45, L"%[^,], %[^)]",
+ pInstrData->wszParam, pInstrData->wszParam2);
+#else
+ TCHAR szName[MAX_PATH], szName2[MAX_PATH];
+ _stscanf(pszPart1 + 45, "%[^,], %[^)]",
+ szName, szName2);
+ mbstowcs(pInstrData->wszParam, szName, strlen(szName)+1);
+ mbstowcs(pInstrData->wszParam2, szName2, strlen(szName2)+1);
+#endif
+ _stscanf(pszPart2 + 56, TEXT("%lx"), &pInstrData->dwParam1);
+
+ pInstrData->ThisID = FindStorageID(ulStorageID);
+
+ return S_OK;
+}
+
+ULONG CStorageParser::Execute_IStorageRenameElement(LPINSTRDATA pInstrData)
+{
+ CStopWatch sw;
+ ULONG ulTime;
+ HRESULT hr;
+ SCODE sc;
+
+ if (FAILED(CheckThisStorageID(pInstrData->ThisID)))
+ return TEST_FAILED;
+
+ sw.Reset();
+ hr = m_apStorages[pInstrData->ThisID]->RenameElement(pInstrData->wszParam,
+ pInstrData->wszParam2);
+ ulTime = sw.Read();
+
+ // check if we failed but script indicated succes,
+ // which means that a name could be wrong
+ if (FAILED(hr) && SUCCEEDED(pInstrData->dwParam1))
+ {
+ sc = CheckForElementName(pInstrData, STGTY_ANY);
+ if (SUCCEEDED(sc))
+ {
+ sw.Reset();
+ hr = m_apStorages[pInstrData->ThisID]->RenameElement(pInstrData->wszParam,
+ pInstrData->wszParam2);
+ ulTime = sw.Read();
+ }
+ }
+
+ m_piMalloc->Free(pInstrData->wszParam2);
+ Log(m_aInstructions[pInstrData->ulInstrID].szPrintName, hr);
+ return ulTime;
+}
+
+/*
+50000A5C::In CExposedDocFile::Stat(xxxxxxxx)
+50000A5C::Out CExposedDocFile::Stat(). ret == ??
+*/
+SCODE CStorageParser::Parse_IStorageStat(LPINSTRDATA pInstrData,
+ LPTSTR pszPart1,
+ LPTSTR pszPart2)
+{
+ ULONG ulStorageID;
+
+ _stscanf(pszPart1, TEXT("%lx"), &ulStorageID);
+ pInstrData->ThisID = FindStorageID(ulStorageID);
+
+ return S_OK;
+}
+
+ULONG CStorageParser::Execute_IStorageStat(LPINSTRDATA pInstrData)
+{
+ CStopWatch sw;
+ ULONG ulTime;
+ HRESULT hr;
+ STATSTG StatStg;
+
+ if (FAILED(CheckThisStorageID(pInstrData->ThisID)))
+ return TEST_FAILED;
+
+ sw.Reset();
+ hr = m_apStorages[pInstrData->ThisID]->Stat(&StatStg, STATFLAG_NONAME);
+ ulTime = sw.Read();
+
+ Log(m_aInstructions[pInstrData->ulInstrID].szPrintName, hr);
+
+ return ulTime;
+}
+
+/*
+50000A5C::In CExposedStream::AddRef()
+50000A5C::Out CExposedStream::AddRef(). ret == 0
+*/
+SCODE CStorageParser::Parse_IStreamAddRef(LPINSTRDATA pInstrData,
+ LPTSTR pszPart1,
+ LPTSTR pszPart2)
+{
+ ULONG ulStreamID;
+
+ _stscanf(pszPart1, TEXT("%lx"), &ulStreamID);
+
+ pInstrData->ThisID = FindStreamID(ulStreamID);
+ return S_OK;
+}
+
+
+ULONG CStorageParser::Execute_IStreamAddRef(LPINSTRDATA pInstrData)
+{
+ CStopWatch sw;
+ ULONG ulTime;
+ ULONG ulRes;
+
+ if (FAILED(CheckThisStreamID(pInstrData->ThisID)))
+ return TEST_FAILED;
+ sw.Reset();
+ ulRes = m_apStreams[pInstrData->ThisID]->AddRef();
+ ulTime = sw.Read();
+
+ Log (m_aInstructions[pInstrData->ulInstrID].szPrintName, S_OK);
+
+ return ulTime;
+}
+
+
+/*
+50000A5C::In CExposedStream::Release()
+50000A5C::Out CExposedStream::Release(). ret == 0
+*/
+SCODE CStorageParser::Parse_IStreamRelease(LPINSTRDATA pInstrData,
+ LPTSTR pszPart1,
+ LPTSTR pszPart2)
+{
+ ULONG ulStreamID;
+
+ _stscanf(pszPart1, TEXT("%lx"), &ulStreamID);
+
+ pInstrData->ThisID = FindStreamID(ulStreamID);
+ return S_OK;
+}
+
+
+ULONG CStorageParser::Execute_IStreamRelease(LPINSTRDATA pInstrData)
+{
+ CStopWatch sw;
+ ULONG ulTime;
+
+ if (FAILED(CheckThisStreamID(pInstrData->ThisID)))
+ return TEST_FAILED;
+
+ sw.Reset();
+ m_apStreams[pInstrData->ThisID]->Release();
+ ulTime = sw.Read();
+
+ Log (m_aInstructions[pInstrData->ulInstrID].szPrintName, S_OK);
+
+ return ulTime;
+}
+
+/*
+50000A5C::In CExposedStream::Revert()
+50000A5C::Out CExposedStream::Revert(). ret == 0
+*/
+SCODE CStorageParser::Parse_IStreamRevert(LPINSTRDATA pInstrData,
+ LPTSTR pszPart1,
+ LPTSTR pszPart2)
+{
+ ULONG ulStreamID;
+
+ _stscanf(pszPart1, TEXT("%lx"), &ulStreamID);
+
+ pInstrData->ThisID = FindStreamID(ulStreamID);
+ return S_OK;
+}
+
+
+ULONG CStorageParser::Execute_IStreamRevert(LPINSTRDATA pInstrData)
+{
+ CStopWatch sw;
+ ULONG ulTime;
+ HRESULT hr;
+
+ if (FAILED(CheckThisStreamID(pInstrData->ThisID)))
+ return TEST_FAILED;
+
+ sw.Reset();
+ hr = m_apStreams[pInstrData->ThisID]->Revert();
+ ulTime = sw.Read();
+
+ Log (m_aInstructions[pInstrData->ulInstrID].szPrintName, hr);
+
+ return ulTime;
+}
+
+/*
+50000A5C::In CExposedStream::Commit(0)
+50000A5C::Out CExposedStream::Commit(). ret == 0
+*/
+SCODE CStorageParser::Parse_IStreamCommit(LPINSTRDATA pInstrData,
+ LPTSTR pszPart1,
+ LPTSTR pszPart2)
+{
+ ULONG ulStreamID;
+
+ _stscanf(pszPart1, TEXT("%lx"), &ulStreamID);
+ _stscanf(pszPart1 + 37, TEXT("%lx"), &pInstrData->dwParam1);
+
+ pInstrData->ThisID = FindStreamID(ulStreamID);
+ return S_OK;
+}
+
+
+ULONG CStorageParser::Execute_IStreamCommit(LPINSTRDATA pInstrData)
+{
+ CStopWatch sw;
+ ULONG ulTime;
+ HRESULT hr;
+
+ if (FAILED(CheckThisStreamID(pInstrData->ThisID)))
+ return TEST_FAILED;
+
+ sw.Reset();
+ hr = m_apStreams[pInstrData->ThisID]->Commit(pInstrData->dwParam1);
+ ulTime = sw.Read();
+
+ Log (m_aInstructions[pInstrData->ulInstrID].szPrintName, hr);
+
+ return ulTime;
+}
+
+/*
+50000A5C::In CExposedStream::SetSize(10)
+50000A5C::Out CExposedStream::SetSize(). ret == 0
+*/
+SCODE CStorageParser::Parse_IStreamSetSize(LPINSTRDATA pInstrData,
+ LPTSTR pszPart1,
+ LPTSTR pszPart2)
+{
+ ULONG ulStreamID;
+
+ _stscanf(pszPart1, TEXT("%lx"), &ulStreamID);
+ _stscanf(pszPart1 + 38, TEXT("%lu"), &pInstrData->dwParam1);
+
+ pInstrData->ThisID = FindStreamID(ulStreamID);
+ return S_OK;
+}
+
+
+ULONG CStorageParser::Execute_IStreamSetSize(LPINSTRDATA pInstrData)
+{
+ CStopWatch sw;
+ ULONG ulTime;
+ HRESULT hr;
+ ULARGE_INTEGER liSize;
+
+ if (FAILED(CheckThisStreamID(pInstrData->ThisID)))
+ return TEST_FAILED;
+
+ LISet32(liSize, pInstrData->dwParam1);
+
+ sw.Reset();
+ hr = m_apStreams[pInstrData->ThisID]->SetSize(liSize);
+ ulTime = sw.Read();
+
+ Log (m_aInstructions[pInstrData->ulInstrID].szPrintName, hr);
+
+ return ulTime;
+}
+
+/*
+50000A5C::In CExposedStream::Write(xxxxxxxx, 1234, xxxxxxxx)
+50000A5C::Out CExposedStream::Write(). ret == 0
+*/
+SCODE CStorageParser::Parse_IStreamWrite(LPINSTRDATA pInstrData,
+ LPTSTR pszPart1,
+ LPTSTR pszPart2)
+{
+ ULONG ulStreamID;
+
+ _stscanf(pszPart1, TEXT("%lx"), &ulStreamID);
+ _stscanf(pszPart1 + 46, TEXT("%lu"), &pInstrData->dwParam1);
+
+ pInstrData->ThisID = FindStreamID(ulStreamID);
+ return S_OK;
+}
+
+
+ULONG CStorageParser::Execute_IStreamWrite(LPINSTRDATA pInstrData)
+{
+ CStopWatch sw;
+ ULONG ulTime;
+ HRESULT hr;
+ BYTE *pData;
+
+ pData = (BYTE *) m_piMalloc->Alloc(pInstrData->dwParam1);
+ if (pData == NULL)
+ {
+ Log(TEXT("Can't allocate memory for write"), E_OUTOFMEMORY);
+ return TEST_FAILED;
+ }
+
+ if (FAILED(CheckThisStreamID(pInstrData->ThisID)))
+ return TEST_FAILED;
+
+ sw.Reset();
+ hr = m_apStreams[pInstrData->ThisID]->Write(pData, pInstrData->dwParam1, NULL);
+ ulTime = sw.Read();
+
+ Log (m_aInstructions[pInstrData->ulInstrID].szPrintName, hr);
+ m_piMalloc->Free(pData);
+
+ return ulTime;
+}
+
+
+TCHAR *CStorageParser::GetName_IStreamWrite(LPINSTRDATA pInstrData)
+{
+ _stscanf(m_szBuffer, TEXT("IStream::Write %-8lu"), pInstrData->dwParam1);
+ return m_szBuffer;
+}
+
+
+/*
+50000A5C::In CExposedStream::Read(xxxxxxxx, 1234, xxxxxxxx)
+50000A5C::Out CExposedStream::Read(). ret == 0
+*/
+SCODE CStorageParser::Parse_IStreamRead(LPINSTRDATA pInstrData,
+ LPTSTR pszPart1,
+ LPTSTR pszPart2)
+{
+ ULONG ulStreamID;
+
+ _stscanf(pszPart1, TEXT("%lx"), &ulStreamID);
+ _stscanf(pszPart1 + 45, TEXT("%lu"), &pInstrData->dwParam1);
+
+ pInstrData->ThisID = FindStreamID(ulStreamID);
+ return S_OK;
+}
+
+
+ULONG CStorageParser::Execute_IStreamRead(LPINSTRDATA pInstrData)
+{
+ CStopWatch sw;
+ ULONG ulTime;
+ HRESULT hr;
+ BYTE *pData;
+
+ pData = (BYTE *) m_piMalloc->Alloc(pInstrData->dwParam1);
+ if (pData == NULL)
+ {
+ Log(TEXT("Can't allocate memory for read"), E_OUTOFMEMORY);
+ return TEST_FAILED;
+ }
+
+ if (FAILED(CheckThisStreamID(pInstrData->ThisID)))
+ return TEST_FAILED;
+
+ sw.Reset();
+ hr = m_apStreams[pInstrData->ThisID]->Read(pData, pInstrData->dwParam1, NULL);
+ ulTime = sw.Read();
+
+ Log (m_aInstructions[pInstrData->ulInstrID].szPrintName, hr);
+ m_piMalloc->Free(pData);
+
+ return ulTime;
+}
+
+TCHAR *CStorageParser::GetName_IStreamRead(LPINSTRDATA pInstrData)
+{
+ _stscanf(m_szBuffer, TEXT("IStream::Read %-8lu"), pInstrData->dwParam1);
+ return m_szBuffer;
+}
+
+/*
+50000A5C::In CExposedStream::Seek(0, 1234, xxxxxxxx)
+50000A5C::Out CExposedStream::Seek(). ulPos == %lu, ret == 0
+*/
+SCODE CStorageParser::Parse_IStreamSeek(LPINSTRDATA pInstrData,
+ LPTSTR pszPart1,
+ LPTSTR pszPart2)
+{
+ ULONG ulStreamID;
+
+ _stscanf(pszPart1, TEXT("%lx"), &ulStreamID);
+ _stscanf(pszPart1 + 35, TEXT("%ld, %lu"),
+ &pInstrData->dwParam1, &pInstrData->dwParam2);
+
+ pInstrData->ThisID = FindStreamID(ulStreamID);
+ return S_OK;
+}
+
+
+ULONG CStorageParser::Execute_IStreamSeek(LPINSTRDATA pInstrData)
+{
+ CStopWatch sw;
+ ULONG ulTime;
+ HRESULT hr;
+ LARGE_INTEGER liSize;
+
+ if (FAILED(CheckThisStreamID(pInstrData->ThisID)))
+ return TEST_FAILED;
+
+ LISet32(liSize, pInstrData->dwParam1);
+
+ sw.Reset();
+ hr = m_apStreams[pInstrData->ThisID]->Seek(liSize,
+ pInstrData->dwParam2,
+ NULL);
+ ulTime = sw.Read();
+
+ Log (m_aInstructions[pInstrData->ulInstrID].szPrintName, hr);
+
+ return ulTime;
+}
+
+TCHAR *CStorageParser::GetName_IStreamSeek(LPINSTRDATA pInstrData)
+{
+ _stscanf(m_szBuffer, TEXT("IStream::Seek %lu %lu"),
+ pInstrData->dwParam1, pInstrData->dwParam2);
+
+ return m_szBuffer;
+}
+
+
+/*
+500074A4::In CExposedStream::Clone(0012DCE8)
+500074A4::Out CExposedStream::Clone(). *ppstm == 50007324, ret == 0
+*/
+SCODE CStorageParser::Parse_IStreamClone(LPINSTRDATA pInstrData,
+ LPTSTR pszPart1,
+ LPTSTR pszPart2)
+{
+ ULONG ulStreamID1;
+ ULONG ulStreamID2;
+
+ _stscanf(pszPart1, TEXT("%lx"), &ulStreamID1);
+ _stscanf(pszPart2 + 50, TEXT("%lx"), &ulStreamID2);
+
+ pInstrData->ThisID = FindStreamID(ulStreamID1);
+ pInstrData->OutID = FindStreamID(ulStreamID2);
+
+ return S_OK;
+}
+
+ULONG CStorageParser::Execute_IStreamClone(LPINSTRDATA pInstrData)
+{
+ CStopWatch sw;
+ ULONG ulTime;
+ HRESULT hr;
+
+ if (FAILED(CheckThisStreamID(pInstrData->ThisID)))
+ return TEST_FAILED;
+
+ sw.Reset();
+ hr = m_apStreams[pInstrData->ThisID]->Clone(&m_apStreams[pInstrData->OutID]);
+ ulTime = sw.Read();
+
+ Log(m_aInstructions[pInstrData->ulInstrID].szPrintName, hr);
+ return ulTime;
+}
+
+/*
+50000A5C::In CExposedStream::Stat(xxxxxxxx)
+50000A5C::Out CExposedStream::Stat). ret == 0
+*/
+SCODE CStorageParser::Parse_IStreamStat(LPINSTRDATA pInstrData,
+ LPTSTR pszPart1,
+ LPTSTR pszPart2)
+{
+ ULONG ulStreamID;
+
+ _stscanf(pszPart1, TEXT("%lx"), &ulStreamID);
+
+ pInstrData->ThisID = FindStreamID(ulStreamID);
+ return S_OK;
+}
+
+
+ULONG CStorageParser::Execute_IStreamStat(LPINSTRDATA pInstrData)
+{
+ CStopWatch sw;
+ ULONG ulTime;
+ HRESULT hr;
+ STATSTG StatStg;
+
+ if (FAILED(CheckThisStreamID(pInstrData->ThisID)))
+ return TEST_FAILED;
+
+
+ sw.Reset();
+ hr = m_apStreams[pInstrData->ThisID]->Stat(&StatStg, STATFLAG_NONAME);
+ ulTime = sw.Read();
+
+ Log (m_aInstructions[pInstrData->ulInstrID].szPrintName, hr);
+
+ return ulTime;
+}
diff --git a/private/oleutest/perform/cairole/tests/bmp_test.cxx b/private/oleutest/perform/cairole/tests/bmp_test.cxx
new file mode 100644
index 000000000..329b98ef1
--- /dev/null
+++ b/private/oleutest/perform/cairole/tests/bmp_test.cxx
@@ -0,0 +1,90 @@
+//
+// A very simple test based on parser base classes
+// It understands only two commands 1 and 2 in first column.
+// 2's are simply ignored.
+// on execution of 1's I just loop for the id of current command
+// which is increased by 1 with every command encounterd, starting with 0.
+//
+//
+// t-vadims
+//
+
+#include <headers.cxx>
+#pragma hdrstop
+
+#include <bmp_test.hxx>
+
+
+SCODE CSimpleTest::SetParserObject ()
+{
+ m_pParser = new CParserTest;
+ return S_OK;
+}
+
+SCODE CSimpleTest::DeleteParserObject ()
+{
+ delete m_pParser;
+ return S_OK;
+}
+
+
+WCHAR* CSimpleTest::Name ()
+{
+ return L"ParserTest";
+}
+
+WCHAR* CSimpleTest::SectionHeader()
+{
+ return L"Simple test of interpreting files";
+}
+
+
+SCODE CParserTest::Setup (CTestInput *pInput)
+{
+ /* do any neccessary setup staff */
+ m_iInstrID = 0;
+ return S_OK;
+}
+
+SCODE CParserTest::Cleanup ()
+{
+ /* do any neccessary clean up */
+ return S_OK;
+}
+
+ULONG CParserTest::ParseNewInstruction(LPWSTR pwszInstr)
+{
+ ULONG ulID;
+
+ if (pwszInstr[0] == L'1')
+ {
+ m_iInstrID ++;
+ ulID = m_iInstrID;
+ }
+ else if (pwszInstr[0] == L'2')
+ ulID = NOT_INSTRUCTION;
+ else
+ ulID = INVALID_INSTRUCTION;
+
+ return ulID;
+}
+
+ULONG CParserTest::ExecuteInstruction(ULONG ulID)
+{
+ CStopWatch sw;
+
+ sw.Reset();
+ for (ULONG i =0; i <=ulID; i++)
+ /* empty loop */;
+ return sw.Read();
+}
+
+
+WCHAR* CParserTest::InstructionName(ULONG ulID)
+{
+ wsprintf(m_wszBuf, L"Instruction %ld", ulID);
+ return m_wszBuf;
+}
+
+
+
diff --git a/private/oleutest/perform/cairole/tests/bmp_test.hxx b/private/oleutest/perform/cairole/tests/bmp_test.hxx
new file mode 100644
index 000000000..d10770b74
--- /dev/null
+++ b/private/oleutest/perform/cairole/tests/bmp_test.hxx
@@ -0,0 +1,41 @@
+
+//
+// header file for bmp_test.cxx
+// see bmp_test.cxx for information
+//
+
+#ifndef _BMP_TEST_HXX_
+#define _BMP_TEST_HXX_
+
+#include <bm_parse.hxx>
+
+class CSimpleTest : public CTimerBase
+{
+public:
+ virtual SCODE SetParserObject ();
+ virtual SCODE DeleteParserObject ();
+
+ virtual WCHAR *Name ();
+ virtual WCHAR* SectionHeader ();
+};
+
+
+
+class CParserTest : public CParserBase
+{
+public:
+ virtual SCODE Setup (CTestInput *pInput);
+ virtual SCODE Cleanup ();
+
+ virtual ULONG ParseNewInstruction(LPWSTR pszNewInstruction);
+ virtual ULONG ExecuteInstruction(ULONG ulInstrID);
+ virtual WCHAR* InstructionName(ULONG ulInstrID);
+
+private:
+
+ ULONG m_iInstrID;
+ WCHAR m_wszBuf[30];
+};
+
+
+#endif
diff --git a/private/oleutest/perform/cairole/tests/daytona/makefile b/private/oleutest/perform/cairole/tests/daytona/makefile
new file mode 100644
index 000000000..1d3728d41
--- /dev/null
+++ b/private/oleutest/perform/cairole/tests/daytona/makefile
@@ -0,0 +1,10 @@
+############################################################################
+#
+# Copyright (C) 1992, Microsoft Corporation.
+#
+# All rights reserved.
+#
+############################################################################
+
+!include $(NTMAKEENV)\makefile.def
+
diff --git a/private/oleutest/perform/cairole/tests/daytona/sources b/private/oleutest/perform/cairole/tests/daytona/sources
new file mode 100644
index 000000000..707a27662
--- /dev/null
+++ b/private/oleutest/perform/cairole/tests/daytona/sources
@@ -0,0 +1,81 @@
+!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.
+
+!ENDIF
+
+!include ..\..\..\daytona.inc
+
+#
+# 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= bmtests
+
+#
+# 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= LIBRARY
+
+INCLUDES= $(INCLUDES);$(OLEDIR)\com\inc
+INCLUDES= $(INCLUDES);$(OLEUTESTDIR)\balls\common
+C_DEFINES= $(C_DEFINES)
+
+SOURCES= \
+ ..\bm_noise.cxx \
+ ..\bm_api.cxx \
+ ..\bm_alloc.cxx \
+ ..\bm_cgps.cxx \
+ ..\bm_init.cxx \
+ ..\bm_regis.cxx \
+ ..\bm_activ.cxx \
+ ..\bm_obind.cxx \
+ ..\bm_sbind.cxx \
+ ..\bm_props.cxx \
+ ..\bm_marsh.cxx \
+ ..\bm_mrsh2.cxx \
+ ..\bm_rpc.cxx \
+ ..\bm_qi.cxx \
+ ..\bm_iid.cxx \
+ ..\bmguid.cxx \
+ ..\bm_rot.cxx \
+ ..\bm_nest.cxx \
+ ..\bm_rrpc.cxx \
+ ..\bm_rpc2.cxx \
+ ..\bm_filio.cxx \
+ ..\bm_stg.cxx \
+ ..\bm_nstg.cxx \
+ ..\bmp_stg.cxx \
+ ..\bmp_stg2.cxx \
+ ..\rawrpc_c.c \
+ ..\rawrpc_x.c
+
+
+UMTYPE= console
+UMAPPL=
+UMTEST=
+UMLIBS=
+
+PRECOMPILED_INCLUDE = ..\headers.cxx
diff --git a/private/oleutest/perform/cairole/tests/dirs b/private/oleutest/perform/cairole/tests/dirs
new file mode 100644
index 000000000..2084bae88
--- /dev/null
+++ b/private/oleutest/perform/cairole/tests/dirs
@@ -0,0 +1,38 @@
+!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/perform/cairole/tests/headers.cxx b/private/oleutest/perform/cairole/tests/headers.cxx
new file mode 100644
index 000000000..53d9fc546
--- /dev/null
+++ b/private/oleutest/perform/cairole/tests/headers.cxx
@@ -0,0 +1,18 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1992.
+//
+// File: headers.cxx
+//
+// Contents: remote2/new precompiled headers
+//
+// Classes:
+//
+// Functions:
+//
+// History: 24-Aug-93 PhilipLa Created
+//
+//----------------------------------------------------------------------------
+
+#include <benchmrk.hxx>
diff --git a/private/oleutest/perform/cairole/tests/makefile b/private/oleutest/perform/cairole/tests/makefile
new file mode 100644
index 000000000..7f4951e2a
--- /dev/null
+++ b/private/oleutest/perform/cairole/tests/makefile
@@ -0,0 +1,25 @@
+############################################################################
+#
+# Copyright (C) 1992, Microsoft Corporation.
+#
+# All rights reserved.
+#
+############################################################################
+
+!ifdef NTMAKEENV
+
+# We need to do the following so that build will stop reading from the
+# pipe.
+
+all :
+ echo $(BUILDMSG)
+
+clean : all
+
+!else # NTMAKEENV
+
+!include $(CAIROLE)\com\makefile
+
+!include $(DEPENDFILE)
+
+!endif # NTMAKEENV
diff --git a/private/oleutest/perform/cairole/tests/oletest.hxx b/private/oleutest/perform/cairole/tests/oletest.hxx
new file mode 100644
index 000000000..3acd6fbda
--- /dev/null
+++ b/private/oleutest/perform/cairole/tests/oletest.hxx
@@ -0,0 +1,71 @@
+//-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1993.
+//
+// File: oletest.hxx
+//
+// Contents: Definition of OLE test classes
+//
+// Classes: COleTestClass
+//
+// Functions:
+//
+// History: 1-July-93 t-martig Created
+//
+//--------------------------------------------------------------------------
+
+#ifndef __OLETEST_H
+#define __OLETEST_H
+
+#include <windows.h>
+#include <ole2.h>
+
+
+extern "C" const GUID CLSID_COleTestClass;
+extern "C" const GUID CLSID_COleTestClass1;
+extern "C" const GUID CLSID_COleTestClass2;
+extern "C" const GUID CLSID_COleTestClass3;
+extern "C" const GUID CLSID_COleTestClass4;
+extern "C" const GUID CLSID_COleTestClass5;
+extern "C" const GUID CLSID_COleTestClass6;
+extern "C" const GUID CLSID_COleTestClass7;
+extern "C" const GUID CLSID_COleTestClass8;
+
+
+class COleTestClass : public IUnknown
+{
+public:
+ COleTestClass ();
+ ~COleTestClass ();
+
+ // *** IUnknown methods ***
+ STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID FAR* ppvObj) ;
+ STDMETHOD_(ULONG,AddRef) (THIS) ;
+ STDMETHOD_(ULONG,Release) (THIS) ;
+
+private:
+ ULONG refCount;
+};
+
+
+
+class COleTestClassFactory : public IClassFactory
+{
+public:
+ STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID FAR* ppvObj);
+ STDMETHOD_(ULONG,AddRef) (THIS);
+ STDMETHOD_(ULONG,Release) (THIS);
+
+ STDMETHOD(CreateInstance) (THIS_ LPUNKNOWN pUnkOuter,
+ REFIID riid,
+ LPVOID FAR* ppvObject);
+ STDMETHOD(LockServer) (THIS_ BOOL fLock);
+};
+
+
+STDAPI DllGetClassObject (REFCLSID classId, REFIID riid, VOID **ppv);
+STDAPI DllCanUnloadNow ();
+
+
+#endif // __OLETEST_H
diff --git a/private/oleutest/perform/cairole/tests/rawrpc_c.c b/private/oleutest/perform/cairole/tests/rawrpc_c.c
new file mode 100644
index 000000000..d97b7b2f0
--- /dev/null
+++ b/private/oleutest/perform/cairole/tests/rawrpc_c.c
@@ -0,0 +1,848 @@
+#include <string.h>
+#include <limits.h>
+#include <rpc.h>
+
+#include "rawrpc.h"
+static handle_t AutoBindHandle;
+extern RPC_DISPATCH_TABLE IRawRpc_DispatchTable;
+
+static RPC_CLIENT_INTERFACE ___RpcClientInterface = {
+ sizeof(RPC_CLIENT_INTERFACE),
+ {{0x00000145,0x0001,0x0008,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}},
+ {0,0}},
+ {
+ {0x8A885D04L,0x1CEB,0x11C9,{0x9F,0xE8,0x08,0x00,0x2B,0x10,0x48,0x60}},
+ {2,0}
+ }
+ ,
+ 0,0,0,
+ 0
+ }
+;
+RPC_IF_HANDLE IRawRpc_ClientIfHandle = (RPC_IF_HANDLE) &___RpcClientInterface;
+SCODE Quit(
+ handle_t hRpc)
+ {
+ SCODE _ret_value;
+ unsigned char * _packet;
+ unsigned char * _tempbuf;
+ RPC_STATUS _status;
+ RPC_MESSAGE _message;
+ PRPC_MESSAGE _prpcmsg = & _message;
+
+ ((void)( _packet ));
+ ((void)( _tempbuf ));
+ _message.Handle = hRpc;
+ _message.RpcInterfaceInformation = (void __RPC_FAR *) &___RpcClientInterface;
+ _prpcmsg->BufferLength = 0;
+ _message.ProcNum = ( 0 );
+ _message.RpcFlags = ( 0 );
+ _status = I_RpcGetBuffer(&_message);
+ if (_status) RpcRaiseException(_status);
+ _packet = _message.Buffer;
+ _prpcmsg->Buffer = _packet;
+ _status = I_RpcSendReceive(&_message);
+ if (_status) RpcRaiseException(_status);
+ _packet = _message.Buffer;
+ RpcTryFinally
+ {
+ /* receive data into &_ret_value */
+ long_from_ndr((PRPC_MESSAGE)_prpcmsg, (unsigned long *)&_ret_value);
+ }
+ RpcFinally
+ {
+ _message.Buffer = _packet;
+ _status = I_RpcFreeBuffer(&_message);
+ if (_status) RpcRaiseException(_status);
+ }
+ RpcEndFinally
+
+ return (_ret_value);
+ }
+void Void(
+ handle_t hRpc)
+ {
+ unsigned char * _packet;
+ RPC_STATUS _status;
+ RPC_MESSAGE _message;
+ PRPC_MESSAGE _prpcmsg = & _message;
+
+ ((void)( _packet ));
+ _message.Handle = hRpc;
+ _message.RpcInterfaceInformation = (void __RPC_FAR *) &___RpcClientInterface;
+ _prpcmsg->BufferLength = 0;
+ _message.ProcNum = ( 1 );
+ _message.RpcFlags = ( 0 );
+ _status = I_RpcGetBuffer(&_message);
+ if (_status) RpcRaiseException(_status);
+ _packet = _message.Buffer;
+ _prpcmsg->Buffer = _packet;
+ _status = I_RpcSendReceive(&_message);
+ if (_status) RpcRaiseException(_status);
+ _status = I_RpcFreeBuffer(&_message);
+ if (_status) RpcRaiseException(_status);
+
+ }
+SCODE VoidRC(
+ handle_t hRpc)
+ {
+ SCODE _ret_value;
+ unsigned char * _packet;
+ unsigned char * _tempbuf;
+ RPC_STATUS _status;
+ RPC_MESSAGE _message;
+ PRPC_MESSAGE _prpcmsg = & _message;
+
+ ((void)( _packet ));
+ ((void)( _tempbuf ));
+ _message.Handle = hRpc;
+ _message.RpcInterfaceInformation = (void __RPC_FAR *) &___RpcClientInterface;
+ _prpcmsg->BufferLength = 0;
+ _message.ProcNum = ( 2 );
+ _message.RpcFlags = ( 0 );
+ _status = I_RpcGetBuffer(&_message);
+ if (_status) RpcRaiseException(_status);
+ _packet = _message.Buffer;
+ _prpcmsg->Buffer = _packet;
+ _status = I_RpcSendReceive(&_message);
+ if (_status) RpcRaiseException(_status);
+ _packet = _message.Buffer;
+ RpcTryFinally
+ {
+ /* receive data into &_ret_value */
+ long_from_ndr((PRPC_MESSAGE)_prpcmsg, (unsigned long *)&_ret_value);
+ }
+ RpcFinally
+ {
+ _message.Buffer = _packet;
+ _status = I_RpcFreeBuffer(&_message);
+ if (_status) RpcRaiseException(_status);
+ }
+ RpcEndFinally
+
+ return (_ret_value);
+ }
+SCODE VoidPtrIn(
+ handle_t hRpc,
+ ULONG cb,
+ void *pv)
+ {
+ SCODE _ret_value;
+ unsigned char * _packet;
+ unsigned int _length;
+ unsigned char * _tempbuf;
+ RPC_STATUS _status;
+ RPC_MESSAGE _message;
+ PRPC_MESSAGE _prpcmsg = & _message;
+
+ ((void)( _packet ));
+ ((void)( _tempbuf ));
+ ((void)( _length ));
+ _message.Handle = hRpc;
+ _message.RpcInterfaceInformation = (void __RPC_FAR *) &___RpcClientInterface;
+ _prpcmsg->BufferLength = 8;
+ if (pv ==0)
+ RpcRaiseException(RPC_X_NULL_REF_POINTER);
+ _prpcmsg->BufferLength += 4;
+ _prpcmsg->BufferLength += (unsigned int)(cb);
+ _message.ProcNum = ( 3 );
+ _message.RpcFlags = ( 0 );
+ _status = I_RpcGetBuffer(&_message);
+ if (_status) RpcRaiseException(_status);
+ _packet = _message.Buffer;
+ _length = _prpcmsg->BufferLength;
+ _prpcmsg->BufferLength = 0;
+ /* send data from cb */
+ *(*(long **)&_prpcmsg->Buffer)++ = (long)cb;
+ // send total number of elements
+ *(*(long **)&_prpcmsg->Buffer)++ = cb;
+ /* send data from pv */
+ NDRcopy (_prpcmsg->Buffer, (void __RPC_FAR *) ((unsigned char *)pv+0), (unsigned int)(cb));
+ *(unsigned long *)&_prpcmsg->Buffer += cb;
+ _prpcmsg->Buffer = _packet;
+ _prpcmsg->BufferLength = _length;
+ _status = I_RpcSendReceive(&_message);
+ if (_status) RpcRaiseException(_status);
+ _packet = _message.Buffer;
+ RpcTryFinally
+ {
+ /* receive data into &_ret_value */
+ long_from_ndr((PRPC_MESSAGE)_prpcmsg, (unsigned long *)&_ret_value);
+ }
+ RpcFinally
+ {
+ _message.Buffer = _packet;
+ _status = I_RpcFreeBuffer(&_message);
+ if (_status) RpcRaiseException(_status);
+ }
+ RpcEndFinally
+
+ return (_ret_value);
+ }
+SCODE VoidPtrOut(
+ handle_t hRpc,
+ ULONG cb,
+ ULONG *pcb,
+ void *pv)
+ {
+ SCODE _ret_value;
+ unsigned long _alloc_total;
+ unsigned long _valid_lower;
+ unsigned long _valid_total;
+ unsigned char * _packet;
+ unsigned char * _tempbuf;
+ unsigned char * _savebuf;
+ RPC_STATUS _status;
+ RPC_MESSAGE _message;
+ PRPC_MESSAGE _prpcmsg = & _message;
+
+ ((void)( _alloc_total ));
+ ((void)( _valid_total ));
+ ((void)( _valid_lower ));
+ ((void)( _packet ));
+ ((void)( _tempbuf ));
+ ((void)( _savebuf ));
+ _message.Handle = hRpc;
+ _message.RpcInterfaceInformation = (void __RPC_FAR *) &___RpcClientInterface;
+ _prpcmsg->BufferLength = 4;
+ _message.ProcNum = ( 4 );
+ _message.RpcFlags = ( 0 );
+ _status = I_RpcGetBuffer(&_message);
+ if (_status) RpcRaiseException(_status);
+ _packet = _message.Buffer;
+ /* send data from cb */
+ *(*(long **)&_prpcmsg->Buffer)++ = (long)cb;
+ _prpcmsg->Buffer = _packet;
+ _status = I_RpcSendReceive(&_message);
+ if (_status) RpcRaiseException(_status);
+ _packet = _message.Buffer;
+ RpcTryFinally
+ {
+ _tempbuf = (unsigned char *)_prpcmsg->Buffer;
+ if (pcb ==0)
+ RpcRaiseException(RPC_X_NULL_REF_POINTER);
+ /* receive data into pcb */
+ long_from_ndr((PRPC_MESSAGE)_prpcmsg, (unsigned long *)pcb);
+ _tempbuf = (unsigned char *)_prpcmsg->Buffer;
+ if (pv ==0)
+ RpcRaiseException(RPC_X_NULL_REF_POINTER);
+ // recv total number of elements
+ long_from_ndr((PRPC_MESSAGE)_prpcmsg, &_alloc_total);
+ // recv valid range
+ long_from_ndr((PRPC_MESSAGE)_prpcmsg, &_valid_lower);
+ long_from_ndr((PRPC_MESSAGE)_prpcmsg, &_valid_total);
+ byte_array_from_ndr ((PRPC_MESSAGE)_prpcmsg, _valid_lower, _valid_lower + _valid_total, pv);
+ /* receive data into &_ret_value */
+ long_from_ndr((PRPC_MESSAGE)_prpcmsg, (unsigned long *)&_ret_value);
+ }
+ RpcFinally
+ {
+ _message.Buffer = _packet;
+ _status = I_RpcFreeBuffer(&_message);
+ if (_status) RpcRaiseException(_status);
+ }
+ RpcEndFinally
+
+ return (_ret_value);
+ }
+SCODE DwordIn(
+ handle_t hRpc,
+ DWORD dw)
+ {
+ SCODE _ret_value;
+ unsigned char * _packet;
+ unsigned char * _tempbuf;
+ RPC_STATUS _status;
+ RPC_MESSAGE _message;
+ PRPC_MESSAGE _prpcmsg = & _message;
+
+ ((void)( _packet ));
+ ((void)( _tempbuf ));
+ _message.Handle = hRpc;
+ _message.RpcInterfaceInformation = (void __RPC_FAR *) &___RpcClientInterface;
+ _prpcmsg->BufferLength = 4;
+ _message.ProcNum = ( 5 );
+ _message.RpcFlags = ( 0 );
+ _status = I_RpcGetBuffer(&_message);
+ if (_status) RpcRaiseException(_status);
+ _packet = _message.Buffer;
+ /* send data from dw */
+ *(*(long **)&_prpcmsg->Buffer)++ = (long)dw;
+ _prpcmsg->Buffer = _packet;
+ _status = I_RpcSendReceive(&_message);
+ if (_status) RpcRaiseException(_status);
+ _packet = _message.Buffer;
+ RpcTryFinally
+ {
+ /* receive data into &_ret_value */
+ long_from_ndr((PRPC_MESSAGE)_prpcmsg, (unsigned long *)&_ret_value);
+ }
+ RpcFinally
+ {
+ _message.Buffer = _packet;
+ _status = I_RpcFreeBuffer(&_message);
+ if (_status) RpcRaiseException(_status);
+ }
+ RpcEndFinally
+
+ return (_ret_value);
+ }
+SCODE DwordOut(
+ handle_t hRpc,
+ DWORD *pdw)
+ {
+ SCODE _ret_value;
+ unsigned char * _packet;
+ unsigned char * _tempbuf;
+ RPC_STATUS _status;
+ RPC_MESSAGE _message;
+ PRPC_MESSAGE _prpcmsg = & _message;
+
+ ((void)( _packet ));
+ ((void)( _tempbuf ));
+ _message.Handle = hRpc;
+ _message.RpcInterfaceInformation = (void __RPC_FAR *) &___RpcClientInterface;
+ _prpcmsg->BufferLength = 0;
+ _message.ProcNum = ( 6 );
+ _message.RpcFlags = ( 0 );
+ _status = I_RpcGetBuffer(&_message);
+ if (_status) RpcRaiseException(_status);
+ _packet = _message.Buffer;
+ _prpcmsg->Buffer = _packet;
+ _status = I_RpcSendReceive(&_message);
+ if (_status) RpcRaiseException(_status);
+ _packet = _message.Buffer;
+ RpcTryFinally
+ {
+ _tempbuf = (unsigned char *)_prpcmsg->Buffer;
+ if (pdw ==0)
+ RpcRaiseException(RPC_X_NULL_REF_POINTER);
+ /* receive data into pdw */
+ long_from_ndr((PRPC_MESSAGE)_prpcmsg, (unsigned long *)pdw);
+ /* receive data into &_ret_value */
+ long_from_ndr((PRPC_MESSAGE)_prpcmsg, (unsigned long *)&_ret_value);
+ }
+ RpcFinally
+ {
+ _message.Buffer = _packet;
+ _status = I_RpcFreeBuffer(&_message);
+ if (_status) RpcRaiseException(_status);
+ }
+ RpcEndFinally
+
+ return (_ret_value);
+ }
+SCODE DwordInOut(
+ handle_t hRpc,
+ DWORD *pdw)
+ {
+ SCODE _ret_value;
+ unsigned char * _packet;
+ unsigned int _length;
+ unsigned char * _tempbuf;
+ RPC_STATUS _status;
+ RPC_MESSAGE _message;
+ PRPC_MESSAGE _prpcmsg = & _message;
+
+ ((void)( _packet ));
+ ((void)( _tempbuf ));
+ ((void)( _length ));
+ _message.Handle = hRpc;
+ _message.RpcInterfaceInformation = (void __RPC_FAR *) &___RpcClientInterface;
+ _prpcmsg->BufferLength = 4;
+ _message.ProcNum = ( 7 );
+ _message.RpcFlags = ( 0 );
+ _status = I_RpcGetBuffer(&_message);
+ if (_status) RpcRaiseException(_status);
+ _packet = _message.Buffer;
+ _length = _prpcmsg->BufferLength;
+ _prpcmsg->BufferLength = 0;
+ /* send data from *pdw */
+ *(*(long **)&_prpcmsg->Buffer)++ = (long)*pdw;
+ _prpcmsg->Buffer = _packet;
+ _prpcmsg->BufferLength = _length;
+ _status = I_RpcSendReceive(&_message);
+ if (_status) RpcRaiseException(_status);
+ _packet = _message.Buffer;
+ RpcTryFinally
+ {
+ _tempbuf = (unsigned char *)_prpcmsg->Buffer;
+ if (pdw ==0)
+ RpcRaiseException(RPC_X_NULL_REF_POINTER);
+ /* receive data into pdw */
+ long_from_ndr((PRPC_MESSAGE)_prpcmsg, (unsigned long *)pdw);
+ /* receive data into &_ret_value */
+ long_from_ndr((PRPC_MESSAGE)_prpcmsg, (unsigned long *)&_ret_value);
+ }
+ RpcFinally
+ {
+ _message.Buffer = _packet;
+ _status = I_RpcFreeBuffer(&_message);
+ if (_status) RpcRaiseException(_status);
+ }
+ RpcEndFinally
+
+ return (_ret_value);
+ }
+SCODE LiIn(
+ handle_t hRpc,
+ LARGE_INTEGER li)
+ {
+ SCODE _ret_value;
+ unsigned char * _packet;
+ unsigned char * _tempbuf;
+ RPC_STATUS _status;
+ RPC_MESSAGE _message;
+ PRPC_MESSAGE _prpcmsg = & _message;
+
+ ((void)( _packet ));
+ ((void)( _tempbuf ));
+ _message.Handle = hRpc;
+ _message.RpcInterfaceInformation = (void __RPC_FAR *) &___RpcClientInterface;
+ _prpcmsg->BufferLength = 8;
+ _message.ProcNum = ( 8 );
+ _message.RpcFlags = ( 0 );
+ _status = I_RpcGetBuffer(&_message);
+ if (_status) RpcRaiseException(_status);
+ _packet = _message.Buffer;
+ /* send data from &li */
+ NDRcopy (_prpcmsg->Buffer, (void __RPC_FAR *) (&li), (unsigned int)(8));
+ *(unsigned long *)&_prpcmsg->Buffer += 8;
+ _prpcmsg->Buffer = _packet;
+ _status = I_RpcSendReceive(&_message);
+ if (_status) RpcRaiseException(_status);
+ _packet = _message.Buffer;
+ RpcTryFinally
+ {
+ /* receive data into &_ret_value */
+ long_from_ndr((PRPC_MESSAGE)_prpcmsg, (unsigned long *)&_ret_value);
+ }
+ RpcFinally
+ {
+ _message.Buffer = _packet;
+ _status = I_RpcFreeBuffer(&_message);
+ if (_status) RpcRaiseException(_status);
+ }
+ RpcEndFinally
+
+ return (_ret_value);
+ }
+SCODE LiOut(
+ handle_t hRpc,
+ LARGE_INTEGER *pli)
+ {
+ SCODE _ret_value;
+ unsigned long _alloc_total;
+ unsigned char * _packet;
+ unsigned char * _tempbuf;
+ RPC_STATUS _status;
+ RPC_MESSAGE _message;
+ PRPC_MESSAGE _prpcmsg = & _message;
+
+ ((void)( _alloc_total ));
+ ((void)( _packet ));
+ ((void)( _tempbuf ));
+ _message.Handle = hRpc;
+ _message.RpcInterfaceInformation = (void __RPC_FAR *) &___RpcClientInterface;
+ _prpcmsg->BufferLength = 0;
+ _message.ProcNum = ( 9 );
+ _message.RpcFlags = ( 0 );
+ _status = I_RpcGetBuffer(&_message);
+ if (_status) RpcRaiseException(_status);
+ _packet = _message.Buffer;
+ _prpcmsg->Buffer = _packet;
+ _status = I_RpcSendReceive(&_message);
+ if (_status) RpcRaiseException(_status);
+ _packet = _message.Buffer;
+ RpcTryFinally
+ {
+ _tempbuf = (unsigned char *)_prpcmsg->Buffer;
+ if (pli ==0)
+ RpcRaiseException(RPC_X_NULL_REF_POINTER);
+ data_from_ndr((PRPC_MESSAGE)_prpcmsg, (void __RPC_FAR *) (pli), "4ll", 8);
+ /* receive data into &_ret_value */
+ long_from_ndr((PRPC_MESSAGE)_prpcmsg, (unsigned long *)&_ret_value);
+ }
+ RpcFinally
+ {
+ _message.Buffer = _packet;
+ _status = I_RpcFreeBuffer(&_message);
+ if (_status) RpcRaiseException(_status);
+ }
+ RpcEndFinally
+
+ return (_ret_value);
+ }
+SCODE ULiIn(
+ handle_t hRpc,
+ ULARGE_INTEGER uli)
+ {
+ SCODE _ret_value;
+ unsigned char * _packet;
+ unsigned char * _tempbuf;
+ RPC_STATUS _status;
+ RPC_MESSAGE _message;
+ PRPC_MESSAGE _prpcmsg = & _message;
+
+ ((void)( _packet ));
+ ((void)( _tempbuf ));
+ _message.Handle = hRpc;
+ _message.RpcInterfaceInformation = (void __RPC_FAR *) &___RpcClientInterface;
+ _prpcmsg->BufferLength = 8;
+ _message.ProcNum = ( 10 );
+ _message.RpcFlags = ( 0 );
+ _status = I_RpcGetBuffer(&_message);
+ if (_status) RpcRaiseException(_status);
+ _packet = _message.Buffer;
+ /* send data from &uli */
+ NDRcopy (_prpcmsg->Buffer, (void __RPC_FAR *) (&uli), (unsigned int)(8));
+ *(unsigned long *)&_prpcmsg->Buffer += 8;
+ _prpcmsg->Buffer = _packet;
+ _status = I_RpcSendReceive(&_message);
+ if (_status) RpcRaiseException(_status);
+ _packet = _message.Buffer;
+ RpcTryFinally
+ {
+ /* receive data into &_ret_value */
+ long_from_ndr((PRPC_MESSAGE)_prpcmsg, (unsigned long *)&_ret_value);
+ }
+ RpcFinally
+ {
+ _message.Buffer = _packet;
+ _status = I_RpcFreeBuffer(&_message);
+ if (_status) RpcRaiseException(_status);
+ }
+ RpcEndFinally
+
+ return (_ret_value);
+ }
+SCODE ULiOut(
+ handle_t hRpc,
+ ULARGE_INTEGER *puli)
+ {
+ SCODE _ret_value;
+ unsigned long _alloc_total;
+ unsigned char * _packet;
+ unsigned char * _tempbuf;
+ RPC_STATUS _status;
+ RPC_MESSAGE _message;
+ PRPC_MESSAGE _prpcmsg = & _message;
+
+ ((void)( _alloc_total ));
+ ((void)( _packet ));
+ ((void)( _tempbuf ));
+ _message.Handle = hRpc;
+ _message.RpcInterfaceInformation = (void __RPC_FAR *) &___RpcClientInterface;
+ _prpcmsg->BufferLength = 0;
+ _message.ProcNum = ( 11 );
+ _message.RpcFlags = ( 0 );
+ _status = I_RpcGetBuffer(&_message);
+ if (_status) RpcRaiseException(_status);
+ _packet = _message.Buffer;
+ _prpcmsg->Buffer = _packet;
+ _status = I_RpcSendReceive(&_message);
+ if (_status) RpcRaiseException(_status);
+ _packet = _message.Buffer;
+ RpcTryFinally
+ {
+ _tempbuf = (unsigned char *)_prpcmsg->Buffer;
+ if (puli ==0)
+ RpcRaiseException(RPC_X_NULL_REF_POINTER);
+ data_from_ndr((PRPC_MESSAGE)_prpcmsg, (void __RPC_FAR *) (puli), "4ll", 8);
+ /* receive data into &_ret_value */
+ long_from_ndr((PRPC_MESSAGE)_prpcmsg, (unsigned long *)&_ret_value);
+ }
+ RpcFinally
+ {
+ _message.Buffer = _packet;
+ _status = I_RpcFreeBuffer(&_message);
+ if (_status) RpcRaiseException(_status);
+ }
+ RpcEndFinally
+
+ return (_ret_value);
+ }
+SCODE StringIn(
+ handle_t hRpc,
+ LPWSTR pwsz)
+ {
+ SCODE _ret_value;
+ unsigned char * _packet;
+ unsigned int _length;
+ unsigned char * _buffer;
+ unsigned char * _treebuf;
+ unsigned char * _tempbuf;
+ RPC_STATUS _status;
+ RPC_MESSAGE _message;
+ PRPC_MESSAGE _prpcmsg = & _message;
+
+ ((void)( _packet ));
+ ((void)( _buffer ));
+ ((void)( _treebuf ));
+ ((void)( _tempbuf ));
+ ((void)( _length ));
+ _message.Handle = hRpc;
+ _message.RpcInterfaceInformation = (void __RPC_FAR *) &___RpcClientInterface;
+ _prpcmsg->BufferLength = 0;
+ if (pwsz ==0)
+ RpcRaiseException(RPC_X_NULL_REF_POINTER);
+ tree_size_ndr((void __RPC_FAR *)&(pwsz), (PRPC_MESSAGE)_prpcmsg, "s2", 1);
+ _message.ProcNum = ( 12 );
+ _message.RpcFlags = ( 0 );
+ _status = I_RpcGetBuffer(&_message);
+ if (_status) RpcRaiseException(_status);
+ _packet = _message.Buffer;
+ _length = _prpcmsg->BufferLength;
+ _prpcmsg->BufferLength = 0;
+ tree_into_ndr((void __RPC_FAR *)&(pwsz), (PRPC_MESSAGE)_prpcmsg, "s2", 1);
+ _prpcmsg->Buffer = _packet;
+ _prpcmsg->BufferLength = _length;
+ _status = I_RpcSendReceive(&_message);
+ if (_status) RpcRaiseException(_status);
+ _packet = _message.Buffer;
+ RpcTryFinally
+ {
+ /* receive data into &_ret_value */
+ long_from_ndr((PRPC_MESSAGE)_prpcmsg, (unsigned long *)&_ret_value);
+ }
+ RpcFinally
+ {
+ _message.Buffer = _packet;
+ _status = I_RpcFreeBuffer(&_message);
+ if (_status) RpcRaiseException(_status);
+ }
+ RpcEndFinally
+
+ return (_ret_value);
+ }
+SCODE StringOut(
+ handle_t hRpc,
+ LPWSTR *ppwsz)
+ {
+ SCODE _ret_value;
+ unsigned long _alloc_total;
+ unsigned long _valid_lower;
+ unsigned long _valid_total;
+ unsigned char * _packet;
+ unsigned int _length;
+ unsigned char * _buffer;
+ unsigned char * _treebuf;
+ unsigned char * _tempbuf;
+ unsigned char * _savebuf;
+ RPC_STATUS _status;
+ RPC_MESSAGE _message;
+ PRPC_MESSAGE _prpcmsg = & _message;
+
+ ((void)( _alloc_total ));
+ ((void)( _valid_total ));
+ ((void)( _valid_lower ));
+ ((void)( _packet ));
+ ((void)( _buffer ));
+ ((void)( _treebuf ));
+ ((void)( _tempbuf ));
+ ((void)( _savebuf ));
+ ((void)( _length ));
+ _message.Handle = hRpc;
+ _message.RpcInterfaceInformation = (void __RPC_FAR *) &___RpcClientInterface;
+ _prpcmsg->BufferLength = 0;
+ _message.ProcNum = ( 13 );
+ _message.RpcFlags = ( 0 );
+ _status = I_RpcGetBuffer(&_message);
+ if (_status) RpcRaiseException(_status);
+ _packet = _message.Buffer;
+ _prpcmsg->Buffer = _packet;
+ _status = I_RpcSendReceive(&_message);
+ if (_status) RpcRaiseException(_status);
+ _packet = _message.Buffer;
+ RpcTryFinally
+ {
+ _tempbuf = (unsigned char *)_prpcmsg->Buffer;
+ _treebuf = 0;
+ if (ppwsz ==0)
+ RpcRaiseException(RPC_X_NULL_REF_POINTER);
+ *(unsigned long *)&_prpcmsg->Buffer += 3;
+ *(unsigned long *)&_prpcmsg->Buffer &= 0xfffffffc;
+ if (*(*(unsigned long **)&_prpcmsg->Buffer)++)
+ {
+ // recv total number of elements
+ long_from_ndr((PRPC_MESSAGE)_prpcmsg, &_alloc_total);
+ if ((*ppwsz) ==0)
+ {
+ (*ppwsz) = (WCHAR *)MIDL_user_allocate ((size_t)(_alloc_total * sizeof(WCHAR)));
+ }
+ data_from_ndr((PRPC_MESSAGE)_prpcmsg, (void __RPC_FAR *) ((*ppwsz)), "s2", 1);
+ }
+ else
+ {
+ (*ppwsz) = 0;
+ }
+ /* receive data into &_ret_value */
+ long_from_ndr((PRPC_MESSAGE)_prpcmsg, (unsigned long *)&_ret_value);
+ }
+ RpcFinally
+ {
+ _message.Buffer = _packet;
+ _status = I_RpcFreeBuffer(&_message);
+ if (_status) RpcRaiseException(_status);
+ }
+ RpcEndFinally
+
+ return (_ret_value);
+ }
+SCODE StringInOut(
+ handle_t hRpc,
+ LPWSTR pwsz)
+ {
+ SCODE _ret_value;
+ unsigned long _alloc_total;
+ unsigned long _valid_lower;
+ unsigned long _valid_total;
+ unsigned char * _packet;
+ unsigned int _length;
+ unsigned char * _buffer;
+ unsigned char * _treebuf;
+ unsigned char * _tempbuf;
+ unsigned char * _savebuf;
+ RPC_STATUS _status;
+ RPC_MESSAGE _message;
+ PRPC_MESSAGE _prpcmsg = & _message;
+
+ ((void)( _alloc_total ));
+ ((void)( _valid_total ));
+ ((void)( _valid_lower ));
+ ((void)( _packet ));
+ ((void)( _buffer ));
+ ((void)( _treebuf ));
+ ((void)( _tempbuf ));
+ ((void)( _savebuf ));
+ ((void)( _length ));
+ _message.Handle = hRpc;
+ _message.RpcInterfaceInformation = (void __RPC_FAR *) &___RpcClientInterface;
+ _prpcmsg->BufferLength = 0;
+ if (pwsz ==0)
+ RpcRaiseException(RPC_X_NULL_REF_POINTER);
+ tree_size_ndr((void __RPC_FAR *)&(pwsz), (PRPC_MESSAGE)_prpcmsg, "s2", 1);
+ _message.ProcNum = ( 14 );
+ _message.RpcFlags = ( 0 );
+ _status = I_RpcGetBuffer(&_message);
+ if (_status) RpcRaiseException(_status);
+ _packet = _message.Buffer;
+ _length = _prpcmsg->BufferLength;
+ _prpcmsg->BufferLength = 0;
+ tree_into_ndr((void __RPC_FAR *)&(pwsz), (PRPC_MESSAGE)_prpcmsg, "s2", 1);
+ _prpcmsg->Buffer = _packet;
+ _prpcmsg->BufferLength = _length;
+ _status = I_RpcSendReceive(&_message);
+ if (_status) RpcRaiseException(_status);
+ _packet = _message.Buffer;
+ RpcTryFinally
+ {
+ _tempbuf = (unsigned char *)_prpcmsg->Buffer;
+ _treebuf = 0;
+ if (pwsz ==0)
+ RpcRaiseException(RPC_X_NULL_REF_POINTER);
+ // recv total number of elements
+ long_from_ndr((PRPC_MESSAGE)_prpcmsg, &_alloc_total);
+ data_from_ndr((PRPC_MESSAGE)_prpcmsg, (void __RPC_FAR *) (pwsz), "s2", 1);
+ /* receive data into &_ret_value */
+ long_from_ndr((PRPC_MESSAGE)_prpcmsg, (unsigned long *)&_ret_value);
+ }
+ RpcFinally
+ {
+ _message.Buffer = _packet;
+ _status = I_RpcFreeBuffer(&_message);
+ if (_status) RpcRaiseException(_status);
+ }
+ RpcEndFinally
+
+ return (_ret_value);
+ }
+SCODE GuidIn(
+ handle_t hRpc,
+ GUID guid)
+ {
+ SCODE _ret_value;
+ unsigned char * _packet;
+ unsigned char * _tempbuf;
+ RPC_STATUS _status;
+ RPC_MESSAGE _message;
+ PRPC_MESSAGE _prpcmsg = & _message;
+
+ ((void)( _packet ));
+ ((void)( _tempbuf ));
+ _message.Handle = hRpc;
+ _message.RpcInterfaceInformation = (void __RPC_FAR *) &___RpcClientInterface;
+ _prpcmsg->BufferLength = 16;
+ _message.ProcNum = ( 15 );
+ _message.RpcFlags = ( 0 );
+ _status = I_RpcGetBuffer(&_message);
+ if (_status) RpcRaiseException(_status);
+ _packet = _message.Buffer;
+ /* send data from &guid */
+ NDRcopy (_prpcmsg->Buffer, (void __RPC_FAR *) (&guid), (unsigned int)(16));
+ *(unsigned long *)&_prpcmsg->Buffer += 16;
+ _prpcmsg->Buffer = _packet;
+ _status = I_RpcSendReceive(&_message);
+ if (_status) RpcRaiseException(_status);
+ _packet = _message.Buffer;
+ RpcTryFinally
+ {
+ /* receive data into &_ret_value */
+ long_from_ndr((PRPC_MESSAGE)_prpcmsg, (unsigned long *)&_ret_value);
+ }
+ RpcFinally
+ {
+ _message.Buffer = _packet;
+ _status = I_RpcFreeBuffer(&_message);
+ if (_status) RpcRaiseException(_status);
+ }
+ RpcEndFinally
+
+ return (_ret_value);
+ }
+SCODE GuidOut(
+ handle_t hRpc,
+ GUID *pguid)
+ {
+ SCODE _ret_value;
+ unsigned long _alloc_total;
+ unsigned char * _packet;
+ unsigned char * _tempbuf;
+ RPC_STATUS _status;
+ RPC_MESSAGE _message;
+ PRPC_MESSAGE _prpcmsg = & _message;
+
+ ((void)( _alloc_total ));
+ ((void)( _packet ));
+ ((void)( _tempbuf ));
+ _message.Handle = hRpc;
+ _message.RpcInterfaceInformation = (void __RPC_FAR *) &___RpcClientInterface;
+ _prpcmsg->BufferLength = 0;
+ _message.ProcNum = ( 16 );
+ _message.RpcFlags = ( 0 );
+ _status = I_RpcGetBuffer(&_message);
+ if (_status) RpcRaiseException(_status);
+ _packet = _message.Buffer;
+ _prpcmsg->Buffer = _packet;
+ _status = I_RpcSendReceive(&_message);
+ if (_status) RpcRaiseException(_status);
+ _packet = _message.Buffer;
+ RpcTryFinally
+ {
+ _tempbuf = (unsigned char *)_prpcmsg->Buffer;
+ if (pguid ==0)
+ RpcRaiseException(RPC_X_NULL_REF_POINTER);
+ _gns__GUID ((GUID *)pguid, (PRPC_MESSAGE)_prpcmsg);
+ /* receive data into &_ret_value */
+ long_from_ndr((PRPC_MESSAGE)_prpcmsg, (unsigned long *)&_ret_value);
+ }
+ RpcFinally
+ {
+ _message.Buffer = _packet;
+ _status = I_RpcFreeBuffer(&_message);
+ if (_status) RpcRaiseException(_status);
+ }
+ RpcEndFinally
+
+ return (_ret_value);
+ }
diff --git a/private/oleutest/perform/cairole/tests/rawrpc_x.c b/private/oleutest/perform/cairole/tests/rawrpc_x.c
new file mode 100644
index 000000000..4701c238f
--- /dev/null
+++ b/private/oleutest/perform/cairole/tests/rawrpc_x.c
@@ -0,0 +1,5 @@
+#include <string.h>
+#include <limits.h>
+#include <rpc.h>
+
+#include "rawrpc.h"
diff --git a/private/oleutest/perform/cairole/ui/bm_cache.cxx b/private/oleutest/perform/cairole/ui/bm_cache.cxx
new file mode 100644
index 000000000..dfedda4e1
--- /dev/null
+++ b/private/oleutest/perform/cairole/ui/bm_cache.cxx
@@ -0,0 +1,503 @@
+//+------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1993.
+//
+// File: bm_Cache.cxx
+//
+// Contents: Contains the impl of COleCacheTest which deals with Clipboard related
+// apis.
+//
+// Classes: COleCacheTest
+//
+// Functions:
+//
+// History:
+//
+//--------------------------------------------------------------------------
+
+#include <headers.cxx>
+#pragma hdrstop
+
+#include "hlp_util.hxx"
+#include "hlp_iocs.hxx"
+#include "hlp_ias.hxx"
+#include "hlp_app.hxx"
+#include "hlp_site.hxx"
+#include "hlp_doc.hxx"
+#include "bm_cache.hxx"
+#include <oleauto.h>
+
+
+//**********************************************************************
+//
+// CCacheTest::Name, SetUp, Run, CleanUp
+//
+// Purpose:
+//
+// These routines provide the implementation for the Name, Setup,
+// Run and CleanUp of the class CCacheTest. For details see the doc
+// for driver what are these routines supposed to do.
+//
+// Parameters:
+//
+//
+// Return Value:
+//
+// None
+//
+//
+// Comments:
+// If STRESS is defined don't do anything with timer variable! We are
+// not interested in time values.
+//
+//********************************************************************
+
+
+TCHAR *COleCacheTest::Name ()
+{
+ return TEXT("CacheTest");
+}
+
+
+SCODE COleCacheTest::Setup (CTestInput *pInput)
+{
+ CTestBase::Setup(pInput);
+ HRESULT sc;
+ HRESULT hres;
+
+#ifdef STRESS
+ //If stress condition loop number of time = STRESSCOUNT
+ m_ulIterations = STRESSCOUNT;
+#else
+ // get iteration count
+ m_ulIterations = pInput->GetIterations(Name());
+#endif
+
+ // initialize timing arrays
+#ifndef STRESS
+
+ //INIT_RESULTS(m_CacheTimesOutl.ulCreateCache);
+ for (int xx = 0; xx < TEST_MAX_ITERATIONS; xx++)
+ {
+ m_CacheTimesOutl[xx].ulCreateCache = NOTAVAIL;
+ m_CacheTimesOutl[xx].ulCache = NOTAVAIL;
+ m_CacheTimesOutl[xx].ulInitCache = NOTAVAIL;
+ m_CacheTimesOutl[xx].ulLoadCache = NOTAVAIL;
+ m_CacheTimesOutl[xx].ulSaveCache = NOTAVAIL;
+ m_CacheTimesOutl[xx].ulUncache = NOTAVAIL;
+ m_CacheTimesOutl[xx].ulUpdateCache = NOTAVAIL;
+ m_CacheTimesOutl[xx].ulDiscardCache = NOTAVAIL;
+ }
+
+#endif
+
+
+ sc = OleInitialize(NULL);
+ if (FAILED(sc))
+ {
+ Log (TEXT("Setup - OleInitialize failed."), sc);
+ return sc;
+ }
+
+ hres = CLSIDFromString(OutlineClassName, &m_clsidOutl);
+ Log (TEXT("CLSIDFromString returned ."), hres);
+ assert (hres == NOERROR);
+
+ //Create root Doc and STorage for Doc
+ m_lpDoc = CSimpleDoc::Create();
+
+ //Create Individual Objects and Init the table
+ for (ULONG iIter=0; iIter<m_ulIterations; iIter++) {
+
+ // Create an instance of Site
+ CSimpleSite *pObj = CSimpleSite::Create(m_lpDoc, iIter);
+ if (pObj)
+ m_pSite[iIter] = pObj;
+ }
+
+ return sc;
+}
+
+
+SCODE COleCacheTest::Cleanup ()
+{
+
+
+ for (ULONG iIter=0; iIter<m_ulIterations; iIter++)
+ {
+ delete m_pSite[iIter];
+ }
+
+ OleUninitialize();
+ return S_OK;
+}
+
+
+SCODE COleCacheTest::Run ()
+{
+ BOOL fRet;
+
+ fRet = CallRunCache(m_clsidOutl, m_pSite, m_pOleCache2, m_ulIterations, m_CacheTimesOutl);
+ return S_OK;
+}
+
+
+
+SCODE COleCacheTest::Report (CTestOutput &output)
+{
+//Bail out immediately on STRESS because none of the following variables
+//will have sane value
+#ifdef STRESS
+ return S_OK;
+#endif
+
+ output.WriteString (TEXT("*************************************************\n"));
+ output.WriteSectionHeader (Name(), TEXT("Cache Apis"), *m_pInput);
+ output.WriteString (TEXT("*************************************************\n"));
+ output.WriteString (TEXT("\n"));
+ WriteCacheOutput(output, TEXT("Outline"), m_CacheTimesOutl, m_ulIterations);
+ output.WriteString (TEXT("\n"));
+
+
+ return S_OK;
+}
+
+//**********************************************************************
+//
+// CallRunCache
+//
+// Purpose:
+// Creates an embedded object and calls routines to create cache
+// Initialize them and then Save and load them.
+//
+//
+// Parameters:
+//
+//
+// Return Value:
+//
+// None
+//
+// Functions called:
+// OleCreate OLE2 api
+// CreateCacheObjects Create Cache objects
+// FillCache To fill up the caches with pDO
+// SaveAndLoadCache Get the estimates for Save and Load Cache
+//
+//
+// Comments:
+//
+//
+//********************************************************************
+
+
+BOOL CallRunCache(REFCLSID rclsid, CSimpleSite *pSite[], LPOLECACHE2 pOleCache2[],
+ ULONG ulIterations, CacheTimes Cachetimes[])
+{
+ HRESULT hres;
+ ULONG iIter;
+ BOOL retVal = FALSE;
+ LPDATAOBJECT pDO = NULL;
+
+ CSimpleSite* pTempSite = CSimpleSite::Create(pSite[0]->m_lpDoc, -1); //Some temporary name
+ if (!pTempSite)
+ goto error;
+
+ //If we have not had any problem then
+ HEAPVALIDATE() ;
+ hres = OleCreate(rclsid, IID_IOleObject, OLERENDER_DRAW, NULL,
+ &pTempSite->m_OleClientSite, pTempSite->m_lpObjStorage,
+ (VOID FAR* FAR*)&pTempSite->m_lpOleObject);
+
+ LOGRESULTS (TEXT("OleCreate "), hres);
+ if (hres != NOERROR)
+ {
+ goto error;
+ }
+ hres = pTempSite->m_lpOleObject->QueryInterface(IID_IDataObject, (LPVOID FAR*)&pDO);
+ if (hres != NOERROR)
+ goto error;
+
+
+ //Now call Appropriate routines to Save and Cache the objects
+ hres = CreateCacheObjects( pSite, pOleCache2, ulIterations, Cachetimes);
+ if (hres != NOERROR)
+ goto error; //there is no point in going if we had problem with creation
+ FillCache(pDO, pOleCache2, ulIterations, Cachetimes);
+ SaveAndLoadCache(pSite, pOleCache2, ulIterations, Cachetimes);
+
+ retVal = TRUE;
+
+error:
+
+ if (hres != NOERROR)
+ Log (TEXT("Routine CallRunCache failed with hres = "), hres);
+
+ if (pDO)
+ pDO->Release();
+ if (pTempSite)
+ {
+ pTempSite->UnloadOleObject();
+ delete pTempSite;
+ }
+
+ for (iIter=0; iIter < ulIterations; iIter++)
+ {
+ if (pOleCache2[iIter])
+ {
+ pOleCache2[iIter]->Release();
+ pOleCache2[iIter] = NULL;
+ }
+ }
+
+return retVal;
+}
+
+//**********************************************************************
+//
+// CreateCacheObjects
+//
+// Purpose:
+// Creates Cache objects and then initlaize them.
+//
+//
+//
+//
+// Parameters:
+//
+//
+// Return Value:
+//
+// HRESULT that came from IPS->InitNew
+//
+// Functions called:
+// CreateDataCache OLE2 api
+//
+//
+// Comments:
+//
+//
+//********************************************************************
+
+
+HRESULT CreateCacheObjects(CSimpleSite *pSite[], LPOLECACHE2 pOleCache2[],
+ ULONG ulIterations, CacheTimes Cachetimes[])
+
+{
+ CStopWatch sw;
+ HRESULT hres;
+ ULONG iIter;
+ BOOL retVal = FALSE;
+
+ for (iIter=0; iIter<ulIterations; iIter++)
+ {
+ sw.Reset();
+ hres = CreateDataCache(NULL, CLSID_NULL, IID_IOleCache2, (LPVOID FAR*)&pOleCache2[iIter]);
+ GetTimerVal(Cachetimes[iIter].ulCreateCache);
+
+ LOGRESULTS (TEXT("CreateDataCache "), hres);
+ if (hres != NOERROR)
+ {
+ goto error;
+ }
+ //
+ //Initlaize the cache for use later
+ //
+ LPPERSISTSTORAGE lpStg = NULL;
+ hres = pOleCache2[iIter]->QueryInterface(IID_IPersistStorage, (LPVOID FAR*) &lpStg);
+ if (hres == NOERROR)
+ {
+ hres = lpStg->InitNew(pSite[iIter]->m_lpObjStorage);
+ lpStg->Release();
+ }
+ }
+error:
+
+ if (hres != NOERROR)
+ Log (TEXT("Routine CreateCacheObject failed with hres = "), hres);
+ return hres;
+}
+
+
+VOID FillCache(LPDATAOBJECT pDO, LPOLECACHE2 pOleCache2[], ULONG ulIterations,
+ CacheTimes Cachetimes[])
+
+{
+ CStopWatch sw;
+ HRESULT hres;
+ ULONG iIter;
+ BOOL retVal = FALSE;
+
+ //Initalize the cache
+ //NOTE: What I am doing below is trying to Init the cache with format that
+ //I think are very basic and common. So that we can profile the rest of the
+ //Cache methods with these options
+ //
+ //Work On: Create more Cache nodes!!!
+ //
+ for (iIter=0; iIter<ulIterations; iIter++)
+ {
+ FORMATETC fmte;
+ DWORD dwConnection = 0L;
+
+ fmte.cfFormat = CF_METAFILEPICT;
+ fmte.dwAspect = DVASPECT_CONTENT;
+ fmte.ptd = NULL;
+ fmte.tymed = TYMED_MFPICT;
+ fmte.lindex = -1;
+
+ sw.Reset();
+ hres = pOleCache2[iIter]->Cache(&fmte, ADVF_PRIMEFIRST | ADVFCACHE_ONSAVE | ADVF_DATAONSTOP,
+ &dwConnection);
+ GetTimerVal(Cachetimes[iIter].ulCache);
+
+ LOGRESULTS (TEXT("IOleCache:Cache "), hres);
+ if (hres != NOERROR)
+ {
+ goto error;
+ }
+
+ }
+
+ //Fill the Cache from Data object provided
+ for (iIter=0; iIter<ulIterations; iIter++)
+ {
+ sw.Reset();
+ hres = pOleCache2[iIter]->InitCache(pDO);
+ GetTimerVal(Cachetimes[iIter].ulInitCache);
+
+ LOGRESULTS (TEXT("IOleCache:InitCache "), hres);
+ if (hres != NOERROR)
+ {
+ goto error;
+ }
+ }
+
+error:
+
+ if (hres != NOERROR)
+ Log (TEXT("Routine FillCache failed with hres = "), hres);
+}
+
+VOID SaveAndLoadCache(CSimpleSite *pSite[], LPOLECACHE2 pOleCache2[],
+ ULONG ulIterations, CacheTimes Cachetimes[])
+{
+ CStopWatch sw;
+ HRESULT hres;
+ ULONG iIter;
+
+ // Save the Cache, i.e. save the formats Cached
+ for (iIter=0; iIter<ulIterations; iIter++)
+ {
+ LPPERSISTSTORAGE lpStg = NULL;
+
+ hres = pOleCache2[iIter]->QueryInterface(IID_IPersistStorage, (LPVOID FAR*)&lpStg);
+ if (hres != NOERROR)
+ continue; //TRy next Cache, it is unexpected condition though
+
+ sw.Reset();
+ hres = lpStg->Save(pSite[iIter]->m_lpObjStorage, TRUE);
+ hres = lpStg->SaveCompleted(NULL);
+
+ GetTimerVal(Cachetimes[iIter].ulSaveCache);
+ if (lpStg)
+ lpStg->Release();
+ LOGRESULTS (TEXT("Cache- Save and SaveCompleted "), hres);
+ }
+
+ //
+ //To test IOC:Load we need to destroy old cache nodes, create new
+ //ones and ask them to laod themselves
+ //
+ for (iIter=0; iIter < ulIterations; iIter++)
+ {
+ if (pOleCache2[iIter])
+ {
+ pOleCache2[iIter]->Release();
+ pOleCache2[iIter] = NULL;
+ }
+ }
+
+ //Create new set of Cache
+ for (iIter=0; iIter<ulIterations; iIter++)
+ {
+ sw.Reset();
+ hres = CreateDataCache(NULL, CLSID_NULL, IID_IOleCache2, (LPVOID FAR*)&pOleCache2[iIter]);
+ GetTimerVal(Cachetimes[iIter].ulCreateCache);
+
+ LOGRESULTS (TEXT("CreateDataCache "), hres);
+ if (hres != NOERROR)
+ {
+ goto error;
+ }
+ }
+
+ //Load the Cache from the storage provided
+ for (iIter=0; iIter<ulIterations; iIter++)
+ {
+ LPPERSISTSTORAGE lpStg = NULL;
+
+ //Query for IPS to load the object
+ hres = pOleCache2[iIter]->QueryInterface(IID_IPersistStorage, (LPVOID FAR*) &lpStg);
+ if (hres != NOERROR)
+ continue; //Try next Cache
+
+ sw.Reset();
+ hres = lpStg->Load(pSite[iIter]->m_lpObjStorage);
+ GetTimerVal(Cachetimes[iIter].ulLoadCache);
+
+ if (lpStg)
+ lpStg->Release();
+ LOGRESULTS (TEXT("Cache- Load "), hres);
+ } //End For
+
+error:
+
+ if (hres != NOERROR)
+ Log (TEXT("Routine SaveAndLoadCache failed with hres = "), hres);
+
+}
+
+void WriteCacheOutput(CTestOutput &output, LPTSTR lpstr, CacheTimes *CTimes, ULONG ulIterations)
+{
+ UINT iIter;
+
+ output.WriteString (TEXT("Name"));
+ output.WriteString (lpszTab);
+ output.WriteString (TEXT("Create"));
+ output.WriteString (lpszTab);
+ output.WriteString (TEXT("IOC:Cache"));
+ output.WriteString (lpszTab);
+ output.WriteString (TEXT("IOC:InitCache"));
+ output.WriteString (lpszTab);
+ output.WriteString (TEXT("LoadCache"));
+ output.WriteString (lpszTab);
+ output.WriteString (TEXT("SaveCache"));
+ output.WriteString (TEXT("\n"));
+
+ for (iIter = 0; iIter < ulIterations; iIter++)
+ {
+ output.WriteString (lpstr);
+ output.WriteString (lpszTab);
+ output.WriteString (lpszTab);
+ output.WriteLong (CTimes[iIter].ulCreateCache);
+ output.WriteString (lpszTab);
+ output.WriteLong (CTimes[iIter].ulCache);
+ output.WriteString (lpszTab);
+ output.WriteLong (CTimes[iIter].ulInitCache);
+ output.WriteString (lpszTab);
+ output.WriteLong (CTimes[iIter].ulLoadCache);
+ output.WriteString (lpszTab);
+ output.WriteLong (CTimes[iIter].ulSaveCache);
+ output.WriteString (TEXT("\n"));
+ }
+
+ }
+
+
+
+
+
+
+
diff --git a/private/oleutest/perform/cairole/ui/bm_cache.hxx b/private/oleutest/perform/cairole/ui/bm_cache.hxx
new file mode 100644
index 000000000..7b4d0df4c
--- /dev/null
+++ b/private/oleutest/perform/cairole/ui/bm_cache.hxx
@@ -0,0 +1,69 @@
+//+------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1993.
+//
+// File: bm_cache.hxx
+// It contains the definition for COleCacheTest class.
+//
+//
+// History: SanjayK Created
+//
+//--------------------------------------------------------------------------
+
+#ifndef _BM_CACHE_HXX_
+#define _BM_CACHE_HXX_
+
+#include <bm_base.hxx>
+
+
+typedef struct _tagCacheTimes {
+ ULONG ulCreateCache;
+ ULONG ulCache;
+ ULONG ulInitCache;
+ ULONG ulLoadCache;
+ ULONG ulSaveCache;
+ ULONG ulUncache;
+ ULONG ulUpdateCache;
+ ULONG ulDiscardCache;
+ } CacheTimes;
+
+
+class COleCacheTest : public CTestBase
+{
+public:
+ virtual TCHAR *Name ();
+ virtual SCODE Setup (CTestInput *input);
+ virtual SCODE Run ();
+ virtual SCODE Report (CTestOutput &OutputFile);
+ virtual SCODE Cleanup ();
+
+private:
+ ULONG m_ulIterations;
+
+#ifdef STRESS
+ LPOLECACHE2 m_pOleCache2[STRESSCOUNT];
+ CSimpleSite* m_pSite[STRESSCOUNT];
+#else
+ LPOLECACHE2 m_pOleCache2[TEST_MAX_ITERATIONS];
+ CSimpleSite* m_pSite[TEST_MAX_ITERATIONS];
+#endif
+
+ CSimpleDoc* m_lpDoc;
+ CLSID m_clsidOutl;
+
+ CacheTimes m_CacheTimesOutl[TEST_MAX_ITERATIONS];
+
+};
+
+BOOL CallRunCache(REFCLSID rclsid, CSimpleSite *pSite[], LPOLECACHE2 pOleCache2[], ULONG ulIterations, CacheTimes Cachetimes[]);
+HRESULT CreateCacheObjects(CSimpleSite *pSite[], LPOLECACHE2 pOleCache2[],
+ ULONG ulIterations, CacheTimes Cachetimes[]) ;
+VOID FillCache(LPDATAOBJECT pDO, LPOLECACHE2 pOleCache2[], ULONG ulIterations,
+ CacheTimes Cachetimes[]);
+VOID SaveAndLoadCache(CSimpleSite *pSite[], LPOLECACHE2 pOleCache2[],
+ ULONG ulIterations, CacheTimes Cachetimes[]);
+
+void WriteCacheOutput(CTestOutput &output, LPTSTR lpstr, CacheTimes *CTimes, ULONG ulIterations);
+
+#endif
diff --git a/private/oleutest/perform/cairole/ui/bm_clip.cxx b/private/oleutest/perform/cairole/ui/bm_clip.cxx
new file mode 100644
index 000000000..4a599b5b3
--- /dev/null
+++ b/private/oleutest/perform/cairole/ui/bm_clip.cxx
@@ -0,0 +1,608 @@
+//+------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1993.
+//
+// File: bm_Clip.cxx
+//
+// Contents: Contains the impl of CClipbrdTest which deals with
+// Clipboard related apis.
+//
+// Classes: CClipbrdTest
+//
+// Functions:
+//
+// History: Doesn't work yet. The code to place data on the clipboard
+// uses autoamation which isn't supported in the server.
+//
+//--------------------------------------------------------------------------
+
+#include <headers.cxx>
+#pragma hdrstop
+
+#include "hlp_util.hxx"
+#include "hlp_iocs.hxx"
+#include "hlp_ias.hxx"
+#include "hlp_app.hxx"
+#include "hlp_site.hxx"
+#include "hlp_doc.hxx"
+#include "bm_Clip.hxx"
+#include <oleauto.h>
+
+
+//**********************************************************************
+//
+// CClipbrd::Name, SetUp, Run, CleanUp
+//
+// Purpose:
+//
+// These routines provide the implementation for the Name, Setup,
+// Run and CleanUp of the class CClipbrd. For details see the doc
+// for driver what are these routines supposed to do.
+//
+// Parameters:
+//
+//
+// Return Value:
+//
+// None
+//
+//
+// Comments:
+// If STRESS is defined don't do anything with timer variable! We are
+// not interested in time values.
+//
+//********************************************************************
+
+
+TCHAR *CClipbrdTest::Name ()
+{
+ return TEXT("ClipbrdTest");
+}
+
+
+
+SCODE CClipbrdTest::Setup (CTestInput *pInput)
+{
+ CTestBase::Setup(pInput);
+ HRESULT sc;
+ HRESULT hres;
+
+#ifdef STRESS
+ //If stress condition loop number of time = STRESSCOUNT
+ m_ulIterations = STRESSCOUNT;
+#else
+ // get iteration count
+ m_ulIterations = pInput->GetIterations(Name());
+#endif
+
+ // initialize timing arrays
+
+#ifndef STRESS
+
+ INIT_RESULTS(m_ulOleGetClipbrd);
+ INIT_RESULTS(m_ulOleQueryCreate);
+ INIT_RESULTS(m_ulOleQueryLink);
+
+ INIT_RESULTS(m_ulCreateFromClipOutl);
+ INIT_RESULTS(m_ulCreateFromClipRenderDrawOutl);
+ INIT_RESULTS(m_ulCreateFromClipRenderAsisOutl);
+
+ INIT_RESULTS(m_ulCreateLinkFromClipOutl);
+ INIT_RESULTS(m_ulCreateLinkFromClipRenderDrawOutl);
+
+ INIT_RESULTS(m_ulCreateStaticFromClipRenderDrawOutl);
+ INIT_RESULTS(m_ulCreateStaticFromClipRenderDrawBMOutl);
+#endif //STRESS
+
+ sc = OleInitialize(NULL);
+ if (FAILED(sc))
+ {
+ Log (TEXT("Setup - OleInitialize failed."), sc);
+ return sc;
+ }
+
+ hres = CLSIDFromString(OutlineClassName, &m_clsidOutl);
+ Log (TEXT("CLSIDFromString returned ."), hres);
+ assert (hres == NOERROR);
+
+ //Create root Doc and STorage for Doc
+ m_lpDoc = CSimpleDoc::Create();
+
+ //Create Individual Objects and Init the table
+ for (ULONG iIter=0; iIter<m_ulIterations; iIter++) {
+
+ // CreateLink an instance of Site
+ CSimpleSite *pObj = CSimpleSite::Create(m_lpDoc, iIter);
+ if (pObj)
+ m_pSite[iIter] = pObj;
+ }
+
+ return sc;
+}
+
+
+SCODE CClipbrdTest::Cleanup ()
+{
+
+ for (ULONG iIter=0; iIter<m_ulIterations; iIter++)
+ {
+ delete m_pSite[iIter];
+ }
+
+ OleUninitialize();
+ return S_OK;
+}
+
+
+//**********************************************************************
+//
+// CClipbrd::Run
+//
+// Purpose:
+// This is the work horse routine which calls OLE apis.
+//
+//
+// Parameters:
+//
+//
+// Return Value:
+//
+// None
+//
+// Functions called:
+// OleSetClipboard OLE - Is profiled here
+// OleGetClipboard OLE - Is profiled here
+// OleCreateFromClip defined below
+//
+//
+// Comments:
+//
+//********************************************************************
+
+
+SCODE CClipbrdTest::Run ()
+{
+ CStopWatch sw;
+ HRESULT hres;
+ BOOL fRet;
+
+ TCHAR szTemp[MAX_PATH];
+ OLECHAR szOutlFileName[MAX_PATH];
+
+
+ // Get file name of .ini file. if not specified in the command
+ // line, use the default BM.INI in the local directory
+ GetCurrentDirectory (MAX_PATH, szTemp);
+ swprintf(szOutlFileName,
+#ifdef UNICODE
+ L"%s\\foo.oln",
+#else
+ L"%S\\foo.oln",
+#endif
+ szTemp);
+
+ //Empty clipboard and get the estimate on empty clipboard
+ hres = OleSetClipboard(NULL);
+ sw.Reset();
+ hres = OleSetClipboard(NULL);
+ GetTimerVal(m_ulSetClipEmpty);
+
+ fRet = CallOleGetClipbrd(szOutlFileName, m_ulIterations, m_ulOleGetClipbrd,
+ m_ulOleQueryCreate, m_ulOleQueryLink);
+
+ //Now Empty clipboard again. This time Data on clipboard from SvrOutl
+ sw.Reset();
+ hres = OleSetClipboard(NULL);
+ GetTimerVal(m_ulSetClipOutl);
+
+
+ //
+ //Test cases for OleCreateFromData
+ //
+
+ fRet = CallCreateFromClip(szOutlFileName, m_pSite, IID_IOleObject, OLERENDER_NONE,
+ NULL, m_ulIterations, m_ulCreateFromClipOutl, OLECREATE);
+ //Empty clipboard for next test case
+ hres = OleSetClipboard(NULL);
+ fRet = CallCreateFromClip(szOutlFileName, m_pSite, IID_IOleObject, OLERENDER_DRAW,
+ NULL, m_ulIterations, m_ulCreateFromClipRenderDrawOutl, OLECREATE);
+ //Empty clipboard for next test case
+ hres = OleSetClipboard(NULL);
+ fRet = CallCreateFromClip(szOutlFileName, m_pSite, IID_IOleObject, OLERENDER_ASIS,
+ NULL, m_ulIterations, m_ulCreateFromClipRenderAsisOutl, OLECREATE);
+
+ //
+ //Test cases for OleCreateLinkFromData
+ //
+ hres = OleSetClipboard(NULL);
+ fRet = CallCreateFromClip(szOutlFileName, m_pSite, IID_IOleObject, OLERENDER_NONE,
+ NULL, m_ulIterations, m_ulCreateLinkFromClipOutl, OLECREATELINK);
+ //Empty clipboard for next test case
+ hres = OleSetClipboard(NULL);
+ fRet = CallCreateFromClip(szOutlFileName, m_pSite, IID_IOleObject, OLERENDER_DRAW,
+ NULL, m_ulIterations, m_ulCreateLinkFromClipRenderDrawOutl, OLECREATELINK);
+
+ //
+ //Test cases for OleCreateLinkFromData
+ //
+ //I would have liked Bitmap but SvrOutl only supports Metafile
+ FORMATETC fmte = {CF_ENHMETAFILE, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
+ hres = OleSetClipboard(NULL);
+ fRet = CallCreateFromClip(szOutlFileName, m_pSite, IID_IOleObject, OLERENDER_FORMAT,
+ &fmte, m_ulIterations, m_ulCreateStaticFromClipRenderDrawBMOutl, OLECREATESTATIC);
+ //Empty clipboard for next test case
+ hres = OleSetClipboard(NULL);
+ fRet = CallCreateFromClip(szOutlFileName, m_pSite, IID_IOleObject, OLERENDER_DRAW,
+ NULL, m_ulIterations, m_ulCreateStaticFromClipRenderDrawOutl, OLECREATESTATIC);
+ return S_OK;
+}
+
+
+
+SCODE CClipbrdTest::Report (CTestOutput &output)
+{
+//Bail out immediately on STRESS because none of the following variables
+//will have sane value
+#ifdef STRESS
+ return S_OK;
+#endif
+
+ output.WriteString (TEXT("*************************************************\n"));
+ output.WriteSectionHeader (Name(), TEXT("Clipbrd Apis"), *m_pInput);
+ output.WriteString (TEXT("*************************************************\n"));
+
+ output.WriteString (TEXT("\n"));
+ output.WriteResults (TEXT("OleGetClipbrd \t\t\t"), m_ulIterations, m_ulOleGetClipbrd);
+ output.WriteString (TEXT("\n"));
+
+ output.WriteString (TEXT("\n"));
+ output.WriteResults (TEXT("OleSetClipbrd Empty\t\t"), 1, &m_ulSetClipEmpty);
+ output.WriteString (TEXT("\n"));
+ output.WriteResults (TEXT("OleSetClipbrd Data\t\t"), 1, &m_ulSetClipOutl);
+ output.WriteString (TEXT("\n"));
+
+ output.WriteString (TEXT("\n"));
+ output.WriteString (TEXT("***************************************\n"));
+ output.WriteResults (TEXT("OleCreateFromClip Outline \t\t\t"), m_ulIterations, m_ulCreateFromClipOutl);
+ output.WriteString (TEXT("\n"));
+
+ output.WriteString (TEXT("\n"));
+ output.WriteResults (TEXT("OleCreateFromClip with RenderDraw Outline\t"), m_ulIterations, m_ulCreateFromClipRenderDrawOutl);
+ output.WriteString (TEXT("\n"));
+
+ output.WriteString (TEXT("\n"));
+ output.WriteResults (TEXT("OleCreateFromClip with RenderFormatMF Outline\t "), m_ulIterations, m_ulCreateFromClipRenderFormatMFOutl);
+ output.WriteString (TEXT("\n"));
+
+
+ output.WriteString (TEXT("\n"));
+ output.WriteResults (TEXT("OleCreateFromClip with RenderAsIs Outline \t"), m_ulIterations, m_ulCreateFromClipRenderAsisOutl);
+ output.WriteString (TEXT("\n"));
+ output.WriteString (TEXT("\n"));
+ output.WriteString (TEXT("***************************************\n"));
+ output.WriteResults (TEXT("OleCreateLinkFromClip Outline \t\t"), m_ulIterations, m_ulCreateLinkFromClipOutl);
+ output.WriteString (TEXT("\n"));
+
+ output.WriteString (TEXT("\n"));
+ output.WriteResults (TEXT("OleCreateLinkFromClip with RenderDraw Outline \t"), m_ulIterations, m_ulCreateLinkFromClipRenderDrawOutl);
+ output.WriteString (TEXT("\n"));
+ output.WriteString (TEXT("***************************************\n"));
+ output.WriteResults (TEXT("OleCreateStaticFromClip Outline\t"), m_ulIterations, m_ulCreateStaticFromClipRenderDrawOutl);
+ output.WriteString (TEXT("\n"));
+
+#if VERIFYSTATICBEHAVIOR
+
+ output.WriteString (TEXT("\n"));
+ output.WriteResults (TEXT("OleCreateStaticFromClip with RenderDraw Outline \t"), m_ulIterations, m_ulCreateStaticFromClipRenderDrawBMOutl);
+ output.WriteString (TEXT("\n"));
+#endif
+
+
+ return S_OK;
+}
+
+
+
+//**********************************************************************
+//
+// OleGetClipboard
+//
+// Purpose:
+// This routine is called CallOleGetClipboard but it also instruments
+// OLeQueryXX apis! (This was the best place to do that otherwise what
+// to do with Clipboard data).
+//
+//
+// Parameters:
+//
+//
+// Return Value:
+//
+// None
+//
+// Functions called:
+// CreateFileMoniker OLE - creates file moniker
+// CreateBindCtx OLE
+// IDispatch::GetIDsOfNames Dispatch routine which makes call into SvrOutl (yet another version!)
+// OleGetClipboard OLE - Is profiled here
+// OleQueryCreateFromData OLE - Is profiled here
+// OleLinkFromData OLE - Is profiled here
+//
+//
+// Comments:
+//
+//********************************************************************
+
+
+
+BOOL CallOleGetClipbrd(LPCOLESTR lpFileName, ULONG ulIterations, ULONG uOleClipbrdtime[],
+ ULONG uOleQCreatetime[], ULONG uOleQLinktime[])
+{
+ CStopWatch sw;
+ HRESULT hres;
+ ULONG iIter;
+ BOOL retVal = FALSE;
+
+ LPDATAOBJECT pDO = NULL;
+ LPMONIKER pmk = NULL;
+ LPBC pbc = NULL;
+ IDispatch FAR* pDisp = NULL;
+
+ hres = CreateFileMoniker(lpFileName, &pmk);
+
+ if (hres != NOERROR)
+ goto error;
+ else {
+
+
+ //Bind to moniker object and ask for IID_IDispatch
+ hres = CreateBindCtx(NULL, &pbc);
+ if (hres != NOERROR)
+ goto error;
+
+ hres = pmk->BindToObject(pbc, NULL, IID_IDispatch, (LPVOID FAR*) &pDisp);
+ if (hres != NOERROR)
+ goto error;
+
+
+ //Now Make outline copy object to clipboard
+ OLECHAR FAR* pCopy = L"COPY";
+ DISPID dispid;
+ EXCEPINFO expinfo;
+ DISPPARAMS vNullDisp = {NULL, 0, 0, NULL};
+
+ hres = pDisp->GetIDsOfNames(
+ IID_NULL,
+ &pCopy,
+ 1, LOCALE_USER_DEFAULT,
+ &dispid);
+
+ if (hres == NOERROR) {
+ //Invoke Method Copy so that SvrOutl copies data to clipboard
+ hres = pDisp->Invoke( dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD,
+ &vNullDisp, NULL, &expinfo, NULL);
+ if (hres != NOERROR)
+ goto error;
+ }
+
+ pDisp->Release();
+ pDisp = NULL;
+ }
+
+ for ( iIter=0; iIter<ulIterations; iIter++) {
+
+ //If we have not had any problem then
+ sw.Reset();
+ //Get the Clipboard data
+ hres = OleGetClipboard(&pDO);
+ GetTimerVal(uOleClipbrdtime[iIter]);
+
+ LOGRESULTS (TEXT("OleGetClipboard "), hres);
+ if (hres != NOERROR)
+ {
+ goto error;
+ }
+
+ //Now call QueryCreate and QueryLinkFromCLip Apis
+
+ sw.Reset();
+ hres = OleQueryCreateFromData(pDO);
+ GetTimerVal(uOleQCreatetime[iIter]);
+ LOGRESULTS (TEXT("OleQueryCreateFromData "), hres);
+
+ sw.Reset();
+ hres = OleQueryLinkFromData(pDO);
+ GetTimerVal(uOleQLinktime[iIter]);
+ LOGRESULTS (TEXT("OleQueryCreateLinkFromData "), hres);
+
+
+ if (pDO) {
+ pDO->Release();
+ pDO = NULL;
+ }
+ }
+
+
+ retVal = TRUE;
+
+error:
+ if (hres != NOERROR)
+ Log (TEXT("Routine OleGetClipbrd failed with hres = "), hres);
+
+ if (pmk)
+ pmk->Release();
+ if (pDO)
+ pDO->Release();
+ if (pbc)
+ pbc->Release();
+ if (pDisp)
+ pDisp->Release();
+
+return retVal;
+}
+
+
+
+
+//**********************************************************************
+//
+// CallCreateFromClip
+//
+// Purpose:
+// This routine creates the OLE object from Clipboard data. It creates
+// both embedded and linked object.
+//
+//
+// Parameters:
+//
+//
+// Return Value:
+//
+// None
+//
+// Functions called:
+// CreateFileMoniker OLE - creates file moniker
+// CreateBindCtx OLE
+// IDispatch::GetIDsOfNames Dispatch routine which makes call into SvrOutl (yet another version!)
+// IDispatch::Invoke Dispatch routine asking Svroutl to copy to clipboard
+// OleGetClipboard OLE - called to get Data object on Clip
+// OleCreateFromData OLE - Is profiled here
+// OleCreateLinkFromData OLE - Is profiled here
+// OleCreateStaticFromData OLE - Is profiled here
+//
+//
+// Comments:
+//
+//********************************************************************
+
+BOOL CallCreateFromClip(LPCOLESTR lpFileName, CSimpleSite * pSite[], REFIID riid, DWORD renderopt,
+ LPFORMATETC pFormatEtc, ULONG ulIterations, ULONG uOleClipbrdtime[], CREATE_METHOD MethodID)
+{
+ CStopWatch sw;
+ HRESULT hres;
+ ULONG iIter;
+ BOOL retVal = FALSE;
+
+ LPDATAOBJECT pDO = NULL;
+ LPMONIKER pmk = NULL;
+ LPBC pbc = NULL;
+ IDispatch FAR* pDisp = NULL;
+
+ hres = CreateFileMoniker(lpFileName, &pmk);
+
+ if (hres != NOERROR)
+ goto error;
+ else {
+
+
+ //Bind to moniker object and ask for IID_IDispatch
+ hres = CreateBindCtx(NULL, &pbc);
+ if (hres != NOERROR)
+ goto error;
+
+ hres = pmk->BindToObject(pbc, NULL, IID_IDispatch, (LPVOID FAR*)&pDisp);
+ if (hres != NOERROR)
+ goto error;
+
+
+ //Now Make outline copy object to clipboard
+ OLECHAR FAR* pCopy = L"COPY";
+ DISPID dispid;
+ EXCEPINFO expinfo;
+ DISPPARAMS vNullDisp = {NULL, 0, 0, NULL};
+
+
+ hres = pDisp->GetIDsOfNames(
+ IID_NULL,
+ &pCopy,
+ 1, LOCALE_USER_DEFAULT,
+ &dispid);
+ if (hres == NOERROR) {
+ hres = pDisp->Invoke( dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD,
+ &vNullDisp, NULL, &expinfo, NULL);
+ if (hres != NOERROR)
+ goto error;
+ }
+
+ pDisp->Release();
+ pDisp = NULL;
+ }
+ //Get the Clipboard data
+ hres = OleGetClipboard(&pDO);
+ if (hres != NOERROR)
+ goto error;
+
+
+ for ( iIter=0; iIter<ulIterations; iIter++) {
+
+ //If we have not had any problem then
+ HEAPVALIDATE() ;
+ switch(MethodID) {
+ case OLECREATE:
+ {
+
+ sw.Reset();
+ hres = OleCreateFromData(pDO, riid, renderopt,
+ pFormatEtc, &pSite[iIter]->m_OleClientSite,
+ pSite[iIter]->m_lpObjStorage, (VOID FAR* FAR*)&pSite[iIter]->m_lpOleObject);
+ break;
+ }
+
+ case OLECREATELINK:
+ {
+
+ sw.Reset();
+ hres = OleCreateLinkFromData(pDO, riid, renderopt,
+ pFormatEtc, &pSite[iIter]->m_OleClientSite,
+ pSite[iIter]->m_lpObjStorage, (VOID FAR* FAR*)&pSite[iIter]->m_lpOleObject);
+ break;
+ }
+
+ case OLECREATESTATIC:
+ {
+
+ sw.Reset();
+ hres = OleCreateStaticFromData(pDO, riid, renderopt,
+ pFormatEtc, &pSite[iIter]->m_OleClientSite,
+ pSite[iIter]->m_lpObjStorage, (VOID FAR* FAR*)&pSite[iIter]->m_lpOleObject);
+ break;
+ }
+ default:
+ assert(FALSE);
+ }
+ GetTimerVal(uOleClipbrdtime[iIter]);
+
+ LOGRESULTS (TEXT("OleCreate/Link/Static "), hres);
+ if (hres != NOERROR)
+ {
+ goto error;
+ }
+
+ }
+
+
+ for (iIter=0; iIter<ulIterations; iIter++)
+ {
+ // Unload the object and release the Ole Object
+ pSite[iIter]->UnloadOleObject();
+ }
+ retVal = TRUE;
+
+error:
+ if (hres != NOERROR)
+ Log (TEXT("Routine CallCreateFromClip failed with hres = "), hres);
+
+ if (pmk)
+ pmk->Release();
+ if (pDO)
+ pDO->Release();
+ if (pbc)
+ pbc->Release();
+ if (pDisp)
+ pDisp->Release();
+return retVal;
+}
+
+
+
diff --git a/private/oleutest/perform/cairole/ui/bm_clip.hxx b/private/oleutest/perform/cairole/ui/bm_clip.hxx
new file mode 100644
index 000000000..11adb9f3f
--- /dev/null
+++ b/private/oleutest/perform/cairole/ui/bm_clip.hxx
@@ -0,0 +1,87 @@
+//+------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1993.
+//
+// File: bm_clip.hxx
+// It contains the definition for CClipbrdTest class.
+//
+//
+// History: SanjayK Created
+//
+//--------------------------------------------------------------------------
+
+#ifndef _BM_CLIP_HXX_
+#define _BM_CLIP_HXX_
+
+#include <bm_base.hxx>
+
+class CClipbrdTest : public CTestBase
+{
+public:
+ virtual TCHAR *Name ();
+ virtual SCODE Setup (CTestInput *input);
+ virtual SCODE Run ();
+ virtual SCODE Report (CTestOutput &OutputFile);
+ virtual SCODE Cleanup ();
+
+private:
+ ULONG m_ulIterations;
+
+#ifdef STRESS
+ CSimpleSite* m_pSite[STRESSCOUNT];
+#else
+ CSimpleSite* m_pSite[TEST_MAX_ITERATIONS];
+#endif
+ CSimpleDoc* m_lpDoc;
+ CLSID m_clsidOutl;
+ // Clipbrd Apis
+
+
+ ULONG m_ulSetClipEmpty;
+ ULONG m_ulSetClipOutl;
+
+ ULONG m_ulOleGetClipbrd[TEST_MAX_ITERATIONS];
+
+ ULONG m_ulOleQueryCreate[TEST_MAX_ITERATIONS];
+ ULONG m_ulOleQueryLink[TEST_MAX_ITERATIONS];
+
+ ULONG m_ulCreateFromClipOutl[TEST_MAX_ITERATIONS];
+ ULONG m_ulCreateFromClipRenderDrawOutl[TEST_MAX_ITERATIONS];
+ ULONG m_ulCreateFromClipRenderAsisOutl[TEST_MAX_ITERATIONS];
+ ULONG m_ulCreateFromClipRenderFormatMFOutl[TEST_MAX_ITERATIONS];
+
+ ULONG m_ulCreateLinkFromClipOutl[TEST_MAX_ITERATIONS];
+ ULONG m_ulCreateLinkFromClipRenderDrawOutl[TEST_MAX_ITERATIONS];
+
+ ULONG m_ulCreateStaticFromClipRenderDrawOutl[TEST_MAX_ITERATIONS];
+ ULONG m_ulCreateStaticFromClipRenderDrawBMOutl[TEST_MAX_ITERATIONS];
+
+};
+
+typedef enum {
+ OLECREATE,
+ OLECREATELINK,
+ OLECREATESTATIC
+ } CREATE_METHOD;
+
+
+BOOL CallOleGetClipbrd(LPCOLESTR lpszFileName, ULONG ulIterations, ULONG uOleClipbrdtime[], ULONG uOleQT[], ULONG uOleQLT[]);
+BOOL CallCreateFromClip(LPCOLESTR lpszFileName, CSimpleSite * pSite[], REFIID riid, DWORD renderopt,
+ LPFORMATETC pFormatEtc, ULONG ulIterations, ULONG uOleClipbrdtime[], CREATE_METHOD Method);
+
+#endif
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/private/oleutest/perform/cairole/ui/bm_crt.cxx b/private/oleutest/perform/cairole/ui/bm_crt.cxx
new file mode 100644
index 000000000..72f8ad207
--- /dev/null
+++ b/private/oleutest/perform/cairole/ui/bm_crt.cxx
@@ -0,0 +1,332 @@
+//+------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1993.
+//
+// File: bm_Crt.cxx
+//
+// Contents: Create apis
+//
+// Classes: CCreateApi
+//
+// Functions:
+//
+// History:
+//
+//--------------------------------------------------------------------------
+
+#include <headers.cxx>
+#pragma hdrstop
+
+#include "hlp_util.hxx"
+#include "hlp_iocs.hxx"
+#include "hlp_ias.hxx"
+#include "hlp_app.hxx"
+#include "hlp_site.hxx"
+#include "hlp_doc.hxx"
+#include "bm_Crt.hxx"
+
+TCHAR vlpScratchBuf[256];
+
+//**********************************************************************
+//
+// CCreate::Name, SetUp, Run, CleanUp
+//
+// Purpose:
+//
+// These routines provide the implementation for the Name, Setup,
+// Run and CleanUp of the class CCreateTest. For details see the doc
+// for driver what are these routines supposed to do.
+//
+// Parameters:
+//
+//
+// Return Value:
+//
+// None
+//
+//
+// Comments:
+// If STRESS is defined don't do anything with timer variable! We are
+// not interested in time values.
+//
+//********************************************************************
+
+
+TCHAR *CCreateTest::Name ()
+{
+ return TEXT("CreateTest");
+}
+
+
+SCODE CCreateTest::Setup (CTestInput *pInput)
+{
+ CTestBase::Setup(pInput);
+ HRESULT sc;
+ HRESULT hres;
+
+#ifdef STRESS
+ //If stress condition loop number of time = STRESSCOUNT
+ m_ulIterations = STRESSCOUNT;
+#else
+ // get iteration count
+ m_ulIterations = pInput->GetIterations(Name());
+#endif
+
+#ifndef STRESS
+ // initialize timing arrays
+ INIT_RESULTS(m_ulOleCreateSr32);
+ INIT_RESULTS(m_ulOleCreateOutl);
+ INIT_RESULTS(m_ulOleCreateRenderDrawSr32);
+ INIT_RESULTS(m_ulOleCreateRenderDrawOutl);
+#endif
+
+
+ sc = OleInitialize(NULL);
+ if (FAILED(sc))
+ {
+ Log (TEXT("Setup - OleInitialize failed."), sc);
+ return sc;
+ }
+
+ hres = CLSIDFromString(L"Sr32test", &m_clsidSr32);
+ Log (TEXT("CLSIDFromString returned ."), hres);
+ if (hres != NOERROR)
+ return E_FAIL;
+
+ hres = CLSIDFromString(OutlineClassName, &m_clsidOutl);
+ Log (TEXT("CLSIDFromString returned ."), hres);
+ if (hres != NOERROR)
+ return E_FAIL;
+
+ //Create Doc and Root storage
+ m_lpDoc = CSimpleDoc::Create();
+
+ for (ULONG iIter=0; iIter<m_ulIterations; iIter++) {
+
+ // Create an instance of Site
+ CSimpleSite *pObj = CSimpleSite::Create(m_lpDoc, iIter);
+ if (pObj)
+ m_pSite[iIter] = pObj;
+ }
+
+ return sc;
+}
+
+
+
+SCODE CCreateTest::Cleanup ()
+{
+ for (ULONG iIter=0; iIter<m_ulIterations; iIter++)
+ {
+ delete m_pSite[iIter];
+ }
+
+
+ OleUninitialize();
+ return S_OK;
+}
+
+
+//**********************************************************************
+//
+// CCreateTest::Run
+//
+// Purpose:
+// This is the work horse routine which calls OLE apis.
+// The profile is done by calling OleCreate on Sr32test and SvrOutl.
+// We get results for different FormatEtc types.
+//
+//
+// Parameters:
+//
+//
+// Return Value:
+//
+// None
+//
+// Functions called:
+// CallOleCreate defined below
+//
+//
+// Comments:
+// Need to add more Server types including In-Proc servers.
+//
+//********************************************************************
+
+
+
+SCODE CCreateTest::Run ()
+{
+ CStopWatch sw;
+ BOOL fRet;
+
+ fRet = CallOleCreate(m_clsidSr32, m_pSite, IID_IOleObject,
+ NULL, NULL, m_ulIterations, m_ulOleCreateSr32);
+ fRet = CallOleCreate(m_clsidOutl, m_pSite, IID_IOleObject, NULL, NULL,
+ m_ulIterations, m_ulOleCreateOutl);
+
+ fRet = CallOleCreate(m_clsidSr32, m_pSite, IID_IOleObject, OLERENDER_DRAW,
+ NULL, m_ulIterations, m_ulOleCreateRenderDrawSr32);
+ fRet = CallOleCreate(m_clsidOutl, m_pSite, IID_IOleObject, OLERENDER_DRAW,
+ NULL, m_ulIterations, m_ulOleCreateRenderDrawOutl);
+
+ //Create the objects with RenderFormat = Metafile
+
+ FORMATETC fmte = {CF_METAFILEPICT, NULL, DVASPECT_CONTENT, -1, TYMED_MFPICT};
+ fRet = CallOleCreate(m_clsidSr32, m_pSite, IID_IOleObject, OLERENDER_FORMAT,
+ &fmte, m_ulIterations, m_ulOleCreateRenderFormatMFSr32);
+ fRet = CallOleCreate(m_clsidOutl, m_pSite, IID_IOleObject, OLERENDER_FORMAT,
+ &fmte, m_ulIterations, m_ulOleCreateRenderFormatMFOutl);
+
+
+ //Create the objects with RenderFormat = Bitmap
+ fmte.cfFormat = CF_BITMAP;
+ fmte.dwAspect = DVASPECT_CONTENT;
+ fmte.tymed = TYMED_GDI;
+ fRet = CallOleCreate(m_clsidSr32, m_pSite, IID_IOleObject, OLERENDER_FORMAT,
+ &fmte, m_ulIterations, m_ulOleCreateRenderFormatBMSr32);
+ fRet = CallOleCreate(m_clsidOutl, m_pSite, IID_IOleObject, OLERENDER_FORMAT,
+ &fmte, m_ulIterations, m_ulOleCreateRenderFormatBMOutl);
+
+ //Create the objects with RenderFormat = Text
+ fmte.cfFormat = CF_TEXT;
+ fmte.dwAspect = DVASPECT_CONTENT;
+ fmte.tymed = TYMED_HGLOBAL;
+ fRet = CallOleCreate(m_clsidSr32, m_pSite, IID_IOleObject, OLERENDER_FORMAT,
+ &fmte, m_ulIterations, m_ulOleCreateRenderFormatTextSr32);
+ fRet = CallOleCreate(m_clsidOutl, m_pSite, IID_IOleObject, OLERENDER_FORMAT,
+ &fmte, m_ulIterations, m_ulOleCreateRenderFormatTextOutl);
+
+ return S_OK;
+}
+
+
+
+SCODE CCreateTest::Report (CTestOutput &output)
+{
+//Bail out immediately on STRESS because none of the following variables
+//will have sane value
+#ifdef STRESS
+ return S_OK;
+#endif
+
+ output.WriteString (TEXT("*************************************************\n"));
+ output.WriteSectionHeader (Name(), TEXT("Create Apis\t\t"), *m_pInput);
+ output.WriteString (TEXT("*************************************************\n"));
+
+ output.WriteString (TEXT("\n"));
+ output.WriteResults (TEXT("OleCreate Sr32test \t\t\t"), m_ulIterations, m_ulOleCreateSr32);
+ output.WriteString (TEXT("\n"));
+
+ output.WriteString (TEXT("\n"));
+ output.WriteResults (TEXT("OleCreate Outline\t\t\t "), m_ulIterations, m_ulOleCreateOutl);
+ output.WriteString (TEXT("\n"));
+
+ output.WriteString (TEXT("\n"));
+ output.WriteResults (TEXT("OleCreate with RenderDraw Sr32test \t"), m_ulIterations, m_ulOleCreateRenderDrawSr32);
+ output.WriteString (TEXT("\n"));
+
+ output.WriteString (TEXT("\n"));
+ output.WriteResults (TEXT("OleCreate with RenderDraw Outline \t "), m_ulIterations, m_ulOleCreateRenderDrawOutl);
+ output.WriteString (TEXT("\n"));
+
+ output.WriteString (TEXT("\n"));
+ output.WriteResults (TEXT("OleCreate with RenderFormatMF Sr32test \t"), m_ulIterations, m_ulOleCreateRenderFormatMFSr32);
+ output.WriteString (TEXT("\n"));
+
+ output.WriteString (TEXT("\n"));
+ output.WriteResults (TEXT("OleCreate with RenderFormatMF Outline \t "), m_ulIterations, m_ulOleCreateRenderFormatMFOutl);
+ output.WriteString (TEXT("\n"));
+
+ output.WriteString (TEXT("\n"));
+ output.WriteResults (TEXT("OleCreate with RenderFormatBM Sr32test \t"), m_ulIterations, m_ulOleCreateRenderFormatBMSr32);
+ output.WriteString (TEXT("\n"));
+
+ output.WriteString (TEXT("\n"));
+ output.WriteResults (TEXT("OleCreate with RenderFormatBM Outline \t "), m_ulIterations, m_ulOleCreateRenderFormatBMOutl);
+ output.WriteString (TEXT("\n"));
+
+ output.WriteString (TEXT("\n"));
+ output.WriteResults (TEXT("OleCreate with RenderFormatTxt Sr32test\t "), m_ulIterations, m_ulOleCreateRenderFormatTextSr32);
+ output.WriteString (TEXT("\n"));
+
+ output.WriteString (TEXT("\n"));
+ output.WriteResults (TEXT("OleCreate with RenderFormatTxt Outline\t "), m_ulIterations, m_ulOleCreateRenderFormatTextOutl);
+ output.WriteString (TEXT("\n"));
+
+ return S_OK;
+}
+
+
+
+
+
+
+//**********************************************************************
+//
+// CallOleCreate
+//
+// Purpose:
+// Calls OleCreate to create the object and then destroys them.
+//
+//
+// Parameters:
+//
+//
+// Return Value:
+//
+// None
+//
+// Functions called:
+// OleCreate OLE2 api - Is profiled here
+//
+//
+// Comments:
+// Need to add more Server types including In-Proc servers.
+//
+//********************************************************************
+
+
+
+BOOL CallOleCreate(REFCLSID rclsid, CSimpleSite * pSite[], REFIID riid, DWORD renderopt,
+ LPFORMATETC pFormatEtc, ULONG ulIterations, ULONG uOleCreatetime[])
+{
+ CStopWatch sw;
+ HRESULT hres;
+ ULONG iIter;
+
+ for ( iIter=0; iIter<ulIterations; iIter++)
+ {
+ HEAPVALIDATE();
+ sw.Reset();
+ hres = OleCreate(rclsid, riid, renderopt, pFormatEtc,
+ &pSite[iIter]->m_OleClientSite,
+ pSite[iIter]->m_lpObjStorage, (VOID FAR* FAR*)&pSite[iIter]->m_lpOleObject);
+
+ GetTimerVal(uOleCreatetime[iIter]);
+ LOGRESULTS (TEXT("OleCreate "), hres);
+ if (hres != NOERROR)
+ {
+ goto error;
+ }
+ }
+
+ //CleanUp before going to Next
+ for (iIter=0; iIter<ulIterations; iIter++)
+ {
+ // Unload the object and release the Ole Object
+ pSite[iIter]->UnloadOleObject();
+
+#ifdef REVIEW //BIG REVIEW I am keeping same ClientSIte and Reusing
+ //delete pSite[iIter];
+#endif
+ }
+ return TRUE;
+
+error:
+ if (hres != NOERROR)
+ Log (TEXT("Routine CallOleCreate failed with hres = "), hres);
+
+ return FALSE;
+}
diff --git a/private/oleutest/perform/cairole/ui/bm_crt.hxx b/private/oleutest/perform/cairole/ui/bm_crt.hxx
new file mode 100644
index 000000000..9bb406159
--- /dev/null
+++ b/private/oleutest/perform/cairole/ui/bm_crt.hxx
@@ -0,0 +1,67 @@
+//+------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1993.
+//
+// File: bm_crt.hxx
+//
+// Contents: test creation apis
+//
+// Classes: CCreateApis
+//
+// Functions:
+//
+// History:
+//
+//--------------------------------------------------------------------------
+
+#ifndef _BM_CREATE_HXX_
+#define _BM_CREATE_HXX_
+
+#include <bm_base.hxx>
+
+class CCreateTest : public CTestBase
+{
+public:
+ virtual TCHAR *Name ();
+ virtual SCODE Setup (CTestInput *input);
+ virtual SCODE Run ();
+ virtual SCODE Report (CTestOutput &OutputFile);
+ virtual SCODE Cleanup ();
+
+private:
+ ULONG m_ulIterations;
+
+#ifdef STRESS
+ CSimpleSite* m_pSite[STRESSCOUNT];
+#else
+ CSimpleSite* m_pSite[TEST_MAX_ITERATIONS];
+#endif
+ CSimpleDoc* m_lpDoc;
+ CLSID m_clsidSr32;
+ CLSID m_clsidOutl;
+
+ // Create Apis
+ ULONG m_ulOleCreateSr32[TEST_MAX_ITERATIONS];
+ ULONG m_ulOleCreateOutl[TEST_MAX_ITERATIONS];
+
+ ULONG m_ulOleCreateRenderDrawSr32[TEST_MAX_ITERATIONS];
+ ULONG m_ulOleCreateRenderDrawOutl[TEST_MAX_ITERATIONS];
+
+ ULONG m_ulOleCreateRenderFormatMFSr32[TEST_MAX_ITERATIONS];
+ ULONG m_ulOleCreateRenderFormatMFOutl[TEST_MAX_ITERATIONS];
+
+ ULONG m_ulOleCreateRenderFormatBMSr32[TEST_MAX_ITERATIONS];
+ ULONG m_ulOleCreateRenderFormatBMOutl[TEST_MAX_ITERATIONS];
+
+ ULONG m_ulOleCreateRenderFormatTextSr32[TEST_MAX_ITERATIONS];
+ ULONG m_ulOleCreateRenderFormatTextOutl[TEST_MAX_ITERATIONS];
+
+
+};
+
+BOOL CallOleCreate(REFCLSID rclsid, CSimpleSite * pSite[], REFIID riid, DWORD renderopt,
+ LPFORMATETC pFormatEtc, ULONG ulIterations, ULONG uOleCreatetime[]);
+
+
+#endif
diff --git a/private/oleutest/perform/cairole/ui/bm_crtl.cxx b/private/oleutest/perform/cairole/ui/bm_crtl.cxx
new file mode 100644
index 000000000..233a54bc3
--- /dev/null
+++ b/private/oleutest/perform/cairole/ui/bm_crtl.cxx
@@ -0,0 +1,355 @@
+//+------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1993.
+//
+// File: bm_crtl.cxx
+//
+// Contents: CreateLink apis
+//
+// Classes: CCreateLinkApi
+//
+// Functions:
+//
+// History:
+//
+//--------------------------------------------------------------------------
+
+#include <headers.cxx>
+#pragma hdrstop
+
+#include "hlp_util.hxx"
+#include "hlp_iocs.hxx"
+#include "hlp_ias.hxx"
+#include "hlp_app.hxx"
+#include "hlp_site.hxx"
+#include "hlp_doc.hxx"
+#include "bm_crtl.hxx"
+
+
+//**********************************************************************
+//
+// CCreateLinkTest::Name, SetUp, Run, CleanUp
+//
+// Purpose:
+//
+// These routines provide the implementation for the Name, Setup,
+// Run and CleanUp of the class CCreateLinkTest. For details see the doc
+// for driver what are these routines supposed to do.
+//
+// Parameters:
+//
+//
+// Return Value:
+//
+// None
+//
+//
+// Comments:
+// If STRESS is defined don't do anything with timer variable! We are
+// not interested in time values.
+//
+//********************************************************************
+
+
+TCHAR *CCreateLinkTest::Name ()
+{
+ return TEXT("CreateLinkTest");
+}
+
+
+
+SCODE CCreateLinkTest::Setup (CTestInput *pInput)
+{
+ CTestBase::Setup(pInput);
+ HRESULT sc;
+ HRESULT hres;
+
+#ifdef STRESS
+ //If stress condition loop number of time = STRESSCOUNT
+ m_ulIterations = STRESSCOUNT;
+#else
+ // get iteration count
+ m_ulIterations = pInput->GetIterations(Name());
+#endif
+
+#ifndef STRESS
+ // initialize timing arrays
+ INIT_RESULTS(m_ulOleCreateLinkSr32);
+ INIT_RESULTS(m_ulOleCreateLinkOutl);
+ INIT_RESULTS(m_ulOleCreateLinkRenderDrawSr32);
+ INIT_RESULTS(m_ulOleCreateLinkRenderDrawOutl);
+
+#endif
+
+ sc = OleInitialize(NULL);
+ if (FAILED(sc))
+ {
+ Log (TEXT("Setup - OleInitialize failed."), sc);
+ return sc;
+ }
+
+ hres = CLSIDFromString(L"Sr32test", &m_clsidSr32);
+ Log (TEXT("CLSIDFromString returned ."), hres);
+ if (hres != NOERROR)
+ return E_FAIL;
+
+ hres = CLSIDFromString(OutlineClassName, &m_clsidOutl);
+ Log (TEXT("CLSIDFromString returned ."), hres);
+ if (hres != NOERROR)
+ return E_FAIL;
+
+ //CreateLink Doc and Root Storage
+ m_lpDoc = CSimpleDoc::Create();
+
+ for (ULONG iIter=0; iIter<m_ulIterations; iIter++)
+ {
+ // CreateLink an instance of Site
+ CSimpleSite *pObj = CSimpleSite::Create(m_lpDoc, iIter);
+ if (pObj)
+ m_pSite[iIter] = pObj;
+ }
+
+ return sc;
+}
+
+
+SCODE CCreateLinkTest::Cleanup ()
+{
+
+ for (ULONG iIter=0; iIter<m_ulIterations; iIter++)
+ {
+ delete m_pSite[iIter];
+ }
+
+ OleUninitialize();
+ return S_OK;
+}
+
+
+//**********************************************************************
+//
+// CCreateLinkTest::Run
+//
+// Purpose:
+// This is the work horse routine which calls OLE apis.
+// The profile is done by creating moniker then calling OleCreateLink on moniker.
+//
+//
+// Parameters:
+//
+//
+// Return Value:
+//
+// None
+//
+// Functions called:
+// CallOleCreateLink defined below
+//
+//
+// Comments:
+// Need to add more Server types including In-Proc servers.
+//
+//********************************************************************
+
+
+
+SCODE CCreateLinkTest::Run ()
+{
+ CStopWatch sw;
+ BOOL fRet;
+
+ TCHAR szTemp[MAX_PATH];
+ OLECHAR szSr2FileName[MAX_PATH];
+ OLECHAR szOutlFileName[MAX_PATH];
+
+
+ // Get file name of .ini file. if not specified in the command
+ // line, use the default BM.INI in the local directory
+
+ GetCurrentDirectory (MAX_PATH, szTemp);
+ swprintf(szSr2FileName,
+#ifdef UNICODE
+ L"%s\\foo.sr2",
+#else
+ L"%S\\foo.sr2",
+#endif
+ szTemp);
+ swprintf(szOutlFileName,
+#ifdef UNICODE
+ L"%s\\foo.oln",
+#else
+ L"%S\\foo.oln",
+#endif
+ szTemp);
+
+ fRet = CallOleCreateLink(szSr2FileName, m_pSite, IID_IOleObject, NULL,
+ NULL, m_ulIterations, m_ulOleCreateLinkSr32);
+ fRet = CallOleCreateLink(szOutlFileName, m_pSite, IID_IOleObject, NULL,
+ NULL, m_ulIterations, m_ulOleCreateLinkOutl);
+
+ fRet = CallOleCreateLink(szSr2FileName, m_pSite, IID_IOleObject, OLERENDER_DRAW,
+ NULL, m_ulIterations, m_ulOleCreateLinkRenderDrawSr32);
+ fRet = CallOleCreateLink(szOutlFileName, m_pSite, IID_IOleObject, OLERENDER_DRAW,
+ NULL, m_ulIterations, m_ulOleCreateLinkRenderDrawOutl);
+
+ //Create the objects with RenderFormat = Metafile
+ FORMATETC fmte = {CF_METAFILEPICT, NULL, DVASPECT_CONTENT, -1, TYMED_MFPICT};
+ fRet = CallOleCreateLink(szSr2FileName, m_pSite, IID_IOleObject, OLERENDER_FORMAT,
+ &fmte, m_ulIterations, m_ulOleCreateLinkRenderFormatMFSr32);
+ fRet = CallOleCreateLink(szOutlFileName, m_pSite, IID_IOleObject, OLERENDER_FORMAT,
+ &fmte, m_ulIterations, m_ulOleCreateLinkRenderFormatMFOutl);
+
+ //Create the objects with RenderFormat = Bitmap
+ fmte.cfFormat = CF_BITMAP;
+ fmte.dwAspect = DVASPECT_CONTENT;
+ fmte.tymed = TYMED_GDI;
+ fRet = CallOleCreateLink(szSr2FileName, m_pSite, IID_IOleObject, OLERENDER_FORMAT,
+ &fmte, m_ulIterations, m_ulOleCreateLinkRenderFormatBMSr32);
+
+ //Create the objects with RenderFormat = Text
+ fmte.cfFormat = CF_TEXT;
+ fmte.dwAspect = DVASPECT_CONTENT;
+ fmte.tymed = TYMED_HGLOBAL;
+ fRet = CallOleCreateLink(szSr2FileName, m_pSite, IID_IOleObject, OLERENDER_FORMAT,
+ &fmte, m_ulIterations, m_ulOleCreateLinkRenderFormatTextSr32);
+ fRet = CallOleCreateLink(szOutlFileName, m_pSite, IID_IOleObject, OLERENDER_FORMAT,
+ &fmte, m_ulIterations, m_ulOleCreateLinkRenderFormatTextOutl);
+
+
+ return S_OK;
+}
+
+
+
+SCODE CCreateLinkTest::Report (CTestOutput &output)
+{
+//Bail out immediately on STRESS because none of the following variables
+//will have sane value
+#ifdef STRESS
+ return S_OK;
+#endif
+
+ output.WriteString (TEXT("*************************************************\n"));
+ output.WriteSectionHeader (Name(), TEXT("CreateLink Apis"), *m_pInput);
+ output.WriteString (TEXT("*************************************************\n"));
+
+ output.WriteString (TEXT("\n"));
+ output.WriteResults (TEXT("OleCreateLink Sr32test\t\t\t"), m_ulIterations, m_ulOleCreateLinkSr32);
+ output.WriteString (TEXT("\n"));
+
+ output.WriteString (TEXT("\n"));
+ output.WriteResults (TEXT("OleCreateLink Outline \t\t\t"), m_ulIterations, m_ulOleCreateLinkOutl);
+ output.WriteString (TEXT("\n"));
+
+ output.WriteString (TEXT("\n"));
+ output.WriteResults (TEXT("OleCreateLink with RenderDraw Sr32test\t"), m_ulIterations, m_ulOleCreateLinkRenderDrawSr32);
+ output.WriteString (TEXT("\n"));
+
+ output.WriteString (TEXT("\n"));
+ output.WriteResults (TEXT("OleCreateLink with RenderDraw Outline\t"), m_ulIterations, m_ulOleCreateLinkRenderDrawOutl);
+ output.WriteString (TEXT("\n"));
+
+ output.WriteString (TEXT("\n"));
+ output.WriteResults (TEXT("OleCreateLink with RenderFormatMF Sr32test\t"), m_ulIterations, m_ulOleCreateLinkRenderFormatMFSr32);
+ output.WriteString (TEXT("\n"));
+
+ output.WriteString (TEXT("\n"));
+ output.WriteResults (TEXT("OleCreateLink with RenderFormatMF Outline\t"), m_ulIterations, m_ulOleCreateLinkRenderFormatMFOutl);
+ output.WriteString (TEXT("\n"));
+
+ output.WriteString (TEXT("\n"));
+ output.WriteResults (TEXT("OleCreateLink with RenderFormatBM Sr32test\t "), m_ulIterations, m_ulOleCreateLinkRenderFormatBMSr32);
+ output.WriteString (TEXT("\n"));
+
+#ifdef DOESNOTWORKFOROUTLINE
+ output.WriteString (TEXT("\n"));
+ output.WriteResults (TEXT("OleCreateLink with RenderFormatBM Outline\t"), m_ulIterations, m_ulOleCreateLinkRenderFormatBMOutl);
+ output.WriteString (TEXT("\n"));
+#endif
+
+ output.WriteString (TEXT("\n"));
+ output.WriteResults (TEXT("OleCreateLink with RenderFormatTxt Sr32test\t"), m_ulIterations, m_ulOleCreateLinkRenderFormatTextSr32);
+ output.WriteString (TEXT("\n"));
+
+ output.WriteString (TEXT("\n"));
+ output.WriteResults (TEXT("OleCreateLink with RenderFormatTxt Outline\t "), m_ulIterations, m_ulOleCreateLinkRenderFormatTextOutl);
+ output.WriteString (TEXT("\n"));
+
+ return S_OK;
+}
+
+
+
+
+//**********************************************************************
+//
+// CallOleCreateLink
+//
+// Purpose:
+// Calls OleCreateLink to create the link and then destroys them.
+//
+//
+// Parameters:
+//
+//
+// Return Value:
+//
+// None
+//
+// Functions called:
+// CreateFileMoniker OLE2 api
+// OleCreateLink OLE2 api - Is profiled here
+//
+//
+// Comments:
+// Need to add more Server types including In-Proc servers.
+//
+//********************************************************************
+
+
+
+BOOL CallOleCreateLink(LPCOLESTR lpFileName, CSimpleSite * pSite[], REFIID riid, DWORD renderopt,
+ LPFORMATETC pFormatEtc, ULONG ulIterations, ULONG uOleCreateLinktime[])
+{
+ CStopWatch sw;
+ HRESULT hres;
+ ULONG iIter;
+ LPMONIKER pmk = NULL;
+ BOOL retVal = FALSE;
+
+ hres = CreateFileMoniker(lpFileName, &pmk);
+ if (hres != NOERROR)
+ goto error;
+
+ for ( iIter=0; iIter<ulIterations; iIter++)
+ {
+ HEAPVALIDATE() ;
+ sw.Reset();
+ hres = OleCreateLink(pmk, riid, renderopt, pFormatEtc, &pSite[iIter]->m_OleClientSite,
+ pSite[iIter]->m_lpObjStorage, (VOID FAR* FAR*)&pSite[iIter]->m_lpOleObject);
+ GetTimerVal(uOleCreateLinktime[iIter]);
+
+ LOGRESULTS (TEXT("OleCreateLink "), hres);
+ if (hres != NOERROR)
+ {
+ goto error;
+ }
+ }
+
+ //CleanUp before going to Next
+ for (iIter=0; iIter<ulIterations; iIter++)
+ {
+ // Unload the object and release the Ole Object
+ pSite[iIter]->UnloadOleObject();
+ }
+ retVal = TRUE;
+
+error:
+ if (hres != NOERROR)
+ Log (TEXT("Routine CallOleCreateLink failed with hres = "), hres);
+
+ if (pmk)
+ pmk->Release();
+ return retVal;
+}
diff --git a/private/oleutest/perform/cairole/ui/bm_crtl.hxx b/private/oleutest/perform/cairole/ui/bm_crtl.hxx
new file mode 100644
index 000000000..54c3ccf77
--- /dev/null
+++ b/private/oleutest/perform/cairole/ui/bm_crtl.hxx
@@ -0,0 +1,67 @@
+//+------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1993.
+//
+// File: bm_crtl.hxx
+//
+// Contents: test creation apis
+//
+// Classes: CCreateLinkApis
+//
+// Functions:
+//
+// History:
+//
+//--------------------------------------------------------------------------
+
+#ifndef _BM_CRTL_HXX_
+#define _BM_CRTL_HXX_
+
+#include <bm_base.hxx>
+
+class CCreateLinkTest : public CTestBase
+{
+public:
+ virtual TCHAR *Name ();
+ virtual SCODE Setup (CTestInput *input);
+ virtual SCODE Run ();
+ virtual SCODE Report (CTestOutput &OutputFile);
+ virtual SCODE Cleanup ();
+
+private:
+ ULONG m_ulIterations;
+
+#ifdef STRESS
+ CSimpleSite* m_pSite[STRESSCOUNT];
+#else
+ CSimpleSite* m_pSite[TEST_MAX_ITERATIONS];
+#endif
+ CSimpleDoc* m_lpDoc;
+ CLSID m_clsidSr32;
+ CLSID m_clsidOutl;
+
+ // CreateLink Apis
+
+ ULONG m_ulOleCreateLinkSr32[TEST_MAX_ITERATIONS];
+ ULONG m_ulOleCreateLinkOutl[TEST_MAX_ITERATIONS];
+
+ ULONG m_ulOleCreateLinkRenderDrawSr32[TEST_MAX_ITERATIONS];
+ ULONG m_ulOleCreateLinkRenderDrawOutl[TEST_MAX_ITERATIONS];
+
+ ULONG m_ulOleCreateLinkRenderFormatMFSr32[TEST_MAX_ITERATIONS];
+ ULONG m_ulOleCreateLinkRenderFormatMFOutl[TEST_MAX_ITERATIONS];
+
+ ULONG m_ulOleCreateLinkRenderFormatBMSr32[TEST_MAX_ITERATIONS];
+ ULONG m_ulOleCreateLinkRenderFormatBMOutl[TEST_MAX_ITERATIONS];
+
+ ULONG m_ulOleCreateLinkRenderFormatTextSr32[TEST_MAX_ITERATIONS];
+ ULONG m_ulOleCreateLinkRenderFormatTextOutl[TEST_MAX_ITERATIONS];
+
+};
+
+BOOL CallOleCreateLink(LPCOLESTR lpszFileName, CSimpleSite * pSite[], REFIID riid, DWORD renderopt,
+ LPFORMATETC pFormatEtc, ULONG ulIterations, ULONG uOleCreateLinktime[]);
+
+
+#endif
diff --git a/private/oleutest/perform/cairole/ui/bm_link.cxx b/private/oleutest/perform/cairole/ui/bm_link.cxx
new file mode 100644
index 000000000..4b5781db4
--- /dev/null
+++ b/private/oleutest/perform/cairole/ui/bm_link.cxx
@@ -0,0 +1,629 @@
+//+------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1993.
+//
+// File: bm_Link.cxx
+//
+// Contents: Profile methods which manipulate Links, i.e. interface IOleLink
+//
+// Classes: CIOLTest
+//
+// Functions:
+//
+// History:
+//
+//--------------------------------------------------------------------------
+
+#include <headers.cxx>
+#pragma hdrstop
+
+#include "hlp_util.hxx"
+#include "hlp_iocs.hxx"
+#include "hlp_ias.hxx"
+#include "hlp_app.hxx"
+#include "hlp_site.hxx"
+#include "hlp_doc.hxx"
+#include "bm_link.hxx"
+
+
+//**********************************************************************
+//
+// CIOLTest::Name, SetUp, Run, CleanUp
+//
+// Purpose:
+//
+// These routines provide the implementation for the Name, Setup,
+// Run and CleanUp of the class CIOLTest. For details see the doc
+// for driver what are these routines supposed to do.
+//
+// Parameters:
+//
+//
+// Return Value:
+//
+// None
+//
+//
+// Comments:
+// If STRESS is defined don't do anything with timer variable! We are
+// not interested in time values.
+//
+//********************************************************************
+
+
+TCHAR *CIOLTest::Name ()
+{
+ return TEXT("IOLTest");
+}
+
+
+
+SCODE CIOLTest::Setup (CTestInput *pInput)
+{
+ CTestBase::Setup(pInput);
+ HRESULT sc;
+ HRESULT hres;
+
+#ifdef STRESS
+ //If stress condition loop number of time = STRESSCOUNT
+ m_ulIterations = STRESSCOUNT;
+#else
+ // get iteration count
+ m_ulIterations = pInput->GetIterations(Name());
+#endif
+
+#ifndef STRESS
+ // initialize timing arrays
+ INIT_LINKRESULTS(m_ulOleLinkSr32);
+ INIT_LINKRESULTS(m_ulOleLinkOutl);
+
+#endif
+
+ sc = OleInitialize(NULL);
+ if (FAILED(sc))
+ {
+ Log (TEXT("Setup - OleInitialize failed."), sc);
+ return sc;
+ }
+
+ hres = CLSIDFromString(L"Sr32test", &m_clsidSr32);
+ Log (TEXT("CLSIDFromString returned ."), hres);
+ if (hres != NOERROR)
+ return E_FAIL;
+
+ hres = CLSIDFromString(OutlineClassName, &m_clsidOutl);
+ Log (TEXT("CLSIDFromString returned ."), hres);
+ if (hres != NOERROR)
+ return E_FAIL;
+
+ //CreateLink Doc and Root Storage
+ m_lpDoc = CSimpleDoc::Create();
+
+ for (ULONG iIter=0; iIter<m_ulIterations; iIter++)
+ {
+ // CreateLink an instance of Site
+ CSimpleSite *pObj = CSimpleSite::Create(m_lpDoc, iIter);
+ if (pObj)
+ m_pSite[iIter] = pObj;
+ }
+
+ return sc;
+}
+
+
+SCODE CIOLTest::Cleanup ()
+{
+
+ for (ULONG iIter=0; iIter<m_ulIterations; iIter++)
+ {
+ delete m_pSite[iIter];
+ }
+
+
+ OleUninitialize();
+ return S_OK;
+}
+
+
+//**********************************************************************
+//
+// CIOLTest::Run
+//
+// Purpose:
+// This is the work horse routine which calls OLE apis.
+// The profile is done by creating moniker then calling OleCreateLink on moniker.
+//
+// Parameters:
+//
+//
+// Return Value:
+//
+// None
+//
+// Functions called:
+// CallOleCreate defined below
+//
+//
+// Comments:
+// Need to add more Server types including In-Proc servers.
+//
+//********************************************************************
+
+
+
+SCODE CIOLTest::Run ()
+{
+ CStopWatch sw;
+ BOOL fRet;
+
+ TCHAR szTemp[MAX_PATH];
+ OLECHAR szSr2FileName[MAX_PATH];
+ OLECHAR szOutlFileName[MAX_PATH];
+
+
+ GetCurrentDirectory (MAX_PATH, szTemp);
+ swprintf(szSr2FileName,
+#ifdef UNICODE
+ L"%s\\foo.sr2",
+#else
+ L"%S\\foo.sr2",
+#endif
+ szTemp);
+ swprintf(szOutlFileName,
+#ifdef UNICODE
+ L"%s\\foo.oln",
+#else
+ L"%S\\foo.oln",
+#endif
+ szTemp);
+
+ fRet = CallOleLinkMethods(szSr2FileName, m_pSite, m_ulIterations,
+ m_ulOleLinkSr32, L"OTS001", L"OTS002");
+ fRet = CallOleLinkMethods(szOutlFileName, m_pSite, m_ulIterations,
+ m_ulOleLinkOutl, L"Name1", L"Name2");
+
+ return S_OK;
+}
+
+
+
+SCODE CIOLTest::Report (CTestOutput &output)
+{
+
+//Bail out immediately on STRESS because none of the following variables
+//will have sane value
+#ifdef STRESS
+ return S_OK;
+#endif
+
+ output.WriteString (TEXT("*************************************************\n"));
+ output.WriteSectionHeader (Name(), TEXT("IOleLink Methods"), *m_pInput);
+ output.WriteString (TEXT("*************************************************\n"));
+
+ output.WriteString (TEXT("\n"));
+ WriteLinkOutput(output, TEXT(" Sr32test "), m_ulOleLinkSr32, m_ulIterations);
+ output.WriteString (TEXT("\n"));
+
+ output.WriteString (TEXT("\n"));
+ output.WriteString (TEXT("******************************************\n"));
+ WriteLinkOutput (output, TEXT(" Outline "), m_ulOleLinkOutl, m_ulIterations);
+ output.WriteString (TEXT("\n"));
+
+ return S_OK;
+}
+
+
+
+
+//**********************************************************************
+//
+// CallOleCreateLink
+//
+// Purpose:
+// Calls OleCreateLink to create the link and then destroys them.
+//
+//
+// Parameters:
+//
+//
+// Return Value:
+//
+// None
+//
+// Functions called:
+// CreateFileMoniker OLE2 api
+// OleCreateLink OLE2 api - Is profiled here
+//
+//
+// Comments:
+// Need to add more Server types including In-Proc servers.
+//
+//********************************************************************
+
+
+
+BOOL CallOleLinkMethods(LPCOLESTR lpFileName, CSimpleSite * pSite[],
+ ULONG ulIterations, LinkTimes IOLTime[], LPCOLESTR lpNm1, LPCOLESTR lpNm2)
+{
+ CStopWatch sw;
+ HRESULT hres;
+ ULONG iIter;
+ LPMONIKER pmk = NULL;
+ BOOL retVal = FALSE;
+#ifdef STRESS
+ LPOLELINK pLink[STRESSCOUNT] = { NULL };
+#else
+ LPOLELINK pLink[TEST_MAX_ITERATIONS] = { NULL };
+#endif
+
+ //
+ //Create the Links and also cache link pointer for rest of the tests
+ //this pointer is reqd for all the tests later
+ //
+ for ( iIter=0; iIter<ulIterations; iIter++)
+ {
+ HEAPVALIDATE() ;
+ if (!pSite[iIter])
+ goto error;
+ hres = OleCreateLinkToFile(lpFileName,
+ IID_IOleObject,
+ OLERENDER_DRAW,
+ NULL,
+ &pSite[iIter]->m_OleClientSite,
+ pSite[iIter]->m_lpObjStorage,
+ (VOID FAR* FAR*)&pSite[iIter]->m_lpOleObject
+ );
+ if (hres != NOERROR)
+ goto error;
+
+ //Cache IOleLink pointer for rest of the tests that follow below
+ hres = pSite[iIter]->m_lpOleObject->QueryInterface(IID_IOleLink, (LPVOID FAR*)&pLink[iIter]);
+ if (hres != NOERROR)
+ goto error;
+ }
+
+ //
+ //Run those tests which deal with simple running
+ //
+ CallOleLinkRunMethods(IOLTime, pLink, ulIterations);
+
+ //
+ //Call those tests that deal with SourceDisplayName
+ //
+ CallOleLinkDisplayName(IOLTime, pLink, lpFileName,
+ lpNm1, lpNm2, ulIterations);
+
+
+ retVal = TRUE;
+error:
+ if (hres != NOERROR)
+ Log (TEXT("Routine CallOleCreateLink failed with hres = "), hres);
+
+ //CleanUp before going to Next
+ for (iIter=0; iIter<ulIterations; iIter++)
+ {
+ // Unload the object and release the Ole Object
+ if (pLink[iIter])
+ pLink[iIter]->Release();
+ if (pSite[iIter])
+ pSite[iIter]->UnloadOleObject();
+ }
+
+ return retVal;
+}
+
+
+
+BOOL CallOleLinkRunMethods(LinkTimes IOLTime[], LPOLELINK pLink[], ULONG ulIterations)
+{
+ HRESULT hres;
+ CStopWatch sw;
+ ULONG iIter;
+ BOOL retVal = FALSE;
+ LPBINDCTX pBindCtx = NULL;
+
+ //
+ //1. get the first estimates using NULL BindCtx
+ //
+ for ( iIter=0; iIter< ulIterations; iIter++)
+ {
+ sw.Reset();
+ hres = pLink[iIter]->BindToSource(NULL /* !BIND_EVEN_IF_CLASSDIF */,
+ NULL /*Bind Ctx*/);
+ GetTimerVal(IOLTime[iIter].ulBindToSourceNull);
+ LOGRESULTS (TEXT("IOL:BindToSource "), hres);
+ } //End Bind To Source with Null BindCtx
+
+ //Unbind links to start next estimates. Which also BindToSource with Non
+ //NULL BindCtx
+ for ( iIter=0; iIter< ulIterations; iIter++)
+ {
+ hres = pLink[iIter]->UnbindSource();
+ }
+
+ //
+ //2. Following tests are to be done with BindContext that we get here
+ //
+ hres = CreateBindCtx(NULL, &pBindCtx);
+ if (hres != NOERROR)
+ goto error;
+ //Now get the Estimates when Binding with same BindContext
+ //
+ for ( iIter=0; iIter< ulIterations; iIter++)
+ {
+ sw.Reset();
+ hres = pLink[iIter]->BindToSource(NULL /* !BIND_EVEN_IF_CLASSDIF */,
+ pBindCtx /*Bind Ctx*/);
+ GetTimerVal(IOLTime[iIter].ulBindToSourceBindCtx);
+ LOGRESULTS (TEXT("IOL:BindToSource "), hres);
+ } //End Bind To Source with BindCtx
+
+
+ //
+ //3. Get Estimates for IOL:BindIfRunning
+ //
+ for ( iIter=0; iIter<ulIterations; iIter++)
+ {
+ sw.Reset();
+ hres = pLink[iIter]->BindIfRunning();
+ GetTimerVal(IOLTime[iIter].ulBindIfRunning);
+ LOGRESULTS (TEXT("IOL:BindIfRunning "), hres);
+ } //End BindIfRunning, when actually running.
+
+
+ //
+ //4. Get Estimates for IOL:UnbindSource
+ //
+ for ( iIter=0; iIter<ulIterations; iIter++)
+ {
+ sw.Reset();
+ hres = pLink[iIter]->UnbindSource();
+ GetTimerVal(IOLTime[iIter].ulUnbindSource);
+ LOGRESULTS (TEXT("IOL:UnbindSource "), hres);
+ sw.Reset();
+ hres = pLink[iIter]->UnbindSource();
+ GetTimerVal(IOLTime[iIter].ulUnbindSource2);
+ LOGRESULTS (TEXT("IOL:UnbindSource2 "), hres);
+ }
+ //
+ //5. Get Estimates for IOL:BindIfRunning
+ //
+ for ( iIter=0; iIter<ulIterations; iIter++)
+ {
+ sw.Reset();
+ hres = pLink[iIter]->BindIfRunning();
+ GetTimerVal(IOLTime[iIter].ulBindIfRunning2);
+ LOGRESULTS (TEXT("IOL:BindIfRunning2 "), hres);
+ } //End BindIfRunning, when not running.
+ //
+ //6. Get Estimates for IOL:UnbindSource
+ //
+ for ( iIter=0; iIter<ulIterations; iIter++)
+ {
+ sw.Reset();
+ hres = pLink[iIter]->UnbindSource();
+ GetTimerVal(IOLTime[iIter].ulUnbindSource3);
+ LOGRESULTS (TEXT("IOL:UnbindSource3 "), hres);
+ }
+
+ retVal = TRUE;
+
+error:
+ if (pBindCtx)
+ pBindCtx->Release();
+ return hres;
+}
+
+
+
+
+//**********************************************************************
+//
+// CallOleLinkDisplayName
+//
+// Purpose:
+// Calls
+//
+//
+// Parameters:
+//
+//
+// Return Value:
+//
+// None
+//
+// Functions called:
+// OleLoad OLE2 api
+// OleSave OLE2 api
+//
+//
+// Comments:
+//
+//
+//********************************************************************
+
+BOOL CallOleLinkDisplayName(LinkTimes IOLTime[], LPOLELINK pLink[],
+ LPCOLESTR lpFileName, LPCOLESTR lpNm1,
+ LPCOLESTR lpNm2, ULONG ulIterations)
+{
+ CStopWatch sw;
+ HRESULT hres;
+ HRESULT hres2;
+ ULONG iIter;
+ BOOL retVal = FALSE;
+ OLECHAR szMkName1[256];
+ OLECHAR szMkName2[256];
+ LPBINDCTX pBindCtx = NULL;
+
+ //
+ //Set the display name to something known and then call IOL:SetDisplayName
+ //Then update the link so that rest of its info is now updated by OLE.
+ //
+
+ // This code used to grab the moniker from the link, compose with an item
+ // moniker and then the displayname from the composite moniker. This
+ // works, although it's rather convoluted, the first time but then the
+ // code would end up doing it a second time and the first item moniker
+ // name would still be on the end and it would fail. Just creating the
+ // new display name ourselves seems much easier anyway.
+ //
+ //First get the Moniker Name by following routine
+ //hres = GetLinkCompositeName(pLink[0], lpNm1, &lpMkName1);
+ //if (hres != NOERROR)
+ // goto error;
+
+ swprintf(szMkName1, L"%s!%s", lpFileName, lpNm1);
+
+ for (iIter=0; iIter<ulIterations; iIter++)
+ {
+ sw.Read();
+ hres = pLink[iIter]->SetSourceDisplayName(szMkName1);
+ hres2 = pLink[iIter]->Update(NULL);
+ GetTimerVal(IOLTime[iIter].ulUpdateNull);
+ LOGRESULTS (TEXT("IOL:SetSourceDisplayName "), hres);
+ LOGRESULTS (TEXT("IOL:Update "), hres2);
+
+ } //End SetSourceDisplayName and Update
+
+
+ //
+ //Repeate the iteration when we have BindContext available. Check the
+ //results.
+ //
+ //hres = GetLinkCompositeName(pLink[0], lpNm2, &lpMkName2);
+ //if (hres != NOERROR)
+ // goto error;
+
+ swprintf(szMkName2, L"%s!%s", lpFileName, lpNm2);
+
+ hres = CreateBindCtx(NULL, &pBindCtx);
+ if (hres != NOERROR)
+ goto error;
+
+ for (iIter=0; iIter<ulIterations; iIter++)
+ {
+ sw.Read();
+ hres = pLink[iIter]->SetSourceDisplayName(szMkName2);
+ hres2 = pLink[iIter]->Update(pBindCtx);
+ GetTimerVal(IOLTime[iIter].ulUpdateBindCtx);
+ LOGRESULTS (TEXT("IOL:SetSourceDisplayName "), hres);
+ LOGRESULTS (TEXT("IOL:Update "), hres2);
+
+ } //End SetSourceDisplayName and Update
+
+
+ retVal = TRUE;
+
+error:
+ if (pBindCtx)
+ pBindCtx->Release();
+
+return retVal;
+}
+
+HRESULT GetLinkCompositeName(LPOLELINK lpLink, LPCOLESTR lpItem, LPOLESTR FAR* lpComposeName)
+{
+ HRESULT hres;
+ LPMONIKER lpLinkMon = NULL;
+ LPMONIKER lpItemMk = NULL;
+ LPMONIKER lpCompose = NULL;
+ //SInce NULL BindContext not allowed any more
+ LPBINDCTX pBindCtx = NULL;
+
+ //Get the source moniker of the link
+ hres = lpLink->GetSourceMoniker(&lpLinkMon);
+ if (hres != NOERROR)
+ goto error;
+ //Create item moniker from String Item
+ hres = CreateItemMoniker(L"!", lpItem, &lpItemMk);
+ if (hres != NOERROR)
+ goto error;
+
+ //Ask moniker to compose itself with another one in the end to get Composite
+ //moniker.
+ hres = lpLinkMon->ComposeWith(lpItemMk, FALSE, &lpCompose);
+ if (hres != NOERROR)
+ goto error;
+
+ hres = CreateBindCtx(NULL, &pBindCtx);
+ if (hres != NOERROR)
+ goto error;
+ //Get the display Name of the moniker
+ hres = lpCompose->GetDisplayName(pBindCtx /*BindCtx*/, NULL /*pmkToLeft*/,
+ lpComposeName);
+ if (hres != NOERROR)
+ goto error;
+
+error:
+ if (lpLinkMon)
+ lpLinkMon->Release();
+ if (lpItemMk)
+ lpItemMk->Release();
+ if (lpCompose)
+ lpCompose->Release();
+ if (pBindCtx)
+ pBindCtx->Release();
+
+
+ return hres;
+}
+
+void WriteLinkOutput(CTestOutput &output, LPTSTR lpstr, LinkTimes *lnkTimes, ULONG ulIterations)
+{
+ UINT iIter;
+
+ output.WriteString (TEXT("Name"));
+ output.WriteString (lpszTab);
+ output.WriteString (TEXT("BindToSource (NULL)"));
+ output.WriteString (lpszTab);
+ output.WriteString (TEXT("BindToSource"));
+ output.WriteString (lpszTab);
+ output.WriteString (TEXT("BindIfRunning"));
+ output.WriteString (lpszTab);
+ output.WriteString (TEXT("UnBindSource"));
+ output.WriteString (lpszTab);
+ output.WriteString (TEXT("UnBindSource2"));
+ output.WriteString (lpszTab);
+ output.WriteString (TEXT("BindIfRunning2"));
+ output.WriteString (lpszTab);
+ output.WriteString (TEXT("UnBindSource3"));
+ output.WriteString (lpszTab);
+ output.WriteString (TEXT("Update(NULL)"));
+ output.WriteString (lpszTab);
+ output.WriteString (TEXT("Update"));
+ output.WriteString (TEXT("\n"));
+
+ for (iIter = 0; iIter < ulIterations; iIter++)
+ {
+ output.WriteString (lpstr);
+ output.WriteLong (lnkTimes[iIter].ulBindToSourceNull);
+ output.WriteString (lpszTab);
+ output.WriteString (lpszTab);
+ output.WriteLong (lnkTimes[iIter].ulBindToSourceBindCtx);
+ output.WriteString (lpszTab);
+ output.WriteString (lpszTab);
+ output.WriteLong (lnkTimes[iIter].ulBindIfRunning);
+ output.WriteString (lpszTab);
+ output.WriteString (lpszTab);
+ output.WriteLong (lnkTimes[iIter].ulUnbindSource);
+ output.WriteString (lpszTab);
+ output.WriteString (lpszTab);
+ output.WriteLong (lnkTimes[iIter].ulUnbindSource2);
+ output.WriteString (lpszTab);
+ output.WriteString (lpszTab);
+ output.WriteLong (lnkTimes[iIter].ulBindIfRunning2);
+ output.WriteString (lpszTab);
+ output.WriteString (lpszTab);
+ output.WriteLong (lnkTimes[iIter].ulUnbindSource3);
+ output.WriteString (lpszTab);
+ output.WriteString (lpszTab);
+ output.WriteLong (lnkTimes[iIter].ulUpdateNull);
+ output.WriteString (lpszTab);
+ output.WriteString (lpszTab);
+ output.WriteLong (lnkTimes[iIter].ulUpdateBindCtx);
+ output.WriteString (TEXT("\n"));
+ }
+
+ }
+
diff --git a/private/oleutest/perform/cairole/ui/bm_link.hxx b/private/oleutest/perform/cairole/ui/bm_link.hxx
new file mode 100644
index 000000000..89e63c303
--- /dev/null
+++ b/private/oleutest/perform/cairole/ui/bm_link.hxx
@@ -0,0 +1,90 @@
+//+------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1993.
+//
+// File: bm_link.hxx
+//
+// Contents: test creation apis
+//
+// Classes: CCreateLinkApis
+//
+// Functions:
+//
+// History:
+//
+//--------------------------------------------------------------------------
+
+#ifndef _BM_LINK_HXX_
+#define _BM_LINK_HXX_
+
+#include <bm_base.hxx>
+
+typedef struct _tagLinkTimes {
+ ULONG ulBindToSourceNull;
+ ULONG ulBindToSourceBindCtx;
+ ULONG ulBindIfRunning;
+ ULONG ulBindIfRunning2;
+ ULONG ulUnbindSource;
+ ULONG ulUnbindSource2;
+ ULONG ulUnbindSource3;
+ ULONG ulUpdateNull;
+ ULONG ulUpdateBindCtx;
+ } LinkTimes;
+
+#define INIT_LINKRESULTS(array) {\
+ for (int xx = 0; xx < TEST_MAX_ITERATIONS; xx++)\
+ {\
+ array[xx].ulBindToSourceNull = NOTAVAIL;\
+ array[xx].ulBindToSourceBindCtx = NOTAVAIL;\
+ array[xx].ulBindIfRunning = NOTAVAIL;\
+ array[xx].ulBindIfRunning2 = NOTAVAIL;\
+ array[xx].ulUnbindSource = NOTAVAIL;\
+ array[xx].ulUnbindSource2 = NOTAVAIL;\
+ array[xx].ulUnbindSource3 = NOTAVAIL;\
+ array[xx].ulUpdateNull = NOTAVAIL;\
+ array[xx].ulUpdateBindCtx = NOTAVAIL;\
+ }\
+ }
+
+class CIOLTest : public CTestBase
+{
+public:
+ virtual TCHAR *Name ();
+ virtual SCODE Setup (CTestInput *input);
+ virtual SCODE Run ();
+ virtual SCODE Report (CTestOutput &OutputFile);
+ virtual SCODE Cleanup ();
+
+private:
+ ULONG m_ulIterations;
+
+#ifdef STRESS
+ CSimpleSite* m_pSite[STRESSCOUNT];
+#else
+ CSimpleSite* m_pSite[TEST_MAX_ITERATIONS];
+#endif
+
+ CSimpleDoc* m_lpDoc;
+ CLSID m_clsidSr32;
+ CLSID m_clsidOutl;
+
+ LinkTimes m_ulOleLinkSr32[TEST_MAX_ITERATIONS];
+ LinkTimes m_ulOleLinkOutl[TEST_MAX_ITERATIONS];
+
+
+};
+
+
+
+BOOL CallOleLinkMethods(LPCOLESTR lpFileName, CSimpleSite * pSite[], ULONG ulIterations, LinkTimes IOLTime[],
+ LPCOLESTR lpNm1, LPCOLESTR lpNm2);
+
+BOOL CallOleLinkRunMethods(LinkTimes IOLTime[], LPOLELINK pLink[], ULONG ulIterations);
+BOOL CallOleLinkDisplayName( LinkTimes IOLTime[], LPOLELINK pLink[],
+ LPCOLESTR lpFileName, LPCOLESTR lpNm1,
+ LPCOLESTR lpNm2, ULONG ulIterations);
+HRESULT GetLinkCompositeName(LPOLELINK lpLink, LPCOLESTR lpItem, LPOLESTR FAR* lpComposeName);
+void WriteLinkOutput(CTestOutput &output, LPTSTR lpstr, LinkTimes *lnkTimes, ULONG ulIterations);
+
+#endif //LINK
diff --git a/private/oleutest/perform/cairole/ui/bm_load.cxx b/private/oleutest/perform/cairole/ui/bm_load.cxx
new file mode 100644
index 000000000..3519aafb3
--- /dev/null
+++ b/private/oleutest/perform/cairole/ui/bm_load.cxx
@@ -0,0 +1,557 @@
+//+------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1993.
+//
+// File: bm_Load.cxx
+//
+// Contents: Contains the impl of COleLoadTest which deals with Clipboard related
+// apis.
+//
+// Classes: COleLoadTest
+//
+// Functions:
+//
+// History:
+//
+//--------------------------------------------------------------------------
+
+#include <headers.cxx>
+#pragma hdrstop
+
+#include "hlp_util.hxx"
+#include "hlp_iocs.hxx"
+#include "hlp_ias.hxx"
+#include "hlp_app.hxx"
+#include "hlp_site.hxx"
+#include "hlp_doc.hxx"
+#include "bm_Load.hxx"
+#include <oleauto.h>
+
+
+//**********************************************************************
+//
+// CLoadTest::Name, SetUp, Run, CleanUp
+//
+// Purpose:
+//
+// These routines provide the implementation for the Name, Setup,
+// Run and CleanUp of the class CLoadTest. For details see the doc
+// for driver what are these routines supposed to do.
+//
+// Parameters:
+//
+//
+// Return Value:
+//
+// None
+//
+//
+// Comments:
+// If STRESS is defined don't do anything with timer variable! We are
+// not interested in time values.
+//
+//********************************************************************
+
+
+TCHAR *COleLoadTest::Name ()
+{
+ return TEXT("LoadTest");
+}
+
+
+SCODE COleLoadTest::Setup (CTestInput *pInput)
+{
+ CTestBase::Setup(pInput);
+ HRESULT sc;
+ HRESULT hres;
+
+#ifdef STRESS
+ //If stress condition loop number of time = STRESSCOUNT
+ m_ulIterations = STRESSCOUNT;
+#else
+ // get iteration count
+ m_ulIterations = pInput->GetIterations(Name());
+#endif
+
+ // initialize timing arrays
+#ifndef STRESS
+
+ INIT_RESULTS(m_ulEmbedLoadOutl);
+ INIT_RESULTS(m_ulEmbedSaveOutl);
+
+ INIT_RESULTS(m_ulEmbedLoadRenderDrawOutl);
+ INIT_RESULTS(m_ulEmbedSaveRenderDrawOutl);
+
+ INIT_RESULTS(m_ulEmbedLoadRenderAsisOutl);
+ INIT_RESULTS(m_ulEmbedSaveRenderAsisOutl);
+
+ INIT_RESULTS(m_ulLinkLoadOutl);
+ INIT_RESULTS(m_ulLinkAndSaveOutl);
+
+ INIT_RESULTS(m_ulLinkLoadRenderDrawOutl);
+ INIT_RESULTS(m_ulLinkAndSaveRenderDrawOutl);
+
+ INIT_RESULTS(m_ulStaticAndLoadRenderDrawOutl);
+ INIT_RESULTS(m_ulStaticAndSaveRenderDrawOutl);
+
+ INIT_RESULTS(m_ulStaticAndLoadRenderBMOutl);
+ INIT_RESULTS(m_ulStaticAndSaveRenderBMOutl);
+#endif
+
+
+ sc = OleInitialize(NULL);
+ if (FAILED(sc))
+ {
+ Log (TEXT("Setup - OleInitialize failed."), sc);
+ return sc;
+ }
+
+ hres = CLSIDFromString(OutlineClassName, &m_clsidOutl);
+ Log (TEXT("CLSIDFromString returned ."), hres);
+ if (hres != NOERROR)
+ return E_FAIL;
+
+ //Create root Doc and STorage for Doc
+ m_lpDoc = CSimpleDoc::Create();
+
+ //Create Individual Objects and Init the table
+ for (ULONG iIter=0; iIter<m_ulIterations; iIter++) {
+
+ // CreateLink an instance of Site
+ CSimpleSite *pObj = CSimpleSite::Create(m_lpDoc, iIter);
+ if (pObj)
+ m_pSite[iIter] = pObj;
+ }
+
+ return sc;
+}
+
+
+SCODE COleLoadTest::Cleanup ()
+{
+
+ for (ULONG iIter=0; iIter<m_ulIterations; iIter++)
+ {
+ delete m_pSite[iIter];
+ }
+
+
+ OleUninitialize();
+ return S_OK;
+}
+
+
+SCODE COleLoadTest::Run ()
+{
+ CStopWatch sw;
+ BOOL fRet;
+
+ TCHAR szTemp[MAX_PATH];
+ OLECHAR szOutlFileName[MAX_PATH];
+
+
+ // Get file name of .ini file. if not specified in the command
+ // line, use the default BM.INI in the local directory
+ GetCurrentDirectory (MAX_PATH, szTemp);
+ swprintf(szOutlFileName,
+#ifdef UNICODE
+ L"%s\\foo.oln",
+#else
+ L"%S\\foo.oln",
+#endif
+ szTemp);
+
+ //
+ //Test cases for OleSave and OleLoad on Embedding
+ //
+
+ fRet = CallCreateLoadAndSave(m_clsidOutl, m_pSite, IID_IOleObject, OLERENDER_NONE,
+ NULL, m_ulIterations, m_ulEmbedLoadOutl, m_ulEmbedSaveOutl );
+
+ fRet = CallCreateLoadAndSave(m_clsidOutl, m_pSite, IID_IOleObject, OLERENDER_DRAW,
+ NULL, m_ulIterations, m_ulEmbedLoadRenderDrawOutl, m_ulEmbedSaveRenderDrawOutl);
+
+ fRet = CallCreateLoadAndSave(m_clsidOutl, m_pSite, IID_IOleObject, OLERENDER_ASIS,
+ NULL, m_ulIterations, m_ulEmbedLoadRenderAsisOutl, m_ulEmbedSaveRenderAsisOutl );
+
+ FORMATETC fmte = {CF_BITMAP, NULL, DVASPECT_CONTENT, -1, TYMED_GDI};
+ fRet = CallCreateLoadAndSave(m_clsidOutl, m_pSite, IID_IOleObject, OLERENDER_FORMAT,
+ &fmte, m_ulIterations, m_ulEmbedLoadRenderBMOutl, m_ulEmbedSaveRenderBMOutl );
+ //
+ //Test cases for OleSave and OleLoad on Links
+ //
+ fRet = CallLinkLoadAndSave(szOutlFileName, m_pSite, IID_IOleObject, OLERENDER_NONE,
+ NULL, m_ulIterations, m_ulLinkLoadOutl, m_ulLinkAndSaveOutl);
+ fRet = CallLinkLoadAndSave(szOutlFileName, m_pSite, IID_IOleObject, OLERENDER_DRAW,
+ NULL, m_ulIterations, m_ulLinkLoadRenderDrawOutl, m_ulLinkAndSaveRenderDrawOutl);
+
+ //
+ //Test cases for OleSave and OleLoad on Static objects
+ //
+ fRet = CallStaticLoadAndSave(m_clsidOutl, m_lpDoc, m_pSite, IID_IOleObject, OLERENDER_DRAW,
+ NULL, m_ulIterations, m_ulStaticAndLoadRenderDrawOutl, m_ulLinkAndSaveRenderDrawOutl);
+ //fRet = CallStaticLoadAndSave(m_clsidOutl, m_lpDoc, m_pSite, IID_IOleObject, OLERENDER_FORMAT,
+ // &fmte, m_ulIterations, m_ulStaticAndLoadRenderBMOutl, m_ulStaticAndSaveRenderBMOutl);
+ return S_OK;
+}
+
+
+
+SCODE COleLoadTest::Report (CTestOutput &output)
+{
+//Bail out immediately on STRESS because none of the following variables
+//will have sane value
+#ifdef STRESS
+ return S_OK;
+#endif
+
+ output.WriteString (TEXT("*************************************************\n"));
+ output.WriteSectionHeader (Name(), TEXT("Load Apis"), *m_pInput);
+ output.WriteString (TEXT("*************************************************\n"));
+
+ output.WriteString (TEXT("\n"));
+ output.WriteResults (TEXT("OleLoad Embedding \t\t "), m_ulIterations, m_ulEmbedLoadOutl);
+ output.WriteString (TEXT("\n"));
+
+ output.WriteString (TEXT("\n"));
+ output.WriteResults (TEXT("OleSave Embedding \t\t"), m_ulIterations, m_ulEmbedSaveOutl);
+ output.WriteString (TEXT("\n"));
+
+ output.WriteString (TEXT("\n"));
+ output.WriteResults (TEXT("OleLoad Embedding with RenderDraw \t"), m_ulIterations, m_ulEmbedLoadRenderDrawOutl);
+ output.WriteString (TEXT("\n"));
+
+ output.WriteString (TEXT("\n"));
+ output.WriteResults (TEXT("OleSave Embedding with RenderDraw \t"), m_ulIterations, m_ulEmbedSaveRenderDrawOutl);
+ output.WriteString (TEXT("\n"));
+
+ output.WriteString (TEXT("\n"));
+ output.WriteResults (TEXT("OleLoad Embedding with RenderFormatBM Outline \t"), m_ulIterations, m_ulEmbedLoadRenderBMOutl);
+ output.WriteString (TEXT("\n"));
+
+ output.WriteString (TEXT("\n"));
+ output.WriteResults (TEXT("OleSave with RenderFormatBM \t\t "), m_ulIterations, m_ulEmbedLoadRenderBMOutl);
+ output.WriteString (TEXT("\n"));
+
+
+ output.WriteString (TEXT("\n"));
+ output.WriteResults (TEXT("OleLoad Embedding with RenderAsIs \t "), m_ulIterations, m_ulEmbedLoadRenderAsisOutl);
+ output.WriteString (TEXT("\n"));
+ output.WriteString (TEXT("\n"));
+ output.WriteResults (TEXT("OleSave Embedding with RenderAsIs \t"), m_ulIterations, m_ulEmbedLoadRenderAsisOutl);
+ output.WriteString (TEXT("\n"));
+ output.WriteString (TEXT("\n"));
+ output.WriteString (TEXT("***************************************\n"));
+ output.WriteResults (TEXT("OleLoad Link Outline \t\t "), m_ulIterations, m_ulLinkLoadOutl);
+ output.WriteString (TEXT("\n"));
+ output.WriteString (TEXT("\n"));
+ output.WriteResults (TEXT("OleSave Link Outline \t\t "), m_ulIterations, m_ulLinkAndSaveOutl);
+ output.WriteString (TEXT("\n"));
+
+ output.WriteString (TEXT("\n"));
+ output.WriteResults (TEXT("OleLoad Link with RenderDraw \t\t"), m_ulIterations, m_ulLinkLoadRenderDrawOutl);
+ output.WriteString (TEXT("\n"));
+ output.WriteString (TEXT("\n"));
+ output.WriteResults (TEXT("OleSave Link with RenderDraw Outline \t"), m_ulIterations, m_ulLinkAndSaveRenderDrawOutl);
+ output.WriteString (TEXT("\n"));
+ output.WriteString (TEXT("***************************************\n"));
+ output.WriteResults (TEXT("OleCreateStaticAndLoad Outline \t "), m_ulIterations, m_ulStaticAndLoadRenderDrawOutl);
+ output.WriteString (TEXT("\n"));
+
+ output.WriteString (TEXT("\n"));
+ output.WriteResults (TEXT("OleCreateStaticAndLoad with RenderDraw Outline \t"), m_ulIterations, m_ulStaticAndLoadRenderBMOutl);
+ output.WriteString (TEXT("\n"));
+
+
+ return S_OK;
+}
+
+//**********************************************************************
+//
+// CallCreateLoadAndSave
+//
+// Purpose:
+// Calls OleCreate to create the object and then
+// call OleLoad and OleSave to get the performance results on them.
+//
+//
+// Parameters:
+//
+//
+// Return Value:
+//
+// None
+//
+// Functions called:
+// OleCreate OLE2 api
+// LoadAndSave routine defined in this file
+//
+//
+// Comments:
+//
+//
+//********************************************************************
+
+
+BOOL CallCreateLoadAndSave(REFCLSID rclsid, CSimpleSite * pSite[], REFIID riid, DWORD renderopt,
+ LPFORMATETC pFormatEtc, ULONG ulIterations,
+ ULONG uOleLoadtime[], ULONG uOleSavetime[])
+{
+ HRESULT hres;
+ ULONG iIter;
+ BOOL retVal = FALSE;
+
+ //Create the objects
+ for ( iIter=0; iIter<ulIterations; iIter++) {
+
+ //If we have not had any problem then
+ HEAPVALIDATE() ;
+ hres = OleCreate(rclsid, riid, renderopt, pFormatEtc,
+ &pSite[iIter]->m_OleClientSite,
+ pSite[iIter]->m_lpObjStorage, (VOID FAR* FAR*)&pSite[iIter]->m_lpOleObject);
+
+ if (hres != NOERROR)
+ goto error;
+
+ }
+
+ //Now call Appropriate routines to Save and Load the objects
+ LoadAndSave( pSite, ulIterations, uOleLoadtime, uOleSavetime);
+
+ retVal = TRUE;
+
+error:
+
+ if (hres != NOERROR)
+ Log (TEXT("Routine CallCreateLoadAndSave failed with hres = "), hres);
+
+ for (iIter=0; iIter<ulIterations; iIter++)
+ {
+ // Unload the object and release the Ole Object
+ pSite[iIter]->UnloadOleObject();
+ }
+
+return retVal;
+}
+
+BOOL CallLinkLoadAndSave(LPCOLESTR lpFileName, CSimpleSite * pSite[], REFIID riid, DWORD renderopt,
+ LPFORMATETC pFormatEtc, ULONG ulIterations,
+ ULONG uOleLoadtime[], ULONG uOleSavetime[])
+{
+ HRESULT hres;
+ ULONG iIter;
+ BOOL retVal = FALSE;
+
+ //Create the objects
+ for ( iIter=0; iIter<ulIterations; iIter++) {
+
+ //If we have not had any problem then
+ HEAPVALIDATE() ;
+ hres = OleCreateLinkToFile(lpFileName, riid, renderopt, pFormatEtc,
+ &pSite[iIter]->m_OleClientSite,
+ pSite[iIter]->m_lpObjStorage, (VOID FAR* FAR*)&pSite[iIter]->m_lpOleObject);
+
+ if (hres != NOERROR)
+ goto error;
+
+ }
+
+ //Now call Appropriate routines to Save and Load the objects
+ LoadAndSave( pSite, ulIterations, uOleLoadtime, uOleSavetime);
+
+ retVal = TRUE;
+
+error:
+
+ if (hres != NOERROR)
+ Log (TEXT("Routine CallCreateLoadAndSave failed with hres = "), hres);
+
+ for (iIter=0; iIter<ulIterations; iIter++)
+ {
+ // Unload the object and release the Ole Object
+ pSite[iIter]->UnloadOleObject();
+ }
+
+return retVal;
+}
+
+//**********************************************************************
+//
+// LoadAndSave
+//
+// Purpose:
+// Calls OleLoad and OleSave on the object and timing results.
+//
+//
+// Parameters:
+//
+//
+// Return Value:
+//
+// None
+//
+// Functions called:
+// OleLoad OLE2 api
+// OleSave OLE2 api
+//
+//
+// Comments:
+//
+//
+//********************************************************************
+
+BOOL LoadAndSave(CSimpleSite * pSite[], ULONG ulIterations,
+ ULONG uOleLoadtime[], ULONG uOleSavetime[])
+{
+ LPPERSISTSTORAGE pStg = NULL;
+ CStopWatch sw;
+ HRESULT hres;
+ ULONG iIter;
+ BOOL retVal = FALSE;
+
+ //Save the objects
+ for (iIter=0; iIter<ulIterations; iIter++)
+ {
+ hres = pSite[iIter]->m_lpOleObject->QueryInterface(IID_IPersistStorage,
+ (LPVOID FAR*)&pStg);
+ if (hres != NOERROR)
+ goto error;
+
+ sw.Reset();
+ hres = OleSave(pStg, pSite[iIter]->m_lpObjStorage, TRUE);
+ GetTimerVal(uOleSavetime[iIter]);
+
+ LOGRESULTS (TEXT("OleSave "), hres);
+ if (hres != NOERROR)
+ {
+ goto error;
+ }
+ pStg->Release();
+ pStg = NULL;
+
+ }
+
+
+ for (iIter=0; iIter<ulIterations; iIter++)
+ {
+ // Unload the object and release the Ole Object
+ pSite[iIter]->UnloadOleObject();
+ }
+
+ //Load the objects
+ for (iIter=0; iIter<ulIterations; iIter++)
+ {
+ sw.Reset();
+ hres = OleLoad( pSite[iIter]->m_lpObjStorage, IID_IOleObject,
+ &pSite[iIter]->m_OleClientSite, (VOID FAR* FAR*)&pSite[iIter]->m_lpOleObject);
+
+ GetTimerVal(uOleLoadtime[iIter]);
+ LOGRESULTS (TEXT("OleLoad "), hres);
+ }
+
+
+ retVal = TRUE;
+
+error:
+ if (hres != NOERROR)
+ Log (TEXT("Routine LoadAndSave failed with hres = "), hres);
+ if (pStg)
+ pStg->Release();
+
+return retVal;
+}
+
+
+//**********************************************************************
+//
+// CallStaticLoadAndSave
+//
+// Purpose:
+// Calls OleCreateStaticFromDara to create the object and then
+// call OleLoad and OleSave to get the performance results on them.
+//
+//
+// Parameters:
+//
+//
+// Return Value:
+//
+// None
+//
+// Functions called:
+// OleCreate OLE2 api
+// OleCreateStaticFromData OLE2 api
+// LoadAndSave routine defined in this file
+//
+//
+// Comments:
+// In this case we call OleCreateStaticFromData from data object
+// given by application.
+//
+//********************************************************************
+
+
+
+BOOL CallStaticLoadAndSave(REFCLSID rclsid, CSimpleDoc FAR * m_lpDoc, CSimpleSite * pSite[],
+ REFIID riid, DWORD renderopt, LPFORMATETC pFormatEtc, ULONG ulIterations,
+ ULONG uOleLoadtime[], ULONG uOleSavetime[])
+{
+ HRESULT hres;
+ ULONG iIter;
+ BOOL retVal = FALSE;
+ LPDATAOBJECT pDO = NULL;
+ CSimpleSite* pTempSite = CSimpleSite::Create(m_lpDoc, -1); //-1 is unique in this case
+
+ //Create the ole object and ask for IID_IDataObject interface
+ hres = OleCreate(rclsid, IID_IOleObject, renderopt, pFormatEtc,
+ &pTempSite->m_OleClientSite,
+ pTempSite->m_lpObjStorage, (VOID FAR* FAR*)&pTempSite->m_lpOleObject);
+
+ if (hres != NOERROR)
+ goto error;
+ hres = pTempSite->m_lpOleObject->QueryInterface(IID_IDataObject, (LPVOID FAR*)&pDO);
+ if (hres != NOERROR)
+ goto error;
+
+ //Create the static objects from pDO
+ for ( iIter=0; iIter<ulIterations; iIter++) {
+ hres = OleCreateStaticFromData(pDO, riid, renderopt, pFormatEtc,
+ &pSite[iIter]->m_OleClientSite, pSite[iIter]->m_lpObjStorage,
+ (VOID FAR* FAR*)&pSite[iIter]->m_lpOleObject);
+
+ if (hres != NOERROR)
+ goto error;
+
+ HEAPVALIDATE() ;
+ }
+
+ //Now call Appropriate routines to Save and Load the objects
+ LoadAndSave( pSite, ulIterations, uOleLoadtime, uOleSavetime);
+
+ retVal = TRUE;
+
+error:
+
+ if (hres != NOERROR)
+ Log (TEXT("Routine CallCreateLoadAndSave failed with hres = "), hres);
+
+ if (pDO)
+ pDO->Release();
+
+ for (iIter=0; iIter<ulIterations; iIter++)
+ {
+ // Unload the object and release the Ole Object
+ pSite[iIter]->UnloadOleObject();
+ }
+
+ if (pTempSite) //this should also release the object
+ {
+ pTempSite->UnloadOleObject();
+ //delete pTempSite;
+ }
+
+return retVal;
+}
+
+
diff --git a/private/oleutest/perform/cairole/ui/bm_load.hxx b/private/oleutest/perform/cairole/ui/bm_load.hxx
new file mode 100644
index 000000000..d5199a5db
--- /dev/null
+++ b/private/oleutest/perform/cairole/ui/bm_load.hxx
@@ -0,0 +1,95 @@
+//+------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1993.
+//
+// File: bm_load.hxx
+// It contains the definition for COleLoadTest class.
+//
+//
+// History: SanjayK Created
+//
+//--------------------------------------------------------------------------
+
+#ifndef _BM_LOAD_HXX_
+#define _BM_LOAD_HXX_
+
+#include <bm_base.hxx>
+
+class COleLoadTest : public CTestBase
+{
+public:
+ virtual TCHAR *Name ();
+ virtual SCODE Setup (CTestInput *input);
+ virtual SCODE Run ();
+ virtual SCODE Report (CTestOutput &OutputFile);
+ virtual SCODE Cleanup ();
+
+private:
+ ULONG m_ulIterations;
+
+#ifdef STRESS
+ CSimpleSite* m_pSite[STRESSCOUNT];
+#else
+ CSimpleSite* m_pSite[TEST_MAX_ITERATIONS];
+#endif
+
+ CSimpleDoc* m_lpDoc;
+ CLSID m_clsidOutl;
+
+
+ ULONG m_ulEmbedLoadOutl[TEST_MAX_ITERATIONS];
+ ULONG m_ulEmbedSaveOutl[TEST_MAX_ITERATIONS];
+
+ ULONG m_ulEmbedLoadRenderDrawOutl[TEST_MAX_ITERATIONS];
+ ULONG m_ulEmbedSaveRenderDrawOutl[TEST_MAX_ITERATIONS];
+
+ ULONG m_ulEmbedLoadRenderAsisOutl[TEST_MAX_ITERATIONS];
+ ULONG m_ulEmbedSaveRenderAsisOutl[TEST_MAX_ITERATIONS];
+
+ ULONG m_ulEmbedLoadRenderBMOutl[TEST_MAX_ITERATIONS];
+ ULONG m_ulEmbedSaveRenderBMOutl[TEST_MAX_ITERATIONS];
+
+ ULONG m_ulLinkLoadOutl[TEST_MAX_ITERATIONS];
+ ULONG m_ulLinkAndSaveOutl[TEST_MAX_ITERATIONS];
+
+ ULONG m_ulLinkLoadRenderDrawOutl[TEST_MAX_ITERATIONS];
+ ULONG m_ulLinkAndSaveRenderDrawOutl[TEST_MAX_ITERATIONS];
+
+ ULONG m_ulStaticAndLoadRenderDrawOutl[TEST_MAX_ITERATIONS];
+ ULONG m_ulStaticAndSaveRenderDrawOutl[TEST_MAX_ITERATIONS];
+
+ ULONG m_ulStaticAndLoadRenderBMOutl[TEST_MAX_ITERATIONS];
+ ULONG m_ulStaticAndSaveRenderBMOutl[TEST_MAX_ITERATIONS];
+
+
+};
+
+BOOL CallCreateLoadAndSave(REFCLSID rclsid, CSimpleSite * pSite[], REFIID riid, DWORD renderopt,
+ LPFORMATETC pFormatEtc, ULONG ulIterations,
+ ULONG uOleLoadtime[], ULONG uOleSavetime[]);
+BOOL CallLinkLoadAndSave(LPCOLESTR lpFileName, CSimpleSite * pSite[], REFIID riid, DWORD renderopt,
+ LPFORMATETC pFormatEtc, ULONG ulIterations,
+ ULONG uOleLoadtime[], ULONG uOleSavetime[]);
+BOOL LoadAndSave(CSimpleSite * pSite[], ULONG ulIterations,
+ ULONG uOleLoadtime[], ULONG uOleSavetime[]);
+
+BOOL CallStaticLoadAndSave(REFCLSID rclsid, CSimpleDoc FAR * m_lpDoc, CSimpleSite * pSite[], REFIID riid, DWORD renderopt,
+ LPFORMATETC pFormatEtc, ULONG ulIterations,
+ ULONG uOleLoadtime[], ULONG uOleSavetime[]);
+
+#endif
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/private/oleutest/perform/cairole/ui/daytona/makefile b/private/oleutest/perform/cairole/ui/daytona/makefile
new file mode 100644
index 000000000..1d3728d41
--- /dev/null
+++ b/private/oleutest/perform/cairole/ui/daytona/makefile
@@ -0,0 +1,10 @@
+############################################################################
+#
+# Copyright (C) 1992, Microsoft Corporation.
+#
+# All rights reserved.
+#
+############################################################################
+
+!include $(NTMAKEENV)\makefile.def
+
diff --git a/private/oleutest/perform/cairole/ui/daytona/sources b/private/oleutest/perform/cairole/ui/daytona/sources
new file mode 100644
index 000000000..ac35fc06e
--- /dev/null
+++ b/private/oleutest/perform/cairole/ui/daytona/sources
@@ -0,0 +1,64 @@
+!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.
+
+!ENDIF
+
+!include ..\..\..\daytona.inc
+
+#
+# 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= apitests
+
+#
+# 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= LIBRARY
+
+INCLUDES= $(INCLUDES);$(OLEUTESTDIR)\balls\common;$(BASEDIR)\private\cinc;
+C_DEFINES= $(C_DEFINES)
+
+SOURCES= \
+ ..\bm_crt.cxx \
+ ..\bm_crtl.cxx \
+ ..\bm_load.cxx \
+ ..\bm_link.cxx \
+ ..\bm_cache.cxx \
+ ..\hlp_site.cxx \
+ ..\hlp_doc.cxx \
+ ..\hlp_iocs.cxx \
+ ..\hlp_ias.cxx
+
+# ..\bm_clip.cxx \
+
+
+UMTYPE= console
+UMAPPL=
+UMTEST=
+UMLIBS=
+
+PRECOMPILED_INCLUDE = ..\headers.cxx
diff --git a/private/oleutest/perform/cairole/ui/dirs b/private/oleutest/perform/cairole/ui/dirs
new file mode 100644
index 000000000..2084bae88
--- /dev/null
+++ b/private/oleutest/perform/cairole/ui/dirs
@@ -0,0 +1,38 @@
+!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/perform/cairole/ui/headers.cxx b/private/oleutest/perform/cairole/ui/headers.cxx
new file mode 100644
index 000000000..53d9fc546
--- /dev/null
+++ b/private/oleutest/perform/cairole/ui/headers.cxx
@@ -0,0 +1,18 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1992.
+//
+// File: headers.cxx
+//
+// Contents: remote2/new precompiled headers
+//
+// Classes:
+//
+// Functions:
+//
+// History: 24-Aug-93 PhilipLa Created
+//
+//----------------------------------------------------------------------------
+
+#include <benchmrk.hxx>
diff --git a/private/oleutest/perform/cairole/ui/hlp_app.cxx b/private/oleutest/perform/cairole/ui/hlp_app.cxx
new file mode 100644
index 000000000..3d53a5288
--- /dev/null
+++ b/private/oleutest/perform/cairole/ui/hlp_app.cxx
@@ -0,0 +1,963 @@
+//**********************************************************************
+// File name: hlp_app.cxx
+//
+// Implementation file for the CSimpleApp Class
+//
+// Functions:
+//
+// See app.hxx for a list of member functions.
+//
+// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+
+#include "hlp_pre.hxx"
+#include "hlp_iocs.hxx"
+#include "hlp_ias.hxx"
+#include "hlp_app.hxx"
+#include "hlp_site.hxx"
+#include "hlp_doc.hxx"
+
+HWND m_hAppWnd; // main window handle
+HINSTANCE m_hInst; // application instance
+CMDIWnd* v_pMDIWnd;
+//**********************************************************************
+//
+// CSimpleApp::CSimpleApp()
+//
+// Purpose:
+//
+// Constructor for CSimpleApp
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// OutputDebugString Windows API
+// SetRectEmpty Windows API
+//
+// Comments:
+//
+// CSimpleApp has a contained COleInPlaceFrame. On construction
+// of CSimpleApp, we explicitly call the constructor of this
+// contained class and pass a copy of the this pointer, so that
+// COleInPlaceFrame can refer back to this class
+//
+//********************************************************************
+#pragma warning(disable : 4355) // turn off this warning. This warning
+ // tells us that we are passing this in
+ // an initializer, before "this" is through
+ // initializing. This is ok, because
+ // we just store the ptr in the other
+ // constructor
+
+CSimpleApp::CSimpleApp() : m_OleInPlaceFrame(this)
+#pragma warning (default : 4355) // Turn the warning back on
+{
+ DEBUGOUT("In CSimpleApp's Constructor \r\n");
+
+ // Set Ref Count
+ m_nCount = 0;
+
+ // clear members
+ m_hAppWnd = NULL;
+ m_hInst = NULL;
+ m_lpDoc = NULL;
+ m_hwndUIActiveObj = NULL;
+
+ // clear flags
+ m_fInitialized = FALSE;
+ m_fCSHMode = FALSE;
+ m_fMenuMode = FALSE;
+
+ // used for inplace
+ SetRectEmpty(&nullRect);
+}
+
+//**********************************************************************
+//
+// CSimpleApp::~CSimpleApp()
+//
+// Purpose:
+//
+// Destructor for CSimpleApp Class.
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// OutputDebugString Windows API
+// OleUninitialize OLE API
+//
+// Comments:
+//
+//********************************************************************
+
+CSimpleApp::~CSimpleApp()
+{
+ DEBUGOUT("In CSimpleApp's Destructor\r\n");
+
+ if (m_hStdPal)
+ DeleteObject(m_hStdPal);
+
+ // need to uninit the library...
+ if (m_fInitialized)
+ OleUninitialize();
+}
+
+//**********************************************************************
+//
+// CSimpleApp::DestroyDocs()
+//
+// Purpose:
+//
+// Destroys all of the open documents in the application (Only one
+// since this is an SDI app, but could easily be modified to
+// support MDI).
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// Comments:
+//
+//********************************************************************
+
+void CSimpleApp::DestroyDocs()
+{
+ m_lpDoc->Close(); // we have only 1 document
+}
+
+//**********************************************************************
+//
+// CSimpleApp::QueryInterface
+//
+// Purpose:
+//
+// Used for interface negotiation at the Frame level.
+//
+// Parameters:
+//
+// REFIID riid - A reference to the interface that is
+// being queried.
+//
+// LPVOID FAR* ppvObj - An out parameter to return a pointer to
+// the interface.
+//
+// Return Value:
+//
+// S_OK - The interface is supported.
+// S_FALSE - The interface is not supported
+//
+// Function Calls:
+// Function Location
+//
+// OutputDebugString Windows API
+// IsEqualIID OLE API
+// ResultFromScode OLE API
+// COleInPlaceFrame::AddRef IOIPF.cxx
+//
+// Comments:
+//
+// Note that this QueryInterface is associated with the frame.
+// Since the application could potentially have multiple documents
+// and multiple objects, a lot of the interfaces are ambiguous.
+// (ie. which IOleObject is returned?). For this reason, only
+// pointers to interfaces associated with the frame are returned.
+// In this implementation, Only IOleInPlaceFrame (or one of the
+// interfaces it is derived from) can be returned.
+//
+//********************************************************************
+
+STDMETHODIMP CSimpleApp::QueryInterface(REFIID riid, LPVOID FAR* ppvObj)
+{
+ DEBUGOUT("In CSimpleApp::QueryInterface\r\n");
+
+ *ppvObj = NULL; // must set out pointer parameters to NULL
+
+ // looking for IUnknown
+ if ( riid == IID_IUnknown)
+ {
+ AddRef();
+ *ppvObj = this;
+ return ResultFromScode(S_OK);
+ }
+
+ // looking for IOleWindow
+ if ( riid == IID_IOleWindow)
+ {
+ m_OleInPlaceFrame.AddRef();
+ *ppvObj=&m_OleInPlaceFrame;
+ return ResultFromScode(S_OK);
+ }
+
+ // looking for IOleInPlaceUIWindow
+ if ( riid == IID_IOleInPlaceUIWindow)
+ {
+ m_OleInPlaceFrame.AddRef();
+ *ppvObj=&m_OleInPlaceFrame;
+ return ResultFromScode(S_OK);
+ }
+
+ // looking for IOleInPlaceFrame
+ if ( riid == IID_IOleInPlaceFrame)
+ {
+ m_OleInPlaceFrame.AddRef();
+ *ppvObj=&m_OleInPlaceFrame;
+ return ResultFromScode(S_OK);
+ }
+
+ // Not a supported interface
+ return ResultFromScode(E_NOINTERFACE);
+}
+
+//**********************************************************************
+//
+// CSimpleApp::AddRef
+//
+// Purpose:
+//
+// Adds to the reference count at the Application level.
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// ULONG - The new reference count of the application.
+//
+// Function Calls:
+// Function Location
+//
+// OutputDebugString Windows API
+//
+// Comments:
+//
+// Due to the reference counting model that is used in this
+// implementation, this reference count is the sum of the
+// reference counts on all interfaces of all objects open
+// in the application.
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) CSimpleApp::AddRef()
+{
+ DEBUGOUT("In CSimpleApp::AddRef\r\n");
+ return ++m_nCount;
+}
+
+//**********************************************************************
+//
+// CSimpleApp::Release
+//
+// Purpose:
+//
+// Decrements the reference count at this level
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// ULONG - The new reference count of the application.
+//
+// Function Calls:
+// Function Location
+//
+// OutputDebugString Windows API
+//
+// Comments:
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) CSimpleApp::Release()
+{
+ DEBUGOUT("In CSimpleApp::Release\r\n");
+
+ if (--m_nCount == 0) {
+ delete this;
+ return 0;
+ }
+ return m_nCount;
+}
+
+//**********************************************************************
+//
+// CSimpleApp::fInitApplication
+//
+// Purpose:
+//
+// Initializes the application
+//
+// Parameters:
+//
+// HANDLE hInstance - Instance handle of the application.
+//
+// Return Value:
+//
+// TRUE - Application was successfully initialized.
+// FALSE - Application could not be initialized
+//
+// Function Calls:
+// Function Location
+//
+// LoadIcon Windows API
+// LoadCursor Windows API
+// GetStockObject Windows API
+// RegisterClass Windows API
+//
+// Comments:
+//
+//********************************************************************
+
+BOOL CSimpleApp::fInitApplication(HANDLE hInstance)
+{
+ WNDCLASS wc;
+
+ // Fill in window class structure with parameters that describe the
+ // main window.
+
+ wc.style = NULL; // Class style(s).
+ wc.lpfnWndProc = MainWndProc; // Function to retrieve messages for
+ // windows of this class.
+ wc.cbClsExtra = 0; // No per-class extra data.
+ wc.cbWndExtra = 0; // No per-window extra data.
+ wc.hInstance = hInstance; // Application that owns the class.
+ wc.hIcon = LoadIcon(hInstance, "SimpCntr");
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wc.hbrBackground = GetStockObject(WHITE_BRUSH);
+ wc.lpszMenuName = "SIMPLEMENU"; // Name of menu resource in .RC file.
+ wc.lpszClassName = "SimpCntrAppWClass"; // Name used in CreateWindow call
+
+ if (!RegisterClass(&wc))
+ return FALSE;
+
+ wc.style = CS_DBLCLKS; // Class style(s). allow DBLCLK's
+ wc.lpfnWndProc = DocWndProc; // Function to retrieve messages for
+ // windows of this class.
+ wc.cbClsExtra = 0; // No per-class extra data.
+ wc.cbWndExtra = 0; // No per-window extra data.
+ wc.hInstance = hInstance; // Application that owns the class.
+ wc.hIcon = NULL;
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wc.hbrBackground = GetStockObject(WHITE_BRUSH);
+ wc.lpszMenuName = NULL;
+ wc.lpszClassName = "SimpCntrDocWClass"; // Name used in CreateWindow call.
+
+ // Register the window class and return success/failure code.
+
+ return (RegisterClass(&wc));
+}
+
+//**********************************************************************
+//
+// CSimpleApp::fInitInstance
+//
+// Purpose:
+//
+// Instance initialization.
+//
+// Parameters:
+//
+// HANDLE hInstance - App. Instance Handle.
+//
+// int nCmdShow - Show parameter from WinMain
+//
+// Return Value:
+//
+// TRUE - Initialization Successful
+// FALSE - Initialization Failed.
+//
+//
+// Function Calls:
+// Function Location
+//
+// CreateWindow Windows API
+// ShowWindow Windows API
+// UpdateWindow Windows API
+// OleBuildVersion OLE API
+// OleInitialize OLE API
+//
+// Comments:
+//
+// Note that successful Initalization of the OLE libraries
+// is remembered so the UnInit is only called if needed.
+//
+//********************************************************************
+
+BOOL CSimpleApp::fInitInstance (HANDLE hInstance, int nCmdShow)
+{
+ DWORD dwVer = OleBuildVersion();
+ LPMALLOC lpMalloc = NULL;
+
+ // check to see if we are compatible with this version of the libraries
+ if (HIWORD(dwVer) != rmm || LOWORD(dwVer) < rup) {
+#ifdef _DEBUG
+ OutputDebugString("WARNING: Incompatible OLE library version\r\n");
+#else
+ return FALSE;
+#endif
+ }
+
+#if defined( _DEBUG )
+ /* OLE2NOTE: Use a special debug allocator to help track down
+ ** memory leaks.
+ */
+ OleStdCreateDbAlloc(0, &lpMalloc);
+#endif
+
+ if (OleInitialize(lpMalloc) == NOERROR)
+ m_fInitialized = TRUE;
+
+#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->Release();
+#endif
+
+ m_hInst = hInstance;
+
+ // Create the "application" windows
+ m_hAppWnd = CreateWindow ("SimpCntrAppWClass",
+ "Simple OLE 2.0 In-Place Container",
+ WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ NULL,
+ NULL,
+ hInstance,
+ NULL);
+
+ if (!m_hAppWnd)
+ return FALSE;
+
+ m_pMDIWnd = new (CMDIWnd);
+ v_pMDIWnd.Create();
+
+ m_hStdPal = OleStdCreateStandardPalette();
+
+ ShowWindow (m_hAppWnd, nCmdShow);
+ UpdateWindow (m_hAppWnd);
+
+ return m_fInitialized;
+}
+
+//**********************************************************************
+//
+// CSimpleApp::lCommandHandler
+//
+// Purpose:
+//
+// Handles the processing of WM_COMMAND.
+//
+// Parameters:
+//
+// HWND hWnd - Handle to the application Window
+//
+// UINT message - message (always WM_COMMAND)
+//
+// WPARAM wParam - Same as passed to the WndProc
+//
+// LPARAM lParam - Same as passed to the WndProc
+//
+// Return Value:
+//
+// NULL
+//
+// Function Calls:
+// Function Location
+//
+// IOleInPlaceActiveObject::QueryInterface Object
+// IOleInPlaceObject::ContextSensitiveHelp Object
+// IOleInPlaceObject::Release Object
+// IOleObject::DoVerb Object
+// GetClientRect Windows API
+// MessageBox Windows API
+// DialogBox Windows API
+// MakeProcInstance Windows API
+// FreeProcInstance Windows API
+// SendMessage Windows API
+// DefWindowProc Windows API
+// CSimpleDoc::InsertObject DOC.cxx
+//
+// Comments:
+//
+//********************************************************************
+
+long CSimpleApp::lCommandHandler (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ RECT rect;
+
+ // context sensitive help...
+ if (m_fMenuMode || m_fCSHMode)
+ {
+ if (m_fCSHMode)
+ {
+ // clear context sensitive help flag
+ m_fCSHMode = FALSE;
+
+ // if there is an InPlace active object, call its context sensitive help
+ // method with the FALSE parameter to bring the object out of the
+ // csh state. See the technotes for details.
+ if (m_lpDoc->m_lpActiveObject)
+ {
+ LPOLEINPLACEOBJECT lpInPlaceObject;
+ m_lpDoc->m_lpActiveObject->QueryInterface(IID_IOleInPlaceObject, (LPVOID FAR *)&lpInPlaceObject);
+ lpInPlaceObject->ContextSensitiveHelp(FALSE);
+ lpInPlaceObject->Release();
+ }
+ }
+
+ // see the technotes for details on implementing context sensitive
+ // help
+ if (m_fMenuMode)
+ {
+ m_fMenuMode = FALSE;
+
+ if (m_lpDoc->m_lpActiveObject)
+ m_lpDoc->m_lpActiveObject->ContextSensitiveHelp(FALSE);
+ }
+ // if we provided help, we would do it here...
+ MessageBox (hWnd, "Help", "Help", MB_OK);
+
+ return NULL;
+ }
+
+ // see if the command is a verb selections
+ if (wParam >= IDM_VERB0)
+ {
+ // get the rectangle of the object
+ m_lpDoc->m_lpSite->GetObjRect(&rect);
+
+ m_lpDoc->m_lpSite->m_lpOleObject->DoVerb(wParam - IDM_VERB0, NULL, &m_lpDoc->m_lpSite->m_OleClientSite, -1, m_lpDoc->m_hDocWnd, &rect);
+ }
+ else
+ {
+ switch (wParam) {
+ // bring up the About box
+ case IDM_ABOUT:
+ {
+ FARPROC lpProcAbout = MakeProcInstance((FARPROC)About, m_hInst);
+
+ DialogBox(m_hInst, // current instance
+ "AboutBox", // resource to use
+ m_hAppWnd, // parent handle
+ lpProcAbout); // About() instance address
+
+ FreeProcInstance(lpProcAbout);
+ break;
+ }
+
+ // bring up the InsertObject Dialog
+ case IDM_INSERTOBJECT:
+ m_lpDoc->InsertObject();
+ break;
+
+ // exit the application
+ case IDM_EXIT:
+ SendMessage(hWnd, WM_SYSCOMMAND, SC_CLOSE, 0L);
+ break;
+
+ case IDM_NEW:
+ m_lpDoc->Close();
+ m_lpDoc = NULL;
+ lCreateDoc(hWnd, 0, 0, 0);
+ break;
+
+ case IDM_COPYLINE:
+ case IDM_ADDLINE:
+ case IDM_UNINDENTLINE:
+ m_lpDoc->HandleDispatch(wParam);
+ break;
+
+
+ default:
+ //return (DefWindowProc(hWnd, message, wParam, lParam));
+ return (DefFrameProc(hWnd, v_pMDIWnd->hwndMDIClient, message, wParam, lParam));
+ } // end of switch
+ } // end of else
+ return NULL;
+}
+
+//**********************************************************************
+//
+// CSimpleApp::lSizeHandler
+//
+// Purpose:
+//
+// Handles the WM_SIZE message
+//
+// Parameters:
+//
+// HWND hWnd - Handle to the application Window
+//
+// UINT message - message (always WM_SIZE)
+//
+// WPARAM wParam - Same as passed to the WndProc
+//
+// LPARAM lParam - Same as passed to the WndProc
+//
+// Return Value:
+//
+// LONG - returned from the "document" resizing
+//
+// Function Calls:
+// Function Location
+//
+// GetClientRect Windows API
+// CSimpleDoc::lResizeDoc DOC.cxx
+//
+// Comments:
+//
+//********************************************************************
+
+long CSimpleApp::lSizeHandler (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ RECT rect;
+
+ GetClientRect(m_hAppWnd, &rect);
+ return m_lpDoc->lResizeDoc(&rect);
+}
+
+//**********************************************************************
+//
+// CSimpleApp::lCreateDoc
+//
+// Purpose:
+//
+// Handles the creation of a document.
+//
+// Parameters:
+//
+// HWND hWnd - Handle to the application Window
+//
+// UINT message - message (always WM_CREATE)
+//
+// WPARAM wParam - Same as passed to the WndProc
+//
+// LPARAM lParam - Same as passed to the WndProc
+//
+// Return Value:
+//
+// NULL
+//
+// Function Calls:
+// Function Location
+//
+// GetClientRect Windows API
+// CSimpleDoc::CSimpleDoc DOC.cxx
+//
+// Comments:
+//
+//********************************************************************
+
+long CSimpleApp::lCreateDoc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ RECT rect;
+
+ GetClientRect(hWnd, &rect);
+
+ m_lpDoc = CSimpleDoc::Create(this, &rect, hWnd);
+
+ return NULL;
+}
+
+//**********************************************************************
+//
+// CSimpleApp::AddFrameLevelUI
+//
+// Purpose:
+//
+// Used during InPlace negotiation.
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// COleInPlaceFrame::SetMenu IOIPF.cxx
+// CSimpleApp::AddFrameLevelTools APP.cxx
+//
+// Comments:
+//
+// Be sure to read the Technotes included in the OLE 2.0 toolkit
+//
+//********************************************************************
+
+void CSimpleApp::AddFrameLevelUI()
+{
+ m_OleInPlaceFrame.SetMenu(NULL, NULL, NULL);
+ AddFrameLevelTools();
+}
+
+//**********************************************************************
+//
+// CSimpleApp::AddFrameLevelTools
+//
+// Purpose:
+//
+// Used during InPlace negotiation.
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// COleInPlaceFrame::SetBorderSpace IOIPF.cxx
+// InvalidateRect Windows API
+//
+// Comments:
+//
+// Be sure to read the Technotes included in the OLE 2.0 toolkit
+//
+//********************************************************************
+
+void CSimpleApp::AddFrameLevelTools()
+{
+ m_OleInPlaceFrame.SetBorderSpace(&nullRect);
+ InvalidateRect(m_hAppWnd, NULL, TRUE);
+}
+
+//**********************************************************************
+//
+// CSimpleApp::HandleAccelerators
+//
+// Purpose:
+//
+// To properly handle accelerators in the Message Loop
+//
+// Parameters:
+//
+// LPMSG lpMsg - A pointer to the message structure.
+//
+// Return Value:
+//
+// TRUE - The accelerator was handled
+// FALSE - The accelerator was not handled
+//
+// Function Calls:
+// Function Location
+//
+// IOleInPlaceActiveObject::TranslateAccelerator Object
+//
+// Comments:
+//
+// If an object is InPlace active, it gets the first shot at
+// handling the accelerators.
+//
+//********************************************************************
+
+BOOL CSimpleApp::HandleAccelerators(LPMSG lpMsg)
+{
+ HRESULT hResult;
+ BOOL retval = FALSE;
+
+ // if we have an InPlace Active Object
+ if (m_lpDoc->m_lpActiveObject)
+ {
+ // Pass the accelerator on...
+ hResult = m_lpDoc->m_lpActiveObject->TranslateAccelerator(lpMsg);
+ if (hResult == NOERROR)
+ retval = TRUE;
+ }
+
+ return retval;
+}
+
+//**********************************************************************
+//
+// CSimpleApp::PaintApp
+//
+// Purpose:
+//
+// Handles the painting of the doc window.
+//
+//
+// Parameters:
+//
+// HDC hDC - hDC to the Doc Window.
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// CSimpleDoc::PaintDoc DOC.cxx
+//
+// Comments:
+//
+// This is an app level function in case we want to do palette
+// management.
+//
+//********************************************************************
+
+void CSimpleApp::PaintApp (HDC hDC)
+{
+ // at this level, we could enumerate through all of the
+ // visible objects in the application, so that a palette
+ // that best fits all of the objects can be built.
+
+ // This app is designed to take on the same palette
+ // functionality that was provided in OLE 1.0, the palette
+ // of the last object drawn is realized. Since we only
+ // support one object at a time, it shouldn't be a big
+ // deal.
+
+ // if we supported multiple documents, we would enumerate
+ // through each of the open documents and call paint.
+
+ if (m_lpDoc)
+ m_lpDoc->PaintDoc(hDC);
+
+}
+
+//**********************************************************************
+//
+// CSimpleApp::ContextSensitiveHelp
+//
+// Purpose:
+// Used in supporting context sensitive haelp at the app level.
+//
+//
+// Parameters:
+//
+// BOOL fEnterMode - Entering/Exiting Context Sensitive
+// help mode.
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// IOleInPlaceActiveObject::QueryInterface Object
+// IOleInPlaceObject::ContextSensitiveHelp Object
+// IOleInPlaceObject::Release Object
+//
+// Comments:
+//
+// This function isn't used because we don't support Shift+F1
+// context sensitive help. Be sure to look at the technotes
+// in the OLE 2.0 toolkit.
+//
+//********************************************************************
+
+void CSimpleApp::ContextSensitiveHelp (BOOL fEnterMode)
+{
+ if (m_fCSHMode != fEnterMode)
+ {
+ m_fCSHMode = fEnterMode;
+
+ // this code "trickles" the context sensitive help via shift+f1
+ // to the inplace active object. See the technotes for implementation
+ // details.
+ if (m_lpDoc->m_lpActiveObject)
+ {
+ LPOLEINPLACEOBJECT lpInPlaceObject;
+ m_lpDoc->m_lpActiveObject->QueryInterface(IID_IOleInPlaceObject, (LPVOID FAR *)&lpInPlaceObject);
+ lpInPlaceObject->ContextSensitiveHelp(fEnterMode);
+ lpInPlaceObject->Release();
+ }
+ }
+}
+
+
+/* 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 CSimpleApp::QueryNewPalette(void)
+{
+ if (m_hwndUIActiveObj) {
+ if (SendMessage(m_hwndUIActiveObj, WM_QUERYNEWPALETTE,
+ (WPARAM)0, (LPARAM)0)) {
+ /* Object selected its palette as foreground palette */
+ return (LRESULT)1;
+ }
+ }
+
+ return wSelectPalette(m_hAppWnd, m_hStdPal, FALSE/*fBackground*/);
+}
+
+
+/* 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;
+}
diff --git a/private/oleutest/perform/cairole/ui/hlp_app.hxx b/private/oleutest/perform/cairole/ui/hlp_app.hxx
new file mode 100644
index 000000000..8af3c4e48
--- /dev/null
+++ b/private/oleutest/perform/cairole/ui/hlp_app.hxx
@@ -0,0 +1,75 @@
+//**********************************************************************
+// File name: hlp_app.hxx
+//
+// Definition of CSimpleApp
+//
+// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+
+#if !defined( _HLP_APP_HXX_)
+#define _HLP_APP_HXX_
+
+#include <ole2.h>
+
+class CSimpleDoc;
+
+//These two should be global vars
+extern HWND m_hAppWnd; // main window handle
+extern HINSTANCE m_hInst; // application instance
+
+class CSimpleApp : public IUnknown
+{
+public:
+
+ int m_nCount; // reference count
+ HMENU m_hMainMenu;
+ HMENU m_hFileMenu;
+ HMENU m_hEditMenu;
+ HMENU m_hHelpMenu;
+ HMENU m_hCascadeMenu;
+
+
+// COleInPlaceFrame m_OleInPlaceFrame; // IOleInPlaceFrame Implementation
+
+ CSimpleDoc FAR * m_lpDoc; // pointer to document object
+ BOOL m_fInitialized; // OLE initialization flag
+ BOOL m_fCSHMode;
+ BOOL m_fMenuMode;
+ HWND m_hwndUIActiveObj; // HWND of UIActive Object
+ HPALETTE m_hStdPal; // Color palette used by container
+ BOOL m_fAppActive; // TRUE if app is active
+
+ CSimpleApp(); // Constructor
+ ~CSimpleApp(); // Destructor
+ RECT nullRect;
+
+
+ // IUnknown Interfaces
+ STDMETHODIMP QueryInterface(REFIID riid, LPVOID FAR* ppvObj);
+ STDMETHODIMP_(ULONG) AddRef();
+ STDMETHODIMP_(ULONG) Release();
+
+ // Initialization methods
+
+ BOOL fInitApplication (HANDLE hInstance);
+ BOOL fInitInstance (HANDLE hInstance, int nCmdShow);
+
+ // Message handling methods
+
+ long lCommandHandler (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
+ long lSizeHandler (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
+ long lCreateDoc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
+ BOOL HandleAccelerators (LPMSG lpMsg);
+ void PaintApp(HDC hDC);
+ void DestroyDocs();
+
+ // In-Place support functions
+ void AddFrameLevelUI();
+ void AddFrameLevelTools();
+ void ContextSensitiveHelp (BOOL fEnterMode);
+ LRESULT QueryNewPalette(void);
+};
+
+LRESULT wSelectPalette(HWND hWnd, HPALETTE hPal, BOOL fBackground);
+
+#endif
diff --git a/private/oleutest/perform/cairole/ui/hlp_doc.cxx b/private/oleutest/perform/cairole/ui/hlp_doc.cxx
new file mode 100644
index 000000000..e64b8cb5d
--- /dev/null
+++ b/private/oleutest/perform/cairole/ui/hlp_doc.cxx
@@ -0,0 +1,508 @@
+//**********************************************************************
+// File name: HLP_DOC.CXX
+//
+// Implementation file for CSimpleDoc.
+//
+// Functions:
+//
+// See DOC.H for Class Definition
+//
+// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+
+#include <headers.cxx>
+#pragma hdrstop
+
+#include "hlp_iocs.hxx"
+#include "hlp_ias.hxx"
+#include "hlp_app.hxx"
+#include "hlp_site.hxx"
+#include "hlp_doc.hxx"
+
+//**********************************************************************
+//
+// CSimpleDoc::Create
+//
+// Purpose:
+//
+// Creation for the CSimpleDoc Class
+//
+// Parameters:
+//
+// CSimpleApp FAR * lpApp - Pointer to the CSimpleApp Class
+//
+// LPRECT lpRect - Client area rect of "frame" window
+//
+// HWND hWnd - Window Handle of "frame" window
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// StgCreateDocfile OLE API
+// CreateWindow Windows API
+// ShowWindow Windows API
+// UpdateWindow Windows API
+//
+// Comments:
+//
+// This routine was added so that failure could be returned
+// from object creation.
+//
+//********************************************************************
+
+CSimpleDoc FAR * CSimpleDoc::Create()
+{
+ CSimpleDoc FAR * lpTemp = new CSimpleDoc();
+
+ if (!lpTemp)
+ return NULL;
+
+ // create storage for the doc.
+ HRESULT hErr = StgCreateDocfile (NULL, STGM_READWRITE | STGM_TRANSACTED | STGM_SHARE_EXCLUSIVE,
+ 0, &lpTemp->m_lpStorage);
+
+ if (hErr != NOERROR)
+ goto error;
+
+ // we will add one ref count on our document. later in CSimpleDoc::Close
+ // we will release this ref count. when the document's ref count goes
+ // to 0, the document will be deleted.
+ lpTemp->AddRef();
+
+ return (lpTemp);
+
+error:
+ delete (lpTemp);
+ return NULL;
+
+}
+
+//**********************************************************************
+//
+// CSimpleDoc::Close
+//
+// Purpose:
+//
+// Close CSimpleDoc object.
+// when the document's reference count goes to 0, the document
+// will be destroyed.
+//
+// Parameters:
+//
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// RevokeDragDrop OLE API
+// CoLockObjectExternal OLE API
+// OleFlushClipboard OLE API
+// ShowWindow Windows API
+//
+// Comments:
+//
+//********************************************************************
+
+void CSimpleDoc::Close(void)
+{
+ DEBUGOUT(L"In CSimpleDoc::Close\r\n");
+
+ ShowWindow(m_hDocWnd, SW_HIDE); // Hide the window
+
+ // Close the OLE object in our document
+ if (m_lpSite)
+ m_lpSite->CloseOleObject();
+
+ // Release the ref count added in CSimpleDoc::Create. this will make
+ // the document's ref count go to 0, and the document will be deleted.
+ Release();
+}
+
+//**********************************************************************
+//
+// CSimpleDoc::CSimpleDoc
+//
+// Purpose:
+//
+// Constructor for the CSimpleDoc Class
+//
+// Parameters:
+//
+// CSimpleApp FAR * lpApp - Pointer to the CSimpleApp Class
+//
+// HWND hWnd - Window Handle of "frame" window
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// GetMenu Windows API
+// GetSubMenu Windows API
+//
+// Comments:
+//
+//********************************************************************
+
+CSimpleDoc::CSimpleDoc()
+{
+}
+
+//**********************************************************************
+//
+// CSimpleDoc::~CSimpleDoc
+//
+// Purpose:
+//
+// Destructor for CSimpleDoc
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// CSimpleSite::Release SITE.CPP
+// IStorage::Release OLE API
+//
+// Comments:
+//
+//********************************************************************
+
+CSimpleDoc::~CSimpleDoc()
+{
+ DEBUGOUT(L"In CSimpleDoc's Destructor\r\n");
+
+ // Release all pointers we hold to the OLE object. also release
+ // the ref count added in CSimpleSite::Create. this will make
+ // the Site's ref count go to 0, and the Site will be deleted.
+ if (m_lpSite) {
+ m_lpSite->UnloadOleObject();
+ m_lpSite->Release();
+ m_lpSite = NULL;
+ }
+
+ // Release the Storage
+ if (m_lpStorage) {
+ m_lpStorage->Release();
+ m_lpStorage = NULL;
+ }
+
+ // if the edit menu was modified, remove the menu item and
+ // destroy the popup if it exists
+ if (m_fModifiedMenu)
+ {
+ int nCount = GetMenuItemCount(m_lpApp->m_hEditMenu);
+ RemoveMenu(m_lpApp->m_hEditMenu, nCount-1, MF_BYPOSITION);
+ if (m_lpApp->m_hCascadeMenu)
+ DestroyMenu(m_lpApp->m_hCascadeMenu);
+ }
+
+ DestroyWindow(m_hDocWnd);
+}
+
+
+//**********************************************************************
+//
+// CSimpleDoc::QueryInterface
+//
+// Purpose:
+//
+// Return a pointer to a requested interface
+//
+// Parameters:
+//
+// REFIID riid - ID of interface to be returned
+// LPVOID FAR* ppvObj - Location to return the interface
+//
+// Return Value:
+//
+// S_FALSE - Always
+//
+// Function Calls:
+// Function Location
+//
+// ResultFromScode OLE API
+//
+// Comments:
+//
+// In this implementation, there are no doc level interfaces.
+// In an MDI application, there would be an IOleInPlaceUIWindow
+// associated with the document to provide document level tool
+ // space negotiation.
+//
+//********************************************************************
+
+STDMETHODIMP CSimpleDoc::QueryInterface(REFIID riid, LPVOID FAR* ppvObj)
+{
+ DEBUGOUT(L"In CSimpleDoc::QueryInterface\r\n");
+
+ *ppvObj = NULL; // must set out pointer parameters to NULL
+
+ // Not a supported interface
+ return ResultFromScode(E_NOINTERFACE);
+}
+
+//**********************************************************************
+//
+// CSimpleDoc::AddRef
+//
+// Purpose:
+//
+// Increments the document reference count
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// UINT - The current reference count on the document
+//
+// Function Calls:
+// Function Location
+//
+// CSimpleApp::AddRef APP.CPP
+//
+// Comments:
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) CSimpleDoc::AddRef()
+{
+ DEBUGOUT(L"In CSimpleDoc::AddRef\r\n");
+ return ++m_nCount;
+}
+
+//**********************************************************************
+//
+// CSimpleDoc::Release
+//
+// Purpose:
+//
+// Decrements the document reference count
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// UINT - The current reference count on the document
+//
+// Function Calls:
+// Function Location
+//
+//
+// Comments:
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) CSimpleDoc::Release()
+{
+ DEBUGOUT(L"In CSimpleDoc::Release\r\n");
+
+ if (--m_nCount == 0) {
+ delete this;
+ return 0;
+ }
+ return m_nCount;
+}
+
+//**********************************************************************
+//
+// CSimpleDoc::InsertObject
+//
+// Purpose:
+//
+// Inserts a new object to this document
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// CSimpleSite::CSimpleSite SITE.CPP
+// CSimpleSite::InitObject SITE.CPP
+// memset C Runtime
+// OleUIInsertObject OUTLUI function
+// CSimpleDoc::DisableInsertObject DOC.CPP
+//
+// Comments:
+//
+// This implementation only allows one object to be inserted
+// into a document. Once the object has been inserted, then
+// the Insert Object menu choice is greyed out, to prevent
+// the user from inserting another.
+//
+//********************************************************************
+
+void CSimpleDoc::InsertObject()
+{
+#if 0
+ m_lpSite = CSimpleSite::Create(this);
+ iret = OleUIInsertObject(&io);
+
+ if (iret == OLEUI_OK)
+ {
+ m_lpSite->InitObject((BOOL)(io.dwFlags & IOF_SELECTCREATENEW));
+ // disable Insert Object menu item
+ DisableInsertObject();
+ }
+ else
+ {
+ m_lpSite->Release();
+ m_lpSite = NULL;
+ m_lpStorage->Revert();
+ }
+#endif
+
+}
+
+//**********************************************************************
+//
+// CSimpleDoc::lResizeDoc
+//
+// Purpose:
+//
+// Resizes the document
+//
+// Parameters:
+//
+// LPRECT lpRect - The size of the client are of the "frame"
+// Window.
+//
+// Return Value:
+//
+// NULL
+//
+// Function Calls:
+// Function Location
+//
+// IOleInPlaceActiveObject::ResizeBorder Object
+// MoveWindow Windows API
+//
+// Comments:
+//
+//********************************************************************
+
+long CSimpleDoc::lResizeDoc(LPRECT lpRect)
+{
+ // if we are InPlace, then call ResizeBorder on the object, otherwise
+ // just move the document window.
+ //if (m_fInPlaceActive)
+ //m_lpActiveObject->ResizeBorder(lpRect, &m_lpApp->m_OleInPlaceFrame, TRUE);
+ //else
+ MoveWindow(m_hDocWnd, lpRect->left, lpRect->top, lpRect->right, lpRect->bottom, TRUE);
+
+ return NULL;
+}
+
+//**********************************************************************
+//
+// CSimpleDoc::lAddVerbs
+//
+// Purpose:
+//
+// Adds the objects verbs to the edit menu.
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// NULL
+//
+// Function Calls:
+// Function Location
+//
+// GetMenuItemCount Windows API
+// OleUIAddVerbMenu OUTLUI function
+//
+// Comments:
+//
+//********************************************************************
+
+long CSimpleDoc::lAddVerbs(void)
+{
+#if 0
+ // m_fModifiedMenu is TRUE if the menu has already been modified
+ // once. Since we only support one obect every time the application
+ // is run, then once the menu is modified, it doesn't have
+ // to be done again.
+ if (m_lpSite && !m_fInPlaceActive && !m_fModifiedMenu)
+ {
+ int nCount = GetMenuItemCount(m_lpApp->m_hEditMenu);
+
+ OleUIAddVerbMenu ( m_lpSite->m_lpOleObject,
+ NULL,
+ m_lpApp->m_hEditMenu,
+ nCount + 1,
+ IDM_VERB0,
+ 0, // no maximum verb IDM enforced
+ FALSE,
+ 0,
+ &m_lpApp->m_hCascadeMenu);
+
+ m_fModifiedMenu = TRUE;
+ }
+#endif
+ return (NULL);
+}
+
+//**********************************************************************
+//
+// CSimpleDoc::PaintDoc
+//
+// Purpose:
+//
+// Paints the Document
+//
+// Parameters:
+//
+// HDC hDC - hDC of the document Window
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// CSimpleSite::PaintObj SITE.CPP
+//
+// Comments:
+//
+//********************************************************************
+
+void CSimpleDoc::PaintDoc (HDC hDC)
+{
+ // if we supported multiple objects, then we would enumerate
+ // the objects and call paint on each of them from here.
+
+ if (m_lpSite)
+ m_lpSite->PaintObj(hDC);
+
+}
+
diff --git a/private/oleutest/perform/cairole/ui/hlp_doc.hxx b/private/oleutest/perform/cairole/ui/hlp_doc.hxx
new file mode 100644
index 000000000..f052f5ff3
--- /dev/null
+++ b/private/oleutest/perform/cairole/ui/hlp_doc.hxx
@@ -0,0 +1,52 @@
+//**********************************************************************
+// File name: hlp_doc.hxx
+//
+// Definition of CSimpleDoc
+//
+// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+
+#if !defined( _HLP_DOC_HXX_ )
+#define _HLP_DOC_HXX_
+
+class CSimpleSite;
+class CAutomateSite;
+class CSimpleApp;
+
+class CSimpleDoc : public IUnknown
+{
+public:
+ int m_nCount;
+ LPSTORAGE m_lpStorage;
+ LPOLEINPLACEACTIVEOBJECT m_lpActiveObject;
+ BOOL m_fInPlaceActive;
+ BOOL m_fAddMyUI;
+ BOOL m_fModifiedMenu;
+
+ CSimpleSite FAR * m_lpSite;
+ CSimpleApp FAR * m_lpApp;
+
+ HWND m_hDocWnd;
+
+ static CSimpleDoc FAR * Create();
+
+ void Close(void);
+
+ CSimpleDoc();
+ CSimpleDoc(CSimpleApp FAR *lpApp, HWND hWnd);
+ ~CSimpleDoc();
+
+ // IUnknown Interface
+ STDMETHODIMP QueryInterface(REFIID riid, LPVOID FAR* ppvObj);
+ STDMETHODIMP_(ULONG) AddRef();
+ STDMETHODIMP_(ULONG) Release();
+
+ void InsertObject(void);
+ void DisableInsertObject(void);
+ long lResizeDoc(LPRECT lpRect);
+ long lAddVerbs(void);
+ void PaintDoc(HDC hDC);
+ void HandleDispatch(WPARAM);
+};
+
+#endif
diff --git a/private/oleutest/perform/cairole/ui/hlp_ias.cxx b/private/oleutest/perform/cairole/ui/hlp_ias.cxx
new file mode 100644
index 000000000..5e55d33b0
--- /dev/null
+++ b/private/oleutest/perform/cairole/ui/hlp_ias.cxx
@@ -0,0 +1,318 @@
+//**********************************************************************
+// File name: HLP_IAS.cxx
+//
+// Implementation file of CAdviseSink
+//
+//
+// Functions:
+//
+// See IAS.H for Class Definition
+//
+// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+#include <headers.cxx>
+#pragma hdrstop
+
+
+#include "hlp_iocs.hxx"
+#include "hlp_ias.hxx"
+#include "hlp_app.hxx"
+#include "hlp_site.hxx"
+#include "hlp_doc.hxx"
+
+//**********************************************************************
+//
+// CAdviseSink::QueryInterface
+//
+// Purpose:
+//
+// Returns a pointer to a requested interface.
+//
+// Parameters:
+//
+// REFIID riid - The requested interface
+//
+// LPVOID FAR* ppvObj - Place to return the interface
+//
+// Return Value:
+//
+// HRESULT from CSimpleSite::QueryInterface
+//
+// Function Calls:
+// Function Location
+//
+// CSimpleSite::QueryInterface SITE.cxx
+// OutputDebugString Windows API
+//
+// Comments:
+//
+// This function simply delegates to the Object class, which is
+// aware of the supported interfaces.
+//
+//********************************************************************
+
+STDMETHODIMP CAdviseSink::QueryInterface(REFIID riid, LPVOID FAR* ppvObj)
+{
+ DEBUGOUT(L"In IAS::QueryInterface\r\n");
+
+ // delegate to the document Object
+ return m_pSite->QueryInterface(riid, ppvObj);
+}
+
+//**********************************************************************
+//
+// CAdviseSink::AddRef
+//
+// Purpose:
+//
+// Increments the reference count on this interface
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// The current reference count on this interface.
+//
+// Function Calls:
+// Function Location
+//
+// CSimpleSite::AddReff SITE.cxx
+// OutputDebugString Windows API
+//
+// Comments:
+//
+// This function adds one to the ref count of the interface,
+// and calls then calls CSimpleSite to increment its ref.
+// count.
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) CAdviseSink::AddRef()
+{
+ DEBUGOUT(L"In IAS::AddRef\r\n");
+
+ // increment the interface reference count (for debugging only)
+ ++m_nCount;
+
+ // delegate to the container Site
+ return m_pSite->AddRef();
+}
+
+//**********************************************************************
+//
+// CAdviseSink::Release
+//
+// Purpose:
+//
+// Decrements the reference count on this interface
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// The current reference count on this interface.
+//
+// Function Calls:
+// Function Location
+//
+// CSimpleSite::Release SITE.cxx
+// OutputDebugString Windows API
+//
+// Comments:
+//
+// This function subtracts one from the ref count of the interface,
+// and calls then calls CSimpleSite to decrement its ref.
+// count.
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) CAdviseSink::Release()
+{
+ DEBUGOUT(L"In IAS::Release\r\n");
+
+ // decrement the interface reference count (for debugging only)
+ m_nCount--;
+
+ // delegate to the container Site
+ return m_pSite->Release();
+}
+
+//**********************************************************************
+//
+// CAdviseSink::OnDataChange
+//
+// Purpose:
+//
+// Not Implemented (needs to be stubbed out)
+//
+// Parameters:
+//
+// Not Implemented (needs to be stubbed out)
+//
+// Return Value:
+//
+// Not Implemented (needs to be stubbed out)
+//
+// Function Calls:
+// Function Location
+//
+// OutputDebugString Windows API
+//
+// Comments:
+//
+// Not Implemented (needs to be stubbed out)
+//
+//********************************************************************
+
+STDMETHODIMP_(void) CAdviseSink::OnDataChange (FORMATETC FAR* pFormatetc, STGMEDIUM FAR* pStgmed)
+{
+ DEBUGOUT(L"In IAS::OnDataChange\r\n");
+}
+
+//**********************************************************************
+//
+// CAdviseSink::OnViewChange
+//
+// Purpose:
+//
+// Notifies us that the view has changed and needs to be updated.
+//
+// Parameters:
+//
+// DWORD dwAspect - Aspect that has changed
+//
+// LONG lindex - Index that has changed
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// OutputDebugString Windows API
+// InvalidateRect Windows API
+// IViewObject2::GetExtent Object
+//
+// Comments:
+//
+//********************************************************************
+
+STDMETHODIMP_(void) CAdviseSink::OnViewChange (DWORD dwAspect, LONG lindex)
+{
+ LPVIEWOBJECT2 lpViewObject2;
+ DEBUGOUT(L"In IAS::OnViewChange\r\n");
+
+ // get a pointer to IViewObject2
+ HRESULT hErr = m_pSite->m_lpOleObject->QueryInterface(
+ IID_IViewObject2,(LPVOID FAR *)&lpViewObject2);
+
+ if (hErr == NOERROR) {
+ // get extent of the object
+ // NOTE: this method will never be remoted; it can be called w/i this async method
+ lpViewObject2->GetExtent(DVASPECT_CONTENT, -1 , NULL, &m_pSite->m_sizel);
+ lpViewObject2->Release();
+ }
+
+ InvalidateRect(m_pSite->m_lpDoc->m_hDocWnd, NULL, TRUE);
+}
+
+//**********************************************************************
+//
+// CAdviseSink::OnRename
+//
+// Purpose:
+//
+// Not Implemented (needs to be stubbed out)
+//
+// Parameters:
+//
+// Not Implemented (needs to be stubbed out)
+//
+// Return Value:
+//
+// Not Implemented (needs to be stubbed out)
+//
+// Function Calls:
+// Function Location
+//
+// OutputDebugString Windows API
+//
+// Comments:
+//
+// Not Implemented (needs to be stubbed out)
+//
+//********************************************************************
+
+STDMETHODIMP_(void) CAdviseSink::OnRename (LPMONIKER pmk)
+{
+ DEBUGOUT(L"In IAS::OnRename\r\n");
+}
+
+//**********************************************************************
+//
+// CAdviseSink::OnSave
+//
+// Purpose:
+//
+// Not Implemented (needs to be stubbed out)
+//
+// Parameters:
+//
+// Not Implemented (needs to be stubbed out)
+//
+// Return Value:
+//
+// Not Implemented (needs to be stubbed out)
+//
+// Function Calls:
+// Function Location
+//
+// OutputDebugString Windows API
+//
+// Comments:
+//
+// Not Implemented (needs to be stubbed out)
+//
+//********************************************************************
+
+STDMETHODIMP_(void) CAdviseSink::OnSave ()
+{
+ DEBUGOUT(L"In IAS::OnSave\r\n");
+}
+
+//**********************************************************************
+//
+// CAdviseSink::OnClose
+//
+// Purpose:
+//
+// Not Implemented (needs to be stubbed out)
+//
+// Parameters:
+//
+// Not Implemented (needs to be stubbed out)
+//
+// Return Value:
+//
+// Not Implemented (needs to be stubbed out)
+//
+// Function Calls:
+// Function Location
+//
+// OutputDebugString Windows API
+//
+// Comments:
+//
+// Not Implemented (needs to be stubbed out)
+//
+//********************************************************************
+
+STDMETHODIMP_(void) CAdviseSink::OnClose()
+{
+ DEBUGOUT(L"In IAS::OnClose\r\n");
+}
diff --git a/private/oleutest/perform/cairole/ui/hlp_ias.hxx b/private/oleutest/perform/cairole/ui/hlp_ias.hxx
new file mode 100644
index 000000000..e2135d7e5
--- /dev/null
+++ b/private/oleutest/perform/cairole/ui/hlp_ias.hxx
@@ -0,0 +1,44 @@
+//**********************************************************************
+// File name: HLP_IAS.HXX
+//
+// Definition of CAdviseSink
+//
+// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+#if !defined( _HLP_IAS_HXX_ )
+#define _HLP_IAS_HXX_
+
+#include <assert.h>
+
+class CSimpleSite;
+
+interface CAdviseSink : public IAdviseSink
+{
+ int m_nCount;
+ CSimpleSite FAR * m_pSite;
+
+ CAdviseSink(CSimpleSite FAR * pSite) {
+ OutputDebugString(TEXT("In IAS's constructor\r\n"));
+ m_pSite = pSite;
+ m_nCount = 0;
+ };
+
+ ~CAdviseSink() {
+ OutputDebugString(TEXT("In IAS's destructor\r\n"));
+ assert(m_nCount == 0);
+ } ;
+
+ STDMETHODIMP QueryInterface (REFIID riid, LPVOID FAR* ppv);
+ STDMETHODIMP_(ULONG) AddRef ();
+ STDMETHODIMP_(ULONG) Release ();
+
+ // *** IAdviseSink methods ***
+ STDMETHODIMP_(void) OnDataChange (FORMATETC FAR* pFormatetc, STGMEDIUM FAR* pStgmed);
+ STDMETHODIMP_(void) OnViewChange (DWORD dwAspect, LONG lindex);
+ STDMETHODIMP_(void) OnRename (LPMONIKER pmk);
+ STDMETHODIMP_(void) OnSave ();
+ STDMETHODIMP_(void) OnClose ();
+};
+
+
+#endif
diff --git a/private/oleutest/perform/cairole/ui/hlp_iocs.cxx b/private/oleutest/perform/cairole/ui/hlp_iocs.cxx
new file mode 100644
index 000000000..2588118da
--- /dev/null
+++ b/private/oleutest/perform/cairole/ui/hlp_iocs.cxx
@@ -0,0 +1,373 @@
+//**********************************************************************
+// File name: HLP_IOCS.cxx
+//
+// Implementation file for COleClientSite
+//
+// Functions:
+//
+// See IOCS.H for class definition
+//
+// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+
+#include <headers.cxx>
+#pragma hdrstop
+
+#include "hlp_iocs.hxx"
+#include "hlp_ias.hxx"
+#include "hlp_app.hxx"
+#include "hlp_site.hxx"
+#include "hlp_doc.hxx"
+
+
+//**********************************************************************
+//
+// COleClientSite::QueryInterface
+//
+// Purpose:
+//
+// Used for interface negotiation at this interface
+//
+// Parameters:
+//
+// REFIID riid - A reference to the interface that is
+// being queried.
+//
+// LPVOID FAR* ppvObj - An out parameter to return a pointer to
+// the interface.
+//
+// Return Value:
+//
+// S_OK - The interface is supported.
+// E_NOINTERFACE - The interface is not supported
+//
+// Function Calls:
+// Function Location
+//
+// OutputDebugString Windows API
+// CSimpleSite::QueryInterface SITE.cxx
+//
+// Comments:
+//
+//********************************************************************
+
+STDMETHODIMP COleClientSite::QueryInterface(REFIID riid, LPVOID FAR* ppvObj)
+{
+ DEBUGOUT(L"In IOCS::QueryInterface\r\n");
+
+ HEAPVALIDATE();
+
+ // delegate to the container Site
+ return m_pSite->QueryInterface(riid, ppvObj);
+}
+
+//**********************************************************************
+//
+// CSimpleApp::AddRef
+//
+// Purpose:
+//
+// Adds to the reference count at the interface level.
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// ULONG - The new reference count of the interface
+//
+// Function Calls:
+// Function Location
+//
+// OutputDebugString Windows API
+//
+// Comments:
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) COleClientSite::AddRef()
+{
+ DEBUGOUT(L"In IOCS::AddRef\r\n");
+
+ // increment the interface reference count (for debugging only)
+ ++m_nCount;
+
+ // delegate to the container Site
+ return m_pSite->AddRef();
+}
+
+
+//**********************************************************************
+//
+// CSimpleApp::Release
+//
+// Purpose:
+//
+// Decrements the reference count at this level
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// ULONG - The new reference count of the interface.
+//
+// Function Calls:
+// Function Location
+//
+// OutputDebugString Windows API
+//
+// Comments:
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) COleClientSite::Release()
+{
+ DEBUGOUT(L"In IOCS::Release\r\n");
+
+ // decrement the interface reference count (for debugging only)
+ --m_nCount;
+
+ // delegate to the container Site
+ return m_pSite->Release();
+}
+
+//**********************************************************************
+//
+// COleClientSite::SaveObject
+//
+// Purpose:
+//
+// Called by the object when it wants to be saved to persistant
+// storage
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// OutputDebugString Windows API
+// IOleObject::QueryInterface Object
+// IPersistStorage::SaveCompleted Object
+// IPersistStorage::Release Object
+// OleSave OLE API
+// ResultFromScode OLE API
+//
+// Comments:
+//
+//********************************************************************
+
+STDMETHODIMP COleClientSite::SaveObject()
+{
+ LPPERSISTSTORAGE lpPS;
+ SCODE sc = E_FAIL;
+
+ HEAPVALIDATE();
+ DEBUGOUT(L"In IOCS::SaveObject\r\n");
+
+ // get a pointer to IPersistStorage
+ HRESULT hErr = m_pSite->m_lpOleObject->QueryInterface(IID_IPersistStorage, (LPVOID FAR *)&lpPS);
+
+ // save the object
+ if (hErr == NOERROR)
+ {
+ sc = GetScode( OleSave(lpPS, m_pSite->m_lpObjStorage, TRUE) );
+ lpPS->SaveCompleted(NULL);
+ lpPS->Release();
+ }
+
+ HEAPVALIDATE();
+ return ResultFromScode(sc);
+}
+
+//**********************************************************************
+//
+// COleClientSite::GetMoniker
+//
+// Purpose:
+//
+// Not Implemented
+//
+// Parameters:
+//
+// Not Implemented
+//
+// Return Value:
+//
+// Function Calls:
+// Function Location
+//
+// OutputDebugString Windows API
+//
+// Comments:
+//
+// This function is not implemented because we don't support
+// linking.
+//
+//********************************************************************
+
+STDMETHODIMP COleClientSite::GetMoniker(DWORD dwAssign, DWORD dwWhichMoniker, LPMONIKER FAR* ppmk)
+{
+ DEBUGOUT(L"In IOCS::GetMoniker\r\n");
+
+ // need to null the out pointer
+ *ppmk = NULL;
+
+ HEAPVALIDATE();
+ return ResultFromScode(E_NOTIMPL);
+}
+
+//**********************************************************************
+//
+// COleClientSite::GetContainer
+//
+// Purpose:
+//
+// Not Implemented
+//
+// Parameters:
+//
+// Not Implemented
+//
+// Return Value:
+//
+// Not Implemented
+//
+// Function Calls:
+// Function Location
+//
+// OutputDebugString Windows API
+//
+// Comments:
+//
+// Not Implemented
+//
+//********************************************************************
+
+STDMETHODIMP COleClientSite::GetContainer(LPOLECONTAINER FAR* ppContainer)
+{
+ DEBUGOUT(L"In IOCS::GetContainer\r\n");
+
+ // NULL the out pointer
+ *ppContainer = NULL;
+
+ return ResultFromScode(E_NOTIMPL);
+}
+
+//**********************************************************************
+//
+// COleClientSite::ShowObject
+//
+// Purpose:
+//
+// Not Implemented
+//
+// Parameters:
+//
+// Not Implemented
+//
+// Return Value:
+//
+// Not Implemented
+//
+// Function Calls:
+// Function Location
+//
+// OutputDebugString Windows API
+//
+// Comments:
+//
+// This function is not implemented because we don't support
+// linking.
+//
+//********************************************************************
+
+STDMETHODIMP COleClientSite::ShowObject()
+{
+ DEBUGOUT(L"In IOCS::ShowObject\r\n");
+ HEAPVALIDATE();
+ return NOERROR;
+}
+
+//**********************************************************************
+//
+// COleClientSite::OnShowWindow
+//
+// Purpose:
+//
+// Object calls this method when it is opening/closing non-InPlace
+// Window
+//
+// Parameters:
+//
+// BOOL fShow - TRUE if Window is opening, FALSE if closing
+//
+// Return Value:
+//
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// OutputDebugString Windows API
+// InvalidateRect Windows API
+// ResultFromScode OLE API
+//
+// Comments:
+//
+//********************************************************************
+
+STDMETHODIMP COleClientSite::OnShowWindow(BOOL fShow)
+{
+ DEBUGOUT(L"In IOCS::OnShowWindow\r\n");
+ m_pSite->m_fObjectOpen = fShow;
+ InvalidateRect(m_pSite->m_lpDoc->m_hDocWnd, NULL, TRUE);
+
+ // if object window is closing, then bring container window to top
+ if (! fShow) {
+ BringWindowToTop(m_pSite->m_lpDoc->m_hDocWnd);
+ SetFocus(m_pSite->m_lpDoc->m_hDocWnd);
+ }
+ return ResultFromScode(S_OK);
+}
+
+//**********************************************************************
+//
+// COleClientSite::RequestNewObjectLayout
+//
+// Purpose:
+//
+// Not Implemented
+//
+// Parameters:
+//
+// Not Implemented
+//
+// Return Value:
+//
+// Not Implemented
+//
+// Function Calls:
+// Function Location
+//
+// OutputDebugString Windows API
+//
+// Comments:
+//
+// Not Implemented
+//
+//********************************************************************
+
+STDMETHODIMP COleClientSite::RequestNewObjectLayout()
+{
+ DEBUGOUT(L"In IOCS::RequestNewObjectLayout\r\n");
+ return ResultFromScode(E_NOTIMPL);
+}
diff --git a/private/oleutest/perform/cairole/ui/hlp_iocs.hxx b/private/oleutest/perform/cairole/ui/hlp_iocs.hxx
new file mode 100644
index 000000000..18dac700b
--- /dev/null
+++ b/private/oleutest/perform/cairole/ui/hlp_iocs.hxx
@@ -0,0 +1,44 @@
+//**********************************************************************
+// File name: HLP_IOCS.HXX
+//
+// Definition of COleClientSite
+//
+// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+#if !defined( _HLP_IOCS_HXX_ )
+#define _HLP_IOCS_HXX_
+
+#include <assert.h>
+
+class CSimpleSite;
+
+interface COleClientSite : public IOleClientSite
+{
+ int m_nCount;
+ CSimpleSite FAR * m_pSite;
+
+ COleClientSite(CSimpleSite FAR * pSite) {
+ OutputDebugString(TEXT("In IOCS's constructor\r\n"));
+ m_pSite = pSite;
+ m_nCount = 0;
+ }
+
+ ~COleClientSite() {
+ OutputDebugString(TEXT("In IOCS's destructor\r\n"));
+ assert(m_nCount == 0);
+ }
+
+ STDMETHODIMP QueryInterface(REFIID riid, LPVOID FAR* ppvObj);
+ STDMETHODIMP_(ULONG) AddRef();
+ STDMETHODIMP_(ULONG) Release();
+
+ // *** IOleClientSite methods ***
+ STDMETHODIMP SaveObject();
+ STDMETHODIMP GetMoniker(DWORD dwAssign, DWORD dwWhichMoniker, LPMONIKER FAR* ppmk);
+ STDMETHODIMP GetContainer(LPOLECONTAINER FAR* ppContainer);
+ STDMETHODIMP ShowObject();
+ STDMETHODIMP OnShowWindow(BOOL fShow);
+ STDMETHODIMP RequestNewObjectLayout();
+};
+
+#endif
diff --git a/private/oleutest/perform/cairole/ui/hlp_iopf.cxx b/private/oleutest/perform/cairole/ui/hlp_iopf.cxx
new file mode 100644
index 000000000..43e4dffc1
--- /dev/null
+++ b/private/oleutest/perform/cairole/ui/hlp_iopf.cxx
@@ -0,0 +1,641 @@
+//**********************************************************************
+// File name: HLP_IOIPF.cxx
+//
+// Implementation file for COleInPlaceFrame
+//
+// Functions:
+//
+// See IOIPF.H for class definition
+//
+// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+
+#include "hlp_pre.hxx"
+#include "hlp_iocs.hxx"
+#include "hlp_ias.hxx"
+#include "hlp_iopf.hxx"
+#include "hlp_iops.hxx"
+#include "hlp_app.hxx"
+#include "hlp_site.hxx"
+#include "hlp_doc.hxx"
+
+
+//**********************************************************************
+//
+// COleInPlaceFrame::QueryInterface
+//
+// Purpose:
+//
+// Used for interface negotiation
+//
+// Parameters:
+//
+// REFIID riid - A reference to the interface that is
+// being queried.
+//
+// LPVOID FAR* ppvObj - An out parameter to return a pointer to
+// the interface.
+//
+// Return Value:
+//
+// S_OK - The interface is supported.
+// E_NOINTERFACE - The interface is not supported
+//
+// Function Calls:
+// Function Location
+//
+// OutputDebugString Windows API
+// CSimpleApp::QueryInterface APP.cxx
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleInPlaceFrame::QueryInterface(REFIID riid, LPVOID FAR* ppvObj)
+{
+ DEBUGOUT(TEXT("In IOIPF::QueryInterface\r\n"));
+
+ // delegate to the application Object
+ return m_pApp->QueryInterface(riid, ppvObj);
+}
+
+//**********************************************************************
+//
+// COleInPlaceFrame::AddRef
+//
+// Purpose:
+//
+// Increments the reference count of the CSimpleApp. Since
+// COleInPlaceFrame is a nested class of CSimpleApp, we don't need an
+// extra reference count for COleInPlaceFrame. We can safely use the
+// reference count of CSimpleApp.
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// ULONG - The new reference count of the CSimpleApp
+//
+// Function Calls:
+// Function Location
+//
+// OutputDebugString Windows API
+// CSimpleApp::AddRef APP.cxx
+//
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) COleInPlaceFrame::AddRef()
+{
+ DEBUGOUT(TEXT("In IOIPF::AddRef\r\n"));
+
+ // delegate to the application Object
+ return m_pApp->AddRef();
+}
+
+//**********************************************************************
+//
+// COleInPlaceFrame::Release
+//
+// Purpose:
+//
+// Decrements the reference count of the CSimpleApp. Since
+// COleInPlaceFrame is a nested class of CSimpleApp, we don't need an
+// extra reference count for COleInPlaceFrame. We can safely use the
+// reference count of CSimpleApp.
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// ULONG - The new reference count of CSimpleApp.
+//
+// Function Calls:
+// Function Location
+//
+// OutputDebugString Windows API
+// CSimpleApp::Release APP.cxx
+//
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) COleInPlaceFrame::Release()
+{
+ DEBUGOUT(TEXT("In IOIPF::Release\r\n"));
+
+ // delegate to the document object
+ return m_pApp->Release();
+
+}
+
+//**********************************************************************
+//
+// COleInPlaceFrame::GetWindow
+//
+// Purpose:
+//
+// Returns the frame window handle
+//
+// Parameters:
+//
+// HWND FAR* lphwnd - Location to return the window handle
+//
+// Return Value:
+//
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// OutputDebugString Windows API
+// ResultFromScode OLE API
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleInPlaceFrame::GetWindow (HWND FAR* lphwnd)
+{
+ DEBUGOUT(TEXT("In IOIPF::GetWindow\r\n"));
+ *lphwnd = m_pApp->m_hAppWnd;
+ return ResultFromScode(S_OK);
+}
+
+//**********************************************************************
+//
+// COleInPlaceFrame::ContextSensitiveHelp
+//
+// Purpose:
+//
+// Used in implementing Context sensitive help
+//
+// Parameters:
+//
+// BOOL fEnterMode - TRUE if starting Context Sensitive help mode
+//
+// Return Value:
+//
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// OutputDebugString Windows API
+// ResultFromScode OLE API
+//
+// Comments:
+//
+// Be sure to read the technotes in the OLE toolkit.
+//
+//********************************************************************
+
+STDMETHODIMP COleInPlaceFrame::ContextSensitiveHelp (BOOL fEnterMode)
+{
+ DEBUGOUT(TEXT("In IOIPF::ContextSensitiveHelp\r\n"));
+
+ m_pApp->m_fMenuMode = fEnterMode;
+
+ return ResultFromScode(S_OK);
+}
+//**********************************************************************
+//
+// COleInPlaceFrame::GetBorder
+//
+// Purpose:
+//
+// Returns the outermost border that frame adornments can be attached
+// during InPlace Activation.
+//
+// Parameters:
+//
+// LPRECT lprectBorder - return parameter to contain the outermost
+// rect for frame adornments
+//
+// Return Value:
+//
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// OutputDebugString Windows API
+// GetClientRect Windows API
+// CopyRect Windows API
+// ResultFromScode OLE API
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleInPlaceFrame::GetBorder (LPRECT lprectBorder)
+{
+ RECT rect;
+
+ DEBUGOUT(TEXT("In IOIPF::GetBorder\r\n"));
+
+ // get the rect for the entire frame.
+ GetClientRect(m_pApp->m_hAppWnd, &rect);
+
+ CopyRect(lprectBorder, &rect);
+
+ return ResultFromScode(S_OK);
+}
+
+//**********************************************************************
+//
+// COleInPlaceFrame::RequestBorderSpace
+//
+// Purpose:
+//
+// Approves/Denies requests for border space during InPlace
+// negotiation.
+//
+// Parameters:
+//
+// LPCBORDERWIDTHS lpborderwidths - The width in pixels needed on
+// each side of the frame.
+//
+// Return Value:
+//
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// OutputDebugString Windows API
+// ResultFromScode OLE API
+//
+// Comments:
+//
+// This implementation doesn't care about how much border space
+// is used. It always returns S_OK.
+//
+//********************************************************************
+
+STDMETHODIMP COleInPlaceFrame::RequestBorderSpace (LPCBORDERWIDTHS
+ lpborderwidths)
+{
+ DEBUGOUT(TEXT("In IOIPF::RequestBorderSpace\r\n"));
+
+ // always approve the request
+ return ResultFromScode(S_OK);
+}
+
+//**********************************************************************
+//
+// COleInPlaceFrame::SetBorderSpace
+//
+// Purpose:
+//
+// The object calls this method when it is actually going to
+// start using the border space.
+//
+// Parameters:
+//
+// LPCBORDERWIDTHS lpborderwidths - Border space actually being used
+// by the object
+//
+// Return Value:
+//
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// CSimpleApp::AddFrameLevelTools APP.cxx
+// OutputDebugString Windows API
+// GetClientRect Windows API
+// MoveWindow Windows API
+// ResultFromScode Windows API
+//
+// Comments:
+//
+// This routine could be a little smarter and check to see if
+// the object is requesting the entire client area of the
+// window.
+//
+//********************************************************************
+
+STDMETHODIMP COleInPlaceFrame::SetBorderSpace (LPCBORDERWIDTHS lpborderwidths)
+{
+
+ DEBUGOUT(TEXT("In IOIPF::SetBorderSpace\r\n"));
+
+ if (lpborderwidths == NULL)
+ m_pApp->AddFrameLevelTools();
+ else
+ {
+ RECT rect;
+
+ GetClientRect(m_pApp->m_hAppWnd, &rect);
+
+ MoveWindow( m_pApp->m_lpDoc->m_hDocWnd,
+ rect.left + lpborderwidths->left,
+ rect.top + lpborderwidths->top,
+ rect.right - lpborderwidths->right - lpborderwidths->left,
+ rect.bottom - lpborderwidths->bottom - lpborderwidths->top,
+ TRUE);
+ }
+ return ResultFromScode(S_OK);
+}
+
+//**********************************************************************
+//
+// COleInPlaceFrame::SetActiveObject
+//
+// Purpose:
+// install the object being activated in-place
+//
+//
+// Parameters:
+//
+// LPOLEINPLACEACTIVEOBJECT lpActiveObject - Pointer to the
+// objects
+// IOleInPlaceActiveObject
+// interface
+//
+// LPCOLESTR lpszObjName - Name of the object
+//
+// Return Value:
+//
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// OutputDebugString Windows API
+// IOleInPlaceActiveObject::AddRef Object
+// IOleInPlaceActiveObject::Release Object
+// ResultFromScode OLE API
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleInPlaceFrame::SetActiveObject (LPOLEINPLACEACTIVEOBJECT
+ lpActiveObject, LPCOLESTR lpszObjName)
+{
+
+ DEBUGOUT(TEXT("In IOIPF::SetActiveObject\r\n"));
+
+ // AddRef() it and save it...
+ if (lpActiveObject)
+ {
+ lpActiveObject->AddRef();
+
+ lpActiveObject->GetWindow(&m_pApp->m_hwndUIActiveObj);
+ if (m_pApp->m_hwndUIActiveObj)
+ SendMessage(m_pApp->m_hwndUIActiveObj, WM_QUERYNEWPALETTE, 0, 0L);
+ }
+ else
+ {
+ if (m_pApp->m_lpDoc->m_lpActiveObject)
+ m_pApp->m_lpDoc->m_lpActiveObject->Release();
+ m_pApp->m_hwndUIActiveObj = NULL;
+ }
+
+ // in an MDI app, this method really shouldn't be called,
+ // this method associated with the doc is called instead.
+
+ m_pApp->m_lpDoc->m_lpActiveObject = lpActiveObject;
+ // should set window title here
+
+ return ResultFromScode(S_OK);
+}
+
+//**********************************************************************
+//
+// COleInPlaceFrame::InsertMenus
+//
+// Purpose:
+//
+// Inserts the container menu into the combined menu
+//
+// Parameters:
+//
+// HMENU hmenuShared - Menu Handle to be set.
+// LPOLEMENUGROUPWIDTHS lpMenuWidths - Width of menus
+//
+// Return Value:
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// OutputDebugString Windows API
+// AppendMenu Windows API
+// ResultFromScode OLE API
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleInPlaceFrame::InsertMenus (HMENU hmenuShared,
+ LPOLEMENUGROUPWIDTHS lpMenuWidths)
+{
+ DEBUGOUT(TEXT("In IOIPF::InsertMenus\r\n"));
+
+ AppendMenu(hmenuShared, MF_BYPOSITION | MF_POPUP,
+ (UINT) m_pApp->m_lpDoc->m_hFileMenu, TEXT("&File"));
+ AppendMenu(hmenuShared, MF_BYPOSITION | MF_POPUP,
+ (UINT) m_pApp->m_lpDoc->m_hHelpMenu, TEXT("&Other"));
+
+ lpMenuWidths->width[0] = 1;
+ lpMenuWidths->width[2] = 0;
+ lpMenuWidths->width[4] = 1;
+
+ return ResultFromScode(S_OK);
+}
+
+
+//**********************************************************************
+//
+// COleInPlaceFrame::SetMenu
+//
+// Purpose:
+//
+// Sets the application menu to the combined menu
+//
+// Parameters:
+//
+// HMENU hmenuShared - The combined menu
+//
+// HOLEMENU holemenu - Used by OLE
+//
+// HWND hwndActiveObject - Used by OLE
+//
+// Return Value:
+//
+// S_OK - if menu was correctly installed
+// E_FAIL - otherwise
+//
+// Function Calls:
+// Function Location
+//
+// OutputDebugString Windows API
+// SetMenu Windows API
+// OleSetMenuDescriptor OLE API
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleInPlaceFrame::SetMenu (HMENU hmenuShared, HOLEMENU holemenu,
+ HWND hwndActiveObject)
+{
+
+ DEBUGOUT(TEXT("In IOIPF::SetMenu\r\n"));
+
+ HMENU hMenu = m_pApp->m_lpDoc->m_hMainMenu;
+
+ if (holemenu)
+ hMenu = hmenuShared;
+
+ // call the windows api, not this method
+ ::SetMenu (m_pApp->m_hAppWnd, hMenu);
+
+ HRESULT hRes = OleSetMenuDescriptor(holemenu, m_pApp->m_hAppWnd,
+ hwndActiveObject, this,
+ m_pApp->m_lpDoc->m_lpActiveObject);
+
+ return hRes;
+}
+
+
+//**********************************************************************
+//
+// COleInPlaceFrame::RemoveMenus
+//
+// Purpose:
+//
+// Removes the container menus from the combined menu
+//
+// Parameters:
+//
+// HMENU hmenuShared - Handle to the combined menu.
+//
+// Return Value:
+//
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// OutputDebugString Windows API
+// GetMenuItemCount Windows API
+// RemoveMenu Windows API
+// ResultFromScode OLE API
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleInPlaceFrame::RemoveMenus (HMENU hmenuShared)
+{
+ int retval;
+
+ DEBUGOUT(TEXT("In IOIPF::RemoveMenus\r\n"));
+
+ while ((retval = GetMenuItemCount(hmenuShared)) && (retval != -1))
+ RemoveMenu(hmenuShared, 0, MF_BYPOSITION);
+
+ return ResultFromScode(S_OK);
+}
+
+//**********************************************************************
+//
+// COleInPlaceFrame::SetStatusText
+//
+// Purpose:
+//
+// Not Implemented
+//
+// Parameters:
+//
+// LPCOLESTR lpszStatusText - character string containing the message
+//
+// Return Value:
+//
+// E_FAIL
+//
+// Function Calls:
+// Function Location
+//
+// OutputDebugString Windows API
+//
+// Comments:
+//
+// This function is not implemented due to the fact
+// that this application does not have a status bar.
+//
+//********************************************************************
+
+STDMETHODIMP COleInPlaceFrame::SetStatusText (LPCOLESTR lpszStatusText)
+{
+ DEBUGOUT(TEXT("In IOIPF::SetStatusText\r\n"));
+ return ResultFromScode(E_FAIL);
+}
+
+//**********************************************************************
+//
+// COleInPlaceFrame::EnableModeless
+//
+// Purpose:
+//
+// Enables/Disables container modeless dialogs
+//
+// Parameters:
+//
+// BOOL fEnable - Enable/Disable
+//
+// Return Value:
+//
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// OutputDebugString Windows API
+//
+// Comments:
+//
+// There are no modeless dialogs in this application, so the
+// implementation of this method is trivial.
+//
+//********************************************************************
+
+STDMETHODIMP COleInPlaceFrame::EnableModeless (BOOL fEnable)
+{
+ DEBUGOUT(TEXT("In IOIPF::EnableModeless\r\n"));
+ return ResultFromScode(S_OK);
+}
+
+//**********************************************************************
+//
+// COleInPlaceFrame::TranslateAccelerator
+//
+// Purpose:
+//
+// Not Implemented
+//
+// Parameters:
+//
+// LPMSG lpmsg - structure containing keystroke message
+// WORD wID - identifier value corresponding to the keystroke
+//
+// Return Value:
+//
+// S_FALSE
+//
+// Function Calls:
+// Function Location
+//
+// OutputDebugString Windows API
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleInPlaceFrame::TranslateAccelerator (LPMSG lpmsg, WORD wID)
+{
+ DEBUGOUT(TEXT("In IOIPF::TranslateAccelerator\r\n"));
+ return ::TranslateAccelerator(m_pApp->m_hAppWnd, m_pApp->m_hAccel, lpmsg)
+ ? ResultFromScode(S_OK)
+ : ResultFromScode(S_FALSE);
+}
diff --git a/private/oleutest/perform/cairole/ui/hlp_iopf.hxx b/private/oleutest/perform/cairole/ui/hlp_iopf.hxx
new file mode 100644
index 000000000..d77ed8b64
--- /dev/null
+++ b/private/oleutest/perform/cairole/ui/hlp_iopf.hxx
@@ -0,0 +1,52 @@
+//**********************************************************************
+// File name: HLP_IOPF.HXX
+//
+// Definition of COleInPlaceFrame
+//
+// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+#if !defined( _HLP_IOPF_HXX_ )
+#define _HLP_IOPF_HXX_
+
+
+class CSimpleApp;
+
+interface COleInPlaceFrame : public IOleInPlaceFrame
+{
+ CSimpleApp FAR * m_pApp;
+
+ COleInPlaceFrame(CSimpleApp FAR * pApp)
+ {
+ OutputDebugString(TEXT("In IOIPF's constructor\r\n"));
+ m_pApp = pApp;
+ };
+
+ ~COleInPlaceFrame()
+ {
+ OutputDebugString(TEXT("In IOIPFS's destructor\r\n"));
+ };
+
+ STDMETHODIMP QueryInterface (REFIID riid, LPVOID FAR* ppv);
+ STDMETHODIMP_(ULONG) AddRef ();
+ STDMETHODIMP_(ULONG) Release ();
+
+ STDMETHODIMP GetWindow (HWND FAR* lphwnd);
+ STDMETHODIMP ContextSensitiveHelp (BOOL fEnterMode);
+
+ // *** IOleInPlaceUIWindow methods ***
+ STDMETHODIMP GetBorder (LPRECT lprectBorder);
+ STDMETHODIMP RequestBorderSpace (LPCBORDERWIDTHS lpborderwidths);
+ STDMETHODIMP SetBorderSpace (LPCBORDERWIDTHS lpborderwidths);
+ STDMETHODIMP SetActiveObject (LPOLEINPLACEACTIVEOBJECT lpActiveObject,LPCOLESTR lpszObjName);
+
+ // *** IOleInPlaceFrame methods ***
+ STDMETHODIMP InsertMenus (HMENU hmenuShared, LPOLEMENUGROUPWIDTHS lpMenuWidths);
+ STDMETHODIMP SetMenu (HMENU hmenuShared, HOLEMENU holemenu, HWND hwndActiveObject);
+ STDMETHODIMP RemoveMenus (HMENU hmenuShared);
+ STDMETHODIMP SetStatusText (LPCOLESTR lpszStatusText);
+ STDMETHODIMP EnableModeless (BOOL fEnable);
+ STDMETHODIMP TranslateAccelerator (LPMSG lpmsg, WORD wID);
+};
+
+#endif
+
diff --git a/private/oleutest/perform/cairole/ui/hlp_iops.cxx b/private/oleutest/perform/cairole/ui/hlp_iops.cxx
new file mode 100644
index 000000000..b612170eb
--- /dev/null
+++ b/private/oleutest/perform/cairole/ui/hlp_iops.cxx
@@ -0,0 +1,609 @@
+//**********************************************************************
+// File name: HLP_IOPS.cxx
+//
+// Implementation file for COleInPlaceSite
+//
+// Functions:
+//
+// See IOIPS.H for class Definition
+//
+// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+
+#include "hlp_pre.hxx"
+#include "hlp_iocs.hxx"
+#include "hlp_ias.hxx"
+#include "hlp_iopf.hxx"
+#include "hlp_iops.hxx"
+#include "hlp_app.hxx"
+#include "hlp_site.hxx"
+#include "hlp_doc.hxx"
+
+//**********************************************************************
+//
+// COleInPlaceSite::QueryInterface
+//
+// Purpose:
+//
+// Used for interface negotiation
+//
+// Parameters:
+//
+// REFIID riid - A reference to the interface that is
+// being queried.
+//
+// LPVOID FAR* ppvObj - An out parameter to return a pointer to
+// the interface.
+//
+// Return Value:
+//
+// S_OK - The interface is supported.
+// S_FALSE - The interface is not supported
+//
+// Function Calls:
+// Function Location
+//
+// OutputDebugString Windows API
+// CSimpleSite::QueryInterface SITE.cxx
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleInPlaceSite::QueryInterface(REFIID riid, LPVOID FAR* ppvObj)
+{
+ DEBUGOUT(TEXT("In IOIPS::QueryInterface\r\n"));
+
+ // delegate to the container Site
+ return m_pSite->QueryInterface(riid, ppvObj);
+}
+
+//**********************************************************************
+//
+// COleInPlaceSite::AddRef
+//
+// Purpose:
+//
+// Increments the reference count of the CSimpleSite. Since
+// COleInPlaceSite is a nested class of CSimpleSite, we don't need an
+// extra reference count for COleInPlaceSite. We can safely use the
+// reference count of CSimpleSite.
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// ULONG - The new reference count of CSimpleSite
+//
+// Function Calls:
+// Function Location
+//
+// OutputDebugString Windows API
+// CSimpleSite::QueryInterface SITE.cxx
+//
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) COleInPlaceSite::AddRef()
+{
+ DEBUGOUT(TEXT("In IOIPS::AddRef\r\n"));
+
+ // delegate to the container Site
+ return m_pSite->AddRef();
+}
+
+//**********************************************************************
+//
+// COleInPlaceSite::Release
+//
+// Purpose:
+//
+// Decrements the reference count of the CSimpleSite. Since
+// COleInPlaceSite is a nested class of CSimpleSite, we don't need an
+// extra reference count for COleInPlaceSite. We can safely use the
+// reference count of CSimpleSite.
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// ULONG - The new reference count of CSimpleSite
+//
+// Function Calls:
+// Function Location
+//
+// OutputDebugString Windows API
+// CSimpleSite::Release SITE.cxx
+//
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) COleInPlaceSite::Release()
+{
+ DEBUGOUT(TEXT("In IOIPS::Release\r\n"));
+
+ // delegate to the container Site
+ return m_pSite->Release();
+}
+
+//**********************************************************************
+//
+// COleInPlaceSite::GetWindow
+//
+// Purpose:
+//
+// Returns the Window Handle of the client site
+//
+// Parameters:
+//
+// HWND FAR* lphwnd - place to return the handle
+//
+// Return Value:
+//
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// OutputDebugString Windows API
+// ResultFromScode OLE API
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleInPlaceSite::GetWindow (HWND FAR* lphwnd)
+{
+ DEBUGOUT(TEXT("In IOIPS::GetWindow\r\n"));
+
+ // return the handle to our editing window.
+ *lphwnd = m_pSite->m_lpDoc->m_hDocWnd;
+
+ return ResultFromScode(S_OK);
+}
+
+//**********************************************************************
+//
+// COleInPlaceSite::ContextSensitiveHelp
+//
+// Purpose:
+// set/reset context sensitive help mode
+//
+// Parameters:
+//
+// BOOL fEnterMode - TRUE for entering Context Sensitive help mode
+//
+// Return Value:
+//
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// OutputDebugString Windows API
+// ResultFromScode OLE API
+//
+// Comments:
+//
+// Be sure to read the technotes included with the OLE toolkit.
+//
+//********************************************************************
+
+STDMETHODIMP COleInPlaceSite::ContextSensitiveHelp (BOOL fEnterMode)
+{
+ DEBUGOUT(TEXT("In IOIPS::ContextSensitiveHelp\r\n"));
+
+ if (m_pSite->m_lpDoc->m_lpApp->m_fCSHMode != fEnterMode)
+ m_pSite->m_lpDoc->m_lpApp->m_fCSHMode = fEnterMode;
+
+ return ResultFromScode(S_OK);
+}
+
+//**********************************************************************
+//
+// COleInPlaceSite::CanInPlaceActivate
+//
+// Purpose:
+//
+// Object calls to find out if the container can InPlace activate
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// OutputDebugString Windows API
+// ResultFromScode OLE API
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleInPlaceSite::CanInPlaceActivate ()
+{
+ DEBUGOUT(TEXT("In IOIPS::CanInPlaceActivate\r\n"));
+
+ // return S_OK to indicate we can in-place activate
+ return ResultFromScode(S_OK);
+}
+
+//**********************************************************************
+//
+// COleInPlaceSite::OnInPlaceActivate
+//
+// Purpose:
+//
+// Called by the object on InPlace Activation
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// S_OK - if the interface can be found
+// E_FAIL - otherwise
+//
+// Function Calls:
+// Function Location
+//
+// OutputDebugString Windows API
+// ResultFromScode OLE API
+// IOleObject::QueryInterface Object
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleInPlaceSite::OnInPlaceActivate ()
+{
+ HRESULT hrErr;
+ DEBUGOUT(TEXT("In IOIPS::OnInPlaceActivate\r\n"));
+
+ hrErr = m_pSite->m_lpOleObject->QueryInterface(
+ IID_IOleInPlaceObject, (LPVOID FAR *)&m_pSite->m_lpInPlaceObject);
+ if (hrErr != NOERROR)
+ return ResultFromScode(E_FAIL);
+
+ // return S_OK to indicate we can in-place activate.
+ return ResultFromScode(S_OK);
+}
+
+//**********************************************************************
+//
+// COleInPlaceSite::OnUIActivate
+//
+// Purpose:
+//
+// Object calls this method when it displays it's UI.
+//
+// Parameters:
+//
+// None.
+//
+// Return Value:
+//
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// OutputDebugString Windows API
+// ResultFromScode OLE API
+// IOleInPlaceObject::GetWindow Object
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleInPlaceSite::OnUIActivate ()
+{
+ DEBUGOUT(TEXT("In IOIPS::OnUIActivate\r\n"));
+
+ m_pSite->m_lpDoc->m_fAddMyUI=FALSE;
+ m_pSite->m_lpDoc->m_fInPlaceActive = TRUE;
+ m_pSite->m_fInPlaceActive = TRUE;
+
+ m_pSite->m_lpInPlaceObject->GetWindow((HWND FAR*)&m_pSite->m_hwndIPObj);
+
+ // return S_OK to continue in-place activation
+ return ResultFromScode(S_OK);
+}
+
+//**********************************************************************
+//
+// COleInPlaceSite::GetWindowContext
+//
+// Purpose:
+//
+// Called by the object to get information for InPlace Negotiation.
+//
+// Parameters:
+//
+// LPOLEINPLACEFRAME FAR* lplpFrame - Location to return a pointer
+// to IOleInPlaceFrame.
+//
+// LPOLEINPLACEUIWINDOW FAR* lplpDoc - Location to return a pointer
+// to IOleInPlaceUIWindow.
+//
+// LPRECT lprcPosRect - The rect that the object
+// occupies
+//
+// LPRECT lprcClipRect - The clipping rect
+//
+// LPOLEINPLACEFRAMEINFO lpFrameInfo - Pointer to FRAMEINFO
+//
+//
+// Return Value:
+//
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// COleInPlaceFrame::AddRef IOIPF.cxx
+// CSimpleSite::GetObjRect SITE.cxx
+// OutputDebugString Windows API
+// CopyRect Windows API
+// GetClientRect Windows API
+// ResultFromScode OLE API
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleInPlaceSite::GetWindowContext (
+ LPOLEINPLACEFRAME FAR* lplpFrame,
+ LPOLEINPLACEUIWINDOW FAR* lplpDoc,
+ LPRECT lprcPosRect,
+ LPRECT lprcClipRect,
+ LPOLEINPLACEFRAMEINFO lpFrameInfo)
+{
+ RECT rect;
+
+ DEBUGOUT(TEXT("In IOIPS::GetWindowContext\r\n"));
+
+ // the frame is associated with the application object.
+ // need to AddRef() it...
+ m_pSite->m_lpDoc->m_lpApp->m_OleInPlaceFrame.AddRef();
+ *lplpFrame = &m_pSite->m_lpDoc->m_lpApp->m_OleInPlaceFrame;
+ *lplpDoc = NULL; // must be NULL, cause we're SDI.
+
+ // get the size of the object in pixels
+ m_pSite->GetObjRect(&rect);
+
+ // Copy this to the passed buffer
+ CopyRect(lprcPosRect, &rect);
+
+ // fill the clipping region
+ GetClientRect(m_pSite->m_lpDoc->m_hDocWnd, &rect);
+ CopyRect(lprcClipRect, &rect);
+
+ // fill the FRAMEINFO
+ lpFrameInfo->fMDIApp = FALSE;
+ lpFrameInfo->hwndFrame = m_pSite->m_lpDoc->m_lpApp->m_hAppWnd;
+ lpFrameInfo->haccel = m_pSite->m_lpDoc->m_lpApp->m_hAccel;
+ lpFrameInfo->cAccelEntries = SIMPCNTR_ACCEL_CNT;
+
+ return ResultFromScode(S_OK);
+}
+
+//**********************************************************************
+//
+// COleInPlaceSite::Scroll
+//
+// Purpose:
+//
+// Not Implemented
+//
+// Parameters:
+//
+// SIZE scrollExtent - number of pixels scrolled in X and Y direction
+//
+// Return Value:
+//
+// E_FAIL
+//
+// Function Calls:
+// Function Location
+//
+// OutputDebugString Windows API
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleInPlaceSite::Scroll (SIZE scrollExtent)
+{
+ DEBUGOUT(TEXT("In IOIPS::Scroll\r\n"));
+ return ResultFromScode(E_FAIL);
+}
+
+//**********************************************************************
+//
+// COleInPlaceSite::OnUIDeactivate
+//
+// Purpose:
+//
+// Called by the object when its UI goes away
+//
+// Parameters:
+//
+// BOOL fUndoable
+//
+// Return Value:
+//
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// OutputDebugString Windows API
+// CSimpleAPP::QueryNewPalette APP.cxx
+// CSimpleAPP::AddFrameLevelUI APP.cxx
+// ResultFromScode OLE API
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleInPlaceSite::OnUIDeactivate (BOOL fUndoable)
+{
+ DEBUGOUT(TEXT("In IOIPS::OnUIDeactivate\r\n"));
+
+ // need to clear this flag first
+ m_pSite->m_lpDoc->m_fInPlaceActive = FALSE;
+ m_pSite->m_fInPlaceActive = FALSE;
+
+ m_pSite->m_lpDoc->m_lpApp->QueryNewPalette();
+ m_pSite->m_lpDoc->m_lpApp->AddFrameLevelUI();
+ return ResultFromScode(S_OK);
+}
+
+//**********************************************************************
+//
+// COleInPlaceSite::OnInPlaceDeactivate
+//
+// Purpose:
+//
+// Called when the inplace session is over
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// OutputDebugString Windows API
+// ResultFromScode OLE API
+// IOleInPlaceObject::Release Object
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleInPlaceSite::OnInPlaceDeactivate ()
+{
+ DEBUGOUT(TEXT("In IOIPS::OnInPlaceDeactivate\r\n"));
+
+ if (m_pSite->m_lpInPlaceObject)
+ {
+ m_pSite->m_lpInPlaceObject->Release();
+ m_pSite->m_lpInPlaceObject = NULL;
+ }
+ return ResultFromScode(S_OK);
+}
+
+//**********************************************************************
+//
+// COleInPlaceSite::DiscardUndoState
+//
+// Purpose:
+//
+// Not Implemented
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// E_FAIL
+//
+// Function Calls:
+// Function Location
+//
+// OutputDebugString Windows API
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleInPlaceSite::DiscardUndoState ()
+{
+ DEBUGOUT(TEXT("In IOIPS::DiscardUndoState\r\n"));
+ return ResultFromScode(E_FAIL);
+}
+
+//**********************************************************************
+//
+// COleInPlaceSite::DeactivateAndUndo
+//
+// Purpose:
+//
+// Not Implemented
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// E_FAIL
+//
+// Function Calls:
+// Function Location
+//
+// OutputDebugString Windows API
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleInPlaceSite::DeactivateAndUndo ()
+{
+ DEBUGOUT(TEXT("In IOIPS::DeactivateAndUndo\r\n"));
+ return ResultFromScode(E_FAIL);
+}
+
+//**********************************************************************
+//
+// COleInPlaceSite::OnPosRectChange
+//
+// Purpose:
+//
+// The object calls this method when it's size changes during an
+// InPlace Session
+//
+// Parameters:
+//
+// LPCRECT lprcPosRect - The new object rect
+//
+// Return Value:
+//
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// OutputDebugString Windows API
+// GetClientRect Windows API
+// IOleObject::GetExtent Object
+// IOleInPlaceObject::SetObjectRects Object
+// ResultFromScode OLE API
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleInPlaceSite::OnPosRectChange (LPCRECT lprcPosRect)
+{
+ DEBUGOUT(TEXT("In IOIPS::OnPosRectChange\r\n"));
+
+ // update the size in the document object
+ // NOTE: here we must call IOleObject::GetExtent to get actual extents
+ // of the running object. IViewObject2::GetExtent returns the
+ // last cached extents.
+ m_pSite->m_lpOleObject->GetExtent(DVASPECT_CONTENT, &m_pSite->m_sizel);
+ RECT rect;
+ GetClientRect(m_pSite->m_lpDoc->m_hDocWnd, &rect);
+
+ // tell the object its new size
+ m_pSite->m_lpInPlaceObject->SetObjectRects(lprcPosRect, &rect);
+
+ return ResultFromScode(S_OK);
+}
+
diff --git a/private/oleutest/perform/cairole/ui/hlp_iops.hxx b/private/oleutest/perform/cairole/ui/hlp_iops.hxx
new file mode 100644
index 000000000..4a21fb394
--- /dev/null
+++ b/private/oleutest/perform/cairole/ui/hlp_iops.hxx
@@ -0,0 +1,54 @@
+//**********************************************************************
+// File name: HLP_IOPS.HXX
+//
+// Definition of COleInPlaceSite
+//
+// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+#if !defined( _HLP_IOPS_HXX_ )
+#define _HLP_IOPS_HXX_
+
+
+class CSimpleSite;
+
+interface COleInPlaceSite : public IOleInPlaceSite
+{
+ CSimpleSite FAR * m_pSite;
+
+ COleInPlaceSite(CSimpleSite FAR *pSite)
+ {
+ OutputDebugString(TEXT("In IOIPS's constructor\r\n"));
+ m_pSite = pSite;
+ };
+
+ ~COleInPlaceSite()
+ {
+ OutputDebugString(TEXT("In IOIPS;s destructor\r\n"));
+ };
+
+ STDMETHODIMP QueryInterface (REFIID riid, LPVOID FAR* ppv);
+ STDMETHODIMP_(ULONG) AddRef ();
+ STDMETHODIMP_(ULONG) Release ();
+
+ STDMETHODIMP GetWindow (HWND FAR* lphwnd);
+ STDMETHODIMP ContextSensitiveHelp (BOOL fEnterMode);
+
+ // *** IOleInPlaceSite methods ***
+ STDMETHODIMP CanInPlaceActivate ();
+ STDMETHODIMP OnInPlaceActivate ();
+ STDMETHODIMP OnUIActivate ();
+ STDMETHODIMP GetWindowContext (LPOLEINPLACEFRAME FAR* lplpFrame,
+ LPOLEINPLACEUIWINDOW FAR* lplpDoc,
+ LPRECT lprcPosRect,
+ LPRECT lprcClipRect,
+ LPOLEINPLACEFRAMEINFO lpFrameInfo);
+ STDMETHODIMP Scroll (SIZE scrollExtent);
+ STDMETHODIMP OnUIDeactivate (BOOL fUndoable);
+ STDMETHODIMP OnInPlaceDeactivate ();
+ STDMETHODIMP DiscardUndoState ();
+ STDMETHODIMP DeactivateAndUndo ();
+ STDMETHODIMP OnPosRectChange (LPCRECT lprcPosRect);
+};
+
+#endif
+
diff --git a/private/oleutest/perform/cairole/ui/hlp_site.cxx b/private/oleutest/perform/cairole/ui/hlp_site.cxx
new file mode 100644
index 000000000..21e5f926a
--- /dev/null
+++ b/private/oleutest/perform/cairole/ui/hlp_site.cxx
@@ -0,0 +1,668 @@
+//**********************************************************************
+// File name: HLP_SITE.cxx
+//
+// Implementation file for CSimpleSite
+//
+// Functions:
+//
+// See SITE.H for class definition
+//
+// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+
+#include <headers.cxx>
+#pragma hdrstop
+
+#include "hlp_iocs.hxx"
+#include "hlp_ias.hxx"
+#include "hlp_app.hxx"
+#include "hlp_site.hxx"
+#include "hlp_doc.hxx"
+
+//**********************************************************************
+//
+// CSimpleSite::Create
+//
+// Purpose:
+//
+// Creation routine for CSimpleSite
+//
+// Parameters:
+//
+// CSimpleDoc FAR *lpDoc - Pointer to CSimpleDoc
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// IStorage::CreateStorage OLE API
+// assert C Runtime
+//
+// Comments:
+//
+//********************************************************************
+
+CSimpleSite FAR * CSimpleSite::Create(CSimpleDoc FAR *lpDoc, INT iIter)
+{
+ CSimpleSite FAR * lpTemp = new CSimpleSite(lpDoc);
+
+ if (!lpTemp)
+ return NULL;
+
+ OLECHAR szTempName[128];
+ swprintf(szTempName, L"Object %d", iIter);
+
+ // create a sub-storage for the object
+ HRESULT hErr = lpDoc->m_lpStorage->CreateStorage( szTempName,
+ STGM_READWRITE | STGM_TRANSACTED | STGM_SHARE_EXCLUSIVE,
+ 0,
+ 0,
+ &lpTemp->m_lpObjStorage);
+
+ assert(hErr == NOERROR);
+
+ if (hErr != NOERROR)
+ {
+ delete lpTemp;
+ return NULL;
+ }
+
+ // we will add one ref count on our Site. later when we want to destroy
+ // the Site object we will release this ref count. when the Site's ref
+ // count goes to 0, it will be deleted.
+ lpTemp->AddRef();
+
+ HEAPVALIDATE();
+
+ return lpTemp;
+}
+
+//**********************************************************************
+//
+// CSimpleSite::CSimpleSite
+//
+// Purpose:
+//
+// Constructor for CSimpleSite
+//
+// Parameters:
+//
+// CSimpleDoc FAR *lpDoc - Pointer to CSimpleDoc
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// Comments:
+//
+//********************************************************************
+#pragma warning(disable : 4355) // turn off this warning. This warning
+ // tells us that we are passing this in
+ // an initializer, before "this" is through
+ // initializing. This is ok, because
+ // we just store the ptr in the other
+ // constructors
+
+CSimpleSite::CSimpleSite (CSimpleDoc FAR *lpDoc) : m_OleClientSite(this),
+ m_AdviseSink(this)
+// m_OleInPlaceSite(this)
+#pragma warning (default : 4355) // Turn the warning back on
+{
+ // remember the pointer to the doc
+ m_lpDoc = lpDoc;
+
+ // clear the reference count
+ m_nCount = 0;
+
+ m_dwDrawAspect = DVASPECT_CONTENT;
+ m_lpOleObject = NULL;
+ m_lpInPlaceObject = NULL;
+ m_hwndIPObj = NULL;
+ m_fInPlaceActive = FALSE;
+ m_fObjectOpen = FALSE;
+
+ HEAPVALIDATE();
+
+}
+
+//**********************************************************************
+//
+// CSimpleSite::~CSimpleSite
+//
+// Purpose:
+//
+// Destructor for CSimpleSite
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// OutputDebugString Windows API
+// IOleObject::Release Object
+// IStorage::Release OLE API
+//
+// Comments:
+//
+//********************************************************************
+
+CSimpleSite::~CSimpleSite ()
+{
+ DEBUGOUT (L"In CSimpleSite's Destructor \r\n");
+
+ if (m_lpOleObject)
+ m_lpOleObject->Release();
+
+ if (m_lpObjStorage)
+ m_lpObjStorage->Release();
+}
+
+
+//**********************************************************************
+//
+// CSimpleSite::CloseOleObject
+//
+// Purpose:
+//
+// Call IOleObject::Close on the object of the CSimpleSite
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// OutputDebugString Windows API
+// IOleObject::QueryInterface Object
+// IOleObject::Close Object
+// IOleInPlaceObject::UIDeactivate Object
+// IOleInPlaceObject::InPlaceDeactivate Object
+// IOleInPlaceObject::Release Object
+//
+// Comments:
+//
+//********************************************************************
+
+void CSimpleSite::CloseOleObject (void)
+{
+ LPOLEINPLACEOBJECT lpObject;
+ LPVIEWOBJECT lpViewObject = NULL;
+
+ DEBUGOUT (L"In CSimpleSite::CloseOleObject \r\n");
+
+ if (m_lpOleObject)
+ {
+ if (m_fInPlaceActive)
+ {
+ m_lpOleObject->QueryInterface(IID_IOleInPlaceObject, (LPVOID FAR *)&lpObject);
+ lpObject->UIDeactivate();
+ // don't need to worry about inside-out because the object
+ // is going away.
+ lpObject->InPlaceDeactivate();
+ lpObject->Release();
+ }
+
+ m_lpOleObject->Close(OLECLOSE_NOSAVE);
+ }
+
+ //Make sure Heap is proper before leaving the routine
+ HEAPVALIDATE();
+}
+
+
+//**********************************************************************
+//
+// CSimpleSite::UnloadOleObject
+//
+// Purpose:
+//
+// Close and release all pointers to the object of the CSimpleSite
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// OutputDebugString Windows API
+// CSimpleSite::CloseOleObject SITE.cxx
+// IOleObject::QueryInterface Object
+// IViewObject::SetAdvise Object
+// IViewObject::Release Object
+// IStorage::Release OLE API
+//
+// Comments:
+//
+//********************************************************************
+
+void CSimpleSite::UnloadOleObject (void)
+{
+ DEBUGOUT (L"In CSimpleSite::UnloadOleObject \r\n");
+ HEAPVALIDATE();
+
+ if (m_lpOleObject)
+ {
+ LPVIEWOBJECT lpViewObject;
+ CloseOleObject(); // ensure object is closed; NOP if already closed
+
+ m_lpOleObject->QueryInterface(IID_IViewObject, (LPVOID FAR *)&lpViewObject);
+
+ if (lpViewObject)
+ {
+ // Remove the view advise
+ lpViewObject->SetAdvise(m_dwDrawAspect, 0, NULL);
+ lpViewObject->Release();
+ }
+
+ m_lpOleObject->Release();
+ m_lpOleObject = NULL;
+ }
+
+}
+
+
+//**********************************************************************
+//
+// CSimpleSite::QueryInterface
+//
+// Purpose:
+//
+// Used for interface negotiation of the container Site.
+//
+// Parameters:
+//
+// REFIID riid - A reference to the interface that is
+// being queried.
+//
+// LPVOID FAR* ppvObj - An out parameter to return a pointer to
+// the interface.
+//
+// Return Value:
+//
+// S_OK - The interface is supported.
+// S_FALSE - The interface is not supported
+//
+// Function Calls:
+// Function Location
+//
+// OutputDebugString Windows API
+// IsEqualIID OLE API
+// ResultFromScode OLE API
+// CSimpleSite::AddRef OBJ.cxx
+// COleClientSite::AddRef IOCS.cxx
+// CAdviseSink::AddRef IAS.cxx
+//
+// Comments:
+//
+//
+//********************************************************************
+
+STDMETHODIMP CSimpleSite::QueryInterface(REFIID riid, LPVOID FAR* ppvObj)
+{
+ DEBUGOUT(L"In CSimpleSite::QueryInterface\r\n");
+
+ HEAPVALIDATE();
+ *ppvObj = NULL; // must set out pointer parameters to NULL
+
+ if ( riid == IID_IUnknown)
+ {
+ AddRef();
+ *ppvObj = this;
+ return ResultFromScode(S_OK);
+ }
+
+ if ( riid == IID_IOleClientSite)
+ {
+ m_OleClientSite.AddRef();
+ *ppvObj = &m_OleClientSite;
+ return ResultFromScode(S_OK);
+ }
+
+ if ( riid == IID_IAdviseSink)
+ {
+ m_AdviseSink.AddRef();
+ *ppvObj = &m_AdviseSink;
+ return ResultFromScode(S_OK);
+ }
+
+#if 0
+ if ( riid == IID_IOleInPlaceSite)
+ {
+ m_OleInPlaceSite.AddRef();
+ *ppvObj = &m_OleInPlaceSite;
+ return ResultFromScode(S_OK);
+ }
+#endif
+
+ // Not a supported interface
+ HEAPVALIDATE();
+ return ResultFromScode(E_NOINTERFACE);
+}
+
+//**********************************************************************
+//
+// CSimpleSite::AddRef
+//
+// Purpose:
+//
+// Increments the reference count of the container Site.
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// ULONG - The new reference count of the site.
+//
+// Function Calls:
+// Function Location
+//
+// OutputDebugString Windows API
+//
+// Comments:
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) CSimpleSite::AddRef()
+{
+ DEBUGOUT(L"In CSimpleSite::AddRef\r\n");
+
+ return ++m_nCount;
+}
+
+//**********************************************************************
+//
+// CSimpleSite::Release
+//
+// Purpose:
+//
+// Decrements the reference count of the container Site
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// ULONG - The new reference count of the Site.
+//
+// Function Calls:
+// Function Location
+//
+// OutputDebugString Windows API
+//
+// Comments:
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) CSimpleSite::Release()
+{
+ DEBUGOUT(L"In CSimpleSite::Release\r\n");
+
+ if (--m_nCount == 0) {
+ delete this;
+ return 0;
+ }
+ HEAPVALIDATE();
+ return m_nCount;
+}
+
+//**********************************************************************
+//
+// CSimpleSite::InitObject
+//
+// Purpose:
+//
+// Used to initialize a newly create object (can't be done in the
+// constructor).
+//
+// Parameters:
+//
+// BOOL fCreateNew - TRUE if insert NEW object
+// FALSE if create object FROM FILE
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// IOleObject::SetHostNames Object
+// IOleObject::QueryInterface Object
+// IViewObject2::GetExtent Object
+// IOleObject::DoVerb Object
+// IViewObject::SetAdvise Object
+// IViewObject::Release Object
+// GetClientRect Windows API
+// OleSetContainedObject OLE API
+//
+// Comments:
+//
+//********************************************************************
+
+void CSimpleSite::InitObject(BOOL fCreateNew)
+{
+ LPVIEWOBJECT2 lpViewObject2;
+ RECT rect;
+
+ // Set a View Advise
+ m_lpOleObject->QueryInterface(IID_IViewObject2,(LPVOID FAR *)&lpViewObject2);
+ lpViewObject2->SetAdvise(m_dwDrawAspect, ADVF_PRIMEFIRST, &m_AdviseSink);
+
+ // get the initial size of the object
+ lpViewObject2->GetExtent(m_dwDrawAspect, -1 /*lindex*/, NULL /*ptd*/, &m_sizel);
+ GetObjRect(&rect); // get the rectangle of the object in pixels
+ lpViewObject2->Release();
+
+ // give the object the name of the container app/document
+ m_lpOleObject->SetHostNames(L"Simple Application", L"Simple OLE 2.0 In-Place Container");
+
+ // inform object handler/DLL object that it is used in the embedding container's context
+ OleSetContainedObject(m_lpOleObject, TRUE);
+
+ if (fCreateNew) {
+ // force new object to save to guarantee valid object in our storage.
+ // OLE 1.0 objects may close w/o saving. this is NOT necessary if the
+ // object is created FROM FILE; its data in storage is already valid.
+ m_OleClientSite.SaveObject();
+
+ // we only want to DoVerb(SHOW) if this is an InsertNew object.
+ // we should NOT DoVerb(SHOW) if the object is created FromFile.
+ m_lpOleObject->DoVerb(
+ OLEIVERB_SHOW,
+ NULL,
+ &m_OleClientSite,
+ -1,
+ m_lpDoc->m_hDocWnd,
+ &rect);
+ }
+}
+
+//**********************************************************************
+//
+// CSimpleSite::PaintObj
+//
+// Purpose:
+//
+// Paints the object
+//
+// Parameters:
+//
+// HDC hDC - Device context of the document window
+//
+// Return Value:
+//
+// Function Calls:
+// Function Location
+//
+// IOleObject::QueryInterface Object
+// IViewObject::GetColorSet Object
+// IViewObject::Release Object
+// SetMapMode Windows API
+// LPtoDP Windows API
+// CreateHatchBrush Windows API
+// SelectObject Windows API
+// DeleteObject Windows API
+// CreatePalette Windows API
+// SelectPalette Windows API
+// RealizePalette Windows API
+// OleStdFree OUTLUI Function
+// OleDraw OLE API
+//
+// Comments:
+//
+//********************************************************************
+
+void CSimpleSite::PaintObj(HDC hDC)
+{
+RECT rect;
+
+ // need to check to make sure there is a valid object
+ // available. This is needed if there is a paint msg
+ // between the time that CSimpleSite is instantiated
+ // and OleUIInsertObject returns.
+ if (!m_lpOleObject)
+ return;
+
+ // convert it to pixels
+ GetObjRect(&rect);
+
+ LPLOGPALETTE pColorSet = NULL;
+ LPVIEWOBJECT lpView = NULL;
+
+ // get a pointer to IViewObject
+ m_lpOleObject->QueryInterface(IID_IViewObject,(LPVOID FAR *) &lpView);
+
+ // draw the object
+ OleDraw(m_lpOleObject, m_dwDrawAspect, hDC, &rect);
+#if 0
+ // if the object is open, draw a hatch rect.
+ if (m_fObjectOpen)
+ {
+ HBRUSH hBrush = CreateHatchBrush ( HS_BDIAGONAL, RGB(0,0,0) );
+ HBRUSH hOldBrush = SelectObject (hDC, hBrush);
+ SetROP2(hDC, R2_MASKPEN);
+ Rectangle (hDC, rect.left, rect.top, rect.right, rect.bottom);
+ SelectObject(hDC, hOldBrush);
+ DeleteObject(hBrush);
+ }
+#endif
+
+ // if a view pointer was successfully returned, it needs to be released.
+ if (lpView)
+ lpView->Release();
+}
+
+#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)
+
+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) 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;
+ }
+
+
+//**********************************************************************
+//
+// CSimpleSite::GetObjRect
+//
+// Purpose:
+//
+// Retrieves the rect of the object in pixels
+//
+// Parameters:
+//
+// LPRECT lpRect - Rect structure filled with object's rect in pixels
+//
+// Return Value:
+//
+// Function Calls:
+// Function Location
+//
+// XformWidthInHimetricToPixels OUTLUI Function
+// XformHeightInHimetricToPixels OUTLUI Function
+//
+// Comments:
+//
+//********************************************************************
+
+void CSimpleSite::GetObjRect(LPRECT lpRect)
+{
+ // convert it to pixels
+ lpRect->left = lpRect->top = 0;
+ lpRect->right = XformWidthInHimetricToPixels(NULL,(int)m_sizel.cx);
+ lpRect->bottom = XformHeightInHimetricToPixels(NULL,(int)m_sizel.cy);
+}
+
+
+
+
+
diff --git a/private/oleutest/perform/cairole/ui/hlp_site.hxx b/private/oleutest/perform/cairole/ui/hlp_site.hxx
new file mode 100644
index 000000000..dd087617f
--- /dev/null
+++ b/private/oleutest/perform/cairole/ui/hlp_site.hxx
@@ -0,0 +1,63 @@
+//**********************************************************************
+// File name: HLP_SITE.HXX
+//
+// Definition of CSimpleSite
+//
+// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+#if !defined( _HLP_SITE_HXX_ )
+#define _HLP_SITE_HXX_
+
+#include <ole2.h>
+#include "hlp_ias.hxx"
+#include "hlp_iocs.hxx"
+
+class CSimpleDoc;
+
+class CSimpleSite : public IUnknown
+{
+public:
+ int m_nCount;
+ DWORD m_dwConnection;
+ LPOLEOBJECT m_lpOleObject;
+ LPOLEINPLACEOBJECT m_lpInPlaceObject;
+ HWND m_hwndIPObj;
+ DWORD m_dwDrawAspect;
+ SIZEL m_sizel;
+ BOOL m_fInPlaceActive;
+ BOOL m_fObjectOpen;
+ LPSTORAGE m_lpObjStorage;
+
+ CAdviseSink m_AdviseSink;
+ //COleInPlaceSite m_OleInPlaceSite;
+ COleClientSite m_OleClientSite;
+
+ CSimpleDoc FAR * m_lpDoc;
+
+ // IUnknown Interfaces
+ STDMETHODIMP QueryInterface(REFIID riid, LPVOID FAR* ppvObj);
+ STDMETHODIMP_(ULONG) AddRef();
+ STDMETHODIMP_(ULONG) Release();
+
+ void InitObject(BOOL fCreateNew);
+ static CSimpleSite FAR * Create(CSimpleDoc FAR *lpDoc, INT iIter);
+ CSimpleSite(CSimpleDoc FAR *lpDoc);
+ ~CSimpleSite();
+ void PaintObj(HDC hDC);
+ void GetObjRect(LPRECT lpRect);
+ void CloseOleObject(void);
+ void UnloadOleObject(void);
+};
+
+#ifdef DEBUG
+#define HEAPVALIDATE() \
+ if (!HeapValidate(GetProcessHeap(), 0, NULL)) {DebugBreak();}
+
+#define DEBUGOUT(lpstr) OutputDebugString(lpstr)
+#else
+#define HEAPVALIDATE()
+#define DEBUGOUT(lpstr)
+#endif //Debug
+
+
+#endif
diff --git a/private/oleutest/perform/cairole/ui/hlp_util.hxx b/private/oleutest/perform/cairole/ui/hlp_util.hxx
new file mode 100644
index 000000000..4c096ab98
--- /dev/null
+++ b/private/oleutest/perform/cairole/ui/hlp_util.hxx
@@ -0,0 +1,37 @@
+//+------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1993.
+//
+// File: utils.hxx
+//
+//
+// History: SanjayK Created
+//
+//--------------------------------------------------------------------------
+#ifndef _UTILS_HXX_
+#define _UTILS_HXX_
+
+#ifdef STRESS
+#define GetTimerVal(var)
+#else
+#define GetTimerVal(var) var = sw.Read()
+#endif //STRESS
+#define STRESSCOUNT 50
+
+#define OutlineClassName L"OLE2SvrOutl32"
+#define lpszTab TEXT("\t")
+#define lpszSUCCESS TEXT("returned SUCCESS")
+#define lpszFAIL TEXT("returned FAIL")
+extern TCHAR vlpScratchBuf[];
+
+
+#define LOGRESULTS(lpstr, hres) \
+ if (hres == NOERROR) \
+ wsprintf(vlpScratchBuf, TEXT("%s %s, hres = "), lpstr, lpszSUCCESS);\
+ else \
+ wsprintf(vlpScratchBuf, TEXT("%s %s"), lpstr, lpszFAIL); \
+ Log(vlpScratchBuf, hres);
+
+
+#endif //UTILS_HXX
diff --git a/private/oleutest/perform/cairole/ui/makefile b/private/oleutest/perform/cairole/ui/makefile
new file mode 100644
index 000000000..21eedcbe0
--- /dev/null
+++ b/private/oleutest/perform/cairole/ui/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/perform/cairole/ui/readme b/private/oleutest/perform/cairole/ui/readme
new file mode 100644
index 000000000..4a8a5b453
--- /dev/null
+++ b/private/oleutest/perform/cairole/ui/readme
@@ -0,0 +1,13 @@
+Grab the following from \\cosmosaxp\ctdaily\<build>\daytona\i386\CtOleUi\bin
+
+sr32test.exe
+ole2test.reg
+outline\svrout32.exe
+outline\cntout32.exe
+outline\icnout32.exe
+outline\isvout32.exe
+outline\ole2ansi.dll
+outline\ole2ui.dll
+outline\bttncur.dll
+outline\gizmobar.dll
+outline\outline.reg
diff --git a/private/oleutest/perform/common/benchmrk.hxx b/private/oleutest/perform/common/benchmrk.hxx
new file mode 100644
index 000000000..d9904f524
--- /dev/null
+++ b/private/oleutest/perform/common/benchmrk.hxx
@@ -0,0 +1,41 @@
+//+------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1993.
+//
+// File: benchmrk.hxx
+//
+// Contents: definitions for benchmark test
+//
+// Classes:
+//
+// Functions:
+//
+// History: 30-June-93 t-martig Created
+//
+//--------------------------------------------------------------------------
+
+
+#ifndef __BENCHMRK_H
+#define __BENCHMRK_H
+
+#include <windows.h>
+#include <ole2.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef _CAIRO_
+#include <oleext.h> // cairo extensions to OLE, OleInitializeEx, etc.
+#endif
+
+#ifdef WIN32 // BUGBUG: need replacement for WIN16
+#include <stopwtch.hxx>
+#endif
+
+#include <bmcomm.hxx>
+#include <bminput.hxx>
+#include <bmoutput.hxx>
+#include <bmlog.hxx>
+
+#endif // __BENCHMRK_H
diff --git a/private/oleutest/perform/common/bm_base.cxx b/private/oleutest/perform/common/bm_base.cxx
new file mode 100644
index 000000000..b7461b79b
--- /dev/null
+++ b/private/oleutest/perform/common/bm_base.cxx
@@ -0,0 +1,87 @@
+//+------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1993.
+//
+// File: bm_base.cxx
+//
+// Contents: output class for benchmark results
+//
+// Classes: CTestBase
+//
+// Functions:
+//
+// History: 30-June-93 t-martig Created
+//
+//--------------------------------------------------------------------------
+
+#include <benchmrk.hxx>
+#include <bm_base.hxx>
+
+
+SCODE CTestBase::Setup (CTestInput *pInput)
+{
+ m_pInput = pInput;
+
+ // get the OleInitialize flag.
+ m_dwInitFlag = m_pInput->GetOleInitFlag();
+
+ return S_OK;
+}
+
+
+SCODE CTestBase::Cleanup ()
+{
+ return S_OK;
+}
+
+
+SCODE CTestBase::InitOLE()
+{
+ SCODE sc;
+
+#ifdef OLE_THREADING_SUPPORT
+ if (m_dwInitFlag == COINIT_MULTITHREADED)
+ {
+ // we are Cairo and want MULTI_THREADING, call OleInitEx
+ sc = OleInitializeEx(NULL, m_dwInitFlag);
+ }
+ else
+#endif // OLE_THREADING_SUPPORT
+ {
+ sc = OleInitialize(NULL);
+ }
+
+ return sc;
+}
+
+void CTestBase::UninitOLE()
+{
+ OleUninitialize();
+}
+
+
+SCODE CTestBase::InitCOM()
+{
+ SCODE sc;
+
+#ifdef COM_THREADING_SUPPORT
+ if (m_dwInitFlag == COINIT_MULTITHREADED)
+ {
+ // we are Cairo and want MULTI_THREADING, call OleInitEx
+ sc = CoInitializeEx(NULL, m_dwInitFlag);
+ }
+ else
+#endif // COM_THREADING_SUPPORT
+ {
+ sc = CoInitialize(NULL);
+ }
+
+ return sc;
+}
+
+
+void CTestBase::UninitCOM()
+{
+ CoUninitialize();
+}
diff --git a/private/oleutest/perform/common/bm_base.hxx b/private/oleutest/perform/common/bm_base.hxx
new file mode 100644
index 000000000..2f4805068
--- /dev/null
+++ b/private/oleutest/perform/common/bm_base.hxx
@@ -0,0 +1,41 @@
+//+------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1993.
+//
+// File: bm_base.hxx
+//
+// Contents: base test class definition
+//
+// Classes: CTestBase
+//
+// Functions:
+//
+// History: 19-July-93 t-martig Created
+//
+//--------------------------------------------------------------------------
+#ifndef _BM_BASE_HXX_
+#define _BM_BASE_HXX_
+
+#include <bmoutput.hxx>
+
+class CTestBase
+{
+public:
+ virtual TCHAR *Name () = 0;
+ virtual SCODE Setup (CTestInput *input);
+ virtual SCODE Run () = 0;
+ virtual SCODE Report (CTestOutput &OutputFile) = 0;
+ virtual SCODE Cleanup ();
+ virtual SCODE InitOLE ();
+ virtual void UninitOLE ();
+ virtual SCODE InitCOM ();
+ virtual void UninitCOM ();
+
+protected:
+
+ CTestInput *m_pInput;
+ DWORD m_dwInitFlag; // OleInitializeEx init flag
+};
+
+#endif // _BM_BASE_HXX_
diff --git a/private/oleutest/perform/common/bm_parse.cxx b/private/oleutest/perform/common/bm_parse.cxx
new file mode 100644
index 000000000..8cf4e8cf4
--- /dev/null
+++ b/private/oleutest/perform/common/bm_parse.cxx
@@ -0,0 +1,347 @@
+//+------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1994.
+//
+// File: bm_parse.cxx
+//
+// Contents: Implementation of Base class for generic parsers
+//
+// Classes: CTimerBase
+//
+// Functions:
+//
+// History: 16-June-94 t-vadims Created
+//
+//
+//--------------------------------------------------------------------------
+
+#include <benchmrk.hxx>
+#include <bm_parse.hxx>
+
+#define MAX_INSTR_LENGTH 150
+
+#define BLANK_LINE (FIRST_INTERNALID + 2)
+
+//
+// Structure for linked list of instructions with their timings
+//
+struct SInstruction
+{
+ ULONG ulID;
+ ULONG ulTime[TEST_MAX_ITERATIONS];
+ SInstruction *pNext;
+};
+
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CTimerBase::Setup, public
+//
+// Synopsis: Makes all neccessary initializations.
+//
+// History: 16-June-94 t-vadims Created
+//
+//--------------------------------------------------------------------
+SCODE CTimerBase::Setup (CTestInput *pInput)
+{
+ SCODE sc;
+ char szFileName[80];
+ TCHAR szBuf[80];
+
+
+ CTestBase::Setup(pInput);
+
+ m_iIterations = pInput->GetIterations(Name());
+
+ // get name of the script file
+ pInput->GetConfigString(Name(), TEXT("ScriptName"), TEXT("script.txt"), szBuf, 80);
+
+#ifdef UNICODE
+ wcstombs(szFileName, szBuf, 80);
+#else
+ strcpy(szFileName, szBuf);
+#endif
+
+ m_fpIn = fopen(szFileName, "r");
+ if(m_fpIn == NULL)
+ {
+ Log(TEXT("Can't open script file"), STG_E_FILENOTFOUND);
+ return STG_E_FILENOTFOUND;
+ }
+
+
+ m_pParser = NULL;
+ sc = SetParserObject(); // virtual call to setup m_pParser object.
+
+ if(m_pParser == NULL)
+ sc = E_FAIL;
+
+ if(FAILED(sc))
+ {
+ Log(TEXT("Setup failed to initialize parser object"), sc);
+ fclose(m_fpIn);
+ return sc;
+ }
+
+#ifdef THREADING_SUPPORT
+ OleInitializeEx(NULL, pInput->GetOleInitFlag());
+#else
+ OleInitialize(NULL);
+#endif
+
+ sc = m_pParser->Setup(pInput);
+ if(FAILED(sc))
+ {
+ Log(TEXT("Setup of Parser object failed"), sc);
+ DeleteParserObject();
+ OleUninitialize();
+ fclose(m_fpIn);
+ return sc;
+ }
+
+ m_pHead = NULL;
+ m_iLine = 0;
+ return S_OK;
+}
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CTimerBase::Cleanup, public
+//
+// Synopsis: Clean everything up.
+//
+// History: 16-June-94 t-vadims Created
+//
+//--------------------------------------------------------------------
+SCODE CTimerBase::Cleanup ()
+{
+ SInstruction *pInstr, *pNextInstr;
+
+ pInstr = m_pHead;
+ while (pInstr != NULL)
+ {
+ pNextInstr = pInstr->pNext;
+ delete pInstr;
+ pInstr = pNextInstr;
+ }
+ m_pHead = NULL;
+
+ m_pParser->Cleanup();
+ DeleteParserObject();
+ fclose (m_fpIn);
+
+ OleUninitialize();
+
+ return S_OK;
+}
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CTimerBase::Run, public
+//
+// Synopsis: Read and execute the script file.
+//
+// History: 16-June-94 t-vadims Created
+//
+//--------------------------------------------------------------------
+
+SCODE CTimerBase::Run ()
+{
+ ReadFile ();
+ ExecuteFile ();
+ return S_OK;
+}
+
+
+
+BOOL CTimerBase::IsEmptyLine (LPTSTR pszLine)
+{
+ while (*pszLine)
+ {
+ if ( *pszLine != TEXT(' ') && *pszLine != TEXT('\n') &&
+ *pszLine != TEXT('\t'))
+ return FALSE;
+
+ pszLine++;
+ }
+
+ return TRUE;
+}
+
+
+
+BOOL CTimerBase::IsInternalID (ULONG ulID)
+{
+ return (ulID >= FIRST_INTERNALID);
+}
+
+//+-------------------------------------------------------------------
+//
+// Member: CTimerBase::ReadFile, private
+//
+// Synopsis: Reads script file, adding each instruction to the
+// link list.
+//
+// History: 16-June-94 t-vadims Created
+//
+//--------------------------------------------------------------------
+SCODE CTimerBase::ReadFile ()
+{
+ TCHAR szBuf[MAX_INSTR_LENGTH];
+ SInstruction *pTail = NULL;
+ ULONG ulID;
+
+
+ while ( SUCCEEDED(GetNextLine(szBuf))) // get line from file to szBuf
+ {
+ m_iLine ++;
+
+ if (IsEmptyLine(szBuf))
+ {
+ pTail = AddNewInstruction(pTail, BLANK_LINE);
+ }
+ else
+ {
+ ulID = m_pParser->ParseNewInstruction(szBuf);
+
+ if (ulID == INVALID_INSTRUCTION)
+ {
+ wsprintf(szBuf, TEXT("Invalid instruction on line %d"), m_iLine );
+ Log(szBuf, E_FAIL);
+ }
+ else if(ulID != NOT_INSTRUCTION) // valid instruction
+ {
+ pTail = AddNewInstruction(pTail, ulID);
+ }
+ }
+ }
+ return S_OK;
+}
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CTimerBase::AddNewInstruction, private
+//
+// Synopsis: Adds new instruction to linked list
+//
+// History: 16-June-94 t-vadims Created
+//
+//--------------------------------------------------------------------
+SInstruction *CTimerBase::AddNewInstruction(SInstruction *pTail, ULONG ulID)
+{
+ SInstruction *pInstruction = new SInstruction;
+
+ pInstruction->ulID = ulID;
+ pInstruction->pNext = NULL;
+ INIT_RESULTS(pInstruction->ulTime);
+
+ if (m_pHead == NULL) // first instruction
+ {
+ m_pHead = pTail = pInstruction;
+ }
+ else
+ {
+ pTail->pNext = pInstruction;
+ pTail = pInstruction;
+ }
+
+ return pTail;
+}
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CTimerBase::GetNextLine, private
+//
+// Synopsis: Reads the next line from the file.
+// Returns E_FAIL on end of file
+//
+// History: 16-June-94 t-vadims Created
+//
+//--------------------------------------------------------------------
+SCODE CTimerBase::GetNextLine(LPTSTR pszLine)
+{
+#ifdef UNICODE
+ CHAR szBuf[MAX_INSTR_LENGTH];
+
+ if (fgets(szBuf, MAX_INSTR_LENGTH, m_fpIn) != NULL)
+ {
+ mbstowcs(pszLine, szBuf, MAX_INSTR_LENGTH);
+ return S_OK;
+ }
+#else
+ if (fgets(pszLine, MAX_INSTR_LENGTH, m_fpIn) != NULL)
+ {
+ return S_OK;
+ }
+#endif
+ else
+ return E_FAIL;
+}
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CTimerBase::ExecuteFile, private
+//
+// Synopsis: Loops throug the linked list execute each command, and
+// recording timings.
+//
+// History: 16-June-94 t-vadims Created
+//
+//--------------------------------------------------------------------
+SCODE CTimerBase::ExecuteFile()
+{
+ ULONG iIter;
+ SInstruction *pInstr;
+
+ for (iIter = 0; iIter < m_iIterations; iIter++)
+ {
+ pInstr = m_pHead;
+ while (pInstr != NULL)
+ {
+ if (!IsInternalID(pInstr->ulID))
+ pInstr->ulTime[iIter] = m_pParser->ExecuteInstruction(pInstr->ulID);
+ pInstr = pInstr->pNext;
+ }
+ }
+
+ return S_OK;
+}
+
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CTimerBase::Report, public
+//
+// Synopsis: Loops throug the linked list, outputing timings of each command.
+//
+// History: 16-June-94 t-vadims Created
+//
+//--------------------------------------------------------------------
+SCODE CTimerBase::Report (CTestOutput &output)
+{
+ SInstruction *pInstr = m_pHead;
+
+ output.WriteSectionHeader (Name(), SectionHeader(), *m_pInput);
+ output.WriteString (TEXT("\n"));
+
+ while (pInstr != NULL)
+ {
+ if (pInstr->ulID == BLANK_LINE)
+ output.WriteString (TEXT("\n"));
+ else
+ output.WriteResults (m_pParser->InstructionName(pInstr->ulID),
+ m_iIterations, pInstr->ulTime);
+
+ pInstr = pInstr->pNext;
+ }
+
+ return S_OK;
+}
diff --git a/private/oleutest/perform/common/bm_parse.hxx b/private/oleutest/perform/common/bm_parse.hxx
new file mode 100644
index 000000000..aa45f2004
--- /dev/null
+++ b/private/oleutest/perform/common/bm_parse.hxx
@@ -0,0 +1,86 @@
+//+------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1994.
+//
+// File: bm_parse.hxx
+//
+// Contents: Base class for generic parsers
+//
+// Classes: CParserBase
+// CTimerBase
+//
+// Functions:
+//
+// History: 16-June-94 t-vadims Created
+//
+// Notes: To use, derive 2 new classes, one from each base, and
+// define all functions that are pure virtual in the base.
+//
+//--------------------------------------------------------------------------
+
+#ifndef _BM_PARSE_HXX_
+#define _BM_PARSE_HXX_
+
+#include <bm_base.hxx>
+
+#define FIRST_INTERNALID 0xffffff00
+#define INVALID_INSTRUCTION FIRST_INTERNALID
+#define NOT_INSTRUCTION (FIRST_INTERNALID + 1)
+
+
+class CParserBase
+{
+public:
+ virtual SCODE Setup (CTestInput *input) = 0;
+ virtual SCODE Cleanup () = 0;
+
+ virtual ULONG ParseNewInstruction(LPTSTR pszNewLine) = 0;
+ virtual ULONG ExecuteInstruction(ULONG ulInstrID) = 0;
+ virtual TCHAR* InstructionName(ULONG ulInstrID) = 0;
+};
+
+
+struct SInstruction; // forward declaration
+
+
+class CTimerBase : public CTestBase
+{
+
+public:
+ virtual SCODE SetParserObject () = 0;
+ virtual SCODE DeleteParserObject () = 0;
+
+ virtual TCHAR *Name () = 0;
+ virtual TCHAR* SectionHeader() = 0;
+
+
+ SCODE Setup (CTestInput *pInput);
+ SCODE Run ();
+ SCODE Report (CTestOutput &OutputFile);
+ SCODE Cleanup ();
+
+
+protected:
+
+ CParserBase *m_pParser;
+
+private:
+ SCODE ReadFile ();
+ SCODE ExecuteFile ();
+ SCODE GetNextLine (LPTSTR);
+
+ SInstruction* AddNewInstruction(SInstruction *pTail, ULONG ulID);
+
+ BOOL IsInternalID (ULONG ulID);
+ BOOL IsEmptyLine (LPTSTR);
+
+ ULONG m_iIterations; // number of iterations to be performed
+
+ ULONG m_iLine; // line count
+ FILE *m_fpIn; // Script file
+ SInstruction *m_pHead; // Linked list of instructions
+
+};
+
+#endif
diff --git a/private/oleutest/perform/common/bmcomm.cxx b/private/oleutest/perform/common/bmcomm.cxx
new file mode 100644
index 000000000..bdc0eaab4
--- /dev/null
+++ b/private/oleutest/perform/common/bmcomm.cxx
@@ -0,0 +1,47 @@
+//+------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1993.
+//
+// File: bmcomm.cxx
+//
+// Contents: definitions for benchmark test
+//
+// Classes:
+//
+// Functions:
+//
+// History: 30-June-93 t-martig Created
+//
+//--------------------------------------------------------------------------
+
+#include <benchmrk.hxx>
+
+// the external definitions for these are in bmcomm.hxx
+
+DWORD dwaClsCtx[] = {CLSCTX_INPROC_SERVER, CLSCTX_LOCAL_SERVER};
+
+LPTSTR apszClsCtx[] = {TEXT("InProc Server"), TEXT("Local Server")};
+LPTSTR apszClsIDName[] = {TEXT("ClsID_InProc"), TEXT("ClsID_Local")};
+LPOLESTR apszPerstName[] = {aszPerstName[0], aszPerstName[1]};
+LPOLESTR apszPerstNameNew[] = {aszPerstNameNew[0], aszPerstNameNew[1]};
+
+
+LPTSTR saModeNames[] = { TEXT("InProc"),
+ TEXT("Local"),
+ TEXT("Handler"),
+ NULL };
+
+DWORD dwaModes[] = { CLSCTX_INPROC_SERVER,
+ CLSCTX_LOCAL_SERVER,
+ CLSCTX_INPROC_HANDLER };
+
+
+OLECHAR aszPerstName[2][80]; // actual name for persistent instances
+OLECHAR aszPerstNameNew[2][80]; // actual name for persistent instances
+
+
+HRESULT OleInitializeEx(LPMALLOC pMalloc, DWORD dwIgnored)
+{
+ return OleInitialize(pMalloc);
+}
diff --git a/private/oleutest/perform/common/bmcomm.hxx b/private/oleutest/perform/common/bmcomm.hxx
new file mode 100644
index 000000000..6e9092171
--- /dev/null
+++ b/private/oleutest/perform/common/bmcomm.hxx
@@ -0,0 +1,49 @@
+//+------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1993.
+//
+// File: bmcomm.hxx
+//
+// Contents: definitions for benchmark test
+//
+// Classes:
+//
+// Functions:
+//
+// History: 30-June-93 t-martig Created
+//
+//--------------------------------------------------------------------------
+#ifndef __BMCOMM_HXX__
+#define __BMCOMM_HXX__
+
+#define NOTAVAIL 0xffffffff
+#define TEST_FAILED 0xfffffffe
+#define TEST_MAX_ITERATIONS 200
+
+#define INIT_RESULTS(array) \
+ { for (int xx=0; xx<TEST_MAX_ITERATIONS; xx++) { array[xx]=NOTAVAIL; }; }
+
+#define ZERO_RESULTS(array) \
+ { for (int xx=0; xx<TEST_MAX_ITERATIONS; xx++) { array[xx]=0; }; }
+
+
+// count of class contexts
+#define CNT_CLSCTX 2
+
+
+// static externals
+extern DWORD g_fFullInfo; // print full execution info
+extern DWORD dwaClsCtx[]; // class contexts
+extern LPTSTR apszClsCtx[]; // names of class contexts
+extern LPTSTR apszClsIDName[]; // .ini names for each class for each ctx
+extern LPOLESTR apszPerstName[]; // ptr to name for persistent instances
+extern LPOLESTR apszPerstNameNew[]; // ptr to name for persistent instances
+
+extern OLECHAR aszPerstName[2][80]; // actual name for persistent instances
+extern OLECHAR aszPerstNameNew[2][80]; // actual name for persistent instances
+
+extern DWORD dwaModes[];
+extern LPTSTR saModeNames[];
+
+#endif // __BMCOMM_HXX__
diff --git a/private/oleutest/perform/common/bmconfig.cxx b/private/oleutest/perform/common/bmconfig.cxx
new file mode 100644
index 000000000..36417ada6
--- /dev/null
+++ b/private/oleutest/perform/common/bmconfig.cxx
@@ -0,0 +1,96 @@
+//+------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1993.
+//
+// File: bmconfig.cxx
+//
+// Contents: configuration inquiry and reporting
+//
+// Classes:
+//
+// Functions: ReportBMConfig
+//
+// History: 2-July-93 t-martig Created
+//
+//--------------------------------------------------------------------------
+
+#include <benchmrk.hxx>
+#include <bmdriver.hxx>
+
+
+//+-------------------------------------------------------------------
+//
+// Function: ReportBMConfig
+//
+// Synopsis: Writes the current system / hardware configuration
+// to a specified output class
+//
+// Parameters: [lpswzConfigFile] Name and path of .ini file
+// [output] Output class
+//
+// History: 2-July-93 t-martig Created
+//
+//--------------------------------------------------------------------
+
+void ReportBMConfig (CTestInput &input, CTestOutput &output)
+{
+ TCHAR cname[MAX_COMPUTERNAME_LENGTH+1];
+ SYSTEM_INFO sinf;
+ TCHAR *temp;
+ DWORD dwSize = MAX_COMPUTERNAME_LENGTH+1;
+
+ GetComputerName (cname, &dwSize);
+ output.WriteTextString (cname);
+
+ output.WriteString (TEXT("\t"));
+ output.WriteConfigEntry (input, TEXT("Config"), TEXT("Mfg"), TEXT("n/a"));
+
+ GetSystemInfo (&sinf);
+
+ switch (sinf.dwProcessorType)
+ {
+ case 386:
+ temp = TEXT("i386");
+ break;
+ case 486:
+ temp = TEXT("i486");
+ break;
+ case 860:
+ temp = TEXT("i860");
+ break;
+ case 2000:
+ temp = TEXT("R2000");
+ break;
+ case 3000:
+ temp = TEXT("R3000");
+ break;
+ case 4000:
+ temp = TEXT("R4000");
+ break;
+ default:
+ temp = TEXT("Unknown");
+
+ break;
+ }
+ output.WriteString (TEXT("\t"));
+ output.WriteConfigEntry (input, TEXT("Config"), TEXT("CPU"), temp);
+ output.WriteString (TEXT("\t"));
+ output.WriteConfigEntry (input, TEXT("Config"), TEXT("RAM"), TEXT("n/a"));
+ output.WriteString (TEXT("\t"));
+ output.WriteConfigEntry (input, TEXT("Config"), TEXT("OS"), TEXT("Cairo"));
+ output.WriteString (TEXT("\t"));
+ output.WriteConfigEntry (input, TEXT("Driver"), TEXT("InitFlag"), TEXT("COINIT_MULTITHREADED"));
+
+ output.WriteString (TEXT("\n\t\t\t\t"));
+
+ output.WriteString (TEXT("All times in microseconds\n"));
+
+// NtQuerySystemInformation
+}
+
+
+
+
+
+
diff --git a/private/oleutest/perform/common/bmdriver.hxx b/private/oleutest/perform/common/bmdriver.hxx
new file mode 100644
index 000000000..a159850e0
--- /dev/null
+++ b/private/oleutest/perform/common/bmdriver.hxx
@@ -0,0 +1,37 @@
+//+------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1993.
+//
+// File: bmdriver.hxx
+//
+// Contents: benchmark driver class definition
+//
+// Classes: CBenchMarkDriver
+//
+// Functions:
+//
+// History: 19-July-93 t-martig Created
+//
+//--------------------------------------------------------------------------
+
+#ifndef _BM_BMDRIVER_HXX_
+#define _BM_BMDRIVER_HXX_
+
+#include <benchmrk.hxx>
+#include <bm_base.hxx>
+
+
+class CBenchMarkDriver
+{
+public:
+ SCODE RunTest (CTestInput &input, CTestOutput &output,
+ CTestBase *pTest);
+ SCODE Run (LPSTR lpCmdLine);
+ void WriteHeader (CTestInput &input, CTestOutput &output);
+};
+
+
+void ReportBMConfig (CTestInput &input, CTestOutput &output);
+
+#endif // _BM_BMDRIVER_HXX_
diff --git a/private/oleutest/perform/common/bminput.cxx b/private/oleutest/perform/common/bminput.cxx
new file mode 100644
index 000000000..1998fa7d3
--- /dev/null
+++ b/private/oleutest/perform/common/bminput.cxx
@@ -0,0 +1,267 @@
+//+------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1993.
+//
+// File: bminput.cxx
+//
+// Contents: input class for benchmark config
+//
+// Classes: CTestinput
+//
+// Functions:
+//
+// History: 14-July-93 t-martig Created
+// 07-July-94 t-vadims Added GetConfigInt and changed
+// GetIterations to use it.
+//
+//--------------------------------------------------------------------------
+#include <benchmrk.hxx>
+#include <bminput.hxx>
+
+//+-------------------------------------------------------------------
+//
+// Member: CTestInput,public
+//
+// Synopsis: constructor for test input class
+//
+//+-------------------------------------------------------------------
+CTestInput::CTestInput (LPTSTR lpszFileName)
+{
+ lstrcpy (m_szFileName, lpszFileName);
+}
+
+
+//+-------------------------------------------------------------------
+//
+// Member: GetConfigString,public
+//
+// Synopsis: returns profile string from specified section and
+// parameter.
+//
+//+-------------------------------------------------------------------
+LPTSTR CTestInput::GetConfigString (LPTSTR lpszSection, LPTSTR lpszEntry,
+ LPTSTR lpszDefault, LPTSTR lpszDest,
+ DWORD dwLen)
+{
+ GetPrivateProfileString (lpszSection, lpszEntry, lpszDefault,
+ lpszDest, dwLen, m_szFileName);
+ return lpszDest;
+}
+
+//+-------------------------------------------------------------------
+//
+// Member: GetConfigInt,public
+//
+// Synopsis: returns profile integer from specified section and
+// parameter.
+//
+//+-------------------------------------------------------------------
+DWORD CTestInput::GetConfigInt (LPTSTR lpszSection, LPTSTR lpszEntry,
+ DWORD dwDefault)
+{
+ return GetPrivateProfileInt (lpszSection, lpszEntry,
+ dwDefault, m_szFileName);
+}
+
+//+-------------------------------------------------------------------
+//
+// Member: GetClassCtx,public
+//
+// Synopsis: Gets the custom class activation context from .ini
+// file (entry name = "ClsCtx")
+//
+// Parameters: [lpszTestName] Section under which "ClsCtx"
+// is listed
+//
+// Returns: CLSCTX_... mode according to entry:
+//
+// "InProc" CLSCTX_INPROC_SERVER
+// "Local" CLSCTX_LOCAL_SERVER,
+// "Handler" CLSCTX_INPROC_HANDLER
+// any other CLSCTX_INPROC_SERVER
+//
+// History: 12-July-93 t-martig Created
+//
+//--------------------------------------------------------------------
+DWORD CTestInput::GetClassCtx (LPTSTR lpszTestName)
+{
+ TCHAR szMode[50];
+ int i;
+
+ GetConfigString (lpszTestName, TEXT("ClsCtx"), TEXT("InProc"),
+ szMode, sizeof(szMode)/sizeof(TCHAR));
+
+ i = 0;
+ while (saModeNames[i])
+ {
+ if (lstrcmpi (saModeNames[i], szMode) == 0)
+ return dwaModes[i];
+ i++;
+ }
+
+ return dwaModes[0];
+}
+
+
+//+-------------------------------------------------------------------
+//
+// Member: GetOleInitFlag,public
+//
+// Synopsis: Gets OleInitialize flag
+//
+// Parameters:
+//
+// History: 13-August-93 t-martig Created
+//
+//--------------------------------------------------------------------
+DWORD CTestInput::GetOleInitFlag(void)
+{
+ TCHAR szInitFlag[60];
+
+ GetPrivateProfileString (TEXT("Driver"), TEXT("InitFlag"),
+ TEXT("COINIT_APARTMENTTHREADED"),
+ szInitFlag, sizeof(szInitFlag)/sizeof(TCHAR),
+ m_szFileName);
+
+#ifdef THREADING_SUPPORT
+ if (lstrlen(szInitFlag)==0)
+ return COINIT_APARTMENTTHREADED;
+
+ if (!lstrcmpi(szInitFlag, TEXT("COINIT_MULTITHREADED")))
+ return COINIT_MULTITHREADED;
+ else
+#endif
+ return 2; // COINIT_APARTMENTTHREADED;
+}
+
+
+//+-------------------------------------------------------------------
+//
+// Member: GetInfoLevelFlag,public
+//
+// Synopsis: Gets InfoLevel flag
+//
+// Parameters:
+//
+// History: 13-August-93 t-martig Created
+//
+//--------------------------------------------------------------------
+DWORD CTestInput::GetInfoLevelFlag(void)
+{
+ TCHAR szInfoFlag[60];
+
+ GetPrivateProfileString (TEXT("Driver"), TEXT("InfoLevel"),
+ TEXT("BASE"),
+ szInfoFlag, sizeof(szInfoFlag)/sizeof(TCHAR),
+ m_szFileName);
+
+ if (lstrlen(szInfoFlag)==0)
+ return 0;
+
+ if (!lstrcmpi(szInfoFlag, TEXT("FULL")))
+ return 1;
+ else
+ return 0;
+}
+
+
+//+-------------------------------------------------------------------
+//
+// Member: GetGUID,public
+//
+// Synopsis: Gets GUID from .ini file
+//
+// Parameters: [pClsID] Address where to put class ID
+// [lpszTestName] Section
+// [lpszEntry] Entry name
+//
+// History: 13-August-93 t-martig Created
+//
+//--------------------------------------------------------------------
+SCODE CTestInput::GetGUID (CLSID *pClsID, LPTSTR lpszTestName,
+ LPTSTR lpszEntry)
+{
+ TCHAR szClsID[60];
+ LPOLESTR lpszClsID;
+
+ GetConfigString (lpszTestName, lpszEntry, TEXT(""),
+ szClsID, sizeof(szClsID)/sizeof(TCHAR));
+
+ if (lstrlen(szClsID)==0)
+ return E_FAIL;
+#ifdef UNICODE
+ lpszClsID = szClsID;
+#else
+ OLECHAR szTmp[60];
+ MultiByteToWideChar(CP_ACP, 0, szClsID, -1, szTmp, 60);
+ lpszClsID = szTmp;
+#endif
+
+ return CLSIDFromString(lpszClsID, pClsID);
+}
+
+
+
+//+-------------------------------------------------------------------
+//
+// Member: GetClassID,public
+//
+// Synopsis: Gets the custom class ID from .ini file
+// (entry name = "ClsID")
+//
+// Parameters: [pClsID] Address where to put class ID
+// [lpszTestName] Section under which "ClsID"
+// is listed
+//
+// History: 13-July-93 t-martig Created
+//
+//--------------------------------------------------------------------
+SCODE CTestInput::GetClassID (CLSID *pClsID, LPTSTR lpszTestName)
+{
+ return GetGUID(pClsID, lpszTestName, TEXT("ClsID"));
+}
+
+
+
+//+-------------------------------------------------------------------
+//
+// Member: GetIterations, public
+//
+// Synopsis: returns the iteration count for the test. if out of
+// range, it returns either 1 or TEST_MAX_ITERATIONS.
+//
+// History: 07-July-94 t-vadims Modified to use new GetConfigInt function.
+//
+//+-------------------------------------------------------------------
+DWORD CTestInput::GetIterations (LPTSTR lpszTestName, int iIterDefault)
+{
+ int iIterations;
+
+ iIterations = GetConfigInt (lpszTestName, TEXT("Iterations"), iIterDefault);
+
+ if (iIterations > TEST_MAX_ITERATIONS)
+ iIterations = TEST_MAX_ITERATIONS;
+
+ return (iIterations > 0) ? iIterations : 1;
+}
+
+
+//+-------------------------------------------------------------------
+//
+// Member: GetRealIterations, public
+//
+// Synopsis: returns the iteration count for the test. Does not
+// range check.
+//
+// History: 07-July-94 t-vadims Modified to use new GetConfigInt function.
+//
+//+-------------------------------------------------------------------
+DWORD CTestInput::GetRealIterations (LPTSTR lpszTestName, int iIterDefault)
+{
+ int iIterations;
+
+ iIterations = GetConfigInt (lpszTestName, TEXT("Iterations"), iIterDefault);
+
+ return (iIterations > 0) ? iIterations : 1;
+}
diff --git a/private/oleutest/perform/common/bminput.hxx b/private/oleutest/perform/common/bminput.hxx
new file mode 100644
index 000000000..ff8a155e5
--- /dev/null
+++ b/private/oleutest/perform/common/bminput.hxx
@@ -0,0 +1,56 @@
+//+------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1993.
+//
+// File: bminput.hxx
+//
+// Contents: input class definition
+//
+// Classes: CTestInput
+//
+// Functions:
+//
+// History: 19-July-93 t-martig Created
+// 07-July-93 t-vadims Added GetConfigInt
+//
+//--------------------------------------------------------------------------
+
+#ifndef _BMINPUT_HXX_
+#define _BMINPUT_HXX_
+
+class CTestInput
+{
+public:
+ CTestInput (LPTSTR lpszFileName);
+
+ LPTSTR GetConfigString(LPTSTR lpszSection,
+ LPTSTR lpszEntry,
+ LPTSTR lpszDefault,
+ LPTSTR lpszDest,
+ DWORD dwLen);
+
+ DWORD GetConfigInt(LPTSTR lpszSection,
+ LPTSTR lpszEntry,
+ DWORD dwDefault);
+
+
+ DWORD GetClassCtx (LPTSTR lpszTestName);
+ DWORD GetOleInitFlag (void);
+ DWORD GetInfoLevelFlag (void);
+
+ SCODE GetGUID (GUID *pClsID,
+ LPTSTR lpszTestName,
+ LPTSTR lpszEntryName);
+
+ SCODE GetClassID (GUID *pClsID, LPTSTR lpszTestName);
+
+ DWORD GetIterations (LPTSTR lpszTestName, int iIterDefault = 1);
+ DWORD GetRealIterations (LPTSTR lpszTestName, int iIterDefault = 1);
+
+private:
+ TCHAR m_szFileName[80];
+};
+
+
+#endif // _BMINPUT_HXX_
diff --git a/private/oleutest/perform/common/bmlog.cxx b/private/oleutest/perform/common/bmlog.cxx
new file mode 100644
index 000000000..4ca728eb7
--- /dev/null
+++ b/private/oleutest/perform/common/bmlog.cxx
@@ -0,0 +1,105 @@
+//+------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1993.
+//
+// File: bmlog.cxx
+//
+// Contents: Benchmark test error logging
+//
+// Classes:
+//
+// Functions:
+//
+// History: 29-July-93 t-martig Created
+//
+//--------------------------------------------------------------------------
+
+#include <benchmrk.hxx>
+#include <bmoutput.hxx>
+#include <bmlog.hxx>
+
+CTestOutput *logOutput;
+
+
+//+------------------------------------------------------------------------
+//
+// funtion: LogTo
+//
+// purpose: writes the benchmark header to the logfile
+//
+//+------------------------------------------------------------------------
+
+void LogTo (CTestOutput *_logOutput)
+{
+ logOutput = _logOutput;
+ _SYSTEMTIME stTimeDate;
+
+ logOutput->WriteString (TEXT("CairOLE Benchmark Log File\t"));
+ GetLocalTime (&stTimeDate);
+ logOutput->WriteDate (&stTimeDate);
+ logOutput->WriteString (TEXT("\t"));
+ logOutput->WriteTime (&stTimeDate);
+ logOutput->WriteString (TEXT("\n\n"));
+}
+
+
+//+------------------------------------------------------------------------
+//
+// funtion: LogSection
+//
+// purpose: writes the section header to the logfile
+//
+//+------------------------------------------------------------------------
+
+void LogSection (LPTSTR lpszName)
+{
+ if (!logOutput)
+ return;
+
+ logOutput->WriteString (lpszName);
+ logOutput->WriteString (TEXT("\n"));
+}
+
+
+//+------------------------------------------------------------------------
+//
+// funtion: Log
+//
+// purpose: records the result of one action taken by the benchmark test
+//
+//+------------------------------------------------------------------------
+
+int Log (LPTSTR lpszActionName, SCODE hr)
+{
+ if (!logOutput)
+ return !SUCCEEDED(hr);
+
+ logOutput->WriteString (TEXT(" "));
+ logOutput->WriteString (lpszActionName);
+
+ if (SUCCEEDED(hr))
+ {
+ logOutput->WriteString (TEXT("\tOK\n"));
+ return FALSE;
+ }
+ else
+ {
+ logOutput->WriteString (TEXT("\tERROR: "));
+ logOutput->WriteSCODE (hr);
+ logOutput->WriteString (TEXT("\n"));
+ return TRUE;
+ }
+}
+
+
+int Log (LPTSTR lpszActionName, ULONG ulCode)
+{
+ if (!logOutput)
+ return FALSE;
+
+ logOutput->WriteString (TEXT(" "));
+ logOutput->WriteString (lpszActionName);
+ logOutput->WriteLong(ulCode);
+ return TRUE;
+}
diff --git a/private/oleutest/perform/common/bmlog.hxx b/private/oleutest/perform/common/bmlog.hxx
new file mode 100644
index 000000000..7d319f4cf
--- /dev/null
+++ b/private/oleutest/perform/common/bmlog.hxx
@@ -0,0 +1,28 @@
+//+------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1993.
+//
+// File: bmlog.hxx
+//
+// Contents: Benchmark test error logging
+//
+// Classes:
+//
+// Functions:
+//
+// History: 29-July-93 t-martig Created
+//
+//--------------------------------------------------------------------------
+
+#ifndef _BMLOG_HXX_
+#define _BMLOG_HXX_
+
+#include <bmoutput.hxx>
+
+void LogTo (CTestOutput *_logOutput);
+void LogSection (LPTSTR lpszName);
+int Log (LPTSTR lpszActionName, SCODE hr);
+int Log (LPTSTR lpszActionName, ULONG ulCode);
+
+#endif
diff --git a/private/oleutest/perform/common/bmoutput.cxx b/private/oleutest/perform/common/bmoutput.cxx
new file mode 100644
index 000000000..61afc61c5
--- /dev/null
+++ b/private/oleutest/perform/common/bmoutput.cxx
@@ -0,0 +1,474 @@
+//+------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1993.
+//
+// File: bmoutput.cxx
+//
+// Contents: output class for benchmark results
+//
+// Classes: CTestOutput
+//
+// Functions:
+//
+// History: 30-June-93 t-martig Created
+// 15-Aug-94 davidfie Make ASCII/Unicode for chicago
+//
+//--------------------------------------------------------------------------
+
+#include <benchmrk.hxx>
+#include <bmoutput.hxx>
+
+//+-------------------------------------------------------------------
+//
+// Member: CTestOutput::CTestOutput, public
+//
+// Synopsis: Generates output file
+//
+// History: 30-June-93 t-martig Created
+//
+//--------------------------------------------------------------------
+
+CTestOutput::CTestOutput (LPTSTR lpszFileName)
+{
+#ifdef UNICODE
+ char szFileName[80];
+
+ wcstombs (szFileName, lpszFileName, wcslen(lpszFileName)+1);
+ fpOut = fopen (szFileName, "wt");
+#else
+ fpOut = fopen (lpszFileName, "wt");
+#endif
+}
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CTestOutput::~CTestOutput, public
+//
+// Synopsis: Closes output file
+//
+// History: 30-June-93 t-martig Created
+//
+//--------------------------------------------------------------------
+
+
+CTestOutput::~CTestOutput ()
+{
+ if (fpOut)
+ fclose (fpOut);
+}
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CTestOutput::Flush, public
+//
+// Synopsis: flushes the buffers associated with the output file
+//
+// History: 30-June-93 t-martig Created
+//
+//--------------------------------------------------------------------
+
+void CTestOutput::Flush(void)
+{
+ fflush (fpOut);
+}
+
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CTestOutput::WriteTextString, public
+//
+// Synopsis: Writes a TEXT format string to output file
+//
+// Parameters: [lpswzString] String to be printed
+//
+// History: 30-June-93 t-martig Created
+//
+//--------------------------------------------------------------------
+
+void CTestOutput::WriteTextString (LPTSTR lpszString)
+{
+ WriteString(lpszString);
+}
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CTestOutput::WriteString, public
+//
+// Synopsis: Writes string to output file
+//
+// Parameters: [lpszString] String to be printed
+//
+// History: 30-June-93 t-martig Created
+//
+//--------------------------------------------------------------------
+
+void CTestOutput::WriteString (LPTSTR lpszString)
+{
+#ifdef UNICODE
+ char *fmt = "%ws";
+#else
+ char *fmt = "%s";
+#endif
+
+ if (!fpOut)
+ return;
+ fprintf (fpOut, fmt, lpszString);
+}
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CTestOutput::WriteLong, public
+//
+// Synopsis: Writes long to output file
+//
+// Parameters: [lpswzString] String to be printed
+//
+// History: 30-June-93 t-martig Created
+//
+//--------------------------------------------------------------------
+
+void CTestOutput::WriteLong (ULONG l)
+{
+ if (!fpOut)
+ return;
+ fprintf (fpOut, "%lu", l);
+}
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CTestOutput::WriteConfigEntry, public
+//
+// Synopsis: Writes string from config file to output file
+//
+// Parameters: [input] Input class (config file)
+// [lpszSection] Section name of entry to be printed
+// [lpszEntry] Entry name to be printed
+// [lpszDefault] Default string in case entry does
+// not exist
+//
+// History: 30-June-93 t-martig Created
+//
+//--------------------------------------------------------------------
+
+void CTestOutput::WriteConfigEntry (CTestInput &input, LPTSTR lpszSection,
+ LPTSTR lpszEntry, LPTSTR lpszDefault)
+{
+ TCHAR destName[160];
+
+ if (!fpOut)
+ return;
+
+ input.GetConfigString (lpszSection, lpszEntry, lpszDefault,
+ destName, sizeof(destName)/sizeof(TCHAR));
+
+ WriteString (destName);
+}
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CTestOutput::WriteSectionHeader, public
+//
+// Synopsis: Writes general test section header to output file
+//
+// Parameters: [lpszTestName] General test name (from
+// [TestClass].Name(),like "OLE")
+// [lpszSectionName] Specific test name (like
+// "Object Bind Test")
+// [input] .ini file class
+//
+// History: 30-June-93 t-martig Created
+//
+//--------------------------------------------------------------------
+
+void CTestOutput::WriteSectionHeader (LPTSTR lpszTestName,
+ LPTSTR lpszSectionName, CTestInput &input)
+{
+ if (!fpOut)
+ return;
+
+ if (!lpszSectionName)
+ lpszSectionName = TEXT("");
+
+
+ if (g_fFullInfo)
+ {
+#ifdef UNICODE
+ char *fmt = "\n\n%ws - %ws\n\nComments:\t";
+#else
+ char *fmt = "\n\n%s - %s\n\nComments:\t";
+#endif
+ // we conditionally skip writing the comment to make it
+ // easier to format for excel.
+ fprintf (fpOut, fmt, lpszTestName, lpszSectionName);
+
+ WriteConfigEntry (input, lpszTestName, TEXT("comment"));
+ fprintf (fpOut, "\n");
+ }
+ else
+ {
+#ifdef UNICODE
+ char *fmt = "\n\n%ws\n";
+#else
+ char *fmt = "\n\n%s\n";
+#endif
+ fprintf (fpOut, fmt, lpszSectionName);
+ }
+}
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CTestOutput::WriteResult, public
+//
+// Synopsis: Writes test result line to output file, in the form
+// "Create moniker <tab> 30800"
+//
+// Parameters: [lpszMeasurementName] Name of result (like
+// "Create moniker"
+// [ulTime] Measured time in microseconds
+//
+// History: 30-June-93 t-martig Created
+//
+//--------------------------------------------------------------------
+
+void CTestOutput::WriteResult (LPTSTR lpszMeasurementName, ULONG ulTime)
+{
+ if (fpOut)
+ {
+ WriteString (lpszMeasurementName);
+ fprintf (fpOut, "\t");
+
+ if (ulTime == NOTAVAIL)
+ {
+ fprintf (fpOut, "n/a\n");
+ }
+ else if (ulTime == TEST_FAILED)
+ {
+ fprintf (fpOut, "F\n");
+ }
+ else
+ {
+ fprintf (fpOut, "%lu\n", ulTime);
+ }
+ }
+}
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CTestOutput::WriteResult, public
+//
+// Synopsis: Writes test results over several columns
+//
+// Parameters: [lpszMeasurementName] Name of result (like
+// "Create moniker"
+// [iIterations] Number of results
+// [paUlTime] Array with measurement times
+//
+// History: 30-June-93 t-martig Created
+//
+//--------------------------------------------------------------------
+
+void CTestOutput::WriteResults (LPTSTR lpszMeasurementName, int iIterations,
+ ULONG *paUlTimes)
+{
+ int i;
+
+ if (fpOut)
+ {
+ WriteString (lpszMeasurementName);
+
+ for (i=0; i<iIterations; i++)
+ {
+ if (paUlTimes[i] == NOTAVAIL)
+ {
+ fprintf (fpOut, "\tn/a");
+ }
+ else if (paUlTimes[i] == TEST_FAILED)
+ {
+ fprintf (fpOut, "\tF");
+ }
+ else
+ {
+ fprintf (fpOut, "\t%lu", paUlTimes[i]);
+ }
+ }
+
+ fprintf (fpOut, "\n");
+ }
+}
+
+
+//+-------------------------------------------------------------------
+//
+// Member: WriteClassCtx, public
+//
+// Synopsis: Prints the class activation conL as string to
+// a specified output class
+//
+// Parameters: [dwClsCtx] Class conL to be printed
+//
+// CLSCTX_INPROC_SERVER --> "InProc"
+// CLSCTX_LOCAL_SERVER --> "LocaL"
+// CLSCTX_INPROC_HANDLER --> "Handler"
+// any other --> "Unknown"
+//
+// History: 12-July-93 t-martig Created
+//
+//--------------------------------------------------------------------
+
+void CTestOutput::WriteClassCtx (DWORD dwClsCtx)
+{
+ LPTSTR pc = TEXT("Unknown");
+ int i = 0;
+
+ while (saModeNames[i])
+ {
+ if (dwaModes[i] == dwClsCtx)
+ {
+ pc = saModeNames[i];
+ break;
+ }
+ i++;
+ }
+
+ WriteString (TEXT("ClsCtx\t"));
+ WriteString (pc);
+ WriteString (TEXT("\n"));
+}
+
+
+//+-------------------------------------------------------------------
+//
+// Member: WriteClassID
+//
+// Synopsis: Prints the class ID as string to
+// a specified output class
+//
+// Parameters: [pClsID] Class ID to be printed
+//
+// History: 13-July-93 t-martig Created
+//
+//--------------------------------------------------------------------
+
+void CTestOutput::WriteClassID (CLSID *pClsID)
+{
+ if (g_fFullInfo)
+ {
+ TCHAR szGUID[50];
+
+ WriteString (TEXT("ClsID\t"));
+ StringFromGUID(*pClsID, szGUID);
+ WriteString (szGUID);
+ WriteString (TEXT("\n"));
+ }
+}
+
+
+//+-------------------------------------------------------------------
+//
+// Member: WriteTime
+//
+// Synopsis: Prints time to a specified output class
+//
+// Parameters: [pstTime] System time
+//
+// History: 5-August-93 t-martig Created
+//
+//--------------------------------------------------------------------
+
+void CTestOutput::WriteTime (_SYSTEMTIME *pstTime)
+{
+ WORD wHour;
+ char cAmpm;
+
+ if (fpOut)
+ {
+ cAmpm = 'a';
+ wHour = pstTime->wHour;
+
+ if (wHour >= 12)
+ {
+ cAmpm = 'p';
+ if (wHour > 12)
+ wHour-=12;
+ }
+ if (wHour==0)
+ wHour=12;
+
+ fprintf (fpOut, "%d:%02d%c", wHour, pstTime->wMinute, cAmpm);
+ }
+}
+
+
+//+-------------------------------------------------------------------
+//
+// Member: WriteDate
+//
+// Synopsis: Prints date to a specified output class
+//
+// Parameters: [pstdate] System date
+//
+// History: 5-August-93 t-martig Created
+//
+//--------------------------------------------------------------------
+
+void CTestOutput::WriteDate (_SYSTEMTIME *pstDate)
+{
+ if (fpOut)
+ {
+ fprintf (fpOut, "%02d-%02d-%02d",
+ pstDate->wMonth, pstDate->wDay, pstDate->wYear % 100);
+ }
+}
+
+
+//+-------------------------------------------------------------------
+//
+// Member: WriteSCODE
+//
+// Synopsis: Prints an SCODE to a specified output class
+//
+// Parameters: [sc] SCODE
+//
+// History: 5-August-93 t-martig Created
+//
+//--------------------------------------------------------------------
+
+void CTestOutput::WriteSCODE (SCODE sc)
+{
+ if (fpOut)
+ fprintf (fpOut, "%xh/%xh", SCODE_FACILITY(sc), SCODE_CODE(sc));
+}
+
+
+//+-------------------------------------------------------------------
+//
+// Member: StringFromGUID
+//
+// Synopsis: converts a GUID into a string so that it may be
+// printed to a specified output class
+//
+// Parameters: [pClsID] Class ID to be printed
+//
+// History: 13-July-93 t-martig Created
+//
+//--------------------------------------------------------------------
+
+void CTestOutput::StringFromGUID(GUID &rguid, LPTSTR lpsz)
+{
+ wsprintf(lpsz, TEXT("{%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}"),
+ rguid.Data1, rguid.Data2, rguid.Data3,
+ rguid.Data4[0], rguid.Data4[1],
+ rguid.Data4[2], rguid.Data4[3],
+ rguid.Data4[4], rguid.Data4[5],
+ rguid.Data4[6], rguid.Data4[7]);
+}
diff --git a/private/oleutest/perform/common/bmoutput.hxx b/private/oleutest/perform/common/bmoutput.hxx
new file mode 100644
index 000000000..6860b59a4
--- /dev/null
+++ b/private/oleutest/perform/common/bmoutput.hxx
@@ -0,0 +1,53 @@
+//+------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1993.
+//
+// File: bmoutput.hxx
+//
+// Contents: output class definition
+//
+// Classes: CTestOutput
+//
+// Functions:
+//
+// History: 19-July-93 t-martig Created
+//
+//--------------------------------------------------------------------------
+
+#ifndef _BMOUTPUT_HXX_
+#define _BMOUTPUT_HXX_
+
+#include <bminput.hxx>
+
+class CTestOutput
+{
+public:
+ CTestOutput (LPTSTR lpszFileName);
+ ~CTestOutput ();
+
+ void Flush(void);
+ void WriteSectionHeader (LPTSTR lpszTestName,
+ LPTSTR lpszSectionName,
+ CTestInput &input);
+ void WriteTextString (LPTSTR lpszString);
+ void WriteString (LPTSTR lpwszString);
+ void WriteLong (ULONG ul);
+ void WriteConfigEntry (CTestInput &input, LPTSTR lpszSection,
+ LPTSTR lpszEntry, LPTSTR lpszDefault = TEXT(""));
+ void WriteResult (LPTSTR lpszMeasurementName, ULONG ulTime);
+ void WriteResults (LPTSTR lpszMeasurementName, int iIterations,
+ ULONG *paUltimes);
+ void WriteClassCtx (DWORD dwClsCtx);
+ void WriteClassID (GUID *pClsId);
+ void WriteTime (SYSTEMTIME *pstTime);
+ void WriteDate (SYSTEMTIME *pstDate);
+ void WriteSCODE (SCODE sc);
+
+private:
+ void StringFromGUID(GUID &rguid, LPTSTR lpsz);
+
+ FILE *fpOut;
+};
+
+#endif // _BMOUTPUT_HXX_
diff --git a/private/oleutest/perform/common/bmrpc.cxx b/private/oleutest/perform/common/bmrpc.cxx
new file mode 100644
index 000000000..9e413cb44
--- /dev/null
+++ b/private/oleutest/perform/common/bmrpc.cxx
@@ -0,0 +1,74 @@
+//+------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1993.
+//
+// File: bmrpc.cxx
+//
+// Contents: common Raw Rpc code
+//
+// Classes: None
+//
+// Functions:
+//
+// History: 02-Feb-94 Rickhi Created
+//
+//--------------------------------------------------------------------------
+
+#include <benchmrk.hxx>
+#include <rawrpc.h>
+
+extern "C" const GUID IID_IRawRpc =
+ {0x00000145,0x0001,0x0008,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}};
+
+
+
+extern "C" void _gns__GUID (GUID* _target, PRPC_MESSAGE _prpcmsg);
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: MIDL_user_allocate
+//
+// Synopsis: Allocate memory via OLE task allocator.
+//
+//--------------------------------------------------------------------------
+void *__stdcall MIDL_user_allocate(size_t size)
+{
+ void *pMemory = (void *) new BYTE[size];
+
+ if(pMemory == 0)
+ RaiseException((unsigned long)E_OUTOFMEMORY, 0, 0, 0);
+
+ return pMemory;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: MIDL_user_free
+//
+// Synopsis: Free memory using OLE task allocator.
+//
+//--------------------------------------------------------------------------
+void __stdcall MIDL_user_free(void *pMemory)
+{
+ delete pMemory;
+}
+
+
+
+/* routine that gets node for struct _GUID */
+void _gns__GUID (GUID * _target, PRPC_MESSAGE _prpcmsg)
+{
+ unsigned long _alloc_total;
+ ((void)( _alloc_total ));
+ *(unsigned long *)&_prpcmsg->Buffer += 3;
+ *(unsigned long *)&_prpcmsg->Buffer &= 0xfffffffc;
+ /* receive data into &_target->Data1 */
+ long_from_ndr((PRPC_MESSAGE)_prpcmsg, (unsigned long *)&_target->Data1);
+ /* receive data into &_target->Data2 */
+ short_from_ndr((PRPC_MESSAGE)_prpcmsg, (unsigned short *)&_target->Data2);
+ /* receive data into &_target->Data3 */
+ short_from_ndr((PRPC_MESSAGE)_prpcmsg, (unsigned short *)&_target->Data3);
+ char_array_from_ndr ((PRPC_MESSAGE)_prpcmsg, 0, 0 + 8, (unsigned char *)_target->Data4);
+}
diff --git a/private/oleutest/perform/common/cqisrv.cxx b/private/oleutest/perform/common/cqisrv.cxx
new file mode 100644
index 000000000..9df07c5c0
--- /dev/null
+++ b/private/oleutest/perform/common/cqisrv.cxx
@@ -0,0 +1,114 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1992.
+//
+// File: cqi.cxx
+//
+// Contents: implementations for QueryInterface test
+//
+// Functions:
+// CQI::CQI
+// CQI::~CQI
+// CQI::QueryInterface
+//
+// History: 06-Aug-92 Rickhi Created
+//
+//--------------------------------------------------------------------------
+#include <headers.cxx>
+#pragma hdrstop
+#include <cqisrv.hxx> // class definition
+
+//+-------------------------------------------------------------------------
+//
+// Method: CQI::CQI
+//
+// Synopsis: Creates an instance of CQI
+//
+// History: 06-Aug-92 Rickhi Created
+//
+//--------------------------------------------------------------------------
+CQI::CQI(void) : _cRefs(1)
+{
+}
+
+CQI::~CQI(void)
+{
+ // automatic actions are enough
+}
+
+//+-------------------------------------------------------------------------
+//
+// Method: CQI::AddRef/Release
+//
+// Synopsis: track reference counts
+//
+// History: 06-Aug-92 Rickhi Created
+//
+//--------------------------------------------------------------------------
+STDMETHODIMP_(ULONG) CQI::AddRef(void)
+{
+ InterlockedIncrement((LONG *)&_cRefs);
+ return _cRefs;
+}
+
+STDMETHODIMP_(ULONG) CQI::Release(void)
+{
+ if (InterlockedDecrement((LONG *)&_cRefs) == 0)
+ {
+ delete this;
+ return 0;
+ }
+
+ return _cRefs;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Method: CQI::QueryInterface
+//
+// Synopsis: returns ptr to requested interface.
+//
+// DANGER: this returns SUCCESS on almost every interface,
+// though the only valid methods on any interface are IUnknown.
+//
+// Arguments: [riid] - interface instance requested
+// [ppv] - where to put pointer to interface instance
+//
+// Returns: S_OK or E_NOINTERFACE
+//
+// History: 06-Aug-92 Rickhi Created
+//
+//--------------------------------------------------------------------------
+STDMETHODIMP CQI::QueryInterface(REFIID riid, void **ppv)
+{
+ // the interface cant be one of these or marshalling will fail.
+
+ if (IsEqualIID(riid,IID_IUnknown) ||
+ IsEqualIID(riid,IID_IAdviseSink) ||
+ IsEqualIID(riid,IID_IDataObject) ||
+ IsEqualIID(riid,IID_IOleObject) ||
+ IsEqualIID(riid,IID_IOleClientSite) ||
+ IsEqualIID(riid,IID_IParseDisplayName) ||
+ IsEqualIID(riid,IID_IPersistStorage) ||
+ IsEqualIID(riid,IID_IPersistFile) ||
+ IsEqualIID(riid,IID_IStorage) ||
+ IsEqualIID(riid,IID_IOleContainer) ||
+ IsEqualIID(riid,IID_IOleItemContainer) ||
+ IsEqualIID(riid,IID_IOleInPlaceSite) ||
+ IsEqualIID(riid,IID_IOleInPlaceActiveObject) ||
+ IsEqualIID(riid,IID_IOleInPlaceObject) ||
+ IsEqualIID(riid,IID_IOleInPlaceUIWindow) ||
+ IsEqualIID(riid,IID_IOleInPlaceFrame) ||
+ IsEqualIID(riid,IID_IOleWindow))
+ {
+ *ppv = (void *)(IUnknown *) this;
+ AddRef();
+ return S_OK;
+ }
+ else
+ {
+ *ppv = NULL;
+ return E_NOINTERFACE;
+ }
+}
diff --git a/private/oleutest/perform/common/cqisrv.hxx b/private/oleutest/perform/common/cqisrv.hxx
new file mode 100644
index 000000000..fef10799b
--- /dev/null
+++ b/private/oleutest/perform/common/cqisrv.hxx
@@ -0,0 +1,48 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1992.
+//
+// File: cqi.hxx
+//
+// Contents: Class to answer YES to any QueryInterface call.
+//
+// Classes: CQI
+//
+// History: 06-Aug-92 Rickhi Created
+//
+//--------------------------------------------------------------------------
+#ifndef __CQI__
+#define __CQI__
+
+//+-------------------------------------------------------------------------
+//
+// Class: CQI
+//
+// Purpose: Class to answer YES to any QueryInterface call.
+//
+// Interface: QueryInterface
+// AddRef
+// Release
+//
+// History: 06-Aug-92 Rickhi Created
+//
+//--------------------------------------------------------------------------
+
+class CQI : public IUnknown
+{
+public:
+ CQI(void);
+
+ STDMETHOD(QueryInterface)(REFIID riid, void **ppunk);
+ STDMETHOD_(ULONG, AddRef)(void);
+ STDMETHOD_(ULONG, Release)(void);
+
+private:
+ ~CQI(void);
+
+ ULONG _cRefs;
+};
+
+
+#endif // __CQI__
diff --git a/private/oleutest/perform/common/daytona/makefile b/private/oleutest/perform/common/daytona/makefile
new file mode 100644
index 000000000..1d3728d41
--- /dev/null
+++ b/private/oleutest/perform/common/daytona/makefile
@@ -0,0 +1,10 @@
+############################################################################
+#
+# Copyright (C) 1992, Microsoft Corporation.
+#
+# All rights reserved.
+#
+############################################################################
+
+!include $(NTMAKEENV)\makefile.def
+
diff --git a/private/oleutest/perform/common/daytona/sources b/private/oleutest/perform/common/daytona/sources
new file mode 100644
index 000000000..4197cc678
--- /dev/null
+++ b/private/oleutest/perform/common/daytona/sources
@@ -0,0 +1,62 @@
+!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.
+
+!ENDIF
+
+!include ..\..\daytona.inc
+
+#
+# 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= common
+
+#
+# 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= LIBRARY
+
+INCLUDES= $(INCLUDES)
+C_DEFINES= $(C_DEFINES)
+
+SOURCES= \
+ ..\bmcomm.cxx \
+ ..\stopwtch.cxx \
+ ..\bminput.cxx \
+ ..\bmoutput.cxx \
+ ..\bmconfig.cxx \
+ ..\bmlog.cxx \
+ ..\bm_base.cxx \
+ ..\bm_parse.cxx \
+ ..\bmrpc.cxx \
+ ..\stream.cxx
+
+
+UMTYPE= console
+UMENTRY= winmain
+UMAPPL=
+UMTEST=
+UMLIBS=
diff --git a/private/oleutest/perform/common/dirs b/private/oleutest/perform/common/dirs
new file mode 100644
index 000000000..2084bae88
--- /dev/null
+++ b/private/oleutest/perform/common/dirs
@@ -0,0 +1,38 @@
+!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/perform/common/rawrpc.h b/private/oleutest/perform/common/rawrpc.h
new file mode 100644
index 000000000..aa6483807
--- /dev/null
+++ b/private/oleutest/perform/common/rawrpc.h
@@ -0,0 +1,167 @@
+#ifndef __RAWRPC_H__
+#define __RAWRPC_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define small char
+
+#include "rpc.h"
+#include "rpcndr.h"
+
+
+
+#include "wtypes.h"
+
+extern RPC_IF_HANDLE IRawRpc_ServerIfHandle;
+
+extern RPC_IF_HANDLE IRawRpc_ClientIfHandle;
+
+#ifndef _SIZE_T_DEFINED
+typedef unsigned int size_t;
+#define _SIZE_T_DEFINED
+#endif
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#ifndef _ERROR_STATUS_T_DEFINED
+typedef unsigned long error_status_t;
+#define _ERROR_STATUS_T_DEFINED
+#endif
+
+#ifndef _WCHAR_T_DEFINED
+typedef unsigned short wchar_t;
+#define _WCHAR_T_DEFINED
+#endif
+
+SCODE Quit(
+ handle_t hRpc);
+void Void(
+ handle_t hRpc);
+SCODE VoidRC(
+ handle_t hRpc);
+SCODE VoidPtrIn(
+ handle_t hRpc,
+ ULONG cb,
+ void *pv);
+SCODE VoidPtrOut(
+ handle_t hRpc,
+ ULONG cb,
+ ULONG *pcb,
+ void *pv);
+SCODE DwordIn(
+ handle_t hRpc,
+ DWORD dw);
+SCODE DwordOut(
+ handle_t hRpc,
+ DWORD *pdw);
+SCODE DwordInOut(
+ handle_t hRpc,
+ DWORD *pdw);
+SCODE LiIn(
+ handle_t hRpc,
+ LARGE_INTEGER li);
+SCODE LiOut(
+ handle_t hRpc,
+ LARGE_INTEGER *pli);
+SCODE ULiIn(
+ handle_t hRpc,
+ ULARGE_INTEGER uli);
+SCODE ULiOut(
+ handle_t hRpc,
+ ULARGE_INTEGER *puli);
+SCODE StringIn(
+ handle_t hRpc,
+ LPWSTR pwsz);
+SCODE StringOut(
+ handle_t hRpc,
+ LPWSTR *ppwsz);
+SCODE StringInOut(
+ handle_t hRpc,
+ LPWSTR pwsz);
+SCODE GuidIn(
+ handle_t hRpc,
+ GUID guid);
+SCODE GuidOut(
+ handle_t hRpc,
+ GUID *pguid);
+
+#if !defined(IMPORT_USED_MULTIPLE) && !defined(IMPORT_USED_SINGLE)
+
+#endif /*!defined(IMPORT_USED_MULTIPLE) && !defined(IMPORT_USED_SINGLE)*/
+
+typedef struct _IRawRpc_SERVER_EPV
+ {
+ SCODE (__RPC_FAR * Quit)(
+ handle_t hRpc);
+ void (__RPC_FAR * Void)(
+ handle_t hRpc);
+ SCODE (__RPC_FAR * VoidRC)(
+ handle_t hRpc);
+ SCODE (__RPC_FAR * VoidPtrIn)(
+ handle_t hRpc,
+ ULONG cb,
+ void *pv);
+ SCODE (__RPC_FAR * VoidPtrOut)(
+ handle_t hRpc,
+ ULONG cb,
+ ULONG *pcb,
+ void *pv);
+ SCODE (__RPC_FAR * DwordIn)(
+ handle_t hRpc,
+ DWORD dw);
+ SCODE (__RPC_FAR * DwordOut)(
+ handle_t hRpc,
+ DWORD *pdw);
+ SCODE (__RPC_FAR * DwordInOut)(
+ handle_t hRpc,
+ DWORD *pdw);
+ SCODE (__RPC_FAR * LiIn)(
+ handle_t hRpc,
+ LARGE_INTEGER li);
+ SCODE (__RPC_FAR * LiOut)(
+ handle_t hRpc,
+ LARGE_INTEGER *pli);
+ SCODE (__RPC_FAR * ULiIn)(
+ handle_t hRpc,
+ ULARGE_INTEGER uli);
+ SCODE (__RPC_FAR * ULiOut)(
+ handle_t hRpc,
+ ULARGE_INTEGER *puli);
+ SCODE (__RPC_FAR * StringIn)(
+ handle_t hRpc,
+ LPWSTR pwsz);
+ SCODE (__RPC_FAR * StringOut)(
+ handle_t hRpc,
+ LPWSTR *ppwsz);
+ SCODE (__RPC_FAR * StringInOut)(
+ handle_t hRpc,
+ LPWSTR pwsz);
+ SCODE (__RPC_FAR * GuidIn)(
+ handle_t hRpc,
+ GUID guid);
+ SCODE (__RPC_FAR * GuidOut)(
+ handle_t hRpc,
+ GUID *pguid);
+ }
+IRawRpc_SERVER_EPV;
+void __RPC_FAR * __RPC_API MIDL_user_allocate(size_t);
+void __RPC_API MIDL_user_free(void __RPC_FAR *);
+#ifndef __MIDL_USER_DEFINED
+#define midl_user_allocate MIDL_user_allocate
+#define midl_user_free MIDL_user_free
+#define __MIDL_USER_DEFINED
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/private/oleutest/perform/common/stopwtch.cxx b/private/oleutest/perform/common/stopwtch.cxx
new file mode 100644
index 000000000..dc15a727f
--- /dev/null
+++ b/private/oleutest/perform/common/stopwtch.cxx
@@ -0,0 +1,101 @@
+//+------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1993.
+//
+// File: stopwtch.cxx
+//
+// Contents: StopWatch timer
+//
+// Classes: CStopWatch
+//
+// Functions:
+//
+// History: 30-June-93 t-martig Created
+//
+//--------------------------------------------------------------------------
+
+extern "C"
+{
+ #include <nt.h>
+ #include <ntrtl.h>
+ #include <nturtl.h>
+};
+#include <windows.h>
+#include <stopwtch.hxx>
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CStopWatch::Resolution, public
+//
+// Synopsis: Inquires performance timer resolution
+//
+// Returns: Performance counter ticks / second
+//
+// History: 30-June-93 t-martig Created
+//
+//--------------------------------------------------------------------
+CStopWatch::CStopWatch ()
+{
+ QueryPerformanceFrequency (&liFreq);
+}
+
+//+-------------------------------------------------------------------
+//
+// Member: CStopWatch::Reset, public
+//
+// Synopsis: Starts measurement cycle
+//
+// History: 30-June-93 t-martig Created
+//
+//--------------------------------------------------------------------
+
+void CStopWatch::Reset ()
+{
+ QueryPerformanceCounter (&liStart); // BUGBUG - test for error !
+}
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CStopWatch::Read, public
+//
+// Synopsis: Reads stop watch timer
+//
+// Returns: Time since call of CStopWatch::Reset (in microseconds)
+//
+// History: 30-June-93 t-martig Created
+//
+//--------------------------------------------------------------------
+
+ULONG CStopWatch::Read ()
+{
+ LARGE_INTEGER liNow, liDelta, liRemainder;
+
+ QueryPerformanceCounter (&liNow); // BUGBUG - test for error
+
+ liDelta = RtlLargeIntegerSubtract (liNow, liStart);
+ liDelta = RtlExtendedIntegerMultiply (liDelta, 1000000);
+ liDelta = RtlLargeIntegerDivide (liDelta, liFreq, &liRemainder);
+
+ return liDelta.LowPart;
+}
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CStopWatch::Resolution, public
+//
+// Synopsis: Inquires performance timer resolution
+//
+// Returns: Performance counter ticks / second
+//
+// History: 30-June-93 t-martig Created
+//
+//--------------------------------------------------------------------
+
+ULONG CStopWatch::Resolution ()
+{
+ return liFreq.LowPart;
+}
diff --git a/private/oleutest/perform/common/stopwtch.hxx b/private/oleutest/perform/common/stopwtch.hxx
new file mode 100644
index 000000000..82963c5b3
--- /dev/null
+++ b/private/oleutest/perform/common/stopwtch.hxx
@@ -0,0 +1,61 @@
+//+------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1993.
+//
+// File: stopwtch.hxx
+//
+// Contents: class definition for performance timer
+//
+// Classes: CStopWatch
+//
+// Functions:
+//
+// History: 8-July-93 t-martig Created
+//
+//--------------------------------------------------------------------------
+
+#ifndef __STOPWTCH_H
+#define __STOPWTCH_H
+
+class CStopWatch
+{
+public:
+ CStopWatch();
+ ULONG Read ();
+ void Reset ();
+ ULONG Resolution ();
+
+private:
+ LARGE_INTEGER liStart;
+ LARGE_INTEGER liFreq;
+};
+
+// Helper functions to make the code cleaner when you want to be
+// able to get both the individual and average times.
+inline void ResetAverage( BOOL fAverage, CStopWatch &sw )
+{
+ if (fAverage)
+ sw.Reset();
+}
+
+inline void ResetNotAverage( BOOL fAverage, CStopWatch &sw )
+{
+ if (!fAverage)
+ sw.Reset();
+}
+
+inline void ReadAverage( BOOL fAverage, CStopWatch &sw,
+ ULONG &ulTime, ULONG ulIterations )
+{
+ if (fAverage)
+ ulTime = sw.Read() / ulIterations;
+}
+
+inline void ReadNotAverage( BOOL fAverage, CStopWatch &sw, ULONG &ulTime )
+{
+ if (!fAverage)
+ ulTime = sw.Read();
+}
+
+#endif // __STOPWTCH_H
diff --git a/private/oleutest/perform/common/stream.cxx b/private/oleutest/perform/common/stream.cxx
new file mode 100644
index 000000000..b99c562c3
--- /dev/null
+++ b/private/oleutest/perform/common/stream.cxx
@@ -0,0 +1,315 @@
+//+-------------------------------------------------------------------
+//
+// File: stream.cxx
+//
+// Contents: Stream interface on flat File.
+//
+// Classes: CStreamOnFile
+//
+// Macros: DEFINE_INTERFACE_XMIT_ROUTINES
+//
+// History: 08-08-95 Rickhi Created
+//
+//--------------------------------------------------------------------
+#include <ole2.h>
+#include <stream.hxx>
+
+
+CStreamOnFile::CStreamOnFile(const WCHAR *pwszFileName, SCODE &sc, BOOL fRead) :
+ _clRefs(1),
+ _hFile(NULL),
+ _lOffset(0),
+ _cSize(0),
+ _cbData(0),
+ _fRead(fRead)
+{
+ _pbData = new BYTE[2048]; // should be big enough
+ if (!_pbData)
+ {
+ sc = E_OUTOFMEMORY;
+ return;
+ }
+
+ _cbData = 2048;
+
+ // open the file.
+ DWORD fdwCreate = (_fRead) ? OPEN_EXISTING : CREATE_ALWAYS;
+
+
+ _hFile = CreateFile(pwszFileName,
+ GENERIC_READ | GENERIC_WRITE, // fdwAccess
+ FILE_SHARE_READ | FILE_SHARE_WRITE, // fdwShareMode
+ NULL, // lpsaSecurity
+ fdwCreate, // creation options
+ FILE_ATTRIBUTE_NORMAL, // attributes & flags
+ NULL // hTemplateFile
+ );
+
+ if (_hFile == INVALID_HANDLE_VALUE)
+ {
+ sc = HRESULT_FROM_WIN32(GetLastError());
+ return;
+ }
+
+ // read the file into the memory block
+ DWORD cbRead = 0;
+ if (_fRead && ! ReadFile(_hFile,
+ _pbData,
+ _cbData,
+ &cbRead,
+ NULL))
+ {
+ sc = HRESULT_FROM_WIN32(GetLastError());
+ return;
+ }
+
+ if (_fRead)
+ {
+ _cSize = _cbData;
+ }
+
+ sc = S_OK;
+}
+
+CStreamOnFile::~CStreamOnFile(void)
+{
+ if (_hFile)
+ {
+ if (!_fRead)
+ {
+ // write the data to the file
+ DWORD cbWritten = 0;
+ if (!WriteFile(_hFile,
+ _pbData,
+ _cbData,
+ &cbWritten,
+ NULL))
+ {
+ SCODE sc = HRESULT_FROM_WIN32(GetLastError());
+ }
+ }
+
+ CloseHandle(_hFile);
+ }
+}
+
+
+
+STDMETHODIMP CStreamOnFile::QueryInterface(
+ REFIID iidInterface,
+ void FAR* FAR* ppvObj)
+{
+ HRESULT hresult = S_OK;
+
+ // We only support IUnknown and IStream
+ if (IsEqualIID(iidInterface, IID_IUnknown) ||
+ IsEqualIID(iidInterface, IID_IStream))
+ {
+ *ppvObj = this;
+ AddRef();
+ }
+ else
+ {
+ *ppvObj = NULL;
+ hresult = E_NOINTERFACE;
+ }
+
+ return hresult;
+}
+
+STDMETHODIMP_(ULONG) CStreamOnFile::AddRef(void)
+{
+ InterlockedIncrement(&_clRefs);
+ return _clRefs;
+}
+
+STDMETHODIMP_(ULONG) CStreamOnFile::Release(void)
+{
+ if (InterlockedDecrement(&_clRefs) == 0)
+ {
+ delete this;
+ return 0;
+ }
+
+ return _clRefs;
+}
+
+STDMETHODIMP CStreamOnFile::Read(
+ VOID HUGEP* pv,
+ ULONG cb,
+ ULONG FAR* pcbRead)
+{
+ HRESULT hresult = S_OK;
+
+ if (pcbRead)
+ {
+ *pcbRead = 0L;
+ }
+
+ if ((LONG)cb + _lOffset > _cSize)
+ {
+ cb = _cSize - _lOffset;
+ hresult = STG_E_READFAULT;
+ }
+
+ memcpy(pv, _pbData + _lOffset, (size_t) cb);
+ _lOffset += cb;
+
+ if (pcbRead != NULL)
+ {
+ *pcbRead = cb;
+ }
+
+ return hresult;
+}
+
+STDMETHODIMP CStreamOnFile::Write(
+ VOID const HUGEP* pv,
+ ULONG cbToWrite,
+ ULONG FAR* pcbWritten)
+{
+ HRESULT hresult = S_OK;
+
+ if (pcbWritten)
+ {
+ *pcbWritten = 0L;
+ }
+
+ if (cbToWrite + _lOffset > _cbData)
+ {
+ return E_OUTOFMEMORY;
+ }
+
+ // copy in the new data
+ memcpy(_pbData + _lOffset, pv, (size_t) cbToWrite);
+ _lOffset += cbToWrite;
+
+ if (pcbWritten != NULL)
+ {
+ *pcbWritten = cbToWrite;
+ }
+
+ // We assume maxium size of buffer is the size to send on the network.
+ if (_cSize < _lOffset)
+ {
+ _cSize = _lOffset;
+ }
+
+ return hresult;
+}
+
+
+
+STDMETHODIMP CStreamOnFile::Seek(
+ LARGE_INTEGER dlibMoveIN,
+ DWORD dwOrigin,
+ ULARGE_INTEGER FAR* plibNewPosition)
+{
+ HRESULT hresult = S_OK;
+
+ LONG dlibMove = dlibMoveIN.LowPart;
+ ULONG cbNewPos = dlibMove;
+
+ switch(dwOrigin)
+ {
+ case STREAM_SEEK_SET:
+
+ if (dlibMove >= 0)
+ {
+ _lOffset = dlibMove;
+ }
+ else
+ {
+ hresult = STG_E_SEEKERROR;
+ }
+ break;
+
+ case STREAM_SEEK_CUR:
+
+ if (!(dlibMove < 0 && (-dlibMove > _lOffset)))
+ {
+ _lOffset += (ULONG) dlibMove;
+ }
+ else
+ {
+ hresult = STG_E_SEEKERROR;
+ }
+ break;
+
+ case STREAM_SEEK_END:
+
+ if (!(dlibMove < 0 && ((ULONG) -dlibMove) > _cbData))
+ {
+ _lOffset = _cbData + dlibMove;
+ }
+ else
+ {
+ hresult = STG_E_SEEKERROR;
+ }
+ break;
+
+ default:
+
+ hresult = STG_E_SEEKERROR;
+ }
+
+ if (plibNewPosition != NULL)
+ {
+ ULISet32(*plibNewPosition, _lOffset);
+ }
+
+ return hresult;
+}
+
+STDMETHODIMP CStreamOnFile::SetSize(ULARGE_INTEGER cb)
+{
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP CStreamOnFile::CopyTo(
+ IStream FAR* pstm,
+ ULARGE_INTEGER cb,
+ ULARGE_INTEGER FAR* pcbRead,
+ ULARGE_INTEGER FAR* pcbWritten)
+{
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP CStreamOnFile::Commit(DWORD grfCommitFlags)
+{
+ return NOERROR;
+}
+
+STDMETHODIMP CStreamOnFile::Revert(void)
+{
+ return NOERROR;
+}
+
+STDMETHODIMP CStreamOnFile::LockRegion(
+ ULARGE_INTEGER libOffset,
+ ULARGE_INTEGER cb,
+ DWORD dwLockType)
+{
+ return STG_E_INVALIDFUNCTION;
+}
+
+STDMETHODIMP CStreamOnFile::UnlockRegion(
+ ULARGE_INTEGER libOffset,
+ ULARGE_INTEGER cb,
+ DWORD dwLockType)
+{
+ return STG_E_INVALIDFUNCTION;
+}
+
+STDMETHODIMP CStreamOnFile::Stat(
+ STATSTG FAR* pstatstg,
+ DWORD statflag)
+{
+ memset(pstatstg, 0, sizeof(STATSTG));
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP CStreamOnFile::Clone(IStream FAR * FAR *ppstm)
+{
+ return E_NOTIMPL;
+}
diff --git a/private/oleutest/perform/common/stream.hxx b/private/oleutest/perform/common/stream.hxx
new file mode 100644
index 000000000..0c6d62760
--- /dev/null
+++ b/private/oleutest/perform/common/stream.hxx
@@ -0,0 +1,96 @@
+//+-------------------------------------------------------------------
+//
+// File: stream.hxx
+//
+// Contents: Stream class on a file.
+//
+// Classes: CStreamOnFile
+//
+// History: 08-08-95 Rickhi Created
+//
+//--------------------------------------------------------------------
+#ifndef __STREAMONFILE_HXX__
+#define __STREAMONFILE_HXX__
+
+
+//+-------------------------------------------------------------------
+//
+// Class: CStreamOnFile
+//
+// Purpose: Stream wrapper for a flat file.
+//
+// History: 08-08-95 Rickhi Created
+//
+//--------------------------------------------------------------------
+class CStreamOnFile : public IStream
+{
+public:
+ CStreamOnFile(const WCHAR *pwszFileName, SCODE &sc, BOOL fRead);
+ ~CStreamOnFile(void);
+
+ STDMETHOD(QueryInterface)(
+ REFIID iidInterface,
+ void FAR* FAR* ppvObj);
+
+ STDMETHOD_(ULONG,AddRef)(void);
+
+ STDMETHOD_(ULONG,Release)(void);
+
+ STDMETHOD(Read)(
+ VOID HUGEP* pv,
+ ULONG cb,
+ ULONG FAR* pcbRead);
+
+ STDMETHOD(Write)(
+ VOID const HUGEP* pv,
+ ULONG cb,
+ ULONG FAR* pcbWritten);
+
+ STDMETHOD(Seek)(
+ LARGE_INTEGER dlibMove,
+ DWORD dwOrigin,
+ ULARGE_INTEGER FAR* plibNewPosition);
+
+ STDMETHOD(SetSize) (ULARGE_INTEGER cb);
+
+ STDMETHOD(CopyTo)(
+ IStream FAR* pstm,
+ ULARGE_INTEGER cb,
+ ULARGE_INTEGER FAR* pcbRead,
+ ULARGE_INTEGER FAR* pcbWritten);
+
+ STDMETHOD(Commit)(DWORD grfCommitFlags);
+
+ STDMETHOD(Revert)(void);
+
+ STDMETHOD(LockRegion)(
+ ULARGE_INTEGER libOffset,
+ ULARGE_INTEGER cb,
+ DWORD dwLockType);
+
+ STDMETHOD(UnlockRegion)(
+ ULARGE_INTEGER libOffset,
+ ULARGE_INTEGER cb,
+ DWORD dwLockType);
+
+ STDMETHOD(Stat)(
+ STATSTG FAR* pstatstg,
+ DWORD statflag);
+
+ STDMETHOD(Clone)(IStream FAR * FAR *ppstm);
+
+private:
+
+ LONG _clRefs; // reference count
+ HANDLE _hFile; // file handle
+ BOOL _fRead; // read or write side
+
+ LONG _lOffset; // current seek ptr
+ LONG _cSize; // number of bytes written
+
+ ULONG _cbData; // size of data
+ BYTE *_pbData; // ptr to data
+
+};
+
+#endif // _STREAMONFILE_HXX__
diff --git a/private/oleutest/perform/daytona.inc b/private/oleutest/perform/daytona.inc
new file mode 100644
index 000000000..6eaddf993
--- /dev/null
+++ b/private/oleutest/perform/daytona.inc
@@ -0,0 +1,40 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ daytona.inc
+
+Abstract:
+
+ common root include file for daytona version of performance
+ project build. This gets included by all sources files under
+ this directory.
+
+!ENDIF
+
+MAJORCOMP = cairole
+MINORCOMP = perform
+
+OLEDIR= $(BASEDIR)\private\ole32
+OLEUTESTDIR= $(BASEDIR)\private\oleutest
+OLEPERFDIR= $(OLEUTESTDIR)\perform
+
+
+INCLUDES= ;..;$(OLEPERFDIR)\common;$(OLEPERFDIR)\cairole\tests
+INCLUDES= $(INCLUDES);$(OLEUTESTDIR)\balls\oleprx32\daytona
+INCLUDES= $(INCLUDES);$(OLEDIR)\ih;$(OLEDIR)\common\daytona
+
+
+C_DEFINES= \
+ $(C_DEFINES) \
+ -DFLAT \
+ -DWIN32=100 \
+ -D_NT1X_=100 \
+ -DUNICODE \
+ -D_UNICODE \
+ -DNOEXCEPTIONS \
+ -DCAIROLE_DOWNLEVEL
+
+BLDCRT=1
diff --git a/private/oleutest/perform/dirs b/private/oleutest/perform/dirs
new file mode 100644
index 000000000..2c829cc34
--- /dev/null
+++ b/private/oleutest/perform/dirs
@@ -0,0 +1,40 @@
+!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= \
+ common \
+ cairole \
+ driver \
+ rawrpc \
+ procswap
+
+#
+# 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=
diff --git a/private/oleutest/perform/driver/bm.ini b/private/oleutest/perform/driver/bm.ini
new file mode 100644
index 000000000..67eea184d
--- /dev/null
+++ b/private/oleutest/perform/driver/bm.ini
@@ -0,0 +1,301 @@
+;
+; CairOLE BenchMark Testing Parameter File
+;
+
+
+; Parameters in this section are header info and global test parameters
+; such as the log file and results file.
+;
+[Driver]
+ Tester=Unknown
+ Report=bm.res
+ Log=bm.log
+ InitFlag=COINIT_APARTMENTTHREADED
+ PauseBetweenTests=100
+
+
+; Some of the config specifications are checked automatically but can
+; be overridden with these entries
+;
+[Config]
+; Mfg=Gateway 486DX/33
+; CPU=i486/33
+; RAM=16 Meg.
+; OS=Free Nt755
+; DISK=FAT
+
+
+; Test for raw performance/timer accuracy
+;
+[Noise Test]
+ Comment=Basic raw performance/timer accuracy tests
+
+
+; Test calling OleInitialize/OleUninitialize repeatedly
+;
+[OleInitialize]
+ Comment=First case is pairs of calls.
+ Iterations=8
+
+
+; Tests CoRegisterClassObject & CoRevokeClassObject
+;
+[ObjRegistration]
+ Comment=Internal Class is used
+ ClsId_InProc={99999999-0000-0008-C000-000000000052}
+ ClsId_Local={99999999-0000-0008-C000-000000000051}
+ Iterations=8
+
+
+; Test CoGetClassObject, CreateInstance
+;
+[ObjActivation]
+ Comment= LocalServer = mdi.exe, InProcServer = dlltest.dll
+ ClsId_InProc={99999999-0000-0008-C000-000000000052}
+ ClsId_Local={99999999-0000-0008-C000-000000000051}
+ Iterations=8
+
+
+; Tests FileMoniker BindToObject
+;
+[BindToObject]
+ Comment= LocalServer = mdi.exe, InProcServer = dlltest.dll
+ ClsId_InProc={99999999-0000-0008-C000-000000000052}
+ ClsId_Local={99999999-0000-0008-C000-000000000051}
+ Iterations=8
+
+
+; Tests FileMoniker BindToStorage
+;
+[BindToStorage]
+ Comment= LocalServer = mdi.exe, InProcServer = dlltest.dll
+ ClsId_InProc={99999999-0000-0008-C000-000000000052}
+ ClsId_Local={99999999-0000-0008-C000-000000000051}
+ Iterations=8
+
+
+; Test Running Object Table
+;
+[ROT]
+ Comment= LocalServer = mdi.exe, InProcServer = dlltest.dll
+ ClsId_InProc={99999999-0000-0008-C000-000000000052}
+ ClsId_Local={99999999-0000-0008-C000-000000000051}
+ Iterations=8
+
+
+; Not Yet Working
+;
+[Properties]
+ Comment=TBD
+
+
+; Tests CoMarshalInterface & CoUnmarshalInterface
+;
+[Marshalling]
+ Comment=Unmarshalled into same process. LocalServer = qisrv.exe
+ ClsId={00000140-0000-0008-C000-000000000046}
+ ClsCtx=InProc
+ Iterations=8
+
+
+; Tests various marshaling APIs
+;
+[Marshalling2]
+ Comment=Unmarshalled into same process. LocalServer = qisrv.exe
+ ClsId={00000140-0000-0008-C000-000000000046}
+ ClsCtx=InProc
+ Iterations=8
+
+
+; Tests Ole Object Method Calls over Rpc
+;
+[RpcTest]
+ Comment=Ole Object Method Calls over Rpc. LocalServer = rpctst.exe
+ Clsid_Local={0000013d-0001-0008-C000-000000000046}
+ Clsid_Inproc={00000140-0000-0008-C000-000000000046}
+ Iterations=8
+ Average=N
+
+
+; Tests Ole Object Method Calls over Rpc
+;
+[RpcTest2]
+ Comment=Ole Object Method Calls over Rpc. LocalServer = rpctst.exe
+ Clsid_Local={0000013d-0001-0008-C000-000000000046}
+ Clsid_Inproc={00000140-0000-0008-C000-000000000046}
+ Iterations=8
+ Average=N
+
+
+; Tests function calls over Raw Rpc
+;
+[RawRpc]
+ Comment=Function calls over Raw Rpc
+ Iterations=8
+ Server=rawrpc.exe
+ Debug=N
+ Protseq=ncalrpc
+ Average=N
+
+
+; Tests nested calls over Rpc
+;
+[Nested]
+ Comment=Nested Rpc calls. LocalServer = loopsrv.exe
+ Clsid_Local={0000013c-0001-0008-C000-000000000046}
+ Iterations=8
+
+
+; Tests Ole QueryInterface Calls
+;
+[QueryInterface]
+ Comment=QueryInterface calls over Rpc. LocalServer = qisrv.exe
+ Clsid_Local={00000140-0000-0008-C000-000000000046}
+ Clsid_Inproc={00000140-0000-0008-C000-000000000046}
+ Iterations=8
+
+
+; Tests calling IsEqualGUID api vs memcmp
+;
+[GuidCompare]
+ Comment=Compare timings of memcmp vs IsEqualGUID
+ Iterations=8
+
+
+; Tests calling CoGetPSClsid
+;
+[CoGetPSClsidTest]
+ Comment=call CoGetPSClsid
+ Iterations=8
+
+
+; Tests Miscellaneous COM Apis
+;
+[ApiTest]
+ Comment=Miscellaneous COM Apis
+ ClsId_Local={99999999-0000-0008-C000-000000000051}
+ Iterations=8
+
+
+; Tests default OLE IMalloc implementation
+;
+[IMalloc]
+ Comment=OLE2 IMalloc
+ Iterations=8
+
+;
+; Win32 File IO Api test
+; AccessMode is either NORMAL, MAPPED or ASYNC
+; ReadMode is either RANDOM or SEQUENTIAL
+;
+[FileIOTest]
+ Commet=File IO Test
+ Iterations=8
+ FileName=stgtest.bm
+ AccessMode=MAPPED
+ ReadMode=SEQUENTIAL
+ WriteThrough=OFF
+ Flush=ON
+ StartSize=512
+ EndSize=4096
+ RepeatFactor=1
+
+
+;
+; Simple Storage Test
+; FileMode is either DIRECT or TRANSACTED
+; ReadMode is either RANDOM or SEQUENTIAL
+;
+[StorageTest]
+ Comment=Storage Test
+ Iterations=8
+ FileName=stgtest.bm
+ FileMode=DIRECT
+ ReadMode=SEQUENTIAL
+ SetSize=ON
+ StartSize=512
+ EndSize=4096
+ RepeatFactor=1
+
+
+;
+; Nested Storage Test
+;
+[NestedStorageTest]
+ Comment=Nested Storage Test
+ Iterations=1
+ FileName=stgtest.bm
+ FileMode=DIRECT
+ DataSize=4096
+ Branching=2
+ Nesting=3
+ Delete=ON
+
+;
+; Generic Storage test
+; Executes commands from <ScriptName> file
+;
+[StorageParserTest]
+ Comment=Storage parser test
+ Iterations=1
+ ScriptName=storage.scp
+
+[CreateTest]
+ Comment=Testing Ole Create Api
+ Iterations=8
+
+[CreateLinkTest]
+ Comment=Testing Ole CreateLink Api
+ Iterations=8
+
+[ClipbrdTest]
+ Comment=Testing Ole Clipboard Apis
+ Iterations=8
+
+[LoadTest]
+ Comment=Testing OleLoad And OleSave
+ Iterations=8
+
+[IOLTest]
+ Comment=Testing IOleLink methods
+ Iterations=8
+
+[CacheTest]
+ Comment=Testing IOleCache methods
+ Iterations=8
+
+; This sections lists each test and whether to execute it or not. Setting
+; the value to OFF or FALSE turns execution off.
+;
+[Tests]
+ Properties=OFF
+ FileIOTest=off
+ StorageTest=OFF
+ NestedStorageTest=OFF
+ StorageParserTest=off
+ CreateTest=off
+ CreateLinkTest=off
+ ClipbrdTest=off
+ LoadTest=OFF
+ IOLTest=off
+ CacheTest=off
+ RpcTest2=off
+
+
+ Noise Test=on
+ RawRpc=on
+ OleInitialize=on
+ ObjRegistration=on
+ ObjActivation=on
+ BindToObject=on
+ BindToStorage=on
+ ROT=on
+ Nested=on
+ QueryInterface=on
+ ApiTest=on
+ IMalloc=on
+ GuidCompare=on
+ Marshalling2=on
+ RpcTest=on
+ Marshalling=on
+ CoGetPSClsidTest=on
diff --git a/private/oleutest/perform/driver/bm.reg b/private/oleutest/perform/driver/bm.reg
new file mode 100644
index 000000000..54738fcd3
--- /dev/null
+++ b/private/oleutest/perform/driver/bm.reg
@@ -0,0 +1,36 @@
+REGEDIT
+HKEY_CLASSES_ROOT\CLSID
+HKEY_CLASSES_ROOT\Interface
+
+HKEY_CLASSES_ROOT\CLSID\{20730701-0001-0008-C000-000000000046} = OleTestClass
+HKEY_CLASSES_ROOT\CLSID\{20730701-0001-0008-C000-000000000046}\InprocServer32 = oletest.dll
+HKEY_CLASSES_ROOT\CLSID\{20730701-0001-0008-C000-000000000046}\LocalServer32 = bmtstsvr.exe
+
+HKEY_CLASSES_ROOT\CLSID\{20730711-0001-0008-C000-000000000046} = OleTestClass1
+HKEY_CLASSES_ROOT\CLSID\{20730711-0001-0008-C000-000000000046}\InprocServer32 = oletest.dll
+
+HKEY_CLASSES_ROOT\CLSID\{20730712-0001-0008-C000-000000000046} = OleTestClass2
+HKEY_CLASSES_ROOT\CLSID\{20730712-0001-0008-C000-000000000046}\InprocServer32 = oletest.dll
+
+HKEY_CLASSES_ROOT\CLSID\{20730713-0001-0008-C000-000000000046} = OleTestClass3
+HKEY_CLASSES_ROOT\CLSID\{20730713-0001-0008-C000-000000000046}\InprocServer32 = oletest.dll
+
+HKEY_CLASSES_ROOT\CLSID\{20730714-0001-0008-C000-000000000046} = OleTestClass4
+HKEY_CLASSES_ROOT\CLSID\{20730714-0001-0008-C000-000000000046}\InprocServer32 = oletest.dll
+
+HKEY_CLASSES_ROOT\CLSID\{20730715-0001-0008-C000-000000000046} = OleTestClass5
+HKEY_CLASSES_ROOT\CLSID\{20730715-0001-0008-C000-000000000046}\InprocServer32 = oletest.dll
+
+HKEY_CLASSES_ROOT\CLSID\{20730716-0001-0008-C000-000000000046} = OleTestClass6
+HKEY_CLASSES_ROOT\CLSID\{20730716-0001-0008-C000-000000000046}\InprocServer32 = oletest.dll
+
+HKEY_CLASSES_ROOT\CLSID\{20730717-0001-0008-C000-000000000046} = OleTestClass7
+HKEY_CLASSES_ROOT\CLSID\{20730717-0001-0008-C000-000000000046}\InprocServer32 = oletest.dll
+
+HKEY_CLASSES_ROOT\CLSID\{20730718-0001-0008-C000-000000000046} = OleTestClass8
+HKEY_CLASSES_ROOT\CLSID\{20730718-0001-0008-C000-000000000046}\InprocServer32 = oletest.dll
+
+HKEY_CLASSES_ROOT\CLSID\{20730712-0001-0008-C000-000000000046}\LocalServer32 = bmtstsvr.exe
+
+HKEY_CLASSES_ROOT\.bm1 = CLSID\{99999999-0000-0008-C000-000000000052}
+HKEY_CLASSES_ROOT\.bm2 = CLSID\{99999999-0000-0008-C000-000000000051}
diff --git a/private/oleutest/perform/driver/bmdriver.cxx b/private/oleutest/perform/driver/bmdriver.cxx
new file mode 100644
index 000000000..ab106e408
--- /dev/null
+++ b/private/oleutest/perform/driver/bmdriver.cxx
@@ -0,0 +1,512 @@
+//+------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1993.
+//
+// File: bmdriver.cxx
+//
+// Contents: Main module of the benchmark test
+//
+// Classes: CBenchMarkDriver
+//
+// Functions: WinMain
+//
+// History: 30-June-93 t-martig Created
+// 07-June-94 t-vadims Added Storage tests
+//
+//--------------------------------------------------------------------------
+
+#include <benchmrk.hxx>
+#include <bmdriver.hxx>
+
+#include <bm_activ.hxx>
+#include <bm_alloc.hxx>
+#include <bm_api.hxx>
+#include <bm_cgps.hxx>
+#include <bm_iid.hxx>
+#include <bm_init.hxx>
+#include <bm_marsh.hxx>
+#include <bm_mrsh2.hxx>
+#include <bm_noise.hxx>
+#include <bm_nest.hxx>
+#include <bm_obind.hxx>
+#include <bm_props.hxx>
+#include <bm_qi.hxx>
+#include <bm_regis.hxx>
+#include <bm_rot.hxx>
+#include <bm_rpc.hxx>
+#include <bm_rpc2.hxx>
+#include <bm_rrpc.hxx>
+#include <bm_sbind.hxx>
+#include <bm_filio.hxx>
+#include <bm_stg.hxx>
+#include <bm_nstg.hxx>
+#include <bmp_stg.hxx>
+#include "..\cairole\ui\hlp_iocs.hxx"
+#include "..\cairole\ui\hlp_ias.hxx"
+#include "..\cairole\ui\hlp_site.hxx"
+#include "..\cairole\ui\hlp_doc.hxx"
+#include "..\cairole\ui\bm_crt.hxx"
+#include "..\cairole\ui\bm_crtl.hxx"
+//#include "..\cairole\ui\bm_clip.hxx"
+#include "..\cairole\ui\bm_load.hxx"
+#include "..\cairole\ui\bm_link.hxx"
+#include "..\cairole\ui\bm_cache.hxx"
+
+
+#define REGISTRY_ENTRY_LEN 256
+
+typedef struct
+{
+ const char *key;
+ const char *value;
+} RegistryKeyValue;
+
+const RegistryKeyValue REG_CONST_KEY[] =
+{
+ ".bm1", "CLSID\\{99999999-0000-0008-C000-000000000052}",
+ ".bm2", "CLSID\\{99999999-0000-0008-C000-000000000051}",
+
+ "CLSID\\{20730701-0001-0008-C000-000000000046}", "OleTestClass",
+ "CLSID\\{20730711-0001-0008-C000-000000000046}", "OleTestClass1",
+ "CLSID\\{20730712-0001-0008-C000-000000000046}", "OleTestClass2",
+ "CLSID\\{20730713-0001-0008-C000-000000000046}", "OleTestClass3",
+ "CLSID\\{20730714-0001-0008-C000-000000000046}", "OleTestClass4",
+ "CLSID\\{20730715-0001-0008-C000-000000000046}", "OleTestClass5",
+ "CLSID\\{20730716-0001-0008-C000-000000000046}", "OleTestClass6",
+ "CLSID\\{20730717-0001-0008-C000-000000000046}", "OleTestClass7",
+ "CLSID\\{20730718-0001-0008-C000-000000000046}", "OleTestClass8",
+
+ "CLSID\\{00000138-0001-0008-C000-000000000046}", "CPrxyBalls",
+ "Interface\\{00000138-0001-0008-C000-000000000046}", "IBalls",
+ "Interface\\{00000139-0001-0008-C000-000000000046}", "ICube",
+ "Interface\\{00000136-0001-0008-C000-000000000046}", "ILoops",
+ "Interface\\{00000137-0001-0008-C000-000000000046}", "IRpcTest",
+
+ "Interface\\{00000138-0001-0008-C000-000000000046}\\ProxyStubClsid32", "{00000138-0001-0008-C000-000000000046}",
+ "Interface\\{00000139-0001-0008-C000-000000000046}\\ProxyStubClsid32", "{00000138-0001-0008-C000-000000000046}",
+ "Interface\\{00000136-0001-0008-C000-000000000046}\\ProxyStubClsid32", "{00000138-0001-0008-C000-000000000046}",
+ "Interface\\{00000137-0001-0008-C000-000000000046}\\ProxyStubClsid32", "{00000138-0001-0008-C000-000000000046}",
+ "CLSID\\{0000013a-0001-0008-C000-000000000046}\\ProgID", "ProgID60",
+ "CLSID\\{0000013a-0001-0008-C000-000000000046}", "CBallsClassFactory",
+ "CLSID\\{0000013b-0001-0008-C000-000000000046}", "CCubesClassFactory",
+ "CLSID\\{0000013c-0001-0008-C000-000000000046}", "CLoopClassFactory",
+ "CLSID\\{0000013d-0001-0008-C000-000000000046}", "CRpcTestClassFactory",
+ "CLSID\\{00000140-0000-0008-C000-000000000046}", "CQueryInterface",
+ "CLSID\\{00000142-0000-0008-C000-000000000046}", "Dummy",
+
+
+ ".ut4", "ProgID50",
+ ".ut5", "ProgID51",
+ ".ut6", "ProgID52",
+ ".ut7", "ProgID53",
+ ".ut8", "ProgID54",
+ ".ut9", "ProgID55",
+ ".bls", "ProgID60",
+
+ "CLSID\\{99999999-0000-0008-C000-000000000050}", "SDI",
+ "CLSID\\{99999999-0000-0008-C000-000000000051}", "MDI",
+ "CLSID\\{99999999-0000-0008-C000-000000000052}", "InprocNoRegister",
+ "CLSID\\{99999999-0000-0008-C000-000000000053}", "InprocRegister",
+ "CLSID\\{99999999-0000-0008-C000-000000000054}", "InprocRegister",
+ "CLSID\\{99999999-0000-0008-C000-000000000054}\\TreatAs", "{99999999-0000-0008-C000-000000000050}",
+ "CLSID\\{99999999-0000-0008-C000-000000000055}", "MDI",
+ "CLSID\\{99999999-0000-0008-C000-000000000055}\\ActivateAtBits", "Y",
+
+ "ProgID50", "objact sdi",
+ "ProgID50\\CLSID", "{99999999-0000-0008-C000-000000000050}",
+ "ProgID51", "objact mdi",
+ "ProgID51\\CLSID", "{99999999-0000-0008-C000-000000000051}",
+ "ProgID52", "objact dll",
+ "ProgID52\\CLSID", "{99999999-0000-0008-C000-000000000052}",
+ "ProgID53", "objact dll reg",
+ "ProgID53\\CLSID", "{99999999-0000-0008-C000-000000000053}",
+ "ProgID54", "objact dll reg",
+ "ProgID54\\CLSID", "{99999999-0000-0008-C000-000000000054}",
+ "ProgID55", "remote activation",
+ "ProgID55\\CLSID", "{99999999-0000-0008-C000-000000000055}",
+ "ProgID60", "CLSIDFromProgID test",
+ "ProgID60\\CLSID", "{0000013a-0001-0008-C000-000000000046}",
+
+ // Indicates end of list.
+ "", ""
+};
+
+const RegistryKeyValue REG_EXE_KEY[] =
+{
+ "CLSID\\{20730701-0001-0008-C000-000000000046}\\InprocServer32", "oletest.dll",
+ "CLSID\\{20730711-0001-0008-C000-000000000046}\\InprocServer32", "oletest.dll",
+ "CLSID\\{20730712-0001-0008-C000-000000000046}\\InprocServer32", "oletest.dll",
+ "CLSID\\{20730713-0001-0008-C000-000000000046}\\InprocServer32", "oletest.dll",
+ "CLSID\\{20730714-0001-0008-C000-000000000046}\\InprocServer32", "oletest.dll",
+ "CLSID\\{20730715-0001-0008-C000-000000000046}\\InprocServer32", "oletest.dll",
+ "CLSID\\{20730716-0001-0008-C000-000000000046}\\InprocServer32", "oletest.dll",
+ "CLSID\\{20730717-0001-0008-C000-000000000046}\\InprocServer32", "oletest.dll",
+ "CLSID\\{20730718-0001-0008-C000-000000000046}\\InprocServer32", "oletest.dll",
+
+ "CLSID\\{20730712-0001-0008-C000-000000000046}\\LocalServer32", "bmtstsvr.exe",
+ "CLSID\\{20730701-0001-0008-C000-000000000046}\\LocalServer32", "bmtstsvr.exe",
+
+ "CLSID\\{0000013a-0001-0008-C000-000000000046}\\LocalServer32", "ballsrv.exe",
+ "CLSID\\{00000138-0001-0008-C000-000000000046}\\InprocServer32", "iballs.dll",
+ "CLSID\\{0000013b-0001-0008-C000-000000000046}\\LocalServer32", "cubesrv.exe",
+ "CLSID\\{0000013c-0001-0008-C000-000000000046}\\LocalServer32", "loopsrv.exe",
+ "CLSID\\{0000013d-0001-0008-C000-000000000046}\\LocalServer32", "rpctst.exe",
+ "CLSID\\{00000140-0000-0008-C000-000000000046}\\LocalServer32", "qisrv.exe",
+ "CLSID\\{00000140-0000-0008-C000-000000000046}\\InprocServer32", "qisrv.dll",
+ "CLSID\\{00000142-0000-0008-C000-000000000046}\\InprocServer32", "ballsrv.dll",
+
+
+ "CLSID\\{99999999-0000-0008-C000-000000000050}\\LocalServer32", "sdi.exe",
+ "CLSID\\{99999999-0000-0008-C000-000000000051}\\LocalServer32", "mdi.exe",
+ "CLSID\\{99999999-0000-0008-C000-000000000052}\\InprocServer32", "dlltest.dll",
+ "CLSID\\{99999999-0000-0008-C000-000000000053}\\InprocServer32", "dlltest.dll",
+ "CLSID\\{99999999-0000-0008-C000-000000000055}\\LocalServer32", "db.exe",
+
+ // Indicates end of list.
+ "", ""
+};
+
+DWORD g_fFullInfo = 0; // write full info or not
+DWORD g_dwPauseBetweenTests = 0; // time delay between running tests
+
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CBenchMarkDriver::RunTest, public
+//
+// Synopsis: Sets up, runs, reports and cleans up test procedure
+// of specified class
+//
+// Parameters: [output] Output class for results
+// [pTest] Test object
+//
+// History: 30-June-93 t-martig Created
+//
+//--------------------------------------------------------------------
+
+SCODE CBenchMarkDriver::RunTest (CTestInput &input,
+ CTestOutput &output, CTestBase *pTest)
+{
+ TCHAR szConfigString[80];
+ SCODE sc;
+
+ input.GetConfigString (TEXT("Tests"), pTest->Name(),
+ TEXT("OFF"), szConfigString, 80);
+
+ if (lstrcmpi (szConfigString, TEXT("OFF")) != 0 &&
+ lstrcmpi (szConfigString, TEXT("FALSE")) != 0)
+ {
+ LogSection (pTest->Name());
+
+ sc=pTest->Setup(&input);
+ if (FAILED(sc))
+ return sc;
+
+ // pause between test invocations
+ Sleep(g_dwPauseBetweenTests);
+
+ sc = pTest->Run();
+ pTest->Report(output);
+ pTest->Cleanup();
+
+ if (FAILED(sc))
+ {
+ output.WriteString (TEXT("\nStatus:\tERROR, see log file\n"));
+ }
+
+ // pause between test invocations
+ Sleep(g_dwPauseBetweenTests);
+ }
+
+ return sc;
+}
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CBenchMarkDriver::WriteHeader, public
+//
+// Synopsis: Prints test form header into output file
+//
+// History: 5-August-93 t-martig Created
+//
+//--------------------------------------------------------------------
+
+void CBenchMarkDriver::WriteHeader (CTestInput &input, CTestOutput &output)
+{
+ _SYSTEMTIME stTimeDate;
+
+ output.WriteString (TEXT("CairOLE Benchmarks\n"));
+ output.WriteConfigEntry (input, TEXT("Driver"), TEXT("Tester"), TEXT(""));
+ GetLocalTime (&stTimeDate);
+ output.WriteDate (&stTimeDate);
+ output.WriteString (TEXT("\t"));
+ output.WriteTime (&stTimeDate);
+ output.WriteString (TEXT("\n\n"));
+}
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CBenchMarkDriver::Run, public
+//
+// Synopsis: Runs all tests specified in .ini file
+//
+// History: 30-June-93 t-martig Created
+//
+//--------------------------------------------------------------------
+
+#define RUN_TEST(CMyTestClass) \
+{ \
+ CTestBase *pTest; \
+ pTest = new CMyTestClass; \
+ RunTest (input, output, pTest); \
+ delete pTest; \
+ output.Flush(); \
+}
+
+
+SCODE CBenchMarkDriver::Run (LPSTR lpCmdLine)
+{
+ TCHAR szBenchMarkIniFile[MAX_PATH];
+ TCHAR szOutputFileName[MAX_PATH];
+ TCHAR szLogFileName[MAX_PATH];
+ TCHAR szTemp[MAX_PATH];
+
+
+ // Get file name of .ini file. if not specified in the command
+ // line, use the default BM.INI in the local directory
+
+ GetCurrentDirectory (MAX_PATH, szTemp);
+
+ lstrcpy(szBenchMarkIniFile, szTemp);
+ lstrcat (szBenchMarkIniFile, TEXT("\\BM.INI"));
+
+ // create the names for the temporary files. uses pid.xxx. Its the
+ // current directory appended with the pid and a file extension.
+ OLECHAR szPid[9];
+ DWORD pid = GetCurrentProcessId();
+ CHAR aszPid[9];
+ _itoa(pid, aszPid, 16);
+ mbstowcs(szPid, aszPid, strlen(aszPid)+1);
+
+#ifdef UNICODE
+ wcscpy(aszPerstName[0], szTemp);
+#else
+ mbstowcs(aszPerstName[0], szTemp, strlen(szTemp)+1);
+#endif
+ wcscat(aszPerstName[0], L"\\");
+ wcscat(aszPerstName[0], szPid);
+
+ wcscpy(aszPerstName[1], aszPerstName[0]);
+ wcscpy(aszPerstNameNew[0], aszPerstName[0]);
+ wcscpy(aszPerstNameNew[1], aszPerstName[0]);
+
+ wcscat(aszPerstName[0], L".BM1");
+ wcscat(aszPerstNameNew[0], L"NEW.BM1");
+ wcscat(aszPerstName[1], L".BM2");
+ wcscat(aszPerstNameNew[1], L"NEW.BM2");
+
+
+
+ // Define input, output and log file
+
+ CTestInput input (szBenchMarkIniFile);
+ CTestOutput output (input.GetConfigString (TEXT("Driver"), TEXT("Report"),
+ TEXT("BM.RES"), szOutputFileName, MAX_PATH));
+ CTestOutput log (input.GetConfigString (TEXT("Driver"), TEXT("Log"),
+ TEXT("BM.LOG"), szLogFileName, MAX_PATH));
+
+ LogTo (&log);
+
+
+ // Get the pause time between test invocations
+
+ g_dwPauseBetweenTests = input.GetConfigInt (TEXT("Driver"),
+ TEXT("PauseBetweenTests"),
+ 2000);
+
+ // Get global info level flag
+
+ g_fFullInfo = input.GetInfoLevelFlag();
+
+
+ // Write the correct OleInitialize flag to win.ini for the various
+ // OLE servers to use, based on the init flag in bm.ini.
+
+ LPTSTR pszOleInit;
+#ifdef THREADING_SUPPORT
+ if (input.GetOleInitFlag() == COINIT_MULTITHREADED)
+ {
+// pszOleInit = TEXT("MultiThreaded");
+ }
+ else
+#endif
+ {
+// pszOleInit = TEXT("ApartmentThreaded");
+ }
+
+// WriteProfileString(TEXT("TestSrv"), TEXT("ThreadMode"), pszOleInit);
+// WriteProfileString(TEXT("OleSrv"), TEXT("ThreadMode"), pszOleInit);
+
+
+ // Write header and configuration info
+
+ WriteHeader (input, output);
+ ReportBMConfig (input, output);
+
+
+ // Run all the tests
+ // To add tests, use macro RUN_TEST, the parameter is the name of
+ // the test class. Be sure to include a sction called [<TestClass>] in
+ // the BM.INI file, as well as a switch under the [Tests] section
+ // (<TestClass> = ON, e.g.)
+
+ Sleep(1000);
+
+ RUN_TEST (COleMarshalTest2);
+ RUN_TEST (CNoiseTest);
+ RUN_TEST (CRawRpc); // NOTE: must come before any OLE tests
+ RUN_TEST (COleInitializeTest);
+ RUN_TEST (COleRegistrationTest);
+ RUN_TEST (COleActivationTest);
+ RUN_TEST (CFileMonikerStorageBindTest);
+ RUN_TEST (CFileMonikerObjBindTest);
+ RUN_TEST (CROTTest);
+ RUN_TEST (COlePropertyTest);
+ RUN_TEST (COleMarshalTest);
+ RUN_TEST (CRpcTest);
+ RUN_TEST (CRpcTest2);
+ RUN_TEST (CNestTest);
+ RUN_TEST (CQueryInterfaceTest);
+ RUN_TEST (CApiTest);
+ RUN_TEST (CCGPSTest);
+ RUN_TEST (COleAllocTest);
+ RUN_TEST (CGuidCompareTest);
+ RUN_TEST (CFileIOTest);
+ RUN_TEST (CStorageTest);
+ RUN_TEST (CNestedStorageTest);
+ RUN_TEST (CStorageParserTest);
+
+ //Upper layer tests
+ RUN_TEST (CCreateTest);
+ RUN_TEST (CCreateLinkTest);
+// RUN_TEST (CClipbrdTest);
+ RUN_TEST (COleLoadTest);
+ RUN_TEST (CIOLTest);
+ RUN_TEST (COleCacheTest);
+
+
+ return S_OK;
+}
+
+
+//+-------------------------------------------------------------------
+//
+// Function: RegistrySetup
+//
+// Synopsis: If the registry entries for this program are not set,
+// write them
+//
+// Note: This function uses all Ascii characters and character
+// arithmatic because it has to run on NT and Chicago.
+//
+// History: 16 Dec 94 AlexMit Created
+//
+//--------------------------------------------------------------------
+
+BOOL RegistrySetup()
+{
+ char value[REGISTRY_ENTRY_LEN];
+ LONG value_size;
+ LONG result;
+ char directory[MAX_PATH];
+ char *appname;
+ BOOL success = FALSE;
+
+ // Write constant entries.
+ for (int i = 0; REG_CONST_KEY[i].key[0] != '\0'; i++)
+ {
+ result = RegSetValueA(
+ HKEY_CLASSES_ROOT,
+ REG_CONST_KEY[i].key,
+ REG_SZ,
+ REG_CONST_KEY[i].value,
+ strlen(REG_CONST_KEY[i].value) );
+
+ if (result != ERROR_SUCCESS)
+ goto cleanup;
+ }
+
+ // Compute the path to the application.
+ result = GetFullPathNameA("benchmrk", sizeof(directory), directory, &appname);
+ if (result == 0)
+ goto cleanup;
+
+ // Add the path to all the dll and exe entries.
+ for (i = 0; REG_EXE_KEY[i].key[0] != '\0'; i++)
+ {
+ // Verify that the path will fit in the buffer and compute the path
+ // to the next executable.
+ if (strlen(REG_EXE_KEY[i].value) >=
+ (ULONG)(MAX_PATH - (appname - directory)))
+ goto cleanup;
+
+ strcpy(appname, REG_EXE_KEY[i].value);
+
+ // Write the next entry.
+ result = RegSetValueA(
+ HKEY_CLASSES_ROOT,
+ REG_EXE_KEY[i].key,
+ REG_SZ,
+ directory,
+ strlen(directory));
+
+ if (result != ERROR_SUCCESS)
+ goto cleanup;
+ }
+
+ success = TRUE;
+
+cleanup:
+ return success;
+}
+
+//+-------------------------------------------------------------------
+//
+// Function: WinMain
+//
+// Synopsis: Program entry point, starts benchmark driver
+//
+// History: 30-June-93 t-martig Created
+//
+//--------------------------------------------------------------------
+
+int APIENTRY WinMain(
+ HINSTANCE hInstance,
+ HINSTANCE hPrevInstance,
+ LPSTR lpCmdLine,
+ int nCmdShow)
+{
+ CBenchMarkDriver driver;
+
+ if (!_stricmp(lpCmdLine, "/r") || !_stricmp(lpCmdLine, "-r"))
+ {
+ if (!RegistrySetup())
+ {
+ printf("Registry Updated\n");
+ return 0;
+ }
+ else
+ {
+ printf("Registry Update Failed\n");
+ return 1;
+ }
+ }
+
+ driver.Run (lpCmdLine);
+ return 0;
+}
+
diff --git a/private/oleutest/perform/driver/bmguid.cxx b/private/oleutest/perform/driver/bmguid.cxx
new file mode 100644
index 000000000..edcbb3214
--- /dev/null
+++ b/private/oleutest/perform/driver/bmguid.cxx
@@ -0,0 +1,45 @@
+//-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1993.
+//
+// File: bmguid.cxx
+//
+// Contents: OLE test guids
+//
+// Classes:
+//
+// Functions:
+//
+// History: 12-August-93 t-martig Created
+//
+//--------------------------------------------------------------------------
+
+
+#define INITGUID
+#include "windows.h"
+
+#ifdef _NTIDW340
+// Handle port problems easily
+// #define WIN32
+
+#ifdef __cplusplus
+// PORT: Handle the fact that jmp_buf doesn't make any sense in cpp.
+#define jmp_buf int
+#endif // __cplusplus
+#endif // _NTIDW340
+
+// PORT: HTASK no longer seems to be defined in Win32
+#define HTASK DWORD
+#define HINSTANCE_ERROR 32
+#define __loadds
+#define __segname
+#define BASED_CODE
+#define HUGE
+#define _ffree free
+#define __based(x)
+#include <port1632.h>
+
+DEFINE_OLEGUID(CLSID_COleTestClass, 0x20730701, 1, 8); // CT Test GUID
+DEFINE_OLEGUID(CLSID_COleTestClass2, 0x20730712, 1, 8); // CT Test GUID
+DEFINE_OLEGUID(CLSID_TestProp, 0x20730722, 1, 8); // CT Test GUID
diff --git a/private/oleutest/perform/driver/daytona/makefile b/private/oleutest/perform/driver/daytona/makefile
new file mode 100644
index 000000000..1d3728d41
--- /dev/null
+++ b/private/oleutest/perform/driver/daytona/makefile
@@ -0,0 +1,10 @@
+############################################################################
+#
+# Copyright (C) 1992, Microsoft Corporation.
+#
+# All rights reserved.
+#
+############################################################################
+
+!include $(NTMAKEENV)\makefile.def
+
diff --git a/private/oleutest/perform/driver/daytona/sources b/private/oleutest/perform/driver/daytona/sources
new file mode 100644
index 000000000..a1032baec
--- /dev/null
+++ b/private/oleutest/perform/driver/daytona/sources
@@ -0,0 +1,71 @@
+!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.
+
+!ENDIF
+
+!include ..\..\daytona.inc
+
+#
+# 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= benchmrk
+
+#
+# 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= $(INCLUDES)
+C_DEFINES= $(C_DEFINES)
+
+SOURCES= \
+ ..\bmdriver.cxx
+
+UMTYPE= windows
+UMENTRY= winmain
+UMAPPL=
+UMTEST=
+UMLIBS=
+
+LINKLIBS= \
+ ..\..\cairole\tests\daytona\obj\*\bmtests.lib \
+ ..\..\common\daytona\obj\*\common.lib \
+ ..\..\cairole\ui\daytona\obj\*\apitests.lib \
+ ..\..\cairole\dll\daytona\obj\*\oletest.obj \
+ $(OLEDIR)\common\daytona\obj\*\common.lib \
+ $(OLEUTESTDIR)\balls\common\daytona\obj\*\servers.lib \
+ $(OLEUTESTDIR)\balls\oleprx32\uuid\daytona\obj\*\uuid.lib \
+ $(BASEDIR)\public\sdk\lib\*\crtdll.lib \
+ $(BASEDIR)\public\sdk\lib\*\uuid.lib \
+ $(BASEDIR)\public\sdk\lib\*\ole32.lib \
+ $(BASEDIR)\public\sdk\lib\*\rpcndr.lib \
+ $(BASEDIR)\public\sdk\lib\*\rpcrt4.lib \
+ $(BASEDIR)\public\sdk\lib\*\rpcns4.lib \
+ $(BASEDIR)\public\sdk\lib\*\ntdll.lib
+
+
+USE_CRTDLL= 1
diff --git a/private/oleutest/perform/driver/dirs b/private/oleutest/perform/driver/dirs
new file mode 100644
index 000000000..2084bae88
--- /dev/null
+++ b/private/oleutest/perform/driver/dirs
@@ -0,0 +1,38 @@
+!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/perform/driver/makefil0 b/private/oleutest/perform/driver/makefil0
new file mode 100644
index 000000000..2067d8710
--- /dev/null
+++ b/private/oleutest/perform/driver/makefil0
@@ -0,0 +1,13 @@
+# Copy text files for benchmrk test to dump directory
+# Copyright (c) 1994, Microsoft Corporation
+#
+# History:
+# 19 Dec 94 AlexMit
+#
+
+!INCLUDE $(NTMAKEENV)\makefile.plt
+
+all:
+ binplace bm.ini
+
+clean:
diff --git a/private/oleutest/perform/driver/makefile b/private/oleutest/perform/driver/makefile
new file mode 100644
index 000000000..7f4951e2a
--- /dev/null
+++ b/private/oleutest/perform/driver/makefile
@@ -0,0 +1,25 @@
+############################################################################
+#
+# Copyright (C) 1992, Microsoft Corporation.
+#
+# All rights reserved.
+#
+############################################################################
+
+!ifdef NTMAKEENV
+
+# We need to do the following so that build will stop reading from the
+# pipe.
+
+all :
+ echo $(BUILDMSG)
+
+clean : all
+
+!else # NTMAKEENV
+
+!include $(CAIROLE)\com\makefile
+
+!include $(DEPENDFILE)
+
+!endif # NTMAKEENV
diff --git a/private/oleutest/perform/le/create/makefile b/private/oleutest/perform/le/create/makefile
new file mode 100644
index 000000000..1d3728d41
--- /dev/null
+++ b/private/oleutest/perform/le/create/makefile
@@ -0,0 +1,10 @@
+############################################################################
+#
+# Copyright (C) 1992, Microsoft Corporation.
+#
+# All rights reserved.
+#
+############################################################################
+
+!include $(NTMAKEENV)\makefile.def
+
diff --git a/private/oleutest/perform/le/create/ocperf.cpp b/private/oleutest/perform/le/create/ocperf.cpp
new file mode 100644
index 000000000..9b93a2119
--- /dev/null
+++ b/private/oleutest/perform/le/create/ocperf.cpp
@@ -0,0 +1,793 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: ocperf.cpp
+//
+// Contents: OleCreate performance test
+//
+// Classes: CBareServer
+//
+// Functions:
+//
+// History: dd-mmm-yy Author Comment
+// 01-Jan-95 alexgo author
+//
+//--------------------------------------------------------------------------
+
+#include <windows.h>
+#include <ole2.h>
+#include <stdio.h>
+
+#include <initguid.h>
+
+DEFINE_GUID(CLSID_BareServer, 0xce3d5220, 0x25fa, 0x11ce, 0x90, 0xeb, 0x00,
+0x00, 0x4c, 0x75, 0x2a, 0x63);
+
+class CBareServer : public IOleObject, public IDataObject,
+ public IPersistStorage
+{
+
+public:
+
+ // IUnknown methods
+
+ STDMETHOD(QueryInterface) ( REFIID riid, LPVOID FAR* ppvObj);
+ STDMETHOD_(ULONG,AddRef) (void);
+ STDMETHOD_(ULONG,Release) (void);
+
+ // IDataObject methods
+
+ STDMETHOD(GetData) ( LPFORMATETC pformatetcIn,
+ LPSTGMEDIUM pmedium );
+ STDMETHOD(GetDataHere) ( LPFORMATETC pformatetc,
+ LPSTGMEDIUM pmedium );
+ STDMETHOD(QueryGetData) ( LPFORMATETC pformatetc );
+ STDMETHOD(GetCanonicalFormatEtc) ( LPFORMATETC pformatetc,
+ LPFORMATETC pformatetcOut);
+ STDMETHOD(SetData) ( LPFORMATETC pformatetc,
+ LPSTGMEDIUM pmedium, BOOL fRelease);
+ STDMETHOD(EnumFormatEtc) ( DWORD dwDirection,
+ LPENUMFORMATETC FAR* ppenumFormatEtc);
+ STDMETHOD(DAdvise) ( FORMATETC FAR* pFormatetc, DWORD advf,
+ IAdviseSink FAR* pAdvSink,
+ DWORD FAR* pdwConnection);
+ STDMETHOD(DUnadvise) ( DWORD dwConnection);
+ STDMETHOD(EnumDAdvise) ( LPENUMSTATDATA FAR* ppenumAdvise);
+
+ // IOleObject methods
+
+ STDMETHOD(SetClientSite) ( LPOLECLIENTSITE pClientSite);
+ STDMETHOD(GetClientSite) ( LPOLECLIENTSITE FAR* ppClientSite);
+ STDMETHOD(SetHostNames) ( LPCOLESTR szContainerApp,
+ LPCOLESTR szContainerObj);
+ STDMETHOD(Close) ( DWORD reserved);
+ STDMETHOD(SetMoniker) ( DWORD dwWhichMoniker, LPMONIKER pmk);
+ STDMETHOD(GetMoniker) ( DWORD dwAssign, DWORD dwWhichMoniker,
+ LPMONIKER FAR* ppmk);
+ STDMETHOD(InitFromData) ( LPDATAOBJECT pDataObject,
+ BOOL fCreation,
+ DWORD dwReserved);
+ STDMETHOD(GetClipboardData) ( DWORD dwReserved,
+ LPDATAOBJECT FAR* ppDataObject);
+ STDMETHOD(DoVerb) ( LONG iVerb,
+ LPMSG lpmsg,
+ LPOLECLIENTSITE pActiveSite,
+ LONG lindex,
+ HWND hwndParent,
+ const RECT FAR* lprcPosRect);
+ STDMETHOD(EnumVerbs) ( IEnumOLEVERB FAR* FAR* ppenumOleVerb);
+ STDMETHOD(Update) (void);
+ STDMETHOD(IsUpToDate) (void);
+ STDMETHOD(GetUserClassID) ( CLSID FAR* pClsid);
+ STDMETHOD(GetUserType) ( DWORD dwFormOfType,
+ LPOLESTR FAR* pszUserType);
+ STDMETHOD(SetExtent) ( DWORD dwDrawAspect, LPSIZEL lpsizel);
+ STDMETHOD(GetExtent) ( DWORD dwDrawAspect, LPSIZEL lpsizel);
+ STDMETHOD(Advise)(IAdviseSink FAR* pAdvSink,
+ DWORD FAR* pdwConnection);
+ STDMETHOD(Unadvise)( DWORD dwConnection);
+ STDMETHOD(EnumAdvise) ( LPENUMSTATDATA FAR* ppenumAdvise);
+ STDMETHOD(GetMiscStatus) ( DWORD dwAspect,
+ DWORD FAR* pdwStatus);
+ STDMETHOD(SetColorScheme) ( LPLOGPALETTE lpLogpal);
+
+ // IPeristStorage methods
+
+ STDMETHOD(GetClassID) ( LPCLSID pClassID);
+ STDMETHOD(IsDirty) (void);
+ STDMETHOD(InitNew) ( LPSTORAGE pstg);
+ STDMETHOD(Load) ( LPSTORAGE pstg);
+ STDMETHOD(Save) ( LPSTORAGE pstgSave, BOOL fSameAsLoad);
+ STDMETHOD(SaveCompleted) ( LPSTORAGE pstgNew);
+ STDMETHOD(HandsOffStorage) ( void);
+
+
+ CBareServer();
+
+private:
+
+ ~CBareServer();
+
+ ULONG _cRefs;
+ IStorage * _pstg;
+ IOleClientSite * _pclientsite;
+ IOleAdviseHolder * _poaholder;
+
+};
+
+CBareServer::CBareServer()
+{
+ _cRefs = 1;
+ _pstg = NULL;
+ _pclientsite = NULL;
+ _poaholder = NULL;
+}
+
+CBareServer::~CBareServer()
+{
+ if( _poaholder )
+ {
+ _poaholder->Release();
+ _poaholder = NULL;
+ }
+
+ if( _pclientsite )
+ {
+ _pclientsite->Release();
+ _pclientsite = NULL;
+ }
+
+ if( _pstg )
+ {
+ _pstg->Release();
+ _pstg = NULL;
+ }
+}
+
+// IUnknown methods
+
+STDMETHODIMP CBareServer::QueryInterface ( REFIID riid, LPVOID FAR* ppvObj)
+{
+ HRESULT hresult = NOERROR;
+
+ if( IsEqualIID(riid, IID_IUnknown) )
+ {
+ *ppvObj = (void *)(IOleObject *)this;
+ }
+ else if( IsEqualIID(riid, IID_IOleObject) )
+ {
+ *ppvObj = (void *)(IOleObject *)this;
+ }
+ else if( IsEqualIID(riid, IID_IDataObject) )
+ {
+ *ppvObj = (void *)(IDataObject *)this;
+ }
+ else if( IsEqualIID(riid, IID_IPersistStorage) )
+ {
+ *ppvObj = (void *)(IPersistStorage *)this;
+ }
+ else
+ {
+ hresult = E_NOINTERFACE;
+ *ppvObj = NULL;
+ }
+
+ if( hresult == NOERROR )
+ {
+ AddRef();
+ }
+
+ return hresult;
+}
+
+STDMETHODIMP_(ULONG) CBareServer::AddRef(void)
+{
+ _cRefs++;
+ return _cRefs;
+}
+
+STDMETHODIMP_(ULONG) CBareServer::Release(void)
+{
+ _cRefs--;
+
+ if( _cRefs == 0 )
+ {
+ delete this;
+ return 0;
+ }
+
+ return _cRefs;
+}
+
+// IDataObject methods
+
+STDMETHODIMP CBareServer::GetData ( LPFORMATETC pformatetcIn,
+ LPSTGMEDIUM pmedium )
+{
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP CBareServer::GetDataHere ( LPFORMATETC pformatetc,
+ LPSTGMEDIUM pmedium )
+{
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP CBareServer::QueryGetData ( LPFORMATETC pformatetc )
+{
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP CBareServer::GetCanonicalFormatEtc ( LPFORMATETC pformatetc,
+ LPFORMATETC pformatetcOut)
+{
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP CBareServer::SetData ( LPFORMATETC pformatetc,
+ LPSTGMEDIUM pmedium, BOOL fRelease)
+{
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP CBareServer::EnumFormatEtc ( DWORD dwDirection,
+ LPENUMFORMATETC FAR* ppenumFormatEtc)
+{
+ *ppenumFormatEtc = NULL;
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP CBareServer::DAdvise ( FORMATETC FAR* pFormatetc, DWORD advf,
+ IAdviseSink FAR* pAdvSink,
+ DWORD FAR* pdwConnection)
+{
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP CBareServer::DUnadvise ( DWORD dwConnection)
+{
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP CBareServer::EnumDAdvise ( LPENUMSTATDATA FAR* ppenumAdvise)
+{
+ return E_NOTIMPL;
+}
+
+// IOleObject methods
+
+STDMETHODIMP CBareServer::SetClientSite ( LPOLECLIENTSITE pClientSite)
+{
+ _pclientsite = pClientSite;
+ _pclientsite->AddRef();
+
+ return NOERROR;
+}
+
+STDMETHODIMP CBareServer::GetClientSite ( LPOLECLIENTSITE FAR* ppClientSite)
+{
+ return E_NOTIMPL;
+}
+
+
+STDMETHODIMP CBareServer::SetHostNames ( LPCOLESTR szContainerApp,
+ LPCOLESTR szContainerObj)
+{
+ return NOERROR;
+}
+
+STDMETHODIMP CBareServer::Close ( DWORD reserved)
+{
+ printf("close called\n");
+
+ if( _poaholder )
+ {
+ _poaholder->SendOnClose();
+ }
+
+ CoDisconnectObject((IOleObject *)this, 0);
+
+ return NOERROR;
+}
+
+STDMETHODIMP CBareServer::SetMoniker ( DWORD dwWhichMoniker, LPMONIKER pmk)
+{
+ return NOERROR;
+}
+
+STDMETHODIMP CBareServer::GetMoniker ( DWORD dwAssign, DWORD dwWhichMoniker,
+ LPMONIKER FAR* ppmk)
+{
+ *ppmk = NULL;
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP CBareServer::InitFromData ( LPDATAOBJECT pDataObject,
+ BOOL fCreation,
+ DWORD dwReserved)
+{
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP CBareServer::GetClipboardData ( DWORD dwReserved,
+ LPDATAOBJECT FAR* ppDataObject)
+{
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP CBareServer::DoVerb ( LONG iVerb,
+ LPMSG lpmsg,
+ LPOLECLIENTSITE pActiveSite,
+ LONG lindex,
+ HWND hwndParent,
+ const RECT FAR* lprcPosRect)
+{
+ return NOERROR;
+}
+
+STDMETHODIMP CBareServer::EnumVerbs ( IEnumOLEVERB FAR* FAR* ppenumOleVerb)
+{
+ return OLE_S_USEREG;
+}
+
+STDMETHODIMP CBareServer::Update (void)
+{
+ return NOERROR;
+}
+
+STDMETHODIMP CBareServer::IsUpToDate (void)
+{
+ return NOERROR;
+}
+
+STDMETHODIMP CBareServer::GetUserClassID ( CLSID FAR* pClsid)
+{
+ *pClsid = CLSID_BareServer;
+
+ return NOERROR;
+}
+
+STDMETHODIMP CBareServer::GetUserType ( DWORD dwFormOfType,
+ LPOLESTR FAR* pszUserType)
+{
+ return OLE_S_USEREG;
+}
+
+STDMETHODIMP CBareServer::SetExtent ( DWORD dwDrawAspect, LPSIZEL lpsizel)
+{
+ return NOERROR;
+}
+
+STDMETHODIMP CBareServer::GetExtent ( DWORD dwDrawAspect, LPSIZEL lpsizel)
+{
+ return NOERROR;
+}
+
+STDMETHODIMP CBareServer::Advise (IAdviseSink FAR* pAdvSink,
+ DWORD FAR* pdwConnection)
+{
+
+ printf("Advise called\n");
+
+ HRESULT hresult;
+
+ if( !_poaholder )
+ {
+ hresult = CreateOleAdviseHolder(&_poaholder);
+ }
+
+ if( _poaholder )
+ {
+ hresult = _poaholder->Advise(pAdvSink, pdwConnection);
+ }
+
+ return hresult;
+}
+
+STDMETHODIMP CBareServer::Unadvise ( DWORD dwConnection)
+{
+ if( _poaholder )
+ {
+ return _poaholder->Unadvise(dwConnection);
+ }
+
+ return E_FAIL;
+}
+
+STDMETHODIMP CBareServer::EnumAdvise ( LPENUMSTATDATA FAR* ppenumAdvise)
+{
+ if( _poaholder )
+ {
+ return _poaholder->EnumAdvise(ppenumAdvise);
+ }
+
+ return E_FAIL;
+}
+
+STDMETHODIMP CBareServer::GetMiscStatus ( DWORD dwAspect,
+ DWORD FAR* pdwStatus)
+{
+ return OLE_S_USEREG;
+}
+
+STDMETHODIMP CBareServer::SetColorScheme ( LPLOGPALETTE lpLogpal)
+{
+ return NOERROR;
+}
+
+
+// IPeristStorage methods
+
+STDMETHODIMP CBareServer::GetClassID ( LPCLSID pClassID)
+{
+ *pClassID = CLSID_BareServer;
+
+ return NOERROR;
+}
+
+STDMETHODIMP CBareServer::IsDirty (void)
+{
+ return NOERROR;
+}
+
+STDMETHODIMP CBareServer::InitNew ( LPSTORAGE pstg)
+{
+ printf("InitNew called\n");
+
+ _pstg = pstg;
+ _pstg->AddRef();
+
+ return NOERROR;
+}
+
+STDMETHODIMP CBareServer::Load ( LPSTORAGE pstg)
+{
+ _pstg = pstg;
+ _pstg->AddRef();
+
+ return NOERROR;
+}
+
+STDMETHODIMP CBareServer::Save ( LPSTORAGE pstgSave, BOOL fSameAsLoad)
+{
+ return NOERROR;
+}
+
+STDMETHODIMP CBareServer::SaveCompleted ( LPSTORAGE pstgNew)
+{
+ return NOERROR;
+}
+
+STDMETHODIMP CBareServer::HandsOffStorage ( void)
+{
+ _pstg->Release();
+ _pstg = NULL;
+
+ return NOERROR;
+}
+
+
+// class factory
+
+class CBareFactory : public IClassFactory
+{
+
+public:
+ STDMETHOD(QueryInterface) (REFIID iid, LPVOID FAR* ppvObj);
+ STDMETHOD_(ULONG,AddRef) (void);
+ STDMETHOD_(ULONG,Release) (void);
+ STDMETHOD(CreateInstance) (LPUNKNOWN pUnkOuter, REFIID iid,
+ LPVOID FAR* ppv);
+ STDMETHOD(LockServer) ( BOOL fLock );
+
+ CBareFactory();
+
+private:
+ ULONG _cRefs;
+};
+
+CBareFactory::CBareFactory()
+{
+ _cRefs = 1;
+}
+
+STDMETHODIMP CBareFactory::QueryInterface (REFIID iid, LPVOID FAR* ppvObj)
+{
+ if( IsEqualIID(iid, IID_IClassFactory) ||
+ IsEqualIID(iid, IID_IUnknown) )
+ {
+ *ppvObj = this;
+ AddRef();
+ return NOERROR;
+ }
+ else
+ {
+ *ppvObj = NULL;
+ return E_NOINTERFACE;
+ }
+}
+
+STDMETHODIMP_(ULONG) CBareFactory::AddRef (void)
+{
+ _cRefs++;
+ return _cRefs;
+}
+
+STDMETHODIMP_(ULONG) CBareFactory::Release (void)
+{
+ _cRefs--;
+
+ if( _cRefs == 0 )
+ {
+ delete this;
+ return 0;
+ }
+
+ return _cRefs;
+}
+
+STDMETHODIMP CBareFactory::CreateInstance (LPUNKNOWN pUnkOuter, REFIID iid,
+ LPVOID FAR* ppv)
+{
+ *ppv = (IOleObject *)new CBareServer();
+
+ return NOERROR;
+}
+
+STDMETHODIMP CBareFactory::LockServer ( BOOL fLock )
+{
+ return NOERROR;
+}
+
+// Client Site
+
+class CBareClientSite : public IOleClientSite
+{
+public:
+
+ STDMETHOD(QueryInterface)(REFIID riid, LPVOID FAR* ppvObj);
+ STDMETHOD_(ULONG, AddRef)();
+ STDMETHOD_(ULONG, Release)();
+
+ // *** IOleClientSite methods ***
+ STDMETHOD(SaveObject)();
+ STDMETHOD(GetMoniker)(DWORD dwAssign, DWORD dwWhichMoniker,
+ LPMONIKER FAR* ppmk);
+ STDMETHOD(GetContainer)(LPOLECONTAINER FAR* ppContainer);
+ STDMETHOD(ShowObject)();
+ STDMETHOD(OnShowWindow)(BOOL fShow);
+ STDMETHOD(RequestNewObjectLayout)();
+
+ CBareClientSite();
+
+private:
+
+ ULONG _cRefs;
+};
+
+CBareClientSite::CBareClientSite()
+{
+ _cRefs = 1;
+}
+
+STDMETHODIMP CBareClientSite::QueryInterface(REFIID riid, LPVOID FAR* ppvObj)
+{
+ if( IsEqualIID(riid, IID_IUnknown) ||
+ IsEqualIID(riid, IID_IOleClientSite) )
+ {
+ *ppvObj = this;
+ AddRef();
+ return NOERROR;
+ }
+ else
+ {
+ *ppvObj = NULL;
+ return E_NOINTERFACE;
+ }
+}
+
+STDMETHODIMP_(ULONG) CBareClientSite::AddRef()
+{
+ _cRefs++;
+ return _cRefs;
+}
+
+STDMETHODIMP_(ULONG) CBareClientSite::Release()
+{
+ _cRefs--;
+
+ if( _cRefs == 0 )
+ {
+ delete this;
+ return 0;
+ }
+
+ return _cRefs;
+}
+
+// *** IOleClientSite methods ***
+STDMETHODIMP CBareClientSite::SaveObject()
+{
+ return NOERROR;
+}
+
+STDMETHODIMP CBareClientSite::GetMoniker(DWORD dwAssign, DWORD dwWhichMoniker,
+ LPMONIKER FAR* ppmk)
+{
+ *ppmk = NULL;
+ return E_FAIL;
+}
+
+STDMETHODIMP CBareClientSite::GetContainer(LPOLECONTAINER FAR* ppContainer)
+{
+ *ppContainer = NULL;
+ return E_NOINTERFACE;
+}
+
+STDMETHODIMP CBareClientSite::ShowObject()
+{
+ return NOERROR;
+}
+
+STDMETHODIMP CBareClientSite::OnShowWindow(BOOL fShow)
+{
+ return NOERROR;
+}
+
+STDMETHODIMP CBareClientSite::RequestNewObjectLayout()
+{
+ return NOERROR;
+}
+
+
+void RunServerSide(void)
+{
+ DWORD dwcf = 0;
+ HWND hwnd;
+ MSG msg;
+
+ IClassFactory *pcf = new CBareFactory();
+
+ WNDCLASS wc;
+
+ // Register Clipboard window class
+ //
+ wc.style = 0;
+ wc.lpfnWndProc = DefWindowProc;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = 4;
+ wc.hInstance = NULL;
+ wc.hIcon = NULL;
+ wc.hCursor = NULL;
+ wc.hbrBackground = NULL;
+ wc.lpszMenuName = NULL;
+ wc.lpszClassName = "BareServerWindow";
+
+ // don't bother checking for errors
+ RegisterClass(&wc);
+
+ hwnd = CreateWindow("BareServerWindow","",WS_POPUP,CW_USEDEFAULT,
+ CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,
+ NULL,NULL,NULL,NULL);
+
+ CoRegisterClassObject( CLSID_BareServer, pcf, CLSCTX_LOCAL_SERVER,
+ REGCLS_MULTIPLEUSE, &dwcf );
+
+ while (GetMessage(&msg, NULL, NULL, NULL))
+ {
+ TranslateMessage(&msg); /* Translates virtual key codes */
+ DispatchMessage(&msg); /* Dispatches message to window */
+ }
+
+ CoRevokeClassObject(dwcf);
+}
+
+void RunContainerSide()
+{
+ DWORD dwStart, dwFinish, i;
+ HRESULT hresult;
+ IStorage *pstg;
+ IOleObject *poo;
+ IOleClientSite *pcs;
+
+ hresult = StgCreateDocfile(NULL, STGM_CREATE | STGM_READWRITE |
+ STGM_SHARE_EXCLUSIVE,
+ 0, &pstg);
+
+ if( hresult != NOERROR )
+ {
+ printf("CreateDocFile failed! (%lx)\n", hresult);
+ exit(hresult);
+ }
+
+ pcs = (IOleClientSite *)new CBareClientSite();
+
+ // prime the server
+
+ hresult = OleCreate( CLSID_BareServer, IID_IOleObject, OLERENDER_NONE,
+ NULL, pcs, pstg, (void **)&poo);
+
+ if( hresult != NOERROR )
+ {
+ printf("OleCreate failed! (%lx)\n", hresult);
+ exit(hresult);
+ }
+
+ hresult = OleRun(poo);
+
+ if( hresult != NOERROR )
+ {
+ printf("OleRun failed! (%lx)\n", hresult);
+ exit(hresult);
+ }
+
+ poo->Close(0);
+ poo->Release();
+ poo = NULL;
+
+ pcs->Release();
+ pcs = NULL;
+
+ for( i = 0; i < 100; i++ )
+ {
+
+ pcs = (IOleClientSite *)new CBareClientSite();
+
+ dwStart = GetTickCount();
+
+ hresult = OleCreate(CLSID_BareServer, IID_IOleObject, OLERENDER_NONE,
+ NULL, pcs, pstg, (void **)&poo);
+
+ if( hresult == NOERROR )
+ {
+ hresult = OleRun(poo);
+ }
+
+ dwFinish = GetTickCount();
+
+ if( hresult == NOERROR )
+ {
+ poo->Close(0);
+ poo->Release();
+ poo = NULL;
+
+ printf("%ld\n", dwFinish - dwStart);
+ }
+ else
+ {
+ printf("%ld failed! (%lx)\n", i, hresult);
+ }
+
+ pcs->Release();
+ pcs = NULL;
+ }
+
+ pstg->Release();
+}
+
+
+int main( int argc, char **argv )
+{
+ OleInitialize(NULL);
+
+ if( argc == 2 )
+ {
+ // assume -Embedding
+ RunServerSide();
+ }
+ else
+ {
+ RunContainerSide();
+ }
+
+ OleUninitialize();
+
+ return 0;
+}
+
+
+
+
+
diff --git a/private/oleutest/perform/le/create/ocperf.reg b/private/oleutest/perform/le/create/ocperf.reg
new file mode 100644
index 000000000..0439b06cd
--- /dev/null
+++ b/private/oleutest/perform/le/create/ocperf.reg
@@ -0,0 +1,20 @@
+REGEDIT
+HKEY_CLASSES_ROOT\OCPerf = OleCreatePerformance
+HKEY_CLASSES_ROOT\SIMPSVR\protocol\StdFileEditing\server = ocperf.exe
+HKEY_CLASSES_ROOT\SIMPSVR\protocol\StdFileEditing\verb\0 = &Edit
+HKEY_CLASSES_ROOT\SIMPSVR\protocol\StdFileEditing\verb\1 = &Open
+HKEY_CLASSES_ROOT\SIMPSVR\Insertable
+HKEY_CLASSES_ROOT\SIMPSVR\CLSID = {ce3d5220-25fa-11ce-90eb-00004c752a63}
+HKEY_CLASSES_ROOT\CLSID\{ce3d5220-25fa-11ce-90eb-00004c752a63} = OleCreatePerformance
+HKEY_CLASSES_ROOT\CLSID\{ce3d5220-25fa-11ce-90eb-00004c752a63}\Insertable
+HKEY_CLASSES_ROOT\CLSID\{ce3d5220-25fa-11ce-90eb-00004c752a63}\MiscStatus = 0
+HKEY_CLASSES_ROOT\CLSID\{ce3d5220-25fa-11ce-90eb-00004c752a63}\DefaultIcon = progman.exe,0
+HKEY_CLASSES_ROOT\CLSID\{ce3d5220-25fa-11ce-90eb-00004c752a63}\AuxUserType\2 =OCPerf
+HKEY_CLASSES_ROOT\CLSID\{ce3d5220-25fa-11ce-90eb-00004c752a63}\AuxUserType\3 = OleCreatePerformance
+HKEY_CLASSES_ROOT\CLSID\{ce3d5220-25fa-11ce-90eb-00004c752a63}\Verb\0 = &Play,0,2
+HKEY_CLASSES_ROOT\CLSID\{ce3d5220-25fa-11ce-90eb-00004c752a63}\Verb\1 = &Open,0,2
+HKEY_CLASSES_ROOT\CLSID\{ce3d5220-25fa-11ce-90eb-00004c752a63}\LocalServer32 = ocperf.exe
+HKEY_CLASSES_ROOT\CLSID\{ce3d5220-25fa-11ce-90eb-00004c752a63}\InprocHandler32 = ole32.dll
+HKEY_CLASSES_ROOT\CLSID\{ce3d5220-25fa-11ce-90eb-00004c752a63}\ProgID = OCPerf
+HKEY_CLASSES_ROOT\CLSID\{ce3d5220-25fa-11ce-90eb-00004c752a63}\DataFormats\GetSet\0 = 3,1,32,1
+
diff --git a/private/oleutest/perform/le/create/sources b/private/oleutest/perform/le/create/sources
new file mode 100644
index 000000000..e4a43aa00
--- /dev/null
+++ b/private/oleutest/perform/le/create/sources
@@ -0,0 +1,62 @@
+!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.
+
+!ENDIF
+
+!include ..\..\daytona.inc
+
+#
+# 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= ocperf
+
+#
+# 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= $(INCLUDES)
+C_DEFINES= $(C_DEFINES)
+
+SOURCES= \
+ ..\ocperf.cpp
+
+UMTYPE= console
+UMENTRY= main
+UMAPPL=
+UMTEST=
+UMLIBS= \
+ $(BASEDIR)\public\sdk\lib\*\ole32.lib \
+ $(BASEDIR)\public\sdk\lib\*\comdlg32.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\*\crtdll.lib \
+ $(BASEDIR)\public\sdk\lib\*\uuid.lib
+
+USE_CRTDLL= 1
diff --git a/private/oleutest/perform/makefile b/private/oleutest/perform/makefile
new file mode 100644
index 000000000..7f4951e2a
--- /dev/null
+++ b/private/oleutest/perform/makefile
@@ -0,0 +1,25 @@
+############################################################################
+#
+# Copyright (C) 1992, Microsoft Corporation.
+#
+# All rights reserved.
+#
+############################################################################
+
+!ifdef NTMAKEENV
+
+# We need to do the following so that build will stop reading from the
+# pipe.
+
+all :
+ echo $(BUILDMSG)
+
+clean : all
+
+!else # NTMAKEENV
+
+!include $(CAIROLE)\com\makefile
+
+!include $(DEPENDFILE)
+
+!endif # NTMAKEENV
diff --git a/private/oleutest/perform/procswap/daytona/makefile b/private/oleutest/perform/procswap/daytona/makefile
new file mode 100644
index 000000000..1d3728d41
--- /dev/null
+++ b/private/oleutest/perform/procswap/daytona/makefile
@@ -0,0 +1,10 @@
+############################################################################
+#
+# Copyright (C) 1992, Microsoft Corporation.
+#
+# All rights reserved.
+#
+############################################################################
+
+!include $(NTMAKEENV)\makefile.def
+
diff --git a/private/oleutest/perform/procswap/daytona/sources b/private/oleutest/perform/procswap/daytona/sources
new file mode 100644
index 000000000..fe706c601
--- /dev/null
+++ b/private/oleutest/perform/procswap/daytona/sources
@@ -0,0 +1,70 @@
+!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.
+
+!ENDIF
+
+!include ..\..\daytona.inc
+
+#
+# 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= procswap
+
+#
+# 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= $(INCLUDES)
+C_DEFINES= $(C_DEFINES)
+
+SOURCES= \
+ ..\procswap.cxx
+
+UMTYPE= windows
+UMENTRY= winmain
+UMAPPL=
+UMTEST=
+UMLIBS=
+
+LINKLIBS= \
+ ..\..\common\daytona\obj\*\common.lib \
+ $(OLEDIR)\ilib\daytona\obj\*\uuid.lib \
+ $(OLEDIR)\common\daytona\obj\*\common.lib \
+ $(BASEDIR)\public\sdk\lib\*\uuid.lib \
+ $(BASEDIR)\public\sdk\lib\*\ole32.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\*\rpcndr.lib \
+ $(BASEDIR)\public\sdk\lib\*\rpcrt4.lib \
+ $(BASEDIR)\public\sdk\lib\*\rpcns4.lib \
+ $(BASEDIR)\public\sdk\lib\*\ntdll.lib
+
+
+USE_CRTDLL= 1
diff --git a/private/oleutest/perform/procswap/dirs b/private/oleutest/perform/procswap/dirs
new file mode 100644
index 000000000..2084bae88
--- /dev/null
+++ b/private/oleutest/perform/procswap/dirs
@@ -0,0 +1,38 @@
+!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/perform/procswap/procswap.cxx b/private/oleutest/perform/procswap/procswap.cxx
new file mode 100644
index 000000000..862294777
--- /dev/null
+++ b/private/oleutest/perform/procswap/procswap.cxx
@@ -0,0 +1,1249 @@
+//+------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1993.
+//
+// File: procswap.cxx
+//
+// Contents: Program for measuring task switching performance
+// between two windows programs. The program creates
+// CTaskSwitch objects...
+//
+// Each Object can wait on one of three things...
+// 1. GetMessage
+// 2. MsgWaitForMultipleObjects
+// 3. WaitForSingleObject (event)
+//
+// and when awoken, will signal another Object in one
+// of three ways...
+// 1. PostMessage
+// 2. SendMessage
+// 3. SetEvent
+//
+// These cases can be combined in any manner to obtain
+// a maxtrix of possible scenarios.
+//
+// The CTaskSwitch objects can be in the same process on
+// different threads, or in different processes.
+//
+// Classes: CEvent - event handling class
+// CTaskSwitch - main task switch class
+//
+//
+// Functions: WinMain - entry point of process
+// ThreadEntry - entry point of spawned threads
+// ThreadWndProc - processes windows messages
+//
+//
+// History: 08-Feb-94 Rickhi Created
+//
+//--------------------------------------------------------------------------
+
+#include <benchmrk.hxx>
+#include <tchar.h>
+
+
+// execution parameter structure
+
+typedef struct tagSExecParms
+{
+ int oloop; // outer loop count
+ int iloop; // inner loop count
+ HWND hWndOther; // HWND of other process
+ HANDLE hEventOther; // Event Handle of other process
+ WNDPROC pfnWndProc; // ptr to WndProc function
+ TCHAR szFile[20]; // output file name
+ TCHAR szWaitEvent[20]; // event name to wait on
+ TCHAR szSignalEvent[20]; // event name to signal
+} SExecParms;
+
+
+typedef enum tagWAITTYPES
+{
+ WAIT_EVENT = 1,
+ WAIT_MSGWAITFORMULTIPLE = 2,
+ WAIT_GETMESSAGE = 3,
+ WAIT_SYNCHRONOUS = 4
+} WAITTYPES;
+
+typedef enum tagSIGNALTYPES
+{
+ SIGNAL_EVENT = 1,
+ SIGNAL_POSTMESSAGE = 2,
+ SIGNAL_SENDMESSAGE = 3,
+ SIGNAL_SYNCHRONOUS = 4
+} SIGNALTYPES;
+
+// input names corresponding to the wait types
+LPSTR aszWait[] = {"", "event", "msgwait", "getmsg", "sync", NULL};
+
+// input names corresponding to the signal types
+LPSTR aszSignal[] = {"", "event", "postmsg", "sendmsg", "sync", NULL};
+
+
+
+// Name of window class for dispatching messages.
+
+#define MY_WINDOW_CLASS TEXT("ProcSwapWindowClass")
+
+#define MAX_OLOOP 100
+
+
+// globals
+
+DWORD g_fFullInfo = 0; // write full info or not
+HINSTANCE g_hInst = NULL; // misc windows junk.
+ATOM g_MyClass = 0;
+UINT g_MyMessage = WM_USER;
+
+
+// function prototype
+LRESULT ThreadWndProc(HWND hWnd, UINT msg, WPARAM wparam, LPARAM lparam);
+DWORD ThreadEntry(void *param);
+
+
+//--------------------------------------------------------------------------
+//
+// Class: CEvent
+//
+// Purpose: class for blocking & starting threads.
+//
+//--------------------------------------------------------------------------
+
+class CEvent
+{
+public:
+ CEvent(LPTSTR szName, HRESULT &hr) { Init(szName, hr); }
+ CEvent(void) {m_hdl = NULL; }
+
+ ~CEvent() { CloseHandle(m_hdl); }
+
+ void Signal(void) { SetEvent(m_hdl); }
+ void Reset(void) { ; } // ResetEvent(m_hdl); }
+ void BlockS(void) { WaitForSingleObject(m_hdl, 60000); }
+ void BlockM(void) { WaitForMultipleObjects(1, &m_hdl, FALSE, 60000); }
+ HANDLE *GetHdl(void) { return &m_hdl; };
+
+ void Init(LPTSTR szName, HRESULT &hr);
+
+private:
+
+ HANDLE m_hdl;
+};
+
+
+void CEvent::Init(LPTSTR szName, HRESULT &hr)
+{
+ hr = S_OK;
+
+ // first try opening the event
+ m_hdl = OpenEvent(EVENT_ALL_ACCESS,
+ FALSE,
+ szName);
+
+ if (m_hdl == NULL)
+ {
+ // doesnt exist yet so create it.
+ m_hdl = CreateEvent(NULL, // security
+ FALSE, // auto reset
+ FALSE, // initially not signalled
+ szName);
+
+ if (m_hdl == NULL)
+ {
+ _tprintf (TEXT("Error Creating CEvent (%s)\n"), szName);
+ hr = GetLastError();
+ }
+ else
+ {
+ _tprintf (TEXT("Created CEvent (%s)\n"), szName);
+ }
+ }
+ else
+ {
+ _tprintf (TEXT("Opened CEvent (%s)\n"), szName);
+ }
+}
+
+
+
+//--------------------------------------------------------------------------
+//
+// Class: CTaskSwitch
+//
+// Purpose: class for timing task switches.
+//
+//--------------------------------------------------------------------------
+
+class CTaskSwitch
+{
+public:
+ CTaskSwitch(LPSTR lpszCmdLine, HRESULT &hr);
+ ~CTaskSwitch(void);
+
+ int MainProcessLoop(void);
+ LRESULT ThreadWndProc(HWND hWnd, UINT msg, WPARAM wparam, LPARAM lparam);
+ HRESULT SpawnOtherSide(void);
+
+private:
+
+ // initialization / cleanup methods
+
+ HRESULT ParseCmdLine(LPSTR lpszCmdLine, SExecParms &execp);
+ HRESULT WindowInitialize(WNDPROC pfnWndProc, HWND &hWnd);
+ void WindowUninitialize(HWND hWnd);
+ void CreateOtherParms(void);
+ void WriteExecParms(void);
+ void WriteResults(void);
+ void Help(void);
+ DWORD GetWaitType(LPSTR pszCmd);
+ DWORD GetSignalType(LPSTR pszCmd);
+ DWORD CreateProc(void);
+
+ // processing methods
+
+ HRESULT SendOrWaitFirstSignal(void);
+ void ProcessMsgWaitForMultiple(DWORD dwRet);
+ void ProcessIncommingEvent(void);
+ void UpdateLoopCounters(void);
+ void SignalOtherSide(void);
+
+ // data
+
+ BOOL g_fDone; // when to exit the loop
+ BOOL g_fKicker; // we kick the other guy
+ BOOL g_fThreadSwitch; // thread or process switching?
+ BOOL g_fWaitMultiple; // wait single or multiple
+
+ ULONG g_oloop; // outer loop counter
+ ULONG g_iloop; // inner loop counter
+
+ DWORD g_WaitType; // what to wait on
+ DWORD g_SignalType; // what to signal
+
+ // used only for parameter parseing
+ DWORD g_WaitType1; // what to wait on
+ DWORD g_SignalType1; // what to signal
+ DWORD g_WaitType2; // what to wait on
+ DWORD g_SignalType2; // what to signal
+
+
+ HWND g_hWndOther; // hWnd of other side
+ HWND g_hWndMe; // my hWnd
+
+ CEvent g_WaitEvent; // event to wait on
+ CEvent g_SignalEvent; // event to signal
+
+ ULONG g_time[MAX_OLOOP]; // place to store the timings.
+ CStopWatch g_timer; // global timer proc 1
+
+ SExecParms g_execp; // execution parameters
+ CTestOutput * g_output; // output log
+
+ HRESULT g_hr; // result code
+
+ CHAR g_szOtherParms[MAX_PATH]; // parm string for other guy
+};
+
+
+
+
+// task switch objects - must be global for ThreadWndProc
+
+CTaskSwitch *g_pTaskSwitch1 = NULL;
+CTaskSwitch *g_pTaskSwitch2 = NULL;
+
+
+//--------------------------------------------------------------------------
+//
+// WinMain - main entry point of program. May just call ThreadEntry, or
+// may spawn another thread in the case of thread switching.
+//
+//
+//--------------------------------------------------------------------------
+
+int WinMain(HINSTANCE hinst, HINSTANCE hPrev, LPSTR lpszCmdLine, int CmdShow)
+{
+ HRESULT hr;
+
+ // create the first task switch object for this process
+ g_pTaskSwitch1 = new CTaskSwitch(lpszCmdLine, hr);
+
+ if (hr == S_OK)
+ {
+ // spawn a new thread or a new process to do task switching with.
+ hr = g_pTaskSwitch1->SpawnOtherSide();
+
+ if (hr == S_OK)
+ {
+ // enter the main processing loop
+ g_pTaskSwitch1->MainProcessLoop();
+ }
+ }
+
+ // print the results
+ delete g_pTaskSwitch1;
+ return 1;
+}
+
+
+
+//--------------------------------------------------------------------------
+//
+// ThreadEntry - main entry point for a thread spawned by CreateThread
+// in the case of task switching between threads.
+//
+// Creates an instance of the CTaskSwitch class and invokes it
+// main function.
+//
+//--------------------------------------------------------------------------
+
+DWORD ThreadEntry(void *param)
+{
+ LPSTR lpszCmdLine = (LPSTR) param;
+
+ HRESULT hr;
+
+ // create the second task switch object for this process
+ g_pTaskSwitch2 = new CTaskSwitch(lpszCmdLine, hr);
+
+ if (hr == S_OK)
+ {
+ // enter the main processing loop
+ g_pTaskSwitch2->MainProcessLoop();
+ }
+
+ // print the results
+ delete g_pTaskSwitch2;
+ return hr;
+}
+
+
+
+
+//--------------------------------------------------------------------------
+//
+// Dipatch to the correct CTaskSwitch object if the message is our
+// special message.
+//
+//--------------------------------------------------------------------------
+
+LRESULT ThreadWndProc(HWND hWnd, UINT msg, WPARAM wparam, LPARAM lparam)
+{
+ if (msg == g_MyMessage)
+ {
+ // its my special message, go handle it.
+ // here i have to select which object to dispatch to for the
+ // multithreaded case. i base that decision on lparam.
+
+ if (lparam == 0)
+ {
+ // use the first task switch object
+ return g_pTaskSwitch1->ThreadWndProc(hWnd, msg, wparam, lparam);
+ }
+ else
+ {
+ // use the second task switch object
+ return g_pTaskSwitch2->ThreadWndProc(hWnd, msg, wparam, lparam);
+ }
+ }
+ else
+ {
+ // let the default window procedure have the message.
+ return DefWindowProc(hWnd, msg, wparam, lparam);
+ }
+}
+
+
+
+
+//--------------------------------------------------------------------------
+//
+// Constructor : parse the command line, create the events, create the
+// window, and open a log file.
+//
+//--------------------------------------------------------------------------
+
+CTaskSwitch::CTaskSwitch(LPSTR lpszCmdLine, HRESULT &hr) :
+ g_fDone(FALSE),
+ g_fKicker(FALSE),
+ g_fThreadSwitch(FALSE),
+ g_fWaitMultiple(FALSE),
+ g_oloop(10),
+ g_iloop(100),
+ g_WaitType(WAIT_EVENT),
+ g_SignalType(SIGNAL_EVENT),
+ g_hWndMe(NULL),
+ g_hWndOther(NULL),
+ g_output(NULL),
+ g_hr(S_OK)
+{
+ // parse command line and write the parms to log file.
+ g_hr = ParseCmdLine(lpszCmdLine, g_execp);
+
+ if (g_hr == S_OK)
+ {
+ // Create a log file & write execution parameters
+ g_output = new CTestOutput(g_execp.szFile);
+ WriteExecParms();
+
+ // create the window for this thread
+ g_hr = WindowInitialize(g_execp.pfnWndProc, g_hWndMe);
+ if (g_hr == S_OK)
+ {
+ // Create the Wait event.
+ g_WaitEvent.Init(g_execp.szWaitEvent, g_hr);
+ if (g_hr == S_OK)
+ {
+ // Create the Signal event.
+ g_SignalEvent.Init(g_execp.szSignalEvent, g_hr);
+
+ if (g_hr == S_OK)
+ {
+ // create paramters to send to other side.
+ CreateOtherParms();
+ }
+ }
+ }
+ }
+
+ // return the results
+ hr = g_hr;
+}
+
+
+//--------------------------------------------------------------------------
+//
+// Desructor
+//
+//--------------------------------------------------------------------------
+
+CTaskSwitch::~CTaskSwitch(void)
+{
+ // write the results
+ WriteResults();
+
+ // cleanup window registration
+ WindowUninitialize(g_hWndMe);
+
+ // close the log file
+ delete g_output;
+}
+
+
+//--------------------------------------------------------------------------
+//
+// Spawns either another process or another thread to perform the task
+// switching with.
+//
+//--------------------------------------------------------------------------
+
+HRESULT CTaskSwitch::SpawnOtherSide(void)
+{
+ if (g_fKicker)
+ {
+ // i'm already the second entry, dont spawn anything.
+ // sleep for a bit to make sure both sides are ready
+ // when i kick things off.
+
+ Sleep(1000);
+ return S_OK;
+ }
+
+
+ if (g_fThreadSwitch)
+ {
+ // spawn a thread
+
+ HANDLE hdl;
+ DWORD dwId;
+ hdl = CreateThread(NULL, // default security
+ 0, // default stack size
+ ThreadEntry, // entry point
+ g_szOtherParms, // command line parms
+ 0, // flags
+ &dwId); // threadid
+
+ if (hdl)
+ {
+ // dont need the handle
+ CloseHandle(hdl);
+ }
+ else
+ {
+ // what went wrong?
+ return GetLastError();
+ }
+ }
+ else
+ {
+ // spawn a process
+ DWORD dwRet = CreateProc();
+ if (dwRet != S_OK)
+ {
+ return dwRet;
+ }
+ }
+
+ return S_OK;
+}
+
+
+
+//--------------------------------------------------------------------------
+//
+// MainProcessLoop - does the main wait & process the event
+//
+//--------------------------------------------------------------------------
+
+int CTaskSwitch::MainProcessLoop(void)
+{
+ MSG msg;
+ DWORD dwRet;
+
+
+ // Send, or wait on, the first signal.
+ SendOrWaitFirstSignal();
+
+
+ // Reset the timer and enter the main loop.
+ g_timer.Reset();
+
+
+ // wait loop - based on the type of event we should receive, we
+ // wait here until such an event occurs. Then we send a signal
+ // to the other side based on what it expects from us.
+
+ while (!g_fDone)
+ {
+ switch (g_WaitType)
+ {
+
+ case WAIT_MSGWAITFORMULTIPLE:
+
+ // wait here for a message or an event to be signalled
+ dwRet = MsgWaitForMultipleObjects(1,
+ g_WaitEvent.GetHdl(),
+ FALSE,
+ 600000,
+ QS_ALLINPUT);
+
+ // Dispatch to ThreadWndProc if a message, or
+ // to ProcessEvent if an event was signalled
+ ProcessMsgWaitForMultiple(dwRet);
+ break;
+
+
+ case WAIT_GETMESSAGE:
+
+ // wait for a windows message
+ if (GetMessage(&msg, NULL, 0, 0))
+ {
+ // dispatches to my ThreadWndProc
+ DispatchMessage(&msg);
+ }
+ break;
+
+
+ case WAIT_EVENT:
+
+ // wait for the event to be signalled
+ if (g_fWaitMultiple)
+ g_WaitEvent.BlockM();
+ else
+ g_WaitEvent.BlockS();
+
+ // process the event
+ ProcessIncommingEvent();
+ break;
+
+
+ case WAIT_SYNCHRONOUS:
+
+ // we have a synchronous singal to the other side, so there is
+ // nothing to wait on, we will just go make another synchronous
+ // call. this is valid only if the g_SignalType is
+ // SIGNAL_SENDMESSAGE.
+
+ ProcessIncommingEvent();
+ break;
+
+
+ default:
+
+ // unknown event
+ break;
+ }
+
+ } // while
+
+ return msg.wParam; // Return value from PostQuitMessage
+}
+
+
+
+//--------------------------------------------------------------------------
+//
+// processes a wakeup from MsgWaitForMultiple. Determines if the event was
+// a message arrival (in which case it Peeks it and Dispatches it, or if it
+// was an event signalled, in which case it calls the event handler.
+//
+//--------------------------------------------------------------------------
+
+void CTaskSwitch::ProcessMsgWaitForMultiple(DWORD dwRet)
+{
+ MSG msg;
+
+ if (dwRet == WAIT_OBJECT_0)
+ {
+ // our event got signalled, update the counters
+ ProcessIncommingEvent();
+ }
+
+ else if (dwRet == WAIT_OBJECT_0 + 1)
+ {
+ // some windows message was received. dispatch it.
+
+ if (PeekMessage(&msg, g_hWndMe, 0, 0, PM_REMOVE))
+ {
+ DispatchMessage(&msg);
+ }
+ }
+ else
+ {
+ // our event timed out or our event was abandoned or
+ // an error occurred.
+
+ g_fDone = TRUE;
+ }
+}
+
+
+
+//--------------------------------------------------------------------------
+//
+// processes an incomming event. Just updates the counters and
+// signals the other side.
+//
+//--------------------------------------------------------------------------
+
+void CTaskSwitch::ProcessIncommingEvent(void)
+{
+ // update the loop counters
+ UpdateLoopCounters();
+
+ // Signal the other side
+ SignalOtherSide();
+}
+
+
+
+//--------------------------------------------------------------------------
+//
+// process the incomming message
+//
+//--------------------------------------------------------------------------
+
+LRESULT CTaskSwitch::ThreadWndProc(HWND hWnd, UINT msg, WPARAM wparam, LPARAM lparam)
+{
+ // save the callers hWnd
+ g_hWndOther = (HWND) wparam;
+
+ // process as usual
+ ProcessIncommingEvent();
+
+ return 0;
+}
+
+
+
+//--------------------------------------------------------------------------
+//
+// updates the global loop counters, reseting the time when the inner
+// loop counter expires, and setting the fDone when the outer and inner
+// loop counters expire.
+//
+//--------------------------------------------------------------------------
+
+void CTaskSwitch::UpdateLoopCounters(void)
+{
+ if (g_iloop == 0)
+ {
+ // get time for latest outer loop
+ g_time[g_oloop] = g_timer.Read();
+
+ if (g_oloop == 0)
+ {
+ // that was the last outerloop, we're done.
+ g_fDone = TRUE;
+ }
+ else
+ {
+ // update the counters
+ g_iloop = g_execp.iloop;
+ --g_oloop;
+
+ // restart the timer
+ g_timer.Reset();
+ }
+ }
+ else
+ {
+ // just update the inner loop count
+ --g_iloop;
+ }
+}
+
+
+
+//--------------------------------------------------------------------------
+//
+// signals the other process or thread according to the SendType (either
+// signals an event or posts a message).
+//
+//--------------------------------------------------------------------------
+
+void CTaskSwitch::SignalOtherSide(void)
+{
+ switch (g_SignalType)
+ {
+
+ case SIGNAL_EVENT:
+
+ // signal the other sides event
+ g_SignalEvent.Signal();
+ break;
+
+
+ case SIGNAL_POSTMESSAGE:
+
+ // post a message to the other sides window handle.
+ // lparam tells ThreadWndProc which object to dispatch to, either
+ // g_pTaskSwitch1 or g_pTaskSwitch2. We only go to 2 if we are
+ // doing thread switches AND the poster is not the kicker.
+
+ PostMessage(g_hWndOther,
+ g_MyMessage,
+ (WPARAM)g_hWndMe,
+ (g_fThreadSwitch && !g_fKicker));
+ break;
+
+
+ case SIGNAL_SENDMESSAGE:
+
+ // send a message to the other side. this is a synchronous
+ // event. see comment in PostMessage above regarding lparam.
+
+ SendMessage(g_hWndOther,
+ g_MyMessage,
+ (WPARAM)g_hWndMe,
+ (g_fThreadSwitch && !g_fKicker));
+ break;
+
+
+ case SIGNAL_SYNCHRONOUS:
+
+ // the event we received is a synchronous event. there is no need
+ // to do anything to wake the other side.
+
+ break;
+
+
+ default:
+
+ // unknown signal type
+ break;
+ }
+}
+
+
+//--------------------------------------------------------------------------
+//
+// signals the other process or thread that it can begin the test. this
+// avoids timings skewed due to process startup latency.
+//
+//--------------------------------------------------------------------------
+
+HRESULT CTaskSwitch::SendOrWaitFirstSignal(void)
+{
+ if (g_fKicker)
+ {
+ // send a signal to drop the otherside into its wait loop, and
+ // then call SignalOtherSide to start the cycle, kicking the
+ // other side out of his first wait.
+
+ printf ("Initial Signal to Other Side\n");
+ g_SignalEvent.Signal();
+ SignalOtherSide();
+ }
+ else
+ {
+ printf ("Waiting for Signal From Other Side\n");
+ g_WaitEvent.BlockS();
+ }
+
+ return S_OK;
+}
+
+
+
+//--------------------------------------------------------------------------
+//
+// initializes the window with the specified window proc.
+//
+//--------------------------------------------------------------------------
+
+HRESULT CTaskSwitch::WindowInitialize(WNDPROC pfnWndProc, HWND &hWnd)
+{
+
+ if (!g_MyMessage)
+ {
+ // Register my message type
+ g_MyMessage = RegisterWindowMessage(
+ TEXT("Component Object Model Remote Request Arrival") );
+ }
+
+ if (!g_MyClass)
+ {
+ // Register my window class.
+ WNDCLASS wcls;
+
+ wcls.style = 0;
+ wcls.lpfnWndProc = pfnWndProc;
+ wcls.cbClsExtra = 0;
+ wcls.cbWndExtra = 0;
+ wcls.hInstance = g_hInst;
+ wcls.hIcon = NULL;
+ wcls.hCursor = NULL;
+ wcls.hbrBackground = (HBRUSH) COLOR_BACKGROUND + 1;
+ wcls.lpszMenuName = NULL;
+ wcls.lpszClassName = MY_WINDOW_CLASS;
+
+ g_MyClass = RegisterClass( &wcls );
+ }
+
+
+ if (g_MyClass)
+ {
+ // Create a hidden window.
+ hWnd = CreateWindowEx( 0,
+ (LPCTSTR) g_MyClass,
+ TEXT("Task Switcher"),
+ WS_DISABLED,
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ NULL,
+ NULL,
+ g_hInst,
+ NULL );
+
+
+ if (hWnd)
+ {
+ printf ("Created Window with hWnd %x\n", hWnd);
+ return S_OK;
+ }
+ }
+
+ return E_OUTOFMEMORY;
+}
+
+
+//--------------------------------------------------------------------------
+//
+// destroys the window and unregisters the class.
+//
+//--------------------------------------------------------------------------
+
+void CTaskSwitch::WindowUninitialize(HWND hWnd)
+{
+ if (hWnd != NULL)
+ {
+ DestroyWindow(hWnd);
+ }
+
+ if (g_MyClass != 0)
+ {
+ UnregisterClass(MY_WINDOW_CLASS, g_hInst);
+ }
+}
+
+
+
+//--------------------------------------------------------------------------
+//
+// parses the command line and returns the execution parameters
+//
+//--------------------------------------------------------------------------
+
+HRESULT CTaskSwitch::ParseCmdLine(LPSTR lpszCmdLine, SExecParms &execp)
+{
+ BOOL fFile = FALSE;
+
+ // set the default values for execution parameters.
+
+ execp.oloop = 10;
+ execp.iloop = 100;
+ execp.hWndOther = NULL;
+ execp.pfnWndProc = ::ThreadWndProc;
+
+
+
+ // check the input parameters
+
+ LPSTR pszCmd = lpszCmdLine;
+ LPSTR pszCmdNext = NULL;
+
+ while (pszCmd)
+ {
+ pszCmdNext = strchr(pszCmd, ' ');
+ if (pszCmdNext)
+ {
+ *pszCmdNext = '\0';
+ pszCmdNext++;
+ }
+
+ // check for outer loop count
+ if (!_strnicmp(pszCmd, "/o:", 3))
+ {
+ execp.oloop = atoi (pszCmd+3);
+ if (execp.oloop > MAX_OLOOP)
+ execp.oloop = MAX_OLOOP;
+ }
+
+ // check for inner loop count
+ else if (!_strnicmp(pszCmd, "/i:", 3))
+ {
+ execp.iloop = atoi (pszCmd+3);
+ if (execp.iloop < 1)
+ execp.iloop = 1;
+ }
+
+ // check for window handle
+ else if (!_strnicmp(pszCmd, "/hwnd:", 6))
+ {
+ execp.hWndOther = (HWND) atoi (pszCmd+6);
+ }
+
+ // check for waiter or Kicker
+ else if (!_strnicmp(pszCmd, "/k", 2))
+ {
+ g_fKicker = TRUE;
+ }
+
+ // check for thread or process switch
+ else if (!_strnicmp(pszCmd, "/p", 2))
+ {
+ g_fThreadSwitch = FALSE;
+ }
+
+ // check for thread or process switch
+ else if (!_strnicmp(pszCmd, "/t", 2))
+ {
+ g_fThreadSwitch = TRUE;
+ }
+
+ // check for wait single or multiple
+ else if (!_strnicmp(pszCmd, "/m", 2))
+ {
+ g_fWaitMultiple = TRUE;
+ }
+
+ // check for wait event name
+ else if (!_strnicmp(pszCmd, "/e1:", 4))
+ {
+#ifdef UNICODE
+ mbstowcs(execp.szWaitEvent, pszCmd+4, strlen(pszCmd+4)+1);
+#else
+ strcpy(execp.szWaitEvent, pszCmd+4);
+#endif
+ }
+
+ // check for signal event name
+ else if (!_strnicmp(pszCmd, "/e2:", 4))
+ {
+#ifdef UNICODE
+ mbstowcs(execp.szSignalEvent, pszCmd+4, strlen(pszCmd+4)+1);
+#else
+ strcpy(execp.szSignalEvent, pszCmd+4);
+#endif
+ }
+
+ // check for output file name
+ else if (!_strnicmp(pszCmd, "/f:", 3))
+ {
+ fFile = TRUE;
+#ifdef UNICODE
+ mbstowcs(execp.szFile, pszCmd+3, strlen(pszCmd+3)+1);
+#else
+ strcpy(execp.szFile, pszCmd+3);
+#endif
+ }
+
+ // check for wait type
+ else if (!_strnicmp(pszCmd, "/w1:", 4))
+ {
+ g_WaitType1 = GetWaitType(pszCmd+4);
+ }
+ else if (!_strnicmp(pszCmd, "/w2:", 4))
+ {
+ g_WaitType2 = GetWaitType(pszCmd+4);
+ }
+
+ // check for signal type
+ else if (!_strnicmp(pszCmd, "/s1:", 4))
+ {
+ g_SignalType1 = GetSignalType(pszCmd+4);
+ }
+ else if (!_strnicmp(pszCmd, "/s2:", 4))
+ {
+ g_SignalType2 = GetSignalType(pszCmd+4);
+ }
+
+ // check for help request
+ else if ((!_strnicmp(pszCmd, "/?", 2)) || (!_strnicmp(pszCmd, "/h", 2)))
+ {
+ Help();
+ return -1;
+ }
+
+ pszCmd = pszCmdNext;
+ }
+
+
+ g_iloop = execp.iloop;
+ g_oloop = execp.iloop;
+ g_hWndOther = execp.hWndOther;
+
+
+ if (g_fKicker)
+ {
+ g_WaitType = g_WaitType2;
+ g_SignalType = g_SignalType2;
+ if (!fFile)
+ _tcscpy(execp.szFile, TEXT("kicker"));
+ }
+ else
+ {
+ g_WaitType = g_WaitType1;
+ g_SignalType = g_SignalType1;
+ if (!fFile)
+ _tcscpy(execp.szFile, TEXT("waiter"));
+
+ }
+
+ return S_OK;
+}
+
+
+
+DWORD CTaskSwitch::GetWaitType(LPSTR pszCmd)
+{
+ ULONG i=0;
+
+ while (aszWait[++i]) // slot 0 is not used
+ {
+ if (!_stricmp(pszCmd, aszWait[i]))
+ return i;
+ }
+
+ Help();
+ return 0;
+}
+
+
+DWORD CTaskSwitch::GetSignalType(LPSTR pszCmd)
+{
+ ULONG i=0;
+
+ while (aszSignal[++i]) // slot 0 is not used
+ {
+ if (!_stricmp(pszCmd, aszSignal[i]))
+ return i;
+ }
+
+ Help();
+ return 0;
+}
+
+
+
+//--------------------------------------------------------------------------
+//
+// creates the command line parameters for the other guy
+//
+//--------------------------------------------------------------------------
+
+void CTaskSwitch::CreateOtherParms(void)
+{
+
+
+
+
+ // write the formatted parms to the parm string
+
+ sprintf(g_szOtherParms, "/k %s %s /i:%d /o:%d /hWnd:%ld "
+ "/e1:%hs /e2:%hs /w1:%s /s1:%s /w2:%s /s2:%s",
+ (g_fThreadSwitch) ? "/t" : "/p",
+ (g_fWaitMultiple) ? "/m" : " ",
+ g_execp.iloop, // same loop counts as me
+ g_execp.oloop,
+ g_hWndMe, // posts to my window
+ g_execp.szSignalEvent, // it waits on my signal event
+ g_execp.szWaitEvent, // it signals my wait event
+ aszWait[g_WaitType1], // signal what i wait on
+ aszSignal[g_SignalType1], // wait on what i signal
+ aszWait[g_WaitType2], // signal what i wait on
+ aszSignal[g_SignalType2]); // wait on what i signal
+
+}
+
+
+
+//--------------------------------------------------------------------------
+//
+// writes the execution parameters to a log file.
+//
+//--------------------------------------------------------------------------
+
+void CTaskSwitch::WriteExecParms()
+{
+ // write the run parameters to the output file
+
+ g_output->WriteString(TEXT("Using Parametes:\n"));
+ g_output->WriteResult(TEXT("\tInner Loop Count = "), g_execp.iloop);
+ g_output->WriteResult(TEXT("\tOuter Loop Count = "), g_execp.oloop);
+ g_output->WriteString(TEXT("\n\n"));
+
+ // flush to avoid disk io during the test
+ g_output->Flush();
+}
+
+
+//--------------------------------------------------------------------------
+//
+// writes the results to a log file.
+//
+//--------------------------------------------------------------------------
+
+void CTaskSwitch::WriteResults(void)
+{
+ if (g_hr == S_OK)
+ {
+ // compute the averages
+
+ ULONG tTotal = 0;
+
+ // skip the first & last value as they are sometimes skewed
+ for (int i=0; i<g_execp.oloop; i++)
+ {
+ tTotal += g_time[i];
+ }
+
+ // compute average for 1 call/response
+ tTotal /= (g_execp.oloop * g_execp.iloop);
+
+
+ // display the results
+
+ g_output->WriteResults(TEXT("Times "), g_execp.oloop, g_time);
+ g_output->WriteResult(TEXT("\nAverage "), tTotal);
+ }
+}
+
+
+//--------------------------------------------------------------------------
+//
+// writes the help info to the screen
+//
+//--------------------------------------------------------------------------
+
+void CTaskSwitch::Help()
+{
+ printf ("msgtask\n");
+ printf ("\t/o:<nnn> - outer loop count def 10\n");
+ printf ("\t/i:<nnn> - inner loop count def 100\n");
+ printf ("\t/f:<name> - name of output file. def [kick | wait]\n");
+ printf ("\t/w1:<event|getmsg|msgwait> - what to wait on\n");
+ printf ("\t/s1:<event|postmsg> - what to signal\n");
+ printf ("\t/w2:<event|getmsg|msgwait> - what to wait on\n");
+ printf ("\t/s2:<event|postmsg> - what to signal\n");
+ printf ("\t/e1:<name> - name of wait event\n");
+ printf ("\t/e2:<name> - name of signal event\n");
+ printf ("\t/k - kicker (as opposed to waiter)\n");
+ printf ("\t/t - use thread switching\n");
+ printf ("\t/p - use process switching\n");
+ printf ("\t/m - use WaitMultiple vs WaitSingle\n");
+ printf ("\t/hWnd:<nnnn> - window handle of other side\n");
+
+ printf ("\n");
+ printf ("timings are given for the inner loop count calls\n");
+
+ return;
+}
+
+
+//--------------------------------------------------------------------------
+//
+// creates a process
+//
+//--------------------------------------------------------------------------
+
+DWORD CTaskSwitch::CreateProc(void)
+{
+ // create the command line
+
+ TCHAR szCmdLine[256];
+
+ _stprintf(szCmdLine, TEXT("ntsd procswap %hs"), g_szOtherParms);
+
+
+
+ // build the win32 startup info structure
+
+ STARTUPINFO startupinfo;
+ startupinfo.cb = sizeof(STARTUPINFO);
+ startupinfo.lpReserved = NULL;
+ startupinfo.lpDesktop = NULL;
+ startupinfo.lpTitle = TEXT("Task Switcher");
+ startupinfo.dwX = 40;
+ startupinfo.dwY = 40;
+ startupinfo.dwXSize = 80;
+ startupinfo.dwYSize = 40;
+ startupinfo.dwFlags = 0;
+ startupinfo.wShowWindow = SW_SHOWNORMAL;
+ startupinfo.cbReserved2 = 0;
+ startupinfo.lpReserved2 = NULL;
+
+ PROCESS_INFORMATION ProcInfo;
+
+
+ BOOL fRslt = CreateProcess(NULL, // app name
+ szCmdLine, // command line
+ NULL, // lpsaProcess
+ NULL, // lpsaThread
+ FALSE, // inherit handles
+ CREATE_NEW_CONSOLE,// creation flags
+ NULL, // lpEnvironment
+ NULL, // curr Dir
+ &startupinfo, // Startup Info
+ &ProcInfo); // process info
+
+ if (fRslt)
+ {
+ // we dont need the handles
+ CloseHandle(ProcInfo.hProcess);
+ CloseHandle(ProcInfo.hThread);
+ printf ("Created Process (%ws) pid=%x\n", szCmdLine, ProcInfo.dwProcessId);
+ return S_OK;
+ }
+ else
+ {
+ // what went wrong?
+ DWORD dwRet = GetLastError();
+ printf ("CreateProcess (%ws) failed %x\n", szCmdLine, dwRet);
+ return dwRet;
+ }
+}
diff --git a/private/oleutest/perform/rawrpc/daytona/makefile b/private/oleutest/perform/rawrpc/daytona/makefile
new file mode 100644
index 000000000..1d3728d41
--- /dev/null
+++ b/private/oleutest/perform/rawrpc/daytona/makefile
@@ -0,0 +1,10 @@
+############################################################################
+#
+# Copyright (C) 1992, Microsoft Corporation.
+#
+# All rights reserved.
+#
+############################################################################
+
+!include $(NTMAKEENV)\makefile.def
+
diff --git a/private/oleutest/perform/rawrpc/daytona/sources b/private/oleutest/perform/rawrpc/daytona/sources
new file mode 100644
index 000000000..c466f2145
--- /dev/null
+++ b/private/oleutest/perform/rawrpc/daytona/sources
@@ -0,0 +1,72 @@
+!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.
+
+!ENDIF
+
+!include ..\..\daytona.inc
+
+#
+# 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= rawrpc
+
+#
+# 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= $(INCLUDES)
+C_DEFINES= $(C_DEFINES)
+
+SOURCES= \
+ ..\rawrpc_s.c \
+ ..\rawrpc_y.c \
+ ..\rawrpc.cxx
+
+UMTYPE= console
+UMENTRY= main
+UMAPPL=
+UMTEST=
+UMLIBS=
+
+LINKLIBS= \
+ ..\..\common\daytona\obj\*\common.lib \
+ ..\..\cairole\dll\daytona\obj\*\oletest.obj \
+ $(OLEDIR)\common\daytona\obj\*\common.lib \
+ $(BASEDIR)\public\sdk\lib\*\uuid.lib \
+ $(BASEDIR)\public\sdk\lib\*\ole32.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\*\crtdll.lib \
+ $(BASEDIR)\public\sdk\lib\*\rpcndr.lib \
+ $(BASEDIR)\public\sdk\lib\*\rpcrt4.lib \
+ $(BASEDIR)\public\sdk\lib\*\rpcns4.lib \
+
+
+USE_CRTDLL= 1
diff --git a/private/oleutest/perform/rawrpc/dirs b/private/oleutest/perform/rawrpc/dirs
new file mode 100644
index 000000000..2084bae88
--- /dev/null
+++ b/private/oleutest/perform/rawrpc/dirs
@@ -0,0 +1,38 @@
+!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/perform/rawrpc/rawrpc.cxx b/private/oleutest/perform/rawrpc/rawrpc.cxx
new file mode 100644
index 000000000..8bf02c0f2
--- /dev/null
+++ b/private/oleutest/perform/rawrpc/rawrpc.cxx
@@ -0,0 +1,292 @@
+//+------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1993.
+//
+// File: rawrpc.cxx
+//
+// Contents: definitions for benchmark test
+//
+// Classes:
+//
+// Functions:
+//
+// History: 08-Feb-94 Rickhi Created
+//
+//--------------------------------------------------------------------------
+
+#include <windows.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <rpc.h>
+#include <rawrpc.h>
+
+extern "C" const GUID IID_IRawRpc;
+
+
+int _cdecl main (int argc, char ** argv)
+{
+ // start Rpc
+ RPC_STATUS rc;
+#ifdef USE_MSWMSG
+ LPTSTR pszProtseq = TEXT("mswmsg");
+ MSG msg;
+#else
+ LPTSTR pszProtseq = TEXT("ncalrpc");
+#endif
+ LPTSTR pszEndPoint = TEXT("99999.99999");
+ HANDLE hEvent;
+
+#ifdef UNICODE
+ rc = RpcServerUseProtseqEp(pszProtseq,
+ RPC_C_PROTSEQ_MAX_REQS_DEFAULT,
+ pszEndPoint,
+ NULL);
+#else
+ rc = RpcServerUseProtseqEp((unsigned char *)pszProtseq,
+ RPC_C_PROTSEQ_MAX_REQS_DEFAULT,
+ (unsigned char *)pszEndPoint,
+ NULL);
+#endif
+ if (rc != RPC_S_OK)
+ {
+ return rc;
+ }
+
+
+ rc = RpcServerRegisterIf(IRawRpc_ServerIfHandle, 0, 0);
+ if (rc != RPC_S_OK)
+ {
+ return rc;
+ }
+
+
+ I_RpcSsDontSerializeContext();
+
+ //
+ // Signal the client that we're up and running
+ //
+ hEvent = CreateEvent(NULL, TRUE, FALSE,
+ TEXT("OleBenchRawRpcServerStarted"));
+
+ // start server listening. this call blocks until we get an
+ // RpcMgmtStopServerListening call.
+
+ rc = RpcServerListen(1, 0xffff, 1);
+ if (rc != RPC_S_OK)
+ {
+ CloseHandle(hEvent);
+ return rc;
+ }
+ if (!SetEvent(hEvent))
+ {
+ CloseHandle(hEvent);
+ return GetLastError();
+ }
+ CloseHandle(hEvent);
+
+#ifdef USE_MSWMSG
+ while (GetMessage(&msg, NULL, 0, 0))
+ {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+#endif
+ rc = RpcMgmtWaitServerListen();
+ if (rc != RPC_S_OK)
+ {
+ return rc;
+ }
+
+ // done, exit.
+ return 0;
+}
+
+
+
+// Server side of Rpc functions.
+
+SCODE Quit(handle_t hRpc)
+{
+ SCODE rc;
+
+ rc = RpcMgmtStopServerListening(NULL);
+#ifdef USE_MSWMSG
+ PostQuitMessage(0);
+#endif
+ return rc;
+}
+
+
+//+-------------------------------------------------------------------------
+//
+// Method: Void
+//
+// Synopsis: tests passing no parameters
+//
+// Arguments:
+//
+// Returns:
+//
+// History: 06-Aug-92 Rickhi Created
+//
+//--------------------------------------------------------------------------
+void Void(handle_t hRpc)
+{
+ return;
+}
+
+SCODE VoidRC(handle_t hRpc)
+{
+ return RPC_S_OK;
+}
+
+SCODE VoidPtrIn(handle_t hRpc, ULONG cb, void *pv)
+{
+ return RPC_S_OK;
+}
+
+SCODE VoidPtrOut(handle_t hRpc, ULONG cb, ULONG *pcb, void *pv)
+{
+ memset(pv, 1, cb);
+ *pcb = cb;
+ return RPC_S_OK;
+}
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: Dword
+//
+// Synopsis: tests passing dwords in and out
+//
+// Arguments:
+//
+// Returns: RPC_S_OK
+//
+// History: 06-Aug-92 Ricksa Created
+//
+//--------------------------------------------------------------------------
+SCODE DwordIn(handle_t hRpc, DWORD dw)
+{
+ return RPC_S_OK;
+}
+
+
+SCODE DwordOut(handle_t hRpc, DWORD *pdw)
+{
+ *pdw = 1;
+ return RPC_S_OK;
+}
+
+
+SCODE DwordInOut(handle_t hRpc, DWORD *pdw)
+{
+ *pdw = 1;
+ return RPC_S_OK;
+}
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: Li
+//
+// Synopsis: tests passing LARGE INTEGERS in and out
+//
+// Arguments:
+//
+// Returns: RPC_S_OK
+//
+// History: 06-Aug-92 Ricksa Created
+//
+//--------------------------------------------------------------------------
+
+SCODE LiIn(handle_t hRpc, LARGE_INTEGER li)
+{
+ return RPC_S_OK;
+}
+
+
+SCODE LiOut(handle_t hRpc, LARGE_INTEGER *pli)
+{
+ pli->LowPart = 0;
+ pli->HighPart = 1;
+ return RPC_S_OK;
+}
+
+
+SCODE ULiIn(handle_t hRpc, ULARGE_INTEGER uli)
+{
+ return RPC_S_OK;
+}
+
+
+SCODE ULiOut(handle_t hRpc, ULARGE_INTEGER *puli)
+{
+ puli->LowPart = 0;
+ puli->HighPart = 1;
+ return RPC_S_OK;
+}
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: String
+//
+// Synopsis: tests passing strings in and out
+//
+// Arguments:
+//
+// Returns: RPC_S_OK
+//
+// History: 06-Aug-92 Ricksa Created
+//
+//--------------------------------------------------------------------------
+SCODE StringIn(handle_t hRpc, LPWSTR pwsz)
+{
+ return RPC_S_OK;
+}
+
+
+SCODE StringOut(handle_t hRpc, LPWSTR *ppwsz)
+{
+ // LPOLESTR pwsz = new OLECHAR[80];
+ // *ppwsz = pwsz;
+ wcscpy(*ppwsz, L"Hello World This is a Message");
+ return RPC_S_OK;
+}
+
+
+SCODE StringInOut(handle_t hRpc, LPWSTR pwsz)
+{
+ wcscpy(pwsz, L"Hello World This is a Message");
+ return RPC_S_OK;
+}
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: Guid
+//
+// Synopsis: tests passing GUIDs in and out
+//
+// Arguments:
+//
+// Returns: RPC_S_OK
+//
+// History: 06-Aug-92 Ricksa Created
+//
+//--------------------------------------------------------------------------
+SCODE GuidIn(handle_t hRpc, GUID guid)
+{
+ return RPC_S_OK;
+}
+
+SCODE GuidOut(handle_t hRpc, GUID *piid)
+{
+ memcpy(piid, &IID_IRawRpc, sizeof(GUID));
+ return RPC_S_OK;
+}
diff --git a/private/oleutest/perform/rawrpc/rawrpc_s.c b/private/oleutest/perform/rawrpc/rawrpc_s.c
new file mode 100644
index 000000000..0890cefe2
--- /dev/null
+++ b/private/oleutest/perform/rawrpc/rawrpc_s.c
@@ -0,0 +1,1001 @@
+#include <string.h>
+#include <limits.h>
+#include <rpc.h>
+
+#include "rawrpc.h"
+extern RPC_DISPATCH_TABLE IRawRpc_DispatchTable;
+
+static RPC_SERVER_INTERFACE ___RpcServerInterface = {
+ sizeof(RPC_SERVER_INTERFACE),
+ {{0x00000145,0x0001,0x0008,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}},
+ {0,0}},
+ {
+ {0x8A885D04L,0x1CEB,0x11C9,{0x9F,0xE8,0x08,0x00,0x2B,0x10,0x48,0x60}},
+ {2,0}
+ }
+ ,
+ &IRawRpc_DispatchTable,0,0,
+ 0
+ }
+;
+RPC_IF_HANDLE IRawRpc_ServerIfHandle = (RPC_IF_HANDLE) &___RpcServerInterface;
+void __RPC_STUB IRawRpc_Quit(
+ PRPC_MESSAGE _prpcmsg)
+ {
+ SCODE _ret_value;
+ handle_t hRpc = _prpcmsg->Handle;
+ unsigned char * _packet;
+ unsigned char * _tempbuf;
+ unsigned char * _savebuf;
+ RPC_STATUS _status;
+ _packet = _prpcmsg->Buffer;
+ ((void)( _packet ));
+ ((void)( _tempbuf ));
+ ((void)( _savebuf ));
+ RpcTryExcept
+ {
+ }
+ RpcExcept(1)
+ {
+ RpcRaiseException(RpcExceptionCode());
+ }
+ RpcEndExcept
+ if (((unsigned int)(((unsigned char *)_prpcmsg->Buffer) - _packet)) > _prpcmsg->BufferLength)
+ RpcRaiseException(RPC_X_BAD_STUB_DATA);
+ if (_prpcmsg->ManagerEpv)
+ {
+ _ret_value = ((IRawRpc_SERVER_EPV *)(_prpcmsg->ManagerEpv))->Quit(hRpc);
+ }
+ else
+ {
+ _ret_value = Quit(hRpc);
+ }
+ _prpcmsg->BufferLength = 4;
+ _prpcmsg->Buffer = _packet;
+ _status = I_RpcGetBuffer(_prpcmsg);
+ if (_status) RpcRaiseException(_status);
+ _packet = (unsigned char
+*)_prpcmsg->Buffer; /* send data from _ret_value */
+ *(*(long **)&_prpcmsg->Buffer)++ = (long)_ret_value;
+ _prpcmsg->Buffer = _packet;
+ }
+void __RPC_STUB IRawRpc_Void(
+ PRPC_MESSAGE _prpcmsg)
+ {
+ handle_t hRpc = _prpcmsg->Handle;
+ unsigned char * _packet;
+ unsigned char * _tempbuf;
+ unsigned char * _savebuf;
+ RPC_STATUS _status;
+ _packet = _prpcmsg->Buffer;
+ ((void)( _packet ));
+ ((void)( _tempbuf ));
+ ((void)( _savebuf ));
+ RpcTryExcept
+ {
+ }
+ RpcExcept(1)
+ {
+ RpcRaiseException(RpcExceptionCode());
+ }
+ RpcEndExcept
+ if (((unsigned int)(((unsigned char *)_prpcmsg->Buffer) - _packet)) > _prpcmsg->BufferLength)
+ RpcRaiseException(RPC_X_BAD_STUB_DATA);
+ if (_prpcmsg->ManagerEpv)
+ {
+ ((IRawRpc_SERVER_EPV *)(_prpcmsg->ManagerEpv))->Void(hRpc);
+ }
+ else
+ {
+ Void(hRpc);
+ }
+ _prpcmsg->BufferLength = 0;
+ _prpcmsg->Buffer = _packet;
+ _status = I_RpcGetBuffer(_prpcmsg);
+ if (_status) RpcRaiseException(_status);
+ }
+void __RPC_STUB IRawRpc_VoidRC(
+ PRPC_MESSAGE _prpcmsg)
+ {
+ SCODE _ret_value;
+ handle_t hRpc = _prpcmsg->Handle;
+ unsigned char * _packet;
+ unsigned char * _tempbuf;
+ unsigned char * _savebuf;
+ RPC_STATUS _status;
+ _packet = _prpcmsg->Buffer;
+ ((void)( _packet ));
+ ((void)( _tempbuf ));
+ ((void)( _savebuf ));
+ RpcTryExcept
+ {
+ }
+ RpcExcept(1)
+ {
+ RpcRaiseException(RpcExceptionCode());
+ }
+ RpcEndExcept
+ if (((unsigned int)(((unsigned char *)_prpcmsg->Buffer) - _packet)) > _prpcmsg->BufferLength)
+ RpcRaiseException(RPC_X_BAD_STUB_DATA);
+ if (_prpcmsg->ManagerEpv)
+ {
+ _ret_value = ((IRawRpc_SERVER_EPV *)(_prpcmsg->ManagerEpv))->VoidRC(hRpc);
+ }
+ else
+ {
+ _ret_value = VoidRC(hRpc);
+ }
+ _prpcmsg->BufferLength = 4;
+ _prpcmsg->Buffer = _packet;
+ _status = I_RpcGetBuffer(_prpcmsg);
+ if (_status) RpcRaiseException(_status);
+ _packet = (unsigned char
+*)_prpcmsg->Buffer; /* send data from _ret_value */
+ *(*(long **)&_prpcmsg->Buffer)++ = (long)_ret_value;
+ _prpcmsg->Buffer = _packet;
+ }
+void __RPC_STUB IRawRpc_VoidPtrIn(
+ PRPC_MESSAGE _prpcmsg)
+ {
+ SCODE _ret_value;
+ handle_t hRpc = _prpcmsg->Handle;
+ ULONG cb;
+ void *pv = 0;
+ unsigned long _alloc_total;
+ unsigned char * _packet;
+ unsigned char * _tempbuf;
+ unsigned char * _savebuf;
+ RPC_STATUS _status;
+ _packet = _prpcmsg->Buffer;
+ ((void)( _alloc_total ));
+ ((void)( _packet ));
+ ((void)( _tempbuf ));
+ ((void)( _savebuf ));
+ RpcTryExcept
+ {
+ /* receive data into &cb */
+ long_from_ndr((PRPC_MESSAGE)_prpcmsg, (unsigned long *)&cb);
+ _tempbuf = (unsigned char *)_prpcmsg->Buffer;
+ // recv total number of elements
+ long_from_ndr((PRPC_MESSAGE)_prpcmsg, &_alloc_total);
+ if (pv ==0)
+ {
+ pv = (void *)MIDL_user_allocate ((size_t)(_alloc_total * sizeof(unsigned char)));
+ }
+ byte_array_from_ndr ((PRPC_MESSAGE)_prpcmsg, 0, _alloc_total, pv);
+ }
+ RpcExcept(1)
+ {
+ RpcRaiseException(RpcExceptionCode());
+ }
+ RpcEndExcept
+ if (((unsigned int)(((unsigned char *)_prpcmsg->Buffer) - _packet)) > _prpcmsg->BufferLength)
+ RpcRaiseException(RPC_X_BAD_STUB_DATA);
+ RpcTryFinally
+ {
+ if (_prpcmsg->ManagerEpv)
+ {
+ _ret_value = ((IRawRpc_SERVER_EPV *)(_prpcmsg->ManagerEpv))->VoidPtrIn(hRpc, cb, pv);
+ }
+ else
+ {
+ _ret_value = VoidPtrIn(hRpc, cb, pv);
+ }
+ _prpcmsg->BufferLength = 4;
+ _prpcmsg->Buffer = _packet;
+ _status = I_RpcGetBuffer(_prpcmsg);
+ if (_status) RpcRaiseException(_status);
+ _packet = (unsigned char
+*)_prpcmsg->Buffer; /* send data from _ret_value */
+ *(*(long **)&_prpcmsg->Buffer)++ = (long)_ret_value;
+ }
+ RpcFinally
+ {
+ MIDL_user_free((void *)(pv));
+ }
+ RpcEndFinally
+ _prpcmsg->Buffer = _packet;
+ }
+void __RPC_STUB IRawRpc_VoidPtrOut(
+ PRPC_MESSAGE _prpcmsg)
+ {
+ SCODE _ret_value;
+ handle_t hRpc = _prpcmsg->Handle;
+ ULONG cb;
+ ULONG *pcb = 0;
+ void *pv = 0;
+ unsigned long _alloc_total;
+ unsigned char * _packet;
+ unsigned int _length;
+ unsigned char * _tempbuf;
+ unsigned char * _savebuf;
+ RPC_STATUS _status;
+ _packet = _prpcmsg->Buffer;
+ ((void)( _alloc_total ));
+ ((void)( _packet ));
+ ((void)( _tempbuf ));
+ ((void)( _savebuf ));
+ ((void)( _length ));
+ RpcTryExcept
+ {
+ /* receive data into &cb */
+ long_from_ndr((PRPC_MESSAGE)_prpcmsg, (unsigned long *)&cb);
+ }
+ RpcExcept(1)
+ {
+ RpcRaiseException(RpcExceptionCode());
+ }
+ RpcEndExcept
+ if (((unsigned int)(((unsigned char *)_prpcmsg->Buffer) - _packet)) > _prpcmsg->BufferLength)
+ RpcRaiseException(RPC_X_BAD_STUB_DATA);
+ pcb = (unsigned long *)MIDL_user_allocate ((size_t)(sizeof(long)));
+ _alloc_total = cb;
+ pv = (void *)MIDL_user_allocate ((size_t)(_alloc_total * sizeof(unsigned char)));
+ RpcTryFinally
+ {
+ if (_prpcmsg->ManagerEpv)
+ {
+ _ret_value = ((IRawRpc_SERVER_EPV *)(_prpcmsg->ManagerEpv))->VoidPtrOut(hRpc, cb, pcb, pv);
+ }
+ else
+ {
+ _ret_value = VoidPtrOut(hRpc, cb, pcb, pv);
+ }
+ _prpcmsg->BufferLength = 24;
+ if (pv ==0)
+ RpcRaiseException(RPC_X_NULL_REF_POINTER);
+ if (cb)
+ {
+ if (((*(pcb))) > (cb)) RpcRaiseException(RPC_X_INVALID_BOUND);
+ }
+ else
+ {
+ if (((*(pcb))) != (cb)) RpcRaiseException(RPC_X_INVALID_BOUND);
+ }
+ _prpcmsg->BufferLength += 12;
+ _prpcmsg->BufferLength += (unsigned int)((*(pcb)));
+ _prpcmsg->Buffer = _packet;
+ _status = I_RpcGetBuffer(_prpcmsg);
+ if (_status) RpcRaiseException(_status);
+ _packet = (unsigned char
+*)_prpcmsg->Buffer; _length = _prpcmsg->BufferLength;
+ _prpcmsg->BufferLength = 0;
+ /* send data from *pcb */
+ *(*(long **)&_prpcmsg->Buffer)++ = (long)*pcb;
+ // send total number of elements
+ *(*(long **)&_prpcmsg->Buffer)++ = cb;
+ // send valid range
+ *(*(long **)&_prpcmsg->Buffer)++ = 0;
+ *(*(long **)&_prpcmsg->Buffer)++ = (*(pcb));
+ /* send data from pv */
+ NDRcopy (_prpcmsg->Buffer, (void __RPC_FAR *) ((unsigned char *)pv+0), (unsigned int)((*(pcb))));
+ *(unsigned long *)&_prpcmsg->Buffer += (*(pcb));
+ /* send data from _ret_value */
+ *(unsigned long *)&_prpcmsg->Buffer += 3;
+ *(unsigned long *)&_prpcmsg->Buffer &= 0xfffffffc;
+ *(*(long **)&_prpcmsg->Buffer)++ = (long)_ret_value;
+ }
+ RpcFinally
+ {
+ MIDL_user_free((void *)(pv));
+ MIDL_user_free((void *)(pcb));
+ }
+ RpcEndFinally
+ _prpcmsg->Buffer = _packet;
+ _prpcmsg->BufferLength = _length;
+ }
+void __RPC_STUB IRawRpc_DwordIn(
+ PRPC_MESSAGE _prpcmsg)
+ {
+ SCODE _ret_value;
+ handle_t hRpc = _prpcmsg->Handle;
+ DWORD dw;
+ unsigned char * _packet;
+ unsigned char * _tempbuf;
+ unsigned char * _savebuf;
+ RPC_STATUS _status;
+ _packet = _prpcmsg->Buffer;
+ ((void)( _packet ));
+ ((void)( _tempbuf ));
+ ((void)( _savebuf ));
+ RpcTryExcept
+ {
+ /* receive data into &dw */
+ long_from_ndr((PRPC_MESSAGE)_prpcmsg, (unsigned long *)&dw);
+ }
+ RpcExcept(1)
+ {
+ RpcRaiseException(RpcExceptionCode());
+ }
+ RpcEndExcept
+ if (((unsigned int)(((unsigned char *)_prpcmsg->Buffer) - _packet)) > _prpcmsg->BufferLength)
+ RpcRaiseException(RPC_X_BAD_STUB_DATA);
+ if (_prpcmsg->ManagerEpv)
+ {
+ _ret_value = ((IRawRpc_SERVER_EPV *)(_prpcmsg->ManagerEpv))->DwordIn(hRpc, dw);
+ }
+ else
+ {
+ _ret_value = DwordIn(hRpc, dw);
+ }
+ _prpcmsg->BufferLength = 4;
+ _prpcmsg->Buffer = _packet;
+ _status = I_RpcGetBuffer(_prpcmsg);
+ if (_status) RpcRaiseException(_status);
+ _packet = (unsigned char
+*)_prpcmsg->Buffer; /* send data from _ret_value */
+ *(*(long **)&_prpcmsg->Buffer)++ = (long)_ret_value;
+ _prpcmsg->Buffer = _packet;
+ }
+void __RPC_STUB IRawRpc_DwordOut(
+ PRPC_MESSAGE _prpcmsg)
+ {
+ SCODE _ret_value;
+ handle_t hRpc = _prpcmsg->Handle;
+ DWORD pdw;
+ unsigned char * _packet;
+ unsigned int _length;
+ unsigned char * _tempbuf;
+ unsigned char * _savebuf;
+ RPC_STATUS _status;
+ _packet = _prpcmsg->Buffer;
+ ((void)( _packet ));
+ ((void)( _tempbuf ));
+ ((void)( _savebuf ));
+ ((void)( _length ));
+ RpcTryExcept
+ {
+ }
+ RpcExcept(1)
+ {
+ RpcRaiseException(RpcExceptionCode());
+ }
+ RpcEndExcept
+ if (((unsigned int)(((unsigned char *)_prpcmsg->Buffer) - _packet)) > _prpcmsg->BufferLength)
+ RpcRaiseException(RPC_X_BAD_STUB_DATA);
+ RpcTryFinally
+ {
+ if (_prpcmsg->ManagerEpv)
+ {
+ _ret_value = ((IRawRpc_SERVER_EPV *)(_prpcmsg->ManagerEpv))->DwordOut(hRpc, &pdw);
+ }
+ else
+ {
+ _ret_value = DwordOut(hRpc, &pdw);
+ }
+ _prpcmsg->BufferLength = 8;
+ _prpcmsg->Buffer = _packet;
+ _status = I_RpcGetBuffer(_prpcmsg);
+ if (_status) RpcRaiseException(_status);
+ _packet = (unsigned char
+*)_prpcmsg->Buffer; _length = _prpcmsg->BufferLength;
+ _prpcmsg->BufferLength = 0;
+ /* send data from pdw */
+ *(*(long **)&_prpcmsg->Buffer)++ = (long)pdw;
+ /* send data from _ret_value */
+ *(*(long **)&_prpcmsg->Buffer)++ = (long)_ret_value;
+ }
+ RpcFinally
+ {
+ }
+ RpcEndFinally
+ _prpcmsg->Buffer = _packet;
+ _prpcmsg->BufferLength = _length;
+ }
+void __RPC_STUB IRawRpc_DwordInOut(
+ PRPC_MESSAGE _prpcmsg)
+ {
+ SCODE _ret_value;
+ handle_t hRpc = _prpcmsg->Handle;
+ DWORD pdw;
+ unsigned char * _packet;
+ unsigned int _length;
+ unsigned char * _tempbuf;
+ unsigned char * _savebuf;
+ RPC_STATUS _status;
+ _packet = _prpcmsg->Buffer;
+ ((void)( _packet ));
+ ((void)( _tempbuf ));
+ ((void)( _savebuf ));
+ ((void)( _length ));
+ RpcTryExcept
+ {
+ _tempbuf = (unsigned char *)_prpcmsg->Buffer;
+ /* receive data into &pdw */
+ long_from_ndr((PRPC_MESSAGE)_prpcmsg, (unsigned long *)&pdw);
+ }
+ RpcExcept(1)
+ {
+ RpcRaiseException(RpcExceptionCode());
+ }
+ RpcEndExcept
+ if (((unsigned int)(((unsigned char *)_prpcmsg->Buffer) - _packet)) > _prpcmsg->BufferLength)
+ RpcRaiseException(RPC_X_BAD_STUB_DATA);
+ RpcTryFinally
+ {
+ if (_prpcmsg->ManagerEpv)
+ {
+ _ret_value = ((IRawRpc_SERVER_EPV *)(_prpcmsg->ManagerEpv))->DwordInOut(hRpc, &pdw);
+ }
+ else
+ {
+ _ret_value = DwordInOut(hRpc, &pdw);
+ }
+ _prpcmsg->BufferLength = 8;
+ _prpcmsg->Buffer = _packet;
+ _status = I_RpcGetBuffer(_prpcmsg);
+ if (_status) RpcRaiseException(_status);
+ _packet = (unsigned char
+*)_prpcmsg->Buffer; _length = _prpcmsg->BufferLength;
+ _prpcmsg->BufferLength = 0;
+ /* send data from pdw */
+ *(*(long **)&_prpcmsg->Buffer)++ = (long)pdw;
+ /* send data from _ret_value */
+ *(*(long **)&_prpcmsg->Buffer)++ = (long)_ret_value;
+ }
+ RpcFinally
+ {
+ }
+ RpcEndFinally
+ _prpcmsg->Buffer = _packet;
+ _prpcmsg->BufferLength = _length;
+ }
+void __RPC_STUB IRawRpc_LiIn(
+ PRPC_MESSAGE _prpcmsg)
+ {
+ SCODE _ret_value;
+ handle_t hRpc = _prpcmsg->Handle;
+ LARGE_INTEGER li;
+ unsigned long _alloc_total;
+ unsigned char * _packet;
+ unsigned char * _tempbuf;
+ unsigned char * _savebuf;
+ RPC_STATUS _status;
+ _packet = _prpcmsg->Buffer;
+ ((void)( _alloc_total ));
+ ((void)( _packet ));
+ ((void)( _tempbuf ));
+ ((void)( _savebuf ));
+ RpcTryExcept
+ {
+ data_from_ndr((PRPC_MESSAGE)_prpcmsg, (void __RPC_FAR *) (&li), "4ll", 8);
+ }
+ RpcExcept(1)
+ {
+ RpcRaiseException(RpcExceptionCode());
+ }
+ RpcEndExcept
+ if (((unsigned int)(((unsigned char *)_prpcmsg->Buffer) - _packet)) > _prpcmsg->BufferLength)
+ RpcRaiseException(RPC_X_BAD_STUB_DATA);
+ if (_prpcmsg->ManagerEpv)
+ {
+ _ret_value = ((IRawRpc_SERVER_EPV *)(_prpcmsg->ManagerEpv))->LiIn(hRpc, li);
+ }
+ else
+ {
+ _ret_value = LiIn(hRpc, li);
+ }
+ _prpcmsg->BufferLength = 4;
+ _prpcmsg->Buffer = _packet;
+ _status = I_RpcGetBuffer(_prpcmsg);
+ if (_status) RpcRaiseException(_status);
+ _packet = (unsigned char
+*)_prpcmsg->Buffer; /* send data from _ret_value */
+ *(*(long **)&_prpcmsg->Buffer)++ = (long)_ret_value;
+ _prpcmsg->Buffer = _packet;
+ }
+void __RPC_STUB IRawRpc_LiOut(
+ PRPC_MESSAGE _prpcmsg)
+ {
+ SCODE _ret_value;
+ handle_t hRpc = _prpcmsg->Handle;
+ LARGE_INTEGER pli;
+ unsigned long _alloc_total;
+ unsigned char * _packet;
+ unsigned int _length;
+ unsigned char * _tempbuf;
+ unsigned char * _savebuf;
+ RPC_STATUS _status;
+ _packet = _prpcmsg->Buffer;
+ ((void)( _alloc_total ));
+ ((void)( _packet ));
+ ((void)( _tempbuf ));
+ ((void)( _savebuf ));
+ ((void)( _length ));
+ RpcTryExcept
+ {
+ }
+ RpcExcept(1)
+ {
+ RpcRaiseException(RpcExceptionCode());
+ }
+ RpcEndExcept
+ if (((unsigned int)(((unsigned char *)_prpcmsg->Buffer) - _packet)) > _prpcmsg->BufferLength)
+ RpcRaiseException(RPC_X_BAD_STUB_DATA);
+ RpcTryFinally
+ {
+ if (_prpcmsg->ManagerEpv)
+ {
+ _ret_value = ((IRawRpc_SERVER_EPV *)(_prpcmsg->ManagerEpv))->LiOut(hRpc, &pli);
+ }
+ else
+ {
+ _ret_value = LiOut(hRpc, &pli);
+ }
+ _prpcmsg->BufferLength = 12;
+ _prpcmsg->Buffer = _packet;
+ _status = I_RpcGetBuffer(_prpcmsg);
+ if (_status) RpcRaiseException(_status);
+ _packet = (unsigned char
+*)_prpcmsg->Buffer; _length = _prpcmsg->BufferLength;
+ _prpcmsg->BufferLength = 0;
+ /* send data from &pli */
+ NDRcopy (_prpcmsg->Buffer, (void __RPC_FAR *) (&pli), (unsigned int)(8));
+ *(unsigned long *)&_prpcmsg->Buffer += 8;
+ /* send data from _ret_value */
+ *(*(long **)&_prpcmsg->Buffer)++ = (long)_ret_value;
+ }
+ RpcFinally
+ {
+ }
+ RpcEndFinally
+ _prpcmsg->Buffer = _packet;
+ _prpcmsg->BufferLength = _length;
+ }
+void __RPC_STUB IRawRpc_ULiIn(
+ PRPC_MESSAGE _prpcmsg)
+ {
+ SCODE _ret_value;
+ handle_t hRpc = _prpcmsg->Handle;
+ ULARGE_INTEGER uli;
+ unsigned long _alloc_total;
+ unsigned char * _packet;
+ unsigned char * _tempbuf;
+ unsigned char * _savebuf;
+ RPC_STATUS _status;
+ _packet = _prpcmsg->Buffer;
+ ((void)( _alloc_total ));
+ ((void)( _packet ));
+ ((void)( _tempbuf ));
+ ((void)( _savebuf ));
+ RpcTryExcept
+ {
+ data_from_ndr((PRPC_MESSAGE)_prpcmsg, (void __RPC_FAR *) (&uli), "4ll", 8);
+ }
+ RpcExcept(1)
+ {
+ RpcRaiseException(RpcExceptionCode());
+ }
+ RpcEndExcept
+ if (((unsigned int)(((unsigned char *)_prpcmsg->Buffer) - _packet)) > _prpcmsg->BufferLength)
+ RpcRaiseException(RPC_X_BAD_STUB_DATA);
+ if (_prpcmsg->ManagerEpv)
+ {
+ _ret_value = ((IRawRpc_SERVER_EPV *)(_prpcmsg->ManagerEpv))->ULiIn(hRpc, uli);
+ }
+ else
+ {
+ _ret_value = ULiIn(hRpc, uli);
+ }
+ _prpcmsg->BufferLength = 4;
+ _prpcmsg->Buffer = _packet;
+ _status = I_RpcGetBuffer(_prpcmsg);
+ if (_status) RpcRaiseException(_status);
+ _packet = (unsigned char
+*)_prpcmsg->Buffer; /* send data from _ret_value */
+ *(*(long **)&_prpcmsg->Buffer)++ = (long)_ret_value;
+ _prpcmsg->Buffer = _packet;
+ }
+void __RPC_STUB IRawRpc_ULiOut(
+ PRPC_MESSAGE _prpcmsg)
+ {
+ SCODE _ret_value;
+ handle_t hRpc = _prpcmsg->Handle;
+ ULARGE_INTEGER puli;
+ unsigned long _alloc_total;
+ unsigned char * _packet;
+ unsigned int _length;
+ unsigned char * _tempbuf;
+ unsigned char * _savebuf;
+ RPC_STATUS _status;
+ _packet = _prpcmsg->Buffer;
+ ((void)( _alloc_total ));
+ ((void)( _packet ));
+ ((void)( _tempbuf ));
+ ((void)( _savebuf ));
+ ((void)( _length ));
+ RpcTryExcept
+ {
+ }
+ RpcExcept(1)
+ {
+ RpcRaiseException(RpcExceptionCode());
+ }
+ RpcEndExcept
+ if (((unsigned int)(((unsigned char *)_prpcmsg->Buffer) - _packet)) > _prpcmsg->BufferLength)
+ RpcRaiseException(RPC_X_BAD_STUB_DATA);
+ RpcTryFinally
+ {
+ if (_prpcmsg->ManagerEpv)
+ {
+ _ret_value = ((IRawRpc_SERVER_EPV *)(_prpcmsg->ManagerEpv))->ULiOut(hRpc, &puli);
+ }
+ else
+ {
+ _ret_value = ULiOut(hRpc, &puli);
+ }
+ _prpcmsg->BufferLength = 12;
+ _prpcmsg->Buffer = _packet;
+ _status = I_RpcGetBuffer(_prpcmsg);
+ if (_status) RpcRaiseException(_status);
+ _packet = (unsigned char
+*)_prpcmsg->Buffer; _length = _prpcmsg->BufferLength;
+ _prpcmsg->BufferLength = 0;
+ /* send data from &puli */
+ NDRcopy (_prpcmsg->Buffer, (void __RPC_FAR *) (&puli), (unsigned int)(8));
+ *(unsigned long *)&_prpcmsg->Buffer += 8;
+ /* send data from _ret_value */
+ *(*(long **)&_prpcmsg->Buffer)++ = (long)_ret_value;
+ }
+ RpcFinally
+ {
+ }
+ RpcEndFinally
+ _prpcmsg->Buffer = _packet;
+ _prpcmsg->BufferLength = _length;
+ }
+void __RPC_STUB IRawRpc_StringIn(
+ PRPC_MESSAGE _prpcmsg)
+ {
+ SCODE _ret_value;
+ handle_t hRpc = _prpcmsg->Handle;
+ LPWSTR pwsz = 0;
+ unsigned long _alloc_total;
+ unsigned long _valid_lower;
+ unsigned long _valid_total;
+ unsigned char * _packet;
+ unsigned int _length;
+ unsigned char * _buffer;
+ unsigned char * _treebuf;
+ unsigned char * _tempbuf;
+ unsigned char * _savebuf;
+ RPC_STATUS _status;
+ _packet = _prpcmsg->Buffer;
+ ((void)( _alloc_total ));
+ ((void)( _valid_total ));
+ ((void)( _valid_lower ));
+ ((void)( _packet ));
+ ((void)( _buffer ));
+ ((void)( _treebuf ));
+ ((void)( _tempbuf ));
+ ((void)( _savebuf ));
+ ((void)( _length ));
+ RpcTryExcept
+ {
+ _tempbuf = (unsigned char *)_prpcmsg->Buffer;
+ _treebuf = 0;
+ // recv total number of elements
+ long_from_ndr((PRPC_MESSAGE)_prpcmsg, &_alloc_total);
+ if (pwsz ==0)
+ {
+ pwsz = (WCHAR *)MIDL_user_allocate ((size_t)(_alloc_total * sizeof(WCHAR)));
+ }
+ data_from_ndr((PRPC_MESSAGE)_prpcmsg, (void __RPC_FAR *) (pwsz), "s2", 1);
+ }
+ RpcExcept(1)
+ {
+ RpcRaiseException(RpcExceptionCode());
+ }
+ RpcEndExcept
+ if (((unsigned int)(((unsigned char *)_prpcmsg->Buffer) - _packet)) > _prpcmsg->BufferLength)
+ RpcRaiseException(RPC_X_BAD_STUB_DATA);
+ RpcTryFinally
+ {
+ if (_prpcmsg->ManagerEpv)
+ {
+ _ret_value = ((IRawRpc_SERVER_EPV *)(_prpcmsg->ManagerEpv))->StringIn(hRpc, pwsz);
+ }
+ else
+ {
+ _ret_value = StringIn(hRpc, pwsz);
+ }
+ _prpcmsg->BufferLength = 4;
+ _prpcmsg->Buffer = _packet;
+ _status = I_RpcGetBuffer(_prpcmsg);
+ if (_status) RpcRaiseException(_status);
+ _packet = (unsigned char
+*)_prpcmsg->Buffer; /* send data from _ret_value */
+ *(*(long **)&_prpcmsg->Buffer)++ = (long)_ret_value;
+ }
+ RpcFinally
+ {
+ MIDL_user_free((void *)(pwsz));
+ }
+ RpcEndFinally
+ _prpcmsg->Buffer = _packet;
+ }
+void __RPC_STUB IRawRpc_StringOut(
+ PRPC_MESSAGE _prpcmsg)
+ {
+ SCODE _ret_value;
+ handle_t hRpc = _prpcmsg->Handle;
+ LPWSTR ppwsz = 0;
+ unsigned long _alloc_total;
+ unsigned char * _packet;
+ unsigned int _length;
+ unsigned char * _buffer;
+ unsigned char * _treebuf;
+ unsigned char * _tempbuf;
+ unsigned char * _savebuf;
+ RPC_STATUS _status;
+ _packet = _prpcmsg->Buffer;
+ ((void)( _alloc_total ));
+ ((void)( _packet ));
+ ((void)( _buffer ));
+ ((void)( _treebuf ));
+ ((void)( _tempbuf ));
+ ((void)( _savebuf ));
+ ((void)( _length ));
+ RpcTryExcept
+ {
+ }
+ RpcExcept(1)
+ {
+ RpcRaiseException(RpcExceptionCode());
+ }
+ RpcEndExcept
+ if (((unsigned int)(((unsigned char *)_prpcmsg->Buffer) - _packet)) > _prpcmsg->BufferLength)
+ RpcRaiseException(RPC_X_BAD_STUB_DATA);
+ RpcTryFinally
+ {
+ if (_prpcmsg->ManagerEpv)
+ {
+ _ret_value = ((IRawRpc_SERVER_EPV *)(_prpcmsg->ManagerEpv))->StringOut(hRpc, &ppwsz);
+ }
+ else
+ {
+ _ret_value = StringOut(hRpc, &ppwsz);
+ }
+ _prpcmsg->BufferLength = 16;
+ _prpcmsg->BufferLength += 4;
+ if (ppwsz !=0)
+ {
+ tree_size_ndr((void __RPC_FAR *)&(ppwsz), (PRPC_MESSAGE)_prpcmsg, "s2", 1);
+ }
+ _prpcmsg->Buffer = _packet;
+ _status = I_RpcGetBuffer(_prpcmsg);
+ if (_status) RpcRaiseException(_status);
+ _packet = (unsigned char
+*)_prpcmsg->Buffer; _length = _prpcmsg->BufferLength;
+ _prpcmsg->BufferLength = 0;
+ /* send data from ppwsz */
+ *(*(long **)&_prpcmsg->Buffer)++ = (long)ppwsz;
+ if (ppwsz !=0)
+ {
+ tree_into_ndr((void __RPC_FAR *)&(ppwsz), (PRPC_MESSAGE)_prpcmsg, "s2", 1);
+ }
+ /* send data from _ret_value */
+ *(unsigned long *)&_prpcmsg->Buffer += 3;
+ *(unsigned long *)&_prpcmsg->Buffer &= 0xfffffffc;
+ *(*(long **)&_prpcmsg->Buffer)++ = (long)_ret_value;
+ }
+ RpcFinally
+ {
+ if (ppwsz !=0)
+ {
+ MIDL_user_free((void *)(ppwsz));
+ }
+ }
+ RpcEndFinally
+ _prpcmsg->Buffer = _packet;
+ _prpcmsg->BufferLength = _length;
+ }
+void __RPC_STUB IRawRpc_StringInOut(
+ PRPC_MESSAGE _prpcmsg)
+ {
+ SCODE _ret_value;
+ handle_t hRpc = _prpcmsg->Handle;
+ LPWSTR pwsz = 0;
+ unsigned long _alloc_total;
+ unsigned long _valid_lower;
+ unsigned long _valid_total;
+ unsigned char * _packet;
+ unsigned int _length;
+ unsigned char * _buffer;
+ unsigned char * _treebuf;
+ unsigned char * _tempbuf;
+ unsigned char * _savebuf;
+ RPC_STATUS _status;
+ _packet = _prpcmsg->Buffer;
+ ((void)( _alloc_total ));
+ ((void)( _valid_total ));
+ ((void)( _valid_lower ));
+ ((void)( _packet ));
+ ((void)( _buffer ));
+ ((void)( _treebuf ));
+ ((void)( _tempbuf ));
+ ((void)( _savebuf ));
+ ((void)( _length ));
+ RpcTryExcept
+ {
+ _tempbuf = (unsigned char *)_prpcmsg->Buffer;
+ _treebuf = 0;
+ // recv total number of elements
+ long_from_ndr((PRPC_MESSAGE)_prpcmsg, &_alloc_total);
+ if (pwsz ==0)
+ {
+ pwsz = (WCHAR *)MIDL_user_allocate ((size_t)(_alloc_total * sizeof(WCHAR)));
+ }
+ data_from_ndr((PRPC_MESSAGE)_prpcmsg, (void __RPC_FAR *) (pwsz), "s2", 1);
+ }
+ RpcExcept(1)
+ {
+ RpcRaiseException(RpcExceptionCode());
+ }
+ RpcEndExcept
+ if (((unsigned int)(((unsigned char *)_prpcmsg->Buffer) - _packet)) > _prpcmsg->BufferLength)
+ RpcRaiseException(RPC_X_BAD_STUB_DATA);
+ RpcTryFinally
+ {
+ if (_prpcmsg->ManagerEpv)
+ {
+ _ret_value = ((IRawRpc_SERVER_EPV *)(_prpcmsg->ManagerEpv))->StringInOut(hRpc, pwsz);
+ }
+ else
+ {
+ _ret_value = StringInOut(hRpc, pwsz);
+ }
+ _prpcmsg->BufferLength = 16;
+ if (pwsz ==0)
+ RpcRaiseException(RPC_X_NULL_REF_POINTER);
+ tree_size_ndr((void __RPC_FAR *)&(pwsz), (PRPC_MESSAGE)_prpcmsg, "s2", 1);
+ _prpcmsg->Buffer = _packet;
+ _status = I_RpcGetBuffer(_prpcmsg);
+ if (_status) RpcRaiseException(_status);
+ _packet = (unsigned char
+*)_prpcmsg->Buffer; _length = _prpcmsg->BufferLength;
+ _prpcmsg->BufferLength = 0;
+ tree_into_ndr((void __RPC_FAR *)&(pwsz), (PRPC_MESSAGE)_prpcmsg, "s2", 1);
+ /* send data from _ret_value */
+ *(unsigned long *)&_prpcmsg->Buffer += 3;
+ *(unsigned long *)&_prpcmsg->Buffer &= 0xfffffffc;
+ *(*(long **)&_prpcmsg->Buffer)++ = (long)_ret_value;
+ }
+ RpcFinally
+ {
+ MIDL_user_free((void *)(pwsz));
+ }
+ RpcEndFinally
+ _prpcmsg->Buffer = _packet;
+ _prpcmsg->BufferLength = _length;
+ }
+void __RPC_STUB IRawRpc_GuidIn(
+ PRPC_MESSAGE _prpcmsg)
+ {
+ SCODE _ret_value;
+ handle_t hRpc = _prpcmsg->Handle;
+ GUID guid;
+ unsigned long _alloc_total;
+ unsigned char * _packet;
+ unsigned char * _tempbuf;
+ unsigned char * _savebuf;
+ RPC_STATUS _status;
+ _packet = _prpcmsg->Buffer;
+ ((void)( _alloc_total ));
+ ((void)( _packet ));
+ ((void)( _tempbuf ));
+ ((void)( _savebuf ));
+ RpcTryExcept
+ {
+ _gns__GUID ((GUID *)&guid, (PRPC_MESSAGE)_prpcmsg);
+ }
+ RpcExcept(1)
+ {
+ RpcRaiseException(RpcExceptionCode());
+ }
+ RpcEndExcept
+ if (((unsigned int)(((unsigned char *)_prpcmsg->Buffer) - _packet)) > _prpcmsg->BufferLength)
+ RpcRaiseException(RPC_X_BAD_STUB_DATA);
+ if (_prpcmsg->ManagerEpv)
+ {
+ _ret_value = ((IRawRpc_SERVER_EPV *)(_prpcmsg->ManagerEpv))->GuidIn(hRpc, guid);
+ }
+ else
+ {
+ _ret_value = GuidIn(hRpc, guid);
+ }
+ _prpcmsg->BufferLength = 4;
+ _prpcmsg->Buffer = _packet;
+ _status = I_RpcGetBuffer(_prpcmsg);
+ if (_status) RpcRaiseException(_status);
+ _packet = (unsigned char
+*)_prpcmsg->Buffer; /* send data from _ret_value */
+ *(*(long **)&_prpcmsg->Buffer)++ = (long)_ret_value;
+ _prpcmsg->Buffer = _packet;
+ }
+void __RPC_STUB IRawRpc_GuidOut(
+ PRPC_MESSAGE _prpcmsg)
+ {
+ SCODE _ret_value;
+ handle_t hRpc = _prpcmsg->Handle;
+ GUID pguid;
+ unsigned long _alloc_total;
+ unsigned char * _packet;
+ unsigned int _length;
+ unsigned char * _tempbuf;
+ unsigned char * _savebuf;
+ RPC_STATUS _status;
+ _packet = _prpcmsg->Buffer;
+ ((void)( _alloc_total ));
+ ((void)( _packet ));
+ ((void)( _tempbuf ));
+ ((void)( _savebuf ));
+ ((void)( _length ));
+ RpcTryExcept
+ {
+ }
+ RpcExcept(1)
+ {
+ RpcRaiseException(RpcExceptionCode());
+ }
+ RpcEndExcept
+ if (((unsigned int)(((unsigned char *)_prpcmsg->Buffer) - _packet)) > _prpcmsg->BufferLength)
+ RpcRaiseException(RPC_X_BAD_STUB_DATA);
+ RpcTryFinally
+ {
+ if (_prpcmsg->ManagerEpv)
+ {
+ _ret_value = ((IRawRpc_SERVER_EPV *)(_prpcmsg->ManagerEpv))->GuidOut(hRpc, &pguid);
+ }
+ else
+ {
+ _ret_value = GuidOut(hRpc, &pguid);
+ }
+ _prpcmsg->BufferLength = 20;
+ _prpcmsg->Buffer = _packet;
+ _status = I_RpcGetBuffer(_prpcmsg);
+ if (_status) RpcRaiseException(_status);
+ _packet = (unsigned char
+*)_prpcmsg->Buffer; _length = _prpcmsg->BufferLength;
+ _prpcmsg->BufferLength = 0;
+ /* send data from &pguid */
+ NDRcopy (_prpcmsg->Buffer, (void __RPC_FAR *) (&pguid), (unsigned int)(16));
+ *(unsigned long *)&_prpcmsg->Buffer += 16;
+ /* send data from _ret_value */
+ *(*(long **)&_prpcmsg->Buffer)++ = (long)_ret_value;
+ }
+ RpcFinally
+ {
+ }
+ RpcEndFinally
+ _prpcmsg->Buffer = _packet;
+ _prpcmsg->BufferLength = _length;
+ }
+static RPC_DISPATCH_FUNCTION IRawRpc_table[] =
+ {
+ IRawRpc_Quit,
+ IRawRpc_Void,
+ IRawRpc_VoidRC,
+ IRawRpc_VoidPtrIn,
+ IRawRpc_VoidPtrOut,
+ IRawRpc_DwordIn,
+ IRawRpc_DwordOut,
+ IRawRpc_DwordInOut,
+ IRawRpc_LiIn,
+ IRawRpc_LiOut,
+ IRawRpc_ULiIn,
+ IRawRpc_ULiOut,
+ IRawRpc_StringIn,
+ IRawRpc_StringOut,
+ IRawRpc_StringInOut,
+ IRawRpc_GuidIn,
+ IRawRpc_GuidOut,
+ 0
+ }
+;
+RPC_DISPATCH_TABLE IRawRpc_DispatchTable =
+ {
+ 17,
+ IRawRpc_table
+ }
+;
diff --git a/private/oleutest/perform/rawrpc/rawrpc_y.c b/private/oleutest/perform/rawrpc/rawrpc_y.c
new file mode 100644
index 000000000..4701c238f
--- /dev/null
+++ b/private/oleutest/perform/rawrpc/rawrpc_y.c
@@ -0,0 +1,5 @@
+#include <string.h>
+#include <limits.h>
+#include <rpc.h>
+
+#include "rawrpc.h"
diff --git a/private/oleutest/rot/daytona/makefile b/private/oleutest/rot/daytona/makefile
new file mode 100644
index 000000000..1d3728d41
--- /dev/null
+++ b/private/oleutest/rot/daytona/makefile
@@ -0,0 +1,10 @@
+############################################################################
+#
+# Copyright (C) 1992, Microsoft Corporation.
+#
+# All rights reserved.
+#
+############################################################################
+
+!include $(NTMAKEENV)\makefile.def
+
diff --git a/private/oleutest/rot/daytona/sources b/private/oleutest/rot/daytona/sources
new file mode 100644
index 000000000..bc0aee865
--- /dev/null
+++ b/private/oleutest/rot/daytona/sources
@@ -0,0 +1,81 @@
+!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:
+
+ Donna Liu (DonnaLi) 19-Dec-1993
+
+!ENDIF
+
+MAJORCOMP = cairole
+MINORCOMP = com
+
+#
+# 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= rotut
+
+#
+# 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
+
+DLLDEF= ..\rotut.def
+
+INCLUDES= ..\..\..\cinc;..\..\..\ole32\common\daytona;..\..\..\ole32\ih;..;..\..\common
+
+C_DEFINES= \
+ $(C_DEFINES) \
+ -DFLAT \
+ -DWIN32=100 \
+ -D_NT1X_=100 \
+ -DUNICODE \
+ -D_UNICODE \
+ -DINC_OLE2 \
+ -DNOEXCEPTIONS \
+ -DCAIROLE_DOWNLEVEL
+
+BLDCRT= 1
+
+SOURCES= \
+ ..\rotut.cxx
+
+UMTYPE= console
+UMAPPL=
+UMTEST=
+UMLIBS= \
+ ..\..\..\ole32\com\port\daytona\obj\*\port.lib \
+ $(BASEDIR)\public\sdk\lib\*\ole32.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\*\crtdll.lib \
+ $(BASEDIR)\public\sdk\lib\*\uuid.lib
+
+USE_CRTDLL= 1
diff --git a/private/oleutest/rot/dirs b/private/oleutest/rot/dirs
new file mode 100644
index 000000000..1d0b9edbb
--- /dev/null
+++ b/private/oleutest/rot/dirs
@@ -0,0 +1,38 @@
+!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/rot/rotut.cxx b/private/oleutest/rot/rotut.cxx
new file mode 100644
index 000000000..cb5406270
--- /dev/null
+++ b/private/oleutest/rot/rotut.cxx
@@ -0,0 +1,618 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: rotut.cxx
+//
+// Contents: Unit Test for ROT
+//
+// Classes: MISSING
+//
+// Functions: MISSING
+//
+// History: 16-Oct-93 Ricksa Created
+//
+//--------------------------------------------------------------------------
+#include <windows.h>
+#include <widewrap.h> // For chicago build
+#include <ole2.h>
+#include <stdio.h>
+#include <safepnt.hxx>
+#include <com.hxx>
+
+#define TEST_FAILED(x, y) \
+ if (x) \
+ { \
+ printf("%s:%d %s\n", __FILE__, __LINE__, y); \
+ return TRUE; \
+ }
+
+GUID clsidLocal =
+ {0xbbbbbbbb,0xbbbb,0xbbbb,{0xbb,0xbb,0xbb,0xbb,0xbb,0xbb,0xbb,0xbb}};
+
+CHAR szTmpCurrrentDirectory[MAX_PATH];
+WCHAR szCurrentDirectory[MAX_PATH];
+
+
+SAFE_INTERFACE_PTR(CSafeROT, IRunningObjectTable)
+SAFE_INTERFACE_PTR(CSafeUnk, IUnknown)
+SAFE_INTERFACE_PTR(CSafePersist, IPersist)
+SAFE_INTERFACE_PTR(CSafeEnumMoniker, IEnumMoniker)
+SAFE_INTERFACE_PTR(CSafeMoniker, IMoniker)
+SAFE_INTERFACE_PTR(CSafeStorage, IStorage)
+
+class COleInit
+{
+public:
+ COleInit(HRESULT& hr);
+
+ ~COleInit(void);
+private:
+
+ // No private data
+};
+
+inline COleInit::COleInit(HRESULT& hr)
+{
+ hr = OleInitialize(NULL);
+}
+
+inline COleInit::~COleInit(void)
+{
+ // Do the clean up
+ OleUninitialize();
+}
+
+
+
+class CRotTestObject : public IPersist
+{
+public:
+ CRotTestObject(WCHAR *pwszID);
+
+ // IUnknown Interface
+ STDMETHODIMP QueryInterface(REFIID riid, void **ppv);
+
+ STDMETHODIMP_(ULONG)AddRef(void);
+
+ STDMETHODIMP_(ULONG)Release(void);
+
+ STDMETHODIMP GetClassID(LPCLSID pclsid);
+
+private:
+
+ WCHAR _awcID[256];
+
+ ULONG _cRefs;
+
+};
+
+
+
+
+CRotTestObject::CRotTestObject(WCHAR *pwszID) : _cRefs(1)
+{
+ wcscpy(_awcID, pwszID);
+}
+
+
+
+
+STDMETHODIMP CRotTestObject::QueryInterface(REFIID riid, void **ppv)
+{
+ if ((memcmp((void *) &riid, (void *) &IID_IUnknown, sizeof(GUID)) == 0)
+ || (memcmp((void *) &riid, (void *) &IID_IPersist, sizeof(GUID)) == 0))
+ {
+ _cRefs++;
+ *ppv = (IUnknown *) this;
+ return S_OK;
+ }
+
+ *ppv = NULL;
+ return E_NOINTERFACE;
+}
+
+
+
+STDMETHODIMP_(ULONG) CRotTestObject::AddRef(void)
+{
+ _cRefs++;
+ return (ULONG) _awcID;
+}
+
+
+
+STDMETHODIMP_(ULONG) CRotTestObject::Release(void)
+{
+ if (--_cRefs == 0)
+ {
+ delete this;
+ }
+
+ return _cRefs;
+}
+
+
+
+STDMETHODIMP CRotTestObject::GetClassID(LPCLSID pclsid)
+{
+ memcpy(pclsid, &clsidLocal, sizeof(clsidLocal));
+ return S_OK;
+}
+
+
+
+
+
+
+BOOL VerifyRegistration(
+ IMoniker *pmk,
+ REFCLSID clsidExpected,
+ FILETIME *pFileTimeExpected)
+{
+ CSafeROT prot;
+
+ HRESULT hr = GetRunningObjectTable(0, &prot);
+
+ TEST_FAILED(FAILED(hr),
+ "VerifyRegistration:GetRunningObjectTable failed!\n")
+
+ // Verify the object is running
+ hr = prot->IsRunning(pmk);
+
+ TEST_FAILED((hr != S_OK),
+ "VerifyRegistration:Unexpected return from IsRunning\n")
+
+ // Test Get Object
+ CSafeUnk punk;
+
+ hr = prot->GetObject(pmk, &punk);
+
+ TEST_FAILED((hr != S_OK),
+ "VerifyRegistration:Unexpected from GetObject\n")
+
+ // Confirm object class
+ CSafePersist prst;
+
+ hr = punk->QueryInterface(IID_IPersist, (void **) &prst);
+
+ TEST_FAILED((hr != S_OK),
+ "VerifyRegistration:QI to IPersist failed\n")
+
+ CLSID clsid;
+
+ hr = prst->GetClassID(&clsid);
+
+ TEST_FAILED((hr != S_OK),
+ "VerifyRegistration:GetClassID on IPersist failed\n")
+
+ TEST_FAILED((memcmp(&clsid, &clsidExpected, sizeof(clsid)) != 0),
+ "VerifyRegistration:GetClassID mismatch with expected\n")
+
+ // Test get the time
+ FILETIME filetime;
+
+ hr = prot->GetTimeOfLastChange(pmk, &filetime);
+
+ TEST_FAILED((hr != S_OK), "VerifyRegistration:GetTimeOfLastChange Failed\n")
+
+ TEST_FAILED((memcmp(&filetime, pFileTimeExpected, sizeof(filetime)) != 0),
+ "VerifyRegistration:GetTimeOfLastChange != NoteChangeTime value")
+
+ // Enumerate all the running monikers
+ CSafeEnumMoniker penummk;
+
+ hr = prot->EnumRunning(&penummk);
+
+ TEST_FAILED(FAILED(hr), "VerifyRegistration:EnumRunning Failed\n")
+
+ // Cycle through running object table
+ BOOL fFound = FALSE;
+ IMoniker *pmkTable;
+ int cIdx = 0;
+ int cOurMoniker;
+
+ while (SUCCEEDED(hr = penummk->Next(1, &pmkTable, NULL))
+ && (hr != S_FALSE))
+ {
+ if (pmk->IsEqual(pmkTable) == S_OK)
+ {
+ fFound = TRUE;
+ cOurMoniker = cIdx;
+ pmkTable->Release();
+ break;
+ }
+
+ pmkTable->Release();
+
+ cIdx++;
+ }
+
+ TEST_FAILED(FAILED(hr),
+ "VerifyRegistration:ROT Moniker Enumeration ended in failure")
+
+ TEST_FAILED((!fFound),
+ "VerifyRegistration:Did not find our moniker in the table");
+
+ // Reset the pointer
+ hr = penummk->Reset();
+
+ TEST_FAILED(FAILED(hr),
+ "VerifyRegistration:ROT IEnumMoniker::Reset Failed");
+
+ // Skip to our moniker
+ hr = penummk->Skip(cOurMoniker);
+
+ TEST_FAILED(FAILED(hr),
+ "VerifyRegistration:ROT IEnumMoniker::Skip Failed");
+
+ // Read it from the enumerator
+ hr = penummk->Next(1, &pmkTable, NULL);
+
+ TEST_FAILED(FAILED(hr),
+ "VerifyRegistration:ROT IEnumMoniker::Next Failed");
+
+ TEST_FAILED((pmk->IsEqual(pmkTable) != S_OK),
+ "VerifyRegistration:ROT IEnumMoniker::Next after skip monikers !=");
+
+ // If we get to here the test passed
+ return FALSE;
+}
+
+
+
+BOOL VerifyNotRunning(IMoniker *pmk)
+{
+ CSafeROT prot;
+
+ HRESULT hr = GetRunningObjectTable(0, &prot);
+
+ TEST_FAILED(FAILED(hr), "GetRunningObjectTable failed!\n")
+
+ // Check result from IsRunning
+ hr = prot->IsRunning(pmk);
+
+ TEST_FAILED((hr != S_FALSE),
+ "Unexpected return from IsRunning\n")
+
+ // Test Get Object
+ CSafeUnk punk;
+
+ hr = prot->GetObject(pmk, &punk);
+
+ TEST_FAILED((hr != MK_E_UNAVAILABLE), "Unexpected from GetObject\n")
+
+ // Test get the time
+ FILETIME filetime2;
+
+ hr = prot->GetTimeOfLastChange(pmk, &filetime2);
+
+ TEST_FAILED((hr != MK_E_UNAVAILABLE), "GetTimeOfLastChange Failed\n")
+
+ // Enumerate all the running monikers
+ CSafeEnumMoniker penummk;
+
+ hr = prot->EnumRunning(&penummk);
+
+ TEST_FAILED(FAILED(hr), "EnumRunning Failed\n")
+
+ // Cycle through running object table
+ BOOL fFound = FALSE;
+ IMoniker *pmkTable;
+
+ while (SUCCEEDED(hr = penummk->Next(1, &pmkTable, NULL))
+ && (hr != S_FALSE))
+ {
+ if (pmk->IsEqual(pmkTable) == S_OK)
+ {
+ pmkTable->Release();
+ fFound = TRUE;
+ break;
+ }
+
+ pmkTable->Release();
+ }
+
+ TEST_FAILED(FAILED(hr), "ROT Moniker Enumeration ended in failure")
+
+ TEST_FAILED((fFound), "Found our non-running moniker in the table");
+
+ // If we get to here the test passed
+ return FALSE;
+
+}
+
+
+
+BOOL TestInvalidParameters(void)
+{
+ CSafeROT prot;
+
+ HRESULT hr = GetRunningObjectTable(0, &prot);
+
+ // Test set the time
+ FILETIME filetime;
+ memset(&filetime, 'A', sizeof(filetime));
+
+ // Test with invalid pointer
+ hr = prot->Revoke(0xFFFFFFFF);
+
+ TEST_FAILED((hr != E_INVALIDARG),
+ "WrongResult from Revoke Invalid Address");
+
+ hr = prot->NoteChangeTime(0xFFFFFFFF, &filetime);
+
+ TEST_FAILED((hr != E_INVALIDARG),
+ "WrongResult from NoteChangeTime Invalid Address");
+
+ // Test with valid pointer but invalid data
+ DWORD dwValidAddress[30];
+
+ hr = prot->Revoke((DWORD) dwValidAddress);
+
+ TEST_FAILED((hr != E_INVALIDARG),
+ "WrongResult from Revoke Invalid Data");
+
+ hr = prot->NoteChangeTime((DWORD) dwValidAddress, &filetime);
+
+ TEST_FAILED((hr != E_INVALIDARG),
+ "WrongResult from NoteChangeTime Invalid Data");
+
+ return FALSE;
+}
+
+
+BOOL TestLocalROT(void)
+{
+ CSafeMoniker pmk2;
+ CSafeROT prot;
+
+ HRESULT hr = GetRunningObjectTable(0, &prot);
+
+ TEST_FAILED(FAILED(hr), "GetRunningObjectTable failed!\n")
+
+ // Make sure that we can do something on the pointer that
+ // we got back.
+ prot->AddRef();
+ prot->Release();
+
+ // Create an IUnknown pointer for the class.
+ CSafeUnk punk;
+ punk.Attach(new CRotTestObject(L"First Test Object"));
+
+ hr = CreateItemMoniker(L"\\", L"Bob", &pmk2);
+
+ TEST_FAILED(FAILED(hr), "CreateItemMoniker for \\Bob failed\n")
+
+ // Make sure new object is not running
+ TEST_FAILED(VerifyNotRunning(pmk2), "TestLocalROT:Object Already running\n")
+
+ // Cookie for deregistering object
+ DWORD dwRegister;
+
+ hr = prot->Register(0, punk, pmk2, &dwRegister);
+
+ TEST_FAILED(FAILED(hr), "TestLocalROT:Register in ROT for \\Bob failed\n")
+
+ // Test set the time
+ FILETIME filetime;
+
+ memset(&filetime, 'A', sizeof(filetime));
+
+ hr = prot->NoteChangeTime(dwRegister, &filetime);
+
+ TEST_FAILED((hr != S_OK), "TestLocalROT:NoteChangeTime Failed\n")
+
+ // Verify that this is running
+ TEST_FAILED(VerifyRegistration(pmk2, clsidLocal, &filetime),
+ "TestLocalROT: Registration failed\n");
+
+ // Revoke registration
+ hr = prot->Revoke(dwRegister);
+
+ TEST_FAILED((hr != S_OK), "TestLocalROT:Revoke failed\n");
+
+ // Verify no longer registered
+ TEST_FAILED(VerifyNotRunning(pmk2),
+ "TestLocalROT:VerifyNotRunning failed\n")
+
+ // If we get to here the test passed
+ return FALSE;
+}
+
+
+
+void CreatePath(int iId, WCHAR *pwszPath)
+{
+ wsprintf(pwszPath, L"%s\\%s%ld", szCurrentDirectory, L"ROTUT", iId);
+}
+
+
+BOOL CreateObjectAndBind(WCHAR *pwszPath, IUnknown **ppunk)
+{
+ HRESULT hr;
+
+ // create a storage for the object
+ {
+ CSafeStorage pstg;
+
+ hr = StgCreateDocfile(pwszPath,
+ STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, NULL, &pstg);
+
+ TEST_FAILED(FAILED(hr), "CreateObjectAndBind:StgCreateDocfile failed")
+
+ // Write the class id to the storage
+ hr = pstg->SetClass(CLSID_AdvBnd);
+ }
+
+ TEST_FAILED(FAILED(hr), "CreateObjectAndBind IStorage::SetClass Failed")
+
+ // Bind to the path
+ CSafeMoniker pmk;
+
+ hr = CreateFileMoniker(pwszPath, &pmk);
+
+ TEST_FAILED(FAILED(hr), "CreateObjectAndBind:CreateFileMoniker failed")
+
+ hr = BindMoniker(pmk, 0, IID_IUnknown, (void **) ppunk);
+
+ TEST_FAILED(FAILED(hr), "CreateObjectAndBind:BindMoniker failed")
+
+ // Test set the time
+ FILETIME filetime;
+
+ memset(&filetime, 'B', sizeof(filetime));
+
+ // Verify that it is running
+ TEST_FAILED(VerifyRegistration(pmk, CLSID_AdvBnd, &filetime),
+ "CreateObjectAndBind: Registration failed\n");
+
+ return FALSE;
+}
+
+
+
+BOOL RemoteROT(void)
+{
+ // Create an object of the class
+ WCHAR szPath[MAX_PATH];
+
+ CreatePath(0, szPath);
+
+ CSafeUnk punk;
+
+ // Bind to the object
+ if (CreateObjectAndBind(szPath, &punk))
+ {
+ printf("RemoteRot: Failed on CreateObjectAndBind\n");
+ return TRUE;
+ }
+
+ // Release object
+ punk->Release();
+ punk.Detach();
+
+ // Bind to the path
+ CSafeMoniker pmk;
+
+ HRESULT hr = CreateFileMoniker(szPath, &pmk);
+
+ TEST_FAILED(FAILED(hr), "RemoteROT:CreateFileMoniker failed")
+
+ // Verify that it is freed
+ TEST_FAILED(VerifyNotRunning(pmk),
+ "RemoteROT:VerifyNotRunning failed\n")
+
+ DeleteFile(szPath);
+
+ return FALSE;
+}
+
+
+#define MAX_TO_TEST 100
+IUnknown *apunk[MAX_TO_TEST];
+
+
+
+BOOL TestManyRegistrations(void)
+{
+ // Create an object of the class
+ WCHAR szPath[MAX_PATH];
+
+ for (int i = 0; i < MAX_TO_TEST; i++)
+ {
+ // Create name of bound object
+ CreatePath(i, szPath);
+
+ // Create object
+ printf("Many create %ld\n", i);
+
+ if (CreateObjectAndBind(szPath, &apunk[i]))
+ {
+ printf("TestManyRegistrations failed on %ld\n", i);
+ return TRUE;
+ }
+ }
+
+ for (i = 0; i < MAX_TO_TEST; i++)
+ {
+ printf("Many Release %ld\n", i);
+
+ // Create name of bound object
+ CreatePath(i, szPath);
+
+ // Bind to the path
+ CSafeMoniker pmk;
+
+ HRESULT hr = CreateFileMoniker(szPath, &pmk);
+
+ TEST_FAILED(FAILED(hr),
+ "TestManyRegistrations:CreateFileMoniker failed")
+
+ // Release object
+ apunk[i]->Release();
+
+ // Verify object is not running
+ if (VerifyNotRunning(pmk))
+ {
+ printf("TestManyRegistrations:VerifyNotRunning failed on %ld\n", i);
+ return TRUE;
+ }
+
+ DeleteFile(szPath);
+ }
+
+ return FALSE;
+}
+
+
+
+int _cdecl main(int argc, TCHAR **argv)
+{
+ // Get the current directory
+ int len = GetCurrentDirectoryA(sizeof(szTmpCurrrentDirectory),
+ szTmpCurrrentDirectory);
+
+ // Convert to UNICODE
+ mbstowcs(szCurrentDirectory, szTmpCurrrentDirectory, len + 1);
+
+ // Result of test - TRUE == passed
+ BOOL fTest = FALSE;
+
+ // Initialize Ole
+ HRESULT hr;
+
+ COleInit oleinit(hr);
+
+ if (FAILED(hr))
+ {
+ printf("OleInitialize Failed\n");
+ return -1;
+ }
+
+ // Test Invalidad Parameters and Local ROT
+ if (!TestInvalidParameters() && !TestLocalROT())
+ {
+ // Test Remote Registration for object
+ if (!RemoteROT())
+ {
+ // Test Large Registration
+ if (!TestManyRegistrations())
+ {
+ fTest = TRUE;
+ }
+ }
+ }
+
+ if (fTest)
+ {
+ printf("Test Passed\n");
+ }
+ else
+ {
+ printf("Test FAILED!!!\n");
+ }
+
+ return 0;
+}
diff --git a/private/oleutest/server1/csrvapp.cxx b/private/oleutest/server1/csrvapp.cxx
new file mode 100644
index 000000000..b8792c308
--- /dev/null
+++ b/private/oleutest/server1/csrvapp.cxx
@@ -0,0 +1,294 @@
+//+-------------------------------------------------------------------
+// File: csrvapp.cxx
+//
+// Contents: Implementation of CTestServerApp
+//
+// Classes: CTestServerApp
+//
+// History: 17-Dec-92 DeanE Created
+// 31-Dec-93 ErikGav Chicago port
+// 25-Apr-95 BruceMa CoRevokeClassObject before shutting down
+//---------------------------------------------------------------------
+#pragma optimize("",off)
+#include <windows.h>
+#include <ole2.h>
+#include "testsrv.hxx"
+#include <except.hxx>
+
+void ProcessCmdLine(LPSTR, BOOL *);
+
+// Used to send a quit message
+extern HWND g_hwndMain;
+
+
+//+--------------------------------------------------------------
+// Function: CTestServerApp::CTestServerApp
+//
+// Synopsis: Constructor - initialize members
+//
+// Parameters: None
+//
+// Returns: None
+//
+// History: 17-Dec-92 DeanE Created
+//---------------------------------------------------------------
+CTestServerApp::CTestServerApp()
+{
+ _pteClassFactory = NULL;
+ _dwRegId = 0;
+ _fRegistered = FALSE;
+ _fInitialized = FALSE;
+ _fEmbedded = TRUE;
+ _cEmbeddedObjs = 0;
+}
+
+
+//+--------------------------------------------------------------
+// Function: CTestServerApp::~CTestServerApp
+//
+// Synopsis: Insure pointers are free - note this is mainly for
+// error-checking.
+//
+// Parameters: None
+//
+// Returns: None
+//
+// History: 17-Dec-92 DeanE Created
+//---------------------------------------------------------------
+CTestServerApp::~CTestServerApp()
+{
+ Win4Assert(_pteClassFactory == NULL &&
+ "Class factory should have been released");
+}
+
+
+//+--------------------------------------------------------------
+// Function: CTestServerApp::InitApp
+//
+// Synopsis: Initialize this instance of the app.
+//
+// Parameters: [lpszCmdline] - Command line of the application.
+//
+// Returns: S_OK if everything was initialized, or an error if not.
+//
+// History: 17-Dec-92 DeanE Created
+//
+// Notes: If this does not return, the CloseApp method should
+// still be called for proper cleanup.
+//---------------------------------------------------------------
+SCODE CTestServerApp::InitApp(LPSTR lpszCmdline)
+{
+ SCODE sc;
+
+ // Check OLE version running
+ // BUGBUG - NYI by OLE
+ // Bail out if we are not running with an acceptable version of OLE
+
+ // Process Command Line arguments
+ ProcessCmdLine(lpszCmdline, &_fEmbedded);
+
+ // Look up the thread mode from the win.ini file.
+ DWORD thread_mode;
+ TCHAR buffer[80];
+ int len;
+
+ len = GetProfileString( TEXT("TestSrv"),
+ TEXT("ThreadMode"),
+ TEXT("MultiThreaded"),
+ buffer,
+ sizeof(buffer) / sizeof(TCHAR));
+
+ if (lstrcmp(buffer, TEXT("ApartmentThreaded")) == 0)
+ {
+ thread_mode = COINIT_APARTMENTTHREADED;
+ sc = CoInitialize(NULL);
+ }
+ else
+ {
+#ifdef MULTI_THREADING
+ thread_mode = COINIT_MULTITHREADED;
+ sc = CoInitializeEx(NULL, thread_mode);
+#else
+ // multi-threading not supported
+ sc = E_INVALIDARG;
+#endif
+ }
+
+ if (S_OK == sc)
+ {
+ _fInitialized = TRUE;
+ }
+ else
+ {
+ return(sc);
+ }
+
+ // Create the applications class factory - note that we have to free
+ // at a later time
+ _pteClassFactory = CTestEmbedCF::Create(this);
+ if (NULL == _pteClassFactory)
+ {
+ return(E_ABORT);
+ }
+
+ // Register the class with OLE
+ sc = CoRegisterClassObject(
+ CLSID_TestEmbed,
+ _pteClassFactory,
+ CLSCTX_LOCAL_SERVER,
+ REGCLS_MULTIPLEUSE,
+ &_dwRegId);
+ if (S_OK == sc)
+ {
+ _fRegistered = TRUE;
+ }
+
+ return(sc);
+}
+
+
+//+--------------------------------------------------------------
+// Function: CTestServerApp::CloseApp
+//
+// Synopsis: Clean up resources this instance of the app is using.
+//
+// Parameters: None
+//
+// Returns: S_OK if everything was cleaned up, or an error if not.
+//
+// History: 17-Dec-92 DeanE Created
+//---------------------------------------------------------------
+SCODE CTestServerApp::CloseApp()
+{
+ // Release this apps class factory, and insure the returned count is 0
+ if (NULL != _pteClassFactory)
+ {
+ if (0 == _pteClassFactory->Release())
+ {
+ _pteClassFactory = NULL;
+ }
+ else
+ {
+ // BUGBUG - Log error
+ }
+ }
+
+ // Uninitialize OLE only if OleInitialize succeeded
+ if (TRUE == _fInitialized)
+ {
+ CoUninitialize();
+ }
+ return(S_OK);
+}
+
+
+//+--------------------------------------------------------------
+// Function: CTestServerApp::GetEmbeddedFlag
+//
+// Synopsis: Returns TRUE if app was started for an embedded object,
+// FALSE if standalone.
+//
+// Parameters: None
+//
+// Returns: BOOL (_fEmbedded)
+//
+// History: 17-Dec-92 DeanE Created
+//
+// Notes: BUGBUG - This should be an inline method
+//---------------------------------------------------------------
+CTestServerApp::GetEmbeddedFlag()
+{
+ return(_fEmbedded);
+}
+
+
+//+--------------------------------------------------------------
+// Function: CTestServerApp::IncEmbeddedCount
+//
+// Synopsis: Increments the count of embedded objects the server
+// has open.
+//
+// Parameters: None
+//
+// Returns: ULONG (_cEmbeddedObjs)
+//
+// History: 17-Dec-92 DeanE Created
+//
+// Notes: BUGBUG - This should be an inline method
+//---------------------------------------------------------------
+ULONG CTestServerApp::IncEmbeddedCount()
+{
+ return(++_cEmbeddedObjs);
+}
+
+
+//+--------------------------------------------------------------
+// Function: CTestServerApp::DecEmbeddedCount
+//
+// Synopsis: Decrements the count of embedded objects the server
+// has open. If 0 are left and we were running for an
+// embedded object(s), shut down.
+//
+// Parameters: None
+//
+// Returns: ULONG (_cEmbeddedObjs)
+//
+// History: 17-Dec-92 DeanE Created
+//
+//---------------------------------------------------------------
+ULONG CTestServerApp::DecEmbeddedCount()
+{
+ if ((0 == --_cEmbeddedObjs) && _fEmbedded)
+ {
+ // Revoke the class object, if registered
+ if (TRUE == _fRegistered)
+ {
+ CoRevokeClassObject(_dwRegId);
+// OutputDebugStringA("Revoking class object now!\n");
+ }
+
+ // Shut down the app
+ SendMessage(g_hwndMain, WM_USER, 0xFFFFFFFF, 0xFFFFFFFF);
+ }
+
+ return(_cEmbeddedObjs);
+}
+
+
+//+--------------------------------------------------------------
+// Function: ProcessCmdline
+//
+// Synopsis: Checks the cmd line parameters, in particular for
+// '/Embedding' or '-Embedding'.
+//
+// Parameters: [lpszCmdLine] - Command line buffer.
+// [pfEmbedded] - Flag should be set to true if we get
+// the '/Embedding' switch.
+//
+// Returns: void
+//
+// History: 25-Nov-92 DeanE Created
+//
+// Notes: Only two valid commandlines for this program:
+// (1) -Embedding when started by OLE or (2) Null
+// string if started from the command line.
+//---------------------------------------------------------------
+void ProcessCmdLine(LPSTR lpszCmdline, BOOL *pfEmbedded)
+{
+ if (lpszCmdline[0] == 0)
+ {
+ *pfEmbedded = FALSE;
+ return;
+ }
+
+ if (strcmp(lpszCmdline, "-Embedding") == 0)
+ {
+ *pfEmbedded = TRUE;
+ return;
+ }
+
+ Win4Assert(!"testsrv received an invalid command line!");
+ *pfEmbedded = FALSE;
+
+ return;
+}
diff --git a/private/oleutest/server1/ctestcf.cxx b/private/oleutest/server1/ctestcf.cxx
new file mode 100644
index 000000000..28171ce44
--- /dev/null
+++ b/private/oleutest/server1/ctestcf.cxx
@@ -0,0 +1,176 @@
+//+-------------------------------------------------------------------
+// File: ctestcf.cxx
+//
+// Contents:
+//
+// Classes: CTestEmbedCF - IClassFactory
+//
+// History: 7-Dec-92 DeanE Created
+//---------------------------------------------------------------------
+#pragma optimize("",off)
+#include <windows.h>
+#include <ole2.h>
+#include "testsrv.hxx"
+
+//+-------------------------------------------------------------------
+// Member: CTestEmbedCF::CTestEmbedCF()
+//
+// Synopsis: The constructor for CTestEmbedCF.
+//
+// Arguments: None
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+CTestEmbedCF::CTestEmbedCF(CTestServerApp *ptsaServer) : _cRef(1)
+{
+ _ptsaServer = ptsaServer;
+
+ return;
+}
+
+
+//+-------------------------------------------------------------------
+// Member: CTestEmbedCF::~CTestEmbedCF()
+//
+// Synopsis: The destructor for CTestEmbedCF.
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+CTestEmbedCF::~CTestEmbedCF()
+{
+ _ptsaServer = NULL;
+}
+
+
+//+-------------------------------------------------------------------
+// Member: CTestEmbedCF::Create()
+//
+// Synopsis: Creates a new CTestEmbedCF object.
+//
+// Arguments: None
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+IClassFactory FAR* CTestEmbedCF::Create(CTestServerApp *ptsaServer)
+{
+ CTestEmbedCF FAR* pteCF = new FAR CTestEmbedCF(ptsaServer);
+// if (NULL != pteCF)
+// {
+// _ptsaServer = ptsaServer;
+// }
+ return(pteCF);
+}
+
+
+//+-------------------------------------------------------------------
+// Method: CTestEmbedCF::QueryInterface
+//
+// Synopsis: Only IUnknown and IClassFactory supported
+// return pointer to the actual object
+//
+// Parameters: [iid] - Interface ID to return.
+// [ppv] - Pointer to pointer to object.
+//
+// Returns: S_OK if iid is supported, or E_NOINTERFACE if not.
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP CTestEmbedCF::QueryInterface(REFIID iid, void FAR * FAR * ppv)
+{
+ if (GuidEqual(iid, IID_IUnknown) || GuidEqual(iid, IID_IClassFactory))
+ {
+ *ppv = this;
+ AddRef();
+ return(S_OK);
+ }
+ else
+ {
+ *ppv = NULL;
+ return(E_NOINTERFACE);
+ }
+}
+
+STDMETHODIMP_(ULONG) CTestEmbedCF::AddRef(void)
+{
+ return ++_cRef;
+}
+
+STDMETHODIMP_(ULONG) CTestEmbedCF::Release(void)
+{
+ ULONG cRefs = --_cRef;
+
+ if (cRefs == 0)
+ {
+ delete this;
+ }
+
+ return cRefs;
+}
+
+
+
+
+
+//+-------------------------------------------------------------------
+// Method: CTestEmbedCF::CreateInstance
+//
+// Synopsis: This is called by Binding process to create the
+// actual class object.
+//
+// Parameters: [pUnkOuter] - Ignored. Affects aggregation.
+// [iidInterface] - Interface ID object should support.
+// [ppv] - Pointer to the object.
+//
+// Returns: S_OOM if object couldn't be created, or SCODE from
+// QueryInterface call.
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP CTestEmbedCF::CreateInstance(
+ IUnknown FAR *pUnkOuter,
+ REFIID iidInterface,
+ void FAR* FAR *ppv)
+{
+ CTestEmbed FAR *pteObj;
+ SCODE sc;
+
+ pteObj = new FAR CTestEmbed();
+ if (pteObj == NULL)
+ {
+ return(E_OUTOFMEMORY);
+ }
+ sc = pteObj->InitObject(_ptsaServer, g_hwndMain);
+ if (S_OK != sc)
+ {
+ delete pteObj;
+ return(E_OUTOFMEMORY);
+ }
+
+ // Having created the actual object, ensure desired
+ // interfaces are available.
+ //
+ sc = pteObj->QueryInterface(iidInterface, ppv);
+
+
+ // We are done with the CTestEmbed instance - it's now referenced by ppv
+ pteObj->Release();
+
+ return(sc);
+}
+
+//+-------------------------------------------------------------------
+// Method: CTestEmbedCF::LockServer
+//
+// Synopsis: What does this do?
+//
+// Parameters: [fLock] - ???
+//
+// Returns: ???
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP CTestEmbedCF::LockServer(BOOL fLock)
+{
+ // BUGBUG - What does this do?
+ return(E_FAIL);
+}
diff --git a/private/oleutest/server1/ctestemb.cxx b/private/oleutest/server1/ctestemb.cxx
new file mode 100644
index 000000000..fc8f56a83
--- /dev/null
+++ b/private/oleutest/server1/ctestemb.cxx
@@ -0,0 +1,227 @@
+//+-------------------------------------------------------------------
+// File: ctestemb.cxx
+//
+// Contents: CTestEmbed class implementation.
+//
+// Classes: CTestEmbed
+//
+// History: 7-Dec-92 DeanE Created
+//---------------------------------------------------------------------
+#pragma optimize("",off)
+#include <windows.h>
+#include <ole2.h>
+#include "testsrv.hxx"
+
+
+
+//+-------------------------------------------------------------------
+// Method: CTestEmbed::CTestEmbed
+//
+// Synopsis: Constructor for CTestEmbed objects
+//
+// Parameters: None
+//
+// Returns: None
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+CTestEmbed::CTestEmbed() : _cRef(1)
+{
+ _ptsaServer = NULL;
+ _pDataObject = NULL;
+ _pOleObject = NULL;
+ _pPersStg = NULL;
+ _hwnd = NULL;
+}
+
+
+//+-------------------------------------------------------------------
+// Method: CTestEmbed::~CTestEmbed
+//
+// Synopsis: Performs cleanup for CTestEmbed objects by releasing
+// internal pointers.
+//
+// Parameters: None
+//
+// Returns: None
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+CTestEmbed::~CTestEmbed()
+{
+ // Inform controlling server app this object is gone
+ _ptsaServer->DecEmbeddedCount();
+
+ // Delete all of this objects interface classes
+ delete _pDataObject;
+ delete _pOleObject;
+ delete _pPersStg;
+}
+
+
+//+-------------------------------------------------------------------
+// Method: CTestEmbed::InitObject
+//
+// Synopsis: Initialize this CTestEmbed object - ie, set everything
+// up for actual use.
+//
+// Parameters: None
+//
+// Returns: S_OK if everything is okay to use, or an error code
+//
+// History: 7-Dec-92 DeanE Created
+//
+// Notes: The state of the object must be cleaned up in case of
+// failure - so the destructor will not blow up.
+//--------------------------------------------------------------------
+SCODE CTestEmbed::InitObject(CTestServerApp *ptsaServer, HWND hwnd)
+{
+ SCODE sc = S_OK;
+
+ // Initialize controlling server app
+ if (NULL != ptsaServer)
+ {
+ _ptsaServer = ptsaServer;
+ }
+ else
+ {
+ sc = E_ABORT;
+ }
+
+ // Initilize this objects window handle
+ _hwnd = hwnd;
+
+ // Create a CDataObject
+ if (SUCCEEDED(sc))
+ {
+ _pDataObject = new CDataObject(this);
+ if (NULL == _pDataObject)
+ {
+ sc = E_ABORT;
+ }
+ }
+
+ // Create a COleObject
+ if (SUCCEEDED(sc))
+ {
+ _pOleObject = new COleObject(this);
+ if (NULL == _pOleObject)
+ {
+ sc = E_ABORT;
+ }
+ }
+
+ // Create a CPersistStorage
+ if (SUCCEEDED(sc))
+ {
+ _pPersStg = new CPersistStorage(this);
+ if (NULL == _pPersStg)
+ {
+ sc = E_ABORT;
+ }
+ }
+
+ if (FAILED(sc))
+ {
+ delete _pDataObject;
+ delete _pOleObject;
+ delete _pPersStg;
+ _pDataObject = NULL;
+ _pOleObject = NULL;
+ _pPersStg = NULL;
+ _ptsaServer = NULL;
+ _hwnd = NULL;
+ }
+
+ // Inform controlling server we are a new embedded object
+ if (SUCCEEDED(sc))
+ {
+ _ptsaServer->IncEmbeddedCount();
+ }
+
+ return(sc);
+}
+
+
+//+-------------------------------------------------------------------
+// Method: CTestEmbed::QueryInterface
+//
+// Synopsis: IUnknown, IOleObject, IPersist, IPersistStorage supported
+// return pointer to the actual object
+//
+// Parameters: [iid] - Interface ID to return.
+// [ppv] - Pointer to pointer to object.
+//
+// Returns: S_OK if iid is supported, or E_NOINTERFACE if not.
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP CTestEmbed::QueryInterface(REFIID iid, void FAR * FAR * ppv)
+{
+ SCODE scRet;
+
+ if (GuidEqual(IID_IUnknown, iid))
+ {
+ *ppv = (IUnknown *)this;
+ AddRef();
+ scRet = S_OK;
+ }
+ else
+ if (GuidEqual(IID_IOleObject, iid))
+ {
+ *ppv = _pOleObject;
+ AddRef();
+ scRet = S_OK;
+ }
+ else
+ if (GuidEqual(IID_IPersist, iid) || GuidEqual(IID_IPersistStorage, iid))
+ {
+ *ppv = _pPersStg;
+ AddRef();
+ scRet = S_OK;
+ }
+ else
+ if (GuidEqual(IID_IDataObject, iid))
+ {
+ *ppv = _pDataObject;
+ AddRef();
+ scRet = S_OK;
+ }
+ else
+ {
+ *ppv = NULL;
+ scRet = E_NOINTERFACE;
+ }
+
+ return(scRet);
+}
+
+
+STDMETHODIMP_(ULONG) CTestEmbed::AddRef(void)
+{
+ return ++_cRef;
+}
+
+STDMETHODIMP_(ULONG) CTestEmbed::Release(void)
+{
+ ULONG cRefs = --_cRef;
+
+ if (cRefs == 0)
+ {
+ delete this;
+ }
+
+ return cRefs;
+}
+SCODE CTestEmbed::GetWindow(HWND *phwnd)
+{
+ if (NULL != phwnd)
+ {
+ *phwnd = _hwnd;
+ return(S_OK);
+ }
+ else
+ {
+ return(E_ABORT);
+ }
+}
diff --git a/private/oleutest/server1/daytona/makefile b/private/oleutest/server1/daytona/makefile
new file mode 100644
index 000000000..1d3728d41
--- /dev/null
+++ b/private/oleutest/server1/daytona/makefile
@@ -0,0 +1,10 @@
+############################################################################
+#
+# Copyright (C) 1992, Microsoft Corporation.
+#
+# All rights reserved.
+#
+############################################################################
+
+!include $(NTMAKEENV)\makefile.def
+
diff --git a/private/oleutest/server1/daytona/sources b/private/oleutest/server1/daytona/sources
new file mode 100644
index 000000000..6f6f53f6b
--- /dev/null
+++ b/private/oleutest/server1/daytona/sources
@@ -0,0 +1,80 @@
+!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:
+
+ Donna Liu (DonnaLi) 19-Dec-1993
+
+!ENDIF
+
+MAJORCOMP = cairole
+MINORCOMP = com
+
+#
+# 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= testsrv
+
+#
+# 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= ..;..\..\common;..\..\..\ole32\common\daytona;..\..\..\ole32\ih;..\..\..\cinc
+
+!include ..\..\daytona.inc
+
+C_DEFINES= \
+ $(C_DEFINES)
+
+
+SOURCES= \
+ ..\testsrv.rc \
+ ..\testsrv.cxx \
+ ..\csrvapp.cxx \
+ ..\ctestemb.cxx \
+ ..\ipersist.cxx \
+ ..\ioleobj.cxx \
+ ..\idataobj.cxx \
+ ..\ctestcf.cxx
+
+UMTYPE= windows
+UMENTRY= winmain
+UMAPPL=
+UMTEST=
+UMLIBS= \
+ ..\..\assert\daytona\obj\*\assert.lib \
+ $(BASEDIR)\public\sdk\lib\*\ole32.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\*\crtdll.lib \
+ $(BASEDIR)\public\sdk\lib\*\uuid.lib
+
+USE_CRTDLL= 1
diff --git a/private/oleutest/server1/dirs b/private/oleutest/server1/dirs
new file mode 100644
index 000000000..1d0b9edbb
--- /dev/null
+++ b/private/oleutest/server1/dirs
@@ -0,0 +1,38 @@
+!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/server1/idataobj.cxx b/private/oleutest/server1/idataobj.cxx
new file mode 100644
index 000000000..0bf409bdb
--- /dev/null
+++ b/private/oleutest/server1/idataobj.cxx
@@ -0,0 +1,306 @@
+//+-------------------------------------------------------------------
+// File: idataobj.cxx
+//
+// Contents: IDataObject methods of CTestEmbed class.
+//
+// Classes: CTestEmbed - IDataObject implementation
+//
+// History: 7-Dec-92 DeanE Created
+//---------------------------------------------------------------------
+#pragma optimize("",off)
+#include <windows.h>
+#include <ole2.h>
+#include "testsrv.hxx"
+
+
+//+-------------------------------------------------------------------
+// Member: CDataObject::CDataObject()
+//
+// Synopsis: The constructor for CDataObject.
+//
+// Arguments: None
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+CDataObject::CDataObject(CTestEmbed *pteObject)
+{
+ _cRef = 1;
+ _pDAHolder = NULL;
+ _pteObject = pteObject;
+}
+
+
+//+-------------------------------------------------------------------
+// Member: CDataObject::~CDataObject()
+//
+// Synopsis: The destructor for CDataObject.
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+CDataObject::~CDataObject()
+{
+ // _cRef count should be 1
+ if (1 != _cRef)
+ {
+ // BUGBUG - Log error
+ // Someone hasn't released one of these - Log error
+ }
+ return;
+}
+
+
+//+-------------------------------------------------------------------
+// Method: CDataObject::QueryInterface
+//
+// Synopsis: Forward this to the object we're associated with
+//
+// Parameters: [iid] - Interface ID to return.
+// [ppv] - Pointer to pointer to object.
+//
+// Returns: S_OK if iid is supported, or E_NOINTERFACE if not.
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP CDataObject::QueryInterface(REFIID iid, void FAR * FAR *ppv)
+{
+ return(_pteObject->QueryInterface(iid, ppv));
+}
+
+
+//+-------------------------------------------------------------------
+// Method: CDataObject::AddRef
+//
+// Synopsis: Forward this to the object we're associated with
+//
+// Returns: New reference count.
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP_(ULONG) CDataObject::AddRef(void)
+{
+ ++_cRef;
+ return(_pteObject->AddRef());
+}
+
+
+//+-------------------------------------------------------------------
+// Method: CDataObject::Release
+//
+// Synopsis: Forward this to the object we're associated with
+//
+// Returns: New reference count.
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP_(ULONG) CDataObject::Release(void)
+{
+ --_cRef;
+ return(_pteObject->Release());
+}
+
+
+//+-------------------------------------------------------------------
+// Method: CDataObject::GetData
+//
+// Synopsis: See spec 2.00.09 p129. Retrieve data for this object
+// using the FORMATETC passed.
+//
+// Parameters: [pformatetcIn] - The format caller wants returned data
+// [pmedium] - Returned data
+//
+// Returns: S_OK, or E_FORMAT if we don't support the format requested
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP CDataObject::GetData(
+ LPFORMATETC pformatetcIn,
+ LPSTGMEDIUM pmedium)
+{
+ // BUGBUG - NYI
+ return(E_FAIL);
+}
+
+
+//+-------------------------------------------------------------------
+// Method: CDataObject::GetDataHere
+//
+// Synopsis: See spec 2.00.09 p130. Like GetData, but the pmedium is
+// allocated and ready for us to use.
+//
+// Parameters: [pformatetc] - The format caller wants returned data
+// [pmedium] - STGMEDIUM object ready for our use
+//
+// Returns: S_OK, E_FORMAT
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP CDataObject::GetDataHere(
+ LPFORMATETC pformatetc,
+ LPSTGMEDIUM pmedium)
+{
+ // BUGBUG - NYI
+ return(E_FAIL);
+}
+
+
+//+-------------------------------------------------------------------
+// Method: CDataObject::QueryGetData
+//
+// Synopsis: See spec 2.00.09 p130. Answer if the format requested
+// would be honored by GetData.
+//
+// Parameters: [pformatetc] - The format being queried about
+//
+// Returns: S_OK or S_FALSE
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP CDataObject::QueryGetData(LPFORMATETC pformatetc)
+{
+ // BUGBUG - NYI
+ return(E_FAIL);
+}
+
+
+//+-------------------------------------------------------------------
+// Method: CDataObject::GetCanonicalFormatEtc
+//
+// Synopsis: See spec 2.00.09 p131
+//
+// Parameters: [pformatetc] -
+// [pformatetcOut] -
+//
+// Returns: S_OK
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP CDataObject::GetCanonicalFormatEtc(
+ LPFORMATETC pformatetc,
+ LPFORMATETC pformatetcOut)
+
+{
+ // BUGBUG - NYI
+ return(E_FAIL);
+}
+
+
+//+-------------------------------------------------------------------
+// Method: CDataObject::SetData
+//
+// Synopsis: See spec 2.00.09 p131.
+//
+// Parameters: [pformatetc] -
+// [pmedium] -
+// [fRelease] -
+//
+// Returns: S_OK
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP CDataObject::SetData(
+ LPFORMATETC pformatetc,
+ STGMEDIUM FAR *pmedium,
+ BOOL fRelease)
+{
+ // BUGBUG - NYI
+ return(DV_E_CLIPFORMAT);
+}
+
+
+//+-------------------------------------------------------------------
+// Method: CDataObject::EnumFormatEtc
+//
+// Synopsis: See spec 2.00.09 p131.
+//
+// Parameters: [dwDirection] -
+// [ppenmFormatEtc] -
+//
+// Returns: S_OK
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP CDataObject::EnumFormatEtc(
+ DWORD dwDirection,
+ LPENUMFORMATETC FAR *ppenmFormatEtc)
+{
+ // BUGBUG - NYI
+ *ppenmFormatEtc = NULL;
+ return(E_FAIL);
+}
+
+
+//+-------------------------------------------------------------------
+// Method: CDataObject::DAdvise
+//
+// Synopsis: See spec 2.00.09 p132
+//
+// Parameters: [pFormatetc] -
+// [advf] -
+// [pAdvSink] -
+// [pdwConnection] -
+//
+// Returns: S_OK
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP CDataObject::DAdvise(
+ FORMATETC FAR *pFormatetc,
+ DWORD advf,
+ LPADVISESINK pAdvSink,
+ DWORD FAR *pdwConnection)
+{
+ if (NULL == _pDAHolder)
+ {
+ if (S_OK != CreateDataAdviseHolder(&_pDAHolder))
+ {
+ return(E_OUTOFMEMORY);
+ }
+ }
+
+ return(_pDAHolder->Advise(this, pFormatetc, advf, pAdvSink, pdwConnection));
+}
+
+
+//+-------------------------------------------------------------------
+// Method: CDataObject::DUnadvise
+//
+// Synopsis: See spec 2.00.09 p133
+//
+// Parameters: [dwConnection] -
+//
+// Returns: S_OK
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP CDataObject::DUnadvise(DWORD dwConnection)
+{
+ if (NULL == _pDAHolder)
+ {
+ // Nobody is registered
+ return(E_INVALIDARG);
+ }
+
+ return(_pDAHolder->Unadvise(dwConnection));
+}
+
+
+//+-------------------------------------------------------------------
+// Method: CDataObject::EnumDAdvise
+//
+// Synopsis: See spec 2.00.09 p133
+//
+// Parameters: [ppenmAdvise] -
+//
+// Returns: S_OK
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP CDataObject::EnumDAdvise(LPENUMSTATDATA FAR *ppenmAdvise)
+{
+ if (NULL == _pDAHolder)
+ {
+ return(E_FAIL);
+ }
+
+ return(_pDAHolder->EnumAdvise(ppenmAdvise));
+}
diff --git a/private/oleutest/server1/ioleobj.cxx b/private/oleutest/server1/ioleobj.cxx
new file mode 100644
index 000000000..a26d53c9a
--- /dev/null
+++ b/private/oleutest/server1/ioleobj.cxx
@@ -0,0 +1,629 @@
+//+-------------------------------------------------------------------
+// File: ioleobj.cxx
+//
+// Contents: IOleObject methods of COleObject class.
+//
+// Classes: COleObject - IOleObject implementation
+//
+// History: 7-Dec-92 DeanE Created
+// 31-Dec-93 ErikGav Chicago port
+//---------------------------------------------------------------------
+#pragma optimize("",off)
+#include <windows.h>
+#include <ole2.h>
+#include "testsrv.hxx"
+
+
+//+-------------------------------------------------------------------
+// Member: COleObject::COleObject()
+//
+// Synopsis: The constructor for COleObject.
+//
+// Arguments: None
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+COleObject::COleObject(CTestEmbed *pteObject)
+{
+ _cRef = 1;
+ _pOAHolder = NULL;
+ _pocs = NULL;
+ _pteObject = pteObject;
+ _pmkContainer = NULL;
+}
+
+
+//+-------------------------------------------------------------------
+// Member: COleObject::~COleObject()
+//
+// Synopsis: The destructor for COleObject.
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+COleObject::~COleObject()
+{
+ // _cRef should be 1
+ if (1 != _cRef)
+ {
+ // BUGBUG - Log error - someone hasn't released
+ }
+
+ if (_pocs != NULL)
+ {
+ _pocs->Release();
+ }
+
+ if (_pmkContainer != NULL)
+ {
+ _pmkContainer->Release();
+ }
+
+}
+
+
+//+-------------------------------------------------------------------
+// Method: COleObject::QueryInterface
+//
+// Synopsis: Forward this to the object we're associated with
+//
+// Parameters: [iid] - Interface ID to return.
+// [ppv] - Pointer to pointer to object.
+//
+// Returns: S_OK if iid is supported, or E_NOINTERFACE if not.
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP COleObject::QueryInterface(REFIID iid, void FAR * FAR *ppv)
+{
+ return(_pteObject->QueryInterface(iid, ppv));
+}
+
+
+//+-------------------------------------------------------------------
+// Method: COleObject::AddRef
+//
+// Synopsis: Forward this to the object we're associated with
+//
+// Returns: New reference count.
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP_(ULONG) COleObject::AddRef(void)
+{
+ ++_cRef;
+ return(_pteObject->AddRef());
+}
+
+
+//+-------------------------------------------------------------------
+// Method: COleObject::Release
+//
+// Synopsis: Forward this to the object we're associated with
+//
+// Returns: New reference count.
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP_(ULONG) COleObject::Release(void)
+{
+ --_cRef;
+ return(_pteObject->Release());
+}
+
+
+//+-------------------------------------------------------------------
+// Method: COleObject::SetClientSite
+//
+// Synopsis: Save the IOleClientSite pointer passed - it's this
+// object's client site object.
+//
+// Parameters: [pClientSite] - Pointer to the new client site object.
+//
+// Returns: S_OK
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP COleObject::SetClientSite(LPOLECLIENTSITE pClientSite)
+{
+ if (_pocs != NULL)
+ {
+ _pocs->Release();
+ }
+
+ _pocs = pClientSite;
+
+ if (pClientSite)
+ {
+ _pocs->AddRef();
+ }
+
+ return(S_OK);
+}
+
+
+//+-------------------------------------------------------------------
+// Method: COleObject::GetClientSite
+//
+// Synopsis: Return this objects current client site - NULL indicates
+// it hasn't been set yet.
+//
+// Parameters: [ppClientSite] - Save current client site pointer here.
+//
+// Returns: S_OK
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP COleObject::GetClientSite(LPOLECLIENTSITE FAR *ppClientSite)
+{
+ *ppClientSite = _pocs;
+ _pocs->AddRef();
+ return(S_OK);
+}
+
+
+//+-------------------------------------------------------------------
+// Method: COleObject::SetHostNames
+//
+// Synopsis: See spec 2.00.09 p99. Returns names the caller can use
+// to display our object name (in window titles and such).
+//
+// Parameters: [szContainerApp] - Name of container application.
+// [szContainerObj] - Name of this object.
+//
+// Returns: S_OK
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP COleObject::SetHostNames(
+ LPCWSTR szContainerApp,
+ LPCWSTR szContainerObj)
+{
+ szContainerApp = L"Test Server";
+ szContainerObj = L"Test Server:Test Object";
+ return(S_OK);
+}
+
+
+//+-------------------------------------------------------------------
+// Method: COleObject::Close
+//
+// Synopsis: See spec 2.00.09 p104. Short story is: if fMerelyHide,
+// turn off the UI of this object, else return to the
+// "loaded" state, which for us means to shut down (since we
+// don't do any caching).
+//
+// Parameters: [dwSaveOption] - ???
+//
+// Returns: S_OK
+//
+// History: 7-Dec-92 DeanE Created
+//
+// Notes: BUGBUG - what if we have multiple instances? Do we
+// return the server app to the loaded state or do we
+// return this object to the loaded state?
+//--------------------------------------------------------------------
+STDMETHODIMP COleObject::Close(DWORD dwSaveOption)
+{
+ // BUGBUG - NYI
+ return(S_OK);
+}
+
+
+//+-------------------------------------------------------------------
+// Method: COleObject::SetMoniker
+//
+// Synopsis: See spec 2.00.09 p99. The moniker for this object
+// (or it's container) has been changed to that passed
+// in. Take appropriate actions (de-register old object
+// and register new, inform contained objects, etc).
+//
+// Parameters: [dwWhichMoniker] - Moniker type being sent.
+// [pmk] - The new moniker.
+//
+// Returns: S_OK
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP COleObject::SetMoniker(DWORD dwWhichMoniker, LPMONIKER pmk)
+{
+ if (_pmkContainer)
+ {
+ _pmkContainer->Release();
+
+ }
+
+ _pmkContainer = pmk;
+
+ pmk->AddRef();
+
+ // Set moniker in container
+ IOleObject *pobj;
+
+ HRESULT hresult = _pocs->QueryInterface(IID_IOleObject, (void **) &pobj);
+
+ pobj->SetMoniker(dwWhichMoniker, pmk);
+
+ pobj->Release();
+
+ return S_OK;
+}
+
+
+//+-------------------------------------------------------------------
+// Method: COleObject::GetMoniker
+//
+// Synopsis: See spec 2.00.09 p100. Return either this objects
+// container moniker, this objects relative moniker, or
+// this objects full moniker.
+//
+// Parameters: [dwAssign] - Condition to get moniker.
+// [dwWhichMoniker] - Kind of moniker being requested.
+// [ppmk] - Return moniker here.
+//
+// Returns: S_OK
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP COleObject::GetMoniker(
+ DWORD dwAssign,
+ DWORD dwWhichMoniker,
+ LPMONIKER FAR *ppmk)
+{
+ *ppmk = _pmkContainer;
+ _pmkContainer->AddRef();
+ return S_OK;
+}
+
+
+//+-------------------------------------------------------------------
+// Method: COleObject::InitFromData
+//
+// Synopsis: See spec 2.00.09 p100. Initialize this object from
+// the format passed in.
+//
+// Parameters: [pDataObject] - IDataObject providing data.
+// [fCreation] - TRUE if this is the initial creation.
+// [dwReserved] - Ignored.
+//
+// Returns: S_OK if we attempt to initialize, S_FALSE if we don't
+// want to.
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP COleObject::InitFromData(
+ LPDATAOBJECT pDataObject,
+ BOOL fCreation,
+ DWORD dwReserved)
+{
+ // BUGBUG - NYI
+ return(S_FALSE);
+}
+
+
+//+-------------------------------------------------------------------
+// Method: COleObject::GetClipboardData
+//
+// Synopsis: See spec 2.00.09 p101. Return clipboard object that would
+// be created if Edit/Copy were done to this item.
+//
+// Parameters: [dwReserved] - Ignored.
+// [ppDataObject] - IDataObject return locale.
+//
+// Returns: S_OK or ???
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP COleObject::GetClipboardData(
+ DWORD dwReserved,
+ LPDATAOBJECT FAR *ppDataObject)
+{
+ // BUGBUG - NYI
+ *ppDataObject = NULL;
+ return(S_OK);
+}
+
+
+//+-------------------------------------------------------------------
+// Method: COleObject::DoVerb
+//
+// Synopsis: See spec 2.00.09 p101. Execute the verb passed in.
+//
+// Parameters: [iVerb] - Verb being requested.
+// [pMsg] - Message that triggered the request.
+// [pActiveSite] - IOleClientSite for this object.
+// [lReserved] - Ignored.
+//
+// Returns: S_OK, or other ones specified but not defined yet...
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP COleObject::DoVerb(
+ LONG iVerb,
+ LPMSG pMsg,
+ LPOLECLIENTSITE pActiveSite,
+ LONG lReserved,
+ HWND hwndParent,
+ LPCRECT lprcPosRect)
+{
+ // HWND hwndObj;
+
+ if (OLEIVERB_SHOW == iVerb)
+ {
+ // BUGBUG - NYI
+ // Display the object (we're not in-place yet)
+ // PostMessage(g_hwndMain, WM_REPORT, MB_SHOWVERB, 0);
+ // PostMessage(0xFFFF, WM_REPORT, MB_SHOWVERB, 0);
+ // MessageBox(g_hwndMain, L"Received OLEIVERB_SHOW", L"OLE Server", MB_ICONINFORMATION | MB_OK);
+
+ // Get hwndObj
+ //_pteObject->GetWindow(&hwndObj);
+ //MessageBox(hwndObj, L"Received OLEIVERB_SHOW", L"OLE Server", MB_ICONINFORMATION | MB_OK);
+ }
+ else
+ {
+ // Return alternate error code?
+ }
+
+ return(S_OK);
+}
+
+
+//+-------------------------------------------------------------------
+// Method: COleObject::EnumVerbs
+//
+// Synopsis: See spec 2.00.09 p103. Enumerate all the verbs available
+// on this object in increasing numerical order.
+//
+// Parameters: [ppenmOleVerb] - Enumeration object return locale.
+//
+// Returns: S_OK or ???
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP COleObject::EnumVerbs(IEnumOLEVERB FAR* FAR *ppenmOleVerb)
+{
+ // BUGBUG - NYI
+ *ppenmOleVerb = NULL;
+ return(S_OK);
+}
+
+
+//+-------------------------------------------------------------------
+// Method: COleObject::Update
+//
+// Synopsis: See spec 2.00.09 p105. Ensure any data or view caches
+// maintained inside the object are up to date.
+//
+// Parameters: None
+//
+// Returns: S_OK
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP COleObject::Update()
+{
+ // We don't use any caches, so we don't have to do anything
+ return(S_OK);
+}
+
+
+//+-------------------------------------------------------------------
+// Method: COleObject::IsUpToDate
+//
+// Synopsis: See spec 2.00.09 p105. Check to see if this object is
+// up to date - including embedded children, etc.
+//
+// Parameters: None
+//
+// Returns: S_OK, S_FALSE, or ???
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP COleObject::IsUpToDate()
+{
+ // We should always be up to date as we don't have any caches
+ // or children or links
+ return(S_OK);
+}
+
+
+//+-------------------------------------------------------------------
+// Method: COleObject::GetUserClassID
+//
+// Synopsis: I have little idea what this does. It's not in the
+// spec 2.00.09.
+//
+// Parameters: [dwFormOfType] -
+// [pszUserType] -
+//
+// Returns: S_OK?
+//
+// History: 16-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP COleObject::GetUserClassID(
+ CLSID FAR *pClsid)
+{
+ // BUGBUG - NYI
+ return(E_FAIL);
+}
+
+
+//+-------------------------------------------------------------------
+// Method: COleObject::GetUserType
+//
+// Synopsis: I have little idea what this does. It's not in the
+// spec 2.00.09.
+//
+// Parameters: [dwFormOfType] -
+// [pszUserType] -
+//
+// Returns: S_OK?
+//
+// History: 16-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP COleObject::GetUserType(
+ DWORD dwFormOfType,
+ LPWSTR FAR *pszUserType)
+{
+ // BUGBUG - NYI
+ return(E_FAIL);
+}
+
+
+//+-------------------------------------------------------------------
+// Method: COleObject::SetExtent
+//
+// Synopsis: See spec 2.00.09 p106. Set the rectangular extent of
+// this object. Container will call us with the size
+// it will give us; we must fit accordingly.
+//
+// Parameters: [dwDrawAspect] - DVASPECT specified for this object.
+// [lpsizel] - Extent structure.
+//
+// Returns: S_OK
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP COleObject::SetExtent(DWORD dwDrawAspect, LPSIZEL lpsizel)
+{
+ // BUGBUG - NYI
+ return(S_OK);
+}
+
+
+//+-------------------------------------------------------------------
+// Method: COleObject::GetExtent
+//
+// Synopsis: See spec 2.00.09 p106. Size of the object given in the
+// the last SetExtent call is returned. If SetExtent has
+// not been called, the natural size of the object is
+// returned.
+//
+// Parameters: [dwDrawAspect] - DVASPECT specified for this object.
+// [lpsizel] - Extent structure to set.
+//
+// Returns: S_OK
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP COleObject::GetExtent(DWORD dwDrawAspect, LPSIZEL lpsizel)
+{
+ // BUGBUG - NYI
+ return(S_OK);
+}
+
+
+//+-------------------------------------------------------------------
+// Method: COleObject::Advise
+//
+// Synopsis: See spec 2.00.09 p121. Set up an advisory connection
+// between this object and an advisory sink; when certain
+// events happen (birthdays?) this sink should be informed
+// by this object. Use the OleAdviseHolder object as a
+// helper (see p122).
+//
+// Parameters: [pAdvSink] - Sink that should be informed of changes.
+// [pdwConnection] - Pass advisory token returned so our
+// caller can shut down the link.
+//
+// Returns: S_OK
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP COleObject::Advise(
+ IAdviseSink FAR *pAdvSink,
+ DWORD FAR *pdwConnection)
+{
+// if (NULL == _pOAHolder)
+// {
+// if (S_OK != CreateOleAdviseHolder(&_pOAHolder))
+// {
+// return(E_OUTOFMEMORY);
+// }
+// }
+//
+// return(_pOAHolder->Advise(pAdvSink, pdwConnection));
+ return S_OK;
+}
+
+
+//+-------------------------------------------------------------------
+// Method: COleObject::Unadvise
+//
+// Synopsis: See spec 2.00.09 p121. Tear down an advisory connection
+// set up previously.
+//
+// Parameters: [dwConnection] - Connection established earlier.
+//
+// Returns: S_OK or ???
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP COleObject::Unadvise(DWORD dwConnection)
+{
+ if (NULL == _pOAHolder)
+ {
+ // No one is registered - see ellipswt.cpp for this
+ return(E_INVALIDARG);
+ }
+
+ return(_pOAHolder->Unadvise(dwConnection));
+}
+
+
+//+-------------------------------------------------------------------
+// Method: COleObject::EnumAdvise
+//
+// Synopsis: See spec 2.00.09 p122. Enumerate the advisory connections
+// currently attached to this object.
+//
+// Parameters: [ppenmAdvise] - Enumeration object to return.
+//
+// Returns: S_OK
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP COleObject::EnumAdvise(LPENUMSTATDATA FAR *ppenmAdvise)
+{
+ if (NULL == _pOAHolder)
+ {
+ return(E_FAIL);
+ }
+ return(_pOAHolder->EnumAdvise(ppenmAdvise));
+}
+
+
+//+-------------------------------------------------------------------
+// Method: COleObject::GetMiscStatus
+//
+// Synopsis: I have little idea what this does. It's not in the
+// spec 2.00.09.
+//
+// Returns: S_OK?
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP COleObject::GetMiscStatus(
+ DWORD dwAspect,
+ DWORD FAR *pdwStatus)
+{
+ // BUGBUG - NYI
+ return(E_FAIL);
+}
+
+
+//+-------------------------------------------------------------------
+// Method: COleObject::SetColorScheme
+//
+// Synopsis: I have little idea what this does. It's not in the
+// spec 2.00.09.
+//
+// Returns: S_OK?
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP COleObject::SetColorScheme(LPLOGPALETTE lpLogpal)
+{
+ // BUGBUG - NYI
+ return(S_OK);
+}
diff --git a/private/oleutest/server1/ipersist.cxx b/private/oleutest/server1/ipersist.cxx
new file mode 100644
index 000000000..4928a1e01
--- /dev/null
+++ b/private/oleutest/server1/ipersist.cxx
@@ -0,0 +1,251 @@
+//+-------------------------------------------------------------------
+// File: ipersist.cxx
+//
+// Contents: IPersist and IPersistStorage methods of CPersistStorage class.
+//
+// Classes: CPersistStorage - IPersist, IPersistStorage implementations
+//
+// History: 7-Dec-92 DeanE Created
+//---------------------------------------------------------------------
+#pragma optimize("",off)
+#include <windows.h>
+#include <ole2.h>
+#include "testsrv.hxx"
+
+
+//+-------------------------------------------------------------------
+// Member: CPersistStorage::CPersistStorage()
+//
+// Synopsis: The constructor for CPersistStorage.
+//
+// Arguments: None
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+CPersistStorage::CPersistStorage(CTestEmbed *pteObject)
+{
+ _cRef = 1;
+ _pteObject = pteObject;
+ _fDirty = FALSE;
+}
+
+
+//+-------------------------------------------------------------------
+// Member: CPersistStorage::~CPersistStorage()
+//
+// Synopsis: The destructor for CPersistStorage.
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+CPersistStorage::~CPersistStorage()
+{
+ // _cRef should be 1
+ if (1 != _cRef)
+ {
+ // BUGBUG - Log error, someone hasn't released
+ }
+ return;
+}
+
+
+//+-------------------------------------------------------------------
+// Method: CPersistStorage::QueryInterface
+//
+// Synopsis: Forward this to the object we're associated with
+//
+// Parameters: [iid] - Interface ID to return.
+// [ppv] - Pointer to pointer to object.
+//
+// Returns: S_OK if iid is supported, or E_NOINTERFACE if not.
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP CPersistStorage::QueryInterface(REFIID iid, void FAR * FAR *ppv)
+{
+ return(_pteObject->QueryInterface(iid, ppv));
+}
+
+
+//+-------------------------------------------------------------------
+// Method: CPersistStorage::AddRef
+//
+// Synopsis: Forward this to the object we're associated with
+//
+// Returns: New reference count.
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP_(ULONG) CPersistStorage::AddRef(void)
+{
+ ++_cRef;
+ return(_pteObject->AddRef());
+}
+
+
+//+-------------------------------------------------------------------
+// Method: CPersistStorage::Release
+//
+// Synopsis: Forward this to the object we're associated with
+//
+// Returns: New reference count.
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP_(ULONG) CPersistStorage::Release(void)
+{
+ --_cRef;
+ return(_pteObject->Release());
+}
+
+
+//+-------------------------------------------------------------------
+// Method: CPersistStorage::GetClassId
+//
+// Synopsis: See spec 2.00.09 p197. Answer the Class ID of this
+// object.
+//
+// Parameters: [pClassId] -
+//
+// Returns: S_OK
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP CPersistStorage::GetClassID(LPCLSID pClassId)
+{
+ if (NULL != pClassId)
+ {
+ *pClassId = CLSID_TestEmbed;
+ }
+ return(S_OK);
+}
+
+
+//+-------------------------------------------------------------------
+// Method: CPersistStorage::IsDirty
+//
+// Synopsis: See spec 2.00.09 p200. Return S_OK if the object needs
+// to be saved in order to avoid data loss, or S_FALSE
+// if not.
+//
+// Parameters: None
+//
+// Returns: S_OK or S_FALSE
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP CPersistStorage::IsDirty()
+{
+ // BUGBUG - NYI
+ // Because we are NYI, just return S_FALSE
+ return(S_FALSE);
+}
+
+
+//+-------------------------------------------------------------------
+// Method: CPersistStorage::InitNew
+//
+// Synopsis: See spec 2.00.09 p197. This method provides a way
+// for a container to provide persistent storage to this
+// object. Call AddRef on the pStg passed if we do save
+// it.
+//
+// Parameters: [pStg] - IStorage instance this object can use.
+//
+// Returns: S_OK
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP CPersistStorage::InitNew(LPSTORAGE pStg)
+{
+ // BUGBUG - NYI
+ return(S_OK);
+}
+
+
+//+-------------------------------------------------------------------
+// Method: CPersistStorage::Load
+//
+// Synopsis: See spec 2.00.09 p200. Called by handler to put this
+// object into the running state. Object should use the
+// pStg passed to "initialize" itself. We can hold onto
+// this pStg, but when ::Save is called, this can be
+// a different IStorage.
+//
+// Parameters: [pStg] - IStorage to initialize object from.
+//
+// Returns: S_OK?
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP CPersistStorage::Load(LPSTORAGE pStg)
+{
+ // BUGBUG - NYI
+ // Initialize the object here, though, just as if we had obtained
+ // data from an IStorage
+ return(S_OK);
+}
+
+
+//+-------------------------------------------------------------------
+// Method: CPersistStorage::Save
+//
+// Synopsis: See spec 2.00.09 p197. Save the data in the IStorage
+// passed. Ignore flags for now.
+//
+// Parameters: [pStgSave] - Save data in here.
+// [fSameAsLoad] - Indicates this object is the same one
+// that was initially started.
+// [fRemember] - Only matters if fSameAsLoad is FALSE.
+//
+// Returns: STG_E_MEDIUMFULL - why???
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP CPersistStorage::Save(
+ LPSTORAGE pStgSave,
+ BOOL fSameAsLoad)
+{
+ // BUGBUG - NYI
+ return(STG_E_MEDIUMFULL);
+}
+
+
+//+-------------------------------------------------------------------
+// Method: CPersistStorage::SaveCompleted
+//
+// Synopsis: See spec 2.00.09 p198. Used only in certain circumstances.
+//
+// Parameters: [pStgSaved] -
+//
+// Returns: S_OK
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP CPersistStorage::SaveCompleted(LPSTORAGE pStgSaved)
+{
+ // BUGBUG - NYI
+ // We don't have to worry about this unless we allow a "Save As"
+ // operation
+ return(S_OK);
+}
+
+
+
+//+-------------------------------------------------------------------
+// Method: CPersistStorage::HandsOffStorage
+//
+// Synopsis: See spec 2.00.09 p198. Used only in certain circumstances.
+//
+// Parameters: [pStgSaved] -
+//
+// Returns: S_OK
+//
+// History: 7-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+STDMETHODIMP CPersistStorage::HandsOffStorage(void)
+{
+ // BUGBUG - NYI
+ // We don't have to worry about this unless we allow a "Save As"
+ // operation
+ return(S_OK);
+}
diff --git a/private/oleutest/server1/testsrv.cxx b/private/oleutest/server1/testsrv.cxx
new file mode 100644
index 000000000..6c1a2181e
--- /dev/null
+++ b/private/oleutest/server1/testsrv.cxx
@@ -0,0 +1,204 @@
+//+-------------------------------------------------------------------
+// File: testsrv.cxx
+//
+// Contents:
+//
+// Classes: CBasicSrvCF - IUnknown IClassFactory
+// CBasicSrv - IUnknown IPersist IPersistFile IParseDisplayName
+//
+// Notes: This code is written based on OLE2.0 code. Therefore
+// all error codes, defines etc are OLE style rather than Cairo
+//
+// History: 24-Nov-92 DeanE Created
+// 31-Dec-93 ErikGav Chicago port
+//---------------------------------------------------------------------
+#pragma optimize("",off)
+#include <windows.h>
+#include <ole2.h>
+#include "testsrv.hxx"
+#include <stdio.h>
+
+// BUGBUG - memory allocation hacks need these so new and delete don't
+// break us
+//
+#include <malloc.h>
+#include <dos.h>
+
+#define IDM_DEBUG 0x100
+
+extern "C" LRESULT FAR PASCAL MainWndProc(HWND, UINT, WPARAM, LPARAM);
+void ReportMessage(HWND, WORD);
+
+// This is global because we're still in $%E#$#K 16-bit world
+HWND g_hwndMain = NULL;
+
+// Note constructor cannot fail
+CTestServerApp tsaMain;
+
+
+//+--------------------------------------------------------------
+// Function: WinMain
+//
+// Synopsis: Initializes application and controls message pump.
+//
+// Returns: Exits with exit code 0 if success, non-zero otherwise
+//
+// History: 25-Nov-92 DeanE Created
+//---------------------------------------------------------------
+int PASCAL WinMain(
+ HINSTANCE hInstance,
+ HINSTANCE hPrevInstance,
+ LPSTR lpszCmdline,
+ int nCmdShow)
+{
+ static TCHAR szAppName[] = TEXT("OleServer");
+ MSG msg;
+ WNDCLASS wndclass;
+
+ if (!hPrevInstance)
+ {
+ wndclass.style = CS_HREDRAW | CS_VREDRAW;
+ wndclass.lpfnWndProc = MainWndProc;
+ wndclass.cbClsExtra = 0;
+ wndclass.cbWndExtra = 0;
+ wndclass.hInstance = hInstance;
+ wndclass.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(125));
+ wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wndclass.hbrBackground = (HBRUSH) GetStockObject(BLACK_BRUSH);
+ wndclass.lpszMenuName = NULL;
+ wndclass.lpszClassName = szAppName;
+
+ if (0==RegisterClass(&wndclass))
+ {
+ // Error! Clean up and exit
+ return(LOG_ABORT);
+ }
+ }
+
+ g_hwndMain = CreateWindow(
+ szAppName,
+ TEXT("OLE Server"),
+ WS_OVERLAPPEDWINDOW | WS_VSCROLL,
+ GetSystemMetrics(SM_CXSCREEN)/12, // Init X pos
+ GetSystemMetrics(SM_CYSCREEN)/12, // Init Y pos
+ GetSystemMetrics(SM_CXSCREEN)*2/3, // width
+ GetSystemMetrics(SM_CYSCREEN)*2/3, // height
+ NULL,
+ NULL,
+ hInstance,
+ NULL);
+
+ if (NULL==g_hwndMain)
+ {
+ // Error! Clean up and exit
+ return(LOG_ABORT);
+ }
+
+ // Add debug option to system menu
+ HMENU hmenu = GetSystemMenu(g_hwndMain, FALSE);
+
+ AppendMenu(hmenu, MF_SEPARATOR, 0, NULL);
+ AppendMenu(hmenu, MF_STRING | MF_ENABLED, IDM_DEBUG, TEXT("Debug"));
+
+
+ // Initialize Application
+ if (S_OK != tsaMain.InitApp(lpszCmdline))
+ {
+ tsaMain.CloseApp();
+ return(LOG_ABORT);
+ }
+
+ if (tsaMain.GetEmbeddedFlag())
+ {
+ // We're running as an embedded app
+ // Don't show the main window unless we're instructed to do so
+ // BUGBUG - In-place editing is NYI
+ ShowWindow(g_hwndMain, SW_SHOWMINIMIZED);
+ }
+ else
+ {
+ // We are not running as an embedded app - show the main window
+ ShowWindow(g_hwndMain, nCmdShow);
+ }
+
+ UpdateWindow(g_hwndMain);
+
+
+ // message loop
+ while (GetMessage(&msg, NULL, 0, 0))
+ {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+
+ // Clean up and exit
+ // BUGBUG - check return code?
+ tsaMain.CloseApp();
+
+ return(0);
+}
+
+
+//+--------------------------------------------------------------
+// Function: MainWndProc
+//
+// Synopsis: Callback for the server window
+//
+// Returns: Varies dependent on message received.
+//
+// History: 25-Nov-92 DeanE Created
+//---------------------------------------------------------------
+extern "C" LRESULT FAR PASCAL MainWndProc(
+ HWND hwnd,
+ UINT wMsg,
+ WPARAM wParam,
+ LPARAM lParam)
+{
+ switch(wMsg)
+ {
+ case WM_DESTROY:
+ PostQuitMessage(0);
+ return(0);
+
+ case WM_USER:
+ DestroyWindow(hwnd);
+ return 0;
+
+ case WM_SYSCOMMAND:
+
+ if (wParam == IDM_DEBUG)
+ {
+ // Request for a debug breakpoint!
+ DebugBreak();
+ }
+
+ default:
+ break;
+ }
+
+ return(DefWindowProc(hwnd, wMsg, wParam, lParam));
+}
+
+
+void ReportMessage(HWND hwnd, WORD wParam)
+{
+ TCHAR szBuffer[256];
+ szBuffer[0] = '\0';
+
+ switch (wParam)
+ {
+ case MB_SHOWVERB:
+ lstrcpy(szBuffer, TEXT("OLEIVERB_SHOW Received"));
+ break;
+
+ case MB_PRIMVERB:
+ lstrcpy(szBuffer, TEXT("OLEIVERB_PRIMARY Received"));
+ break;
+
+ default:
+ lstrcpy(szBuffer, TEXT("Unrecognized ReportMessage code"));
+ break;
+ }
+
+ MessageBox(hwnd, szBuffer, TEXT("OLE Server"), MB_ICONINFORMATION | MB_OK);
+}
diff --git a/private/oleutest/server1/testsrv.hxx b/private/oleutest/server1/testsrv.hxx
new file mode 100644
index 000000000..a47aef4f2
--- /dev/null
+++ b/private/oleutest/server1/testsrv.hxx
@@ -0,0 +1,386 @@
+//+-------------------------------------------------------------------
+// File: testsrv.hxx
+//
+// Contents: CTestEmbedCF and CTestEmbed object declarations, other
+// miscellaneous tidbits.
+//
+// History: 24-Nov-92 DeanE Created
+// 31-Dec-93 ErikGav Chicago port
+//---------------------------------------------------------------------
+
+#ifndef __TESTSRV_HXX__
+#define __TESTSRV_HXX__
+
+#include <com.hxx>
+
+#define LOG_ABORT -1
+#define LOG_PASS 1
+#define LOG_FAIL 0
+
+// Application Window messages
+#define WM_RUNTEST (WM_USER + 1)
+#define WM_REPORT (WM_USER + 2)
+
+
+// WM_REPORT wParam codes
+#define MB_SHOWVERB 0x0001
+#define MB_PRIMVERB 0x0002
+
+//+---------------------------------------------------------------------------
+//
+// Function: operator new, public
+//
+// Synopsis: Global operator new which uses CoTaskMemAlloc
+//
+// Arguments: [size] -- Size of the memory to allocate.
+//
+// Returns: A pointer to the allocated memory. Is *NOT* initialized to 0!
+//
+//----------------------------------------------------------------------------
+
+inline void* _CRTAPI1
+operator new (size_t size)
+{
+ return(CoTaskMemAlloc(size));
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: operator delete
+//
+// Synopsis: Free a block of memory using CoTaskMemFree
+//
+// Arguments: [lpv] - block to free.
+//
+//--------------------------------------------------------------------------
+
+inline void _CRTAPI1 operator delete(void FAR* lpv)
+{
+ CoTaskMemFree(lpv);
+}
+
+// Global variables
+extern HWND g_hwndMain;
+
+
+// Forward declarations
+class FAR CDataObject;
+class FAR CPersistStorage;
+class FAR COleObject;
+class FAR CTestEmbedCF;
+
+
+//+-------------------------------------------------------------------
+// Class: CTestServerApp
+//
+// Synopsis: Class that holds application-wide data and methods
+//
+// Methods: InitApp
+// CloseApp
+// GetEmbeddedFlag
+//
+// History: 17-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+class FAR CTestServerApp
+{
+public:
+
+// Constructor/Destructor
+ CTestServerApp();
+ ~CTestServerApp();
+
+ SCODE InitApp (LPSTR lpszCmdline);
+ SCODE CloseApp (void);
+ BOOL GetEmbeddedFlag (void);
+ ULONG IncEmbeddedCount(void);
+ ULONG DecEmbeddedCount(void);
+
+private:
+ IClassFactory *_pteClassFactory;
+ ULONG _cEmbeddedObjs; // Count of embedded objects this server
+ // is controlling now
+ DWORD _dwRegId; // OLE registration ID
+ BOOL _fRegistered; // TRUE if srv was registered w/OLE
+ BOOL _fInitialized; // TRUE if OleInitialize was OK
+ BOOL _fEmbedded; // TRUE if OLE started us at the request
+ // of an embedded obj in a container app
+};
+
+
+//+-------------------------------------------------------------------
+// Class: CTestEmbedCF
+//
+// Synopsis: Class Factory for CTestEmbed object type
+//
+// Methods: QueryInterface - IUnknown
+// AddRef - IUnknown
+// Release - IUnknown
+// CreateInstance - IClassFactory
+// LockServer - IClassFactory
+//
+// History: 24-Nov-92 DeanE Created
+//--------------------------------------------------------------------
+class CTestEmbedCF : public IClassFactory
+{
+public:
+
+// Constructor/Destructor
+ CTestEmbedCF(CTestServerApp *ptsaServer);
+ ~CTestEmbedCF();
+ static IClassFactory FAR *Create(CTestServerApp *ptsaServer);
+
+// IUnknown
+ STDMETHODIMP QueryInterface (REFIID iid, void FAR * FAR *ppv);
+ STDMETHODIMP_(ULONG) AddRef (void);
+ STDMETHODIMP_(ULONG) Release (void);
+
+// IClassFactory
+ STDMETHODIMP CreateInstance (IUnknown FAR *pUnkOuter,
+ REFIID iidInterface,
+ void FAR * FAR *ppv);
+ STDMETHODIMP LockServer (BOOL fLock);
+
+private:
+
+ ULONG _cRef; // Reference count on this object
+
+ CTestServerApp *_ptsaServer; // Controlling server app
+};
+
+
+//+-------------------------------------------------------------------
+// Class: CTestEmbed
+//
+// Synopsis: CTestEmbed (one instance per object)
+//
+// Methods: QueryInterface IUnknown
+// AddRef IUnknown
+// Release IUnknown
+// InitObject
+//
+// History: 24-Nov-92 DeanE Created
+//--------------------------------------------------------------------
+class CTestEmbed : public IUnknown
+{
+public:
+// Constructor/Destructor
+ CTestEmbed();
+ ~CTestEmbed();
+
+// IUnknown
+ STDMETHODIMP QueryInterface(REFIID iid, void FAR * FAR *ppv);
+ STDMETHODIMP_(ULONG) AddRef (void);
+ STDMETHODIMP_(ULONG) Release (void);
+
+ SCODE InitObject (CTestServerApp *ptsaServer, HWND hwnd);
+ SCODE GetWindow (HWND *phwnd);
+
+private:
+
+ ULONG _cRef; // Reference counter
+ CTestServerApp *_ptsaServer; // Server "holding" this object
+ CDataObject *_pDataObject; // Points to object's IDataObject
+ COleObject *_pOleObject; // Points to object's IOleObject
+ CPersistStorage *_pPersStg; // Points to object's IPersistStorage
+ HWND _hwnd; // Window handle for this object
+};
+
+
+//+-------------------------------------------------------------------
+// Class: CDataObject
+//
+// Synopsis: Test class CDataObject
+//
+// Methods: QueryInterface IUnknown
+// AddRef IUnknown
+// Release IUnknown
+// GetData IDataObject
+// GetDataHere IDataObject
+// QueryGetData IDataObject
+// GetCanonicalFormatEtc IDataObject
+// SetData IDataObject
+// EnumFormatEtc IDataObject
+// DAdvise IDataObject
+// DUnadvise IDataObject
+// EnumDAdvise IDataObject
+//
+// History: 24-Nov-92 DeanE Created
+//--------------------------------------------------------------------
+class FAR CDataObject : public IDataObject
+{
+public:
+// Constructor/Destructor
+ CDataObject(CTestEmbed *pteObject);
+ ~CDataObject();
+
+// IUnknown - Everyone inherits from this
+ STDMETHODIMP QueryInterface(REFIID iid, void FAR * FAR *ppv);
+ STDMETHODIMP_(ULONG) AddRef (void);
+ STDMETHODIMP_(ULONG) Release (void);
+
+// IDataObject
+ STDMETHODIMP GetData (LPFORMATETC pformatetcIn,
+ LPSTGMEDIUM pmedium);
+ STDMETHODIMP GetDataHere (LPFORMATETC pformatetc,
+ LPSTGMEDIUM pmedium);
+ STDMETHODIMP QueryGetData (LPFORMATETC pformatetc);
+ STDMETHODIMP GetCanonicalFormatEtc(
+ LPFORMATETC pformatetc,
+ LPFORMATETC pformatetcOut);
+ STDMETHODIMP SetData (LPFORMATETC pformatetc,
+ STGMEDIUM FAR *pmedium,
+ BOOL fRelease);
+ STDMETHODIMP EnumFormatEtc (DWORD dwDirection,
+ LPENUMFORMATETC FAR *ppenmFormatEtc);
+ STDMETHODIMP DAdvise (FORMATETC FAR *pFormatetc,
+ DWORD advf,
+ LPADVISESINK pAdvSink,
+ DWORD FAR *pdwConnection);
+ STDMETHODIMP DUnadvise (DWORD dwConnection);
+ STDMETHODIMP EnumDAdvise (LPENUMSTATDATA FAR *ppenmAdvise);
+
+private:
+ ULONG _cRef; // Reference count
+ IDataAdviseHolder FAR *_pDAHolder; // Advise Holder
+ CTestEmbed *_pteObject; // Object we're associated with
+};
+
+
+//+-------------------------------------------------------------------
+// Class: COleObject
+//
+// Synopsis: COleObject implements the IOleObject interface for OLE
+// objects within the server. There will be one instantiation
+// per OLE object.
+//
+// Methods: QueryInterface IUnknown
+// AddRef IUnknown
+// Release IUnknown
+// SetClientSite IOleObject
+// GetClientSite IOleObject
+// SetHostNames IOleObject
+// Close IOleObject
+// SetMoniker IOleObject
+// GetMoniker IOleObject
+// InitFromData IOleObject
+// GetClipboardData IOleObject
+// DoVerb IOleObject
+// EnumVerbs IOleObject
+// Update IOleObject
+// IsUpToDate IOleObject
+// GetUserType IOleObject
+// SetExtent IOleObject
+// GetExtent IOleObject
+// Advise IOleObject
+// Unadvise IOleObject
+// EnumAdvise IOleObject
+// GetMiscStatus IOleObject
+// SetColorScheme IOleObject
+//
+// History: 17-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+class FAR COleObject : public IOleObject
+{
+public:
+// Constructor/Destructor
+ COleObject(CTestEmbed *pteObject);
+ ~COleObject();
+
+// IUnknown
+ STDMETHODIMP QueryInterface(REFIID iid, void FAR * FAR *ppv);
+ STDMETHODIMP_(ULONG) AddRef (void);
+ STDMETHODIMP_(ULONG) Release (void);
+
+// IOleObject
+ STDMETHODIMP SetClientSite (LPOLECLIENTSITE pClientSite);
+ STDMETHODIMP GetClientSite (LPOLECLIENTSITE FAR *ppClientSite);
+ STDMETHODIMP SetHostNames (LPCWSTR szContainerApp, LPCWSTR szContainerObj);
+ STDMETHODIMP Close (DWORD dwSaveOption);
+ STDMETHODIMP SetMoniker (DWORD dwWhichMoniker, LPMONIKER pmk);
+ STDMETHODIMP GetMoniker (DWORD dwAssign,
+ DWORD dwWhichMoniker,
+ LPMONIKER FAR *ppmk);
+ STDMETHODIMP InitFromData (LPDATAOBJECT pDataObject,
+ BOOL fCreation,
+ DWORD dwReserved);
+ STDMETHODIMP GetClipboardData(
+ DWORD dwReserved,
+ LPDATAOBJECT FAR *ppDataObject);
+ STDMETHODIMP DoVerb (LONG iVerb,
+ LPMSG pMsg,
+ LPOLECLIENTSITE pActiveSite,
+ LONG lReserved,
+ HWND hwndParent,
+ LPCRECT lprcPosRect);
+ STDMETHODIMP EnumVerbs (IEnumOLEVERB FAR* FAR* ppenmOleVerb);
+ STDMETHODIMP Update (void);
+ STDMETHODIMP IsUpToDate (void);
+ STDMETHODIMP GetUserClassID(CLSID FAR* pClsid);
+ STDMETHODIMP GetUserType (DWORD dwFormOfType, LPWSTR FAR *pszUserType);
+ STDMETHODIMP SetExtent (DWORD dwDrawAspect, LPSIZEL lpsizel);
+ STDMETHODIMP GetExtent (DWORD dwDrawAspect, LPSIZEL lpsizel);
+ STDMETHODIMP Advise (IAdviseSink FAR *pAdvSink,
+ DWORD FAR *pdwConnection);
+ STDMETHODIMP Unadvise (DWORD dwConnection);
+ STDMETHODIMP EnumAdvise (LPENUMSTATDATA FAR *ppenmAdvise);
+ STDMETHODIMP GetMiscStatus (DWORD dwAspect, DWORD FAR *pdwStatus);
+ STDMETHODIMP SetColorScheme(LPLOGPALETTE lpLogpal);
+
+private:
+ ULONG _cRef; // Reference count
+ IOleAdviseHolder FAR *_pOAHolder; // Advise Holder
+ IOleClientSite FAR *_pocs; // This objects client site
+ CTestEmbed *_pteObject; // Object we're associated with
+ IMoniker * _pmkContainer;
+};
+
+
+//+-------------------------------------------------------------------
+// Class: CPersistStorage
+//
+// Synopsis: Test class CPersistStorage
+//
+// Methods: QueryInterface IUnknown
+// AddRef IUnknown
+// Release IUnknown
+// GetClassId IPersist
+// IsDirty IPersistStorage
+// InitNew IPersistStorage
+// Load IPersistStorage
+// Save IPersistStorage
+// SaveCompleted IPersistStorage
+//
+// History: 24-Nov-92 DeanE Created
+//--------------------------------------------------------------------
+class FAR CPersistStorage : public IPersistStorage
+{
+public:
+// Constructor/Destructor
+ CPersistStorage(CTestEmbed *pteObject);
+ ~CPersistStorage();
+
+// IUnknown - Everyone inherits from this
+ STDMETHODIMP QueryInterface(REFIID iid, void FAR * FAR *ppv);
+ STDMETHODIMP_(ULONG) AddRef (void);
+ STDMETHODIMP_(ULONG) Release (void);
+
+// IPersist - IPersistStorage inherits from this
+ STDMETHODIMP GetClassID (LPCLSID pClassId);
+
+// IPersistStorage
+ STDMETHODIMP IsDirty (void);
+ STDMETHODIMP InitNew (LPSTORAGE pStg);
+ STDMETHODIMP Load (LPSTORAGE pStg);
+ STDMETHODIMP Save (LPSTORAGE pStgSave,
+ BOOL fSameAsLoad);
+ STDMETHODIMP SaveCompleted (LPSTORAGE pStgSaved);
+ STDMETHODIMP HandsOffStorage (void);
+
+private:
+ ULONG _cRef; // Reference count
+ CTestEmbed *_pteObject; // Object we're associated with
+ BOOL _fDirty; // TRUE if object is dirty
+};
+
+
+#endif // __TESTSRV_HXX__
diff --git a/private/oleutest/server1/testsrv.ico b/private/oleutest/server1/testsrv.ico
new file mode 100644
index 000000000..05dac99c1
--- /dev/null
+++ b/private/oleutest/server1/testsrv.ico
Binary files differ
diff --git a/private/oleutest/server1/testsrv.rc b/private/oleutest/server1/testsrv.rc
new file mode 100644
index 000000000..51681d8b2
--- /dev/null
+++ b/private/oleutest/server1/testsrv.rc
@@ -0,0 +1,3 @@
+#include <windows.h>
+
+125 ICON testsrv.ico
diff --git a/private/oleutest/server2/daytona/makefile b/private/oleutest/server2/daytona/makefile
new file mode 100644
index 000000000..1d3728d41
--- /dev/null
+++ b/private/oleutest/server2/daytona/makefile
@@ -0,0 +1,10 @@
+############################################################################
+#
+# Copyright (C) 1992, Microsoft Corporation.
+#
+# All rights reserved.
+#
+############################################################################
+
+!include $(NTMAKEENV)\makefile.def
+
diff --git a/private/oleutest/server2/daytona/sources b/private/oleutest/server2/daytona/sources
new file mode 100644
index 000000000..498f20e47
--- /dev/null
+++ b/private/oleutest/server2/daytona/sources
@@ -0,0 +1,75 @@
+!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:
+
+ Donna Liu (DonnaLi) 19-Dec-1993
+
+!ENDIF
+
+MAJORCOMP = cairole
+MINORCOMP = com
+
+#
+# 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= olesrv
+
+#
+# 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= ..\..\..\ole32\common\daytona;..\..\..\ole32\ih;..;..\..\common;..\..\..\cinc
+
+!include ..\..\daytona.inc
+
+C_DEFINES= \
+ $(C_DEFINES)
+
+SOURCES= \
+ ..\olesrv.cxx \
+ ..\wterm.c
+
+UMTYPE= windows
+UMENTRY= winmain
+UMAPPL=
+UMTEST=
+UMLIBS= \
+ ..\..\assert\daytona\obj\*\assert.lib \
+ $(BASEDIR)\public\sdk\lib\*\ole32.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\*\crtdll.lib \
+ $(BASEDIR)\public\sdk\lib\*\uuid.lib
+
+USE_CRTDLL= 1
+
+#PRECOMPILED_INCLUDE= ..\headers.cxx
diff --git a/private/oleutest/server2/dirs b/private/oleutest/server2/dirs
new file mode 100644
index 000000000..1d0b9edbb
--- /dev/null
+++ b/private/oleutest/server2/dirs
@@ -0,0 +1,38 @@
+!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/server2/headers.cxx b/private/oleutest/server2/headers.cxx
new file mode 100644
index 000000000..d22e7e9ba
--- /dev/null
+++ b/private/oleutest/server2/headers.cxx
@@ -0,0 +1,18 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1992.
+//
+// File: headers.cxx
+//
+// Contents: class precompiled headers
+//
+// Classes:
+//
+// Functions:
+//
+// History: 24-Aug-93 PhilipLa Created
+//
+//----------------------------------------------------------------------------
+#include <headers.hxx>
+#pragma hdrstop
diff --git a/private/oleutest/server2/headers.hxx b/private/oleutest/server2/headers.hxx
new file mode 100644
index 000000000..3ff8e33cd
--- /dev/null
+++ b/private/oleutest/server2/headers.hxx
@@ -0,0 +1,26 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1992.
+//
+// File: headers.hxx
+//
+// Contents: class precompiled headers
+//
+// Classes:
+//
+// Functions:
+//
+// History: 24-Aug-93 PhilipLa Created
+//
+//----------------------------------------------------------------------------
+#include <windows.h>
+#include <ole2.h>
+#include <com.hxx>
+#include "safepnt.hxx"
+#include "olesrv.hxx"
+
+#if defined _CAIRO_
+#define _DCOM_
+#include <oleext.h>
+#endif
diff --git a/private/oleutest/server2/olesrv.cxx b/private/oleutest/server2/olesrv.cxx
new file mode 100644
index 000000000..2cab08e23
--- /dev/null
+++ b/private/oleutest/server2/olesrv.cxx
@@ -0,0 +1,1001 @@
+//+-------------------------------------------------------------------
+//
+// File: oleimpl.cxx
+//
+// Contents: This file contins the DLL entry points
+// LibMain
+// DllGetClassObject (Bindings key func)
+// CAdvBndCF (class factory)
+// CAdvBnd (actual class implementation)
+//
+// Classes: CAdvBndCF, CAdvBnd
+//
+//
+// History: 30-Nov-92 SarahJ Created
+// 31-Dec-93 ErikGav Chicago port
+//---------------------------------------------------------------------
+
+// Turn off ole Cairol IUnknown
+#include "headers.cxx"
+#pragma hdrstop
+#include <stdio.h>
+#include <stdarg.h>
+#include "wterm.h"
+
+
+#define IDM_DEBUG 0x100
+
+static const TCHAR *szAppName = TEXT("Test OLE Server");
+static const char *szFatalError = "OLESRV - Fatal Error";
+
+void MsgBox(char *pszMsg)
+{
+ MessageBoxA(NULL, pszMsg, szFatalError, MB_OK);
+}
+
+void HrMsgBox(char *pszMsg, HRESULT hr)
+{
+ char awcBuf[512];
+
+ // Build string for output
+ wsprintfA(awcBuf, "%s HRESULT = %lx", pszMsg, hr);
+
+ // Display message box
+ MessageBoxA(NULL, &awcBuf[0], szFatalError, MB_OK);
+}
+
+//+-------------------------------------------------------------------
+// Class: CTestServerApp
+//
+// Synopsis: Class that holds application-wide data and methods
+//
+// Methods: InitApp
+// CloseApp
+// GetEmbeddedFlag
+//
+// History: 17-Dec-92 DeanE Created
+//--------------------------------------------------------------------
+class FAR CTestServerApp
+{
+public:
+
+// Constructor/Destructor
+ CTestServerApp();
+ ~CTestServerApp();
+
+ SCODE InitApp (LPSTR lpszCmdline);
+ SCODE CloseApp (void);
+ BOOL GetEmbeddedFlag (void);
+ ULONG IncEmbeddedCount(void);
+ ULONG DecEmbeddedCount(void);
+
+private:
+ IClassFactory *_pteClassFactory;
+ ULONG _cEmbeddedObjs; // Count of embedded objects this server
+ // is controlling now
+ DWORD _dwRegId; // OLE registration ID
+ BOOL _fRegistered; // TRUE if srv was registered w/OLE
+ BOOL _fEmbedded; // TRUE if OLE started us at the request
+ // of an embedded obj in a container app
+};
+
+CTestServerApp tsaMain;
+HWND g_hMain;
+
+void ProcessCmdLine(LPSTR, BOOL *);
+
+//+--------------------------------------------------------------
+// Function: CTestServerApp::CTestServerApp
+//
+// Synopsis: Constructor - initialize members
+//
+// Parameters: None
+//
+// Returns: None
+//
+// History: 17-Dec-92 DeanE Created
+//---------------------------------------------------------------
+CTestServerApp::CTestServerApp()
+{
+ _pteClassFactory = NULL;
+ _dwRegId = 0;
+ _fRegistered = FALSE;
+ _fEmbedded = TRUE;
+ _cEmbeddedObjs = 0;
+}
+
+
+//+--------------------------------------------------------------
+// Function: CTestServerApp::~CTestServerApp
+//
+// Synopsis: Insure pointers are free - note this is mainly for
+// error-checking.
+//
+// Parameters: None
+//
+// Returns: None
+//
+// History: 17-Dec-92 DeanE Created
+//---------------------------------------------------------------
+CTestServerApp::~CTestServerApp()
+{
+ Win4Assert(_pteClassFactory == NULL &&
+ "Class factory should have been released");
+}
+
+
+//+--------------------------------------------------------------
+// Function: CTestServerApp::InitApp
+//
+// Synopsis: Initialize this instance of the app.
+//
+// Parameters: [lpszCmdline] - Command line of the application.
+//
+// Returns: S_OK if everything was initialized, or an error if not.
+//
+// History: 17-Dec-92 DeanE Created
+//
+// Notes: If this does not return, the CloseApp method should
+// still be called for proper cleanup.
+//---------------------------------------------------------------
+SCODE CTestServerApp::InitApp(LPSTR lpszCmdline)
+{
+ SCODE sc;
+
+ // Check OLE version running
+ // BUGBUG - NYI by OLE
+ // Bail out if we are not running with an acceptable version of OLE
+
+ // Process Command Line arguments
+ ProcessCmdLine(lpszCmdline, &_fEmbedded);
+
+ // Create the applications class factory - note that we have to free
+ // at a later time
+ _pteClassFactory = new CAdvBndCF();
+
+ if (NULL == _pteClassFactory)
+ {
+ MsgBox("Class Object Creation Failed");
+ return(E_ABORT);
+ }
+
+ // Register the class with OLE
+ sc = CoRegisterClassObject(
+ CLSID_AdvBnd,
+ _pteClassFactory,
+ CLSCTX_LOCAL_SERVER,
+ REGCLS_MULTIPLEUSE,
+ &_dwRegId);
+
+ if (S_OK == sc)
+ {
+ _fRegistered = TRUE;
+ }
+ else
+ {
+ HrMsgBox("CoRegisterClassObject FAILED", sc);
+ }
+
+ return(sc);
+}
+
+
+//+--------------------------------------------------------------
+// Function: CTestServerApp::CloseApp
+//
+// Synopsis: Clean up resources this instance of the app is using.
+//
+// Parameters: None
+//
+// Returns: S_OK if everything was cleaned up, or an error if not.
+//
+// History: 17-Dec-92 DeanE Created
+//---------------------------------------------------------------
+SCODE CTestServerApp::CloseApp()
+{
+ // Revoke the class object, if registered
+ if (TRUE == _fRegistered)
+ {
+ CoRevokeClassObject(_dwRegId);
+ }
+
+ // Release this apps class factory, and insure the returned count is 0
+ if (NULL != _pteClassFactory)
+ {
+
+ // NB: Workaround for ref count problem.
+
+ #define HACK 1
+ #if HACK
+ _pteClassFactory->Release();
+ _pteClassFactory = NULL;
+ #else
+ if (0 == _pteClassFactory->Release())
+ {
+ _pteClassFactory = NULL;
+ }
+ else
+ {
+ Win4Assert("Release on class factory returned positive ref count");
+ // BUGBUG - Log error
+ }
+ #endif
+ }
+
+ return(S_OK);
+}
+
+
+//+--------------------------------------------------------------
+// Function: CTestServerApp::GetEmbeddedFlag
+//
+// Synopsis: Returns TRUE if app was started for an embedded object,
+// FALSE if standalone.
+//
+// Parameters: None
+//
+// Returns: BOOL (_fEmbedded)
+//
+// History: 17-Dec-92 DeanE Created
+//
+// Notes: BUGBUG - This should be an inline method
+//---------------------------------------------------------------
+CTestServerApp::GetEmbeddedFlag()
+{
+ return(_fEmbedded);
+}
+
+
+//+--------------------------------------------------------------
+// Function: CTestServerApp::IncEmbeddedCount
+//
+// Synopsis: Increments the count of embedded objects the server
+// has open.
+//
+// Parameters: None
+//
+// Returns: ULONG (_cEmbeddedObjs)
+//
+// History: 17-Dec-92 DeanE Created
+//
+// Notes: BUGBUG - This should be an inline method
+//---------------------------------------------------------------
+ULONG CTestServerApp::IncEmbeddedCount()
+{
+ return(++_cEmbeddedObjs);
+}
+
+
+//+--------------------------------------------------------------
+// Function: CTestServerApp::DecEmbeddedCount
+//
+// Synopsis: Decrements the count of embedded objects the server
+// has open. If 0 are left and we were running for an
+// embedded object(s), shut down.
+//
+// Parameters: None
+//
+// Returns: ULONG (_cEmbeddedObjs)
+//
+// History: 17-Dec-92 DeanE Created
+//
+// Notes: BUGBUG - This should be an inline method
+//---------------------------------------------------------------
+ULONG CTestServerApp::DecEmbeddedCount()
+{
+ if ((0 == --_cEmbeddedObjs) && _fEmbedded)
+ {
+ // We are done so revoke our OLE stuff. We need to do this as
+ // soon as we know that we are shutting down so that the window
+ // for returning a bad class object is shut.
+ CloseApp();
+
+ // Tell window to die
+ SendMessage(g_hMain, WM_USER, 0xFFFFFFFF, 0xFFFFFFFF);
+ }
+
+ return(_cEmbeddedObjs);
+}
+
+
+//+--------------------------------------------------------------
+// Function: ProcessCmdline
+//
+// Synopsis: Checks the cmd line parameters, in particular for
+// '/Embedding' or '-Embedding'.
+//
+// Parameters: [lpszCmdLine] - Command line buffer.
+// [pfEmbedded] - Flag should be set to true if we get
+// the '/Embedding' switch.
+//
+// Returns: void
+//
+// History: 25-Nov-92 DeanE Created
+//
+// Notes: Only two valid commandlines for this program:
+// (1) -Embedding when started by OLE or (2) Null
+// string if started from the command line.
+//---------------------------------------------------------------
+void ProcessCmdLine(LPSTR lpszCmdline, BOOL *pfEmbedded)
+{
+ if (lpszCmdline[0] == 0)
+ {
+ *pfEmbedded = FALSE;
+ return;
+ }
+
+ if (strcmp(lpszCmdline, "-Embedding") == 0)
+ {
+ *pfEmbedded = TRUE;
+ return;
+ }
+
+ MsgBox("Received an invalid command line!");
+ *pfEmbedded = FALSE;
+
+ return;
+}
+
+void Display(TCHAR *pszFmt, ...)
+{
+ va_list marker;
+ TCHAR szBuffer[256];
+
+ va_start(marker, pszFmt);
+
+ #ifdef UNICODE
+ int iLen = vswprintf(szBuffer, pszFmt, marker);
+ #else
+ int iLen = vsprintf(szBuffer, pszFmt, marker);
+ #endif
+
+ va_end(marker);
+
+ // Display the message on terminal window
+ SendMessage(g_hMain, WM_PRINT_LINE, iLen, (LONG) szBuffer);
+}
+
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: ProcessMenu
+//
+// Synopsis: Gets called when a WM_COMMAND message received.
+//
+// Arguments: [hWindow] - handle for the window
+// [uiMessage] - message id
+// [wParam] - word parameter
+// [lParam] - long parameter
+//
+// Returns: DefWindowProc result
+//
+// History: 06-Aug-92 Ricksa Created
+//
+//--------------------------------------------------------------------------
+long ProcessMenu(HWND hWindow, UINT uiMessage, WPARAM wParam, LPARAM lParam,
+ void *)
+{
+ if ((uiMessage == WM_SYSCOMMAND) && (wParam == IDM_DEBUG))
+ {
+ // Request for a debug breakpoint!
+ DebugBreak();
+ }
+
+
+ return (DefWindowProc(hWindow, uiMessage, wParam, lParam));
+}
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: ProcessChar
+//
+// Synopsis: Gets called when a WM_CHAR message received.
+//
+// Arguments: [hWindow] - handle for the window
+// [uiMessage] - message id
+// [wParam] - word parameter
+// [lParam] - long parameter
+//
+// Returns: DefWindowProc result
+//
+// History: 06-Aug-92 Ricksa Created
+//
+//--------------------------------------------------------------------------
+long ProcessChar(HWND hWindow, UINT uiMessage, WPARAM wParam, LPARAM lParam,
+ void *)
+{
+ return (DefWindowProc(hWindow, uiMessage, wParam, lParam));
+}
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: ProcessClose
+//
+// Synopsis: Gets called when a NC_DESTROY message received.
+//
+// Arguments: [hWindow] - handle for the window
+// [uiMessage] - message id
+// [wParam] - word parameter
+// [lParam] - long parameter
+//
+// Returns: DefWindowProc result
+//
+// History: 06-Aug-92 Ricksa Created
+//
+//--------------------------------------------------------------------------
+long ProcessClose(
+ HWND hWindow,
+ UINT uiMessage,
+ WPARAM wParam,
+ LPARAM lParam,
+ void *pvCallBackData)
+{
+ // Take default action with message
+ return (DefWindowProc(hWindow, uiMessage, wParam, lParam));
+}
+
+//+-------------------------------------------------------------------
+//
+// Function: WinMain
+//
+// Synopsis: Entry point to DLL - does little else
+//
+// Arguments:
+//
+// Returns: TRUE
+//
+// History: 21-Nov-92 SarahJ Created
+//
+//--------------------------------------------------------------------
+int WINAPI WinMain(
+ HINSTANCE hInstance,
+ HINSTANCE hPrevInstance,
+ char *lpszCmdLine,
+ int nCmdShow)
+{
+ // For windows message
+ MSG msg;
+ BOOL bRet;
+ HRESULT hr;
+
+ // Register the window class
+ bRet = TermRegisterClass(hInstance, NULL, (LPTSTR) szAppName,
+ (LPTSTR) MAKEINTRESOURCE(IDI_APPLICATION));
+
+ if (!bRet)
+ {
+ MsgBox("TermRegisterClass FAILED");
+ return 1;
+ }
+
+ // Create the server window
+ bRet = TermCreateWindow(
+ (LPTSTR) szAppName,
+ (LPTSTR) szAppName,
+ NULL,
+ ProcessMenu,
+ ProcessChar,
+ ProcessClose,
+ SW_SHOWMINIMIZED,
+ &g_hMain,
+ NULL);
+
+ if (!bRet)
+ {
+ MsgBox("TermCreateWindow FAILED");
+ return 1;
+ }
+
+ // Add debug option to system menu
+ HMENU hmenu = GetSystemMenu(g_hMain, FALSE);
+
+ AppendMenu(hmenu, MF_SEPARATOR, 0, NULL);
+ AppendMenu(hmenu, MF_STRING | MF_ENABLED, IDM_DEBUG, TEXT("Debug"));
+
+ // Look up the thread mode from the win.ini file.
+ DWORD thread_mode;
+ TCHAR buffer[80];
+ int len;
+
+ len = GetProfileString( TEXT("OleSrv"),
+ TEXT("ThreadMode"),
+ TEXT("MultiThreaded"),
+ buffer,
+ sizeof(buffer) / sizeof(TCHAR));
+
+ if (lstrcmp(buffer, TEXT("ApartmentThreaded")) == 0)
+ {
+ thread_mode = COINIT_APARTMENTTHREADED;
+ hr = CoInitialize(NULL);
+ }
+ else
+ {
+#ifdef MULTI_THREADING
+ thread_mode = COINIT_MULTITHREADED;
+ hr = CoInitializeEx(NULL, thread_mode);
+#else
+ hr = E_INVALIDARG;
+#endif
+ }
+
+ if (S_OK != hr)
+ {
+ HrMsgBox("CoInitialize FAILED", hr);
+ return(1);
+ }
+
+
+ // Initialize Application
+ if (S_OK != tsaMain.InitApp(lpszCmdLine))
+ {
+ tsaMain.CloseApp();
+ return(1);
+ }
+
+ if (tsaMain.GetEmbeddedFlag())
+ {
+ // We're running as an embedded app
+ // Don't show the main window unless we're instructed to do so
+ // BUGBUG - In-place editing is NYI
+ ShowWindow(g_hMain, SW_SHOWMINIMIZED);
+ }
+ else
+ {
+ // We are not running as an embedded app - show the main window
+ ShowWindow(g_hMain, nCmdShow);
+ }
+
+ UpdateWindow(g_hMain);
+
+
+ // message loop
+ while (GetMessage(&msg, NULL, 0, 0))
+ {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+
+ // If we get here, we initialized OLE so let's uninitialize it.
+ CoUninitialize();
+
+ return (msg.wParam); /* Returns the value from PostQuitMessage */
+}
+
+
+
+//+-------------------------------------------------------------------
+//
+// Class: CAdvBndCF
+//
+// Synopsis: Class Factory for CAdvBnd
+//
+// Interfaces: IUnknown - QueryInterface, AddRef, Release
+// IClassFactory - CreateInstance
+//
+// History: 21-Nov-92 SarahJ Created
+//
+//--------------------------------------------------------------------
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CAdvBndCF::CAdvBndCF()
+//
+// Synopsis: The constructor for CAdvBnd.
+//
+// Arguments: None
+//
+// History: 21-Nov-92 SarahJ Created
+//
+//--------------------------------------------------------------------
+
+CAdvBndCF::CAdvBndCF() : _cRefs(1)
+{
+ // Load the class object for the class to aggregate.
+ HRESULT hresult = CoGetClassObject(CLSID_BasicBnd, CLSCTX_SERVER, NULL,
+ IID_IClassFactory, (void **) &_xifac);
+
+ return;
+}
+
+//+-------------------------------------------------------------------
+//
+// Member: CAdvBnd::~CAdvBndObj()
+//
+// Synopsis: The destructor for CAdvBnd.
+//
+// History: 21-Nov-92 SarahJ Created
+//
+//--------------------------------------------------------------------
+
+CAdvBndCF::~CAdvBndCF()
+{
+ return;
+}
+
+
+//+-------------------------------------------------------------------
+//
+// Method: CAdvBndCF::QueryInterface
+//
+// Synopsis: Only IUnknown and IClassFactory supported
+//
+//--------------------------------------------------------------------
+STDMETHODIMP CAdvBndCF::QueryInterface(REFIID iid, void FAR * FAR * ppv)
+{
+ if (GuidEqual(iid, IID_IUnknown)
+ || GuidEqual(iid, IID_IClassFactory))
+ {
+ *ppv = (IUnknown *) this;
+ AddRef();
+ return S_OK;
+ }
+ else
+ {
+ *ppv = NULL;
+ return E_NOINTERFACE;
+ }
+}
+
+STDMETHODIMP_(ULONG) CAdvBndCF::AddRef(void)
+{
+ return(++_cRefs);
+}
+
+STDMETHODIMP_(ULONG) CAdvBndCF::Release(void)
+{
+ if (--_cRefs == 0)
+ {
+ delete this;
+ return(0);
+ }
+
+ return _cRefs;
+}
+
+
+
+
+
+//+-------------------------------------------------------------------
+//
+// Method: CAdvBndCF::CreateInstance
+//
+// Synopsis: This is called by Binding process to create the
+// actual class object
+//
+//--------------------------------------------------------------------
+
+STDMETHODIMP CAdvBndCF::CreateInstance(
+ IUnknown FAR* pUnkOuter,
+ REFIID iidInterface,
+ void FAR* FAR* ppv)
+{
+ Display(TEXT("CAdvBndCF::CreateInstance called\n"));
+
+ if (pUnkOuter != NULL)
+ {
+ return E_FAIL;
+ }
+
+ CAdvBnd * lpcBB = new FAR CAdvBnd((IClassFactory *) _xifac);
+
+ if (lpcBB == NULL)
+ {
+ return E_OUTOFMEMORY;
+ }
+
+ HRESULT hresult = lpcBB->QueryInterface(iidInterface, ppv);
+
+ lpcBB->Release();
+
+ return hresult;
+}
+
+STDMETHODIMP CAdvBndCF::LockServer(BOOL fLock)
+{
+ return E_FAIL;
+}
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CAdvBnd::CAdvBnd()
+//
+// Synopsis: The constructor for CAdvBnd. I
+//
+// Arguments: None
+//
+// History: 21-Nov-92 SarahJ Created
+//
+//--------------------------------------------------------------------
+
+CAdvBnd::CAdvBnd(IClassFactory *pcfBase) : _xiunk(), _dwRegister(0), _cRefs(1)
+{
+ HRESULT hresult = pcfBase->CreateInstance((IUnknown *) this, IID_IUnknown,
+ (void **) &_xiunk);
+
+ tsaMain.IncEmbeddedCount();
+
+ return;
+}
+
+//+-------------------------------------------------------------------
+//
+// Member: CAdvBnd::~CAdvBndObj()
+//
+// Synopsis: The destructor for CAdvBnd.
+//
+// History: 21-Nov-92 SarahJ Created
+//
+//--------------------------------------------------------------------
+
+CAdvBnd::~CAdvBnd()
+{
+ Display(TEXT("CAdvBndCF::~CAdvBnd called\n"));
+
+ if (_dwRegister != 0)
+ {
+ // Get the running object table
+ IRunningObjectTable *prot;
+
+ HRESULT hresult = GetRunningObjectTable(0, &prot);
+
+ if (hresult != S_OK)
+ {
+ HrMsgBox("CAdvBnd::~CAdvBnd GetRunningObjectTable failed", hresult);
+ }
+ else
+ {
+ hresult = prot->Revoke(_dwRegister);
+
+ if (hresult != S_OK)
+ {
+ HrMsgBox("CAdvBnd::~CAdvBnd Revoke failed", hresult);
+ }
+
+ prot->Release();
+ }
+ }
+
+ tsaMain.DecEmbeddedCount();
+ return;
+}
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CAdvBnd::QueryInterface
+//
+// Returns: SUCCESS_SUCCCESS
+//
+// History: 21-Nov-92 SarahJ Created
+//
+//--------------------------------------------------------------------
+STDMETHODIMP CAdvBnd::QueryInterface(REFIID iid, void ** ppunk)
+{
+ Display(TEXT("CAdvBnd::QueryInterface called\n"));
+
+ if (GuidEqual(iid, IID_IUnknown))
+ {
+ *ppunk = (IUnknown *) this;
+ AddRef();
+ return S_OK;
+ }
+ else if ((GuidEqual(iid, IID_IPersistFile))
+ || (GuidEqual(iid, IID_IPersist)))
+ {
+ *ppunk = (IPersistFile *) this;
+ AddRef();
+ return S_OK;
+ }
+
+ return _xiunk->QueryInterface(iid, ppunk);
+}
+
+STDMETHODIMP_(ULONG) CAdvBnd::AddRef(void)
+{
+ return ++_cRefs;
+}
+
+STDMETHODIMP_(ULONG) CAdvBnd::Release(void)
+{
+ if (--_cRefs == 0)
+ {
+ delete this;
+ return(0);
+ }
+
+ return _cRefs;
+}
+
+//+-------------------------------------------------------------------
+//
+// Member: CAdvBnd::Load
+//
+// Synopsis: IPeristFile interface - needed 'cause we bind with
+// file moniker and BindToObject insists on calling this
+//
+// History: 21-Nov-92 SarahJ Created
+//
+//--------------------------------------------------------------------
+STDMETHODIMP CAdvBnd::Load(LPCWSTR lpszFileName, DWORD grfMode)
+{
+ Display(TEXT("CAdvBndCF::Load called\n"));
+
+ // Forward call to delegated class
+ IPersistFile *pipfile;
+
+ HRESULT hresult = _xiunk->QueryInterface(IID_IPersistFile,
+ (void **) &pipfile);
+
+ hresult = pipfile->Load(lpszFileName, grfMode);
+
+ pipfile->Release();
+
+ if (FAILED(hresult))
+ {
+ // Make sure delegated too class liked what it got/
+ // BUGBUG: Can't just forward hresults!
+ return hresult;
+ }
+
+ // Create a file moniker
+ IMoniker *pmk;
+ hresult = CreateFileMoniker((LPWSTR)lpszFileName, &pmk);
+
+ if (FAILED(hresult))
+ {
+ HrMsgBox("CAdvBnd::Load CreateFileMoniker failed", hresult);
+ return hresult;
+ }
+
+ // Get the running object table
+ IRunningObjectTable *prot;
+
+ hresult = GetRunningObjectTable(0, &prot);
+
+ if (FAILED(hresult))
+ {
+ HrMsgBox("CAdvBnd::Load GetRunningObjectTable failed", hresult);
+ return hresult;
+ }
+
+ // Register in the running object table
+ IUnknown *punk;
+ QueryInterface(IID_IUnknown, (void **) &punk);
+
+ hresult = prot->Register(0, punk, pmk, &_dwRegister);
+
+ if (FAILED(hresult))
+ {
+ HrMsgBox("CAdvBnd::Load Register failed", hresult);
+ return hresult;
+ }
+
+ // Set filetime to known value
+ FILETIME filetime;
+ memset(&filetime, 'B', sizeof(filetime));
+
+ // Set time to some known value
+ prot->NoteChangeTime(_dwRegister, &filetime);
+
+ // Release uneeded objects
+ pmk->Release();
+ prot->Release();
+ punk->Release();
+
+ return S_OK;
+}
+
+//+-------------------------------------------------------------------
+//
+// Member: CAdvBnd::Save
+//
+// Synopsis: IPeristFile interface - save
+// does little but here for commentry
+//
+// History: 21-Nov-92 SarahJ Created
+//
+//--------------------------------------------------------------------
+STDMETHODIMP CAdvBnd::Save(LPCWSTR lpszFileName, BOOL fRemember)
+{
+ Display(TEXT("CAdvBndCF::Save called\n"));
+
+ // Forward call to delegated class
+ IPersistFile *pipfile;
+
+ HRESULT hresult = _xiunk->QueryInterface(IID_IPersistFile,
+ (void **) &pipfile);
+
+ hresult = pipfile->Save(lpszFileName, fRemember);
+
+ pipfile->Release();
+
+ return hresult;
+}
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CAdvBnd::SaveCpmpleted
+// CAdvBnd::GetCurFile
+// CAdvBnd::IsDirty
+//
+// Synopsis: More IPeristFile interface methods
+//
+// History: 21-Nov-92 SarahJ Created
+//
+//--------------------------------------------------------------------
+STDMETHODIMP CAdvBnd::SaveCompleted(LPCWSTR lpszFileName)
+{
+ Display(TEXT("CAdvBndCF::SaveCompleted called\n"));
+
+ // Forward call to delegated class
+ IPersistFile *pipfile;
+
+ HRESULT hresult = _xiunk->QueryInterface(IID_IPersistFile,
+ (void **) &pipfile);
+
+ hresult = pipfile->SaveCompleted(lpszFileName);
+
+ pipfile->Release();
+
+ return hresult;
+}
+
+STDMETHODIMP CAdvBnd::GetCurFile(LPWSTR FAR *lpszFileName)
+{
+ Display(TEXT("CAdvBndCF::GetCurFile called\n"));
+
+ // Forward call to delegated class
+ IPersistFile *pipfile;
+
+ HRESULT hresult = _xiunk->QueryInterface(IID_IPersistFile,
+ (void **) &pipfile);
+
+ hresult = pipfile->GetCurFile(lpszFileName);
+
+ pipfile->Release();
+
+ return hresult;
+}
+
+STDMETHODIMP CAdvBnd::IsDirty()
+{
+ Display(TEXT("CAdvBndCF::IsDirty called\n"));
+
+ // Forward call to delegated class
+ IPersistFile *pipfile;
+
+ HRESULT hresult = _xiunk->QueryInterface(IID_IPersistFile,
+ (void **) &pipfile);
+
+ hresult = pipfile->IsDirty();
+
+ pipfile->Release();
+
+ return hresult;
+}
+
+//+-------------------------------------------------------------------
+//
+// Interface: IPersist
+//
+// Synopsis: IPersist interface methods
+// Need to return a valid class id here
+//
+// History: 21-Nov-92 SarahJ Created
+//
+
+STDMETHODIMP CAdvBnd::GetClassID(LPCLSID classid)
+{
+ Display(TEXT("CAdvBndCF::GetClassID called\n"));
+
+ *classid = CLSID_AdvBnd;
+ return S_OK;
+}
diff --git a/private/oleutest/server2/olesrv.hxx b/private/oleutest/server2/olesrv.hxx
new file mode 100644
index 000000000..c34a5b073
--- /dev/null
+++ b/private/oleutest/server2/olesrv.hxx
@@ -0,0 +1,145 @@
+//+-------------------------------------------------------------------
+//
+// File: oleimpl.hxx
+//
+// Contents: This file contins the DLL entry points
+// LibMain
+// DllGetClassObject (Bindings key func)
+// DllCanUnloadNow
+// CBasicBndCF (class factory)
+// History: 30-Mar-92 SarahJ Created
+// 31-Dec-93 ErikGav Chicago port
+//
+//---------------------------------------------------------------------
+
+#ifndef __OLESRV_H__
+#define __OLESRV_H__
+
+#include <smartp.hxx>
+
+DefineSmartItfP(IClassFactory)
+
+//+---------------------------------------------------------------------------
+//
+// Function: operator new, public
+//
+// Synopsis: Global operator new which does not throw exceptions.
+//
+// Arguments: [size] -- Size of the memory to allocate.
+//
+// Returns: A pointer to the allocated memory. Is *NOT* initialized to 0!
+//
+// Notes: We override new to make delete easier.
+//
+//----------------------------------------------------------------------------
+
+inline void* _CRTAPI1
+operator new (size_t size)
+{
+ return(CoTaskMemAlloc(size));
+}
+
+//+-------------------------------------------------------------------------
+//
+// Function: ::operator delete
+//
+// Synopsis: Free a block of memory
+//
+// Arguments: [lpv] - block to free.
+//
+//--------------------------------------------------------------------------
+
+inline void _CRTAPI1 operator delete(void FAR* lpv)
+{
+ CoTaskMemFree(lpv);
+}
+
+//+-------------------------------------------------------------------
+//
+// Class: CBasicBndCF
+//
+// Synopsis: Class Factory for CBasicBnd
+//
+// Methods: IUnknown - QueryInterface, AddRef, Release
+// IClassFactory - CreateInstance
+//
+// History: 21-Mar-92 SarahJ Created
+//
+//--------------------------------------------------------------------
+
+
+class CAdvBndCF: public IClassFactory
+{
+public:
+
+ // Constructor/Destructor
+ CAdvBndCF();
+ ~CAdvBndCF();
+ static IClassFactory FAR * Create();
+
+ // IUnknown
+ STDMETHODIMP QueryInterface(REFIID iid, void FAR * FAR * ppv);
+ STDMETHODIMP_(ULONG) AddRef (void);
+ STDMETHODIMP_(ULONG) Release (void);
+
+ // IClassFactory
+ STDMETHODIMP CreateInstance(
+ IUnknown FAR* pUnkOuter,
+ REFIID iidInterface,
+ void FAR* FAR* ppv);
+
+ STDMETHODIMP LockServer(BOOL fLock);
+
+private:
+
+ XIClassFactory _xifac;
+
+ DWORD _dwRegistration;
+
+ ULONG _cRefs;
+};
+
+//+-------------------------------------------------------------------
+//
+// Class: CAdvBnd
+//
+// Synopsis: Test class CBasicBnd
+//
+// Methods:
+//
+// History: 21-Mar-92 SarahJ Created
+//
+//--------------------------------------------------------------------
+
+
+class CAdvBnd: public IPersistFile
+{
+public:
+ CAdvBnd(IClassFactory *pFactory);
+
+ ~CAdvBnd();
+
+ // IUnknown
+ STDMETHODIMP QueryInterface(REFIID iid, void FAR * FAR * ppv);
+ STDMETHODIMP_(ULONG) AddRef (void);
+ STDMETHODIMP_(ULONG) Release (void);
+
+ // IPersitFile
+ STDMETHODIMP GetClassID(LPCLSID lpClassID);
+ STDMETHODIMP IsDirty();
+ STDMETHODIMP Load(LPCWSTR lpszFileName, DWORD grfMode);
+ STDMETHODIMP Save(LPCWSTR lpszFileName, BOOL fRemember);
+ STDMETHODIMP SaveCompleted(LPCWSTR lpszFileName);
+ STDMETHODIMP GetCurFile(LPWSTR FAR * lpszFileName);
+
+private:
+
+ XIUnknown _xiunk;
+
+ DWORD _dwRegister;
+
+ ULONG _cRefs;
+};
+
+
+#endif
diff --git a/private/oleutest/server2/smartp.hxx b/private/oleutest/server2/smartp.hxx
new file mode 100644
index 000000000..cc01eb7be
--- /dev/null
+++ b/private/oleutest/server2/smartp.hxx
@@ -0,0 +1,74 @@
+//+---------------------------------------------------------------------------
+//
+// Copyright (C) 1992, Microsoft Corporation.
+//
+// File: smartp.hxx
+//
+// Contents: Class and associated macros for generic smart pointer
+// capability.
+//
+// Classes: XIUnknown
+// XMem
+//
+// History: 30-Mar-92 MikeSe Created
+// 6-Oct-92 MikeSe Added XMem and related macros.
+//
+// Notes: All of the interesting stuff from here is now in safepnt.hxx
+// which should be used in preference. The following correspondences
+// exist between the macros defined here and those in safepnt,
+// should you wish to convert to avoid the (deliberately) annoying
+// warning:
+//
+// DefineSmartItfP(class) == SAFE_INTERFACE_PTR(Xclass,class)
+// DefineSmartMemP(class,NO_ARROW) == SAFE_MEMALLOC_MEMPTR(Xclass,class)
+// DefineSmartMemP(class,DEFINE_ARROW) == SAFE_MEMALLOC_PTR(Xclass,class)
+//
+//----------------------------------------------------------------------------
+
+#ifndef __SMARTP_HXX__
+#define __SMARTP_HXX__
+
+#include <safepnt.hxx>
+
+//+-------------------------------------------------------------------------
+//
+// Macro: DefineSmartItfP
+//
+// Purpose: Macro to define smart pointer to an IUnknown derivative.
+//
+// Notes: The smart pointer so defined has a fixed name consisting of
+// X (for eXception-safe) prefixed to the name of the pointed-to
+// class. If you want to choose the name, you should use the
+// SAFE_INTERFACE_PTR macro in safepnt.hxx.
+//
+//--------------------------------------------------------------------------
+
+#define DefineSmartItfP(cls) SAFE_INTERFACE_PTR(X##cls,cls)
+
+DefineSmartItfP(IUnknown)
+
+// For backwards compatibility
+#define DefineSmartP(cls) DefineSmartItfP(cls)
+
+//+-------------------------------------------------------------------------
+//
+// Macro: DefineSmartMemP
+//
+// Purpose: Macro to define smart pointer to any MemAlloc'ed structure
+//
+// Notes: This macro is used to define a smart pointer to any structure
+// allocated using MemAlloc. Invocation is as follows:
+//
+// DefineSmartMemP(SWCStringArray,arrow_spec)
+//
+// where arrow_spec is DEFINE_ARROW if the pointed-to type
+// supports a member-of (->) operator, and NO_ARROW if
+// it does not. (EG: use NO_ARROW for WCString).
+//
+//--------------------------------------------------------------------------
+
+#define _MEM_DEFINE_ARROW(cls) SAFE_MEMALLOC_PTR(X##cls,cls)
+#define _MEM_NO_ARROW(cls) SAFE_MEMALLOC_MEMPTR(X##cls,cls)
+#define DefineSmartMemP(cls,arrow) _MEM_##arrow(cls)
+
+#endif // of ifndef __SMARTP_HXX__
diff --git a/private/oleutest/server2/wterm.c b/private/oleutest/server2/wterm.c
new file mode 100644
index 000000000..a8ef70b01
--- /dev/null
+++ b/private/oleutest/server2/wterm.c
@@ -0,0 +1,1029 @@
+/****************************************************************************
+
+ PROGRAM: wterm.c
+
+ PURPOSE: Implementation of TermWClass Windows
+
+ FUNCTIONS:
+
+
+ COMMENTS:
+
+
+****************************************************************************/
+
+#include "windows.h"
+#include "stdlib.h"
+#include "memory.h"
+#include "wterm.h"
+
+#define MAX_ROWS 24
+#define MAX_COLS 80
+
+typedef struct WData
+{
+ // Function to execute for processing a menu
+ MFUNCP pMenuProc;
+
+ // Function to execute for processing a single character
+ CFUNCP pCharProc;
+
+ // Function to execute when window is closed (terminated)
+ TFUNCP pCloseProc;
+
+ // Pass on callback
+ void *pvCallBackData;
+
+ BOOL fGotFocus;
+
+ BOOL fCaretHidden;
+
+ // Rows on the screen
+ int cRows;
+
+ // Columns on the screen
+ int cCols;
+
+ // Row at top of screen
+ int iTopRow;
+
+ // Row at bottom of the screen
+ int iBottomRow;
+
+ // First Column on screen
+ int iFirstCol;
+
+ // Column at bottom of the screen
+ int iBottomCol;
+
+ // Row for next character
+ int iNextRow;
+
+ // Row for next column
+ int iNextCol;
+
+ // Width of character
+ int cxChar;
+
+ // Height of character
+ int cyChar;
+
+ // Memory image of screen this is treated as a circular buffer
+ TCHAR aImage[MAX_ROWS] [MAX_COLS];
+
+ // First row in circular screen buffer
+ int iBufferTop;
+} WData;
+
+static HANDLE hInst = 0;
+TCHAR BlankLine[80];
+
+static int
+row_diff(
+ int row1,
+ int row2)
+{
+ return (row2 > row1)
+ ? MAX_ROWS - (row2 - row1)
+ : row1 - row2;
+}
+
+static void
+set_vscroll_pos(
+ HWND hwnd,
+ WData *pwdata)
+{
+ if (pwdata->cRows != 0)
+ {
+ // Save a few indirections by caching cRows
+ register int cRows = pwdata->cRows;
+
+ // calculate distance bottom of screen from top of data buffer
+ register int top_from_row = row_diff(pwdata->iBottomRow,
+ pwdata->iBufferTop);
+
+ // Output position of scroll bar
+ int new_pos = 0;
+
+ if (top_from_row >= cRows)
+ {
+ // Calculate number of screens to display entire buffer
+ int screens_for_data = MAX_ROWS / cRows
+ + ((MAX_ROWS % cRows != 0) ? 1 : 0);
+
+ // Figure out which screen the row falls in
+ int screen_loc = top_from_row / cRows
+ + ((top_from_row % cRows != 0) ? 1 : 0);
+
+ // If the screen is in the last one set box to max
+ new_pos = (screen_loc == screens_for_data)
+ ? MAX_ROWS : screen_loc * cRows;
+ }
+
+ SetScrollPos(hwnd, SB_VERT, new_pos, TRUE);
+ }
+}
+
+static int
+calc_row(
+ register int row,
+ WData *pwdata)
+{
+ register int top = pwdata->iTopRow;
+ static int boopa = 0;
+
+ if (top > row)
+ boopa++;
+
+ return (row >= top) ? row - top : (MAX_ROWS - (top - row));
+}
+
+static void
+display_text(
+ HWND hwnd,
+ int row,
+ int col,
+ LPTSTR text,
+ int text_len,
+ WData *pWData)
+{
+ // Get the DC to display the text
+ HDC hdc = GetDC(hwnd);
+
+ // Select Font
+ SelectObject(hdc, GetStockObject(SYSTEM_FIXED_FONT));
+
+ // Hide caret while we are printing
+ HideCaret(hwnd);
+
+ // Update the screen
+ TextOut(hdc, (col - pWData->iFirstCol) * pWData->cxChar,
+ calc_row(row, pWData) * pWData->cyChar, text, text_len);
+
+ // Done with DC
+ ReleaseDC(hwnd, hdc);
+
+ // Put the caret back now that we are done
+ ShowCaret(hwnd);
+}
+
+static void
+display_char(
+ HWND hwnd,
+ TCHAR char_to_display,
+ WData *pWData)
+{
+ // Update image buffer
+ pWData->aImage[pWData->iNextRow][pWData->iNextCol] = char_to_display;
+
+ display_text(hwnd, pWData->iNextRow, pWData->iNextCol,
+ &char_to_display, 1, pWData);
+}
+
+static void
+do_backspace(
+ HWND hwnd,
+ WData *pWData)
+{
+ // Point to the previous character in the line
+ if (--pWData->iNextCol < 0)
+ {
+ // Can't backspace beyond the current line
+ pWData->iNextCol = 0;
+ return;
+ }
+
+ display_char(hwnd, ' ', pWData);
+
+ // Null character for repaint
+ pWData->aImage[pWData->iNextRow][pWData->iNextCol] = '\0';
+}
+
+static int
+inc_row(
+ int row,
+ int increment)
+{
+ row += increment;
+
+ if (row >= MAX_ROWS)
+ {
+ row -= MAX_ROWS;
+ }
+ else if (row < 0)
+ {
+ row += MAX_ROWS;
+ }
+
+ return row;
+}
+
+void
+inc_next_row(
+ HWND hwnd,
+ WData *pWData)
+{
+ if (pWData->iNextRow == pWData->iBottomRow)
+ {
+ // Line is at bottom -- scroll the client area one row
+ ScrollWindow(hwnd, 0, -pWData->cyChar, NULL, NULL);
+
+ // Increment the top & bottom of the screen
+ pWData->iTopRow = inc_row(pWData->iTopRow, 1);
+ pWData->iBottomRow = inc_row(pWData->iBottomRow, 1);
+ }
+
+ // Increment the row
+ pWData->iNextRow = inc_row(pWData->iNextRow, 1);
+
+ if (pWData->iNextRow == pWData->iBufferTop)
+ {
+ // Have to reset circular buffer to next
+ pWData->iBufferTop = inc_row(pWData->iBufferTop, 1);
+
+ // Reset line to nulls for repaint
+ memset(&pWData->aImage[pWData->iNextRow][0], '\0', MAX_COLS);
+ }
+
+ pWData->iNextCol = 0;
+}
+
+static void
+do_cr(
+ HWND hwnd,
+ WData *pWData)
+{
+ // Set position to next row
+ inc_next_row(hwnd, pWData);
+ pWData->iNextCol = 0;
+
+ // Make sure next character is null for repaint of line
+ pWData->aImage[pWData->iNextRow][pWData->iNextCol] = '\0';
+
+ // Update the vertical scroll bar's position
+ set_vscroll_pos(hwnd, pWData);
+}
+
+static void
+do_char(
+ HWND hwnd,
+ WPARAM wParam,
+ WData *pWData)
+{
+ display_char(hwnd, (TCHAR) wParam, pWData);
+
+ // Point to the next character in the line
+ if (++pWData->iNextCol > MAX_COLS)
+ {
+ // Handle switch to next line
+ inc_next_row(hwnd, pWData);
+ }
+}
+
+static void
+do_tab(
+ HWND hwnd,
+ WData *pWData)
+{
+ int c = pWData->iNextCol % 8;
+
+ if ((pWData->iNextCol + c) <= MAX_COLS)
+ {
+ for ( ; c; c--)
+ {
+ do_char(hwnd, ' ', pWData);
+ }
+ }
+ else
+ {
+ do_cr(hwnd, pWData);
+ }
+}
+
+static void
+EchoChar(
+ HWND hwnd,
+ WORD cRepeats,
+ WPARAM wParam,
+ WData *pWData)
+{
+ for ( ; cRepeats; cRepeats--)
+ {
+ switch (wParam)
+ {
+ // Backspace
+ case '\b':
+ do_backspace(hwnd, pWData);
+ break;
+
+ // Carriage return
+ case '\n':
+ case '\r':
+ do_cr(hwnd, pWData);
+ break;
+
+ // Tab
+ case '\t':
+ do_tab(hwnd, pWData);
+ break;
+
+ // Regular characters
+ default:
+ do_char(hwnd, wParam, pWData);
+ }
+ }
+
+ // The row is guaranteed to be on the screen because we will
+ // scroll on a CR. However, the next column for input may be
+ // beyond the window we are working in.
+ if (pWData->iNextCol > pWData->iBottomCol)
+ {
+ // We are out of the window so scroll the window one
+ // column to the right.
+ SendMessage(hwnd, WM_HSCROLL, SB_LINEDOWN, 0L);
+ }
+ else if (pWData->iNextCol < pWData->iFirstCol)
+ {
+ // We are out of the window so repaint the window using
+ // iNextCol as the first column for the screen.
+ pWData->iFirstCol = pWData->iNextCol;
+ pWData->iBottomCol = pWData->iFirstCol + pWData->cCols - 1;
+
+ // Reset scroll bar
+ SetScrollPos(hwnd, SB_HORZ, pWData->iFirstCol, TRUE);
+
+ // Tell window to update itself.
+ InvalidateRect(hwnd, NULL, TRUE);
+ UpdateWindow(hwnd);
+ }
+ else
+ {
+ // Reset Caret's position
+ SetCaretPos((pWData->iNextCol - pWData->iFirstCol) * pWData->cxChar,
+ calc_row(pWData->iNextRow, pWData) * pWData->cyChar);
+ }
+}
+
+/****************************************************************************
+
+ FUNCTION: WmCreate(HWND)
+
+ PURPOSE: Initializes control structures for a TermWClass Window
+
+ MESSAGES:
+ WM_CREATE
+
+ COMMENTS:
+
+ This prepares a window for processing character based
+ I/O. In particular it does stuff like calculate the
+ size of the window needed.
+
+****************************************************************************/
+static void
+WmCreate(
+ HWND hwnd,
+ CREATESTRUCT *pInit)
+{
+ WData *pData = (WData *) (pInit->lpCreateParams);
+ HDC hdc = GetDC(hwnd);
+ TEXTMETRIC tm;
+
+ // Store pointer to window data
+ SetWindowLong(hwnd, 0, (LONG) pData);
+
+ // Set font to system fixed font
+ SelectObject(hdc, GetStockObject(SYSTEM_FIXED_FONT));
+
+ // Calculate size of a character
+ GetTextMetrics(hdc, &tm);
+ pData->cxChar = tm.tmAveCharWidth;
+ pData->cyChar = tm.tmHeight;
+ ReleaseDC(hwnd, hdc);
+
+ // Set up vertical scroll bars
+ SetScrollRange(hwnd, SB_VERT, 0, MAX_ROWS, TRUE);
+ SetScrollPos(hwnd, SB_VERT, 0, TRUE);
+
+ // Set up horizontal scroll bars
+ SetScrollRange(hwnd, SB_HORZ, 0, MAX_COLS, TRUE);
+ SetScrollPos(hwnd, SB_HORZ, 0, TRUE);
+}
+
+/****************************************************************************
+
+ FUNCTION: WmSize(HWND, WORD, LONG)
+
+ PURPOSE: Processes a size message
+
+ MESSAGES:
+
+ COMMENTS:
+
+****************************************************************************/
+static void
+WmSize(
+ HWND hwnd,
+ WPARAM wParam,
+ LONG lParam,
+ WData *pwdata)
+{
+ // Get the new size of the window
+ int cxClient;
+ int cyClient;
+ int cRowChange = pwdata->cRows;
+ RECT rect;
+
+ // Get size of client area
+ GetClientRect(hwnd, &rect);
+
+ // Calculate size of client area
+ cxClient = rect.right - rect.left;
+ cyClient = rect.bottom - rect.top;
+
+ // Calculate size of area in rows
+ pwdata->cCols = cxClient / pwdata->cxChar;
+ pwdata->cRows = min(MAX_ROWS, cyClient / pwdata->cyChar);
+ pwdata->iBottomCol = min(pwdata->iFirstCol + pwdata->cCols, MAX_COLS);
+ cRowChange = pwdata->cRows - cRowChange;
+
+ // Keep input line toward bottom of screen
+ if (cRowChange < 0)
+ {
+ // Screen has shrunk in size.
+ if (pwdata->iNextRow != pwdata->iTopRow)
+ {
+ // Has input row moved out of screen?
+ if (row_diff(pwdata->iNextRow, pwdata->iTopRow) >= pwdata->cRows)
+ {
+ // Yes -- Calculate top new top that puts input line on
+ // the bottom.
+ pwdata->iTopRow =
+ inc_row(pwdata->iNextRow, 1 - pwdata->cRows);
+ }
+ }
+ }
+ else
+ {
+ // Screen has gotten bigger -- Display more text if possible
+ if (pwdata->iTopRow != pwdata->iBufferTop)
+ {
+ pwdata->iTopRow = inc_row(pwdata->iTopRow,
+ -(min(row_diff(pwdata->iTopRow, pwdata->iBufferTop),
+ cRowChange)));
+ }
+ }
+
+ // Calculate new bottom
+ pwdata->iBottomRow = inc_row(pwdata->iTopRow, pwdata->cRows - 1);
+
+ InvalidateRect(hwnd, NULL, TRUE);
+ UpdateWindow(hwnd);
+}
+
+static void
+WmSetFocus(
+ HWND hwnd,
+ WData *pwdata)
+{
+ // save indirections
+ register int cxchar = pwdata->cxChar;
+ register int cychar = pwdata->cyChar;
+ pwdata->fGotFocus = TRUE;
+ CreateCaret(hwnd, NULL, cxchar, cychar);
+
+ if (!pwdata->fCaretHidden)
+ {
+ SetCaretPos(pwdata->iNextCol * cxchar,
+ calc_row(pwdata->iNextRow, pwdata) * cychar);
+ }
+
+ ShowCaret(hwnd);
+}
+
+static void
+WmKillFocus(
+ HWND hwnd,
+ WData *pwdata)
+{
+ pwdata->fGotFocus = FALSE;
+
+ if (!pwdata->fCaretHidden)
+ {
+ HideCaret(hwnd);
+ }
+
+ DestroyCaret();
+}
+
+static void
+WmVscroll(
+ HWND hwnd,
+ WPARAM wParam,
+ LONG lParam,
+ WData *pwdata)
+{
+ int cVscrollInc = 0;
+ register int top_diff = row_diff(pwdata->iTopRow, pwdata->iBufferTop);
+ register int bottom_diff = MAX_ROWS - (top_diff + pwdata->cRows);
+
+ switch(wParam)
+ {
+ case SB_TOP:
+
+ if (top_diff != 0)
+ {
+ cVscrollInc = -top_diff;
+ }
+
+ break;
+
+ case SB_BOTTOM:
+
+ if (bottom_diff != 0)
+ {
+ cVscrollInc = bottom_diff;
+ }
+
+ break;
+
+ case SB_LINEUP:
+
+ if (top_diff != 0)
+ {
+ cVscrollInc = -1;
+ }
+
+ break;
+
+ case SB_LINEDOWN:
+
+ if (bottom_diff != 0)
+ {
+ cVscrollInc = 1;
+ }
+
+ break;
+
+ case SB_PAGEUP:
+
+ if (top_diff != 0)
+ {
+ cVscrollInc = - ((top_diff > pwdata->cRows)
+ ? pwdata->cRows : top_diff);
+ }
+
+ break;
+
+ case SB_PAGEDOWN:
+
+ if (bottom_diff != 0)
+ {
+ cVscrollInc = (bottom_diff > pwdata->cRows)
+ ? pwdata->cRows : bottom_diff;
+ }
+
+ break;
+
+ case SB_THUMBTRACK:
+
+ if (LOWORD(lParam) != 0)
+ {
+ cVscrollInc = LOWORD(lParam)
+ - row_diff(pwdata->iTopRow, pwdata->iBufferTop);
+ }
+ }
+
+ // Cacluate new top row
+ if (cVscrollInc != 0)
+ {
+ // Calculate new top and bottom
+ pwdata->iTopRow = inc_row(pwdata->iTopRow, cVscrollInc);
+ pwdata->iBottomRow = inc_row(pwdata->iTopRow, pwdata->cRows);
+
+ // Scroll window
+ ScrollWindow(hwnd, 0, pwdata->cyChar * cVscrollInc, NULL, NULL);
+
+ // Reset scroll bar
+ set_vscroll_pos(hwnd, pwdata);
+
+ // Tell window to update itself.
+ InvalidateRect(hwnd, NULL, TRUE);
+ UpdateWindow(hwnd);
+ }
+}
+
+static void
+WmHscroll(
+ HWND hwnd,
+ WPARAM wParam,
+ LONG lParam,
+ WData *pwdata)
+{
+ register int cHscrollInc = 0;
+
+ switch(wParam)
+ {
+ case SB_LINEUP:
+
+ cHscrollInc = -1;
+ break;
+
+ case SB_LINEDOWN:
+
+ cHscrollInc = 1;
+ break;
+
+ case SB_PAGEUP:
+
+ cHscrollInc = -8;
+ break;
+
+ case SB_PAGEDOWN:
+
+ cHscrollInc = 8;
+ break;
+
+ case SB_THUMBTRACK:
+
+ if (LOWORD(lParam) != 0)
+ {
+ cHscrollInc = LOWORD(lParam) - pwdata->iFirstCol;
+ }
+ }
+
+ if (cHscrollInc != 0)
+ {
+ // Cacluate new first column
+ register int NormalizedScrollInc = cHscrollInc + pwdata->iFirstCol;
+
+ if (NormalizedScrollInc < 0)
+ {
+ cHscrollInc = -pwdata->iFirstCol;
+ }
+ else if (NormalizedScrollInc > MAX_COLS - pwdata->cCols)
+ {
+ cHscrollInc = (MAX_COLS - pwdata->cCols) - pwdata->iFirstCol;
+ }
+
+ pwdata->iFirstCol += cHscrollInc;
+ pwdata->iBottomCol = pwdata->iFirstCol + pwdata->cCols - 1;
+
+ // Scroll window
+ ScrollWindow(hwnd, -(pwdata->cxChar * cHscrollInc), 0, NULL, NULL);
+
+ // Reset scroll bar
+ SetScrollPos(hwnd, SB_HORZ, pwdata->iFirstCol, TRUE);
+
+ // Tell window to update itself.
+ InvalidateRect(hwnd, NULL, TRUE);
+ UpdateWindow(hwnd);
+ }
+}
+
+static void
+WmPaint(
+ HWND hwnd,
+ WData *pwdata)
+{
+ PAINTSTRUCT ps;
+ HDC hdc = BeginPaint(hwnd, &ps);
+ register int row = pwdata->iTopRow;
+ register int col = pwdata->iFirstCol;
+ int bottom_row = pwdata->iBottomRow;
+ int cxChar = pwdata->cxChar;
+ int cyChar = pwdata->cyChar;
+ int y;
+
+ // Select System Font
+ SelectObject(hdc, GetStockObject(SYSTEM_FIXED_FONT));
+
+ while (TRUE)
+ {
+ int len = lstrlen(&pwdata->aImage[row][col]);
+
+ if (len != 0)
+ {
+ y = calc_row(row, pwdata) * cyChar;
+ TextOut(hdc, 0, y, &pwdata->aImage[row][col], len);
+ }
+
+ if (row == bottom_row)
+ {
+ break;
+ }
+
+ row = inc_row(row, 1);
+ }
+
+ if (pwdata->fGotFocus)
+ {
+ if ((pwdata->iNextCol >= pwdata->iFirstCol)
+ && (row_diff(pwdata->iNextRow, pwdata->iTopRow) < pwdata->cRows))
+ {
+ if (pwdata->fCaretHidden)
+ {
+ pwdata->fCaretHidden = FALSE;
+ ShowCaret(hwnd);
+ }
+
+ SetCaretPos(
+ (pwdata->iNextCol - pwdata->iFirstCol) * pwdata->cxChar,
+ calc_row(pwdata->iNextRow, pwdata) * pwdata->cyChar);
+ }
+ else
+ {
+ if (!pwdata->fCaretHidden)
+ {
+ pwdata->fCaretHidden = TRUE;
+ HideCaret(hwnd);
+ }
+ }
+ }
+
+ EndPaint(hwnd, &ps);
+}
+
+
+
+
+
+//
+// FUNCTION: WmPrintLine
+//
+// PURPOSE: Print a line on the screen.
+//
+// Note: this is a user message not an intrinsic Window's message.
+//
+void
+WmPrintLine(
+ HWND hwnd,
+ WPARAM wParam,
+ LONG lParam,
+ WData *pTermData)
+{
+ TCHAR *pBuf = (TCHAR *) lParam;
+
+ // MessageBox(hwnd, L"WmPrintLine", L"Debug", MB_OK);
+
+ // DebugBreak();
+
+ while (wParam--)
+ {
+ // Is character a lf?
+ if (*pBuf == '\n')
+ {
+ // Convert to cr since that is what this window uses
+ *pBuf = '\r';
+ }
+
+ // Write the character to the window
+ EchoChar(hwnd, 1, *pBuf++, pTermData);
+ }
+
+}
+
+//
+// FUNCTION: WmPutc
+//
+// PURPOSE: Print a single character on the screen
+//
+// Note: this is a user message not an intrinsic Window's message.
+//
+void
+WmPutc(
+ HWND hwnd,
+ WPARAM wParam,
+ WData *pTermData)
+{
+ // Is character a lf?
+ if (wParam == '\n')
+ {
+ // Convert to cr since that is what this window uses
+ wParam = '\r';
+ }
+
+ // Write the character to the window
+ EchoChar(hwnd, 1, wParam, pTermData);
+}
+
+
+/****************************************************************************
+
+ FUNCTION: TermWndProc(HWND, unsigned, WORD, LONG)
+
+ PURPOSE: Processes messages
+
+ MESSAGES:
+
+ COMMENTS:
+
+****************************************************************************/
+
+long TermWndProc(
+ HWND hWnd,
+ UINT message,
+ WPARAM wParam,
+ LPARAM lParam)
+{
+ WData *pTerm = (WData *) GetWindowLong(hWnd, 0);
+
+ switch (message)
+ {
+ case WM_CREATE:
+ WmCreate(hWnd, (CREATESTRUCT *) lParam);
+ break;
+
+ case WM_COMMAND:
+ case WM_SYSCOMMAND:
+ // Call procedure that processes the menus
+ return (*(pTerm->pMenuProc))(hWnd, message, wParam, lParam,
+ pTerm->pvCallBackData);
+
+ case WM_SIZE:
+ WmSize(hWnd, wParam, lParam, pTerm);
+ break;
+
+ case WM_SETFOCUS:
+ WmSetFocus(hWnd, pTerm);
+ break;
+
+ case WM_KILLFOCUS:
+ WmKillFocus(hWnd, pTerm);
+ break;
+
+ case WM_VSCROLL:
+ WmVscroll(hWnd, wParam, lParam, pTerm);
+ break;
+
+ case WM_HSCROLL:
+ WmHscroll(hWnd, wParam, lParam, pTerm);
+ break;
+
+ case WM_CHAR:
+ // Character message echo and put in buffer
+ return (*(pTerm->pCharProc))(hWnd, message, wParam, lParam,
+ pTerm->pvCallBackData);
+
+ case WM_PAINT:
+ WmPaint(hWnd, pTerm);
+ break;
+
+ case WM_USER:
+ case WM_CLOSE:
+ DestroyWindow(hWnd);
+ break;
+
+ case WM_NCDESTROY:
+ // Call close notification procedure
+ return (*(pTerm->pCloseProc))(hWnd, message, wParam, lParam,
+ pTerm->pvCallBackData);
+
+ case WM_PRINT_LINE:
+ WmPrintLine(hWnd, wParam, lParam, pTerm);
+ break;
+
+ case WM_PUTC:
+ WmPutc(hWnd, wParam, pTerm);
+ break;
+
+ case WM_DESTROY:
+ PostQuitMessage(0);
+ break;
+
+ case WM_TERM_WND:
+ DestroyWindow(hWnd);
+ break;
+
+ default: /* Passes it on if unproccessed */
+ return (DefWindowProc(hWnd, message, wParam, lParam));
+ }
+
+ return 0;
+}
+
+
+/****************************************************************************
+
+ FUNCTION: TermRegisterClass(HANDLE)
+
+ PURPOSE: Register a class for a terminal window
+
+ COMMENTS:
+
+
+****************************************************************************/
+
+BOOL TermRegisterClass(
+ HANDLE hInstance,
+ LPTSTR MenuName,
+ LPTSTR ClassName,
+ LPTSTR Icon)
+{
+ WNDCLASS wc;
+ BOOL retVal;
+
+ // Make sure blank line is blank
+ memset(BlankLine, ' ', 80);
+
+ /* Fill in window class structure with parameters that describe the */
+ /* main window. */
+
+ wc.style = 0;
+ wc.lpfnWndProc = TermWndProc;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = sizeof(WData *);
+ wc.hInstance = hInstance;
+ wc.hIcon = LoadIcon(NULL, Icon);
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wc.hbrBackground = GetStockObject(WHITE_BRUSH);
+ wc.lpszMenuName = MenuName;
+ wc.lpszClassName = ClassName;
+
+ /* Register the window class and return success/failure code. */
+ if (retVal = RegisterClass(&wc))
+ {
+ // Class got registered -- so finish set up
+ hInst = hInstance;
+ }
+
+ return retVal;
+}
+
+
+/****************************************************************************
+
+ FUNCTION: TermCreateWindow(LPWSTR, LPWSTR, HMENU, void *, void *, int)
+
+ PURPOSE: Create a window of a previously registered window class
+
+ COMMENTS:
+
+
+****************************************************************************/
+
+BOOL
+TermCreateWindow(
+ LPTSTR lpClassName,
+ LPTSTR lpWindowName,
+ HMENU hMenu,
+ MFUNCP MenuProc,
+ CFUNCP CharProc,
+ TFUNCP CloseProc,
+ int nCmdShow,
+ HWND *phNewWindow,
+ void *pvCallBackData)
+{
+ HWND hWnd; // Main window handle.
+ WData *pTermData;
+
+ // Allocate control structure for the window
+ if ((pTermData = malloc(sizeof(WData))) == NULL)
+ {
+ return FALSE;
+ }
+
+ // Set entire structure to nulls
+ memset((TCHAR *) pTermData, '\0', sizeof(WData));
+
+ // Initialize function pointers
+ pTermData->pMenuProc = MenuProc;
+ pTermData->pCharProc = CharProc;
+ pTermData->pCloseProc = CloseProc;
+
+ // Initialize callback data
+ pTermData->pvCallBackData = pvCallBackData;
+
+ // Create a main window for this application instance.
+ hWnd = CreateWindow(
+ lpClassName,
+ lpWindowName,
+ WS_OVERLAPPEDWINDOW,
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ NULL,
+ hMenu,
+ hInst,
+ (LPTSTR) pTermData
+ );
+
+ // If window could not be created, return "failure"
+
+ if (!hWnd)
+ {
+ free(pTermData);
+ return FALSE;
+ }
+
+ // BUGBUG - Why would we want to set focus?
+ // SetFocus(hWnd);
+
+ // Make the window visible; update its client area; and return "success"
+
+ // ShowWindow(hWnd, nCmdShow);
+ // UpdateWindow(hWnd);
+ *phNewWindow = hWnd;
+ return (TRUE);
+}
diff --git a/private/oleutest/server2/wterm.h b/private/oleutest/server2/wterm.h
new file mode 100644
index 000000000..3f5c0e8dd
--- /dev/null
+++ b/private/oleutest/server2/wterm.h
@@ -0,0 +1,48 @@
+#ifndef __WTERM__
+#define __WTERM__
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+// Message to print a line on the window
+#define WM_PRINT_LINE (WM_USER + 1)
+
+// Message to print a character on the window
+#define WM_PUTC (WM_USER + 2)
+
+// Message used to terminate this window
+#define WM_TERM_WND (WM_USER + 3)
+
+//
+// Typedefs for call back functions for the window
+//
+typedef long (*MFUNCP)(HWND, UINT, WPARAM, LPARAM, void *);
+typedef long (*CFUNCP)(HWND, UINT, WPARAM, LPARAM, void *);
+typedef long (*TFUNCP)(HWND, UINT, WPARAM, LPARAM, void *);
+
+// Register the terminal window class
+BOOL TermRegisterClass(
+ HANDLE hInstance,
+ LPTSTR MenuName,
+ LPTSTR ClassName,
+ LPTSTR ICON);
+
+// Create a window for the terminal
+BOOL
+TermCreateWindow(
+ LPTSTR lpClassName,
+ LPTSTR lpWindowName,
+ HMENU hMenu,
+ MFUNCP MenuProc,
+ CFUNCP CharProc,
+ TFUNCP CloseProc,
+ int nCmdShow,
+ HWND *phNewWindow,
+ void *pvCallBackData);
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // __WTERM__
diff --git a/private/oleutest/server3/daytona/makefile b/private/oleutest/server3/daytona/makefile
new file mode 100644
index 000000000..1d3728d41
--- /dev/null
+++ b/private/oleutest/server3/daytona/makefile
@@ -0,0 +1,10 @@
+############################################################################
+#
+# Copyright (C) 1992, Microsoft Corporation.
+#
+# All rights reserved.
+#
+############################################################################
+
+!include $(NTMAKEENV)\makefile.def
+
diff --git a/private/oleutest/server3/daytona/sources b/private/oleutest/server3/daytona/sources
new file mode 100644
index 000000000..5a81a1760
--- /dev/null
+++ b/private/oleutest/server3/daytona/sources
@@ -0,0 +1,74 @@
+!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:
+
+ Donna Liu (DonnaLi) 19-Dec-1993
+
+!ENDIF
+
+MAJORCOMP = cairole
+MINORCOMP = com
+
+#
+# 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= fail
+
+#
+# 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= ..\..\..\ole32\common\daytona;..\..\..\ole32\ih;..;..\..\common;..\..\..\cinc
+
+C_DEFINES= \
+ $(C_DEFINES) \
+ -DFLAT \
+ -DWIN32=100 \
+ -D_NT1X_=100 \
+ -DUNICODE \
+ -D_UNICODE \
+ -DINC_OLE2 \
+ -DNOEXCEPTIONS \
+ -DCAIROLE_DOWNLEVEL
+
+BLDCRT= 1
+
+SOURCES= \
+ ..\fail.cxx
+
+UMTYPE= windows
+UMENTRY= winmain
+UMAPPL=
+UMTEST=
+UMLIBS=
+
+USE_CRTDLL= 1
+
+#PRECOMPILED_INCLUDE= ..\headers.cxx
diff --git a/private/oleutest/server3/dirs b/private/oleutest/server3/dirs
new file mode 100644
index 000000000..1d0b9edbb
--- /dev/null
+++ b/private/oleutest/server3/dirs
@@ -0,0 +1,38 @@
+!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/server3/fail.cxx b/private/oleutest/server3/fail.cxx
new file mode 100644
index 000000000..828ccb3ce
--- /dev/null
+++ b/private/oleutest/server3/fail.cxx
@@ -0,0 +1,82 @@
+//+-------------------------------------------------------------------
+//
+// File: fail.cxx
+//
+// Contents: An exe that just returns: to test failure of process start.
+//
+// History: 1-Dec-94 BillMo Created.
+//
+//---------------------------------------------------------------------
+
+#include <windows.h>
+#include <tchar.h>
+
+#define FILE_SHARE_DELETE 0x00000004
+
+//+-------------------------------------------------------------------
+//
+// Function: WinMain
+//
+// Synopsis: Entry point to EXE - does little else
+//
+// Arguments:
+//
+// Returns: TRUE
+//
+// History: 1-Dec-94 BillMo Created
+//
+//--------------------------------------------------------------------
+
+int WINAPI WinMain(
+ HINSTANCE hInstance,
+ HINSTANCE hPrevInstance,
+ char *lpszCmdLine,
+ int nCmdShow)
+{
+ //
+ // We indicate that we ran by touching a file that olebind will look at the
+ // timestamps of. This is because we don't have a unique error code
+ // to distinguish errors during start of a server.
+ //
+ HANDLE hTouchFile;
+ TCHAR tszFileName[MAX_PATH+1];
+ DWORD dw;
+ SYSTEMTIME st;
+ FILETIME ft;
+
+ GetSystemDirectory(tszFileName, MAX_PATH+1);
+ _tcscat(tszFileName, TEXT("\\failtst.tst"));
+ hTouchFile = CreateFile(tszFileName,
+ GENERIC_READ|GENERIC_WRITE,
+ FILE_SHARE_READ|FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+ if (hTouchFile == INVALID_HANDLE_VALUE)
+ {
+ if (GetLastError() == ERROR_FILE_NOT_FOUND)
+ {
+ MessageBox(GetDesktopWindow(),
+ TEXT("This program (fail.exe) must be run from olebind.exe"),
+ TEXT("Error in test"),
+ MB_OK);
+ }
+ else
+ {
+ MessageBox(GetDesktopWindow(),
+ TEXT("This program (fail.exe) failed for unknown reason"),
+ TEXT("Error in test"),
+ MB_OK);
+ GetLastError();
+ }
+ return 0;
+ }
+
+ GetSystemTime(&st);
+ WriteFile(hTouchFile, &st, sizeof(st), &dw, NULL);
+ CloseHandle(hTouchFile);
+
+ return (0);
+}
+
diff --git a/private/oleutest/simpcntr/app.cpp b/private/oleutest/simpcntr/app.cpp
new file mode 100644
index 000000000..37f4a91aa
--- /dev/null
+++ b/private/oleutest/simpcntr/app.cpp
@@ -0,0 +1,1060 @@
+//**********************************************************************
+// File name: app.cpp
+//
+// Implementation file for the CSimpleApp Class
+//
+// Functions:
+//
+// See app.h for a list of member functions.
+//
+// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+
+#include "pre.h"
+#include "iocs.h"
+#include "ias.h"
+#include "ioipf.h"
+#include "ioips.h"
+#include "app.h"
+#include "site.h"
+#include "doc.h"
+#include <testmess.h>
+
+extern void DeactivateIfActive(HWND hWnd);
+
+#ifdef WIN32
+extern BOOL CALLBACK About(HWND hDlg, UINT message, WPARAM wParam,
+ LPARAM lParam);
+#endif
+
+
+//**********************************************************************
+//
+// CSimpleApp::CSimpleApp()
+//
+// Purpose:
+//
+// Constructor for CSimpleApp
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// SetRectEmpty Windows API
+//
+// Comments:
+//
+// CSimpleApp has a contained COleInPlaceFrame. On construction
+// of CSimpleApp, we explicitly call the constructor of this
+// contained class and pass a copy of the this pointer, so that
+// COleInPlaceFrame can refer back to this class
+//
+//********************************************************************
+#pragma warning(disable : 4355) // turn off this warning. This warning
+ // tells us that we are passing this in
+ // an initializer, before "this" is through
+ // initializing. This is ok, because
+ // we just store the ptr in the other
+ // constructor
+
+CSimpleApp::CSimpleApp() : m_OleInPlaceFrame(this)
+#pragma warning (default : 4355) // Turn the warning back on
+{
+ TestDebugOut(TEXT("In CSimpleApp's Constructor \r\n"));
+
+ // Set Ref Count
+ m_nCount = 0;
+
+ // clear members
+ m_hAppWnd = NULL;
+ m_hInst = NULL;
+ m_lpDoc = NULL;
+
+ // Make sure we don't think we are deactivating
+ m_fDeactivating = FALSE;
+
+ // We haven't got a unit test accelerator so ...
+ m_fGotUtestAccelerator = FALSE;
+
+ // clear flags
+ m_fInitialized = FALSE;
+ m_fCSHMode = FALSE;
+ m_fMenuMode = FALSE;
+
+ // used for inplace
+ SetRectEmpty(&nullRect);
+}
+
+//**********************************************************************
+//
+// CSimpleApp::~CSimpleApp()
+//
+// Purpose:
+//
+// Destructor for CSimpleApp Class.
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// DeleteObject Windows API
+// OleUninitialize OLE API
+//
+//
+//********************************************************************
+
+CSimpleApp::~CSimpleApp()
+{
+ TestDebugOut(TEXT("In CSimpleApp's Destructor\r\n"));
+
+ if (m_hStdPal)
+ DeleteObject(m_hStdPal);
+
+ // need to uninit the library...
+ if (m_fInitialized)
+ OleUninitialize();
+}
+
+//**********************************************************************
+//
+// CSimpleApp::DestroyDocs()
+//
+// Purpose:
+//
+// Destroys all of the open documents in the application (Only one
+// since this is an SDI app, but could easily be modified to
+// support MDI).
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+// CSimpDoc::Close DOC.CPP
+//
+//
+//********************************************************************
+
+void CSimpleApp::DestroyDocs()
+{
+ m_lpDoc->Close(); // we have only 1 document
+}
+
+//**********************************************************************
+//
+// CSimpleApp::QueryInterface
+//
+// Purpose:
+//
+// Used for interface negotiation at the application level.
+//
+// Parameters:
+//
+// REFIID riid - A reference to the interface that is
+// being queried.
+//
+// LPVOID FAR* ppvObj - An out parameter to return a pointer to
+// the interface.
+//
+// Return Value:
+//
+// S_OK - The interface is supported.
+// E_NOINTERFACE - The interface is not supported
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// IsEqualIID OLE API
+// ResultFromScode OLE API
+// COleInPlaceFrame::AddRef IOIPF.CPP
+// CSimpleApp::AddRef APP.CPP
+//
+// Comments:
+//
+// Note that this QueryInterface is associated with the frame.
+// Since the application could potentially have multiple documents
+// and multiple objects, a lot of the interfaces are ambiguous.
+// (ie. which IOleObject is returned?). For this reason, only
+// pointers to interfaces associated with the frame are returned.
+// In this implementation, Only IOleInPlaceFrame (or one of the
+// interfaces it is derived from) can be returned.
+//
+//********************************************************************
+
+STDMETHODIMP CSimpleApp::QueryInterface(REFIID riid, LPVOID FAR* ppvObj)
+{
+ TestDebugOut(TEXT("In CSimpleApp::QueryInterface\r\n"));
+
+ *ppvObj = NULL; // must set out pointer parameters to NULL
+
+ // looking for IUnknown
+ if ( IsEqualIID(riid, IID_IUnknown))
+ {
+ AddRef();
+ *ppvObj = this;
+ return ResultFromScode(S_OK);
+ }
+
+ // looking for IOleWindow
+ if ( IsEqualIID(riid, IID_IOleWindow))
+ {
+ m_OleInPlaceFrame.AddRef();
+ *ppvObj=&m_OleInPlaceFrame;
+ return ResultFromScode(S_OK);
+ }
+
+ // looking for IOleInPlaceUIWindow
+ if ( IsEqualIID(riid, IID_IOleInPlaceUIWindow))
+ {
+ m_OleInPlaceFrame.AddRef();
+ *ppvObj=&m_OleInPlaceFrame;
+ return ResultFromScode(S_OK);
+ }
+
+ // looking for IOleInPlaceFrame
+ if ( IsEqualIID(riid, IID_IOleInPlaceFrame))
+ {
+ m_OleInPlaceFrame.AddRef();
+ *ppvObj=&m_OleInPlaceFrame;
+ return ResultFromScode(S_OK);
+ }
+
+ // Not a supported interface
+ return ResultFromScode(E_NOINTERFACE);
+}
+
+//**********************************************************************
+//
+// CSimpleApp::AddRef
+//
+// Purpose:
+//
+// Adds to the reference count at the Application level.
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// ULONG - The new reference count of the application.
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+// Comments:
+//
+// Due to the reference counting model that is used in this
+// implementation, this reference count is the sum of the
+// reference counts on all interfaces of all objects open
+// in the application.
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) CSimpleApp::AddRef()
+{
+ TestDebugOut(TEXT("In CSimpleApp::AddRef\r\n"));
+ return ++m_nCount;
+}
+
+//**********************************************************************
+//
+// CSimpleApp::Release
+//
+// Purpose:
+//
+// Decrements the reference count at this level
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// ULONG - The new reference count of the application.
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) CSimpleApp::Release()
+{
+ TestDebugOut(TEXT("In CSimpleApp::Release\r\n"));
+
+ if (--m_nCount == 0)
+ {
+ delete this;
+ return 0;
+ }
+ return m_nCount;
+}
+
+//**********************************************************************
+//
+// CSimpleApp::fInitApplication
+//
+// Purpose:
+//
+// Initializes the application
+//
+// Parameters:
+//
+// HANDLE hInstance - Instance handle of the application.
+//
+// Return Value:
+//
+// TRUE - Application was successfully initialized.
+// FALSE - Application could not be initialized
+//
+// Function Calls:
+// Function Location
+//
+// LoadIcon Windows API
+// LoadCursor Windows API
+// GetStockObject Windows API
+// RegisterClass Windows API
+//
+//
+//********************************************************************
+
+BOOL CSimpleApp::fInitApplication(HANDLE hInstance)
+{
+ // Initialize our accelerator table
+ if ((m_hAccel = LoadAccelerators((HINSTANCE) hInstance,
+ TEXT("SimpcntrAccel"))) == NULL)
+ {
+ // Load failed so abort
+ TestDebugOut(TEXT("ERROR: Accelerator Table Load FAILED\r\n"));
+ return FALSE;
+ }
+
+ WNDCLASS wc;
+
+ // Fill in window class structure with parameters that describe the
+ // main window.
+
+ wc.style = NULL; // Class style(s).
+ wc.lpfnWndProc = MainWndProc; // Function to retrieve messages for
+ // windows of this class.
+ wc.cbClsExtra = 0; // No per-class extra data.
+ wc.cbWndExtra = 0; // No per-window extra data.
+ wc.hInstance = (HINSTANCE) hInstance; // Application that owns the
+ // class.
+ wc.hIcon = LoadIcon((HINSTANCE) hInstance, TEXT("SimpCntr"));
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
+ wc.lpszMenuName = TEXT("SIMPLEMENU"); // Name of menu resource in
+ // .RC file.
+ wc.lpszClassName = TEXT("SimpCntrAppWClass"); // Name used in
+ // CreateWindow call
+
+ if (!RegisterClass(&wc))
+ return FALSE;
+
+ wc.style = CS_DBLCLKS; // Class style(s). allow DBLCLK's
+ wc.lpfnWndProc = DocWndProc; // Function to retrieve messages for
+ // windows of this class.
+ wc.cbClsExtra = 0; // No per-class extra data.
+ wc.cbWndExtra = 0; // No per-window extra data.
+ wc.hInstance = (HINSTANCE) hInstance; // Application that owns
+ // the class.
+ wc.hIcon = NULL;
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
+ wc.lpszMenuName = NULL;
+ wc.lpszClassName = TEXT("SimpCntrDocWClass"); // Name used in
+ // CreateWindow call.
+
+ // Register the window class and return success/failure code.
+
+ return (RegisterClass(&wc));
+}
+
+//**********************************************************************
+//
+// CSimpleApp::fInitInstance
+//
+// Purpose:
+//
+// Instance initialization.
+//
+// Parameters:
+//
+// HANDLE hInstance - App. Instance Handle.
+//
+// int nCmdShow - Show parameter from WinMain
+//
+// Return Value:
+//
+// TRUE - Initialization Successful
+// FALSE - Initialization Failed.
+//
+//
+// Function Calls:
+// Function Location
+//
+// CreateWindow Windows API
+// ShowWindow Windows API
+// UpdateWindow Windows API
+// OleBuildVersion OLE API
+// OleInitialize OLE API
+//
+// Comments:
+//
+// Note that successful Initalization of the OLE libraries
+// is remembered so the UnInit is only called if needed.
+//
+//********************************************************************
+
+BOOL CSimpleApp::fInitInstance (HANDLE hInstance, int nCmdShow)
+{
+ LPMALLOC lpMalloc = NULL;
+
+#ifndef WIN32
+ /* Since OLE is part of the operating system in Win32, we don't need to
+ * check the version number in Win32.
+ */
+ DWORD dwVer = OleBuildVersion();
+
+ // check to see if we are compatible with this version of the libraries
+ if (HIWORD(dwVer) != rmm || LOWORD(dwVer) < rup)
+ {
+#ifdef _DEBUG
+ TestDebugOut(TEXT("WARNING:Incompatible OLE library version\r\n"));
+#else
+ return FALSE;
+#endif
+ }
+#endif // WIN32
+
+#if defined( _DEBUG )
+ /* OLE2NOTE: Use a special debug allocator to help track down
+ ** memory leaks.
+ */
+ OleStdCreateDbAlloc(0, &lpMalloc);
+#endif
+
+ // We try passing in our own allocator first - if that fails we
+ // try without overriding the allocator.
+
+ if (SUCCEEDED(OleInitialize(lpMalloc)) ||
+ SUCCEEDED(OleInitialize(NULL)))
+ {
+ m_fInitialized = TRUE;
+ }
+
+#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->Release();
+#endif
+
+ m_hInst = (HINSTANCE) hInstance;
+
+ // Create the "application" windows
+ m_hAppWnd = CreateWindow (TEXT("SimpCntrAppWClass"),
+ TEXT("Simple OLE 2.0 In-Place Container"),
+ WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ NULL,
+ NULL,
+ (HINSTANCE) hInstance,
+ NULL);
+
+ if (!m_hAppWnd)
+ return FALSE;
+
+ m_hStdPal = OleStdCreateStandardPalette();
+
+ ShowWindow (m_hAppWnd, nCmdShow);
+ UpdateWindow (m_hAppWnd);
+
+ // if we have been launched by the test driver, tell it our window handle
+ if( m_hDriverWnd )
+ {
+ PostMessage(m_hDriverWnd, WM_TESTREG, (WPARAM)m_hAppWnd, 0);
+ }
+
+
+
+ return m_fInitialized;
+}
+
+//**********************************************************************
+//
+// CSimpleApp::lCommandHandler
+//
+// Purpose:
+//
+// Handles the processing of WM_COMMAND.
+//
+// Parameters:
+//
+// HWND hWnd - Handle to the application Window
+//
+// UINT message - message (always WM_COMMAND)
+//
+// WPARAM wParam - Same as passed to the WndProc
+//
+// LPARAM lParam - Same as passed to the WndProc
+//
+// Return Value:
+//
+// NULL
+//
+// Function Calls:
+// Function Location
+//
+// IOleInPlaceActiveObject::QueryInterface Object
+// IOleInPlaceObject::ContextSensitiveHelp Object
+// IOleInPlaceObject::Release Object
+// IOleObject::DoVerb Object
+// MessageBox Windows API
+// DialogBox Windows API
+// MakeProcInstance Windows API
+// FreeProcInstance Windows API
+// SendMessage Windows API
+// DefWindowProc Windows API
+// CSimpleDoc::InsertObject DOC.CPP
+// CSimpleSite::GetObjRect SITE.CPP
+// CSimpleApp::lCreateDoc APP.CPP
+//
+//
+//********************************************************************
+
+long CSimpleApp::lCommandHandler (HWND hWnd, UINT message,
+ WPARAM wParam, LPARAM lParam)
+{
+ RECT rect;
+
+ // Win32 uses high word to tell were command came from so we dump it.
+ wParam = LOWORD(wParam);
+
+ // context sensitive help...
+ if (m_fMenuMode || m_fCSHMode)
+ {
+ if (m_fCSHMode)
+ {
+ // clear context sensitive help flag
+ m_fCSHMode = FALSE;
+
+ // if there is an InPlace active object, call its context
+ // sensitive help method with the FALSE parameter to bring the
+ // object out of the csh state. See the technotes for details.
+ if (m_lpDoc->m_lpActiveObject)
+ {
+ LPOLEINPLACEOBJECT lpInPlaceObject;
+ m_lpDoc->m_lpActiveObject->QueryInterface(
+ IID_IOleInPlaceObject,
+ (LPVOID FAR *)&lpInPlaceObject);
+ lpInPlaceObject->ContextSensitiveHelp(FALSE);
+ lpInPlaceObject->Release();
+ }
+ }
+
+ // see the technotes for details on implementing context sensitive
+ // help
+ if (m_fMenuMode)
+ {
+ m_fMenuMode = FALSE;
+
+ if (m_lpDoc->m_lpActiveObject)
+ m_lpDoc->m_lpActiveObject->ContextSensitiveHelp(FALSE);
+ }
+ // if we provided help, we would do it here...
+ MessageBox (hWnd, TEXT("Help"), TEXT("Help"), MB_OK);
+
+ return NULL;
+ }
+
+ // see if the command is a verb selections
+ if (wParam >= IDM_VERB0)
+ {
+ // get the rectangle of the object
+ m_lpDoc->m_lpSite->GetObjRect(&rect);
+
+ m_lpDoc->m_lpSite->m_lpOleObject->DoVerb(wParam - IDM_VERB0, NULL,
+ &m_lpDoc->m_lpSite->m_OleClientSite,
+ -1, m_lpDoc->m_hDocWnd, &rect);
+ }
+ else
+ {
+ switch (wParam)
+ {
+ // bring up the About box
+ case IDM_ABOUT:
+ {
+#ifdef WIN32
+ DialogBox(m_hInst, // current instance
+ TEXT("AboutBox"), // resource to use
+ m_hAppWnd, // parent handle
+ About); // About() instance address
+#else
+ FARPROC lpProcAbout = MakeProcInstance((FARPROC)About,
+ m_hInst);
+
+ DialogBox(m_hInst, // current instance
+ TEXT("AboutBox"), // resource to use
+ m_hAppWnd, // parent handle
+ lpProcAbout); // About() instance address
+
+ FreeProcInstance(lpProcAbout);
+#endif
+
+ break;
+ }
+
+ // bring up the InsertObject Dialog
+ case IDM_INSERTOBJECT:
+ m_lpDoc->InsertObject();
+ break;
+
+ // exit the application
+ case IDM_EXIT:
+ SendMessage(hWnd, WM_SYSCOMMAND, SC_CLOSE, 0L);
+ break;
+
+ case IDM_NEW:
+ m_lpDoc->Close();
+ m_lpDoc = NULL;
+ lCreateDoc(hWnd, 0, 0, 0);
+ break;
+
+ case IDM_DEACTIVATE:
+ DeactivateIfActive(hWnd);
+ break;
+
+ case IDM_UTEST:
+ m_fGotUtestAccelerator = TRUE;
+ break;
+
+ default:
+ return (DefWindowProc(hWnd, message, wParam, lParam));
+ } // end of switch
+ } // end of else
+ return NULL;
+}
+
+//**********************************************************************
+//
+// CSimpleApp::lSizeHandler
+//
+// Purpose:
+//
+// Handles the WM_SIZE message
+//
+// Parameters:
+//
+// HWND hWnd - Handle to the application Window
+//
+// UINT message - message (always WM_SIZE)
+//
+// WPARAM wParam - Same as passed to the WndProc
+//
+// LPARAM lParam - Same as passed to the WndProc
+//
+// Return Value:
+//
+// LONG - returned from the "document" resizing
+//
+// Function Calls:
+// Function Location
+//
+// GetClientRect Windows API
+// CSimpleDoc::lResizeDoc DOC.CPP
+//
+//
+//********************************************************************
+
+long CSimpleApp::lSizeHandler (HWND hWnd, UINT message, WPARAM wParam,
+ LPARAM lParam)
+{
+ RECT rect;
+
+ GetClientRect(m_hAppWnd, &rect);
+ return m_lpDoc->lResizeDoc(&rect);
+}
+
+//**********************************************************************
+//
+// CSimpleApp::lCreateDoc
+//
+// Purpose:
+//
+// Handles the creation of a document.
+//
+// Parameters:
+//
+// HWND hWnd - Handle to the application Window
+//
+// UINT message - message (always WM_CREATE)
+//
+// WPARAM wParam - Same as passed to the WndProc
+//
+// LPARAM lParam - Same as passed to the WndProc
+//
+// Return Value:
+//
+// NULL
+//
+// Function Calls:
+// Function Location
+//
+// GetClientRect Windows API
+// CSimpleDoc::CSimpleDoc DOC.CPP
+//
+//
+//********************************************************************
+
+long CSimpleApp::lCreateDoc (HWND hWnd, UINT message, WPARAM wParam,
+ LPARAM lParam)
+{
+ RECT rect;
+
+ GetClientRect(hWnd, &rect);
+
+ m_lpDoc = CSimpleDoc::Create(this, &rect, hWnd);
+
+ return NULL;
+}
+
+//**********************************************************************
+//
+// CSimpleApp::AddFrameLevelUI
+//
+// Purpose:
+//
+// Used during InPlace negotiation.
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// COleInPlaceFrame::SetMenu IOIPF.CPP
+// CSimpleApp::AddFrameLevelTools APP.CPP
+//
+// Comments:
+//
+// Be sure to read the Technotes included in the OLE 2.0 toolkit
+//
+//********************************************************************
+
+void CSimpleApp::AddFrameLevelUI()
+{
+ m_OleInPlaceFrame.SetMenu(NULL, NULL, NULL);
+ AddFrameLevelTools();
+}
+
+//**********************************************************************
+//
+// CSimpleApp::AddFrameLevelTools
+//
+// Purpose:
+//
+// Used during InPlace negotiation.
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// COleInPlaceFrame::SetBorderSpace IOIPF.CPP
+// InvalidateRect Windows API
+//
+// Comments:
+//
+// Be sure to read the Technotes included in the OLE 2.0 toolkit
+//
+//********************************************************************
+
+void CSimpleApp::AddFrameLevelTools()
+{
+ m_OleInPlaceFrame.SetBorderSpace(&nullRect);
+ InvalidateRect(m_hAppWnd, NULL, TRUE);
+}
+
+//**********************************************************************
+//
+// CSimpleApp::HandleAccelerators
+//
+// Purpose:
+//
+// To properly handle accelerators in the Message Loop
+//
+// Parameters:
+//
+// LPMSG lpMsg - A pointer to the message structure.
+//
+// Return Value:
+//
+// TRUE - The accelerator was handled
+// FALSE - The accelerator was not handled
+//
+// Function Calls:
+// Function Location
+//
+// IOleInPlaceActiveObject::TranslateAccelerator Object
+//
+// Comments:
+//
+// If an object is InPlace active, it gets the first shot at
+// handling the accelerators.
+//
+//********************************************************************
+
+BOOL CSimpleApp::HandleAccelerators(LPMSG lpMsg)
+{
+ HRESULT hResult;
+ BOOL retval = FALSE;
+
+ // The following is what you would do if this were an inproc DLL.
+ // A local server will be passing us commands to process
+#if 0
+ // if we have an InPlace Active Object
+ if (m_lpDoc->m_lpActiveObject)
+ {
+ // Pass the accelerator on...
+ hResult = m_lpDoc->m_lpActiveObject->TranslateAccelerator(lpMsg);
+ if (hResult == NOERROR)
+ retval = TRUE;
+ }
+#endif
+
+ // We process our accelerators
+ return TranslateAccelerator(m_hAppWnd, m_hAccel, lpMsg);
+}
+
+//**********************************************************************
+//
+// CSimpleApp::PaintApp
+//
+// Purpose:
+//
+// Handles the painting of the doc window.
+//
+//
+// Parameters:
+//
+// HDC hDC - hDC to the Doc Window.
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// CSimpleDoc::PaintDoc DOC.CPP
+//
+// Comments:
+//
+// This is an app level function in case we want to do palette
+// management.
+//
+//********************************************************************
+
+void CSimpleApp::PaintApp (HDC hDC)
+{
+ // at this level, we could enumerate through all of the
+ // visible objects in the application, so that a palette
+ // that best fits all of the objects can be built.
+
+ // This app is designed to take on the same palette
+ // functionality that was provided in OLE 1.0, the palette
+ // of the last object drawn is realized. Since we only
+ // support one object at a time, it shouldn't be a big
+ // deal.
+
+ // if we supported multiple documents, we would enumerate
+ // through each of the open documents and call paint.
+
+ if (m_lpDoc)
+ m_lpDoc->PaintDoc(hDC);
+
+}
+
+//**********************************************************************
+//
+// CSimpleApp::ContextSensitiveHelp
+//
+// Purpose:
+// Used in supporting context sensitive help at the app level.
+//
+//
+// Parameters:
+//
+// BOOL fEnterMode - Entering/Exiting Context Sensitive
+// help mode.
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// IOleInPlaceActiveObject::QueryInterface Object
+// IOleInPlaceObject::ContextSensitiveHelp Object
+// IOleInPlaceObject::Release Object
+//
+// Comments:
+//
+// This function isn't used because we don't support Shift+F1
+// context sensitive help. Be sure to look at the technotes
+// in the OLE 2.0 toolkit.
+//
+//********************************************************************
+
+void CSimpleApp::ContextSensitiveHelp (BOOL fEnterMode)
+{
+ if (m_fCSHMode != fEnterMode)
+ {
+ m_fCSHMode = fEnterMode;
+
+ // this code "trickles" the context sensitive help via shift+f1
+ // to the inplace active object. See the technotes for implementation
+ // details.
+ if (m_lpDoc->m_lpActiveObject)
+ {
+ LPOLEINPLACEOBJECT lpInPlaceObject;
+ m_lpDoc->m_lpActiveObject->QueryInterface(IID_IOleInPlaceObject,
+ (LPVOID FAR *)&lpInPlaceObject);
+ lpInPlaceObject->ContextSensitiveHelp(fEnterMode);
+ lpInPlaceObject->Release();
+ }
+ }
+}
+
+/* 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)
+**
+*/
+
+//**********************************************************************
+//
+// CSimpleApp::QueryNewPalette
+//
+// Purpose:
+// See above
+//
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// 0 if the handle to palette (m_hStdPal) is NULL,
+// 1 otherwise
+//
+// Function Calls:
+// Function Location
+//
+// SendMessage Windows API
+//
+//
+//********************************************************************
+
+LRESULT CSimpleApp::QueryNewPalette(void)
+{
+ if (m_hwndUIActiveObj)
+ {
+ if (SendMessage(m_hwndUIActiveObj, WM_QUERYNEWPALETTE,
+ (WPARAM)0, (LPARAM)0))
+ {
+ /* Object selected its palette as foreground palette */
+ return (LRESULT)1;
+ }
+ }
+
+ return wSelectPalette(m_hAppWnd, m_hStdPal, FALSE/*fBackground*/);
+}
+
+
+/* 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;
+}
+
+
diff --git a/private/oleutest/simpcntr/app.h b/private/oleutest/simpcntr/app.h
new file mode 100644
index 000000000..c00bcc3d7
--- /dev/null
+++ b/private/oleutest/simpcntr/app.h
@@ -0,0 +1,76 @@
+//**********************************************************************
+// File name: app.h
+//
+// Definition of CSimpleApp
+//
+// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+
+#if !defined( _APP_H_)
+#define _APP_H_
+
+#include <ole2.h>
+#include "ioipf.h"
+
+class CSimpleDoc;
+
+class CSimpleApp : public IUnknown
+{
+public:
+
+ int m_nCount; // reference count
+ HWND m_hAppWnd; // main window handle
+ HACCEL m_hAccel; // Handle to accelerator table
+ HINSTANCE m_hInst; // application instance
+
+ COleInPlaceFrame m_OleInPlaceFrame; // IOleInPlaceFrame Implementation
+
+ CSimpleDoc FAR * m_lpDoc; // pointer to document object
+ BOOL m_fInitialized; // OLE initialization flag
+ BOOL m_fCSHMode;
+ BOOL m_fMenuMode;
+ HWND m_hwndUIActiveObj; // HWND of UIActive Object
+ HPALETTE m_hStdPal; // Color palette used by container
+ BOOL m_fAppActive; // TRUE if app is active
+
+ BOOL m_fDeactivating; // TRUE if we are in the process of deactivating
+ // an inplace object.
+
+ BOOL m_fGotUtestAccelerator;// Received a unit test accelerator
+
+ HWND m_hDriverWnd; // Window of test driver
+
+ CSimpleApp(); // Constructor
+ ~CSimpleApp(); // Destructor
+ RECT nullRect;
+
+
+ // IUnknown Interfaces
+ STDMETHODIMP QueryInterface(REFIID riid, LPVOID FAR* ppvObj);
+ STDMETHODIMP_(ULONG) AddRef();
+ STDMETHODIMP_(ULONG) Release();
+
+ // Initialization methods
+
+ BOOL fInitApplication (HANDLE hInstance);
+ BOOL fInitInstance (HANDLE hInstance, int nCmdShow);
+
+ // Message handling methods
+
+ long lCommandHandler (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
+ long lSizeHandler (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
+ long lCreateDoc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
+ BOOL HandleAccelerators (LPMSG lpMsg);
+ void PaintApp(HDC hDC);
+ void DestroyDocs();
+
+ // In-Place support functions
+ void AddFrameLevelUI();
+ void AddFrameLevelTools();
+ void ContextSensitiveHelp (BOOL fEnterMode);
+ LRESULT QueryNewPalette(void);
+};
+
+LRESULT wSelectPalette(HWND hWnd, HPALETTE hPal, BOOL fBackground);
+
+#endif
diff --git a/private/oleutest/simpcntr/daytona/makefile b/private/oleutest/simpcntr/daytona/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/oleutest/simpcntr/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/simpcntr/daytona/sources b/private/oleutest/simpcntr/daytona/sources
new file mode 100644
index 000000000..7755e3eff
--- /dev/null
+++ b/private/oleutest/simpcntr/daytona/sources
@@ -0,0 +1,43 @@
+TARGETNAME=SIMPCNTR
+TARGETTYPE=PROGRAM
+TARGETPATH=OBJ
+TARGETLIBS= \
+ $(GUI32_LIBS) \
+ $(WIN32_LIBS) \
+ $(CRT_LIBS) \
+ $(NT_CRT) \
+ $(LIBRARY_PATH)\ole32.lib \
+ $(LIBRARY_PATH)\shell32.lib \
+ $(LIBRARY_PATH)\comdlg32.lib \
+ ..\..\letest\ole2ui\daytona\obj\*\ole2u32a.lib \
+ $(LIBRARY_PATH)\uuid.lib
+
+# BUGBUG (2/14/94) - Change above to $(LIBRARY_PATH)\uuid.lib when types
+# project # adds IViewObject2 and IExternalConnections to its uuid.lib
+
+BLDCRT=1
+UMTYPE=windows
+UMENTRY=winmain
+#UMLIBS= \
+# ..\..\libs\daytona\*\common.lib
+
+INCLUDES=..;..\oletest;..\..\letest\ole2ui;..\..\inc
+
+C_DEFINES=-DWIN32 -DDEBUG -DCLIENT -DWINDOWS
+
+NTDEBUG=ntsd
+NTDEBUGTYPE=both
+MSC_OPTIMIZATION=/Od
+
+SOURCES= \
+..\APP.CPP \
+..\DOC.CPP \
+..\IAS.CPP \
+..\ioipf.cpp \
+..\ioips.cpp \
+..\IOCS.CPP \
+..\PRE.CPP \
+..\SIMPCNTR.CPP \
+..\SITE.CPP \
+..\SIMPCNTR.RC \
+..\TESTS.CPP
diff --git a/private/oleutest/simpcntr/dirs b/private/oleutest/simpcntr/dirs
new file mode 100644
index 000000000..e0e16d167
--- /dev/null
+++ b/private/oleutest/simpcntr/dirs
@@ -0,0 +1,3 @@
+DIRS=
+OPTIONAL_DIRS= \
+ daytona
diff --git a/private/oleutest/simpcntr/doc.cpp b/private/oleutest/simpcntr/doc.cpp
new file mode 100644
index 000000000..5d16dea5c
--- /dev/null
+++ b/private/oleutest/simpcntr/doc.cpp
@@ -0,0 +1,628 @@
+//**********************************************************************
+// File name: DOC.CPP
+//
+// Implementation file for CSimpleDoc.
+//
+// Functions:
+//
+// See DOC.H for Class Definition
+//
+// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+
+#include "pre.h"
+#include "iocs.h"
+#include "ias.h"
+#include "ioipf.h"
+#include "ioips.h"
+#include "app.h"
+#include "site.h"
+#include "doc.h"
+
+//**********************************************************************
+//
+// CSimpleDoc::Create
+//
+// Purpose:
+//
+// Creation for the CSimpleDoc Class
+//
+// Parameters:
+//
+// CSimpleApp FAR * lpApp - Pointer to the CSimpleApp Class
+//
+// LPRECT lpRect - Client area rect of "frame" window
+//
+// HWND hWnd - Window Handle of "frame" window
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// StgCreateDocfile OLE API
+// CreateWindow Windows API
+// ShowWindow Windows API
+// UpdateWindow Windows API
+// EnableMenuItem Windows API
+//
+// Comments:
+//
+// This routine was added so that failure could be returned
+// from object creation.
+//
+//********************************************************************
+
+CSimpleDoc FAR * CSimpleDoc::Create(CSimpleApp FAR *lpApp, LPRECT lpRect,
+ HWND hWnd)
+{
+ CSimpleDoc FAR * lpTemp = new CSimpleDoc(lpApp, hWnd);
+
+ if (!lpTemp)
+ return NULL;
+
+ // create storage for the doc.
+ HRESULT hErr = StgCreateDocfile (NULL,
+ STGM_READWRITE | STGM_TRANSACTED |
+ STGM_SHARE_EXCLUSIVE,
+ 0, &lpTemp->m_lpStorage);
+
+ if (hErr != NOERROR)
+ goto error;
+
+ // create the document Window
+ lpTemp->m_hDocWnd = CreateWindow(
+ TEXT("SimpCntrDocWClass"),
+ NULL,
+ WS_CHILD | WS_CLIPCHILDREN,
+ lpRect->left,
+ lpRect->top,
+ lpRect->right,
+ lpRect->bottom,
+ hWnd,
+ NULL,
+ lpApp->m_hInst,
+ NULL);
+
+ if (!lpTemp->m_hDocWnd)
+ goto error;
+
+ ShowWindow(lpTemp->m_hDocWnd, SW_SHOWNORMAL); // Show the window
+ UpdateWindow(lpTemp->m_hDocWnd); // Sends WM_PAINT message
+
+ // Ensable InsertObject menu choice
+ EnableMenuItem( lpTemp->m_hEditMenu, 0, MF_BYPOSITION | MF_ENABLED);
+
+ // we will add one ref count on our document. later in CSimpleDoc::Close
+ // we will release this ref count. when the document's ref count goes
+ // to 0, the document will be deleted.
+ lpTemp->AddRef();
+
+ return (lpTemp);
+
+error:
+ delete (lpTemp);
+ return NULL;
+
+}
+
+//**********************************************************************
+//
+// CSimpleDoc::Close
+//
+// Purpose:
+//
+// Close CSimpleDoc object.
+// when the document's reference count goes to 0, the document
+// will be destroyed.
+//
+// Parameters:
+// None
+//
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// CSimpleSite::CloseOleObject SITE.CPP
+// ShowWindow Windows API
+// TestDebugOut Windows API
+//
+//
+//********************************************************************
+
+void CSimpleDoc::Close(void)
+{
+ TestDebugOut(TEXT("In CSimpleDoc::Close\r\n"));
+
+ ShowWindow(m_hDocWnd, SW_HIDE); // Hide the window
+
+ // Close the OLE object in our document
+ if (m_lpSite)
+ m_lpSite->CloseOleObject();
+
+ // Release the ref count added in CSimpleDoc::Create. this will make
+ // the document's ref count go to 0, and the document will be deleted.
+ Release();
+}
+
+//**********************************************************************
+//
+// CSimpleDoc::CSimpleDoc
+//
+// Purpose:
+//
+// Constructor for the CSimpleDoc Class
+//
+// Parameters:
+//
+// CSimpleApp FAR * lpApp - Pointer to the CSimpleApp Class
+//
+// HWND hWnd - Window Handle of "frame" window
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// GetMenu Windows API
+// GetSubMenu Windows API
+//
+//
+//********************************************************************
+
+CSimpleDoc::CSimpleDoc(CSimpleApp FAR * lpApp,HWND hWnd)
+{
+ TestDebugOut(TEXT("In CSimpleDoc's Constructor\r\n"));
+ m_lpApp = lpApp;
+ m_lpSite = NULL;
+ m_nCount = 0;
+ // set up menu handles
+ m_hMainMenu = GetMenu(hWnd);
+ m_hFileMenu = GetSubMenu(m_hMainMenu, 0);
+ m_hEditMenu = GetSubMenu(m_hMainMenu, 1);
+ m_hHelpMenu = GetSubMenu(m_hMainMenu, 2);
+ m_hCascadeMenu = NULL;
+
+ m_lpActiveObject = NULL;
+
+ // flags
+ m_fInPlaceActive = FALSE;
+ m_fAddMyUI = FALSE;
+ m_fModifiedMenu = FALSE;
+}
+
+//**********************************************************************
+//
+// CSimpleDoc::~CSimpleDoc
+//
+// Purpose:
+//
+// Destructor for CSimpleDoc
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// CSimpleSite::UnloadOleObject SITE.CPP
+// CSimpleSite::Release SITE.CPP
+// IStorage::Release OLE API
+// GetMenuItemCount Windows API
+// RemoveMenu Windows API
+// DestroyMenu Windows API
+// DestroyWindows Windows API
+//
+//
+//********************************************************************
+
+CSimpleDoc::~CSimpleDoc()
+{
+ TestDebugOut(TEXT("In CSimpleDoc's Destructor\r\n"));
+
+ // Release all pointers we hold to the OLE object. also release
+ // the ref count added in CSimpleSite::Create. this will make
+ // the Site's ref count go to 0, and the Site will be deleted.
+ if (m_lpSite)
+ {
+ m_lpSite->UnloadOleObject();
+ m_lpSite->Release();
+ m_lpSite = NULL;
+ }
+
+ // Release the Storage
+ if (m_lpStorage)
+ {
+ m_lpStorage->Release();
+ m_lpStorage = NULL;
+ }
+
+ // if the edit menu was modified, remove the menu item and
+ // destroy the popup if it exists
+ if (m_fModifiedMenu)
+ {
+ int nCount = GetMenuItemCount(m_hEditMenu);
+ RemoveMenu(m_hEditMenu, nCount-1, MF_BYPOSITION);
+ if (m_hCascadeMenu)
+ DestroyMenu(m_hCascadeMenu);
+ }
+
+ DestroyWindow(m_hDocWnd);
+}
+
+
+//**********************************************************************
+//
+// CSimpleDoc::QueryInterface
+//
+// Purpose:
+//
+// interface negotiation at document level
+//
+// Parameters:
+//
+// REFIID riid - ID of interface to be returned
+// LPVOID FAR* ppvObj - Location to return the interface
+//
+// Return Value:
+//
+// E_NOINTERFACE - Always
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// ResultFromScode OLE API
+//
+// Comments:
+//
+// In this implementation, there are no doc level interfaces.
+// In an MDI application, there would be an IOleInPlaceUIWindow
+// associated with the document to provide document level tool
+// space negotiation.
+//
+//********************************************************************
+
+STDMETHODIMP CSimpleDoc::QueryInterface(REFIID riid, LPVOID FAR* ppvObj)
+{
+ TestDebugOut(TEXT("In CSimpleDoc::QueryInterface\r\n"));
+
+ *ppvObj = NULL; // must set out pointer parameters to NULL
+
+ // Not a supported interface
+ return ResultFromScode(E_NOINTERFACE);
+}
+
+//**********************************************************************
+//
+// CSimpleDoc::AddRef
+//
+// Purpose:
+//
+// Increments the document reference count
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// UINT - The new reference count of CSimpleDoc
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) CSimpleDoc::AddRef()
+{
+ TestDebugOut(TEXT("In CSimpleDoc::AddRef\r\n"));
+ return ++m_nCount;
+}
+
+//**********************************************************************
+//
+// CSimpleDoc::Release
+//
+// Purpose:
+//
+// Decrements the document reference count
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// UINT - The new reference count of CSimpleDoc
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) CSimpleDoc::Release()
+{
+ TestDebugOut(TEXT("In CSimpleDoc::Release\r\n"));
+
+ if (--m_nCount == 0)
+ {
+ delete this;
+ return 0;
+ }
+ return m_nCount;
+}
+
+//**********************************************************************
+//
+// CSimpleDoc::InsertObject
+//
+// Purpose:
+//
+// Inserts a new object to this document
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// CSimpleSite::CSimpleSite SITE.CPP
+// CSimpleSite::InitObject SITE.CPP
+// CSimpleSite::Release SITE.CPP
+// memset C Runtime
+// OleUIInsertObject OLE2UI function
+// CSimpleDoc::DisableInsertObject DOC.CPP
+// IStorage::Revert OLE API
+//
+// Comments:
+//
+// This implementation only allows one object to be inserted
+// into a document. Once the object has been inserted, then
+// the Insert Object menu choice is greyed out, to prevent
+// the user from inserting another.
+//
+//********************************************************************
+
+void CSimpleDoc::InsertObject()
+{
+ OLEUIINSERTOBJECT io;
+ UINT iret;
+ TCHAR szFile[OLEUI_CCHPATHMAX];
+
+ m_lpSite = CSimpleSite::Create(this);
+
+ if (!m_lpSite)
+ {
+ /* memory allocation problem! cannot carry on.
+ */
+ TestDebugOut(TEXT("Memory allocation error!\n"));
+ return;
+ }
+
+ // clear the structure
+ _fmemset(&io, 0, sizeof(OLEUIINSERTOBJECT));
+
+ // fill the structure
+ io.cbStruct = sizeof(OLEUIINSERTOBJECT);
+ io.dwFlags = IOF_SELECTCREATENEW | IOF_DISABLELINK |
+ IOF_DISABLEDISPLAYASICON | IOF_CREATENEWOBJECT |
+ IOF_CREATEFILEOBJECT;
+ io.hWndOwner = m_hDocWnd;
+ io.lpszCaption = (LPTSTR) TEXT("Insert Object");
+ io.iid = IID_IOleObject;
+ io.oleRender = OLERENDER_DRAW;
+ io.lpIOleClientSite = &m_lpSite->m_OleClientSite;
+ io.lpIStorage = m_lpSite->m_lpObjStorage;
+ io.ppvObj = (LPVOID FAR *)&m_lpSite->m_lpOleObject;
+ io.lpszFile = szFile;
+ io.cchFile = sizeof(szFile)/sizeof(TCHAR);
+ // cchFile is the number of characters of szFile
+ _fmemset((LPTSTR)szFile, 0, sizeof(szFile));
+
+ // call OUTLUI to do all the hard work
+ iret = OleUIInsertObject(&io);
+
+ if (iret == OLEUI_OK)
+ {
+ m_lpSite->InitObject((BOOL)(io.dwFlags & IOF_SELECTCREATENEW));
+ // disable Insert Object menu item
+ DisableInsertObject();
+ }
+ else
+ {
+ m_lpSite->Release();
+ m_lpSite = NULL;
+ m_lpStorage->Revert();
+ }
+
+}
+
+//**********************************************************************
+//
+// CSimpleDoc::lResizeDoc
+//
+// Purpose:
+//
+// Resizes the document
+//
+// Parameters:
+//
+// LPRECT lpRect - The size of the client are of the "frame"
+// Window.
+//
+// Return Value:
+//
+// NULL
+//
+// Function Calls:
+// Function Location
+//
+// IOleInPlaceActiveObject::ResizeBorder Object
+// MoveWindow Windows API
+//
+//
+//********************************************************************
+
+long CSimpleDoc::lResizeDoc(LPRECT lpRect)
+{
+ // if we are InPlace, then call ResizeBorder on the object, otherwise
+ // just move the document window.
+ if (m_fInPlaceActive)
+ m_lpActiveObject->ResizeBorder(lpRect, &m_lpApp->m_OleInPlaceFrame,
+ TRUE);
+ else
+ MoveWindow(m_hDocWnd, lpRect->left, lpRect->top, lpRect->right,
+ lpRect->bottom, TRUE);
+
+ return NULL;
+}
+
+//**********************************************************************
+//
+// CSimpleDoc::lAddVerbs
+//
+// Purpose:
+//
+// Adds the objects verbs to the edit menu.
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// NULL
+//
+// Function Calls:
+// Function Location
+//
+// GetMenuItemCount Windows API
+// OleUIAddVerbMenu OLE2UI function
+//
+//
+//********************************************************************
+
+long CSimpleDoc::lAddVerbs(void)
+{
+ // m_fModifiedMenu is TRUE if the menu has already been modified
+ // once. Since we only support one obect every time the application
+ // is run, then once the menu is modified, it doesn't have
+ // to be done again.
+ if (m_lpSite && !m_fInPlaceActive && !m_fModifiedMenu)
+ {
+ int nCount = GetMenuItemCount(m_hEditMenu);
+
+ if (!OleUIAddVerbMenu ( m_lpSite->m_lpOleObject,
+ NULL,
+ m_hEditMenu,
+ nCount + 1,
+ IDM_VERB0,
+ 0, // no maximum verb IDM enforced
+ FALSE,
+ 0,
+ &m_hCascadeMenu))
+ {
+ TestDebugOut(TEXT("Fail in OleUIAddVerbMenu"));
+ }
+
+ m_fModifiedMenu = TRUE;
+ }
+ return (NULL);
+}
+
+//**********************************************************************
+//
+// CSimpleDoc::PaintDoc
+//
+// Purpose:
+//
+// Paints the Document
+//
+// Parameters:
+//
+// HDC hDC - hDC of the document Window
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// CSimpleSite::PaintObj SITE.CPP
+//
+//
+//********************************************************************
+
+void CSimpleDoc::PaintDoc (HDC hDC)
+{
+ // if we supported multiple objects, then we would enumerate
+ // the objects and call paint on each of them from here.
+
+ if (m_lpSite)
+ m_lpSite->PaintObj(hDC);
+
+}
+
+//**********************************************************************
+//
+// CSimpleDoc::DisableInsertObject
+//
+// Purpose:
+//
+// Disable the ability to insert a new object in this document.
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// EnableMenuItem Windows API
+//
+// Comments:
+//
+// This implementation only allows one object to be inserted
+// into a document. Once the object has been inserted, then
+// the Insert Object menu choice is greyed out, to prevent
+// the user from inserting another.
+//
+//********************************************************************
+
+void CSimpleDoc::DisableInsertObject(void)
+{
+ // Disable InsertObject menu choice
+ EnableMenuItem( m_hEditMenu, 0, MF_BYPOSITION | MF_DISABLED | MF_GRAYED);
+}
diff --git a/private/oleutest/simpcntr/doc.h b/private/oleutest/simpcntr/doc.h
new file mode 100644
index 000000000..40aab5d1a
--- /dev/null
+++ b/private/oleutest/simpcntr/doc.h
@@ -0,0 +1,55 @@
+//**********************************************************************
+// File name: doc.h
+//
+// Definition of CSimpleDoc
+//
+// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+
+#if !defined( _DOC_H_ )
+#define _DOC_H_
+
+class CSimpleSite;
+class CSimpleApp;
+
+class CSimpleDoc : public IUnknown
+{
+public:
+ int m_nCount;
+ LPSTORAGE m_lpStorage;
+ HMENU m_hMainMenu;
+ HMENU m_hFileMenu;
+ HMENU m_hEditMenu;
+ HMENU m_hHelpMenu;
+ HMENU m_hCascadeMenu;
+ LPOLEINPLACEACTIVEOBJECT m_lpActiveObject;
+ BOOL m_fInPlaceActive;
+ BOOL m_fAddMyUI;
+ BOOL m_fModifiedMenu;
+
+ CSimpleSite FAR * m_lpSite;
+ CSimpleApp FAR * m_lpApp;
+
+ HWND m_hDocWnd;
+
+ static CSimpleDoc FAR * Create(CSimpleApp FAR *lpApp, LPRECT lpRect,HWND hWnd);
+
+ void Close(void);
+
+ CSimpleDoc();
+ CSimpleDoc(CSimpleApp FAR *lpApp, HWND hWnd);
+ ~CSimpleDoc();
+
+ // IUnknown Interface
+ STDMETHODIMP QueryInterface(REFIID riid, LPVOID FAR* ppvObj);
+ STDMETHODIMP_(ULONG) AddRef();
+ STDMETHODIMP_(ULONG) Release();
+
+ void InsertObject(void);
+ void DisableInsertObject(void);
+ long lResizeDoc(LPRECT lpRect);
+ long lAddVerbs(void);
+ void PaintDoc(HDC hDC);
+};
+
+#endif
diff --git a/private/oleutest/simpcntr/ias.cpp b/private/oleutest/simpcntr/ias.cpp
new file mode 100644
index 000000000..749bdef7b
--- /dev/null
+++ b/private/oleutest/simpcntr/ias.cpp
@@ -0,0 +1,304 @@
+//**********************************************************************
+// File name: IAS.CPP
+//
+// Implementation file of CAdviseSink
+//
+//
+// Functions:
+//
+// See IAS.H for Class Definition
+//
+// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+
+#include "pre.h"
+#include "iocs.h"
+#include "ias.h"
+#include "ioipf.h"
+#include "ioips.h"
+#include "app.h"
+#include "site.h"
+#include "doc.h"
+
+//**********************************************************************
+//
+// CAdviseSink::QueryInterface
+//
+// Purpose:
+//
+// used for interface negotiation
+//
+// Parameters:
+//
+// REFIID riid - The requested interface
+//
+// LPVOID FAR* ppvObj - Place to return the interface
+//
+// Return Value:
+//
+// HRESULT from CSimpleSite::QueryInterface
+//
+// Function Calls:
+// Function Location
+//
+// CSimpleSite::QueryInterface SITE.CPP
+// TestDebugOut Windows API
+//
+// Comments:
+//
+// This function simply delegates to the Object class, which is
+// aware of the supported interfaces.
+//
+//********************************************************************
+
+STDMETHODIMP CAdviseSink::QueryInterface(REFIID riid, LPVOID FAR* ppvObj)
+{
+ TestDebugOut(TEXT("In IAS::QueryInterface\r\n"));
+
+ // delegate to the document Object
+ return m_pSite->QueryInterface(riid, ppvObj);
+}
+
+//**********************************************************************
+//
+// CAdviseSink::AddRef
+//
+// Purpose:
+//
+// Increments the reference count of CSimpleSite. Since CAdviseSink is
+// a nested class of CSimpleSite, we don't need to have a separate
+// reference count for CAdviseSink. We can safely use the reference
+// count of CSimpleSite.
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// The new reference count of CSimpleSite
+//
+// Function Calls:
+// Function Location
+//
+// CSimpleSite::AddReff SITE.CPP
+// TestDebugOut Windows API
+//
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) CAdviseSink::AddRef()
+{
+ TestDebugOut(TEXT("In IAS::AddRef\r\n"));
+
+ // delegate to the container Site
+ return m_pSite->AddRef();
+}
+
+//**********************************************************************
+//
+// CAdviseSink::Release
+//
+// Purpose:
+//
+// Decrements the reference count of CSimpleSite. Since CAdviseSink is
+// a nested class of CSimpleSite, we don't need to have a separate
+// reference count for CAdviseSink. We can safely use the reference
+// count of CSimpleSite.
+//
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// The new reference count of CSimpleSite
+//
+// Function Calls:
+// Function Location
+//
+// CSimpleSite::Release SITE.CPP
+// TestDebugOut Windows API
+//
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) CAdviseSink::Release()
+{
+ TestDebugOut(TEXT("In IAS::Release\r\n"));
+
+ // delegate to the container Site
+ return m_pSite->Release();
+}
+
+//**********************************************************************
+//
+// CAdviseSink::OnDataChange
+//
+// Purpose:
+//
+// Not Implemented (needs to be stubbed out)
+//
+// Parameters:
+//
+// FORMATETC pFormatetc - data format info that was originally set up
+// STGMEDIUM pStgmed - storage medium which data is passed
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+//
+//********************************************************************
+
+STDMETHODIMP_(void) CAdviseSink::OnDataChange (FORMATETC FAR* pFormatetc,
+ STGMEDIUM FAR* pStgmed)
+{
+ TestDebugOut(TEXT("In IAS::OnDataChange\r\n"));
+}
+
+//**********************************************************************
+//
+// CAdviseSink::OnViewChange
+//
+// Purpose:
+//
+// Notifies us that the view has changed and needs to be updated.
+//
+// Parameters:
+//
+// DWORD dwAspect - Aspect that has changed
+//
+// LONG lindex - Index that has changed
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// InvalidateRect Windows API
+// IOleObject::QueryInterface Object
+// IViewObject2::GetExtent Object
+// IViewObject2::Release Object
+//
+//
+//********************************************************************
+
+STDMETHODIMP_(void) CAdviseSink::OnViewChange (DWORD dwAspect, LONG lindex)
+{
+ LPVIEWOBJECT2 lpViewObject2;
+
+ TestDebugOut(TEXT("In IAS::OnViewChange\r\n"));
+
+ // get a pointer to IViewObject2
+ HRESULT hErr = m_pSite->m_lpOleObject->QueryInterface(
+ IID_IViewObject2,(LPVOID FAR *)&lpViewObject2);
+
+ if (hErr == NOERROR)
+ {
+ // get extent of the object
+ // NOTE: this method will never be remoted; it can be called w/i
+ // this async method
+ lpViewObject2->GetExtent(DVASPECT_CONTENT, -1 , NULL,
+ &m_pSite->m_sizel);
+ lpViewObject2->Release();
+ }
+
+ InvalidateRect(m_pSite->m_lpDoc->m_hDocWnd, NULL, TRUE);
+}
+
+//**********************************************************************
+//
+// CAdviseSink::OnRename
+//
+// Purpose:
+//
+// Not Implemented (needs to be stubbed out)
+//
+// Parameters:
+//
+// LPMONIKER pmk - new name of the object
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+//
+//********************************************************************
+
+STDMETHODIMP_(void) CAdviseSink::OnRename (LPMONIKER pmk)
+{
+ TestDebugOut(TEXT("In IAS::OnRename\r\n"));
+}
+
+//**********************************************************************
+//
+// CAdviseSink::OnSave
+//
+// Purpose:
+//
+// Not Implemented (needs to be stubbed out)
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+//
+//********************************************************************
+
+STDMETHODIMP_(void) CAdviseSink::OnSave ()
+{
+ TestDebugOut(TEXT("In IAS::OnSave\r\n"));
+}
+
+//**********************************************************************
+//
+// CAdviseSink::OnClose
+//
+// Purpose:
+//
+// Not Implemented (needs to be stubbed out)
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+//
+//********************************************************************
+
+STDMETHODIMP_(void) CAdviseSink::OnClose()
+{
+ TestDebugOut(TEXT("In IAS::OnClose\r\n"));
+}
diff --git a/private/oleutest/simpcntr/ias.h b/private/oleutest/simpcntr/ias.h
new file mode 100644
index 000000000..cd15e5bb3
--- /dev/null
+++ b/private/oleutest/simpcntr/ias.h
@@ -0,0 +1,44 @@
+//**********************************************************************
+// File name: IAS.H
+//
+// Definition of CAdviseSink
+//
+// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+#if !defined( _IAS_H_ )
+#define _IAS_H_
+
+#include <assert.h>
+
+class CSimpleSite;
+
+interface CAdviseSink : public IAdviseSink
+{
+ CSimpleSite FAR * m_pSite;
+
+ CAdviseSink(CSimpleSite FAR * pSite)
+ {
+ TestDebugOut(TEXT("In IAS's constructor\r\n"));
+ m_pSite = pSite;
+ };
+
+ ~CAdviseSink()
+ {
+ TestDebugOut(TEXT("In IAS's destructor\r\n"));
+ } ;
+
+ STDMETHODIMP QueryInterface (REFIID riid, LPVOID FAR* ppv);
+ STDMETHODIMP_(ULONG) AddRef ();
+ STDMETHODIMP_(ULONG) Release ();
+
+ // *** IAdviseSink methods ***
+ STDMETHODIMP_(void) OnDataChange (FORMATETC FAR* pFormatetc,
+ STGMEDIUM FAR* pStgmed);
+ STDMETHODIMP_(void) OnViewChange (DWORD dwAspect, LONG lindex);
+ STDMETHODIMP_(void) OnRename (LPMONIKER pmk);
+ STDMETHODIMP_(void) OnSave ();
+ STDMETHODIMP_(void) OnClose ();
+};
+
+
+#endif
diff --git a/private/oleutest/simpcntr/iocs.cpp b/private/oleutest/simpcntr/iocs.cpp
new file mode 100644
index 000000000..d11754290
--- /dev/null
+++ b/private/oleutest/simpcntr/iocs.cpp
@@ -0,0 +1,368 @@
+//**********************************************************************
+// File name: IOCS.CPP
+//
+// Implementation file for COleClientSite
+//
+// Functions:
+//
+// See IOCS.H for class definition
+//
+// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+
+#include "pre.h"
+#include "iocs.h"
+#include "ias.h"
+#include "ioipf.h"
+#include "ioips.h"
+#include "app.h"
+#include "site.h"
+#include "doc.h"
+
+
+//**********************************************************************
+//
+// COleClientSite::QueryInterface
+//
+// Purpose:
+//
+// Used for interface negotiation
+//
+// Parameters:
+//
+// REFIID riid - A reference to the interface that is
+// being queried.
+//
+// LPVOID FAR* ppvObj - An out parameter to return a pointer to
+// the interface.
+//
+// Return Value:
+//
+// S_OK - The interface is supported.
+// E_NOINTERFACE - The interface is not supported
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// CSimpleSite::QueryInterface SITE.CPP
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleClientSite::QueryInterface(REFIID riid, LPVOID FAR* ppvObj)
+{
+ TestDebugOut(TEXT("In IOCS::QueryInterface\r\n"));
+
+ // delegate to the container Site
+ return m_pSite->QueryInterface(riid, ppvObj);
+}
+
+//**********************************************************************
+//
+// COleClientSite::AddRef
+//
+// Purpose:
+//
+// Increments the reference count of CSimpleSite. Since COleClientSite
+// is a nested class of CSimpleSite, we don't need to have a separate
+// reference count for COleClientSite. We can safely use the reference
+// count of CSimpleSite.
+//
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// ULONG - The new reference count of CSimpleSite
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// CSimpleSite::AddRef SITE.CPP
+//
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) COleClientSite::AddRef()
+{
+ TestDebugOut(TEXT("In IOCS::AddRef\r\n"));
+
+ // delegate to the container Site
+ return m_pSite->AddRef();
+}
+
+
+//**********************************************************************
+//
+// COleClientSite::Release
+//
+// Purpose:
+//
+// Decrements the reference count of CSimpleSite. Since COleClientSite
+// is a nested class of CSimpleSite, we don't need to have a separate
+// reference count for COleClientSite. We can safely use the reference
+// count of CSimpleSite.
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// ULONG - The new reference count of CSimpleSite
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// CSimpleSite::Release SITE.CPP
+//
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) COleClientSite::Release()
+{
+ TestDebugOut(TEXT("In IOCS::Release\r\n"));
+
+ // delegate to the container Site
+ return m_pSite->Release();
+}
+
+//**********************************************************************
+//
+// COleClientSite::SaveObject
+//
+// Purpose:
+//
+// Called by the object when it wants to be saved to persistant
+// storage
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// IOleObject::QueryInterface Object
+// IPersistStorage::SaveCompleted Object
+// IPersistStorage::Release Object
+// OleSave OLE API
+// GetScode OLE API
+// ResultFromScode OLE API
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleClientSite::SaveObject()
+{
+ LPPERSISTSTORAGE lpPS;
+ SCODE sc = E_FAIL;
+
+ TestDebugOut(TEXT("In IOCS::SaveObject\r\n"));
+
+ // get a pointer to IPersistStorage
+ HRESULT hErr = m_pSite->m_lpOleObject->QueryInterface(IID_IPersistStorage,
+ (LPVOID FAR *)&lpPS);
+
+ // save the object
+ if (hErr == NOERROR)
+ {
+ sc = GetScode( OleSave(lpPS, m_pSite->m_lpObjStorage, TRUE) );
+ lpPS->SaveCompleted(NULL);
+ lpPS->Release();
+ }
+
+ return ResultFromScode(sc);
+}
+
+//**********************************************************************
+//
+// COleClientSite::GetMoniker
+//
+// Purpose:
+//
+// Not Implemented
+//
+// Parameters:
+//
+// DWORD dwAssign - type of moniker to return
+// DWORD dwWhichMoniker - which moniker to return
+//
+// Return Value:
+// E_NOTIMPL
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// ResultFromScode OLE API
+//
+// Comments:
+//
+// This function is not implemented because we don't support
+// linking.
+//
+//********************************************************************
+
+STDMETHODIMP COleClientSite::GetMoniker(DWORD dwAssign, DWORD dwWhichMoniker, LPMONIKER FAR* ppmk)
+{
+ TestDebugOut(TEXT("In IOCS::GetMoniker\r\n"));
+
+ // need to null the out pointer
+ *ppmk = NULL;
+
+ return ResultFromScode(E_NOTIMPL);
+}
+
+//**********************************************************************
+//
+// COleClientSite::GetContainer
+//
+// Purpose:
+//
+// Not Implemented
+//
+// Parameters:
+//
+// LPOLECONTAINER FAR * ppContainer - where IOleContainer interface
+// pointer to be returned
+//
+// Return Value:
+//
+// E_NOTIMPL
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleClientSite::GetContainer(LPOLECONTAINER FAR* ppContainer)
+{
+ TestDebugOut(TEXT("In IOCS::GetContainer\r\n"));
+
+ // NULL the out pointer
+ *ppContainer = NULL;
+
+ return ResultFromScode(E_NOTIMPL);
+}
+
+//**********************************************************************
+//
+// COleClientSite::ShowObject
+//
+// Purpose:
+//
+// Not Implemented
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// NOERROR
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+// Comments:
+//
+// This function is not implemented because we don't support
+// linking.
+//
+//********************************************************************
+
+STDMETHODIMP COleClientSite::ShowObject()
+{
+ TestDebugOut(TEXT("In IOCS::ShowObject\r\n"));
+ return NOERROR;
+}
+
+//**********************************************************************
+//
+// COleClientSite::OnShowWindow
+//
+// Purpose:
+//
+// Object calls this method when it is opening/closing non-InPlace
+// Window
+//
+// Parameters:
+//
+// BOOL fShow - TRUE if Window is opening, FALSE if closing
+//
+// Return Value:
+//
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// InvalidateRect Windows API
+// BringWindowToTop Windows API
+// SetFocus Windows API
+// ResultFromScode OLE API
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleClientSite::OnShowWindow(BOOL fShow)
+{
+ TestDebugOut(TEXT("In IOCS::OnShowWindow\r\n"));
+ m_pSite->m_fObjectOpen = fShow;
+ InvalidateRect(m_pSite->m_lpDoc->m_hDocWnd, NULL, TRUE);
+
+ // if object window is closing, then bring container window to top
+ if (! fShow)
+ {
+ BringWindowToTop(m_pSite->m_lpDoc->m_hDocWnd);
+ SetFocus(m_pSite->m_lpDoc->m_hDocWnd);
+ }
+ return ResultFromScode(S_OK);
+}
+
+//**********************************************************************
+//
+// COleClientSite::RequestNewObjectLayout
+//
+// Purpose:
+//
+// Not Implemented
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// E_NOTIMPL
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleClientSite::RequestNewObjectLayout()
+{
+ TestDebugOut(TEXT("In IOCS::RequestNewObjectLayout\r\n"));
+ return ResultFromScode(E_NOTIMPL);
+}
diff --git a/private/oleutest/simpcntr/iocs.h b/private/oleutest/simpcntr/iocs.h
new file mode 100644
index 000000000..1bd9f66b5
--- /dev/null
+++ b/private/oleutest/simpcntr/iocs.h
@@ -0,0 +1,44 @@
+//**********************************************************************
+// File name: IOCS.H
+//
+// Definition of COleClientSite
+//
+// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+#if !defined( _IOCS_H_ )
+#define _IOCS_H_
+
+#include <assert.h>
+
+class CSimpleSite;
+
+interface COleClientSite : public IOleClientSite
+{
+ CSimpleSite FAR * m_pSite;
+
+ COleClientSite(CSimpleSite FAR * pSite)
+ {
+ TestDebugOut(TEXT("In IOCS's constructor\r\n"));
+ m_pSite = pSite;
+ }
+
+ ~COleClientSite()
+ {
+ TestDebugOut(TEXT("In IOCS's destructor\r\n"));
+ }
+
+ STDMETHODIMP QueryInterface(REFIID riid, LPVOID FAR* ppvObj);
+ STDMETHODIMP_(ULONG) AddRef();
+ STDMETHODIMP_(ULONG) Release();
+
+ // *** IOleClientSite methods ***
+ STDMETHODIMP SaveObject();
+ STDMETHODIMP GetMoniker(DWORD dwAssign, DWORD dwWhichMoniker,
+ LPMONIKER FAR* ppmk);
+ STDMETHODIMP GetContainer(LPOLECONTAINER FAR* ppContainer);
+ STDMETHODIMP ShowObject();
+ STDMETHODIMP OnShowWindow(BOOL fShow);
+ STDMETHODIMP RequestNewObjectLayout();
+};
+
+#endif
diff --git a/private/oleutest/simpcntr/ioipf.cpp b/private/oleutest/simpcntr/ioipf.cpp
new file mode 100644
index 000000000..ca4a0d9af
--- /dev/null
+++ b/private/oleutest/simpcntr/ioipf.cpp
@@ -0,0 +1,641 @@
+//**********************************************************************
+// File name: IOIPF.CPP
+//
+// Implementation file for COleInPlaceFrame
+//
+// Functions:
+//
+// See IOIPF.H for class definition
+//
+// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+
+#include "pre.h"
+#include "iocs.h"
+#include "ias.h"
+#include "ioipf.h"
+#include "ioips.h"
+#include "app.h"
+#include "site.h"
+#include "doc.h"
+
+
+//**********************************************************************
+//
+// COleInPlaceFrame::QueryInterface
+//
+// Purpose:
+//
+// Used for interface negotiation
+//
+// Parameters:
+//
+// REFIID riid - A reference to the interface that is
+// being queried.
+//
+// LPVOID FAR* ppvObj - An out parameter to return a pointer to
+// the interface.
+//
+// Return Value:
+//
+// S_OK - The interface is supported.
+// E_NOINTERFACE - The interface is not supported
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// CSimpleApp::QueryInterface APP.CPP
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleInPlaceFrame::QueryInterface(REFIID riid, LPVOID FAR* ppvObj)
+{
+ TestDebugOut(TEXT("In IOIPF::QueryInterface\r\n"));
+
+ // delegate to the application Object
+ return m_pApp->QueryInterface(riid, ppvObj);
+}
+
+//**********************************************************************
+//
+// COleInPlaceFrame::AddRef
+//
+// Purpose:
+//
+// Increments the reference count of the CSimpleApp. Since
+// COleInPlaceFrame is a nested class of CSimpleApp, we don't need an
+// extra reference count for COleInPlaceFrame. We can safely use the
+// reference count of CSimpleApp.
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// ULONG - The new reference count of the CSimpleApp
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// CSimpleApp::AddRef APP.CPP
+//
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) COleInPlaceFrame::AddRef()
+{
+ TestDebugOut(TEXT("In IOIPF::AddRef\r\n"));
+
+ // delegate to the application Object
+ return m_pApp->AddRef();
+}
+
+//**********************************************************************
+//
+// COleInPlaceFrame::Release
+//
+// Purpose:
+//
+// Decrements the reference count of the CSimpleApp. Since
+// COleInPlaceFrame is a nested class of CSimpleApp, we don't need an
+// extra reference count for COleInPlaceFrame. We can safely use the
+// reference count of CSimpleApp.
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// ULONG - The new reference count of CSimpleApp.
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// CSimpleApp::Release APP.CPP
+//
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) COleInPlaceFrame::Release()
+{
+ TestDebugOut(TEXT("In IOIPF::Release\r\n"));
+
+ // delegate to the document object
+ return m_pApp->Release();
+
+}
+
+//**********************************************************************
+//
+// COleInPlaceFrame::GetWindow
+//
+// Purpose:
+//
+// Returns the frame window handle
+//
+// Parameters:
+//
+// HWND FAR* lphwnd - Location to return the window handle
+//
+// Return Value:
+//
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// ResultFromScode OLE API
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleInPlaceFrame::GetWindow (HWND FAR* lphwnd)
+{
+ TestDebugOut(TEXT("In IOIPF::GetWindow\r\n"));
+ *lphwnd = m_pApp->m_hAppWnd;
+ return ResultFromScode(S_OK);
+}
+
+//**********************************************************************
+//
+// COleInPlaceFrame::ContextSensitiveHelp
+//
+// Purpose:
+//
+// Used in implementing Context sensitive help
+//
+// Parameters:
+//
+// BOOL fEnterMode - TRUE if starting Context Sensitive help mode
+//
+// Return Value:
+//
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// ResultFromScode OLE API
+//
+// Comments:
+//
+// Be sure to read the technotes in the OLE toolkit.
+//
+//********************************************************************
+
+STDMETHODIMP COleInPlaceFrame::ContextSensitiveHelp (BOOL fEnterMode)
+{
+ TestDebugOut(TEXT("In IOIPF::ContextSensitiveHelp\r\n"));
+
+ m_pApp->m_fMenuMode = fEnterMode;
+
+ return ResultFromScode(S_OK);
+}
+//**********************************************************************
+//
+// COleInPlaceFrame::GetBorder
+//
+// Purpose:
+//
+// Returns the outermost border that frame adornments can be attached
+// during InPlace Activation.
+//
+// Parameters:
+//
+// LPRECT lprectBorder - return parameter to contain the outermost
+// rect for frame adornments
+//
+// Return Value:
+//
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// GetClientRect Windows API
+// CopyRect Windows API
+// ResultFromScode OLE API
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleInPlaceFrame::GetBorder (LPRECT lprectBorder)
+{
+ RECT rect;
+
+ TestDebugOut(TEXT("In IOIPF::GetBorder\r\n"));
+
+ // get the rect for the entire frame.
+ GetClientRect(m_pApp->m_hAppWnd, &rect);
+
+ CopyRect(lprectBorder, &rect);
+
+ return ResultFromScode(S_OK);
+}
+
+//**********************************************************************
+//
+// COleInPlaceFrame::RequestBorderSpace
+//
+// Purpose:
+//
+// Approves/Denies requests for border space during InPlace
+// negotiation.
+//
+// Parameters:
+//
+// LPCBORDERWIDTHS lpborderwidths - The width in pixels needed on
+// each side of the frame.
+//
+// Return Value:
+//
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// ResultFromScode OLE API
+//
+// Comments:
+//
+// This implementation doesn't care about how much border space
+// is used. It always returns S_OK.
+//
+//********************************************************************
+
+STDMETHODIMP COleInPlaceFrame::RequestBorderSpace (LPCBORDERWIDTHS
+ lpborderwidths)
+{
+ TestDebugOut(TEXT("In IOIPF::RequestBorderSpace\r\n"));
+
+ // always approve the request
+ return ResultFromScode(S_OK);
+}
+
+//**********************************************************************
+//
+// COleInPlaceFrame::SetBorderSpace
+//
+// Purpose:
+//
+// The object calls this method when it is actually going to
+// start using the border space.
+//
+// Parameters:
+//
+// LPCBORDERWIDTHS lpborderwidths - Border space actually being used
+// by the object
+//
+// Return Value:
+//
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// CSimpleApp::AddFrameLevelTools APP.CPP
+// TestDebugOut Windows API
+// GetClientRect Windows API
+// MoveWindow Windows API
+// ResultFromScode Windows API
+//
+// Comments:
+//
+// This routine could be a little smarter and check to see if
+// the object is requesting the entire client area of the
+// window.
+//
+//********************************************************************
+
+STDMETHODIMP COleInPlaceFrame::SetBorderSpace (LPCBORDERWIDTHS lpborderwidths)
+{
+
+ TestDebugOut(TEXT("In IOIPF::SetBorderSpace\r\n"));
+
+ if (lpborderwidths == NULL)
+ m_pApp->AddFrameLevelTools();
+ else
+ {
+ RECT rect;
+
+ GetClientRect(m_pApp->m_hAppWnd, &rect);
+
+ MoveWindow( m_pApp->m_lpDoc->m_hDocWnd,
+ rect.left + lpborderwidths->left,
+ rect.top + lpborderwidths->top,
+ rect.right - lpborderwidths->right - lpborderwidths->left,
+ rect.bottom - lpborderwidths->bottom - lpborderwidths->top,
+ TRUE);
+ }
+ return ResultFromScode(S_OK);
+}
+
+//**********************************************************************
+//
+// COleInPlaceFrame::SetActiveObject
+//
+// Purpose:
+// install the object being activated in-place
+//
+//
+// Parameters:
+//
+// LPOLEINPLACEACTIVEOBJECT lpActiveObject - Pointer to the
+// objects
+// IOleInPlaceActiveObject
+// interface
+//
+// LPCOLESTR lpszObjName - Name of the object
+//
+// Return Value:
+//
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// IOleInPlaceActiveObject::AddRef Object
+// IOleInPlaceActiveObject::Release Object
+// ResultFromScode OLE API
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleInPlaceFrame::SetActiveObject (LPOLEINPLACEACTIVEOBJECT
+ lpActiveObject, LPCOLESTR lpszObjName)
+{
+
+ TestDebugOut(TEXT("In IOIPF::SetActiveObject\r\n"));
+
+ // AddRef() it and save it...
+ if (lpActiveObject)
+ {
+ lpActiveObject->AddRef();
+
+ lpActiveObject->GetWindow(&m_pApp->m_hwndUIActiveObj);
+ if (m_pApp->m_hwndUIActiveObj)
+ SendMessage(m_pApp->m_hwndUIActiveObj, WM_QUERYNEWPALETTE, 0, 0L);
+ }
+ else
+ {
+ if (m_pApp->m_lpDoc->m_lpActiveObject)
+ m_pApp->m_lpDoc->m_lpActiveObject->Release();
+ m_pApp->m_hwndUIActiveObj = NULL;
+ }
+
+ // in an MDI app, this method really shouldn't be called,
+ // this method associated with the doc is called instead.
+
+ m_pApp->m_lpDoc->m_lpActiveObject = lpActiveObject;
+ // should set window title here
+
+ return ResultFromScode(S_OK);
+}
+
+//**********************************************************************
+//
+// COleInPlaceFrame::InsertMenus
+//
+// Purpose:
+//
+// Inserts the container menu into the combined menu
+//
+// Parameters:
+//
+// HMENU hmenuShared - Menu Handle to be set.
+// LPOLEMENUGROUPWIDTHS lpMenuWidths - Width of menus
+//
+// Return Value:
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// AppendMenu Windows API
+// ResultFromScode OLE API
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleInPlaceFrame::InsertMenus (HMENU hmenuShared,
+ LPOLEMENUGROUPWIDTHS lpMenuWidths)
+{
+ TestDebugOut(TEXT("In IOIPF::InsertMenus\r\n"));
+
+ AppendMenu(hmenuShared, MF_BYPOSITION | MF_POPUP,
+ (UINT) m_pApp->m_lpDoc->m_hFileMenu, TEXT("&File"));
+ AppendMenu(hmenuShared, MF_BYPOSITION | MF_POPUP,
+ (UINT) m_pApp->m_lpDoc->m_hHelpMenu, TEXT("&Other"));
+
+ lpMenuWidths->width[0] = 1;
+ lpMenuWidths->width[2] = 0;
+ lpMenuWidths->width[4] = 1;
+
+ return ResultFromScode(S_OK);
+}
+
+
+//**********************************************************************
+//
+// COleInPlaceFrame::SetMenu
+//
+// Purpose:
+//
+// Sets the application menu to the combined menu
+//
+// Parameters:
+//
+// HMENU hmenuShared - The combined menu
+//
+// HOLEMENU holemenu - Used by OLE
+//
+// HWND hwndActiveObject - Used by OLE
+//
+// Return Value:
+//
+// S_OK - if menu was correctly installed
+// E_FAIL - otherwise
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// SetMenu Windows API
+// OleSetMenuDescriptor OLE API
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleInPlaceFrame::SetMenu (HMENU hmenuShared, HOLEMENU holemenu,
+ HWND hwndActiveObject)
+{
+
+ TestDebugOut(TEXT("In IOIPF::SetMenu\r\n"));
+
+ HMENU hMenu = m_pApp->m_lpDoc->m_hMainMenu;
+
+ if (holemenu)
+ hMenu = hmenuShared;
+
+ // call the windows api, not this method
+ ::SetMenu (m_pApp->m_hAppWnd, hMenu);
+
+ HRESULT hRes = OleSetMenuDescriptor(holemenu, m_pApp->m_hAppWnd,
+ hwndActiveObject, this,
+ m_pApp->m_lpDoc->m_lpActiveObject);
+
+ return hRes;
+}
+
+
+//**********************************************************************
+//
+// COleInPlaceFrame::RemoveMenus
+//
+// Purpose:
+//
+// Removes the container menus from the combined menu
+//
+// Parameters:
+//
+// HMENU hmenuShared - Handle to the combined menu.
+//
+// Return Value:
+//
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// GetMenuItemCount Windows API
+// RemoveMenu Windows API
+// ResultFromScode OLE API
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleInPlaceFrame::RemoveMenus (HMENU hmenuShared)
+{
+ int retval;
+
+ TestDebugOut(TEXT("In IOIPF::RemoveMenus\r\n"));
+
+ while ((retval = GetMenuItemCount(hmenuShared)) && (retval != -1))
+ RemoveMenu(hmenuShared, 0, MF_BYPOSITION);
+
+ return ResultFromScode(S_OK);
+}
+
+//**********************************************************************
+//
+// COleInPlaceFrame::SetStatusText
+//
+// Purpose:
+//
+// Not Implemented
+//
+// Parameters:
+//
+// LPCOLESTR lpszStatusText - character string containing the message
+//
+// Return Value:
+//
+// E_FAIL
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+// Comments:
+//
+// This function is not implemented due to the fact
+// that this application does not have a status bar.
+//
+//********************************************************************
+
+STDMETHODIMP COleInPlaceFrame::SetStatusText (LPCOLESTR lpszStatusText)
+{
+ TestDebugOut(TEXT("In IOIPF::SetStatusText\r\n"));
+ return ResultFromScode(E_FAIL);
+}
+
+//**********************************************************************
+//
+// COleInPlaceFrame::EnableModeless
+//
+// Purpose:
+//
+// Enables/Disables container modeless dialogs
+//
+// Parameters:
+//
+// BOOL fEnable - Enable/Disable
+//
+// Return Value:
+//
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+// Comments:
+//
+// There are no modeless dialogs in this application, so the
+// implementation of this method is trivial.
+//
+//********************************************************************
+
+STDMETHODIMP COleInPlaceFrame::EnableModeless (BOOL fEnable)
+{
+ TestDebugOut(TEXT("In IOIPF::EnableModeless\r\n"));
+ return ResultFromScode(S_OK);
+}
+
+//**********************************************************************
+//
+// COleInPlaceFrame::TranslateAccelerator
+//
+// Purpose:
+//
+// Not Implemented
+//
+// Parameters:
+//
+// LPMSG lpmsg - structure containing keystroke message
+// WORD wID - identifier value corresponding to the keystroke
+//
+// Return Value:
+//
+// S_FALSE
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleInPlaceFrame::TranslateAccelerator (LPMSG lpmsg, WORD wID)
+{
+ TestDebugOut(TEXT("In IOIPF::TranslateAccelerator\r\n"));
+ return ::TranslateAccelerator(m_pApp->m_hAppWnd, m_pApp->m_hAccel, lpmsg)
+ ? ResultFromScode(S_OK)
+ : ResultFromScode(S_FALSE);
+}
diff --git a/private/oleutest/simpcntr/ioipf.h b/private/oleutest/simpcntr/ioipf.h
new file mode 100644
index 000000000..e32edcca5
--- /dev/null
+++ b/private/oleutest/simpcntr/ioipf.h
@@ -0,0 +1,51 @@
+//**********************************************************************
+// File name: IOIPF.H
+//
+// Definition of COleInPlaceFrame
+//
+// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+#if !defined( _IOIPF_H_ )
+#define _IOIPF_H_
+
+
+class CSimpleApp;
+
+interface COleInPlaceFrame : public IOleInPlaceFrame
+{
+ CSimpleApp FAR * m_pApp;
+
+ COleInPlaceFrame(CSimpleApp FAR * pApp)
+ {
+ TestDebugOut(TEXT("In IOIPF's constructor\r\n"));
+ m_pApp = pApp;
+ };
+
+ ~COleInPlaceFrame()
+ {
+ TestDebugOut(TEXT("In IOIPFS's destructor\r\n"));
+ };
+
+ STDMETHODIMP QueryInterface (REFIID riid, LPVOID FAR* ppv);
+ STDMETHODIMP_(ULONG) AddRef ();
+ STDMETHODIMP_(ULONG) Release ();
+
+ STDMETHODIMP GetWindow (HWND FAR* lphwnd);
+ STDMETHODIMP ContextSensitiveHelp (BOOL fEnterMode);
+
+ // *** IOleInPlaceUIWindow methods ***
+ STDMETHODIMP GetBorder (LPRECT lprectBorder);
+ STDMETHODIMP RequestBorderSpace (LPCBORDERWIDTHS lpborderwidths);
+ STDMETHODIMP SetBorderSpace (LPCBORDERWIDTHS lpborderwidths);
+ STDMETHODIMP SetActiveObject (LPOLEINPLACEACTIVEOBJECT lpActiveObject,LPCOLESTR lpszObjName);
+
+ // *** IOleInPlaceFrame methods ***
+ STDMETHODIMP InsertMenus (HMENU hmenuShared, LPOLEMENUGROUPWIDTHS lpMenuWidths);
+ STDMETHODIMP SetMenu (HMENU hmenuShared, HOLEMENU holemenu, HWND hwndActiveObject);
+ STDMETHODIMP RemoveMenus (HMENU hmenuShared);
+ STDMETHODIMP SetStatusText (LPCOLESTR lpszStatusText);
+ STDMETHODIMP EnableModeless (BOOL fEnable);
+ STDMETHODIMP TranslateAccelerator (LPMSG lpmsg, WORD wID);
+};
+
+#endif
diff --git a/private/oleutest/simpcntr/ioips.cpp b/private/oleutest/simpcntr/ioips.cpp
new file mode 100644
index 000000000..f8a97be22
--- /dev/null
+++ b/private/oleutest/simpcntr/ioips.cpp
@@ -0,0 +1,615 @@
+//**********************************************************************
+// File name: IOIPS.CPP
+//
+// Implementation file for COleInPlaceSite
+//
+// Functions:
+//
+// See IOIPS.H for class Definition
+//
+// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+
+#include "pre.h"
+#include "iocs.h"
+#include "ias.h"
+#include "ioipf.h"
+#include "ioips.h"
+#include "app.h"
+#include "site.h"
+#include "doc.h"
+
+//**********************************************************************
+//
+// COleInPlaceSite::QueryInterface
+//
+// Purpose:
+//
+// Used for interface negotiation
+//
+// Parameters:
+//
+// REFIID riid - A reference to the interface that is
+// being queried.
+//
+// LPVOID FAR* ppvObj - An out parameter to return a pointer to
+// the interface.
+//
+// Return Value:
+//
+// S_OK - The interface is supported.
+// S_FALSE - The interface is not supported
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// CSimpleSite::QueryInterface SITE.CPP
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleInPlaceSite::QueryInterface(REFIID riid, LPVOID FAR* ppvObj)
+{
+ TestDebugOut(TEXT("In IOIPS::QueryInterface\r\n"));
+
+ // delegate to the container Site
+ return m_pSite->QueryInterface(riid, ppvObj);
+}
+
+//**********************************************************************
+//
+// COleInPlaceSite::AddRef
+//
+// Purpose:
+//
+// Increments the reference count of the CSimpleSite. Since
+// COleInPlaceSite is a nested class of CSimpleSite, we don't need an
+// extra reference count for COleInPlaceSite. We can safely use the
+// reference count of CSimpleSite.
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// ULONG - The new reference count of CSimpleSite
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// CSimpleSite::QueryInterface SITE.CPP
+//
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) COleInPlaceSite::AddRef()
+{
+ TestDebugOut(TEXT("In IOIPS::AddRef\r\n"));
+
+ // delegate to the container Site
+ return m_pSite->AddRef();
+}
+
+//**********************************************************************
+//
+// COleInPlaceSite::Release
+//
+// Purpose:
+//
+// Decrements the reference count of the CSimpleSite. Since
+// COleInPlaceSite is a nested class of CSimpleSite, we don't need an
+// extra reference count for COleInPlaceSite. We can safely use the
+// reference count of CSimpleSite.
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// ULONG - The new reference count of CSimpleSite
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// CSimpleSite::Release SITE.CPP
+//
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) COleInPlaceSite::Release()
+{
+ TestDebugOut(TEXT("In IOIPS::Release\r\n"));
+
+ // delegate to the container Site
+ return m_pSite->Release();
+}
+
+//**********************************************************************
+//
+// COleInPlaceSite::GetWindow
+//
+// Purpose:
+//
+// Returns the Window Handle of the client site
+//
+// Parameters:
+//
+// HWND FAR* lphwnd - place to return the handle
+//
+// Return Value:
+//
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// ResultFromScode OLE API
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleInPlaceSite::GetWindow (HWND FAR* lphwnd)
+{
+ TestDebugOut(TEXT("In IOIPS::GetWindow\r\n"));
+
+ // return the handle to our editing window.
+ *lphwnd = m_pSite->m_lpDoc->m_hDocWnd;
+
+ return ResultFromScode(S_OK);
+}
+
+//**********************************************************************
+//
+// COleInPlaceSite::ContextSensitiveHelp
+//
+// Purpose:
+// set/reset context sensitive help mode
+//
+// Parameters:
+//
+// BOOL fEnterMode - TRUE for entering Context Sensitive help mode
+//
+// Return Value:
+//
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// ResultFromScode OLE API
+//
+// Comments:
+//
+// Be sure to read the technotes included with the OLE toolkit.
+//
+//********************************************************************
+
+STDMETHODIMP COleInPlaceSite::ContextSensitiveHelp (BOOL fEnterMode)
+{
+ TestDebugOut(TEXT("In IOIPS::ContextSensitiveHelp\r\n"));
+
+ if (m_pSite->m_lpDoc->m_lpApp->m_fCSHMode != fEnterMode)
+ m_pSite->m_lpDoc->m_lpApp->m_fCSHMode = fEnterMode;
+
+ return ResultFromScode(S_OK);
+}
+
+//**********************************************************************
+//
+// COleInPlaceSite::CanInPlaceActivate
+//
+// Purpose:
+//
+// Object calls to find out if the container can InPlace activate
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// ResultFromScode OLE API
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleInPlaceSite::CanInPlaceActivate ()
+{
+ TestDebugOut(TEXT("In IOIPS::CanInPlaceActivate\r\n"));
+
+ // return S_OK to indicate we can in-place activate
+ return ResultFromScode(S_OK);
+}
+
+//**********************************************************************
+//
+// COleInPlaceSite::OnInPlaceActivate
+//
+// Purpose:
+//
+// Called by the object on InPlace Activation
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// S_OK - if the interface can be found
+// E_FAIL - otherwise
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// ResultFromScode OLE API
+// IOleObject::QueryInterface Object
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleInPlaceSite::OnInPlaceActivate ()
+{
+ HRESULT hrErr;
+ TestDebugOut(TEXT("In IOIPS::OnInPlaceActivate\r\n"));
+
+ hrErr = m_pSite->m_lpOleObject->QueryInterface(
+ IID_IOleInPlaceObject, (LPVOID FAR *)&m_pSite->m_lpInPlaceObject);
+ if (hrErr != NOERROR)
+ return ResultFromScode(E_FAIL);
+
+ // return S_OK to indicate we can in-place activate.
+ return ResultFromScode(S_OK);
+}
+
+//**********************************************************************
+//
+// COleInPlaceSite::OnUIActivate
+//
+// Purpose:
+//
+// Object calls this method when it displays it's UI.
+//
+// Parameters:
+//
+// None.
+//
+// Return Value:
+//
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// ResultFromScode OLE API
+// IOleInPlaceObject::GetWindow Object
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleInPlaceSite::OnUIActivate ()
+{
+ TestDebugOut(TEXT("In IOIPS::OnUIActivate\r\n"));
+
+ m_pSite->m_lpDoc->m_fAddMyUI=FALSE;
+ m_pSite->m_lpDoc->m_fInPlaceActive = TRUE;
+ m_pSite->m_fInPlaceActive = TRUE;
+
+ m_pSite->m_lpInPlaceObject->GetWindow((HWND FAR*)&m_pSite->m_hwndIPObj);
+
+ // return S_OK to continue in-place activation
+ return ResultFromScode(S_OK);
+}
+
+//**********************************************************************
+//
+// COleInPlaceSite::GetWindowContext
+//
+// Purpose:
+//
+// Called by the object to get information for InPlace Negotiation.
+//
+// Parameters:
+//
+// LPOLEINPLACEFRAME FAR* lplpFrame - Location to return a pointer
+// to IOleInPlaceFrame.
+//
+// LPOLEINPLACEUIWINDOW FAR* lplpDoc - Location to return a pointer
+// to IOleInPlaceUIWindow.
+//
+// LPRECT lprcPosRect - The rect that the object
+// occupies
+//
+// LPRECT lprcClipRect - The clipping rect
+//
+// LPOLEINPLACEFRAMEINFO lpFrameInfo - Pointer to FRAMEINFO
+//
+//
+// Return Value:
+//
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// COleInPlaceFrame::AddRef IOIPF.CPP
+// CSimpleSite::GetObjRect SITE.CPP
+// TestDebugOut Windows API
+// CopyRect Windows API
+// GetClientRect Windows API
+// ResultFromScode OLE API
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleInPlaceSite::GetWindowContext (
+ LPOLEINPLACEFRAME FAR* lplpFrame,
+ LPOLEINPLACEUIWINDOW FAR* lplpDoc,
+ LPRECT lprcPosRect,
+ LPRECT lprcClipRect,
+ LPOLEINPLACEFRAMEINFO lpFrameInfo)
+{
+ RECT rect;
+
+ TestDebugOut(TEXT("In IOIPS::GetWindowContext\r\n"));
+
+ // the frame is associated with the application object.
+ // need to AddRef() it...
+ m_pSite->m_lpDoc->m_lpApp->m_OleInPlaceFrame.AddRef();
+ *lplpFrame = &m_pSite->m_lpDoc->m_lpApp->m_OleInPlaceFrame;
+ *lplpDoc = NULL; // must be NULL, cause we're SDI.
+
+ // get the size of the object in pixels
+ m_pSite->GetObjRect(&rect);
+
+ // Copy this to the passed buffer
+ CopyRect(lprcPosRect, &rect);
+
+ // fill the clipping region
+ GetClientRect(m_pSite->m_lpDoc->m_hDocWnd, &rect);
+ CopyRect(lprcClipRect, &rect);
+
+ // fill the FRAMEINFO
+ if (sizeof(OLEINPLACEFRAMEINFO) != lpFrameInfo->cb)
+ {
+ TestDebugOut(TEXT("WARNING IOIPS::GetWindowContext "
+ "lpFrameInfo->cb size may be incorrect\r\n"));
+ }
+
+ lpFrameInfo->fMDIApp = FALSE;
+ lpFrameInfo->hwndFrame = m_pSite->m_lpDoc->m_lpApp->m_hAppWnd;
+ lpFrameInfo->haccel = m_pSite->m_lpDoc->m_lpApp->m_hAccel;
+ lpFrameInfo->cAccelEntries = SIMPCNTR_ACCEL_CNT;
+
+ return ResultFromScode(S_OK);
+}
+
+//**********************************************************************
+//
+// COleInPlaceSite::Scroll
+//
+// Purpose:
+//
+// Not Implemented
+//
+// Parameters:
+//
+// SIZE scrollExtent - number of pixels scrolled in X and Y direction
+//
+// Return Value:
+//
+// E_FAIL
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleInPlaceSite::Scroll (SIZE scrollExtent)
+{
+ TestDebugOut(TEXT("In IOIPS::Scroll\r\n"));
+ return ResultFromScode(E_FAIL);
+}
+
+//**********************************************************************
+//
+// COleInPlaceSite::OnUIDeactivate
+//
+// Purpose:
+//
+// Called by the object when its UI goes away
+//
+// Parameters:
+//
+// BOOL fUndoable
+//
+// Return Value:
+//
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// CSimpleAPP::QueryNewPalette APP.CPP
+// CSimpleAPP::AddFrameLevelUI APP.CPP
+// ResultFromScode OLE API
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleInPlaceSite::OnUIDeactivate (BOOL fUndoable)
+{
+ TestDebugOut(TEXT("In IOIPS::OnUIDeactivate\r\n"));
+
+ // need to clear this flag first
+ m_pSite->m_lpDoc->m_fInPlaceActive = FALSE;
+ m_pSite->m_fInPlaceActive = FALSE;
+
+ m_pSite->m_lpDoc->m_lpApp->QueryNewPalette();
+ m_pSite->m_lpDoc->m_lpApp->AddFrameLevelUI();
+ return ResultFromScode(S_OK);
+}
+
+//**********************************************************************
+//
+// COleInPlaceSite::OnInPlaceDeactivate
+//
+// Purpose:
+//
+// Called when the inplace session is over
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// ResultFromScode OLE API
+// IOleInPlaceObject::Release Object
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleInPlaceSite::OnInPlaceDeactivate ()
+{
+ TestDebugOut(TEXT("In IOIPS::OnInPlaceDeactivate\r\n"));
+
+ if (m_pSite->m_lpInPlaceObject)
+ {
+ m_pSite->m_lpInPlaceObject->Release();
+ m_pSite->m_lpInPlaceObject = NULL;
+ }
+ return ResultFromScode(S_OK);
+}
+
+//**********************************************************************
+//
+// COleInPlaceSite::DiscardUndoState
+//
+// Purpose:
+//
+// Not Implemented
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// E_FAIL
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleInPlaceSite::DiscardUndoState ()
+{
+ TestDebugOut(TEXT("In IOIPS::DiscardUndoState\r\n"));
+ return ResultFromScode(E_FAIL);
+}
+
+//**********************************************************************
+//
+// COleInPlaceSite::DeactivateAndUndo
+//
+// Purpose:
+//
+// Not Implemented
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// E_FAIL
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleInPlaceSite::DeactivateAndUndo ()
+{
+ TestDebugOut(TEXT("In IOIPS::DeactivateAndUndo\r\n"));
+ return ResultFromScode(E_FAIL);
+}
+
+//**********************************************************************
+//
+// COleInPlaceSite::OnPosRectChange
+//
+// Purpose:
+//
+// The object calls this method when it's size changes during an
+// InPlace Session
+//
+// Parameters:
+//
+// LPCRECT lprcPosRect - The new object rect
+//
+// Return Value:
+//
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// GetClientRect Windows API
+// IOleObject::GetExtent Object
+// IOleInPlaceObject::SetObjectRects Object
+// ResultFromScode OLE API
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleInPlaceSite::OnPosRectChange (LPCRECT lprcPosRect)
+{
+ TestDebugOut(TEXT("In IOIPS::OnPosRectChange\r\n"));
+
+ // update the size in the document object
+ // NOTE: here we must call IOleObject::GetExtent to get actual extents
+ // of the running object. IViewObject2::GetExtent returns the
+ // last cached extents.
+ m_pSite->m_lpOleObject->GetExtent(DVASPECT_CONTENT, &m_pSite->m_sizel);
+ RECT rect;
+ GetClientRect(m_pSite->m_lpDoc->m_hDocWnd, &rect);
+
+ // tell the object its new size
+ m_pSite->m_lpInPlaceObject->SetObjectRects(lprcPosRect, &rect);
+
+ return ResultFromScode(S_OK);
+}
+
diff --git a/private/oleutest/simpcntr/ioips.h b/private/oleutest/simpcntr/ioips.h
new file mode 100644
index 000000000..3fdbf2385
--- /dev/null
+++ b/private/oleutest/simpcntr/ioips.h
@@ -0,0 +1,53 @@
+//**********************************************************************
+// File name: IOIPS.H
+//
+// Definition of COleInPlaceSite
+//
+// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+#if !defined( _IOIPS_H_ )
+#define _IOIPS_H_
+
+
+class CSimpleSite;
+
+interface COleInPlaceSite : public IOleInPlaceSite
+{
+ CSimpleSite FAR * m_pSite;
+
+ COleInPlaceSite(CSimpleSite FAR *pSite)
+ {
+ TestDebugOut(TEXT("In IOIPS's constructor\r\n"));
+ m_pSite = pSite;
+ };
+
+ ~COleInPlaceSite()
+ {
+ TestDebugOut(TEXT("In IOIPS;s destructor\r\n"));
+ };
+
+ STDMETHODIMP QueryInterface (REFIID riid, LPVOID FAR* ppv);
+ STDMETHODIMP_(ULONG) AddRef ();
+ STDMETHODIMP_(ULONG) Release ();
+
+ STDMETHODIMP GetWindow (HWND FAR* lphwnd);
+ STDMETHODIMP ContextSensitiveHelp (BOOL fEnterMode);
+
+ // *** IOleInPlaceSite methods ***
+ STDMETHODIMP CanInPlaceActivate ();
+ STDMETHODIMP OnInPlaceActivate ();
+ STDMETHODIMP OnUIActivate ();
+ STDMETHODIMP GetWindowContext (LPOLEINPLACEFRAME FAR* lplpFrame,
+ LPOLEINPLACEUIWINDOW FAR* lplpDoc,
+ LPRECT lprcPosRect,
+ LPRECT lprcClipRect,
+ LPOLEINPLACEFRAMEINFO lpFrameInfo);
+ STDMETHODIMP Scroll (SIZE scrollExtent);
+ STDMETHODIMP OnUIDeactivate (BOOL fUndoable);
+ STDMETHODIMP OnInPlaceDeactivate ();
+ STDMETHODIMP DiscardUndoState ();
+ STDMETHODIMP DeactivateAndUndo ();
+ STDMETHODIMP OnPosRectChange (LPCRECT lprcPosRect);
+};
+
+#endif
diff --git a/private/oleutest/simpcntr/pre.cpp b/private/oleutest/simpcntr/pre.cpp
new file mode 100644
index 000000000..9603f4089
--- /dev/null
+++ b/private/oleutest/simpcntr/pre.cpp
@@ -0,0 +1,9 @@
+//**********************************************************************
+// File name: pre.cpp
+//
+// Used for precompiled headers
+//
+// Copyright (c) 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+
+#include "pre.h"
diff --git a/private/oleutest/simpcntr/pre.h b/private/oleutest/simpcntr/pre.h
new file mode 100644
index 000000000..6c1fdd23d
--- /dev/null
+++ b/private/oleutest/simpcntr/pre.h
@@ -0,0 +1,32 @@
+//**********************************************************************
+// File name: pre.h
+//
+// Used for precompiled headers
+//
+// Copyright (c) 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+
+#if !defined( _PRE_H_)
+#define _PRE_H_
+
+#include <windows.h>
+#include <ole2.h>
+#include <ole2ui.h>
+#include <assert.h>
+#include <string.h>
+#include "simpcntr.h"
+#include "resource.h"
+
+extern "C" void TestDebugOut(LPSTR psz);
+
+
+
+#ifndef WIN32
+/* Since OLE is part of the operating system in Win32, we don't need to
+ * check the version number in Win32.
+ */
+#include <ole2ver.h>
+#endif // WIN32
+
+
+#endif
diff --git a/private/oleutest/simpcntr/readme.txt b/private/oleutest/simpcntr/readme.txt
new file mode 100644
index 000000000..9c1947d0f
--- /dev/null
+++ b/private/oleutest/simpcntr/readme.txt
@@ -0,0 +1,31 @@
+Simpcntr
+--------
+This sample is the simplest OLE 2.0 container that can be written and
+still support the visual editing feature. The sample has no native
+file format, and can only support one OLE object at a time. The
+Insert Object command is used to create an object.
+
+See the MAKEFILE for compilation instructions.
+
+
+Simple Container Objects Overview :
+-----------------------------------
+Simple Container consists of three main objects. The top level is CSimpleApp,
+under which is CSimpleDoc, and the innermost level is CSimpleSite. CSimpleApp
+is used to hold the main window information. (eg. handle to the main window,
+handle to the UI Active Object) CSimpleApp always exists as long as the
+simple container application is alive. It demonstrates the implementation of
+IOleInPlaceFrame, in its nested class COleInPlaceFrame.
+
+The next level object is CSimpleDoc object. It is instantiated by CSimpleApp
+when a new document is created. It is used to hold the handles to the main
+menus and the submenus and manipulate changes to these menus.
+
+The CSimpleDoc object instantiates CSimpleSite object as the user chooses to
+insert a new object into the document. CSimpleSite demonstrates the
+implementation of IAdviseSink, IOleInPlaceSite and IOleClientSite through
+its nested classes. These interfaces are implemented as CAdviseSink,
+COleInPlaceSite and COleClientSite accordingly. CSimpleSite acts as a client
+site to communicate to a remote server.
+
+ \ No newline at end of file
diff --git a/private/oleutest/simpcntr/resource.h b/private/oleutest/simpcntr/resource.h
new file mode 100644
index 000000000..0f20f416d
--- /dev/null
+++ b/private/oleutest/simpcntr/resource.h
@@ -0,0 +1,32 @@
+//{{NO_DEPENDENCIES}}
+// App Studio generated include file.
+// Used by SIMPCNTR.RC
+//
+#define IDM_OPEN 102
+#define IDM_SAVE 103
+#define IDM_SAVEAS 104
+#define IDM_PRINT 105
+#define IDM_EXIT 106
+#define IDM_UNDO 107
+#define IDM_CUT 108
+#define IDM_COPY 109
+#define IDM_PASTE 110
+#define ID_EDIT_INSERTOBJECT 111
+#define IDM_INSERTOBJECT 111
+#define IDM_NEW 112
+#define IDM_DEACTIVATE 113
+#define IDM_UTEST 998
+
+#define SIMPCNTR_ACCEL_CNT 3
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+
+#define _APS_NEXT_RESOURCE_VALUE 101
+#define _APS_NEXT_COMMAND_VALUE 113
+#define _APS_NEXT_CONTROL_VALUE 1000
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/private/oleutest/simpcntr/simpcntr.cpp b/private/oleutest/simpcntr/simpcntr.cpp
new file mode 100644
index 000000000..5b9f5adc8
--- /dev/null
+++ b/private/oleutest/simpcntr/simpcntr.cpp
@@ -0,0 +1,523 @@
+//**********************************************************************
+// File name: Simple.cpp
+//
+// Main source file for the Simple OLE 2.0 object container
+//
+// Functions:
+//
+// WinMain - Program entry point
+// MainWndProc - Processes messages for the frame window
+// About - Processes messages for the about dialog
+// DocWndProc - Processes messages for the doc window
+//
+// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+
+#include "pre.h"
+#include "iocs.h"
+#include "ias.h"
+#include "ioipf.h"
+#include "ioips.h"
+#include "app.h"
+#include "site.h"
+#include "doc.h"
+#include "tests.h"
+
+// This line is needed for the debug utilities in OLE2UI
+extern "C" {
+ OLEDBGDATA_MAIN(TEXT("SIMPCNTR"))
+}
+
+CSimpleApp FAR * lpCSimpleApp;
+
+void DeactivateIfActive(HWND hWnd)
+{
+ LPOLEINPLACEOBJECT lpObject;
+ MSG msg;
+ msg.message = WM_LBUTTONDOWN;
+
+
+ if (lpCSimpleApp->m_lpDoc->m_fInPlaceActive)
+ {
+ // We are in the process of deactiving the in place object
+ lpCSimpleApp->m_fDeactivating = TRUE;
+
+ lpCSimpleApp->m_lpDoc->m_lpSite->m_lpOleObject->QueryInterface(
+ IID_IOleInPlaceObject, (LPVOID FAR *)&lpObject);
+ lpObject->UIDeactivate();
+
+ // this code is needed because we don't support inside out.
+ RECT rect;
+ lpCSimpleApp->m_lpDoc->m_lpSite->GetObjRect(&rect);
+ lpCSimpleApp->m_lpDoc->m_lpSite->m_lpOleObject->DoVerb(
+ OLEIVERB_HIDE,
+ &msg,
+ &lpCSimpleApp->m_lpDoc->m_lpSite->m_OleClientSite,
+ -1, hWnd, &rect);
+
+ lpObject->Release();
+
+ // We are done deactiving
+ lpCSimpleApp->m_fDeactivating = FALSE;
+ }
+
+}
+
+
+BOOL fBeVerbose = FALSE;
+extern "C"
+void TestDebugOut(LPSTR psz)
+{
+ if (fBeVerbose)
+ {
+ OutputDebugStringA(psz);
+ }
+}
+
+
+//**********************************************************************
+//
+// WinMain
+//
+// Purpose:
+//
+// Program entry point
+//
+// Parameters:
+//
+// HANDLE hInstance - Instance handle for this instance
+//
+// HANDLE hPrevInstance - Instance handle for the last instance
+//
+// LPSTR lpCmdLine - Pointer to the command line
+//
+// int nCmdShow - Window State
+//
+// Return Value:
+//
+// msg.wParam
+//
+// Function Calls:
+// Function Location
+//
+// CSimpleApp::CSimpleApp APP.CPP
+// CSimpleApp::AddRef APP.CPP
+// CSimpleApp::Release APP.CPP
+// CSimpleApp::fInitApplication APP.CPP
+// CSimpleApp::fInitInstance APP.CPP
+// CSimpleApp::HandleAccelerators APP.CPP
+// CSimpleApp::~CSimpleApp APP.CPP
+// OleUIInitialize OLE2UI
+// OleUIUninitialize OLE2UI
+// GetMessage Windows API
+// TranslateMessage Windows API
+// DispatchMessage Windows API
+//
+//********************************************************************
+int PASCAL WinMain
+#ifdef WIN32
+ (HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow)
+#else
+ (HANDLE hInstance, HANDLE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
+#endif
+{
+ MSG msg;
+
+ // needed for LRPC to work properly...
+ SetMessageQueue(96);
+
+ lpCSimpleApp = new CSimpleApp;
+ fBeVerbose = GetProfileInt("OLEUTEST","BeVerbose",0);
+
+ if(fBeVerbose == 0)
+ {
+ fBeVerbose = GetProfileInt("OLEUTEST","simpcntr",0);
+ }
+
+ if (!lpCSimpleApp)
+ {
+ /* memory allocation error. cannot carry on.
+ */
+ return(FALSE);
+ }
+
+ // we will add one ref count on our App. later when we want to destroy
+ // the App object we will release this ref count. when the App's ref
+ // count goes to 0, it will be deleted.
+ lpCSimpleApp->AddRef();
+
+ char *pszTemp;
+
+ // process the command line
+ if( (pszTemp = strstr(lpCmdLine, "-driver")) )
+ {
+ //we were launched by the test driver
+ lpCSimpleApp->m_hDriverWnd = (HWND)strtoul(pszTemp+8, NULL, 10);
+ }
+
+ // app initialization
+ if (!hPrevInstance)
+ if (!lpCSimpleApp->fInitApplication(hInstance))
+ {
+ lpCSimpleApp->Release();
+ return (FALSE);
+ }
+
+ // instance initialization
+ if (!lpCSimpleApp->fInitInstance(hInstance, nCmdShow))
+ {
+ lpCSimpleApp->Release();
+ return (FALSE);
+ }
+
+ /* Initialization required for OLE 2 UI library. This call is
+ ** needed ONLY if we are using the static link version of the UI
+ ** library. If we are using the DLL version, we should NOT call
+ ** this function in our application.
+ ** The 3rd and 4th parameters passed the OleUIInitialize
+ ** function are strings which are used to name two custom
+ ** control classes used by the OLE2UI library. These strings
+ ** must be unique for each application that uses the OLE2UI
+ ** library. These strings are typically composed by combining
+ ** the APPNAME with a suffix in order to be unique for a
+ ** particular application. The special symbols "SZCLASSICONBOX"
+ ** and "SZCLASSRESULTIMAGE" are used define these strings. These
+ ** symbols must be defined in a header file that is included
+ ** both in this file AND the resource file that included the
+ ** "OLE2UI.RC" resoure file. These symbols should be used in the
+ ** call to OleUIInitialize and are referenced in the INSOBJ.DLG
+ ** and PASTESPL.DLG resouce files of the OLE2UI library.
+ */
+#if 0 // We use the DLL form of OLE2U32A
+ if (!OleUIInitialize(hInstance, hPrevInstance, TEXT(SZCLASSICONBOX),
+ TEXT(SZCLASSRESULTIMAGE)))
+ {
+ OleDbgOut(TEXT("Could not initialize OLEUI library\n"));
+ lpCSimpleApp->Release();
+ return FALSE;
+ }
+#endif
+
+ // message loop
+ while (GetMessage(&msg, NULL, NULL, NULL))
+ if (!lpCSimpleApp->HandleAccelerators(&msg))
+ {
+ TranslateMessage(&msg); /* Translates virtual key codes */
+ DispatchMessage(&msg); /* Dispatches message to window */
+ }
+
+
+#if 0 // We use the DLL form of OLE2U32A
+ // De-initialization for UI libraries. Just like OleUIInitialize, this
+ // funciton is needed ONLY if we are using the static link version of the
+ // OLE UI library.
+ OleUIUninitialize();
+#endif
+
+ // Release the ref count added on the App above. this will make
+ // the App's ref count go to 0, and the App object will be deleted.
+ lpCSimpleApp->Release();
+
+ return (msg.wParam); /* Returns the value from PostQuitMessage */
+}
+
+
+//**********************************************************************
+//
+// MainWndProc
+//
+// Purpose:
+//
+// Processes messages for the frame window
+//
+// Parameters:
+//
+// HWND hWnd - Window handle for frame window
+//
+// UINT message - Message value
+//
+// WPARAM wParam - Message info
+//
+// LPARAM lParam - Message info
+//
+// Return Value:
+//
+// long
+//
+// Function Calls:
+// Function Location
+//
+// CSimpleApp::lCommandHandler APP.CPP
+// CSimpleApp::DestroyDocs APP.CPP
+// CSimpleApp::lCreateDoc APP.CPP
+// CSimpleApp::lSizeHandler APP.CPP
+// CSimpleDoc::lAddVerbs DOC.CPP
+// CSimpleDoc::QueryNewPalette APP.CPP
+// SendMessage Windows API
+// PostQuitMessage Windows API
+// DefWindowProc Windows API
+//
+//
+//********************************************************************
+
+long FAR PASCAL EXPORT MainWndProc(HWND hWnd, UINT message,
+ WPARAM wParam, LPARAM lParam)
+{
+
+ switch (message)
+ {
+ case WM_CLOSE:
+ DestroyWindow(lpCSimpleApp->m_hAppWnd);
+ break;
+
+ case WM_TEST1:
+ // Do the unit test
+ Test1(lpCSimpleApp);
+ break;
+
+ case WM_SETFOCUS:
+ // If we have an inplace application it needs to get the focus
+ if (lpCSimpleApp->m_lpDoc->m_fInPlaceActive
+ && !lpCSimpleApp->m_fDeactivating)
+ {
+ SetFocus(lpCSimpleApp->m_hwndUIActiveObj);
+ break;
+ }
+
+ // Othewise default behavior is enough
+ return (DefWindowProc(hWnd, message, wParam, lParam));
+
+ case WM_COMMAND: // message: command from application menu
+ return lpCSimpleApp->lCommandHandler(hWnd, message,
+ wParam, lParam);
+ break;
+
+ case WM_CREATE:
+ return lpCSimpleApp->lCreateDoc(hWnd, message, wParam, lParam);
+ break;
+
+ case WM_DESTROY: // message: window being destroyed
+ lpCSimpleApp->DestroyDocs(); // need to destroy the doc...
+ PostQuitMessage(0);
+ break;
+
+ case WM_INITMENUPOPUP:
+ // is this the edit menu?
+ if ( LOWORD(lParam) == 1)
+ return lpCSimpleApp->m_lpDoc->lAddVerbs();
+
+ break;
+
+ // this code is needed for 256 color objects to work properly.
+ case WM_QUERYNEWPALETTE:
+ if (! lpCSimpleApp->m_fAppActive)
+ return 0L;
+
+ return lpCSimpleApp->QueryNewPalette();
+
+
+ case WM_PALETTECHANGED:
+ {
+ HWND hWndPalChg = (HWND) wParam;
+
+ if (hWnd != hWndPalChg)
+ wSelectPalette(hWnd, lpCSimpleApp->m_hStdPal,
+ TRUE/*fBackground*/);
+
+ /* 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 (lpCSimpleApp->m_lpDoc && lpCSimpleApp->m_lpDoc->m_lpSite &&
+ lpCSimpleApp->m_lpDoc->m_lpSite->m_hwndIPObj)
+ {
+ SendMessage(lpCSimpleApp->m_lpDoc->m_lpSite->m_hwndIPObj,
+ WM_PALETTECHANGED, wParam, lParam);
+ }
+
+ return 0L;
+ }
+
+ case WM_ACTIVATEAPP:
+ if ((lpCSimpleApp->m_fAppActive = (BOOL)wParam) == TRUE)
+ lpCSimpleApp->QueryNewPalette();
+
+ if (lpCSimpleApp->m_lpDoc->m_lpActiveObject)
+ {
+ lpCSimpleApp->m_lpDoc->m_lpActiveObject->OnFrameWindowActivate(
+ (BOOL)wParam);
+ }
+ break;
+
+ case WM_SIZE:
+ return lpCSimpleApp->lSizeHandler(hWnd, message, wParam, lParam);
+
+ default: // Passes it on if unproccessed
+ return (DefWindowProc(hWnd, message, wParam, lParam));
+ }
+ return (NULL);
+}
+
+
+//**********************************************************************
+//
+// About
+//
+// Purpose:
+//
+// Processes dialog box messages
+//
+// Parameters:
+//
+// HWND hWnd - Window handle for dialog box
+//
+// UINT message - Message value
+//
+// WPARAM wParam - Message info
+//
+// LPARAM lParam - Message info
+//
+// Return Value:
+// TRUE if message processed, FALSE otherwise
+//
+// Function Calls:
+// Function Location
+//
+// EndDialog Windows API
+//
+//
+//********************************************************************
+
+BOOL FAR PASCAL EXPORT About(HWND hDlg,UINT message,WPARAM wParam,LPARAM lParam)
+
+{
+ switch (message)
+ {
+ case WM_INITDIALOG: /* message: initialize dialog box */
+ return (TRUE);
+
+ case WM_COMMAND: /* message: received a command */
+ if (wParam == IDOK /* "OK" box selected? */
+ || wParam == IDCANCEL) /* System menu close command? */
+ {
+ EndDialog(hDlg, TRUE); /* Exits the dialog box */
+ return (TRUE);
+ }
+ break;
+ }
+ return (FALSE); /* Didn't process a message */
+}
+
+//**********************************************************************
+//
+// DocWndProc
+//
+// Purpose:
+//
+// Processes dialog box messages
+//
+// Parameters:
+//
+// HWND hWnd - Window handle for doc window
+//
+// UINT message - Message value
+//
+// WPARAM wParam - Message info
+//
+// LPARAM lParam - Message info
+//
+// Return Value:
+// NULL
+//
+// Function Calls:
+// Function Location
+//
+// CSimpleApp::PaintApp APP.CPP
+// BeginPaint Windows API
+// EndPaint Windows API
+// DefWindowProc Windows API
+// PtInRect Windows API
+// CSimpleSite::GetObjRect SITE.CPP
+// IOleObject::QueryInterface Object
+// IOleInPlaceObject::UIDeactivate Object
+// IOleObject::DoVerb Object
+// IOleInPlaceObject::Release Object
+//
+//
+//********************************************************************
+
+long FAR PASCAL EXPORT DocWndProc(HWND hWnd, UINT message,
+ WPARAM wParam, LPARAM lParam)
+{
+ HDC hDC;
+ PAINTSTRUCT ps;
+
+ switch (message)
+ {
+ case WM_SETFOCUS:
+ // If we have an inplace application it needs to get the focus
+ if (lpCSimpleApp->m_lpDoc->m_fInPlaceActive
+ && !lpCSimpleApp->m_fDeactivating)
+ {
+ SetFocus(lpCSimpleApp->m_hwndUIActiveObj);
+ break;
+ }
+
+ // Otherwise default behavior is enough
+ return (DefWindowProc(hWnd, message, wParam, lParam));
+
+ case WM_PAINT:
+
+ hDC = BeginPaint(hWnd, &ps);
+
+ if (lpCSimpleApp)
+ lpCSimpleApp->PaintApp (hDC);
+
+ EndPaint(hWnd, &ps);
+ break;
+
+
+ case WM_LBUTTONDBLCLK:
+ {
+ POINT pt;
+
+ pt.x = (int)(short)LOWORD (lParam );
+ pt.y = (int)(short)HIWORD (lParam );
+
+ if (lpCSimpleApp->m_lpDoc->m_lpSite &&
+ lpCSimpleApp->m_lpDoc->m_lpSite->m_lpOleObject)
+ {
+ RECT rect;
+
+ lpCSimpleApp->m_lpDoc->m_lpSite->GetObjRect(&rect);
+
+ if ( PtInRect(&rect, pt) )
+ {
+ // Execute object's default verb
+ lpCSimpleApp->m_lpDoc->m_lpSite->m_lpOleObject->DoVerb(
+ OLEIVERB_PRIMARY, (LPMSG)&message,
+ &lpCSimpleApp->m_lpDoc->m_lpSite->m_OleClientSite,
+ -1, hWnd, &rect);
+ }
+ }
+ }
+ break;
+
+ // no code is added to WM_LBUTTONDOWN for context sensitive help, because
+ // this app does not do context sensitive help.
+
+ case WM_LBUTTONDOWN:
+ DeactivateIfActive(hWnd);
+ break;
+
+ default: /* Passes it on if unproccessed */
+ return (DefWindowProc(hWnd, message, wParam, lParam));
+ }
+ return (NULL);
+}
+
diff --git a/private/oleutest/simpcntr/simpcntr.def b/private/oleutest/simpcntr/simpcntr.def
new file mode 100644
index 000000000..d0dd19433
--- /dev/null
+++ b/private/oleutest/simpcntr/simpcntr.def
@@ -0,0 +1,26 @@
+; module-definition file for generic -- used by LINK.EXE
+
+NAME SIMPCNTR ; application's module name
+
+DESCRIPTION 'Sample Microsoft Windows Application'
+
+EXETYPE WINDOWS ; required for all Windows applications
+
+STUB 'WINSTUB.EXE' ; Generates error message if application
+ ; is run without Windows
+
+;CODE can be moved in memory and discarded/reloaded
+CODE PRELOAD MOVEABLE DISCARDABLE
+
+;DATA must be MULTIPLE if program can be invoked more than once
+DATA PRELOAD MOVEABLE MULTIPLE
+
+
+HEAPSIZE 1024
+STACKSIZE 16000
+
+
+; All functions that will be called by any Windows routine
+; MUST be exported.
+
+
diff --git a/private/oleutest/simpcntr/simpcntr.h b/private/oleutest/simpcntr/simpcntr.h
new file mode 100644
index 000000000..190e0c427
--- /dev/null
+++ b/private/oleutest/simpcntr/simpcntr.h
@@ -0,0 +1,40 @@
+//**********************************************************************
+// File name: simple.h
+//
+// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+#define IDM_ABOUT 100
+#define IDM_INSERT 101
+#define IDM_VERB0 1000
+
+int PASCAL WinMain
+#ifdef WIN32
+ (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow);
+#else
+ (HANDLE hInstance, HANDLE hPrevInstance, LPSTR lpCmdLine, int nCmdShow);
+#endif
+
+BOOL InitApplication(HANDLE hInstance);
+BOOL InitInstance(HANDLE hInstance, int nCmdShow);
+long FAR PASCAL EXPORT MainWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
+long FAR PASCAL EXPORT DocWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
+
+#ifdef WIN32
+BOOL CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
+#else
+BOOL FAR PASCAL EXPORT About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
+#endif
+
+
+/* These strings are used to name two custom control classes used by
+** the OLE2UI library. These strings must be unique for each
+** application that uses the OLE2UI library. These strings should be
+** composed by combining the APPNAME with a suffix in order to be
+** unique for a particular application. The special symbols
+** "SZCLASSICONBOX" and "SZCLASSRESULTIMAGE" are used define these
+** strings. These symbols are passed in the OleUIInitialize call and
+** are referenced in the INSOBJ.DLG and PASTESPL.DLG resouce files
+** of the OLE2UI library.
+*/
+#define SZCLASSICONBOX "simpcntrIBClass"
+#define SZCLASSRESULTIMAGE "simpcntrRIClass"
diff --git a/private/oleutest/simpcntr/simpcntr.ico b/private/oleutest/simpcntr/simpcntr.ico
new file mode 100644
index 000000000..5450ff3f0
--- /dev/null
+++ b/private/oleutest/simpcntr/simpcntr.ico
Binary files differ
diff --git a/private/oleutest/simpcntr/simpcntr.rc b/private/oleutest/simpcntr/simpcntr.rc
new file mode 100644
index 000000000..732b496b2
--- /dev/null
+++ b/private/oleutest/simpcntr/simpcntr.rc
@@ -0,0 +1,114 @@
+//Microsoft App Studio generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#define APSTUDIO_HIDDEN_SYMBOLS
+#include "windows.h"
+#undef APSTUDIO_HIDDEN_SYMBOLS
+#include "simpcntr.h"
+#include "ole2ui.rc"
+
+/////////////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+SimpCntr icon simpcntr.ico
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// Menu
+//
+
+SIMPLEMENU MENU DISCARDABLE
+BEGIN
+ POPUP "&File"
+ BEGIN
+ MENUITEM "&New", IDM_NEW
+ MENUITEM SEPARATOR
+ MENUITEM "E&xit", IDM_EXIT
+ END
+ POPUP "&Edit"
+ BEGIN
+ MENUITEM "&Insert Object...", IDM_INSERTOBJECT
+ END
+ POPUP "&Other"
+ BEGIN
+ MENUITEM "&Deactivate Inplace", IDM_DEACTIVATE
+ MENUITEM "&About Simple...", IDM_ABOUT
+ END
+END
+
+
+SimpcntrAccel ACCELERATORS
+ BEGIN
+ "^a", IDM_UTEST
+ VK_F10, IDM_DEACTIVATE, VIRTKEY, CONTROL
+ VK_F11, IDM_ABOUT, VIRTKEY, CONTROL
+ END
+
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+ABOUTBOX DIALOG DISCARDABLE 22, 17, 144, 75
+STYLE DS_MODALFRAME | WS_CAPTION | WS_SYSMENU
+CAPTION "About SimpCntr"
+FONT 8, "System"
+BEGIN
+ CTEXT "Simple OLE 2.0",-1,0,5,144,8
+ CTEXT "In-Place Container Application",-1,0,14,144,8
+ CTEXT "Version 2.01",-1,0,34,144,8
+ DEFPUSHBUTTON "OK",IDOK,53,59,32,14,WS_GROUP
+END
+
+#ifdef APSTUDIO_INVOKED
+//////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "#define APSTUDIO_HIDDEN_SYMBOLS\r\n"
+ "#include ""windows.h""\r\n"
+ "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n"
+ "#include ""simpcntr.h""\r\n"
+ "#include ""..\\ole2ui\\resource\\usa\\strings.rc""\r\n"
+ "#include ""..\\ole2ui\\resource\\usa\\insobj.dlg""\r\n"
+ "\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+/////////////////////////////////////////////////////////////////////////////////////
+#endif // APSTUDIO_INVOKED
+
+
+#ifndef APSTUDIO_INVOKED
+////////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
+
diff --git a/private/oleutest/simpcntr/site.cpp b/private/oleutest/simpcntr/site.cpp
new file mode 100644
index 000000000..70f828a83
--- /dev/null
+++ b/private/oleutest/simpcntr/site.cpp
@@ -0,0 +1,637 @@
+//**********************************************************************
+// File name: SITE.CPP
+//
+// Implementation file for CSimpleSite
+//
+// Functions:
+//
+// See SITE.H for class definition
+//
+// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+
+#include "pre.h"
+#include "iocs.h"
+#include "ias.h"
+#include "ioipf.h"
+#include "ioips.h"
+#include "app.h"
+#include "site.h"
+#include "doc.h"
+
+//**********************************************************************
+//
+// CSimpleSite::Create
+//
+// Purpose:
+//
+// Creation routine for CSimpleSite
+//
+// Parameters:
+//
+// CSimpleDoc FAR *lpDoc - Pointer to CSimpleDoc
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// CSimpleSite::CSimpleSite SITE.CPP
+// IStorage::CreateStorage OLE API
+// CSimpleSite::AddRef SITE.CPP
+// assert C Runtime
+//
+//
+//********************************************************************
+
+CSimpleSite FAR * CSimpleSite::Create(CSimpleDoc FAR *lpDoc)
+{
+ CSimpleSite FAR * lpTemp = new CSimpleSite(lpDoc);
+
+ if (!lpTemp)
+ return NULL;
+
+ // create a sub-storage for the object
+ HRESULT hErr = lpDoc->m_lpStorage->CreateStorage( OLESTR("Object"),
+ STGM_READWRITE | STGM_TRANSACTED | STGM_SHARE_EXCLUSIVE,
+ 0,
+ 0,
+ &lpTemp->m_lpObjStorage);
+
+ assert(hErr == NOERROR);
+
+ if (hErr != NOERROR)
+ {
+ delete lpTemp;
+ return NULL;
+ }
+
+ // we will add one ref count on our Site. later when we want to destroy
+ // the Site object we will release this ref count. when the Site's ref
+ // count goes to 0, it will be deleted.
+ lpTemp->AddRef();
+
+ return lpTemp;
+}
+
+//**********************************************************************
+//
+// CSimpleSite::CSimpleSite
+//
+// Purpose:
+//
+// Constructor for CSimpleSite
+//
+// Parameters:
+//
+// CSimpleDoc FAR *lpDoc - Pointer to CSimpleDoc
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+//
+//********************************************************************
+#pragma warning(disable : 4355) // turn off this warning. This warning
+ // tells us that we are passing this in
+ // an initializer, before "this" is through
+ // initializing. This is ok, because
+ // we just store the ptr in the other
+ // constructors
+
+CSimpleSite::CSimpleSite (CSimpleDoc FAR *lpDoc) : m_OleClientSite(this),
+ m_AdviseSink(this),
+ m_OleInPlaceSite(this)
+#pragma warning (default : 4355) // Turn the warning back on
+{
+ TestDebugOut (TEXT("In CSimpleSite's Constructor \r\n"));
+
+ // remember the pointer to the doc
+ m_lpDoc = lpDoc;
+
+ // clear the reference count
+ m_nCount = 0;
+
+ m_dwDrawAspect = DVASPECT_CONTENT;
+ m_lpOleObject = NULL;
+ m_lpInPlaceObject = NULL;
+ m_hwndIPObj = NULL;
+ m_fInPlaceActive = FALSE;
+ m_fObjectOpen = FALSE;
+}
+
+//**********************************************************************
+//
+// CSimpleSite::~CSimpleSite
+//
+// Purpose:
+//
+// Destructor for CSimpleSite
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// IOleObject::Release Object
+// IStorage::Release OLE API
+//
+//
+//********************************************************************
+
+CSimpleSite::~CSimpleSite ()
+{
+ TestDebugOut (TEXT("In CSimpleSite's Destructor \r\n"));
+
+ if (m_lpOleObject)
+ m_lpOleObject->Release();
+
+ if (m_lpObjStorage)
+ m_lpObjStorage->Release();
+}
+
+
+//**********************************************************************
+//
+// CSimpleSite::CloseOleObject
+//
+// Purpose:
+//
+// Call IOleObject::Close on the object of the CSimpleSite
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// IOleObject::QueryInterface Object
+// IOleObject::Close Object
+// IOleInPlaceObject::UIDeactivate Object
+// IOleInPlaceObject::InPlaceDeactivate Object
+// IOleInPlaceObject::Release Object
+//
+//
+//********************************************************************
+
+void CSimpleSite::CloseOleObject (void)
+{
+ LPOLEINPLACEOBJECT lpObject;
+ LPVIEWOBJECT lpViewObject = NULL;
+
+ TestDebugOut (TEXT("In CSimpleSite::CloseOleObject \r\n"));
+
+ if (m_lpOleObject)
+ {
+ if (m_fInPlaceActive)
+ {
+ m_lpOleObject->QueryInterface(IID_IOleInPlaceObject,
+ (LPVOID FAR *)&lpObject);
+ lpObject->UIDeactivate();
+ // don't need to worry about inside-out because the object
+ // is going away.
+ lpObject->InPlaceDeactivate();
+ lpObject->Release();
+ }
+
+ m_lpOleObject->Close(OLECLOSE_NOSAVE);
+ }
+}
+
+
+//**********************************************************************
+//
+// CSimpleSite::UnloadOleObject
+//
+// Purpose:
+//
+// Close and release all pointers to the object of the CSimpleSite
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// CSimpleSite::CloseOleObject SITE.CPP
+// IOleObject::QueryInterface Object
+// IOleObject::Release Object
+// IViewObject::SetAdvise Object
+// IViewObject::Release Object
+//
+//
+//********************************************************************
+
+void CSimpleSite::UnloadOleObject (void)
+{
+ TestDebugOut (TEXT("In CSimpleSite::UnloadOleObject \r\n"));
+
+ if (m_lpOleObject)
+ {
+ LPVIEWOBJECT lpViewObject;
+ CloseOleObject(); // ensure object is closed; NOP if already closed
+
+ m_lpOleObject->QueryInterface(IID_IViewObject,
+ (LPVOID FAR *)&lpViewObject);
+
+ if (lpViewObject)
+ {
+ // Remove the view advise
+ lpViewObject->SetAdvise(m_dwDrawAspect, 0, NULL);
+ lpViewObject->Release();
+ }
+
+ m_lpOleObject->Release();
+ m_lpOleObject = NULL;
+ }
+}
+
+
+//**********************************************************************
+//
+// CSimpleSite::QueryInterface
+//
+// Purpose:
+//
+// Used for interface negotiation of the container Site.
+//
+// Parameters:
+//
+// REFIID riid - A reference to the interface that is
+// being queried.
+//
+// LPVOID FAR* ppvObj - An out parameter to return a pointer to
+// the interface.
+//
+// Return Value:
+//
+// S_OK - The interface is supported.
+// E_NOINTERFACE - The interface is not supported
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// IsEqualIID OLE API
+// ResultFromScode OLE API
+// CSimpleSite::AddRef OBJ.CPP
+// COleClientSite::AddRef IOCS.CPP
+// CAdviseSink::AddRef IAS.CPP
+// COleInPlaceSite::AddRef IOIPS.CPP
+//
+//
+//********************************************************************
+
+STDMETHODIMP CSimpleSite::QueryInterface(REFIID riid, LPVOID FAR* ppvObj)
+{
+ TestDebugOut(TEXT("In CSimpleSite::QueryInterface\r\n"));
+
+ *ppvObj = NULL; // must set out pointer parameters to NULL
+
+ if ( IsEqualIID(riid, IID_IUnknown))
+ {
+ AddRef();
+ *ppvObj = this;
+ return ResultFromScode(S_OK);
+ }
+
+ if ( IsEqualIID(riid, IID_IOleClientSite))
+ {
+ m_OleClientSite.AddRef();
+ *ppvObj = &m_OleClientSite;
+ return ResultFromScode(S_OK);
+ }
+
+ if ( IsEqualIID(riid, IID_IAdviseSink))
+ {
+ m_AdviseSink.AddRef();
+ *ppvObj = &m_AdviseSink;
+ return ResultFromScode(S_OK);
+ }
+
+ if ( IsEqualIID(riid, IID_IOleInPlaceSite))
+ {
+ m_OleInPlaceSite.AddRef();
+ *ppvObj = &m_OleInPlaceSite;
+ return ResultFromScode(S_OK);
+ }
+
+ // Not a supported interface
+ return ResultFromScode(E_NOINTERFACE);
+}
+
+//**********************************************************************
+//
+// CSimpleSite::AddRef
+//
+// Purpose:
+//
+// Increments the reference count of the container Site.
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// ULONG - The new reference count of the site.
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) CSimpleSite::AddRef()
+{
+ TestDebugOut(TEXT("In CSimpleSite::AddRef\r\n"));
+
+ return ++m_nCount;
+}
+
+//**********************************************************************
+//
+// CSimpleSite::Release
+//
+// Purpose:
+//
+// Decrements the reference count of the container Site
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// ULONG - The new reference count of the Site.
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) CSimpleSite::Release()
+{
+ TestDebugOut(TEXT("In CSimpleSite::Release\r\n"));
+
+ if (--m_nCount == 0)
+ {
+ delete this;
+ return 0;
+ }
+ return m_nCount;
+}
+
+//**********************************************************************
+//
+// CSimpleSite::InitObject
+//
+// Purpose:
+//
+// Used to initialize a newly create object (can't be done in the
+// constructor).
+//
+// Parameters:
+//
+// BOOL fCreateNew - TRUE if insert NEW object
+// FALSE if create object FROM FILE
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// IOleObject::SetHostNames Object
+// IOleObject::QueryInterface Object
+// IViewObject2::GetExtent Object
+// IOleObject::DoVerb Object
+// IViewObject2::SetAdvise Object
+// IViewObject2::Release Object
+// GetClientRect Windows API
+// OleSetContainedObject OLE API
+//
+//
+//********************************************************************
+
+void CSimpleSite::InitObject(BOOL fCreateNew)
+{
+ LPVIEWOBJECT2 lpViewObject2;
+ RECT rect;
+
+ TestDebugOut(TEXT("In CSimpleSite::InitObject\r\n"));
+
+ // Set a View Advise
+ m_lpOleObject->QueryInterface(IID_IViewObject2,
+ (LPVOID FAR *)&lpViewObject2);
+ lpViewObject2->SetAdvise(m_dwDrawAspect, ADVF_PRIMEFIRST, &m_AdviseSink);
+
+ // get the initial size of the object
+ lpViewObject2->GetExtent(m_dwDrawAspect, -1 /*lindex*/, NULL /*ptd*/,
+ &m_sizel);
+ GetObjRect(&rect); // get the rectangle of the object in pixels
+ lpViewObject2->Release();
+
+ // give the object the name of the container app/document
+ m_lpOleObject->SetHostNames(OLESTR("Simple Application"),
+ OLESTR("Simple OLE 2.0 In-Place Container"));
+
+ // inform object handler/DLL object that it is used in the embedding
+ // container's context
+ HRESULT hRes;
+ if ((hRes = OleSetContainedObject(m_lpOleObject, TRUE))
+ != ResultFromScode(S_OK) )
+ {
+ TestDebugOut(TEXT("Fail in OleSetContainedObject\n"));
+ }
+
+ if (fCreateNew)
+ {
+ // force new object to save to guarantee valid object in our storage.
+ // OLE 1.0 objects may close w/o saving. this is NOT necessary if the
+ // object is created FROM FILE; its data in storage is already valid.
+ m_OleClientSite.SaveObject();
+
+ // we only want to DoVerb(SHOW) if this is an InsertNew object.
+ // we should NOT DoVerb(SHOW) if the object is created FromFile.
+ m_lpOleObject->DoVerb(
+ OLEIVERB_SHOW,
+ NULL,
+ &m_OleClientSite,
+ -1,
+ m_lpDoc->m_hDocWnd,
+ &rect);
+ }
+}
+
+//**********************************************************************
+//
+// CSimpleSite::PaintObj
+//
+// Purpose:
+//
+// Paints the object
+//
+// Parameters:
+//
+// HDC hDC - Device context of the document window
+//
+// Return Value:
+// None
+//
+// Function Calls:
+// Function Location
+//
+// CSimpleSite::GetObjRect SITE.CPP
+// IOleObject::QueryInterface Object
+// IViewObject::GetColorSet Object
+// IViewObject::Release Object
+// SetROP2 Windows API
+// Rectamgle Windows API
+// CreateHatchBrush Windows API
+// SelectObject Windows API
+// DeleteObject Windows API
+// CreatePalette Windows API
+// SelectPalette Windows API
+// RealizePalette Windows API
+// OleStdFree OLE2UI Function
+// OleDraw OLE API
+//
+//
+//********************************************************************
+
+void CSimpleSite::PaintObj(HDC hDC)
+{
+ RECT rect;
+
+ // need to check to make sure there is a valid object
+ // available. This is needed if there is a paint msg
+ // between the time that CSimpleSite is instantiated
+ // and OleUIInsertObject returns.
+ if (!m_lpOleObject)
+ return;
+
+ // convert it to pixels
+ GetObjRect(&rect);
+
+ LPLOGPALETTE pColorSet = NULL;
+ LPVIEWOBJECT lpView = NULL;
+
+ // get a pointer to IViewObject
+ m_lpOleObject->QueryInterface(IID_IViewObject,(LPVOID FAR *) &lpView);
+
+ // if the QI succeeds, get the LOGPALETTE for the object
+ if (lpView)
+ lpView->GetColorSet(m_dwDrawAspect, -1, NULL, NULL, NULL, &pColorSet);
+
+ HPALETTE hPal=NULL;
+ HPALETTE hOldPal=NULL;
+
+ // if a LOGPALETTE was returned (not guarateed), create the palette and
+ // realize it.NOTE:A smarter application would want to get the LOGPALETTE
+ // for each of its visible objects, and try to create a palette that
+ // satisfies all of the visible objects. ALSO: OleStdFree() is use to
+ // free the returned LOGPALETTE.
+ if ((pColorSet))
+ {
+ hPal = CreatePalette((const LPLOGPALETTE) pColorSet);
+ hOldPal = SelectPalette(hDC, hPal, FALSE);
+ RealizePalette(hDC);
+ OleStdFree(pColorSet);
+ }
+
+ // draw the object
+ HRESULT hRes;
+ hRes = OleDraw(m_lpOleObject, m_dwDrawAspect, hDC, &rect);
+ if ((hRes != ResultFromScode(S_OK)) &&
+ (hRes != ResultFromScode(OLE_E_BLANK)) &&
+ (hRes != ResultFromScode(DV_E_NOIVIEWOBJECT)))
+ {
+ TestDebugOut(TEXT("Fail in OleDraw\n"));
+ }
+
+ // if the object is open, draw a hatch rect.
+ if (m_fObjectOpen)
+ {
+ HBRUSH hBrush = CreateHatchBrush ( HS_BDIAGONAL, RGB(0,0,0) );
+ HBRUSH hOldBrush = (HBRUSH) SelectObject (hDC, hBrush);
+ SetROP2(hDC, R2_MASKPEN);
+ Rectangle (hDC, rect.left, rect.top, rect.right, rect.bottom);
+ SelectObject(hDC, hOldBrush);
+ DeleteObject(hBrush);
+ }
+
+ // if we created a palette, restore the old one, and destroy
+ // the object.
+ if (hPal)
+ {
+ SelectPalette(hDC,hOldPal,FALSE);
+ DeleteObject(hPal);
+ }
+
+ // if a view pointer was successfully returned, it needs to be released.
+ if (lpView)
+ lpView->Release();
+}
+
+//**********************************************************************
+//
+// CSimpleSite::GetObjRect
+//
+// Purpose:
+//
+// Retrieves the rect of the object in pixels
+//
+// Parameters:
+//
+// LPRECT lpRect - Rect structure filled with object's rect in pixels
+//
+// Return Value:
+// None
+//
+// Function Calls:
+// Function Location
+//
+// XformWidthInHimetricToPixels OLE2UI Function
+// XformHeightInHimetricToPixels OLE2UI Function
+//
+//
+//********************************************************************
+
+void CSimpleSite::GetObjRect(LPRECT lpRect)
+{
+ // convert it to pixels
+ lpRect->left = lpRect->top = 0;
+ lpRect->right = XformWidthInHimetricToPixels(NULL,(int)m_sizel.cx);
+ lpRect->bottom = XformHeightInHimetricToPixels(NULL,(int)m_sizel.cy);
+}
diff --git a/private/oleutest/simpcntr/site.h b/private/oleutest/simpcntr/site.h
new file mode 100644
index 000000000..ada86bcae
--- /dev/null
+++ b/private/oleutest/simpcntr/site.h
@@ -0,0 +1,53 @@
+//**********************************************************************
+// File name: SITE.H
+//
+// Definition of CSimpleSite
+//
+// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+#if !defined( _SITE_H_ )
+#define _SITE_H_
+
+#include <ole2.h>
+#include "ias.h"
+#include "ioips.h"
+#include "iocs.h"
+
+class CSimpleDoc;
+
+class CSimpleSite : public IUnknown
+{
+public:
+ int m_nCount;
+ DWORD m_dwConnection;
+ LPOLEOBJECT m_lpOleObject;
+ LPOLEINPLACEOBJECT m_lpInPlaceObject;
+ HWND m_hwndIPObj;
+ DWORD m_dwDrawAspect;
+ SIZEL m_sizel;
+ BOOL m_fInPlaceActive;
+ BOOL m_fObjectOpen;
+ LPSTORAGE m_lpObjStorage;
+
+ CAdviseSink m_AdviseSink;
+ COleInPlaceSite m_OleInPlaceSite;
+ COleClientSite m_OleClientSite;
+
+ CSimpleDoc FAR * m_lpDoc;
+
+ // IUnknown Interfaces
+ STDMETHODIMP QueryInterface(REFIID riid, LPVOID FAR* ppvObj);
+ STDMETHODIMP_(ULONG) AddRef();
+ STDMETHODIMP_(ULONG) Release();
+
+ void InitObject(BOOL fCreateNew);
+ static CSimpleSite FAR * Create(CSimpleDoc FAR *lpDoc);
+ CSimpleSite(CSimpleDoc FAR *lpDoc);
+ ~CSimpleSite();
+ void PaintObj(HDC hDC);
+ void GetObjRect(LPRECT lpRect);
+ void CloseOleObject(void);
+ void UnloadOleObject(void);
+};
+
+#endif
diff --git a/private/oleutest/simpcntr/tests.cpp b/private/oleutest/simpcntr/tests.cpp
new file mode 100644
index 000000000..48a535d88
--- /dev/null
+++ b/private/oleutest/simpcntr/tests.cpp
@@ -0,0 +1,202 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: tests.cpp
+//
+// Contents: Implementations of the Upper Layer unit tests for Inplace
+//
+// Classes:
+//
+// Functions: Test1
+//
+// History: dd-mmm-yy Author Comment
+// 27-Apr-94 ricksa author
+//
+//--------------------------------------------------------------------------
+
+#include "pre.h"
+#include "iocs.h"
+#include "ias.h"
+#include "ioipf.h"
+#include "ioips.h"
+#include "app.h"
+#include "site.h"
+#include "doc.h"
+#include "tests.h"
+#include "utaccel.h"
+
+const CLSID CLSID_SimpleServer = {0xbcf6d4a0, 0xbe8c, 0x1068, { 0xb6, 0xd4,
+ 0x00, 0xdd, 0x01, 0x0c, 0x05, 0x09 }};
+
+const TCHAR *pszErrorTitle = TEXT("Unit Test FAILURE");
+
+//+-------------------------------------------------------------------------
+//
+// Function: TestMsgPostThread
+//
+// Synopsis: We use this thread to post messages to the inplace server
+//
+// Arguments: [pvApp] - application object
+//
+// Algorithm: Post key board message for the accelerator for the container
+// and wait 3 seconds to see if we get response. If we do, then
+// continue by posting an accelerator to the embeddinging and
+// waiting three seconds for a response. Finally post messages
+// to everyone telling them the test is over.
+//
+// History: dd-mmm-yy Author Comment
+// 02-May-94 ricksa author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+extern "C" DWORD TestMsgPostThread(void *pvApp)
+{
+ CSimpleApp *pApp = (CSimpleApp *) pvApp;
+ HRESULT hr = ResultFromScode(E_UNEXPECTED);
+
+ // Send an accelerator bound for the container
+ PostMessage(pApp->m_hwndUIActiveObj, WM_CHAR, SIMPCNTR_UT_ACCEL, 1);
+
+ // Give 6 seconds for chance to process an accelerator
+ for (int i = 0; i < 6; i++)
+ {
+ // Get embedding and container a chance to process the accelerator
+ Sleep(1000);
+
+ // See if it got processed
+ if (pApp->m_fGotUtestAccelerator)
+ {
+ break;
+ }
+ }
+
+ if (pApp->m_fGotUtestAccelerator)
+ {
+ hr = S_OK;
+ }
+ else
+ {
+ // The container did not received the accelerator
+ MessageBox(pApp->m_hAppWnd,
+ TEXT("Container didn't recieve accelerator"),
+ pszErrorTitle, MB_OK);
+ }
+
+ PostMessage(pApp->m_hDriverWnd, WM_TESTEND,
+ SUCCEEDED(hr) ? TEST_SUCCESS : TEST_FAILURE, (LPARAM) hr);
+
+ PostMessage(pApp->m_hAppWnd, WM_SYSCOMMAND, SC_CLOSE, 0L);
+
+ return 0;
+}
+
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: Test1
+//
+// Synopsis: Inserts an inplace object into this container
+//
+// Arguments: pApp -- a pointer to the CSimpleApp that we're a part of
+//
+// Algorithm: Create a simple server object. Activate the simple server
+// object. Send the container an accelerator and confirm that
+// the accelerator worked. Send the object an accelerator and
+// make sure that that accelerator worked. Then return the
+// result of the test to the test driver.
+//
+// History: dd-mmm-yy Author Comment
+// 27-Apr-94 ricksa author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+void Test1(CSimpleApp *pApp)
+{
+ // Create the inplace object
+ HRESULT hr;
+ static FORMATETC formatetc;
+
+ //insert the simple server object
+
+ formatetc.dwAspect = DVASPECT_CONTENT;
+ formatetc.cfFormat = NULL;
+ formatetc.lindex = -1;
+
+ //need to create the client site
+
+ pApp->m_lpDoc->m_lpSite = CSimpleSite::Create(pApp->m_lpDoc);
+
+ hr = OleCreate(
+ CLSID_SimpleServer,
+ IID_IOleObject,
+ OLERENDER_DRAW,
+ &formatetc,
+ &pApp->m_lpDoc->m_lpSite->m_OleClientSite,
+ pApp->m_lpDoc->m_lpSite->m_lpObjStorage,
+ (void **) &(pApp->m_lpDoc->m_lpSite->m_lpOleObject));
+
+ if(hr == NOERROR)
+ {
+ // Activate the inplace object
+ pApp->m_lpDoc->m_lpSite->InitObject(TRUE);
+
+ // Default to unexpected failure
+ hr = ResultFromScode(E_UNEXPECTED);
+
+ if (pApp->m_lpDoc->m_fInPlaceActive)
+ {
+ // Create thread to send windows messages to container and
+ // embedding
+ DWORD dwThreadId;
+
+ HANDLE hThread = CreateThread(
+ NULL, // Security attributes - default
+ 0, // Stack size - default
+ TestMsgPostThread, // Addresss of thread function
+ pApp, // Parameter to thread
+ 0, // Flags - run immediately
+ &dwThreadId); // Thread ID returned - unused.
+
+ if (hThread != NULL)
+ {
+ // Thread was created so tell routine & dump handle
+ // we won't use.
+ hr = S_OK;
+ CloseHandle(hThread);
+ }
+ else
+ {
+ // The container did not received the accelerator
+ MessageBox(pApp->m_hAppWnd,
+ TEXT("Could not create message sending thread"),
+ pszErrorTitle, MB_OK);
+ }
+ }
+ else
+ {
+ // The object did not get activated in place
+ MessageBox(pApp->m_hAppWnd, TEXT("Could not activate in place"),
+ pszErrorTitle, MB_OK);
+ }
+ }
+ else
+ {
+ // We could not create the object
+ MessageBox(pApp->m_hAppWnd, TEXT("Could not create embedding"),
+ pszErrorTitle, MB_OK);
+ }
+
+ if (FAILED(hr))
+ {
+ PostMessage(pApp->m_hDriverWnd, WM_TESTEND,
+ SUCCEEDED(hr) ? TEST_SUCCESS : TEST_FAILURE, (LPARAM) hr);
+ }
+
+ return;
+}
diff --git a/private/oleutest/simpcntr/tests.h b/private/oleutest/simpcntr/tests.h
new file mode 100644
index 000000000..c4183e7ec
--- /dev/null
+++ b/private/oleutest/simpcntr/tests.h
@@ -0,0 +1,8 @@
+#ifndef _TESTS_H_
+#define _TESTS_H_
+
+#include <testmess.h>
+
+void Test1(CSimpleApp *pApp);
+
+#endif // _TESTS_H_
diff --git a/private/oleutest/simpcntr/utaccel.h b/private/oleutest/simpcntr/utaccel.h
new file mode 100644
index 000000000..c40b4655b
--- /dev/null
+++ b/private/oleutest/simpcntr/utaccel.h
@@ -0,0 +1,7 @@
+#ifndef _UTACCEL_H_
+#define _UTACCEL_H_
+
+#define SIMPCNTR_UT_ACCEL 1
+#define SIMPSVR_UT_ACCEL 3
+
+#endif // _UTACCEL_H_
diff --git a/private/oleutest/simpdnd/app.cpp b/private/oleutest/simpdnd/app.cpp
new file mode 100644
index 000000000..63c093945
--- /dev/null
+++ b/private/oleutest/simpdnd/app.cpp
@@ -0,0 +1,852 @@
+//**********************************************************************
+// File name: app.cpp
+//
+// Implementation file for the CSimpleApp Class
+//
+// Functions:
+//
+// See app.h for a list of member functions.
+//
+// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+
+#include "pre.h"
+#include "iocs.h"
+#include "ias.h"
+#include "app.h"
+#include "site.h"
+#include "doc.h"
+#include <testmess.h>
+
+
+#ifdef WIN32
+extern BOOL CALLBACK About(HWND hDlg,UINT message,WPARAM wParam,LPARAM lParam);
+#endif
+
+//**********************************************************************
+//
+// CSimpleApp::CSimpleApp()
+//
+// Purpose:
+//
+// Constructor for CSimpleApp
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+//********************************************************************
+CSimpleApp::CSimpleApp()
+{
+ TestDebugOut("In CSimpleApp's Constructor \r\n");
+
+ // Set Ref Count
+ m_nCount = 0;
+
+ // clear members
+ m_hAppWnd = NULL;
+ m_hInst = NULL;
+ m_lpDoc = NULL;
+
+ // clear flags
+ m_fInitialized = FALSE;
+
+ // Initialize effects we allow.
+ m_dwSourceEffect = DROPEFFECT_COPY | DROPEFFECT_MOVE;
+ m_dwTargetEffect = DROPEFFECT_COPY | DROPEFFECT_MOVE;
+}
+
+//**********************************************************************
+//
+// CSimpleApp::~CSimpleApp()
+//
+// Purpose:
+//
+// Destructor for CSimpleApp Class.
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// OutdebugString Windows API
+// OleUninitialize OLE API
+//
+//
+//********************************************************************
+
+CSimpleApp::~CSimpleApp()
+{
+ TestDebugOut("In CSimpleApp's Destructor\r\n");
+
+ // need to uninit the library...
+ if (m_fInitialized)
+ OleUninitialize();
+}
+
+//**********************************************************************
+//
+// CSimpleApp::DestroyDocs()
+//
+// Purpose:
+//
+// Destroys all of the open documents in the application (Only one
+// since this is an SDI app, but could easily be modified to
+// support MDI).
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// CSimpleDoc::Close DOC.CPP
+//
+//********************************************************************
+
+void CSimpleApp::DestroyDocs()
+{
+ m_lpDoc->Close(); // we have only 1 document
+}
+
+//**********************************************************************
+//
+// CSimpleApp::QueryInterface
+//
+// Purpose:
+//
+// Used for interface negotiation at the Application level.
+//
+// Parameters:
+//
+// REFIID riid - A reference to the interface that is
+// being queried.
+//
+// LPVOID FAR* ppvObj - An out parameter to return a pointer to
+// the interface.
+//
+// Return Value:
+//
+// S_OK - The interface is supported.
+// S_FALSE - The interface is not supported
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// ResultFromScode OLE API
+//
+//********************************************************************
+
+STDMETHODIMP CSimpleApp::QueryInterface(REFIID riid, LPVOID FAR* ppvObj)
+{
+ TestDebugOut("In CSimpleApp::QueryInterface\r\n");
+
+ *ppvObj = NULL; // must set out pointer parameters to NULL
+
+ // Not a supported interface
+ return ResultFromScode(E_NOINTERFACE);
+}
+
+//**********************************************************************
+//
+// CSimpleApp::AddRef
+//
+// Purpose:
+//
+// Adds to the reference count at the Application level.
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// ULONG - The new reference count of the application.
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+// Comments:
+//
+// Due to the reference counting model that is used in this
+// implementation, this reference count is the sum of the
+// reference counts on all interfaces of all objects open
+// in the application.
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) CSimpleApp::AddRef()
+{
+ TestDebugOut("In CSimpleApp::AddRef\r\n");
+ return ++m_nCount;
+}
+
+//**********************************************************************
+//
+// CSimpleApp::Release
+//
+// Purpose:
+//
+// Decrements the reference count at the application level
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// ULONG - The new reference count of the application.
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) CSimpleApp::Release()
+{
+ TestDebugOut("In CSimpleApp::Release\r\n");
+
+ if (--m_nCount == 0)
+ {
+ delete this;
+ return 0;
+ }
+ return m_nCount;
+}
+
+//**********************************************************************
+//
+// CSimpleApp::fInitApplication
+//
+// Purpose:
+//
+// Initializes the application
+//
+// Parameters:
+//
+// HANDLE hInstance - Instance handle of the application.
+//
+// Return Value:
+//
+// TRUE - Application was successfully initialized.
+// FALSE - Application could not be initialized
+//
+// Function Calls:
+// Function Location
+//
+// LoadIcon Windows API
+// LoadCursor Windows API
+// GetStockObject Windows API
+// RegisterClass Windows API
+//
+//
+//********************************************************************
+
+BOOL CSimpleApp::fInitApplication(HANDLE hInstance)
+{
+ WNDCLASS wc;
+
+ // Fill in window class structure with parameters that describe the
+ // main window.
+
+ wc.style = NULL; // Class style(s).
+ wc.lpfnWndProc = MainWndProc; // Function to retrieve messages for
+ // windows of this class.
+ wc.cbClsExtra = 0; // No per-class extra data.
+ wc.cbWndExtra = 0; // No per-window extra data.
+ wc.hInstance =(HINSTANCE) hInstance; // Application that owns
+ // the class.
+ wc.hIcon = LoadIcon((HINSTANCE)hInstance,TEXT("SimpDnd"));
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
+ wc.lpszMenuName = TEXT("SIMPLEMENU"); // Name of menu resource in
+ // .RC file.
+ wc.lpszClassName = TEXT("SimpDndAppWClass"); // Name used in
+ // CreateWindow call.
+
+ if (!RegisterClass(&wc))
+ return FALSE;
+
+ wc.style = CS_DBLCLKS; // Class style(s). allow DBLCLK's
+ wc.lpfnWndProc = DocWndProc; // Function to retrieve messages for
+ // windows of this class.
+ wc.cbClsExtra = 0; // No per-class extra data.
+ wc.cbWndExtra = 0; // No per-window extra data.
+ wc.hInstance = (HINSTANCE) hInstance; // Application that owns
+ // the class.
+ wc.hIcon = NULL;
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
+ wc.lpszMenuName = NULL;
+ wc.lpszClassName = TEXT("SimpDndDocWClass"); // Name used in
+ //CreateWindow call.
+
+ // Register the window class and return success/failure code.
+
+ return (RegisterClass(&wc));
+}
+
+//**********************************************************************
+//
+// CSimpleApp::fInitInstance
+//
+// Purpose:
+//
+// Instance initialization.
+//
+// Parameters:
+//
+// HANDLE hInstance - App. Instance Handle.
+//
+// int nCmdShow - Show parameter from WinMain
+//
+// Return Value:
+//
+// TRUE - Initialization Successful
+// FALSE - Initialization Failed.
+//
+//
+// Function Calls:
+// Function Location
+//
+// CreateWindow Windows API
+// ShowWindow Windows API
+// UpdateWindow Windows API
+// GetProfileInt Windows API
+// OleBuildVersion OLE API
+// OleInitialize OLE API
+// OleStdCreateDbAlloc OLE2UI
+//
+// Comments:
+//
+// Note that successful Initalization of the OLE libraries
+// is remembered so the UnInit is only called if needed.
+//
+//********************************************************************
+
+BOOL CSimpleApp::fInitInstance (HANDLE hInstance, int nCmdShow)
+{
+ LPMALLOC lpMalloc = NULL;
+
+#ifndef WIN32
+ /* Since OLE is part of the operating system in Win32, we don't need to
+ * check the version number in Win32.
+ */
+ DWORD dwVer = OleBuildVersion();
+
+ // check to see if we are compatible with this version of the libraries
+ if (HIWORD(dwVer) != rmm || LOWORD(dwVer) < rup)
+ {
+#ifdef _DEBUG
+ TestDebugOut("WARNING: Incompatible OLE library version\r\n");
+#else
+ return FALSE;
+#endif
+ }
+#endif // WIN32
+
+#if defined( _DEBUG )
+ /* OLE2NOTE: Use a special debug allocator to help track down
+ ** memory leaks.
+ */
+ OleStdCreateDbAlloc(0, &lpMalloc);
+#endif
+
+ // We try passing in our own allocator first - if that fails we
+ // try without overriding the allocator.
+
+ if (SUCCEEDED(OleInitialize(lpMalloc)) ||
+ SUCCEEDED(OleInitialize(NULL)))
+ {
+ m_fInitialized = TRUE;
+ }
+
+#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->Release();
+#endif
+
+ m_hInst = (HINSTANCE) hInstance;
+
+ // Create the "application" windows
+ m_hAppWnd = CreateWindow (TEXT("SimpDndAppWClass"),
+ TEXT("Simple OLE 2.0 Drag/Drop Container"),
+ WS_OVERLAPPEDWINDOW,
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ NULL,
+ NULL,
+ (HINSTANCE) hInstance,
+ NULL);
+
+ if (!m_hAppWnd)
+ return FALSE;
+
+ // if we have been launched by the test driver, tell it our window handle
+
+ if( m_hDriverWnd )
+ {
+ PostMessage(m_hDriverWnd, WM_TESTREG, (WPARAM)m_hAppWnd, 0);
+ }
+
+ // delay before dragging should start, in milliseconds
+ m_nDragDelay = GetProfileInt(
+ TEXT("windows"),
+ TEXT("DragDelay"),
+ DD_DEFDRAGDELAY
+ );
+
+ // minimum distance (radius) before drag should start, in pixels
+ m_nDragMinDist = GetProfileInt(
+ TEXT("windows"),
+ TEXT("DragMinDist"),
+ DD_DEFDRAGMINDIST
+ );
+
+ // delay before scrolling, in milliseconds
+ m_nScrollDelay = GetProfileInt(
+ TEXT("windows"),
+ TEXT("DragScrollDelay"),
+ DD_DEFSCROLLDELAY
+ );
+
+ // inset-width of the hot zone, in pixels
+ m_nScrollInset = GetProfileInt(
+ TEXT("windows"),
+ TEXT("DragScrollInset"),
+ DD_DEFSCROLLINSET
+ );
+
+ // scroll interval, in milliseconds
+ m_nScrollInterval = GetProfileInt(
+ TEXT("windows"),
+ TEXT("DragScrollInterval"),
+ DD_DEFSCROLLINTERVAL
+ );
+
+ ShowWindow (m_hAppWnd, nCmdShow);
+ UpdateWindow (m_hAppWnd);
+
+ return m_fInitialized;
+}
+
+
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Member: CSimpleApp::UpdateDragDropEffects
+//
+// Synopsis: Update drag/drop effects
+//
+// Arguments: [iMenuPos] - menu position either source or target
+// [iMenuCommand] - what command the menu selection maps to
+// [dwEffect] - new effects
+// [pdwEffectToUpdate] - where to store the effects
+//
+// Algorithm: Get the menu for either source or target. Then clear any
+// outstanding check marks. Check the appropriate item. Finally
+// update the effects that we allow.
+//
+// History: dd-mmm-yy Author Comment
+// 06-May-94 Ricksa author
+//
+//--------------------------------------------------------------------------
+void CSimpleApp::UpdateDragDropEffects(
+ int iMenuPos,
+ int iMenuCommand,
+ DWORD dwEffect,
+ DWORD *pdwEffectToUpdate)
+{
+ // Get the menu that we want to process
+ HMENU hMenuItem = GetSubMenu(m_hHelpMenu, iMenuPos);
+
+ // Clear any current check marks
+ for (int i = 0; i < 3; i++)
+ {
+ CheckMenuItem(hMenuItem, i, MF_BYPOSITION | MF_UNCHECKED);
+ }
+
+ // Check the appropriate item.
+ CheckMenuItem(hMenuItem, iMenuCommand, MF_BYCOMMAND | MF_CHECKED);
+ *pdwEffectToUpdate = dwEffect;
+}
+
+
+//**********************************************************************
+//
+// CSimpleApp::lCommandHandler
+//
+// Purpose:
+//
+// Handles the processing of WM_COMMAND.
+//
+// Parameters:
+//
+// HWND hWnd - Handle to the application Window
+//
+// UINT message - message (always WM_COMMAND)
+//
+// WPARAM wParam - Same as passed to the WndProc
+//
+// LPARAM lParam - Same as passed to the WndProc
+//
+// Return Value:
+//
+// NULL
+//
+// Function Calls:
+// Function Location
+//
+// IOleObject::DoVerb Object
+// GetClientRect Windows API
+// MessageBox Windows API
+// DialogBox Windows API
+// MakeProcInstance Windows API
+// FreeProcInstance Windows API
+// SendMessage Windows API
+// DefWindowProc Windows API
+// CSimpleDoc::InsertObject DOC.CPP
+// CSimpleDoc::CopyObjectToClip DOC.CPP
+// CSimpleDoc::Close DOC.CPP
+//
+//********************************************************************
+
+long CSimpleApp::lCommandHandler (HWND hWnd, UINT message,
+ WPARAM wParam, LPARAM lParam)
+{
+ RECT rect;
+
+ // see if the command is a verb selections
+ if (wParam >= IDM_VERB0)
+ {
+ // get the rectangle of the object
+ m_lpDoc->m_lpSite->GetObjRect(&rect);
+
+ if (m_lpDoc->m_lpSite->m_lpOleObject->DoVerb(
+ wParam - IDM_VERB0, NULL,
+ &m_lpDoc->m_lpSite->m_OleClientSite, -1,
+ m_lpDoc->m_hDocWnd, &rect)
+ != ResultFromScode(S_OK))
+ {
+ TestDebugOut("Fail in IOleObject::DoVerb\n");
+ }
+ }
+ else
+ {
+ switch (wParam)
+ {
+ // bring up the About box
+ case IDM_ABOUT:
+ {
+#ifdef WIN32
+ DialogBox(m_hInst, // current instance
+ TEXT("AboutBox"), // resource to use
+ m_hAppWnd, // parent handle
+ About); // About() instance address
+#else
+ FARPROC lpProcAbout = MakeProcInstance((FARPROC)About,
+ m_hInst);
+
+ DialogBox(m_hInst, // current instance
+ TEXT("AboutBox"), // resource to use
+ m_hAppWnd, // parent handle
+ lpProcAbout); // About() instance address
+
+ FreeProcInstance(lpProcAbout);
+#endif
+ break;
+ }
+
+ // bring up the InsertObject Dialog
+ case IDM_INSERTOBJECT:
+ m_lpDoc->InsertObject();
+ break;
+
+ // Copy the object to the Clipboard
+ case IDM_COPY:
+ m_lpDoc->CopyObjectToClip();
+ break;
+
+ // exit the application
+ case IDM_EXIT:
+ SendMessage(hWnd, WM_SYSCOMMAND, SC_CLOSE, 0L);
+ break;
+
+ case IDM_NEW:
+ lCreateDoc(hWnd, 0, 0, 0);
+ break;
+
+ // Only allow copy from the source
+ case IDM_SOURCE_COPY:
+ UpdateDragDropEffects(SOURCE_EFFECTS_MENU_POS,
+ IDM_SOURCE_COPY, DROPEFFECT_COPY, &m_dwSourceEffect);
+ break;
+
+ // Only allow move from the source
+ case IDM_SOURCE_MOVE:
+ UpdateDragDropEffects(SOURCE_EFFECTS_MENU_POS,
+ IDM_SOURCE_MOVE, DROPEFFECT_MOVE, &m_dwSourceEffect);
+ break;
+
+ // Allow both copy and move from the source
+ case IDM_SOURCE_COPYMOVE:
+ UpdateDragDropEffects(SOURCE_EFFECTS_MENU_POS,
+ IDM_SOURCE_COPYMOVE, DROPEFFECT_COPY | DROPEFFECT_MOVE,
+ &m_dwSourceEffect);
+ break;
+
+ // Only accept copy in target
+ case IDM_TARGET_COPY:
+ UpdateDragDropEffects(TARGET_EFFECTS_MENU_POS,
+ IDM_TARGET_COPY, DROPEFFECT_COPY, &m_dwTargetEffect);
+ break;
+
+ // Only accept move in target
+ case IDM_TARGET_MOVE:
+ UpdateDragDropEffects(TARGET_EFFECTS_MENU_POS,
+ IDM_TARGET_MOVE, DROPEFFECT_MOVE, &m_dwTargetEffect);
+ break;
+
+ // Accept both move and copy in the target
+ case IDM_TARGET_COPYMOVE:
+ UpdateDragDropEffects(TARGET_EFFECTS_MENU_POS,
+ IDM_TARGET_COPYMOVE, DROPEFFECT_COPY | DROPEFFECT_MOVE,
+ &m_dwTargetEffect);
+ break;
+
+ default:
+ return (DefWindowProc(hWnd, message, wParam, lParam));
+ } // end of switch
+
+ } // end of else
+
+ return NULL;
+}
+
+//**********************************************************************
+//
+// CSimpleApp::lSizeHandler
+//
+// Purpose:
+//
+// Handles the WM_SIZE message
+//
+// Parameters:
+//
+// HWND hWnd - Handle to the application Window
+//
+// UINT message - message (always WM_SIZE)
+//
+// WPARAM wParam - Same as passed to the WndProc
+//
+// LPARAM lParam - Same as passed to the WndProc
+//
+// Return Value:
+//
+// LONG - returned from the "document" resizing
+//
+// Function Calls:
+// Function Location
+//
+// GetClientRect Windows API
+// CSimpleDoc::lResizeDoc DOC.CPP
+//
+//
+//********************************************************************
+
+long CSimpleApp::lSizeHandler (HWND hWnd, UINT message,
+ WPARAM wParam, LPARAM lParam)
+{
+ RECT rect;
+
+ GetClientRect(m_hAppWnd, &rect);
+ return m_lpDoc->lResizeDoc(&rect);
+}
+
+//**********************************************************************
+//
+// CSimpleApp::lCreateDoc
+//
+// Purpose:
+//
+// Handles the creation of a document object.
+//
+// Parameters:
+//
+// HWND hWnd - Handle to the application Window
+//
+// UINT message - message (always WM_CREATE)
+//
+// WPARAM wParam - Same as passed to the WndProc
+//
+// LPARAM lParam - Same as passed to the WndProc
+//
+// Return Value:
+//
+// NULL
+//
+// Function Calls:
+// Function Location
+//
+// GetClientRect Windows API
+// CSimpleDoc::CSimpleDoc DOC.CPP
+//
+//
+//********************************************************************
+
+long CSimpleApp::lCreateDoc (HWND hWnd, UINT message,
+ WPARAM wParam, LPARAM lParam)
+{
+ RECT rect;
+ static BOOL fFirstTime = TRUE;
+
+ if (m_lpDoc != NULL)
+ {
+ // There is a document defined already so we close it without
+ // saving which is equivalent to deleting the object.
+ m_lpDoc->Close();
+ m_lpDoc = NULL;
+ }
+
+ GetClientRect(hWnd, &rect);
+
+ m_lpDoc = CSimpleDoc::Create(this, &rect, hWnd);
+
+ // First time initialization - for some reason the doc sets the
+ // the application's m_hHelpMenu which we need. So we do the
+ // initialization here.
+ if (fFirstTime)
+ {
+ fFirstTime = FALSE;
+
+ // Check default allowed effects for the source
+ UpdateDragDropEffects(SOURCE_EFFECTS_MENU_POS, IDM_SOURCE_COPYMOVE,
+ m_dwSourceEffect, &m_dwSourceEffect);
+
+ // Check default allowed effects for the target
+ UpdateDragDropEffects(TARGET_EFFECTS_MENU_POS, IDM_TARGET_COPYMOVE,
+ m_dwTargetEffect, &m_dwTargetEffect);
+ }
+
+ return NULL;
+}
+
+//**********************************************************************
+//
+// CSimpleApp::HandleAccelerators
+//
+// Purpose:
+//
+// To properly handle accelerators in the Message Loop
+//
+// Parameters:
+//
+// LPMSG lpMsg - A pointer to the message structure.
+//
+// Return Value:
+//
+// TRUE - The accelerator was handled
+// FALSE - The accelerator was not handled
+//
+// Function Calls:
+// Function Location
+//
+//
+//********************************************************************
+
+BOOL CSimpleApp::HandleAccelerators(LPMSG lpMsg)
+{
+ BOOL retval = FALSE;
+
+ // we do not have any accelerators
+
+ return retval;
+}
+
+//**********************************************************************
+//
+// CSimpleApp::PaintApp
+//
+// Purpose:
+//
+// Handles the painting of the doc window.
+//
+//
+// Parameters:
+//
+// HDC hDC - hDC to the Doc Window.
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// CSimpleDoc::PaintDoc DOC.CPP
+//
+// Comments:
+//
+// This is an app level function in case we want to do palette
+// management.
+//
+//********************************************************************
+
+void CSimpleApp::PaintApp (HDC hDC)
+{
+ // at this level, we could enumerate through all of the
+ // visible objects in the application, so that a palette
+ // that best fits all of the objects can be built.
+
+ // This app is designed to take on the same palette
+ // functionality that was provided in OLE 1.0, the palette
+ // of the last object drawn is realized. Since we only
+ // support one object at a time, it shouldn't be a big
+ // deal.
+
+ // if we supported multiple documents, we would enumerate
+ // through each of the open documents and call paint.
+
+ if (m_lpDoc)
+ {
+ m_lpDoc->PaintDoc(hDC);
+ }
+
+}
+
+
diff --git a/private/oleutest/simpdnd/app.h b/private/oleutest/simpdnd/app.h
new file mode 100644
index 000000000..37f827897
--- /dev/null
+++ b/private/oleutest/simpdnd/app.h
@@ -0,0 +1,67 @@
+//**********************************************************************
+// File name: app.h
+//
+// Definition of CSimpleApp
+//
+// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+
+#if !defined( _APP_H_)
+#define _APP_H_
+
+#include <ole2.h>
+
+class CSimpleDoc;
+
+class CSimpleApp : public IUnknown
+{
+public:
+
+ int m_nCount; // reference count
+ HWND m_hAppWnd; // main window handle
+ HWND m_hDriverWnd; // window handle for the driver app.
+ HINSTANCE m_hInst; // application instance
+ CSimpleDoc FAR * m_lpDoc; // pointer to document object
+ BOOL m_fInitialized; // OLE initialization flag
+ HMENU m_hMainMenu;
+ HMENU m_hFileMenu;
+ HMENU m_hEditMenu;
+ HMENU m_hHelpMenu;
+ HMENU m_hCascadeMenu; // OLE object's verb
+
+ // Drag/Drop related fields
+ 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)
+
+ DWORD m_dwSourceEffect; // Allowed effects to source
+ DWORD m_dwTargetEffect; // Allowed target effects
+
+ CSimpleApp(); // Constructor
+ ~CSimpleApp(); // Destructor
+
+ // IUnknown Interfaces
+ STDMETHODIMP QueryInterface(REFIID riid, LPVOID FAR* ppvObj);
+ STDMETHODIMP_(ULONG) AddRef();
+ STDMETHODIMP_(ULONG) Release();
+
+ // Initialization methods
+
+ BOOL fInitApplication (HANDLE hInstance);
+ BOOL fInitInstance (HANDLE hInstance, int nCmdShow);
+
+ // Message handling methods
+
+ long lCommandHandler (HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam);
+ long lSizeHandler (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
+ long lCreateDoc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
+ BOOL HandleAccelerators (LPMSG lpMsg);
+ void PaintApp(HDC hDC);
+ void DestroyDocs();
+ void UpdateDragDropEffects(int iMenuPos, int iMenuCommand, DWORD dwEffect,
+ DWORD *pdwEffectToUpdate);
+};
+
+#endif // _APP_H_
diff --git a/private/oleutest/simpdnd/bang.ico b/private/oleutest/simpdnd/bang.ico
new file mode 100644
index 000000000..90fe0f220
--- /dev/null
+++ b/private/oleutest/simpdnd/bang.ico
Binary files differ
diff --git a/private/oleutest/simpdnd/daytona/makefile b/private/oleutest/simpdnd/daytona/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/oleutest/simpdnd/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/simpdnd/daytona/sources b/private/oleutest/simpdnd/daytona/sources
new file mode 100644
index 000000000..170bbe1c1
--- /dev/null
+++ b/private/oleutest/simpdnd/daytona/sources
@@ -0,0 +1,41 @@
+TARGETNAME=SIMPDND
+TARGETTYPE=PROGRAM
+TARGETPATH=OBJ
+TARGETLIBS= \
+ $(GUI32_LIBS) \
+ $(WIN32_LIBS) \
+ $(CRT_LIBS) \
+ $(NT_CRT) \
+ $(LIBRARY_PATH)\ole32.lib \
+ $(LIBRARY_PATH)\shell32.lib \
+ $(LIBRARY_PATH)\comdlg32.lib \
+ ..\..\letest\ole2ui\daytona\obj\*\ole2u32a.lib \
+ $(LIBRARY_PATH)\uuid.lib
+
+BLDCRT=1
+UMTYPE=windows
+UMENTRY=winmain
+#UMLIBS= \
+# ..\..\libs\daytona\*\common.lib
+
+INCLUDES=..;..\oletest;..\..\letest\ole2ui;..\..\inc
+
+C_DEFINES=-DWIN32-DDEBUG -DINC_OLE2 -DCLIENT -DWINDOWS
+
+NTDEBUG=ntsd
+NTDEBUGTYPE=both
+MSC_OPTIMIZATION=/Od
+
+SOURCES= \
+..\APP.CPP \
+..\DOC.CPP \
+..\DXFEROBJ.CPP \
+..\IAS.CPP \
+..\IDS.CPP \
+..\IDT.CPP \
+..\IOCS.CPP \
+..\PRE.CPP \
+..\SIMPDND.CPP \
+..\SITE.CPP \
+..\TESTS.CPP \
+..\SIMPDND.RC
diff --git a/private/oleutest/simpdnd/default.ico b/private/oleutest/simpdnd/default.ico
new file mode 100644
index 000000000..4542c57d3
--- /dev/null
+++ b/private/oleutest/simpdnd/default.ico
Binary files differ
diff --git a/private/oleutest/simpdnd/depend.mk b/private/oleutest/simpdnd/depend.mk
new file mode 100644
index 000000000..42246732a
--- /dev/null
+++ b/private/oleutest/simpdnd/depend.mk
@@ -0,0 +1,227 @@
+#
+# Built automatically
+#
+
+#
+# Source files
+#
+
+$(OBJDIR)\app.obj $(OBJDIR)\app.lst: .\app.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\ole2ver.h \
+ $(CAIROLE)\h\export\oleguid.h $(CAIROLE)\h\export\scode.h \
+ $(CAIROLE)\h\export\storage.h $(COMMON)\ih\winnot.h \
+ $(COMMONINC)\disptype.h $(COMMONINC)\stgprop.h $(CRTINC)\assert.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)\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\ole2ui.h ..\ole2ui\olestd.h .\app.h \
+ .\doc.h .\ias.h .\ids.h .\idt.h .\iocs.h .\pre.h .\resource.h \
+ .\simpdnd.h .\site.h
+
+$(OBJDIR)\doc.obj $(OBJDIR)\doc.lst: .\doc.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\ole2ver.h \
+ $(CAIROLE)\h\export\oleguid.h $(CAIROLE)\h\export\scode.h \
+ $(CAIROLE)\h\export\storage.h $(COMMON)\ih\winnot.h \
+ $(COMMONINC)\disptype.h $(COMMONINC)\stgprop.h $(CRTINC)\assert.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)\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\ole2ui.h ..\ole2ui\olestd.h .\dxferobj.h \
+ .\app.h .\doc.h .\ias.h .\ids.h .\idt.h .\iocs.h .\pre.h \
+ .\resource.h .\simpdnd.h .\site.h
+
+$(OBJDIR)\dxferobj.obj $(OBJDIR)\dxferobj.lst: .\dxferobj.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\ole2ver.h $(CAIROLE)\h\export\oleguid.h \
+ $(CAIROLE)\h\export\scode.h $(CAIROLE)\h\export\storage.h \
+ $(COMMON)\ih\winnot.h $(COMMONINC)\disptype.h $(COMMONINC)\stgprop.h \
+ $(CRTINC)\assert.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)\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\enumfetc.h \
+ ..\ole2ui\ole2ui.h ..\ole2ui\olestd.h .\dxferobj.h .\ias.h .\iocs.h \
+ .\pre.h .\resource.h .\simpdnd.h .\site.h
+
+$(OBJDIR)\ias.obj $(OBJDIR)\ias.lst: .\ias.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\ole2ver.h \
+ $(CAIROLE)\h\export\oleguid.h $(CAIROLE)\h\export\scode.h \
+ $(CAIROLE)\h\export\storage.h $(COMMON)\ih\winnot.h \
+ $(COMMONINC)\disptype.h $(COMMONINC)\stgprop.h $(CRTINC)\assert.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)\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\ole2ui.h ..\ole2ui\olestd.h .\app.h \
+ .\doc.h .\ias.h .\ids.h .\idt.h .\iocs.h .\pre.h .\resource.h \
+ .\simpdnd.h .\site.h
+
+$(OBJDIR)\ids.obj $(OBJDIR)\ids.lst: .\ids.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\ole2ver.h \
+ $(CAIROLE)\h\export\oleguid.h $(CAIROLE)\h\export\scode.h \
+ $(CAIROLE)\h\export\storage.h $(COMMON)\ih\winnot.h \
+ $(COMMONINC)\disptype.h $(COMMONINC)\stgprop.h $(CRTINC)\assert.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)\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\ole2ui.h ..\ole2ui\olestd.h .\doc.h \
+ .\dxferobj.h .\ias.h .\ids.h .\idt.h .\iocs.h .\pre.h .\resource.h \
+ .\simpdnd.h .\site.h
+
+$(OBJDIR)\idt.obj $(OBJDIR)\idt.lst: .\idt.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\ole2ver.h \
+ $(CAIROLE)\h\export\oleguid.h $(CAIROLE)\h\export\scode.h \
+ $(CAIROLE)\h\export\storage.h $(COMMON)\ih\winnot.h \
+ $(COMMONINC)\disptype.h $(COMMONINC)\stgprop.h $(CRTINC)\assert.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)\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\ole2ui.h ..\ole2ui\olestd.h .\app.h \
+ .\doc.h .\ias.h .\ids.h .\idt.h .\iocs.h .\pre.h .\resource.h \
+ .\simpdnd.h .\site.h
+
+$(OBJDIR)\iocs.obj $(OBJDIR)\iocs.lst: .\iocs.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\ole2ver.h $(CAIROLE)\h\export\oleguid.h \
+ $(CAIROLE)\h\export\scode.h $(CAIROLE)\h\export\storage.h \
+ $(COMMON)\ih\winnot.h $(COMMONINC)\disptype.h $(COMMONINC)\stgprop.h \
+ $(CRTINC)\assert.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)\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\ole2ui.h \
+ ..\ole2ui\olestd.h .\app.h .\doc.h .\ias.h .\ids.h .\idt.h \
+ .\iocs.h .\pre.h .\resource.h .\simpdnd.h .\site.h
+
+$(OBJDIR)\pre.obj $(OBJDIR)\pre.lst: .\pre.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\ole2ver.h \
+ $(CAIROLE)\h\export\oleguid.h $(CAIROLE)\h\export\scode.h \
+ $(CAIROLE)\h\export\storage.h $(COMMON)\ih\winnot.h \
+ $(COMMONINC)\disptype.h $(COMMONINC)\stgprop.h $(CRTINC)\assert.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)\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\ole2ui.h ..\ole2ui\olestd.h .\pre.h \
+ .\resource.h .\simpdnd.h
+
+$(OBJDIR)\simpdnd.obj $(OBJDIR)\simpdnd.lst: .\simpdnd.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\ole2ver.h $(CAIROLE)\h\export\oleguid.h \
+ $(CAIROLE)\h\export\scode.h $(CAIROLE)\h\export\storage.h \
+ $(COMMON)\ih\winnot.h $(COMMONINC)\disptype.h $(COMMONINC)\stgprop.h \
+ $(CRTINC)\assert.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)\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\ole2ui.h \
+ ..\ole2ui\olestd.h .\app.h .\doc.h .\ias.h .\ids.h .\idt.h \
+ .\iocs.h .\pre.h .\resource.h .\simpdnd.h .\site.h
+
+$(OBJDIR)\site.obj $(OBJDIR)\site.lst: .\site.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\ole2ver.h $(CAIROLE)\h\export\oleguid.h \
+ $(CAIROLE)\h\export\scode.h $(CAIROLE)\h\export\storage.h \
+ $(COMMON)\ih\winnot.h $(COMMONINC)\disptype.h $(COMMONINC)\stgprop.h \
+ $(CRTINC)\assert.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)\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\ole2ui.h \
+ ..\ole2ui\olestd.h .\app.h .\doc.h .\ias.h .\ids.h .\idt.h \
+ .\iocs.h .\pre.h .\resource.h .\simpdnd.h .\site.h
+
diff --git a/private/oleutest/simpdnd/dirs b/private/oleutest/simpdnd/dirs
new file mode 100644
index 000000000..e0e16d167
--- /dev/null
+++ b/private/oleutest/simpdnd/dirs
@@ -0,0 +1,3 @@
+DIRS=
+OPTIONAL_DIRS= \
+ daytona
diff --git a/private/oleutest/simpdnd/doc.cpp b/private/oleutest/simpdnd/doc.cpp
new file mode 100644
index 000000000..f6eb42add
--- /dev/null
+++ b/private/oleutest/simpdnd/doc.cpp
@@ -0,0 +1,825 @@
+//**********************************************************************
+// File name: DOC.CPP
+//
+// Implementation file for CSimpleDoc.
+//
+// Functions:
+//
+// See DOC.H for Class Definition
+//
+// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+
+#include "pre.h"
+#include "iocs.h"
+#include "ias.h"
+#include "app.h"
+#include "site.h"
+#include "doc.h"
+#include "idt.h"
+#include "dxferobj.h"
+
+//**********************************************************************
+//
+// CSimpleDoc::Create
+//
+// Purpose:
+//
+// Creation for the CSimpleDoc Class
+//
+// Parameters:
+//
+// CSimpleApp FAR * lpApp - Pointer to the CSimpleApp Class
+//
+// LPRECT lpRect - Client area rect of "frame" window
+//
+// HWND hWnd - Window Handle of "frame" window
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// StgCreateDocfile OLE API
+// RegisterDragDrop OLE API
+// CoLockObjectExternal OLE API
+// CreateWindow Windows API
+// ShowWindow Windows API
+// UpdateWindow Windows API
+// EnableMenuItem Windows API
+//
+// Comments:
+//
+// This routine was added so that failure could be returned
+// from object creation.
+//
+//********************************************************************
+
+CSimpleDoc FAR * CSimpleDoc::Create(CSimpleApp FAR *lpApp, LPRECT lpRect,
+ HWND hWnd)
+{
+ CSimpleDoc FAR * lpTemp = new CSimpleDoc(lpApp, hWnd);
+
+ if (!lpTemp)
+ {
+ TestDebugOut("Memory allocation error\n");
+ return NULL;
+ }
+
+ // create storage for the doc.
+ HRESULT hErr = StgCreateDocfile (
+ NULL, // generate temp name
+ STGM_READWRITE | STGM_TRANSACTED | STGM_SHARE_EXCLUSIVE,
+ 0, &lpTemp->m_lpStorage);
+
+ if (hErr != NOERROR)
+ goto error;
+
+ // create the document Window
+ lpTemp->m_hDocWnd = CreateWindow(
+ TEXT("SimpDndDocWClass"),
+ NULL,
+ WS_CHILD | WS_CLIPCHILDREN,
+ lpRect->left,
+ lpRect->top,
+ lpRect->right,
+ lpRect->bottom,
+ hWnd,
+ NULL,
+ lpApp->m_hInst,
+ NULL);
+
+ if (!lpTemp->m_hDocWnd)
+ goto error;
+
+ ShowWindow(lpTemp->m_hDocWnd, SW_SHOWNORMAL); // Show the window
+ UpdateWindow(lpTemp->m_hDocWnd); // Sends WM_PAINT message
+
+#ifdef NOTREADY
+ // Ensable InsertObject menu choice
+ EnableMenuItem( lpApp->m_hEditMenu, 0, MF_BYPOSITION | MF_ENABLED);
+#else
+ // Ensable InsertObject menu choice
+ EnableMenuItem( lpApp->m_hEditMenu, 1, MF_BYPOSITION | MF_ENABLED);
+ // Disable Copy menu choice
+ EnableMenuItem( lpApp->m_hEditMenu, 0, MF_BYPOSITION | MF_DISABLED |
+ MF_GRAYED);
+#endif // NOTREADY
+
+ HRESULT hRes;
+
+ // It is *REQUIRED* to hold a strong LOCK on the object that is
+ // registered as drop target. this call will result in at least one
+ // ref count held on our document. later in CSimpleDoc::Close we will
+ // unlock this lock which will make our document's ref count go to 0.
+ // when the document's ref count goes to 0, it will be deleted.
+ if ( (hRes=CoLockObjectExternal (&lpTemp->m_DropTarget, TRUE, 0))
+ != ResultFromScode(S_OK) )
+ {
+ /* CoLockObjectExternal should never fail. If it fails, we don't want
+ * to carry on since we don't have a guaranteed object lock.
+ */
+ goto error;
+ }
+
+ // Register our window as a DropTarget
+ if (((hRes=RegisterDragDrop(lpTemp->m_hDocWnd, &lpTemp->m_DropTarget))
+ !=ResultFromScode(S_OK))
+ && (hRes != ResultFromScode(DRAGDROP_E_ALREADYREGISTERED)))
+ {
+ lpTemp->m_fRegDragDrop = FALSE;
+ }
+ else
+ {
+ lpTemp->m_fRegDragDrop = TRUE;
+ }
+
+ return (lpTemp);
+
+error:
+ TestDebugOut("Fail in CSimpleDoc::Create\n");
+ delete (lpTemp);
+ return NULL;
+
+}
+
+//**********************************************************************
+//
+// CSimpleDoc::Close
+//
+// Purpose:
+//
+// Close CSimpleDoc object.
+// when the document's reference count goes to 0, the document
+// will be destroyed.
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// RevokeDragDrop OLE API
+// CoLockObjectExternal OLE API
+// OleFlushClipboard OLE API
+// ShowWindow Windows API
+// CSimpleSite::CloseOleObject SITE.CPP
+//
+//
+//********************************************************************
+
+void CSimpleDoc::Close(void)
+{
+ TestDebugOut("In CSimpleDoc::Close\r\n");
+
+ HRESULT hRes;
+
+ ShowWindow(m_hDocWnd, SW_HIDE); // Hide the window
+
+ // Remove our data transfer object from clipboard if it is there.
+ // this will leave HGLOBAL based data behind on the clipboard
+ // including OLE 1.0 compatibility formats.
+
+ if (OleFlushClipboard() != ResultFromScode(S_OK))
+ {
+ TestDebugOut("Fail in OleFlushClipBoard\n");
+ }
+
+ // Revoke our window as a DropTarget
+ if (m_fRegDragDrop)
+ {
+ if (((hRes=RevokeDragDrop(m_hDocWnd)) != ResultFromScode(S_OK)) &&
+ (hRes!=ResultFromScode(DRAGDROP_E_NOTREGISTERED)))
+ {
+ /* if we fail in revoking the drag-drop, we will probably be
+ * having memory leakage.
+ */
+ TestDebugOut("Fail in RevokeDragDrop\n");
+ }
+ else
+ {
+ m_fRegDragDrop = FALSE;
+ }
+ }
+
+ // Close the OLE object in our document
+ if (m_lpSite)
+ m_lpSite->CloseOleObject();
+
+ // Unlock the lock added in CSimpleDoc::Create. this will make
+ // the document's ref count go to 0, and the document will be deleted.
+ if ((hRes=CoLockObjectExternal (&m_DropTarget, FALSE, TRUE))
+ !=ResultFromScode(S_OK))
+ {
+ /* if CoLockObjectExternal fails, this means that we cannot release
+ * the reference count to our destinated object. This will cause
+ * memory leakage.
+ */
+ TestDebugOut("Fail in CoLockObjectExternal\n");
+ }
+}
+
+//**********************************************************************
+//
+// CSimpleDoc::CSimpleDoc
+//
+// Purpose:
+//
+// Constructor for the CSimpleDoc Class
+//
+// Parameters:
+//
+// CSimpleApp FAR * lpApp - Pointer to the CSimpleApp Class
+//
+// HWND hWnd - Window Handle of "frame" window
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// GetMenu Windows API
+// GetSubMenu Windows API
+//
+//
+//********************************************************************
+#pragma warning(disable : 4355) // turn off this warning. This warning
+ // tells us that we are passing this in
+ // an initializer, before "this" is through
+ // initializing. This is ok, because
+ // we just store the ptr in the other
+ // constructor
+
+CSimpleDoc::CSimpleDoc(CSimpleApp FAR * lpApp,HWND hWnd)
+ : m_DropTarget(this), m_DropSource(this)
+#pragma warning (default : 4355) // Turn the warning back on
+{
+ TestDebugOut("In CSimpleDoc's Constructor\r\n");
+ m_lpApp = lpApp;
+ m_lpSite = NULL;
+ m_nCount = 0;
+ // set up menu handles
+ lpApp->m_hMainMenu = GetMenu(hWnd);
+ lpApp->m_hFileMenu = GetSubMenu(lpApp->m_hMainMenu, 0);
+ lpApp->m_hEditMenu = GetSubMenu(lpApp->m_hMainMenu, 1);
+ lpApp->m_hHelpMenu = GetSubMenu(lpApp->m_hMainMenu, 2);
+ lpApp->m_hCascadeMenu = NULL;
+ m_fModifiedMenu = FALSE;
+
+ // drag/drop related stuff
+ m_fRegDragDrop = FALSE; // is doc registered as drop target?
+ m_fLocalDrag = FALSE; // is doc source of the drag
+ m_fLocalDrop = FALSE; // was doc target of the drop
+ m_fCanDropCopy = FALSE; // is Drag/Drop copy/move possible?
+ m_fCanDropLink = FALSE; // is Drag/Drop link possible?
+ m_fDragLeave = FALSE; // has drag left
+ m_fPendingDrag = FALSE; // LButtonDown--possible drag pending
+ m_ptButDown.x = m_ptButDown.y = 0; // LButtonDown coordinates
+
+}
+
+//**********************************************************************
+//
+// CSimpleDoc::~CSimpleDoc
+//
+// Purpose:
+//
+// Destructor for CSimpleDoc
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// GetMenuItemCount Windows API
+// RemoveMenu Windows API
+// DestroyMenu Windows API
+// DestroyWindow Windows API
+// CSimpleSite::Release SITE.CPP
+// CSimpleSite::UnloadOleObject SITE.CPP
+// IStorage::Release OLE API
+//
+//
+//********************************************************************
+
+CSimpleDoc::~CSimpleDoc()
+{
+ TestDebugOut("In CSimpleDoc's Destructor\r\n");
+
+ // Release all pointers we hold to the OLE object, also release
+ // the ref count added in CSimpleSite::Create. this will make
+ // the Site's ref count go to 0, and the Site will be deleted.
+ if (m_lpSite)
+ {
+ m_lpSite->UnloadOleObject();
+ m_lpSite->Release();
+ m_lpSite = NULL;
+ }
+
+ // Release the Storage
+ if (m_lpStorage)
+ {
+ m_lpStorage->Release();
+ m_lpStorage = NULL;
+ }
+
+ // if the edit menu was modified, remove the menu item and
+ // destroy the popup if it exists
+ if (m_fModifiedMenu)
+ {
+ int nCount = GetMenuItemCount(m_lpApp->m_hEditMenu);
+ RemoveMenu(m_lpApp->m_hEditMenu, nCount-1, MF_BYPOSITION);
+ if (m_lpApp->m_hCascadeMenu)
+ DestroyMenu(m_lpApp->m_hCascadeMenu);
+ }
+
+ DestroyWindow(m_hDocWnd);
+}
+
+
+//**********************************************************************
+//
+// CSimpleDoc::QueryInterface
+//
+// Purpose:
+//
+// Used for interface negotiation at the Document level.
+//
+// Parameters:
+//
+// REFIID riid - ID of interface to be returned
+// LPVOID FAR* ppvObj - Location to return the interface
+//
+// Return Value:
+//
+// S_OK - Interface supported
+// E_NOINTERFACE - Interface NOT supported
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// ResultFromScode OLE API
+//
+//
+//********************************************************************
+
+STDMETHODIMP CSimpleDoc::QueryInterface(REFIID riid, LPVOID FAR* ppvObj)
+{
+ TestDebugOut("In CSimpleDoc::QueryInterface\r\n");
+
+ *ppvObj = NULL; // must set out pointer parameters to NULL
+
+ // looking for IUnknown
+ if (IsEqualIID( riid, IID_IUnknown))
+ {
+ AddRef();
+ *ppvObj = this;
+ return ResultFromScode(S_OK);
+ }
+
+ // looking for IDropTarget
+ if (IsEqualIID( riid, IID_IDropTarget))
+ {
+ m_DropTarget.AddRef();
+ *ppvObj=&m_DropTarget;
+ return ResultFromScode(S_OK);
+ }
+
+ // looking for IDropSource
+ if (IsEqualIID( riid, IID_IDropSource))
+ {
+ m_DropSource.AddRef();
+ *ppvObj=&m_DropSource;
+ return ResultFromScode(S_OK);
+ }
+
+ // Not a supported interface
+ return ResultFromScode(E_NOINTERFACE);
+}
+
+//**********************************************************************
+//
+// CSimpleDoc::AddRef
+//
+// Purpose:
+//
+// Increments the document reference count
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// UINT - The new reference count on the document object
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// CSimpleApp::AddRef APP.CPP
+//
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) CSimpleDoc::AddRef()
+{
+ TestDebugOut("In CSimpleDoc::AddRef\r\n");
+ return ++m_nCount;
+}
+
+//**********************************************************************
+//
+// CSimpleDoc::Release
+//
+// Purpose:
+//
+// Decrements the document reference count
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// UINT - The new reference count on the document
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) CSimpleDoc::Release()
+{
+ TestDebugOut("In CSimpleDoc::Release\r\n");
+
+ if (--m_nCount == 0)
+ {
+ delete this;
+ return 0;
+ }
+ return m_nCount;
+}
+
+//**********************************************************************
+//
+// CSimpleDoc::InsertObject
+//
+// Purpose:
+//
+// Inserts a new object to this document
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// CSimpleSite::Create SITE.CPP
+// CSimpleSite::InitObject SITE.CPP
+// CSimpleSite::Release SITE.CPP
+// CSimpleSite::Revert SITE.CPP
+// memset C Runtime
+// OleUIInsertObject OLE2UI function
+// CSimpleDoc::DisableInsertObject DOC.CPP
+//
+// Comments:
+//
+// This implementation only allows one object to be inserted
+// into a document. Once the object has been inserted, then
+// the Insert Object menu choice is greyed out, to prevent
+// the user from inserting another.
+//
+//********************************************************************
+
+void CSimpleDoc::InsertObject()
+{
+ OLEUIINSERTOBJECT io;
+ UINT iret;
+ TCHAR szFile[OLEUI_CCHPATHMAX];
+
+ HRESULT hRes;
+
+ m_lpSite = CSimpleSite::Create(this);
+
+ if (!m_lpSite)
+ {
+ /* memory allocation problem. cannot continue.
+ */
+ TestDebugOut("Memory allocation error\n");
+ return;
+ }
+
+ // clear the structure
+ _fmemset(&io, 0, sizeof(OLEUIINSERTOBJECT));
+
+ // fill the structure
+ io.cbStruct = sizeof(OLEUIINSERTOBJECT);
+ io.dwFlags = IOF_SELECTCREATENEW | IOF_DISABLELINK |
+ IOF_DISABLEDISPLAYASICON | IOF_CREATENEWOBJECT |
+ IOF_CREATEFILEOBJECT;
+ io.hWndOwner = m_hDocWnd;
+ io.lpszCaption = (LPTSTR)TEXT("Insert Object");
+ io.iid = IID_IOleObject;
+ io.oleRender = OLERENDER_DRAW;
+ io.lpIOleClientSite = &m_lpSite->m_OleClientSite;
+ io.lpIStorage = m_lpSite->m_lpObjStorage;
+ io.ppvObj = (LPVOID FAR *)&m_lpSite->m_lpOleObject;
+ io.lpszFile = szFile;
+ io.cchFile = sizeof(szFile)/sizeof(TCHAR);
+ // cchFile is the number of characters
+ _fmemset((LPTSTR)szFile, 0, sizeof(szFile));
+
+ // call OUTLUI to do all the hard work
+ iret = OleUIInsertObject(&io);
+
+ if (iret == OLEUI_OK)
+ {
+ m_lpSite->InitObject((BOOL)(io.dwFlags & IOF_SELECTCREATENEW));
+ // disable Insert Object menu item
+ DisableInsertObject();
+ }
+ else
+ {
+ m_lpSite->Release();
+ m_lpSite = NULL;
+ if (((hRes=m_lpStorage->Revert()) != ResultFromScode(S_OK)) &&
+ (hRes!=ResultFromScode(STG_E_REVERTED)))
+ {
+ TestDebugOut("Fail in IStorage::Revert\n");
+ }
+ }
+}
+
+//**********************************************************************
+//
+// CSimpleDoc::lResizeDoc
+//
+// Purpose:
+//
+// Resizes the document
+//
+// Parameters:
+//
+// LPRECT lpRect - The size of the client are of the "frame"
+// Window.
+//
+// Return Value:
+//
+// NULL
+//
+// Function Calls:
+// Function Location
+//
+// MoveWindow Windows API
+//
+//
+//********************************************************************
+
+long CSimpleDoc::lResizeDoc(LPRECT lpRect)
+{
+ MoveWindow(
+ m_hDocWnd,
+ lpRect->left, lpRect->top,
+ lpRect->right, lpRect->bottom, TRUE);
+
+ return NULL;
+}
+
+//**********************************************************************
+//
+// CSimpleDoc::lAddVerbs
+//
+// Purpose:
+//
+// Adds the objects verbs to the edit menu.
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// NULL
+//
+// Function Calls:
+// Function Location
+//
+// GetMenuItemCount Windows API
+// OleUIAddVerbMenu OLE2UI function
+//
+//
+//********************************************************************
+
+long CSimpleDoc::lAddVerbs(void)
+{
+ // m_fModifiedMenu is TRUE if the menu has already been modified
+ // once. Since we only support one obect every time the application
+ // is run, then once the menu is modified, it doesn't have
+ // to be done again.
+ if (m_lpSite && !m_fModifiedMenu)
+ {
+ int nCount = GetMenuItemCount(m_lpApp->m_hEditMenu);
+
+ if (!OleUIAddVerbMenu ( m_lpSite->m_lpOleObject,
+ NULL,
+ m_lpApp->m_hEditMenu,
+ nCount + 1,
+ IDM_VERB0,
+ 0, // no maximum verb IDM enforced
+ FALSE,
+ 1,
+ &m_lpApp->m_hCascadeMenu) )
+ {
+ TestDebugOut("Fail in OleUIAddVerbMenu\n");
+ }
+
+ m_fModifiedMenu = TRUE;
+ }
+ return (NULL);
+}
+
+//**********************************************************************
+//
+// CSimpleDoc::PaintDoc
+//
+// Purpose:
+//
+// Paints the Document
+//
+// Parameters:
+//
+// HDC hDC - hDC of the document Window
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// CSimpleSite::PaintObj SITE.CPP
+//
+//
+//********************************************************************
+
+void CSimpleDoc::PaintDoc (HDC hDC)
+{
+ // if we supported multiple objects, then we would enumerate
+ // the objects and call paint on each of them from here.
+
+ if (m_lpSite)
+ m_lpSite->PaintObj(hDC);
+
+}
+
+//**********************************************************************
+//
+// CSimpleDoc::DisableInsertObject
+//
+// Purpose:
+//
+// Disable the ability to insert a new object in this document.
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// RevokeDragDrop OLE API
+// EnableMenuItem Windows API
+//
+// Comments:
+//
+// This implementation only allows one object to be inserted
+// into a document. Once the object has been inserted, then
+// the Insert Object menu choice is greyed out, to prevent
+// the user from inserting another. Also we revoke ourself as
+// a potential drop target.
+//
+//********************************************************************
+
+void CSimpleDoc::DisableInsertObject(void)
+{
+#ifdef NOTREADY
+ // Disable InsertObject menu choice
+ EnableMenuItem( m_lpApp->m_hEditMenu, 0, MF_BYPOSITION | MF_DISABLED |
+ MF_GRAYED);
+#else
+ // Disable InsertObject menu choice
+ EnableMenuItem( m_lpApp->m_hEditMenu, 1, MF_BYPOSITION | MF_DISABLED |
+ MF_GRAYED);
+ // Enable Copy menu choice
+ EnableMenuItem( m_lpApp->m_hEditMenu, 0, MF_BYPOSITION | MF_ENABLED);
+#endif // NOTREADY
+
+ // We no longer accept dropping of objects
+ if (m_fRegDragDrop)
+ {
+ HRESULT hRes;
+ if (((hRes=RevokeDragDrop(m_hDocWnd))!=ResultFromScode(S_OK)) &&
+ (hRes!=ResultFromScode(DRAGDROP_E_NOTREGISTERED)))
+ {
+ /* if we fail in revoking the drag-drop, we will probably be
+ * having memory leakage.
+ */
+ TestDebugOut("Fail in RevokeDragDrop\n");
+ }
+ else
+ {
+ m_fRegDragDrop = FALSE;
+ }
+ }
+}
+
+//**********************************************************************
+//
+// CSimpleDoc::CopyObjectToClip
+//
+// Purpose:
+//
+// Copy the embedded OLE object to the clipboard
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// CDataXferObj::Create DXFEROBJ.CPP
+// CDataXferObj::Release DXFEROBJ.CPP
+// CDataXferObj::QueryInterface DXFEROBJ.CPP
+// OleSetClipboard OLE API
+//
+// Comments:
+//
+// This implementation only allows one object to be inserted
+// into a document. Once the object has been inserted, then
+// the Copy menu choice is enabled.
+//
+//********************************************************************
+
+void CSimpleDoc::CopyObjectToClip(void)
+{
+ LPDATAOBJECT lpDataObj;
+
+ // Create a data transfer object by cloning the existing OLE object
+ CDataXferObj FAR* pDataXferObj = CDataXferObj::Create(m_lpSite,NULL);
+ if (! pDataXferObj)
+ {
+ /* memory allocation error !
+ */
+ MessageBox(NULL, TEXT("Out-of-memory"), TEXT("SimpDnD"),
+ MB_SYSTEMMODAL | MB_ICONHAND);
+ return;
+ }
+ // initially obj is created with 0 refcnt. this QI will make it go to 1.
+ pDataXferObj->QueryInterface(IID_IDataObject, (LPVOID FAR*)&lpDataObj);
+
+ // put out data transfer object on the clipboard. this API will AddRef.
+ if (OleSetClipboard(lpDataObj) != ResultFromScode(S_OK))
+ {
+ TestDebugOut("Fail in OleSetClipboard\n");
+ lpDataObj->Release();
+ }
+
+ // Give ownership of data transfer object to clipboard
+ pDataXferObj->Release();
+}
diff --git a/private/oleutest/simpdnd/doc.h b/private/oleutest/simpdnd/doc.h
new file mode 100644
index 000000000..7af852750
--- /dev/null
+++ b/private/oleutest/simpdnd/doc.h
@@ -0,0 +1,75 @@
+//**********************************************************************
+// File name: doc.h
+//
+// Definition of CSimpleDoc
+//
+// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+
+#if !defined( _DOC_H_ )
+#define _DOC_H_
+
+#include "idt.h"
+#include "ids.h"
+
+class CSimpleSite;
+class CSimpleApp;
+
+class CSimpleDoc : public IUnknown
+{
+public:
+ int m_nCount; // reference count
+ LPSTORAGE m_lpStorage; // IStorage* pointer for Doc
+ BOOL m_fModifiedMenu; // is object's verb menu on menu
+
+ // Drag/Drop related fields
+ 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
+
+ CSimpleSite FAR * m_lpSite;
+ CSimpleApp FAR * m_lpApp;
+
+ HWND m_hDocWnd;
+
+ CDropTarget m_DropTarget;
+ CDropSource m_DropSource;
+
+ static CSimpleDoc FAR* Create(CSimpleApp FAR *lpApp, LPRECT lpRect,
+ HWND hWnd);
+
+ void Close(void);
+
+ CSimpleDoc();
+ CSimpleDoc(CSimpleApp FAR *lpApp, HWND hWnd);
+ ~CSimpleDoc();
+
+ // IUnknown Interface
+ STDMETHODIMP QueryInterface(REFIID riid, LPVOID FAR* ppvObj);
+ STDMETHODIMP_(ULONG) AddRef();
+ STDMETHODIMP_(ULONG) Release();
+
+ void InsertObject(void);
+ void DisableInsertObject(void);
+ long lResizeDoc(LPRECT lpRect);
+ long lAddVerbs(void);
+ void PaintDoc(HDC hDC);
+
+ // Drag/Drop and clipboard support methods
+ void CopyObjectToClip(void);
+ BOOL QueryDrag(POINT pt);
+ DWORD DoDragDrop(void);
+ void Scroll(DWORD dwScrollDir) { /*...scroll Doc here...*/ }
+
+private:
+
+ void FailureNotifyHelper(TCHAR *pszMsg, DWORD dwData);
+
+};
+
+#endif // _DOC_H_
diff --git a/private/oleutest/simpdnd/dxferobj.cpp b/private/oleutest/simpdnd/dxferobj.cpp
new file mode 100644
index 000000000..c95dbe8bf
--- /dev/null
+++ b/private/oleutest/simpdnd/dxferobj.cpp
@@ -0,0 +1,739 @@
+//**********************************************************************
+// File name: DXFEROBJ.CPP
+//
+// Implementation file for CDataXferObj, data transfer object
+// implementation of IDataObject interface.
+//
+// Functions:
+//
+// See DXFEROBJ.H for class definition
+//
+// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+
+#include "pre.h"
+#include <enumfetc.h>
+#include <assert.h>
+#include "dxferobj.h"
+#include "site.h"
+
+//BUGBUG: These should be fetched from real header files
+#define CF_HDROP 15
+typedef struct _dropfilestruct {
+ DWORD pFiles;
+ POINT pt;
+ BOOL fNC;
+ BOOL fWide;
+} DROPFILESTRUCT;
+
+
+CLIPFORMAT g_cfEmbeddedObject=RegisterClipboardFormat(CF_EMBEDDEDOBJECT);
+CLIPFORMAT g_cfObjectDescriptor=RegisterClipboardFormat(CF_OBJECTDESCRIPTOR);
+
+// List of formats offered by our data transfer object via EnumFormatEtc
+static FORMATETC s_arrGetFmtEtcs[] =
+{
+ { g_cfEmbeddedObject, NULL, DVASPECT_CONTENT, -1, TYMED_ISTORAGE},
+ { g_cfObjectDescriptor, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL},
+ { CF_METAFILEPICT, NULL, DVASPECT_CONTENT, -1, TYMED_MFPICT}
+};
+
+
+//**********************************************************************
+//
+// CDataXferObj::Create
+//
+// Purpose:
+//
+// Creation routine for CDataXferObj
+//
+// Parameters:
+//
+// CSimpleSite FAR *lpSite - Pointer to source CSimpleSite
+// this is the container site of the
+// source OLE object to be transfered
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// StgCreateDocfile OLE API
+// assert C Runtime
+//
+// Comments:
+// reference count of CDataXferObj will be 0 on return.
+//
+//********************************************************************
+
+CDataXferObj FAR * CDataXferObj::Create(
+ CSimpleSite FAR *lpSite,
+ POINTL FAR* pPointl
+)
+{
+ CDataXferObj FAR * lpTemp = new CDataXferObj();
+
+ if (!lpTemp)
+ return NULL;
+
+ // create a sub-storage for the object
+ HRESULT hErr = StgCreateDocfile(
+ NULL,
+ STGM_READWRITE | STGM_DIRECT | STGM_SHARE_EXCLUSIVE |
+ STGM_DELETEONRELEASE,
+ 0,
+ &lpTemp->m_lpObjStorage);
+
+ assert(hErr == NOERROR);
+
+ if (hErr != NOERROR)
+ {
+ delete lpTemp;
+ return NULL;
+ }
+
+ // Clone the source object
+ if (lpSite->m_lpOleObject)
+ {
+ // Object is loaded; ask the object to save into the new storage
+ LPPERSISTSTORAGE pPersistStorage;
+
+ if (lpSite->m_lpOleObject->QueryInterface(IID_IPersistStorage,
+ (LPVOID FAR*)&pPersistStorage) != ResultFromScode(S_OK))
+ {
+ /* cannot find interface
+ */
+ return(NULL);
+ }
+ assert(pPersistStorage);
+ if (OleSave(pPersistStorage, lpTemp->m_lpObjStorage, FALSE)
+ != ResultFromScode(S_OK))
+ {
+ TestDebugOut("Fail in OleSave\n");
+ }
+
+ // pass NULL so that object application won't forget the real stg
+ if (pPersistStorage->SaveCompleted(NULL) != ResultFromScode(S_OK))
+ {
+ TestDebugOut("Fail in IPersistStorage::SaveCompleted\n");
+ }
+ pPersistStorage->Release();
+ }
+ else
+ {
+ // Object not loaded so use cheaper IStorage CopyTo operation
+ lpSite->m_lpObjStorage->CopyTo(0, NULL, NULL, lpTemp->m_lpObjStorage);
+ }
+
+ if (OleLoad(lpTemp->m_lpObjStorage, IID_IOleObject, NULL,
+ (LPVOID FAR*)&lpTemp->m_lpOleObject)
+ != ResultFromScode(S_OK))
+ {
+ /* we cannot load the embedded/linked object into the memory
+ */
+ return(NULL);
+ }
+ assert(lpTemp->m_lpOleObject);
+
+ lpTemp->m_sizel = lpSite->m_sizel;
+ if (pPointl)
+ lpTemp->m_pointl = *pPointl;
+ else
+ lpTemp->m_pointl.x = lpTemp->m_pointl.y = 0;
+ return lpTemp;
+}
+
+//**********************************************************************
+//
+// CDataXferObj::CDataXferObj
+//
+// Purpose:
+//
+// Constructor for CDataXferObj
+//
+// Parameters:
+//
+// CSimpleDoc FAR *lpDoc - Pointer to CSimpleDoc
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+//
+//********************************************************************
+
+CDataXferObj::CDataXferObj (void)
+{
+ // clear the reference count
+ m_nCount = 0;
+
+ m_lpObjStorage = NULL;
+ m_lpOleObject = NULL;
+ m_sizel.cx = m_sizel.cy = 0;
+ m_pointl.x = m_pointl.y = 0;
+}
+
+//**********************************************************************
+//
+// CDataXferObj::~CDataXferObj
+//
+// Purpose:
+//
+// Destructor for CDataXferObj
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// IOleObject::Release Object
+// IStorage::Release OLE API
+//
+//
+//********************************************************************
+
+CDataXferObj::~CDataXferObj ()
+{
+ TestDebugOut ("In CDataXferObj's Destructor \r\n");
+
+ if (m_lpOleObject)
+ {
+ m_lpOleObject->Release();
+ m_lpOleObject = NULL;
+
+ // Release the storage for this object
+ m_lpObjStorage->Release();
+ m_lpObjStorage = NULL;
+ }
+}
+
+
+
+//**********************************************************************
+//
+// CDataXferObj::QueryInterface
+//
+// Purpose:
+//
+// Used for interface negotiation of the CDataXferObj instance
+//
+// Parameters:
+//
+// REFIID riid - A reference to the interface that is
+// being queried.
+//
+// LPVOID FAR* ppvObj - An out parameter to return a pointer to
+// the interface.
+//
+// Return Value:
+//
+// S_OK - The interface is supported.
+// E_NOINTERFACE - The interface is not supported
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// IsEqualIID OLE API
+// ResultFromScode OLE API
+// CDataXferObj::AddRef DXFEROBJ.CPP
+//
+//
+//********************************************************************
+
+STDMETHODIMP CDataXferObj::QueryInterface(REFIID riid, LPVOID FAR* ppvObj)
+{
+ TestDebugOut("In CDataXferObj::QueryInterface\r\n");
+
+ if (IsEqualIID( riid, IID_IUnknown) || IsEqualIID(riid, IID_IDataObject))
+ {
+ AddRef();
+ *ppvObj = this;
+ return NOERROR;
+ }
+
+ // unknown interface requested
+ *ppvObj = NULL; // must set out pointer parameters to NULL
+ return ResultFromScode(E_NOINTERFACE);
+}
+
+//**********************************************************************
+//
+// CDataXferObj::AddRef
+//
+// Purpose:
+//
+// Increments the reference count of the CDataXferObj instance
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// ULONG - The new reference count of the object
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) CDataXferObj::AddRef()
+{
+ TestDebugOut("In CDataXferObj::AddRef\r\n");
+
+ return ++m_nCount;
+}
+
+//**********************************************************************
+//
+// CDataXferObj::Release
+//
+// Purpose:
+//
+// Decrements the reference count of the CDataXferObj object
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// ULONG - The new reference count of the object.
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) CDataXferObj::Release()
+{
+ TestDebugOut("In CDataXferObj::Release\r\n");
+
+ if (--m_nCount == 0)
+ {
+ delete this;
+ return 0;
+ }
+ return m_nCount;
+}
+
+
+/********************************************************************
+** This IDataObject implementation is used for data transfer.
+**
+** The following methods are NOT supported for data transfer:
+** IDataObject::SetData -- return E_NOTIMPL
+** IDataObject::DAdvise -- return OLE_E_ADVISENOTSUPPORTED
+** ::DUnadvise
+** ::EnumDAdvise
+** IDataObject::GetCanonicalFormatEtc -- return E_NOTIMPL
+** (NOTE: must set pformatetcOut->ptd = NULL)
+*********************************************************************/
+
+
+//**********************************************************************
+//
+// CDataXferObj::QueryGetData
+//
+// Purpose:
+//
+// Called to determine if our object supports a particular
+// FORMATETC.
+//
+// Parameters:
+//
+// LPFORMATETC pformatetc - Pointer to the FORMATETC being queried for.
+//
+// Return Value:
+//
+// DV_E_FORMATETC - The FORMATETC is not supported
+// S_OK - The FORMATETC is supported.
+//
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// ResultFromScode OLE API
+//
+// Comments:
+// we support the following formats:
+// "Embedded Object"
+// "Object Descriptor"
+// CF_METAFILEPICT
+//
+//********************************************************************
+STDMETHODIMP CDataXferObj::QueryGetData (LPFORMATETC pformatetc)
+{
+ SCODE sc = DV_E_FORMATETC;
+
+ TestDebugOut("In CDataXferObj::QueryGetData\r\n");
+
+ // check the validity of the formatetc.
+
+ if ( (pformatetc->cfFormat == g_cfEmbeddedObject) &&
+ (pformatetc->dwAspect == DVASPECT_CONTENT) &&
+ (pformatetc->tymed == TYMED_ISTORAGE) )
+ {
+ sc = S_OK;
+ }
+
+ else if ( (pformatetc->cfFormat == g_cfObjectDescriptor) &&
+ (pformatetc->dwAspect == DVASPECT_CONTENT) &&
+ (pformatetc->tymed == TYMED_HGLOBAL) )
+ {
+ sc = S_OK;
+ }
+
+ else if ( (pformatetc->cfFormat == CF_METAFILEPICT) &&
+ (pformatetc->dwAspect == DVASPECT_CONTENT) &&
+ (pformatetc->tymed == TYMED_MFPICT) )
+ {
+ sc = S_OK;
+ }
+ else if ( (pformatetc->cfFormat == CF_HDROP) &&
+ (pformatetc->dwAspect == DVASPECT_CONTENT) &&
+ (pformatetc->tymed == TYMED_HGLOBAL) )
+ {
+ sc = S_OK;
+ }
+
+ return ResultFromScode(sc);
+}
+
+extern BOOL gfUseEmptyEnumerator;
+
+//**********************************************************************
+//
+// CDataXferObj::EnumFormatEtc
+//
+// Purpose:
+//
+// Enumerates the formats that can be used to store data
+//
+// Parameters:
+//
+// DWORD dwDirection - format to be enumerated
+//
+// LPENUMFORMATETC ppenumFormatEtc - where to return the
+// instantiated enumerator
+//
+// Return Value:
+//
+// S_OK - if the operation is successful
+// E_OUTOFMEMORY - if ran out of memory
+// E_NOTIMPL - if dwDirection is not supported
+//
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// ResultFromScode OLE API
+// OleStdEnumFmtEtc_Create OLE2UI
+//
+//**********************************************************************
+
+STDMETHODIMP CDataXferObj::EnumFormatEtc(
+ DWORD dwDirection,
+ LPENUMFORMATETC FAR* ppenumFormatEtc
+)
+{
+ SCODE sc = E_NOTIMPL;
+
+ TestDebugOut("In CDataXferObj::EnumFormatEtc\r\n");
+ *ppenumFormatEtc = NULL;
+
+ if( gfUseEmptyEnumerator == TRUE )
+ {
+ return E_FAIL;
+ }
+
+ if (dwDirection == DATADIR_GET)
+ {
+ *ppenumFormatEtc = OleStdEnumFmtEtc_Create(
+ sizeof(s_arrGetFmtEtcs)/sizeof(s_arrGetFmtEtcs[0]),
+ s_arrGetFmtEtcs);
+ if (*ppenumFormatEtc == NULL)
+ sc = E_OUTOFMEMORY;
+ else
+ sc = S_OK;
+ }
+ return ResultFromScode(sc);
+}
+
+
+//**********************************************************************
+//
+// CDataXferObj::GetData
+//
+// Purpose:
+//
+// Returns the data in the format specified in pformatetcIn.
+//
+// Parameters:
+//
+// LPFORMATETC pformatetcIn - The format requested by the caller
+//
+// LPSTGMEDIUM pmedium - The medium requested by the caller
+//
+// Return Value:
+//
+// DV_E_FORMATETC - Format not supported
+// S_OK - Success
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// OleStdGetOleObjectData OLE2UI API
+// OleStdGetMetafilePictFromOleObject OLE2UI API
+// OleStdGetObjectDescriptorDataFromOleObject OLE2UI API
+// ResultFromScode OLE API
+// IOleObject::QueryInterface Object
+//
+// Comments:
+// we support GetData for the following formats:
+// "Embedded Object"
+// "Object Descriptor"
+// CF_METAFILEPICT
+//
+//********************************************************************
+
+STDMETHODIMP CDataXferObj::GetData (
+ LPFORMATETC pformatetcIn,
+ LPSTGMEDIUM pmedium
+)
+{
+ SCODE sc = DV_E_FORMATETC;
+
+ TestDebugOut("In CDataXferObj::GetData\r\n");
+
+ // we must set all out pointer parameters to NULL. */
+ pmedium->tymed = TYMED_NULL;
+ pmedium->pUnkForRelease = NULL; // we transfer ownership to caller
+ pmedium->hGlobal = NULL;
+
+ // Check the FORMATETC and fill pmedium if valid.
+ if ( (pformatetcIn->cfFormat == g_cfEmbeddedObject) &&
+ (pformatetcIn->dwAspect == DVASPECT_CONTENT) &&
+ (pformatetcIn->tymed == TYMED_ISTORAGE) )
+ {
+ LPPERSISTSTORAGE pPersistStorage;
+
+ /* render CF_EMBEDDEDOBJECT by asking the object to save
+ ** into a temporary, DELETEONRELEASE IStorage allocated by us.
+ */
+ HRESULT hRes;
+ if ((hRes=m_lpOleObject->QueryInterface(
+ IID_IPersistStorage, (LPVOID FAR*)&pPersistStorage))
+ != ResultFromScode(S_OK))
+ {
+ return(hRes);
+ }
+
+ assert(pPersistStorage);
+ HRESULT hrErr = OleStdGetOleObjectData(
+ pPersistStorage,
+ pformatetcIn,
+ pmedium,
+ FALSE /* fUseMemory -- (use file-base stg) */
+ );
+ pPersistStorage->Release();
+ sc = GetScode( hrErr );
+
+ }
+ else if ( (pformatetcIn->cfFormat == g_cfObjectDescriptor) &&
+ (pformatetcIn->dwAspect == DVASPECT_CONTENT) &&
+ (pformatetcIn->tymed == TYMED_HGLOBAL) )
+ {
+
+ // render CF_OBJECTDESCRIPTOR data
+ pmedium->hGlobal = OleStdGetObjectDescriptorDataFromOleObject(
+ m_lpOleObject,
+ TEXT("Simple OLE 2.0 Container"), //string to identify source
+ DVASPECT_CONTENT,
+ m_pointl,
+ (LPSIZEL)&m_sizel
+ );
+ if (! pmedium->hGlobal)
+ sc = E_OUTOFMEMORY;
+ else
+ {
+ pmedium->tymed = TYMED_HGLOBAL;
+ sc = S_OK;
+ }
+
+ }
+ else if ( (pformatetcIn->cfFormat == CF_METAFILEPICT) &&
+ (pformatetcIn->dwAspect == DVASPECT_CONTENT) &&
+ (pformatetcIn->tymed == TYMED_MFPICT) )
+ {
+
+ // render CF_METAFILEPICT by drawing the object into a metafile DC
+ pmedium->hGlobal = OleStdGetMetafilePictFromOleObject(
+ m_lpOleObject, DVASPECT_CONTENT, NULL, pformatetcIn->ptd);
+ if (! pmedium->hGlobal)
+ sc = E_OUTOFMEMORY;
+ else
+ {
+ pmedium->tymed = TYMED_MFPICT;
+ sc = S_OK;
+ }
+ }
+ else if ( (pformatetcIn->cfFormat == CF_HDROP) &&
+ (pformatetcIn->dwAspect == DVASPECT_CONTENT) &&
+ (pformatetcIn->tymed == TYMED_HGLOBAL) )
+ {
+ // testing for Win3.1 style drag drop. If we offer
+ // CF_HDROP ( basically, a list of filenames) in a data object
+ // given to OLE DoDragDrop, then DoDragDrop will translate
+ // OLE drag drop into Win3.1 drag drop for Win3.1 drop targets
+
+ ULONG cbFile;
+ char szFile[256];
+ DROPFILESTRUCT *pdfs;
+ char *pfile;
+
+
+ cbFile = GetEnvironmentVariable("SystemRoot", szFile, sizeof(szFile));
+
+ if( cbFile == 0 )
+ {
+ sc = E_FAIL;
+ goto errRtn;
+ }
+
+
+ cbFile += sizeof("\\setup.txt");
+
+ strcat(szFile, "\\setup.txt");
+
+ pmedium->tymed = TYMED_HGLOBAL;
+
+ pmedium->hGlobal = GlobalAlloc( GMEM_DDESHARE,
+ sizeof(DROPFILESTRUCT) +
+ cbFile + 3);
+
+ if( pmedium->hGlobal )
+ {
+ pdfs = (DROPFILESTRUCT *)GlobalLock(pmedium->hGlobal);
+
+ if( pdfs )
+ {
+ pdfs->pFiles = sizeof(DROPFILESTRUCT);
+ pfile = (char *)((BYTE *)pdfs) + sizeof(DROPFILESTRUCT);
+ pdfs->fNC = FALSE;
+ pdfs->fWide = FALSE;
+ pdfs->pt.x = 0;
+ pdfs->pt.y = 0;
+ strcpy(pfile, szFile);
+ // double-NULL terminate it
+ pfile[strlen(pfile)+2] = '\0';
+
+ GlobalUnlock(pmedium->hGlobal);
+
+ sc = S_OK;
+ }
+ else
+ {
+ sc = E_OUTOFMEMORY;
+ }
+ }
+ else
+ {
+ sc = E_OUTOFMEMORY;
+ }
+ }
+
+errRtn:
+
+ return ResultFromScode( sc );
+}
+
+//**********************************************************************
+//
+// CDataXferObj::GetDataHere
+//
+// Purpose:
+//
+// Called to get a data format in a caller supplied location
+//
+// Parameters:
+//
+// LPFORMATETC pformatetc - FORMATETC requested
+//
+// LPSTGMEDIUM pmedium - Medium to return the data
+//
+// Return Value:
+//
+// NOERROR - if OleStdGetOleObjectData success
+// DATA_E_FORMATETC - We don't support the requested format
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// OleStdGetOleObjectData OLE2UI API
+// IOleObject::QueryInterface Object
+//
+//
+//********************************************************************
+
+STDMETHODIMP CDataXferObj::GetDataHere (
+ LPFORMATETC pformatetc,
+ LPSTGMEDIUM pmedium
+)
+{
+ SCODE sc = DV_E_FORMATETC;
+
+ TestDebugOut("In CDataXferObj::GetDataHere\r\n");
+
+ // NOTE: pmedium is an IN parameter. we should NOT set
+ // pmedium->pUnkForRelease to NULL
+
+ // Check the FORMATETC and fill pmedium if valid.
+ if ( (pformatetc->cfFormat == g_cfEmbeddedObject) &&
+ (pformatetc->dwAspect == DVASPECT_CONTENT) &&
+ (pformatetc->tymed == TYMED_ISTORAGE) )
+ {
+ LPPERSISTSTORAGE pPersistStorage;
+
+ /* render CF_EMBEDDEDOBJECT by asking the object to save
+ ** into the IStorage allocated by the caller.
+ */
+ HRESULT hRes;
+
+ if ((hRes=m_lpOleObject->QueryInterface(
+ IID_IPersistStorage, (LPVOID FAR*)&pPersistStorage))
+ != ResultFromScode(S_OK))
+ {
+ return(hRes);
+ }
+ assert(pPersistStorage);
+ HRESULT hrErr = OleStdGetOleObjectData(
+ pPersistStorage, pformatetc, pmedium,0 /*fUseMemory--N/A*/ );
+ pPersistStorage->Release();
+ sc = GetScode( hrErr );
+ }
+ return ResultFromScode( sc );
+}
diff --git a/private/oleutest/simpdnd/dxferobj.h b/private/oleutest/simpdnd/dxferobj.h
new file mode 100644
index 000000000..5e92f20de
--- /dev/null
+++ b/private/oleutest/simpdnd/dxferobj.h
@@ -0,0 +1,57 @@
+//**********************************************************************
+// File name: dxferobj.h
+//
+// Definition of CDataXferObj
+//
+// Copyright (c) 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+
+#if !defined( _DATAXFEROBJ_H_)
+#define _DATAXFEROBJ_H_
+
+class CSimpleSite;
+
+interface CDataObject;
+
+class CDataXferObj : public IDataObject
+{
+private:
+ int m_nCount; // reference count
+ SIZEL m_sizel;
+ POINTL m_pointl;
+ LPSTORAGE m_lpObjStorage;
+ LPOLEOBJECT m_lpOleObject;
+
+ // construction/destruction
+ CDataXferObj();
+ ~CDataXferObj();
+
+public:
+ STDMETHODIMP QueryInterface (REFIID riid, LPVOID FAR* ppvObj);
+ STDMETHODIMP_(ULONG) AddRef ();
+ STDMETHODIMP_(ULONG) Release ();
+
+ STDMETHODIMP DAdvise ( FORMATETC FAR* pFormatetc, DWORD advf,
+ LPADVISESINK pAdvSink, DWORD FAR* pdwConnection)
+ { return ResultFromScode(OLE_E_ADVISENOTSUPPORTED); }
+ STDMETHODIMP DUnadvise ( DWORD dwConnection)
+ { return ResultFromScode(OLE_E_ADVISENOTSUPPORTED); }
+ STDMETHODIMP EnumDAdvise ( LPENUMSTATDATA FAR* ppenumAdvise)
+ { return ResultFromScode(OLE_E_ADVISENOTSUPPORTED); }
+ STDMETHODIMP EnumFormatEtc ( DWORD dwDirection,
+ LPENUMFORMATETC FAR* ppenumFormatEtc);
+ STDMETHODIMP GetCanonicalFormatEtc ( LPFORMATETC pformatetc,
+ LPFORMATETC pformatetcOut)
+ { pformatetcOut->ptd = NULL; return ResultFromScode(E_NOTIMPL); }
+ STDMETHODIMP GetData (LPFORMATETC pformatetcIn, LPSTGMEDIUM pmedium );
+ STDMETHODIMP GetDataHere (LPFORMATETC pformatetc, LPSTGMEDIUM pmedium);
+ STDMETHODIMP QueryGetData (LPFORMATETC pformatetc );
+ STDMETHODIMP SetData (LPFORMATETC pformatetc, STGMEDIUM FAR * pmedium,
+ BOOL fRelease)
+ { return ResultFromScode(E_NOTIMPL); }
+
+ static CDataXferObj FAR* Create(CSimpleSite FAR* lpSite,
+ POINTL FAR* pPointl);
+
+};
+#endif // _DATAXFEROBJ_H_
diff --git a/private/oleutest/simpdnd/enumfetc.h b/private/oleutest/simpdnd/enumfetc.h
new file mode 100644
index 000000000..60b82d151
--- /dev/null
+++ b/private/oleutest/simpdnd/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/simpdnd/filelist.mk b/private/oleutest/simpdnd/filelist.mk
new file mode 100644
index 000000000..748afa91f
--- /dev/null
+++ b/private/oleutest/simpdnd/filelist.mk
@@ -0,0 +1,83 @@
+############################################################################
+#
+# 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 = simpdnd.exe
+RELEASE = 0
+TARGET_DESCRIPTION = "$(PLATFORM) $(BUILDTYPE) Simple DragAndDrop"
+
+
+#
+# Source files. Remember to prefix each name with .\
+#
+
+CFILES =
+CPPFILES = .\app.cpp \
+ .\doc.cpp \
+ .\dxferobj.cpp \
+ .\ias.cpp \
+ .\ids.cpp \
+ .\idt.cpp \
+ .\iocs.cpp \
+ .\pre.cpp \
+ .\simpdnd.cpp \
+ .\site.cpp
+RCFILES = .\simpdnd.rc
+
+#
+# Libraries and other object files to link.
+#
+OBJFILES =
+LIBS = $(CAIROLE)\ilib\$(OBJDIR)\ole232.lib \
+ $(CAIROLE)\ilib\$(OBJDIR)\storag32.lib \
+ $(CAIROLE)\ilib\$(OBJDIR)\compob32.lib \
+ ..\ole2ui\$(OBJDIR)\ole2uixd.lib
+
+!if "$(OPSYS)"=="DOS"
+LIBS = $(LIBS) \
+ $(IMPORT)\CHICAGO\lib\comdlg32.lib \
+ $(IMPORT)\CHICAGO\lib\shell32.lib
+!else
+LIBS = $(LIBS) \
+ $(IMPORT)\$(OPSYS)\lib\$(OBJDIR)\comdlg32.lib \
+ $(IMPORT)\$(OPSYS)\lib\$(OBJDIR)\shell32.lib
+!endif
+
+DEFFILE = .\simpdnd.def
+
+#
+# Precompiled headers.
+#
+
+PXXFILE =
+PFILE =
+CINC = -I..\ole2ui -I..\ole2ui\resource\usa \
+ -I..\ole2ui\resource\static
+!if "$(EXPORT)"=="0"
+CINC = $(CINC) -I$(CAIROLE)\h -I$(CAIROLE)\common
+!else
+CINC = $(CINC) -I$(CAIROLE)\h\export
+!endif
+
+CFLAGS=/D_DEBUG
+
+!if "$(INTERNAL)"=="0"
+CFLAGS = $(CFLAGS) /DNOTREADY
+RCFLAGS = /DNOTREADY
+!endif
+
+# For Chicago Build
+!if "$(OPSYS)"=="DOS"
+CFLAGS=$(CFLAGS) /D_INC_OLE
+!endif
+
diff --git a/private/oleutest/simpdnd/ias.cpp b/private/oleutest/simpdnd/ias.cpp
new file mode 100644
index 000000000..d8ab992b8
--- /dev/null
+++ b/private/oleutest/simpdnd/ias.cpp
@@ -0,0 +1,302 @@
+//**********************************************************************
+// File name: IAS.CPP
+//
+// Implementation file of CAdviseSink
+//
+//
+// Functions:
+//
+// See IAS.H for Class Definition
+//
+// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+
+#include "pre.h"
+#include "iocs.h"
+#include "ias.h"
+#include "app.h"
+#include "site.h"
+#include "doc.h"
+
+//**********************************************************************
+//
+// CAdviseSink::QueryInterface
+//
+// Purpose:
+//
+// Used for interface negotiation
+//
+// Parameters:
+//
+// REFIID riid - The requested interface
+//
+// LPVOID FAR* ppvObj - Place to return the interface
+//
+// Return Value:
+//
+// HRESULT from CSimpleSite::QueryInterface
+//
+// Function Calls:
+// Function Location
+//
+// CSimpleSite::QueryInterface SITE.CPP
+// TestDebugOut Windows API
+//
+// Comments:
+//
+// This function simply delegates to the Object class, which is
+// aware of the supported interfaces.
+//
+//********************************************************************
+
+STDMETHODIMP CAdviseSink::QueryInterface(REFIID riid, LPVOID FAR* ppvObj)
+{
+ TestDebugOut("In IAS::QueryInterface\r\n");
+
+ // delegate to the document Object
+ return m_pSite->QueryInterface(riid, ppvObj);
+}
+
+//**********************************************************************
+//
+// CAdviseSink::AddRef
+//
+// Purpose:
+//
+// Increments the reference count on the CSimpleSite. Since CAdviseSink
+// is a nested class of CSimpleSite, we don't need a separate reference
+// count for CAdviseSink. We can just use the reference count of
+// CSimpleSite.
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// The new reference count of CSimpleSite
+//
+// Function Calls:
+// Function Location
+//
+// CSimpleSite::AddRef SITE.CPP
+// TestDebugOut Windows API
+//
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) CAdviseSink::AddRef()
+{
+ TestDebugOut("In IAS::AddRef\r\n");
+
+ // delegate to the container Site
+ return m_pSite->AddRef();
+}
+
+//**********************************************************************
+//
+// CAdviseSink::Release
+//
+// Purpose:
+//
+// Decrements the reference count on the CSimpleSite. Since CAdviseSink
+// is a nested class of CSimpleSite, we don't need a separate reference
+// count for CAdviseSink. We can just use the reference count of
+// CSimpleSite.
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// The new reference count of CSimpleSite
+//
+// Function Calls:
+// Function Location
+//
+// CSimpleSite::Release SITE.CPP
+// TestDebugOut Windows API
+//
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) CAdviseSink::Release()
+{
+ TestDebugOut("In IAS::Release\r\n");
+
+ // delegate to the container Site
+ return m_pSite->Release();
+}
+
+//**********************************************************************
+//
+// CAdviseSink::OnDataChange
+//
+// Purpose:
+//
+// Not Implemented (needs to be stubbed out)
+//
+// Parameters:
+//
+// FORMATETC pFormatetc - data format infomation
+// STGMEDIUM pStgmed - storage medium on which data is passed
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+//
+//********************************************************************
+
+STDMETHODIMP_(void) CAdviseSink::OnDataChange (FORMATETC FAR* pFormatetc,
+ STGMEDIUM FAR* pStgmed)
+{
+ TestDebugOut("In IAS::OnDataChange\r\n");
+}
+
+//**********************************************************************
+//
+// CAdviseSink::OnViewChange
+//
+// Purpose:
+//
+// Notifies us that the view has changed and needs to be updated.
+//
+// Parameters:
+//
+// DWORD dwAspect - Aspect that has changed
+//
+// LONG lindex - Index that has changed
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// InvalidateRect Windows API
+// IViewObject2::GetExtent Object
+// IViewObject2::Release Object
+// IOleObject::QueryInterface Object
+//
+//
+//********************************************************************
+
+STDMETHODIMP_(void) CAdviseSink::OnViewChange (DWORD dwAspect, LONG lindex)
+{
+ LPVIEWOBJECT2 lpViewObject2;
+ TestDebugOut("In IAS::OnViewChange\r\n");
+
+ // get a pointer to IViewObject2
+ HRESULT hErr = m_pSite->m_lpOleObject->QueryInterface(
+ IID_IViewObject2,
+ (LPVOID FAR *)&lpViewObject2);
+
+ if (hErr == NOERROR)
+ {
+ // get extent of the object
+ // NOTE: this method will never be remoted; it can be called w/i
+ // this async method
+ lpViewObject2->GetExtent(DVASPECT_CONTENT, -1 , NULL,
+ &m_pSite->m_sizel);
+ lpViewObject2->Release();
+ }
+
+ // need to clean up the region
+ InvalidateRect(m_pSite->m_lpDoc->m_hDocWnd, NULL, TRUE);
+}
+
+//**********************************************************************
+//
+// CAdviseSink::OnRename
+//
+// Purpose:
+//
+// Not Implemented (needs to be stubbed out)
+//
+// Parameters:
+//
+// LPMONIKER pmk - pointer to moniker
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+//
+//********************************************************************
+
+STDMETHODIMP_(void) CAdviseSink::OnRename (LPMONIKER pmk)
+{
+ TestDebugOut("In IAS::OnRename\r\n");
+}
+
+//**********************************************************************
+//
+// CAdviseSink::OnSave
+//
+// Purpose:
+//
+// Not Implemented (needs to be stubbed out)
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+//
+//********************************************************************
+
+STDMETHODIMP_(void) CAdviseSink::OnSave ()
+{
+ TestDebugOut("In IAS::OnSave\r\n");
+}
+
+//**********************************************************************
+//
+// CAdviseSink::OnClose
+//
+// Purpose:
+//
+// Not Implemented (needs to be stubbed out)
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+//
+//********************************************************************
+
+STDMETHODIMP_(void) CAdviseSink::OnClose()
+{
+ TestDebugOut("In IAS::OnClose\r\n");
+}
diff --git a/private/oleutest/simpdnd/ias.h b/private/oleutest/simpdnd/ias.h
new file mode 100644
index 000000000..aa71ea70d
--- /dev/null
+++ b/private/oleutest/simpdnd/ias.h
@@ -0,0 +1,43 @@
+//**********************************************************************
+// File name: IAS.H
+//
+// Definition of CAdviseSink
+//
+// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+#if !defined( _IAS_H_ )
+#define _IAS_H_
+
+#include <assert.h>
+
+class CSimpleSite;
+
+interface CAdviseSink : public IAdviseSink
+{
+ CSimpleSite FAR * m_pSite;
+
+ CAdviseSink(CSimpleSite FAR * pSite)
+ {
+ TestDebugOut("In IAS's constructor\r\n");
+ m_pSite = pSite;
+ };
+
+ ~CAdviseSink()
+ {
+ TestDebugOut("In IAS's destructor\r\n");
+ };
+
+ STDMETHODIMP QueryInterface (REFIID riid, LPVOID FAR* ppv);
+ STDMETHODIMP_(ULONG) AddRef ();
+ STDMETHODIMP_(ULONG) Release ();
+
+ // *** IAdviseSink methods ***
+ STDMETHODIMP_(void) OnDataChange (FORMATETC FAR* pFormatetc, STGMEDIUM FAR* pStgmed);
+ STDMETHODIMP_(void) OnViewChange (DWORD dwAspect, LONG lindex);
+ STDMETHODIMP_(void) OnRename (LPMONIKER pmk);
+ STDMETHODIMP_(void) OnSave ();
+ STDMETHODIMP_(void) OnClose ();
+};
+
+
+#endif
diff --git a/private/oleutest/simpdnd/ids.cpp b/private/oleutest/simpdnd/ids.cpp
new file mode 100644
index 000000000..5c7bdf8ad
--- /dev/null
+++ b/private/oleutest/simpdnd/ids.cpp
@@ -0,0 +1,384 @@
+//**********************************************************************
+// File name: IDS.CPP
+//
+// Implementation file for CDropSource
+//
+// Functions:
+//
+// See IDS.H for class definition
+//
+// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+
+#include "pre.h"
+#include "app.h"
+#include "doc.h"
+#include "site.h"
+#include "dxferobj.h"
+
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Member: CSimpleDoc::FailureNotifyHelper(
+//
+// Synopsis: Report a drag drop error
+//
+// Arguments: [pszMsg] - Message
+// [dwData] - Data to print out
+//
+// Algorithm: Print a message box for fatal errors during drag drop
+// operation.
+//
+// History: dd-mmm-yy Author Comment
+// 06-May-94 Ricksa author
+//
+//--------------------------------------------------------------------------
+void CSimpleDoc::FailureNotifyHelper(TCHAR *pszMsg, DWORD dwData)
+{
+ TCHAR pszBuf[256];
+
+ wsprintf(pszBuf, TEXT("%s %lx"), pszMsg, dwData);
+
+ MessageBox(m_hDocWnd, pszBuf, TEXT("Drag/Drop Error"), MB_OK);
+}
+
+
+
+//**********************************************************************
+//
+// CSimpleDoc::QueryDrag
+//
+// Purpose:
+//
+// Check to see if Drag operation should be initiated based on the
+// current position of the mouse.
+//
+// Parameters:
+//
+// POINT pt - position of mouse
+//
+// Return Value:
+//
+// BOOL - TRUE if drag should take place,
+// else FALSE
+//
+// Function Calls:
+// Function Location
+//
+// CSimpleSite::GetObjRect SITE.CPP
+// PtInRect Windows API
+//
+//
+//********************************************************************
+
+BOOL CSimpleDoc::QueryDrag(POINT pt)
+{
+ // if pt is within rect of object, then start drag
+ if (m_lpSite)
+ {
+ RECT rect;
+ m_lpSite->GetObjRect(&rect);
+ return ( PtInRect(&rect, pt) ? TRUE : FALSE );
+ }
+ else
+ return FALSE;
+}
+
+
+//**********************************************************************
+//
+// CSimpleDoc::DoDragDrop
+//
+// Purpose:
+//
+// Actually perform a drag/drop operation with the current
+// selection in the source document.
+//
+// Parameters:
+//
+// none.
+//
+// Return Value:
+//
+// DWORD - returns the result effect of the
+// drag/drop operation:
+// DROPEFFECT_NONE,
+// DROPEFFECT_COPY,
+// DROPEFFECT_MOVE, or
+// DROPEFFECT_LINK
+//
+// Function Calls:
+// Function Location
+//
+// CDataXferObj::Create DXFEROBJ.CPP
+// CDataXferObj::QueryInterface DXFEROBJ.CPP
+// CDataXferObj::Release DXFEROBJ.CPP
+// DoDragDrop OLE API
+// TestDebugOut Windows API
+// MessageBox Windows API
+//
+//
+//********************************************************************
+
+DWORD CSimpleDoc::DoDragDrop (void)
+{
+ DWORD dwEffect = 0;
+ LPDATAOBJECT lpDataObj;
+
+ TestDebugOut("In CSimpleDoc::DoDragDrop\r\n");
+
+ // Create a data transfer object by cloning the existing OLE object
+ CDataXferObj FAR* pDataXferObj = CDataXferObj::Create(m_lpSite,NULL);
+
+ if (! pDataXferObj)
+ {
+ MessageBox(NULL, TEXT("Out-of-memory"), TEXT("SimpDnD"),
+ MB_SYSTEMMODAL | MB_ICONHAND);
+ return DROPEFFECT_NONE;
+ }
+
+ // initially obj is created with 0 refcnt. this QI will make it go to 1.
+ pDataXferObj->QueryInterface(IID_IDataObject, (LPVOID FAR*)&lpDataObj);
+ assert(lpDataObj);
+
+ m_fLocalDrop = FALSE;
+ m_fLocalDrag = TRUE;
+
+ HRESULT hRes;
+ hRes=::DoDragDrop(lpDataObj,
+ &m_DropSource,
+ m_lpApp->m_dwSourceEffect, // we only allow copy
+ &dwEffect);
+
+ if (hRes!=ResultFromScode(S_OK)
+ && hRes!=ResultFromScode(DRAGDROP_S_DROP)
+ && hRes!=ResultFromScode(DRAGDROP_S_CANCEL))
+ {
+ FailureNotifyHelper(
+ TEXT("Unexpected error from DoDragDrop"), hRes);
+ }
+
+ // Validate the responses
+ if (hRes == ResultFromScode(DRAGDROP_S_DROP))
+ {
+ // Drop was successful so make sure the effects make sense
+ if (((dwEffect & m_lpApp->m_dwSourceEffect) == 0)
+ && (dwEffect != DROPEFFECT_NONE))
+ {
+ FailureNotifyHelper(
+ TEXT("Unexpected Effect on DRAGDROP_S_DROP from DoDragDrop"),
+ dwEffect);
+ }
+ }
+ else if ((hRes == ResultFromScode(DRAGDROP_S_CANCEL))
+ || (hRes == ResultFromScode(S_OK)))
+ {
+ // Drop was cancelled/or never happened so the effect s/b none
+ if (dwEffect != DROPEFFECT_NONE)
+ {
+ FailureNotifyHelper(
+ TEXT("Unexpected Effect on S_OK or Cancel from DoDragDrop"),
+ dwEffect);
+ }
+ }
+
+ m_fLocalDrag = FALSE;
+
+ /* if after the Drag/Drop modal (mouse capture) loop is finished
+ ** and a drag MOVE operation was performed, then we must delete
+ ** the selection that was dragged.
+ */
+ if ( (dwEffect & DROPEFFECT_MOVE) != 0 )
+ {
+ // Dump our object - we never save it.
+ m_lpApp->lCreateDoc(m_lpApp->m_hAppWnd, 0, 0, 0);
+ }
+
+ pDataXferObj->Release(); // this should destroy the DataXferObj
+ return dwEffect;
+}
+
+
+
+//**********************************************************************
+//
+// CDropSource::QueryInterface
+//
+// Purpose:
+//
+// Return a pointer to a requested interface
+//
+// Parameters:
+//
+// REFIID riid - ID of interface to be returned
+// LPVOID FAR* ppvObj - Location to return the interface
+//
+// Return Value:
+//
+// S_OK - Interface supported
+// E_NOINTERFACE - Interface NOT supported
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// CSimpleDoc::QueryInterface DOC.CPP
+//
+//
+//********************************************************************
+
+STDMETHODIMP CDropSource::QueryInterface(REFIID riid, LPVOID FAR* ppvObj)
+{
+ TestDebugOut("In IDS::QueryInterface\r\n");
+
+ // delegate to the document
+ return m_pDoc->QueryInterface(riid, ppvObj);
+}
+
+
+//**********************************************************************
+//
+// CDropSource::AddRef
+//
+// Purpose:
+//
+// Increments the reference count of CSimpleDoc. Since CDropSource is
+// a nested class of CSimpleDoc, we don't need a separate reference
+// count for the CDropSource. We can safely use the reference count
+// of CSimpleDoc here.
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// The new reference count of CSimpleDoc
+//
+// Function Calls:
+// Function Location
+//
+// CSimpleDoc::AddRef DOC.CPP
+// TestDebugOut Windows API
+//
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) CDropSource::AddRef()
+{
+ TestDebugOut("In IDS::AddRef\r\n");
+
+ // delegate to the document Object
+ return m_pDoc->AddRef();
+}
+
+//**********************************************************************
+//
+// CDropSource::Release
+//
+// Purpose:
+//
+// Decrements the reference count of CSimpleDoc. Since CDropSource is
+// a nested class of CSimpleDoc, we don't need a separate reference
+// count for the CDropSource. We can safely use the reference count
+// of CSimpleDoc here.
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// The new reference count of CSimpleDoc
+//
+// Function Calls:
+// Function Location
+//
+// CSimpleDoc::Release DOC.CPP
+// TestDebugOut Windows API
+//
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) CDropSource::Release()
+{
+ TestDebugOut("In IDS::Release\r\n");
+
+ // delegate to the document object
+ return m_pDoc->Release();
+}
+
+//**********************************************************************
+//
+// CDropSource::QueryContinueDrag
+//
+// Purpose:
+//
+// Called to determine if a drop should take place or be canceled.
+//
+// Parameters:
+//
+// BOOL fEscapePressed - TRUE if ESCAPE key has been pressed
+// DWORD grfKeyState - key state
+//
+// Return Value:
+//
+// DRAGDROP_S_CANCEL - drag operation should be canceled
+// DRAGDROP_S_DROP - drop operation should be performed
+// S_OK - dragging should continue
+//
+//
+// Function Calls:
+// Function Location
+//
+// ResultFromScode OLE API
+//
+//
+//********************************************************************
+
+STDMETHODIMP CDropSource::QueryContinueDrag (
+ BOOL fEscapePressed,
+ DWORD grfKeyState
+)
+{
+ if (fEscapePressed)
+ return ResultFromScode(DRAGDROP_S_CANCEL);
+ else
+ if (!(grfKeyState & MK_LBUTTON))
+ return ResultFromScode(DRAGDROP_S_DROP);
+ else
+ return NOERROR;
+}
+
+
+//**********************************************************************
+//
+// CDropSource::GiveFeedback
+//
+// Purpose:
+//
+// Called to set cursor feedback
+//
+// Parameters:
+//
+// DWORD dwEffect - drop operation to give feedback for
+//
+// Return Value:
+//
+// DRAGDROP_S_USEDEFAULTCURSORS - tells OLE to use standard cursors
+//
+// Function Calls:
+// Function Location
+//
+// ResultFromScode OLE API
+//
+//
+//********************************************************************
+
+STDMETHODIMP CDropSource::GiveFeedback (DWORD dwEffect)
+{
+ return ResultFromScode(DRAGDROP_S_USEDEFAULTCURSORS);
+}
+
diff --git a/private/oleutest/simpdnd/ids.h b/private/oleutest/simpdnd/ids.h
new file mode 100644
index 000000000..470d05ee2
--- /dev/null
+++ b/private/oleutest/simpdnd/ids.h
@@ -0,0 +1,43 @@
+//**********************************************************************
+// File name: ids.h
+//
+// Definition of CDropSource
+//
+// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+#if !defined( _IDS_H_ )
+#define _IDS_H_
+
+#include <assert.h>
+
+class CSimpleDoc;
+
+interface CDropSource : public IDropSource
+{
+ CSimpleDoc FAR * m_pDoc;
+
+ CDropSource(CSimpleDoc FAR * pDoc)
+ {
+ TestDebugOut("In IDS's constructor\r\n");
+ m_pDoc = pDoc;
+ };
+
+ ~CDropSource()
+ {
+ TestDebugOut("In IDS's destructor\r\n");
+ };
+
+ STDMETHODIMP QueryInterface (REFIID riid, LPVOID FAR* ppv);
+ STDMETHODIMP_(ULONG) AddRef ();
+ STDMETHODIMP_(ULONG) Release ();
+
+ // *** IDropSource methods ***
+ STDMETHODIMP QueryContinueDrag (BOOL fEscapePressed, DWORD grfKeyState);
+ STDMETHODIMP GiveFeedback (DWORD dwEffect);
+
+private:
+
+};
+
+
+#endif
diff --git a/private/oleutest/simpdnd/idt.cpp b/private/oleutest/simpdnd/idt.cpp
new file mode 100644
index 000000000..db83df09a
--- /dev/null
+++ b/private/oleutest/simpdnd/idt.cpp
@@ -0,0 +1,851 @@
+//**********************************************************************
+// File name: IDT.CPP
+//
+// Implementation file for CDropTarget
+//
+// Functions:
+//
+// See IDT.H for class definition
+//
+// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+
+#include "pre.h"
+#include "iocs.h"
+#include "ias.h"
+#include "app.h"
+#include "site.h"
+#include "doc.h"
+#include "idt.h"
+
+extern CLIPFORMAT g_cfObjectDescriptor;
+
+
+//**********************************************************************
+//
+// CDropTarget::QueryDrop
+//
+// Purpose:
+//
+// Check if the desired drop operation (identified by the given key
+// state) is possible at the current mouse position (pointl).
+//
+// Parameters:
+//
+// DWORD grfKeyState - current key state
+// POINTL pointl - position of mouse
+// BOOL fDragScroll - TRUE if drag scrolling cursor should
+// be shown.
+// LPDWORD pdwEffect - (OUT) drag effect that should occur
+//
+// Return Value:
+//
+// BOOL - TRUE if drop could take place,
+// else FALSE
+//
+// Function Calls:
+// Function Location
+//
+// OleStdGetDropEffect OLE2UI API
+//
+//
+//********************************************************************
+
+BOOL CDropTarget::QueryDrop (
+ DWORD grfKeyState,
+ POINTL pointl,
+ BOOL fDragScroll,
+ LPDWORD pdwEffect
+)
+{
+ DWORD dwScrollEffect = 0L;
+ DWORD dwOKEffects = m_pDoc->m_lpApp->m_dwTargetEffect & *pdwEffect;
+
+ /* 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 (! m_fCanDropCopy && ! m_fCanDropLink)
+ 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
+ */
+
+ *pdwEffect = OleStdGetDropEffect(grfKeyState);
+ if (*pdwEffect == 0)
+ {
+ // No modifier keys given. Try in order MOVE, COPY, LINK.
+ if ((DROPEFFECT_MOVE & dwOKEffects) && m_fCanDropCopy)
+ *pdwEffect = DROPEFFECT_MOVE;
+ else if ((DROPEFFECT_COPY & dwOKEffects) && m_fCanDropCopy)
+ *pdwEffect = DROPEFFECT_COPY;
+ else if ((DROPEFFECT_LINK & dwOKEffects) && m_fCanDropLink)
+ *pdwEffect = DROPEFFECT_LINK;
+ else
+ goto dropeffect_none;
+ }
+ else
+ {
+ /* OLE2NOTE: we should check if the drag source application allows
+ ** the desired drop effect.
+ */
+ if (!(*pdwEffect & dwOKEffects))
+ goto dropeffect_none;
+
+ if ((*pdwEffect == DROPEFFECT_COPY || *pdwEffect == DROPEFFECT_MOVE)
+ && ! m_fCanDropCopy)
+ goto dropeffect_none;
+
+ if (*pdwEffect == DROPEFFECT_LINK && ! m_fCanDropLink)
+ goto dropeffect_none;
+ }
+
+ *pdwEffect |= dwScrollEffect;
+ return TRUE;
+
+dropeffect_none:
+
+ *pdwEffect = DROPEFFECT_NONE;
+ return FALSE;
+}
+
+
+//**********************************************************************
+//
+// CDropTarget::QueryDrop
+//
+// Purpose:
+//
+// Check to see if Drag scroll operation should be initiated.
+//
+// Parameters:
+//
+// POINTL pointl - position of mouse
+//
+// Return Value:
+//
+// BOOL - TRUE if scroll cursor should be given
+// else FALSE
+//
+// Function Calls:
+// Function Location
+//
+// ScreenToClient WINDOWS API
+// GetClientRect WINDOWS API
+//
+// Comments:
+// 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 CDropTarget::DoDragScroll (POINTL pointl)
+{
+ DWORD dwScrollDir = SCROLLDIR_NULL;
+ DWORD dwTime = GetCurrentTime();
+ int nScrollInset = m_pDoc->m_lpApp->m_nScrollInset;
+ int nScrollDelay = m_pDoc->m_lpApp->m_nScrollDelay;
+ int nScrollInterval = m_pDoc->m_lpApp->m_nScrollInterval;
+ POINT point;
+ RECT rect;
+
+ point.x = (int)pointl.x;
+ point.y = (int)pointl.y;
+
+ ScreenToClient( m_pDoc->m_hDocWnd, &point);
+ GetClientRect ( m_pDoc->m_hDocWnd, (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;
+ else if (rect.left <= point.x && point.x <= (rect.left+nScrollInset))
+ dwScrollDir = SCROLLDIR_LEFT;
+ else if ((rect.right-nScrollInset) <= point.x && point.x <= rect.right)
+ dwScrollDir = SCROLLDIR_RIGHT;
+
+ if (m_dwTimeEnterScrollArea)
+ {
+ /* cursor was already in Scroll Area */
+
+ if (! dwScrollDir)
+ {
+ /* cusor moved OUT of scroll area.
+ ** clear "EnterScrollArea" time.
+ */
+ m_dwTimeEnterScrollArea = 0L;
+ m_dwNextScrollTime = 0L;
+ m_dwLastScrollDir = SCROLLDIR_NULL;
+
+ }
+ else
+ if (dwScrollDir != m_dwLastScrollDir)
+ {
+ /* cusor moved into a different direction scroll area.
+ ** reset "EnterScrollArea" time to start a new 50ms delay.
+ */
+ m_dwTimeEnterScrollArea = dwTime;
+ m_dwNextScrollTime = dwTime + (DWORD)nScrollDelay;
+ m_dwLastScrollDir = dwScrollDir;
+
+ }
+ else
+ if (dwTime && dwTime >= m_dwNextScrollTime)
+ {
+ m_pDoc->Scroll ( dwScrollDir ); // Scroll document now
+ m_dwNextScrollTime = dwTime + (DWORD)nScrollInterval;
+ }
+ }
+ else
+ {
+ if (dwScrollDir)
+ {
+ /* cusor moved INTO a scroll area.
+ ** reset "EnterScrollArea" time to start a new 50ms delay.
+ */
+ m_dwTimeEnterScrollArea = dwTime;
+ m_dwNextScrollTime = dwTime + (DWORD)nScrollDelay;
+ m_dwLastScrollDir = dwScrollDir;
+ }
+ }
+
+ return (dwScrollDir ? TRUE : FALSE);
+}
+
+
+// Support functions/macros
+#define SetTopLeft(rc, pt) \
+ ((rc)->top = (pt)->y,(rc)->left = (pt)->x)
+#define SetBottomRight(rc, pt) \
+ ((rc)->bottom = (pt)->y,(rc)->right = (pt)->x)
+#define OffsetPoint(pt, dx, dy) \
+ ((pt)->x += dx, (pt)->y += dy)
+
+
+/* HighlightRect
+** -------------
+** Invert rectangle on screen. used for drop target feedback.
+*/
+
+static int HighlightRect(HWND hwnd, HDC hdc, LPRECT rc)
+{
+ POINT pt1, pt2;
+ int old = SetROP2(hdc, R2_NOT);
+ HPEN hpen;
+ HGDIOBJ hold;
+
+ pt1.x = rc->left;
+ pt1.y = rc->top;
+ pt2.x = rc->right;
+ pt2.y = rc->bottom;
+
+ ScreenToClient(hwnd, &pt1);
+ ScreenToClient(hwnd, &pt2);
+
+ hold = SelectObject(hdc, GetStockObject(HOLLOW_BRUSH));
+ hpen = (HPEN) SelectObject(hdc, CreatePen(PS_SOLID, 2,
+ GetSysColor(COLOR_ACTIVEBORDER)));
+
+ Rectangle(hdc, pt1.x, pt1.y, pt2.x, pt2.y);
+
+ SetROP2(hdc, old);
+
+ hold = SelectObject(hdc, hold);
+ hpen = (HPEN) SelectObject(hdc, hpen);
+
+ DeleteObject(hpen);
+
+ return 0;
+}
+
+
+//**********************************************************************
+//
+// CDropTarget::InitDragFeedback
+//
+// Purpose:
+//
+// Initialize data used to draw drop target feedback.
+// As feedback we draw a rectangle the size of the object.
+//
+// Parameters:
+//
+// LPDATAOBJECT pDataObj - IDataObject from Drop source
+// POINTL pointl - position of mouse
+//
+// Return Value:
+//
+// none.
+//
+// Function Calls:
+// Function Location
+//
+// IDataObject::GetData Object
+// XformSizeInHimetricToPixels OLE2UI Library
+// GlobalLock WINDOWS API
+// GlobalUnlock WINDOWS API
+// ReleaseStgMedium OLE2 API
+// OffsetPoint IDT.CPP
+// SetTopLeft IDT.CPP
+// SetBottomRight IDT.CPP
+//
+// Comments:
+// In order to know the size of the object before the object
+// is actually dropped, we render CF_OBJECTDESCRIPTOR format.
+// this data format tells us both the size of the object as
+// well as which aspect is the object is displayed as in the
+// source. If the object is currently displayed as DVASPECT_ICON
+// then we want to create the object also as DVASPECT_ICON.
+//
+//********************************************************************
+
+void CDropTarget::InitDragFeedback(LPDATAOBJECT pDataObj, POINTL pointl)
+{
+ FORMATETC fmtetc;
+ STGMEDIUM stgmed;
+ POINT pt;
+ int height, width;
+ HRESULT hrErr;
+
+ height = width = 100; // some default values
+ pt.x = (int)pointl.x;
+ pt.y = (int)pointl.y;
+
+ // do a GetData for CF_OBJECTDESCRIPTOR format to get the size of the
+ // object as displayed in the source. using this size, initialize the
+ // size for the drag feedback rectangle.
+ fmtetc.cfFormat = g_cfObjectDescriptor;
+ fmtetc.ptd = NULL;
+ fmtetc.lindex = -1;
+ fmtetc.dwAspect = DVASPECT_CONTENT;
+ fmtetc.tymed = TYMED_HGLOBAL;
+
+ hrErr = pDataObj->GetData(&fmtetc, &stgmed);
+ if (hrErr == NOERROR)
+ {
+ LPOBJECTDESCRIPTOR pOD=(LPOBJECTDESCRIPTOR)GlobalLock(stgmed.hGlobal);
+ if (pOD != NULL)
+ {
+ XformSizeInHimetricToPixels(NULL, &pOD->sizel, &pOD->sizel);
+
+ width = (int)pOD->sizel.cx;
+ height = (int)pOD->sizel.cy;
+ m_dwSrcAspect = pOD->dwDrawAspect;
+ }
+
+ GlobalUnlock(stgmed.hGlobal);
+ ReleaseStgMedium(&stgmed);
+ }
+
+ m_ptLast = pt;
+ m_fDragFeedbackDrawn = FALSE;
+
+ OffsetPoint(&pt, -(width/2), -(height/2));
+ SetTopLeft(&m_rcDragRect, &pt);
+
+ OffsetPoint(&pt, width, height);
+ SetBottomRight(&m_rcDragRect, &pt);
+}
+
+
+//**********************************************************************
+//
+// CDropTarget::UndrawDragFeedback
+//
+// Purpose:
+//
+// Erase any drop target feedback.
+// As feedback we draw a rectangle the size of the object.
+//
+// Parameters:
+//
+// none.
+//
+// Return Value:
+//
+// none.
+//
+// Function Calls:
+// Function Location
+//
+// GetDC WINDOWS API
+// ReleaseDC WINDOWS API
+// HighlightRect IDT.CPP
+//
+// Comments:
+// In order to know the size of the object before the object
+// is actually dropped, we render CF_OBJECTDESCRIPTOR format.
+// this data format tells us both the size of the object as
+// well as which aspect is the object is displayed as in the
+// source. if the object is currently displayed as DVASPECT_ICON
+// then we want to create the object also as DVASPECT_ICON.
+//
+//********************************************************************
+
+void CDropTarget::UndrawDragFeedback( void )
+{
+ if (m_fDragFeedbackDrawn)
+ {
+ m_fDragFeedbackDrawn = FALSE;
+ HDC hDC = GetDC(m_pDoc->m_hDocWnd);
+ HighlightRect(m_pDoc->m_hDocWnd, hDC, &m_rcDragRect);
+ ReleaseDC(m_pDoc->m_hDocWnd, hDC);
+ }
+}
+
+
+//**********************************************************************
+//
+// CDropTarget::DrawDragFeedback
+//
+// Purpose:
+//
+// Compute new position of drop target feedback rectangle and
+// erase old rectangle and draw new rectangle.
+// As feedback we draw a rectangle the size of the object.
+//
+// Parameters:
+//
+// POINTL pointl - position of mouse
+//
+// Return Value:
+//
+// none.
+//
+// Function Calls:
+// Function Location
+//
+// OffsetPoint IDT.CPP
+// OffsetRect IDT.CPP
+// HighlightRect IDT.CPP
+// GetDC WINDOWS API
+// ReleaseDC WINDOWS API
+//
+//
+//********************************************************************
+
+void CDropTarget::DrawDragFeedback( POINTL pointl )
+{
+ POINT ptDiff;
+
+ ptDiff.x = (int)pointl.x - m_ptLast.x;
+ ptDiff.y = (int)pointl.y - m_ptLast.y;
+
+ if (m_fDragFeedbackDrawn && (ptDiff.x == 0 && ptDiff.y == 0))
+ return; // mouse did not move; leave rectangle as drawn
+
+ HDC hDC = GetDC(m_pDoc->m_hDocWnd);
+ if (m_fDragFeedbackDrawn)
+ {
+ m_fDragFeedbackDrawn = FALSE;
+ HighlightRect(m_pDoc->m_hDocWnd, hDC, &m_rcDragRect);
+ }
+
+ OffsetRect(&m_rcDragRect, ptDiff.x, ptDiff.y);
+ HighlightRect(m_pDoc->m_hDocWnd, hDC, &m_rcDragRect);
+ m_fDragFeedbackDrawn = TRUE;
+ m_ptLast.x = (int)pointl.x;
+ m_ptLast.y = (int)pointl.y;
+ ReleaseDC(m_pDoc->m_hDocWnd, hDC);
+}
+
+
+//**********************************************************************
+//
+// CDropTarget::QueryInterface
+//
+// Purpose:
+//
+// Used for interface negotiation
+//
+// Parameters:
+//
+// REFIID riid - ID of interface to be returned
+// LPVOID FAR* ppvObj - Location to return the interface
+//
+// Return Value:
+//
+// S_OK - Interface supported
+// E_NOINTERFACE - Interface NOT supported
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// CSimpleDoc::QueryInterface DOC.CPP
+//
+//
+//********************************************************************
+
+STDMETHODIMP CDropTarget::QueryInterface(REFIID riid, LPVOID FAR* ppvObj)
+{
+ TestDebugOut("In IDT::QueryInterface\r\n");
+
+ // delegate to the document
+ return m_pDoc->QueryInterface(riid, ppvObj);
+}
+
+
+//**********************************************************************
+//
+// CDropTarget::AddRef
+//
+// Purpose:
+//
+// Increments the reference count of CSimpleDoc. Since CDropTarget is
+// a nested class of CSimpleDoc, we don't need a separate reference
+// count for CDropTarget. We can safely use the reference count of
+// CSimpleDoc.
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// The new reference count of CSimpleDoc
+//
+// Function Calls:
+// Function Location
+//
+// CSimpleDoc::AddReff DOC.CPP
+// TestDebugOut Windows API
+//
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) CDropTarget::AddRef()
+{
+ TestDebugOut("In IDT::AddRef\r\n");
+
+ // delegate to the document Object
+ return m_pDoc->AddRef();
+}
+
+//**********************************************************************
+//
+// CDropTarget::Release
+//
+// Purpose:
+//
+// Decrements the reference count of CSimpleDoc. Since CDropTarget is
+// a nested class of CSimpleDoc, we don't need a separate reference
+// count for CDropTarget. We can safely use the reference count of
+// CSimpleDoc.
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// The new reference count of CSimpleDoc
+//
+// Function Calls:
+// Function Location
+//
+// CSimpleDoc::Release DOC.CPP
+// TestDebugOut Windows API
+//
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) CDropTarget::Release()
+{
+ TestDebugOut("In IDT::Release\r\n");
+
+ // delegate to the document object
+ return m_pDoc->Release();
+}
+
+
+//**********************************************************************
+//
+// CDropTarget::DragEnter
+//
+// Purpose:
+//
+// Called when the mouse first enters our DropTarget window
+//
+// Parameters:
+//
+// LPDATAOBJECT pDataObj - IDataObject from Drop source
+// DWORD grfKeyState - current key state
+// POINTL pointl - position of mouse
+// LPDWORD pdwEffect - (IN-OUT) drag effect that should occur
+// ON INPUT, this is dwOKEffects that source
+// passed to DoDragDrop API.
+// ON OUTPUT, this is the effect that we
+// want to take effect (used to determine
+// cursor feedback).
+//
+// Return Value:
+//
+// NOERROR
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// OleQueryCreateFromData OLE2 API
+// DoDragScroll IDT.CPP
+// QueryDrop IDT.CPP
+// InitDragFeedback IDT.CPP
+// DrawDragFeedback IDT.CPP
+//
+// Comments:
+// Callee should honor the dwEffects as passed in to determine
+// if the caller allows DROPEFFECT_MOVE.
+//
+//********************************************************************
+
+STDMETHODIMP CDropTarget::DragEnter(LPDATAOBJECT pDataObj, DWORD grfKeyState,
+ POINTL pointl, LPDWORD pdwEffect)
+{
+ TestDebugOut("In IDT::DragEnter\r\n");
+
+ /* Determine if the drag source data object offers a data format
+ ** that we understand. we accept only creating embedded objects.
+ */
+ m_fCanDropCopy = ((OleQueryCreateFromData(pDataObj) == NOERROR) ?
+ TRUE : FALSE);
+ m_fCanDropLink = FALSE; // linking NOT supported in this simple sample
+
+ if (m_fCanDropCopy || m_fCanDropLink)
+ InitDragFeedback(pDataObj, pointl);
+
+ BOOL fDragScroll = DoDragScroll ( pointl );
+
+ if (QueryDrop(grfKeyState,pointl,fDragScroll,pdwEffect))
+ {
+ DrawDragFeedback( pointl );
+ }
+
+ // with our drag drop optimization, pDataObj will actually be a
+ // wrapper data object. QueryGetData calls (currently) will be
+ // propogated to the drag source (whereas EnumFormatetc is handled
+ // locally). Make sure we can do a QueryGetData.
+
+ FORMATETC formatetc;
+ formatetc.cfFormat = CF_METAFILEPICT;
+ formatetc.tymed = TYMED_MFPICT;
+ formatetc.ptd = NULL;
+ formatetc.lindex = -1;
+ formatetc.dwAspect = DVASPECT_CONTENT;
+
+ // E_FAIL is usually returned if we could not get the drag source
+ // data object.
+ if( pDataObj->QueryGetData(&formatetc) == E_FAIL )
+ {
+ TestDebugOut("WARNING! QueryGetData failed!");
+ }
+
+ return NOERROR;
+}
+
+
+//**********************************************************************
+//
+// CDropTarget::DragOver
+//
+// Purpose:
+//
+// Called when the mouse moves, key state changes, or a time
+// interval passes while the mouse is still within our DropTarget
+// window.
+//
+// Parameters:
+//
+// DWORD grfKeyState - current key state
+// POINTL pointl - position of mouse
+// LPDWORD pdwEffect - (IN-OUT) drag effect that should occur
+// ON INPUT, this is dwOKEffects that source
+// passed to DoDragDrop API.
+// ON OUTPUT, this is the effect that we
+// want to take effect (used to determine
+// cursor feedback).
+//
+// Return Value:
+//
+// NOERROR
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// DoDragScroll IDT.CPP
+// QueryDrop IDT.CPP
+// DrawDragFeedback IDT.CPP
+// UndrawDragFeedback IDT.CPP
+//
+// Comments:
+// Callee should honor the dwEffects as passed in to determine
+// if the caller allows DROPEFFECT_MOVE. OLE pulses the DragOver
+// calls in order that the DropTarget can implement drag scrolling
+//
+//********************************************************************
+
+STDMETHODIMP CDropTarget::DragOver (DWORD grfKeyState, POINTL pointl,
+ LPDWORD pdwEffect)
+{
+ TestDebugOut("In IDT::DragOver\r\n");
+
+ BOOL fDragScroll = DoDragScroll ( pointl );
+
+ if (QueryDrop(grfKeyState,pointl,fDragScroll,pdwEffect))
+ {
+ DrawDragFeedback( pointl );
+ }
+ else
+ {
+ UndrawDragFeedback();
+ }
+
+ return NOERROR;
+}
+
+
+//**********************************************************************
+//
+// CDropTarget::DragLeave
+//
+// Purpose:
+//
+// Called when the mouse leaves our DropTarget window
+//
+// Parameters:
+//
+// none.
+//
+// Return Value:
+//
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// UndrawDragFeedback IDT.CPP
+// ResultFromScode OLE2 API
+//
+//
+//********************************************************************
+
+STDMETHODIMP CDropTarget::DragLeave ()
+{
+ TestDebugOut("In IDT::DragLeave\r\n");
+
+ UndrawDragFeedback();
+
+ return ResultFromScode(S_OK);
+}
+
+
+//**********************************************************************
+//
+// CDropTarget::Drop
+//
+// Purpose:
+//
+// Called when a Drop operation should take place.
+//
+// Parameters:
+//
+// LPDATAOBJECT pDataObj - IDataObject from Drop source
+// DWORD grfKeyState - current key state
+// POINTL pointl - position of mouse
+// LPDWORD pdwEffect - (IN-OUT) drag effect that should occur
+// ON INPUT, this is dwOKEffects that source
+// passed to DoDragDrop API.
+// ON OUTPUT, this is the effect that we
+// want to take effect (used to determine
+// cursor feedback).
+//
+// Return Value:
+//
+// S_OK if sucess or HRESULT of the error code if fails
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// CSimpleSite::Create SITE.CPP
+// CSimpleSite::InitObject SITE.CPP
+// OleCreateFromData OLE2 API
+// DoDragScroll IDT.CPP
+// QueryDrop IDT.CPP
+// InitDragFeedback IDT.CPP
+// DrawDragFeedback IDT.CPP
+// UndrawDragFeedback IDT.CPP
+// GetScode OLE2 API
+// ResultFromScode OLE2 API
+//
+// Comments:
+// Callee should honor the dwEffects as passed in to determine
+// if the caller allows DROPEFFECT_MOVE.
+//
+//********************************************************************
+
+STDMETHODIMP CDropTarget::Drop (LPDATAOBJECT pDataObj, DWORD grfKeyState,
+ POINTL pointl, LPDWORD pdwEffect)
+{
+ FORMATETC fmtetc;
+ SCODE sc = S_OK;
+
+ TestDebugOut("In IDT::Drop\r\n");
+
+ UndrawDragFeedback();
+
+ if (pDataObj && QueryDrop(grfKeyState,pointl,FALSE,pdwEffect))
+ {
+ m_pDoc->m_lpSite = CSimpleSite::Create(m_pDoc);
+ if (!m_pDoc->m_lpSite)
+ {
+ /* memory allocation problem. cannot continue.
+ */
+ return(ResultFromScode(E_OUTOFMEMORY));
+ }
+
+ // keep same aspect as drop source
+ m_pDoc->m_lpSite->m_dwDrawAspect = m_dwSrcAspect;
+
+ // in order to specify a particular drawing Aspect we must
+ // pass a FORMATETC* to OleCreateFromData
+ fmtetc.cfFormat = NULL; // use whatever for drawing
+ fmtetc.ptd = NULL;
+ fmtetc.lindex = -1;
+ fmtetc.dwAspect = m_dwSrcAspect; // desired drawing aspect
+ fmtetc.tymed = TYMED_NULL;
+
+ HRESULT hrErr = OleCreateFromData (
+ pDataObj,
+ IID_IOleObject,
+ OLERENDER_DRAW,
+ &fmtetc,
+ &m_pDoc->m_lpSite->m_OleClientSite,
+ m_pDoc->m_lpSite->m_lpObjStorage,
+ (LPVOID FAR *)&m_pDoc->m_lpSite->m_lpOleObject);
+
+ if (hrErr == NOERROR)
+ {
+ m_pDoc->m_lpSite->InitObject(FALSE /* fCreateNew */);
+ m_pDoc->DisableInsertObject();
+ }
+ else
+ sc = GetScode(hrErr);
+ }
+
+ return ResultFromScode(sc);
+}
diff --git a/private/oleutest/simpdnd/idt.h b/private/oleutest/simpdnd/idt.h
new file mode 100644
index 000000000..16b82071d
--- /dev/null
+++ b/private/oleutest/simpdnd/idt.h
@@ -0,0 +1,76 @@
+//**********************************************************************
+// File name: idt.h
+//
+// Definition of CDropTarget
+//
+// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+#if !defined( _IDT_H_ )
+#define _IDT_H_
+
+#include <assert.h>
+
+class CSimpleDoc;
+
+/* Flags to control direction for drag scrolling */
+typedef enum tagSCROLLDIR {
+ SCROLLDIR_NULL = 0,
+ SCROLLDIR_UP = 1,
+ SCROLLDIR_DOWN = 2,
+ SCROLLDIR_RIGHT = 3,
+ SCROLLDIR_LEFT = 4
+} SCROLLDIR;
+
+interface CDropTarget : public IDropTarget
+{
+ CSimpleDoc FAR * m_pDoc;
+ BOOL m_fCanDropCopy;
+ BOOL m_fCanDropLink;
+ DWORD m_dwSrcAspect;
+ RECT m_rcDragRect;
+ POINT m_ptLast;
+ BOOL m_fDragFeedbackDrawn;
+ DWORD m_dwTimeEnterScrollArea; // time of entering scroll border region
+ DWORD m_dwLastScrollDir; // current dir for drag scroll
+ DWORD m_dwNextScrollTime; // time for next scroll
+
+ CDropTarget(CSimpleDoc FAR * pDoc)
+ {
+ TestDebugOut("In IDT's constructor\r\n");
+ m_pDoc = pDoc;
+ m_fCanDropCopy = FALSE;
+ m_fCanDropLink = FALSE;
+ m_fDragFeedbackDrawn = FALSE;
+ m_dwTimeEnterScrollArea = 0L;
+ m_dwNextScrollTime = 0L;
+ m_dwLastScrollDir = SCROLLDIR_NULL;
+ };
+
+ ~CDropTarget()
+ {
+ TestDebugOut("In IDT's destructor\r\n");
+ } ;
+
+ STDMETHODIMP QueryInterface (REFIID riid, LPVOID FAR* ppv);
+ STDMETHODIMP_(ULONG) AddRef ();
+ STDMETHODIMP_(ULONG) Release ();
+
+ // *** IDropTarget methods ***
+ STDMETHODIMP DragEnter (LPDATAOBJECT pDataObj, DWORD grfKeyState,
+ POINTL pt, LPDWORD pdwEffect);
+ STDMETHODIMP DragOver (DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect);
+ STDMETHODIMP DragLeave ();
+ STDMETHODIMP Drop (LPDATAOBJECT pDataObj, DWORD grfKeyState, POINTL pt,
+ LPDWORD pdwEffect);
+
+private:
+ // Drag/Drop support methods
+ BOOL QueryDrop (DWORD grfKeyState, POINTL pointl, BOOL fDragScroll,
+ LPDWORD lpdwEffect);
+ BOOL DoDragScroll( POINTL pointl );
+ void InitDragFeedback(LPDATAOBJECT pDataObj, POINTL pointl);
+ void DrawDragFeedback( POINTL pointl );
+ void UndrawDragFeedback( void );
+};
+
+#endif // _IDT_H_
diff --git a/private/oleutest/simpdnd/iocs.cpp b/private/oleutest/simpdnd/iocs.cpp
new file mode 100644
index 000000000..c17b08b5f
--- /dev/null
+++ b/private/oleutest/simpdnd/iocs.cpp
@@ -0,0 +1,365 @@
+//**********************************************************************
+// File name: IOCS.CPP
+//
+// Implementation file for COleClientSite
+//
+// Functions:
+//
+// See IOCS.H for class definition
+//
+// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+
+#include "pre.h"
+#include "iocs.h"
+#include "ias.h"
+#include "app.h"
+#include "site.h"
+#include "doc.h"
+
+
+//**********************************************************************
+//
+// COleClientSite::QueryInterface
+//
+// Purpose:
+//
+// Used for interface negotiation
+//
+// Parameters:
+//
+// REFIID riid - A reference to the interface that is
+// being queried.
+//
+// LPVOID FAR* ppvObj - An out parameter to return a pointer to
+// the interface.
+//
+// Return Value:
+//
+// S_OK - The interface is supported.
+// E_NOINTERFACE - The interface is not supported
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// CSimpleSite::QueryInterface SITE.CPP
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleClientSite::QueryInterface(REFIID riid, LPVOID FAR* ppvObj)
+{
+ TestDebugOut("In IOCS::QueryInterface\r\n");
+
+ // delegate to the container Site
+ return m_pSite->QueryInterface(riid, ppvObj);
+}
+
+//**********************************************************************
+//
+// COleClientSite::AddRef
+//
+// Purpose:
+//
+// Increments the reference count to CSimpleSite. Since COleClientSite
+// is a nested class of CSimpleSite, we don't need an extra reference
+// count for COleClientSite. We can safely use the reference count of
+// CSimpleSite.
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// ULONG - The new reference count of CSimpleSite
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// CSimpleSite::AddRef SITE.CPP
+//
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) COleClientSite::AddRef()
+{
+ TestDebugOut("In IOCS::AddRef\r\n");
+
+ // delegate to the container Site
+ return m_pSite->AddRef();
+}
+
+
+//**********************************************************************
+//
+// COleClientSite::Release
+//
+// Purpose:
+//
+// Decrements the reference count to CSimpleSite. Since COleClientSite
+// is a nested class of CSimpleSite, we don't need an extra reference
+// count for COleClientSite. We can safely use the reference count of
+// CSimpleSite.
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// ULONG - The new reference count of the CSimpleSite
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// CSimpleSite::Release SITE.CPP
+//
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) COleClientSite::Release()
+{
+ TestDebugOut("In IOCS::Release\r\n");
+
+ // delegate to the container Site
+ return m_pSite->Release();
+}
+
+//**********************************************************************
+//
+// COleClientSite::SaveObject
+//
+// Purpose:
+//
+// Called by the object when it wants to be saved to persistant
+// storage
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// IOleObject::QueryInterface Object
+// IPersistStorage::SaveCompleted Object
+// IPersistStorage::Release Object
+// ResultFromScode OLE API
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleClientSite::SaveObject()
+{
+ LPPERSISTSTORAGE lpPS;
+ SCODE sc = E_FAIL;
+
+ TestDebugOut("In IOCS::SaveObject\r\n");
+
+ // get a pointer to IPersistStorage
+ HRESULT hErr = m_pSite->m_lpOleObject->QueryInterface(
+ IID_IPersistStorage,(LPVOID FAR *)&lpPS);
+
+ // save the object
+ if (hErr == NOERROR)
+ {
+ sc = GetScode( OleSave(lpPS, m_pSite->m_lpObjStorage, TRUE) );
+ lpPS->SaveCompleted(NULL);
+ lpPS->Release();
+ }
+
+ return ResultFromScode(sc);
+}
+
+//**********************************************************************
+//
+// COleClientSite::GetMoniker
+//
+// Purpose:
+//
+// Not Implemented
+//
+// Parameters:
+//
+// DWORD dwAssign - the type of Moniker to be returned
+// DWORD dwWhichMoniker - which Moniker to be returned in ppmk
+// LPMONIKER ppmk - point to where to return the Moniker
+//
+// Return Value:
+//
+// E_NOTIMPL
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+// Comments:
+//
+// This function is not implemented because we don't support
+// linking.
+//
+//********************************************************************
+
+STDMETHODIMP COleClientSite::GetMoniker(DWORD dwAssign, DWORD dwWhichMoniker,
+ LPMONIKER FAR* ppmk)
+{
+ TestDebugOut("In IOCS::GetMoniker\r\n");
+
+ // need to null the out pointer
+ *ppmk = NULL;
+
+ return ResultFromScode(E_NOTIMPL);
+}
+
+//**********************************************************************
+//
+// COleClientSite::GetContainer
+//
+// Purpose:
+//
+// Not Implemented
+//
+// Parameters:
+//
+// LPOLECONTAINER ppContainer - point to where the interface to be
+// returned
+//
+// Return Value:
+//
+// E_NOTIMPL
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleClientSite::GetContainer(LPOLECONTAINER FAR* ppContainer)
+{
+ TestDebugOut("In IOCS::GetContainer\r\n");
+
+ // NULL the out pointer
+ *ppContainer = NULL;
+
+ return ResultFromScode(E_NOTIMPL);
+}
+
+//**********************************************************************
+//
+// COleClientSite::ShowObject
+//
+// Purpose:
+//
+// Not Implemented
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// NOERROR
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+// Comments:
+//
+// This function is not implemented because we don't support
+// linking.
+//
+//********************************************************************
+
+STDMETHODIMP COleClientSite::ShowObject()
+{
+ TestDebugOut("In IOCS::ShowObject\r\n");
+ return NOERROR;
+}
+
+//**********************************************************************
+//
+// COleClientSite::OnShowWindow
+//
+// Purpose:
+//
+// Object calls this method when it is opening/closing non-InPlace
+// Window
+//
+// Parameters:
+//
+// BOOL fShow - TRUE if Window is opening, FALSE if closing
+//
+// Return Value:
+//
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// InvalidateRect Windows API
+// BringWindowToTop Windows API
+// SetFocus Windows API
+// ResultFromScode OLE API
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleClientSite::OnShowWindow(BOOL fShow)
+{
+ TestDebugOut("In IOCS::OnShowWindow\r\n");
+ m_pSite->m_fObjectOpen = fShow;
+ InvalidateRect(m_pSite->m_lpDoc->m_hDocWnd, NULL, TRUE);
+
+ // if object window is closing, then bring container window to top
+ if (! fShow)
+ {
+ BringWindowToTop(m_pSite->m_lpDoc->m_hDocWnd);
+ SetFocus(m_pSite->m_lpDoc->m_hDocWnd);
+ }
+ return ResultFromScode(S_OK);
+}
+
+//**********************************************************************
+//
+// COleClientSite::RequestNewObjectLayout
+//
+// Purpose:
+//
+// Not Implemented
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// E_NOTIMPL
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleClientSite::RequestNewObjectLayout()
+{
+ TestDebugOut("In IOCS::RequestNewObjectLayout\r\n");
+ return ResultFromScode(E_NOTIMPL);
+}
diff --git a/private/oleutest/simpdnd/iocs.h b/private/oleutest/simpdnd/iocs.h
new file mode 100644
index 000000000..54b90ec32
--- /dev/null
+++ b/private/oleutest/simpdnd/iocs.h
@@ -0,0 +1,44 @@
+//**********************************************************************
+// File name: IOCS.H
+//
+// Definition of COleClientSite
+//
+// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+#if !defined( _IOCS_H_ )
+#define _IOCS_H_
+
+#include <assert.h>
+
+class CSimpleSite;
+
+interface COleClientSite : public IOleClientSite
+{
+ CSimpleSite FAR * m_pSite;
+
+ COleClientSite(CSimpleSite FAR * pSite)
+ {
+ TestDebugOut("In IOCS's constructor\r\n");
+ m_pSite = pSite;
+ }
+
+ ~COleClientSite()
+ {
+ TestDebugOut("In IOCS's destructor\r\n");
+ }
+
+ STDMETHODIMP QueryInterface(REFIID riid, LPVOID FAR* ppvObj);
+ STDMETHODIMP_(ULONG) AddRef();
+ STDMETHODIMP_(ULONG) Release();
+
+ // *** IOleClientSite methods ***
+ STDMETHODIMP SaveObject();
+ STDMETHODIMP GetMoniker(DWORD dwAssign, DWORD dwWhichMoniker,
+ LPMONIKER FAR* ppmk);
+ STDMETHODIMP GetContainer(LPOLECONTAINER FAR* ppContainer);
+ STDMETHODIMP ShowObject();
+ STDMETHODIMP OnShowWindow(BOOL fShow);
+ STDMETHODIMP RequestNewObjectLayout();
+};
+
+#endif
diff --git a/private/oleutest/simpdnd/pre.cpp b/private/oleutest/simpdnd/pre.cpp
new file mode 100644
index 000000000..9603f4089
--- /dev/null
+++ b/private/oleutest/simpdnd/pre.cpp
@@ -0,0 +1,9 @@
+//**********************************************************************
+// File name: pre.cpp
+//
+// Used for precompiled headers
+//
+// Copyright (c) 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+
+#include "pre.h"
diff --git a/private/oleutest/simpdnd/pre.h b/private/oleutest/simpdnd/pre.h
new file mode 100644
index 000000000..141d528d5
--- /dev/null
+++ b/private/oleutest/simpdnd/pre.h
@@ -0,0 +1,30 @@
+//**********************************************************************
+// File name: pre.h
+//
+// Used for precompiled headers
+//
+// Copyright (c) 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+
+#if !defined( _PRE_H_)
+#define _PRE_H_
+
+#include <windows.h>
+#include <ole2.h>
+#include <ole2ui.h>
+#include <assert.h>
+#include <string.h>
+#include "simpdnd.h"
+#include "resource.h"
+
+
+extern "C" void TestDebugOut(LPSTR psz);
+
+#ifndef WIN32
+/* Since OLE is part of the operating system in Win32, we don't need to
+ * check the version number in Win32.
+ */
+#include <ole2ver.h>
+#endif // WIN32
+
+#endif
diff --git a/private/oleutest/simpdnd/readme.txt b/private/oleutest/simpdnd/readme.txt
new file mode 100644
index 000000000..afcca0b6c
--- /dev/null
+++ b/private/oleutest/simpdnd/readme.txt
@@ -0,0 +1,47 @@
+Simple Drag and Drop Sample
+---------------------------
+
+This sample demonstrates an implementation of OLE 2 drag and drop. It allows
+drag and drop operations between two instances of the sample application.
+For information on compiling and building the sample, see the makefile in
+this directory.
+
+
+Simple Drag and Drop Objects Overview :
+---------------------------------------
+Simple Drag and Drop consists of three main objects. The top level is
+CSimpleApp, under which is CSimpleDoc, and the innermost level is CSimpleSite.
+CSimpleApp is used to hold all the main window information. (eg. handle to
+the main window, handles to the main, edit, and help menus and the application
+instance) CSimpleApp always exists as long as the simple drag and drop
+application is alive.
+
+The next level object is CSimpleDoc object. It is instantiated when a new
+document is created. It enables and disables the menu items in the main menu.
+Since simple drag and drop is a single document interface application, the
+user is only allowed to insert one object into the document. It is
+necessary to disable certain items from the main menu to avoid incorrect
+selection. It also registers the window for drag and drop and manipulates
+the clipboard operations, such as copy to the clipboard, flush the clipboard.
+It demonstrates the implementates of two OLE interfaces in its nested classes,
+IDropSource and IDropTarget. These two interfaces are implemented as
+CDropSource and CDropTarget respectively.
+
+The CSimpleDoc object instantiates two different objects based on the user
+selection from the main menu. The CSimpleSite object is instantiated if the
+user chooses to insert a new object into the document. CSimpleSite
+demonstrates the implementation of IAdviseSink and IOleClientSite through its
+nested classes. These two interfaces are implemented as CAdviseSink and
+COleClientSite accordingly. CSimpleSite manipulates the storage handling and
+acts as a client site to communicate to a remote server. Such server can be
+an executable server or a dll server. The CDataXferObj object is instantiated
+when the user chooses to copy the existing object from the current document.
+it is required to copy an object to the clipboard. CDataXferObj demonstrates
+the IDataObject interface implementation and performs data transfer
+operations.
+
+
+
+
+
+ \ No newline at end of file
diff --git a/private/oleutest/simpdnd/resource.h b/private/oleutest/simpdnd/resource.h
new file mode 100644
index 000000000..2817b0642
--- /dev/null
+++ b/private/oleutest/simpdnd/resource.h
@@ -0,0 +1,39 @@
+//{{NO_DEPENDENCIES}}
+// App Studio generated include file.
+// Used by SIMPDND.RC
+//
+#define IDM_OPEN 102
+#define IDC_DRAGPENDING 102
+#define IDM_SAVE 103
+#define IDM_SAVEAS 104
+#define IDM_PRINT 105
+#define IDM_EXIT 106
+#define IDM_UNDO 107
+#define IDM_CUT 108
+#define IDM_COPY 109
+#define IDM_PASTE 110
+#define ID_EDIT_INSERTOBJECT 111
+#define IDM_INSERTOBJECT 111
+#define IDM_NEW 112
+#define IDM_SOURCE_COPY 113
+#define IDM_SOURCE_MOVE 114
+#define IDM_SOURCE_COPYMOVE 115
+#define IDM_TARGET_COPY 116
+#define IDM_TARGET_MOVE 117
+#define IDM_TARGET_COPYMOVE 118
+
+// Menu positions of source/target effects menus
+#define SOURCE_EFFECTS_MENU_POS 0
+#define TARGET_EFFECTS_MENU_POS 1
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+
+#define _APS_NEXT_RESOURCE_VALUE 103
+#define _APS_NEXT_COMMAND_VALUE 113
+#define _APS_NEXT_CONTROL_VALUE 1000
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/private/oleutest/simpdnd/simpdnd.cpp b/private/oleutest/simpdnd/simpdnd.cpp
new file mode 100644
index 000000000..b70a99e30
--- /dev/null
+++ b/private/oleutest/simpdnd/simpdnd.cpp
@@ -0,0 +1,502 @@
+//**********************************************************************
+// File name: Simple.cpp
+//
+// Main source file for the Simple OLE 2.0 object container
+//
+// Functions:
+//
+// WinMain - Program entry point
+// MainWndProc - Processes messages for the frame window
+// About - Processes messages for the about dialog
+// DocWndProc - Processes messages for the doc window
+//
+// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+
+#include "pre.h"
+#include "iocs.h"
+#include "ias.h"
+#include "app.h"
+#include "site.h"
+#include "doc.h"
+#include <stdlib.h>
+#include <testmess.h>
+#include "tests.h"
+
+
+// This line is needed for the debug utilities in OLE2UI
+extern "C" {
+ OLEDBGDATA_MAIN(TEXT("SIMPDND"))
+}
+
+CSimpleApp FAR * lpCSimpleApp;
+BOOL fBeVerbose = FALSE;
+extern "C"
+void TestDebugOut(LPSTR psz)
+{
+ if (fBeVerbose)
+ {
+ OutputDebugStringA(psz);
+ }
+}
+
+BOOL gfUseEmptyEnumerator;
+
+
+//**********************************************************************
+//
+// WinMain
+//
+// Purpose:
+//
+// Program entry point
+//
+// Parameters:
+//
+// HANDLE hInstance - Instance handle for this instance
+//
+// HANDLE hPrevInstance - Instance handle for the last instance
+//
+// LPSTR lpCmdLine - Pointer to the command line
+//
+// int nCmdShow - Window State
+//
+// Return Value:
+//
+// msg.wParam or FALSE if failure to initialize
+//
+// Function Calls:
+// Function Location
+//
+// CSimpleApp::CSimpleApp APP.CPP
+// CSimpleApp::fInitApplication APP.CPP
+// CSimpleApp::fInitInstance APP.CPP
+// CSimpleApp::~CSimpleApp APP.CPP
+// CSimpleApp::AddRef APP.CPP
+// CSimpleApp::Release APP.CPP
+// OleUIInitialize OLE2UI
+// OleUIUninitialize OLE2UI
+// GetMessage Windows API
+// SetMessageQueue Windows API
+// MessageBox Windows API
+// TranslateMessage Windows API
+// DispatchMessage Windows API
+//
+//
+//********************************************************************
+
+int PASCAL WinMain
+#ifdef WIN32
+ (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine,
+ int nCmdShow)
+#else
+ (HANDLE hInstance, HANDLE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
+#endif
+{
+ MSG msg;
+ LPSTR pszTemp;
+ fBeVerbose = GetProfileInt("OLEUTEST","BeVerbose",0);
+
+ if(fBeVerbose == 0)
+ {
+ fBeVerbose = GetProfileInt("OLEUTEST","simpdnd",0);
+ }
+
+ // needed for LRPC to work properly...
+ SetMessageQueue(96);
+
+ lpCSimpleApp = new CSimpleApp;
+
+
+ if (!lpCSimpleApp)
+ {
+ /* memory allocation problem. We cannot carry on.
+ */
+ MessageBox(NULL, TEXT("Out of Memory"), TEXT("SimpDnD"),
+ MB_SYSTEMMODAL | MB_ICONHAND);
+ return(FALSE);
+ }
+
+ // we will add one ref count on our App. later when we want to destroy
+ // the App object we will release this ref count. when the App's ref
+ // count goes to 0, it will be deleted.
+ lpCSimpleApp->AddRef();
+
+ // process the command line
+
+ if( (pszTemp = strstr(lpCmdLine, "-driver")) )
+ {
+ //we were launched by the test driver
+ lpCSimpleApp->m_hDriverWnd = (HWND)strtoul(pszTemp+8, NULL, 10);
+ }
+
+ // check for the -empty flag (use empty enumerator)
+ if( strstr(lpCmdLine, "-empty") )
+ {
+ gfUseEmptyEnumerator = TRUE;
+ }
+
+ // app initialization
+ if (!hPrevInstance)
+ if (!lpCSimpleApp->fInitApplication(hInstance))
+ {
+ lpCSimpleApp->Release();
+ return (FALSE);
+ }
+
+ // instance initialization
+ if (!lpCSimpleApp->fInitInstance(hInstance, nCmdShow))
+ {
+ lpCSimpleApp->Release();
+ return (FALSE);
+ }
+
+#if 0
+ /* Initialization required for OLE 2 UI library. This call is
+ ** needed ONLY if we are using the static link version of the UI
+ ** library. If we are using the DLL version, we should NOT call
+ ** this function in our application.
+ */
+
+ if (!OleUIInitialize(hInstance, hPrevInstance, TEXT(SZCLASSICONBOX),
+ TEXT(SZCLASSRESULTIMAGE)))
+ {
+ OleDbgOut(TEXT("Could not initialize OLEUI library\n"));
+ lpCSimpleApp->Release();
+ return FALSE;
+ }
+#endif
+ // message loop
+ while (GetMessage(&msg, NULL, NULL, NULL))
+ if (!lpCSimpleApp->HandleAccelerators(&msg))
+ {
+ TranslateMessage(&msg); /* Translates virtual key codes */
+ DispatchMessage(&msg); /* Dispatches message to window */
+ }
+
+#if 0
+ // De-initialization for UI libraries. Just like OleUIInitialize, this
+ // funciton is needed ONLY if we are using the static link version of the
+ // OLE UI library.
+ OleUIUninitialize();
+#endif
+
+ // Release the ref count added on the App above. this will make
+ // the App's ref count go to 0, and the App object will be deleted.
+ lpCSimpleApp->Release();
+
+ return (msg.wParam); /* Returns the value from PostQuitMessage */
+}
+
+
+//**********************************************************************
+//
+// MainWndProc
+//
+// Purpose:
+//
+// Processes messages for the frame window
+//
+// Parameters:
+//
+// HWND hWnd - Window handle for frame window
+//
+// UINT message - Message value
+//
+// WPARAM wParam - Message info
+//
+// LPARAM lParam - Message info
+//
+// Return Value:
+//
+// long
+//
+// Function Calls:
+// Function Location
+//
+// CSimpleApp::lCommandHandler APP.CPP
+// CSimpleApp::DestroyDocs APP.CPP
+// CSimpleApp::lCreateDoc APP.CPP
+// CSimpleApp::lSizeHandler APP.CPP
+// CSimpleDoc::lAddVerbs DOC.CPP
+// PostQuitMessage Windows API
+// DefWindowProc Windows API
+// DestroyWindow Windows API
+//
+//
+//********************************************************************
+
+long FAR PASCAL EXPORT MainWndProc(HWND hWnd, UINT message,
+ WPARAM wParam, LPARAM lParam)
+{
+
+ switch (message)
+ {
+ case WM_TEST2:
+ StartTest2(lpCSimpleApp);
+ break;
+ case WM_TEST1:
+ StartTest1(lpCSimpleApp);
+ break;
+ case WM_CLOSE:
+ DestroyWindow(lpCSimpleApp->m_hAppWnd);
+ break;
+
+ case WM_COMMAND: // message: command from application menu
+ return lpCSimpleApp->lCommandHandler(hWnd, message, wParam,
+ lParam);
+ break;
+
+ case WM_CREATE:
+#ifdef NOTREADY
+ RemoveMenu(GetSubMenu(GetMenu(hWnd), 1), 0, MF_BYPOSITION);
+#endif // NOTREADY
+ return lpCSimpleApp->lCreateDoc(hWnd, message, wParam, lParam);
+ break;
+
+ case WM_DESTROY: // message: window being destroyed
+ lpCSimpleApp->DestroyDocs(); // need to destroy the doc...
+ PostQuitMessage(0);
+ break;
+
+ case WM_INITMENUPOPUP:
+ // is this the edit menu?
+ if ( LOWORD(lParam) == 1)
+ return lpCSimpleApp->m_lpDoc->lAddVerbs();
+ break;
+
+ case WM_SIZE:
+ return lpCSimpleApp->lSizeHandler(hWnd, message, wParam, lParam);
+
+ default: // Passes it on if unproccessed
+ return (DefWindowProc(hWnd, message, wParam, lParam));
+ }
+ return (NULL);
+}
+
+
+//**********************************************************************
+//
+// About
+//
+// Purpose:
+//
+// Processes dialog box messages
+//
+// Parameters:
+//
+// HWND hWnd - Window handle for dialog box
+//
+// UINT message - Message value
+//
+// WPARAM wParam - Message info
+//
+// LPARAM lParam - Message info
+//
+// Return Value:
+//
+// Function Calls:
+// Function Location
+//
+// EndDialog Windows API
+//
+//
+//********************************************************************
+BOOL
+#ifdef WIN32
+ CALLBACK
+#else
+ FAR PASCAL EXPORT
+#endif
+ About(HWND hDlg,UINT message,WPARAM wParam,LPARAM lParam)
+
+{
+ switch (message)
+ {
+ case WM_INITDIALOG: /* message: initialize dialog box */
+ return (TRUE);
+
+ case WM_COMMAND: /* message: received a command */
+ if (wParam == IDOK /* "OK" box selected? */
+ || wParam == IDCANCEL) /* System menu close command? */
+ {
+ EndDialog(hDlg, TRUE); /* Exits the dialog box */
+ return (TRUE);
+ }
+ break;
+ }
+
+ return (FALSE); /* Didn't process a message */
+}
+
+//**********************************************************************
+//
+// DocWndProc
+//
+// Purpose:
+//
+// Processes dialog box messages
+//
+// Parameters:
+//
+// HWND hWnd - Window handle for doc window
+//
+// UINT message - Message value
+//
+// WPARAM wParam - Message info
+//
+// LPARAM lParam - Message info
+//
+// Return Value:
+//
+// long
+//
+// Function Calls:
+// Function Location
+//
+// CSimpleApp::PaintApp APP.CPP
+// BeginPaint Windows API
+// EndPaint Windows API
+// DefWindowProc Windows API
+// IOleObject::DoVerb Object
+// CSimpleSite::GetObjRect SITE.CPP
+// CSimpleDoc::QueryDrag DOC.CPP
+// CSimpleDoc::DoDragDrop DOC.CPP
+// SetTimer Windows API
+// KillTimer Windows API
+// SetCapture Windows API
+// ReleaseCapture Windows API
+//
+//
+//********************************************************************
+
+long FAR PASCAL EXPORT DocWndProc(HWND hWnd, UINT message, WPARAM wParam,
+ LPARAM lParam)
+{
+ HDC hDC;
+ PAINTSTRUCT ps;
+
+ switch (message)
+ {
+ case WM_PAINT:
+
+ hDC = BeginPaint(hWnd, &ps);
+
+ if (lpCSimpleApp)
+ lpCSimpleApp->PaintApp (hDC);
+
+ EndPaint(hWnd, &ps);
+ break;
+
+ case WM_LBUTTONDBLCLK:
+ {
+ POINT pt;
+
+ pt.x = (int)(short)LOWORD (lParam );
+ pt.y = (int)(short)HIWORD (lParam );
+
+ if (lpCSimpleApp->m_lpDoc->m_lpSite &&
+ lpCSimpleApp->m_lpDoc->m_lpSite->m_lpOleObject)
+ {
+ RECT rect;
+
+ lpCSimpleApp->m_lpDoc->m_lpSite->GetObjRect(&rect);
+
+ if ( PtInRect(&rect, pt) )
+ {
+ // Execute object's default verb
+ lpCSimpleApp->m_lpDoc->m_lpSite->m_lpOleObject->DoVerb(
+ OLEIVERB_PRIMARY, (LPMSG)&message,
+ &lpCSimpleApp->m_lpDoc->m_lpSite->m_OleClientSite,
+ -1, hWnd, &rect);
+ }
+ }
+ break;
+ }
+
+ case WM_LBUTTONDOWN:
+ {
+ POINT pt;
+
+ pt.x = (int)(short)LOWORD (lParam );
+ pt.y = (int)(short)HIWORD (lParam );
+
+ /* OLE2NOTE: check if this is a button down on the region
+ ** that is a handle to start a drag operation. for us,
+ ** this this is any where in the window. we
+ ** do NOT want to start a drag immediately; we want to
+ ** wait until the mouse moves a certain threshold. or a
+ ** certain amount of time has elapsed. if
+ ** LButtonUp comes before the drag is started, then
+ ** the fPendingDrag state is cleared. we must capture
+ ** the mouse to ensure the modal state is handled
+ ** properly.
+ */
+ if (lpCSimpleApp->m_lpDoc->QueryDrag(pt) )
+ {
+ lpCSimpleApp->m_lpDoc->m_fPendingDrag = TRUE;
+ lpCSimpleApp->m_lpDoc->m_ptButDown = pt;
+ SetTimer(hWnd, 1, lpCSimpleApp->m_nDragDelay, NULL);
+ SetCapture(hWnd);
+ }
+ break;
+ }
+
+ case WM_LBUTTONUP:
+
+ if (lpCSimpleApp->m_lpDoc->m_fPendingDrag)
+ {
+ /* ButtonUP came BEFORE distance/time threshholds were
+ ** exceeded. clear fPendingDrag state.
+ */
+ ReleaseCapture();
+ KillTimer(hWnd, 1);
+ lpCSimpleApp->m_lpDoc->m_fPendingDrag = FALSE;
+ }
+ break;
+
+ case WM_MOUSEMOVE:
+ {
+ if (lpCSimpleApp->m_lpDoc->m_fPendingDrag)
+ {
+ int x = (int)(short)LOWORD (lParam );
+ int y = (int)(short)HIWORD (lParam );
+ POINT pt = lpCSimpleApp->m_lpDoc->m_ptButDown;
+ int nDragMinDist = lpCSimpleApp->m_nDragMinDist;
+
+ if (! ( ((pt.x - nDragMinDist) <= x)
+ && (x <= (pt.x + nDragMinDist))
+ && ((pt.y - nDragMinDist) <= y)
+ && (y <= (pt.y + nDragMinDist)) ) )
+ {
+ // mouse moved beyond threshhold to start drag
+ ReleaseCapture();
+ KillTimer(hWnd, 1);
+ lpCSimpleApp->m_lpDoc->m_fPendingDrag = FALSE;
+
+ // perform the modal drag/drop operation.
+ lpCSimpleApp->m_lpDoc->DoDragDrop( );
+ }
+ }
+ break;
+ }
+
+ case WM_TIMER:
+ {
+ // drag time delay threshhold exceeded -- start drag
+ ReleaseCapture();
+ KillTimer(hWnd, 1);
+ lpCSimpleApp->m_lpDoc->m_fPendingDrag = FALSE;
+
+ // perform the modal drag/drop operation.
+ lpCSimpleApp->m_lpDoc->DoDragDrop( );
+ break;
+ }
+
+ default: /* Passes it on if unproccessed */
+ return (DefWindowProc(hWnd, message, wParam, lParam));
+ }
+ return (NULL);
+}
+
+
diff --git a/private/oleutest/simpdnd/simpdnd.h b/private/oleutest/simpdnd/simpdnd.h
new file mode 100644
index 000000000..1337a3907
--- /dev/null
+++ b/private/oleutest/simpdnd/simpdnd.h
@@ -0,0 +1,45 @@
+//**********************************************************************
+// File name: simpdnd.h
+//
+// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+#define IDM_ABOUT 100
+#define IDM_INSERT 101
+#define IDM_VERB0 1000
+
+int PASCAL WinMain
+#ifdef WIN32
+ (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow);
+#else
+ (HANDLE hInstance, HANDLE hPrevInstance, LPSTR lpCmdLine, int nCmdShow);
+#endif
+
+
+BOOL InitApplication(HANDLE hInstance);
+BOOL InitInstance(HANDLE hInstance, int nCmdShow);
+
+long FAR PASCAL EXPORT MainWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
+long FAR PASCAL EXPORT DocWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
+
+#ifdef WIN32
+BOOL CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LONG lParam);
+#else
+BOOL FAR PASCAL EXPORT About(HWND hDlg, UINT message, WPARAM wParam, LONG lParam);
+#endif
+
+#ifndef LATER
+#define SZCLASSICONBOX "SimpDndIBClass"
+#define SZCLASSRESULTIMAGE "SimpDndRIClass"
+#endif
+
+
+#ifdef WIN32
+
+// Macro for TestDebugOut
+#ifdef UNICODE
+#undef TestDebugOut
+#define TestDebugOut(A); TestDebugOutW(TEXT(A));
+#endif
+
+#endif
+
diff --git a/private/oleutest/simpdnd/simpdnd.ico b/private/oleutest/simpdnd/simpdnd.ico
new file mode 100644
index 000000000..c5aceb582
--- /dev/null
+++ b/private/oleutest/simpdnd/simpdnd.ico
Binary files differ
diff --git a/private/oleutest/simpdnd/simpdnd.rc b/private/oleutest/simpdnd/simpdnd.rc
new file mode 100644
index 000000000..ebd4f8ff4
--- /dev/null
+++ b/private/oleutest/simpdnd/simpdnd.rc
@@ -0,0 +1,114 @@
+//Microsoft App Studio generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#define APSTUDIO_HIDDEN_SYMBOLS
+#include "windows.h"
+#undef APSTUDIO_HIDDEN_SYMBOLS
+#include "simpdnd.h"
+#include "ole2ui.rc"
+
+//////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+SimpDnd icon simpdnd.ico
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// Menu
+//
+
+SIMPLEMENU MENU DISCARDABLE
+BEGIN
+ POPUP "&File"
+ BEGIN
+ MENUITEM "&New", IDM_NEW
+ MENUITEM SEPARATOR
+ MENUITEM "E&xit", IDM_EXIT
+ END
+ POPUP "&Edit"
+ BEGIN
+ MENUITEM "&Copy", IDM_COPY
+ MENUITEM "&Insert Object...", IDM_INSERTOBJECT
+ END
+ POPUP "&Other"
+ BEGIN
+ POPUP "&Source Options"
+ BEGIN
+ MENUITEM "&Copy Only", IDM_SOURCE_COPY
+ MENUITEM "&Move Only", IDM_SOURCE_MOVE
+ MENUITEM "&Both Copy/Move" IDM_SOURCE_COPYMOVE
+ END
+ POPUP "&Target Options"
+ BEGIN
+ MENUITEM "&Copy Only", IDM_TARGET_COPY
+ MENUITEM "&Move Only", IDM_TARGET_MOVE
+ MENUITEM "&Both Copy/Move" IDM_TARGET_COPYMOVE
+ END
+ MENUITEM "&About Simple...", IDM_ABOUT
+ END
+END
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+ABOUTBOX DIALOG DISCARDABLE 22, 17, 144, 75
+STYLE DS_MODALFRAME | WS_CAPTION | WS_SYSMENU
+CAPTION "About SimpDnD"
+FONT 8, "System"
+BEGIN
+ CTEXT "Simple OLE 2.0",-1,0,5,144,8
+ CTEXT "Drag/Drop Container Application",-1,0,14,144,8
+ CTEXT "Version 2.01",-1,0,34,144,8
+ DEFPUSHBUTTON "OK",IDOK,53,59,32,14,WS_GROUP
+END
+
+#ifdef APSTUDIO_INVOKED
+//////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "#define APSTUDIO_HIDDEN_SYMBOLS\r\n"
+ "#include ""windows.h""\r\n"
+ "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n"
+ "#include ""simpdnd.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+/////////////////////////////////////////////////////////////////////////////////////
+#endif // APSTUDIO_INVOKED
+
+
+#ifndef APSTUDIO_INVOKED
+////////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
+
diff --git a/private/oleutest/simpdnd/site.cpp b/private/oleutest/simpdnd/site.cpp
new file mode 100644
index 000000000..3ae88d623
--- /dev/null
+++ b/private/oleutest/simpdnd/site.cpp
@@ -0,0 +1,632 @@
+//**********************************************************************
+// File name: SITE.CPP
+//
+// Implementation file for CSimpleSite
+//
+// Functions:
+//
+// See SITE.H for class definition
+//
+// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+
+#include "pre.h"
+#include "iocs.h"
+#include "ias.h"
+#include "app.h"
+#include "site.h"
+#include "doc.h"
+
+//**********************************************************************
+//
+// CSimpleSite::Create
+//
+// Purpose:
+//
+// Creation routine for CSimpleSite
+//
+// Parameters:
+//
+// CSimpleDoc FAR *lpDoc - Pointer to CSimpleDoc
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// CSimpleSite::CSimpleSite SITE.CPP
+// CSimpleSite::~CSimpleSite SITE.CPP
+// CSimpleSite::AddRef SITE.CPP
+// IStorage::CreateStorage OLE API
+// assert C Runtime
+//
+//
+//********************************************************************
+
+CSimpleSite FAR * CSimpleSite::Create(CSimpleDoc FAR *lpDoc)
+{
+ CSimpleSite FAR * lpTemp = new CSimpleSite(lpDoc);
+
+ if (!lpTemp)
+ return NULL;
+
+ // create a sub-storage for the object
+ HRESULT hErr = lpDoc->m_lpStorage->CreateStorage( OLESTR("Object"),
+ STGM_READWRITE | STGM_TRANSACTED | STGM_SHARE_EXCLUSIVE,
+ 0,
+ 0,
+ &lpTemp->m_lpObjStorage);
+
+ assert(hErr == NOERROR);
+
+ if (hErr != NOERROR)
+ {
+ delete lpTemp;
+ return NULL;
+ }
+
+ // we will add one ref count on our Site. later when we want to destroy
+ // the Site object we will release this ref count. when the Site's ref
+ // count goes to 0, it will be deleted.
+ lpTemp->AddRef();
+
+ return lpTemp;
+}
+
+//**********************************************************************
+//
+// CSimpleSite::CSimpleSite
+//
+// Purpose:
+//
+// Constructor for CSimpleSite
+//
+// Parameters:
+//
+// CSimpleDoc FAR *lpDoc - Pointer to CSimpleDoc
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+//
+//********************************************************************
+#pragma warning(disable : 4355) // turn off this warning. This warning
+ // tells us that we are passing this in
+ // an initializer, before "this" is through
+ // initializing. This is ok, because
+ // we just store the ptr in the other
+ // constructors
+
+CSimpleSite::CSimpleSite (CSimpleDoc FAR *lpDoc) : m_OleClientSite(this),
+ m_AdviseSink(this)
+#pragma warning (default : 4355) // Turn the warning back on
+{
+ // remember the pointer to the doc
+ m_lpDoc = lpDoc;
+ m_sizel.cx = 0;
+ m_sizel.cy = 0;
+
+ // clear the reference count
+ m_nCount = 0;
+
+ m_dwDrawAspect = DVASPECT_CONTENT;
+ m_lpOleObject = NULL;
+ m_fObjectOpen = FALSE;
+}
+
+//**********************************************************************
+//
+// CSimpleSite::~CSimpleSite
+//
+// Purpose:
+//
+// Destructor for CSimpleSite
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// IOleObject::Release Object
+// IStorage::Release OLE API
+//
+//
+//********************************************************************
+
+CSimpleSite::~CSimpleSite ()
+{
+ TestDebugOut ("In CSimpleSite's Destructor \r\n");
+
+ if (m_lpOleObject)
+ m_lpOleObject->Release();
+
+ if (m_lpObjStorage)
+ m_lpObjStorage->Release();
+}
+
+
+//**********************************************************************
+//
+// CSimpleSite::CloseOleObject
+//
+// Purpose:
+//
+// Call IOleObject::Close on the object of the CSimpleSite
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// IOleObject::Close Object
+//
+//
+//********************************************************************
+
+void CSimpleSite::CloseOleObject (void)
+{
+ LPVIEWOBJECT lpViewObject = NULL;
+
+ TestDebugOut ("In CSimpleSite::CloseOleObject \r\n");
+
+ if (m_lpOleObject)
+ {
+ m_lpOleObject->Close(OLECLOSE_NOSAVE);
+ }
+}
+
+
+//**********************************************************************
+//
+// CSimpleSite::UnloadOleObject
+//
+// Purpose:
+//
+// Close and release all pointers to the object of the CSimpleSite
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// CSimpleSite::CloseOleObject SITE.CPP
+// IOleObject::QueryInterface Object
+// IViewObject::SetAdvise Object
+// IViewObject::Release Object
+// IOleObject::Release Object
+//
+//
+//********************************************************************
+
+void CSimpleSite::UnloadOleObject (void)
+{
+ TestDebugOut ("In CSimpleSite::UnloadOleObject \r\n");
+
+ if (m_lpOleObject)
+ {
+ LPVIEWOBJECT lpViewObject;
+ CloseOleObject(); // ensure object is closed; NOP if already closed
+
+ m_lpOleObject->QueryInterface(IID_IViewObject,
+ (LPVOID FAR *)&lpViewObject);
+
+ if (lpViewObject)
+ {
+ // Remove the view advise
+ lpViewObject->SetAdvise(m_dwDrawAspect, 0, NULL);
+ lpViewObject->Release();
+ }
+
+ m_lpOleObject->Release();
+ m_lpOleObject = NULL;
+ }
+}
+
+
+//**********************************************************************
+//
+// CSimpleSite::QueryInterface
+//
+// Purpose:
+//
+// Used for interface negotiation of the container Site.
+//
+// Parameters:
+//
+// REFIID riid - A reference to the interface that is
+// being queried.
+//
+// LPVOID FAR* ppvObj - An out parameter to return a pointer to
+// the interface.
+//
+// Return Value:
+//
+// S_OK - The interface is supported.
+// S_FALSE - The interface is not supported
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// IsEqualIID OLE API
+// ResultFromScode OLE API
+// CSimpleSite::AddRef OBJ.CPP
+// COleClientSite::AddRef IOCS.CPP
+// CAdviseSink::AddRef IAS.CPP
+//
+//
+//********************************************************************
+
+STDMETHODIMP CSimpleSite::QueryInterface(REFIID riid, LPVOID FAR* ppvObj)
+{
+ TestDebugOut("In CSimpleSite::QueryInterface\r\n");
+
+ *ppvObj = NULL; // must set out pointer parameters to NULL
+
+ if ( IsEqualIID(riid, IID_IUnknown))
+ {
+ AddRef();
+ *ppvObj = this;
+ return ResultFromScode(S_OK);
+ }
+
+ if ( IsEqualIID(riid, IID_IOleClientSite))
+ {
+ m_OleClientSite.AddRef();
+ *ppvObj = &m_OleClientSite;
+ return ResultFromScode(S_OK);
+ }
+
+ if ( IsEqualIID(riid, IID_IAdviseSink))
+ {
+ m_AdviseSink.AddRef();
+ *ppvObj = &m_AdviseSink;
+ return ResultFromScode(S_OK);
+ }
+
+ // Not a supported interface
+ return ResultFromScode(E_NOINTERFACE);
+}
+
+//**********************************************************************
+//
+// CSimpleSite::AddRef
+//
+// Purpose:
+//
+// Increments the reference count of the container Site.
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// ULONG - The new reference count of the site.
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) CSimpleSite::AddRef()
+{
+ TestDebugOut("In CSimpleSite::AddRef\r\n");
+
+ return ++m_nCount;
+}
+
+//**********************************************************************
+//
+// CSimpleSite::Release
+//
+// Purpose:
+//
+// Decrements the reference count of the container Site
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// ULONG - The new reference count of the Site.
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) CSimpleSite::Release()
+{
+ TestDebugOut("In CSimpleSite::Release\r\n");
+
+ if (--m_nCount == 0)
+ {
+ delete this;
+ return 0;
+ }
+ return m_nCount;
+}
+
+//**********************************************************************
+//
+// CSimpleSite::InitObject
+//
+// Purpose:
+//
+// Used to initialize a newly create object (can't be done in the
+// constructor).
+//
+// Parameters:
+//
+// BOOL fCreateNew - TRUE if insert NEW object
+// FALSE if create object FROM FILE
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// IOleObject::SetHostNames Object
+// IOleObject::QueryInterface Object
+// IViewObject2::GetExtent Object
+// IOleObject::DoVerb Object
+// IViewObject2::SetAdvise Object
+// IViewObject2::Release Object
+// GetClientRect Windows API
+// OleSetContainedObject OLE API
+//
+//
+//********************************************************************
+
+HRESULT CSimpleSite::InitObject(BOOL fCreateNew)
+{
+ LPVIEWOBJECT2 lpViewObject2;
+ RECT rect;
+ HRESULT hRes;
+
+ // Set a View Advise
+ hRes = m_lpOleObject->QueryInterface(IID_IViewObject2,
+ (LPVOID FAR *)&lpViewObject2);
+ if (hRes == ResultFromScode(S_OK))
+ {
+ hRes = lpViewObject2->SetAdvise(m_dwDrawAspect, ADVF_PRIMEFIRST,
+ &m_AdviseSink);
+
+ if( FAILED(hRes))
+ {
+ goto errRtn;
+ }
+ // get the initial size of the object
+
+ hRes = lpViewObject2->GetExtent(m_dwDrawAspect, -1 /*lindex*/, NULL /*ptd*/,
+ &m_sizel);
+
+ //
+ // Is OK if the object is actually blank
+ //
+ if( FAILED(hRes) && (hRes != OLE_E_BLANK) )
+ {
+ goto errRtn;
+ }
+
+ lpViewObject2->Release();
+ }
+ GetObjRect(&rect); // get the rectangle of the object in pixels
+
+ // give the object the name of the container app/document
+ hRes = m_lpOleObject->SetHostNames(OLESTR("Simple Application"),
+ OLESTR("Simple OLE 2.0 Drag/Drop Container"));
+
+ if( FAILED(hRes) )
+ {
+ goto errRtn;
+ }
+
+ // inform object handler/DLL object that it is used in the embedding
+ // container's context
+ if (OleSetContainedObject(m_lpOleObject, TRUE) != ResultFromScode(S_OK))
+ {
+ TestDebugOut("Fail in OleSetContainedObject\n");
+ }
+
+ if (fCreateNew)
+ {
+ // force new object to save to guarantee valid object in our storage.
+ // OLE 1.0 objects may close w/o saving. this is NOT necessary if the
+ // object is created FROM FILE; its data in storage is already valid.
+ m_OleClientSite.SaveObject();
+
+ // we only want to DoVerb(SHOW) if this is an InsertNew object.
+ // we should NOT DoVerb(SHOW) if the object is created FromFile.
+ hRes = m_lpOleObject->DoVerb(
+ OLEIVERB_SHOW,
+ NULL,
+ &m_OleClientSite,
+ -1,
+ m_lpDoc->m_hDocWnd,
+ &rect);
+ }
+
+errRtn:
+ return hRes;
+
+}
+
+//**********************************************************************
+//
+// CSimpleSite::PaintObj
+//
+// Purpose:
+//
+// Paints the object
+//
+// Parameters:
+//
+// HDC hDC - Device context of the document window
+//
+// Return Value:
+// None
+//
+// Function Calls:
+// Function Location
+//
+// IOleObject::QueryInterface Object
+// IViewObject::GetColorSet Object
+// IViewObject::Release Object
+// CreateHatchBrush Windows API
+// SelectObject Windows API
+// SetROP2 Windows API
+// Rectangle Windows API
+// DeleteObject Windows API
+// CreatePalette Windows API
+// SelectPalette Windows API
+// RealizePalette Windows API
+// OleStdFree OUTLUI Function
+// OleDraw OLE API
+// CSimpleSite::GetObjRect SITE.CPP
+//
+//
+//********************************************************************
+
+void CSimpleSite::PaintObj(HDC hDC)
+{
+ RECT rect;
+
+ // need to check to make sure there is a valid object
+ // available. This is needed if there is a paint msg
+ // between the time that CSimpleSite is instantiated
+ // and OleUIInsertObject returns.
+ if (!m_lpOleObject)
+ return;
+
+ // convert it to pixels
+ GetObjRect(&rect);
+
+ LPLOGPALETTE pColorSet = NULL;
+ LPVIEWOBJECT lpView = NULL;
+
+ // get a pointer to IViewObject
+ m_lpOleObject->QueryInterface(IID_IViewObject,(LPVOID FAR *) &lpView);
+
+ // if the QI succeeds, get the LOGPALETTE for the object
+ if (lpView)
+ lpView->GetColorSet(m_dwDrawAspect, -1, NULL, NULL, NULL, &pColorSet);
+
+ HPALETTE hPal=NULL;
+ HPALETTE hOldPal=NULL;
+
+ // if a LOGPALETTE was returned (not guarateed), create the palette and
+ // realize it. NOTE: A smarter application would want to get the LOGPALETTE
+ // for each of its visible objects, and try to create a palette that
+ // satisfies all of the visible objects. ALSO: OleStdFree() is use to
+ // free the returned LOGPALETTE.
+ if ((pColorSet))
+ {
+ hPal = CreatePalette((const LPLOGPALETTE) pColorSet);
+ hOldPal = SelectPalette(hDC, hPal, FALSE);
+ RealizePalette(hDC);
+ OleStdFree(pColorSet);
+ }
+
+ // draw the object
+ HRESULT hRes;
+ hRes = OleDraw(m_lpOleObject, m_dwDrawAspect, hDC, &rect);
+ if ((hRes != ResultFromScode(S_OK)) &&
+ (hRes != ResultFromScode(OLE_E_BLANK)) &&
+ (hRes != ResultFromScode(DV_E_NOIVIEWOBJECT)))
+ {
+ TestDebugOut("Fail in OleDraw\n");
+ }
+
+ // if the object is open, draw a hatch rect.
+ if (m_fObjectOpen)
+ {
+ HBRUSH hBrush = CreateHatchBrush ( HS_BDIAGONAL, RGB(0,0,0) );
+ HBRUSH hOldBrush = (HBRUSH) SelectObject (hDC, hBrush);
+ SetROP2(hDC, R2_MASKPEN);
+ Rectangle (hDC, rect.left, rect.top, rect.right, rect.bottom);
+ SelectObject(hDC, hOldBrush);
+ DeleteObject(hBrush);
+ }
+
+ // if we created a palette, restore the old one, and destroy
+ // the object.
+ if (hPal)
+ {
+ SelectPalette(hDC,hOldPal,FALSE);
+ DeleteObject(hPal);
+ }
+
+ // if a view pointer was successfully returned, it needs to be released.
+ if (lpView)
+ lpView->Release();
+}
+
+//**********************************************************************
+//
+// CSimpleSite::GetObjRect
+//
+// Purpose:
+//
+// Retrieves the rect of the object in pixels
+//
+// Parameters:
+//
+// LPRECT lpRect - Rect structure filled with object's rect in pixels
+//
+// Return Value:
+// None
+//
+// Function Calls:
+// Function Location
+//
+// XformWidthInHimetricToPixels OLE2UI Function
+// XformHeightInHimetricToPixels OLE2UI Function
+//
+//
+//********************************************************************
+
+void CSimpleSite::GetObjRect(LPRECT lpRect)
+{
+ // convert it to pixels
+ lpRect->left = lpRect->top = 0;
+ lpRect->right = XformWidthInHimetricToPixels(NULL,(int)m_sizel.cx);
+ lpRect->bottom = XformHeightInHimetricToPixels(NULL,(int)m_sizel.cy);
+}
diff --git a/private/oleutest/simpdnd/site.h b/private/oleutest/simpdnd/site.h
new file mode 100644
index 000000000..f9e0301ab
--- /dev/null
+++ b/private/oleutest/simpdnd/site.h
@@ -0,0 +1,47 @@
+//**********************************************************************
+// File name: SITE.H
+//
+// Definition of CSimpleSite
+//
+// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+#if !defined( _SITE_H_ )
+#define _SITE_H_
+
+#include <ole2.h>
+#include "ias.h"
+#include "iocs.h"
+
+class CSimpleDoc;
+
+class CSimpleSite : public IUnknown
+{
+public:
+ int m_nCount;
+ LPOLEOBJECT m_lpOleObject;
+ DWORD m_dwDrawAspect;
+ SIZEL m_sizel;
+ BOOL m_fObjectOpen;
+ LPSTORAGE m_lpObjStorage;
+
+ CAdviseSink m_AdviseSink;
+ COleClientSite m_OleClientSite;
+
+ CSimpleDoc FAR * m_lpDoc;
+
+ // IUnknown Interfaces
+ STDMETHODIMP QueryInterface(REFIID riid, LPVOID FAR* ppvObj);
+ STDMETHODIMP_(ULONG) AddRef();
+ STDMETHODIMP_(ULONG) Release();
+
+ HRESULT InitObject(BOOL fCreateNew);
+ static CSimpleSite FAR * Create(CSimpleDoc FAR *lpDoc);
+ CSimpleSite(CSimpleDoc FAR *lpDoc);
+ ~CSimpleSite();
+ void PaintObj(HDC hDC);
+ void GetObjRect(LPRECT lpRect);
+ void CloseOleObject(void);
+ void UnloadOleObject(void);
+};
+
+#endif // _SITE_H_
diff --git a/private/oleutest/simpdnd/strings.rc b/private/oleutest/simpdnd/strings.rc
new file mode 100644
index 000000000..f3f8c415a
--- /dev/null
+++ b/private/oleutest/simpdnd/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/simpdnd/tests.cpp b/private/oleutest/simpdnd/tests.cpp
new file mode 100644
index 000000000..7119442de
--- /dev/null
+++ b/private/oleutest/simpdnd/tests.cpp
@@ -0,0 +1,198 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: tests.cpp
+//
+// Contents: Implementations of the Upper Layer unit tests
+//
+// Classes:
+//
+// Functions: StartTest1
+//
+// History: dd-mmm-yy Author Comment
+// 07-Feb-94 alexgo author
+//
+//--------------------------------------------------------------------------
+
+#include "pre.h"
+#include "iocs.h"
+#include "ias.h"
+#include "app.h"
+#include "site.h"
+#include "doc.h"
+#include <testmess.h>
+
+const CLSID CLSID_SimpleServer = {0xbcf6d4a0, 0xbe8c, 0x1068, { 0xb6, 0xd4,
+ 0x00, 0xdd, 0x01, 0x0c, 0x05, 0x09 }};
+
+const CLSID CLSID_Paintbrush = {0x0003000a, 0, 0, { 0xc0, 0,0,0,0,0,0,0x46 }};
+
+//+-------------------------------------------------------------------------
+//
+// Function: StartTest1
+//
+// Synopsis: Starts unit test1, inserting a simple server object into
+// this (simpdnd) container.
+//
+// Effects:
+//
+// Arguments: pApp -- a pointer to the CSimpleApp that we're a part of
+//
+// Requires:
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 07-Feb-94 alexgo author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+void StartTest1( CSimpleApp *pApp )
+{
+ HRESULT hresult;
+ static FORMATETC formatetc;
+
+ //insert the simple server object
+
+ formatetc.dwAspect = DVASPECT_CONTENT;
+ formatetc.cfFormat = NULL;
+ formatetc.lindex = -1;
+
+ //need to create the client site
+
+ pApp->m_lpDoc->m_lpSite = CSimpleSite::Create(pApp->m_lpDoc);
+
+ hresult = OleCreate(CLSID_SimpleServer, IID_IOleObject,
+ OLERENDER_DRAW, &formatetc,
+ &pApp->m_lpDoc->m_lpSite->m_OleClientSite,
+ pApp->m_lpDoc->m_lpSite->m_lpObjStorage,
+ (void **)&(pApp->m_lpDoc->m_lpSite->m_lpOleObject));
+
+ if( hresult != NOERROR )
+ {
+ goto errRtn;
+ }
+
+ //initialize the object
+
+ hresult = pApp->m_lpDoc->m_lpSite->InitObject(TRUE);
+
+ if( hresult == NOERROR )
+ {
+ //tell it to paint itself, then we'll quit
+ PostMessage(pApp->m_lpDoc->m_hDocWnd, WM_PAINT, 0L, 0L);
+ PostMessage(pApp->m_hDriverWnd, WM_TESTEND, TEST_SUCCESS,
+ (LPARAM)hresult);
+ PostMessage(pApp->m_hAppWnd, WM_SYSCOMMAND, SC_CLOSE, 0L);
+ return;
+ }
+
+errRtn:
+ PostMessage(pApp->m_hDriverWnd, WM_TESTEND, TEST_FAILURE,
+ (LPARAM)hresult);
+ PostMessage(pApp->m_hAppWnd, WM_SYSCOMMAND, SC_CLOSE, 0L);
+ return;
+}
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: StartTest2
+//
+// Synopsis: Starts unit Test2, inserting a paintbrush object into
+// this (simpdnd) container.
+//
+// Effects:
+//
+// Arguments: pApp -- a pointer to the CSimpleApp that we're a part of
+//
+// Requires:
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 24-May-94 kevinro & alexgo author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+void StartTest2( CSimpleApp *pApp )
+{
+ HRESULT hresult;
+ static FORMATETC formatetc;
+
+ //insert the simple server object
+
+ formatetc.dwAspect = DVASPECT_CONTENT;
+ formatetc.cfFormat = NULL;
+ formatetc.lindex = -1;
+
+ //need to create the client site
+
+ pApp->m_lpDoc->m_lpSite = CSimpleSite::Create(pApp->m_lpDoc);
+
+ hresult = OleCreate(CLSID_Paintbrush, IID_IOleObject,
+ OLERENDER_DRAW, &formatetc,
+ &pApp->m_lpDoc->m_lpSite->m_OleClientSite,
+ pApp->m_lpDoc->m_lpSite->m_lpObjStorage,
+ (void **)&(pApp->m_lpDoc->m_lpSite->m_lpOleObject));
+
+ if( hresult != NOERROR )
+ {
+ goto errRtn;
+ }
+
+ //initialize the object
+
+ hresult = pApp->m_lpDoc->m_lpSite->InitObject(TRUE);
+
+ //
+ // The DDE layer is going to ignore all of the parameters except
+ // the verb index. The parameters here are mostly dummies.
+ //
+ if (hresult == NOERROR)
+ {
+ hresult = pApp->m_lpDoc->m_lpSite->m_lpOleObject->DoVerb(0,
+ NULL,
+ &(pApp->m_lpDoc->m_lpSite->m_OleClientSite),
+ -1,
+ NULL,
+ NULL);
+ }
+
+ if( hresult == NOERROR )
+ {
+ //tell it to paint itself, then we'll quit
+ PostMessage(pApp->m_lpDoc->m_hDocWnd, WM_PAINT, 0L, 0L);
+ PostMessage(pApp->m_hDriverWnd, WM_TESTEND, TEST_SUCCESS,
+ (LPARAM)hresult);
+ PostMessage(pApp->m_hAppWnd, WM_SYSCOMMAND, SC_CLOSE, 0L);
+ return;
+ }
+
+errRtn:
+ PostMessage(pApp->m_hDriverWnd, WM_TESTEND, TEST_FAILURE,
+ (LPARAM)hresult);
+ PostMessage(pApp->m_hAppWnd, WM_SYSCOMMAND, SC_CLOSE, 0L);
+ return;
+}
+
+
+
diff --git a/private/oleutest/simpdnd/tests.h b/private/oleutest/simpdnd/tests.h
new file mode 100644
index 000000000..30d3b1baa
--- /dev/null
+++ b/private/oleutest/simpdnd/tests.h
@@ -0,0 +1,27 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: tests.h
+//
+// Contents: Declarations for the unit test functions
+//
+// Classes:
+//
+// Functions:
+//
+// History: dd-mmm-yy Author Comment
+// 07-Feb-94 alexgo author
+//
+//--------------------------------------------------------------------------
+
+#ifndef __TESTS_H
+#define __TESTS_H
+
+void StartTest1(CSimpleApp *);
+void StartTest2(CSimpleApp *);
+
+#endif
+
+
diff --git a/private/oleutest/simpsvr/app.cpp b/private/oleutest/simpsvr/app.cpp
new file mode 100644
index 000000000..bc096c968
--- /dev/null
+++ b/private/oleutest/simpsvr/app.cpp
@@ -0,0 +1,987 @@
+//**********************************************************************
+// File name: app.cpp
+//
+// Implementation file for the CSimpSvrApp Class
+//
+// Functions:
+//
+// See app.h for a list of member functions.
+//
+// Copyright (c) 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+
+#include "pre.h"
+#include "obj.h"
+#include "app.h"
+#include "doc.h"
+#include "icf.h"
+#include <msgfiltr.h>
+
+#include "initguid.h"
+DEFINE_GUID(GUID_SIMPLE, 0xBCF6D4A0, 0xBE8C, 0x1068, 0xB6, 0xD4, 0x00, 0xDD, 0x01, 0x0C, 0x05, 0x09);
+
+#ifdef WIN32
+extern BOOL CALLBACK About(HWND hDlg,UINT message,WPARAM wParam,LPARAM lParam);
+#endif
+
+//+-------------------------------------------------------------------------
+//
+// Function: SimpsvrMsgCallBack
+//
+// Synopsis: Tell Standard Message Filter not to toss windows messages
+//
+// Arguments: [pmsg] - first message in the queue
+//
+// History: dd-mmm-yy Author Comment
+// 19-May-94 ricksa author
+//
+//--------------------------------------------------------------------------
+BOOL CALLBACK SimpsvrMsgCallBack(MSG *pmsg)
+{
+ // We don't care about any of the in particular. We simply care that
+ // our messages are not tossed not matter what.
+ return TRUE;
+}
+
+//**********************************************************************
+//
+// CSimpSvrApp::CSimpSvrApp()
+//
+// Purpose:
+//
+// Constructor for CSimpSvrApp
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// SetRectEmpty Windows API
+//
+// Comments:
+//
+//
+//********************************************************************
+
+CSimpSvrApp::CSimpSvrApp()
+{
+ TestDebugOut(TEXT("In CSimpSvrApp's Constructor \r\n"));
+
+ // Set Ref Count
+ m_nCount = 0;
+
+ // clear members
+ m_hAppWnd = NULL;
+ m_hInst = NULL;
+ m_lpDoc = NULL;
+
+ // clear flags
+ m_fInitialized = FALSE;
+
+ // used for inplace
+ SetRectEmpty(&nullRect);
+}
+
+//**********************************************************************
+//
+// CSimpSvrApp::~CSimpSvrApp()
+//
+// Purpose:
+//
+// Destructor for CSimpSvrApp Class.
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// DestroyWindow Windows API
+// CSimpSvrApp::IsInitialized APP.H
+// OleUninitialize OLE API
+//
+//********************************************************************
+
+CSimpSvrApp::~CSimpSvrApp()
+{
+ TestDebugOut(TEXT("In CSimpSvrApp's Destructor\r\n"));
+
+ /* The Simple Server is structured so that SimpSvrApp is ALWAYS the
+ * last one to be released, after all the SimpSvrDoc and SimpSvrObj are
+ * released. So, we don't need to do any clean up to the SimpSvrDoc
+ * and SimpSvrObj objects.
+ */
+
+ // Revoke our message filter as the last step.
+ CoRegisterMessageFilter(NULL, NULL);
+
+ // need to uninit the library...
+ if (IsInitialized())
+ OleUninitialize();
+
+ DestroyWindow(m_hAppWnd);
+}
+
+
+//**********************************************************************
+//
+// CSimpSvrApp::QueryInterface
+//
+// Purpose:
+//
+// Used for interface negotiation at Application Level
+//
+// Parameters:
+//
+// REFIID riid - A reference to the interface that is
+// being queried.
+//
+// LPVOID FAR* ppvObj - An out parameter to return a pointer to
+// the interface.
+//
+// Return Value:
+//
+// S_OK - The interface is supported.
+// E_NOINTERFACE - The interface is not supported
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// ResultFromScode OLE API
+// IUnknown::AddRef APP.CPP
+//
+//
+//
+//********************************************************************
+
+STDMETHODIMP CSimpSvrApp::QueryInterface(REFIID riid, LPVOID FAR* ppvObj)
+{
+ TestDebugOut(TEXT("In CSimpSvrApp::QueryInterface\r\n"));
+
+ SCODE sc = S_OK;
+
+ if (IsEqualIID(riid, IID_IUnknown))
+ *ppvObj = this;
+ else
+ {
+ *ppvObj = NULL;
+ sc = E_NOINTERFACE;
+ }
+
+ if (*ppvObj)
+ ((LPUNKNOWN)*ppvObj)->AddRef();
+
+ // asking for something we don't understand at this level.
+ return ResultFromScode(sc);
+}
+
+//**********************************************************************
+//
+// CSimpSvrApp::AddRef
+//
+// Purpose:
+//
+// Adds to the reference count at the Application level.
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// ULONG - The new reference count of the application.
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+// Comments:
+//
+// Due to the reference counting model that is used in this
+// implementation, this reference count is the sum of the
+// reference counts on all interfaces of all objects open
+// in the application.
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) CSimpSvrApp::AddRef()
+{
+ TestDebugOut(TEXT("In CSimpSvrApp::AddRef\r\n"));
+ return ++m_nCount;
+}
+
+//**********************************************************************
+//
+// CSimpSvrApp::Release
+//
+// Purpose:
+//
+// Decrements the reference count at this level
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// ULONG - The new reference count of the application.
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+// Comments:
+//
+// Due to the reference counting model that is used in this
+// implementation, this reference count is the sum of the
+// reference counts on all interfaces of all objects open
+// in the application.
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) CSimpSvrApp::Release()
+{
+ TestDebugOut(TEXT("In CSimpSvrApp::Release\r\n"));
+
+ if (--m_nCount==0)
+ {
+ delete this;
+ return(0);
+ }
+
+ return m_nCount;
+}
+
+//**********************************************************************
+//
+// CSimpSvrApp::fInitApplication
+//
+// Purpose:
+//
+// Initializes the application
+//
+// Parameters:
+//
+// HANDLE hInstance - Instance handle of the application.
+//
+// Return Value:
+//
+// TRUE - Application was successfully initialized.
+// FALSE - Application could not be initialized
+//
+// Function Calls:
+// Function Location
+//
+// LoadIcon Windows API
+// LoadCursor Windows API
+// GetStockObject Windows API
+// RegisterClass Windows API
+// RegisterHatchWindowClass OUTLUI.DLL
+//
+//
+//********************************************************************
+
+BOOL CSimpSvrApp::fInitApplication(HANDLE hInstance)
+{
+ WNDCLASS wc;
+
+ // Fill in window class structure with parameters that describe the
+ // main window.
+
+ wc.style = NULL; // Class style(s).
+ wc.lpfnWndProc = MainWndProc; // Function to retrieve messages for
+ // windows of this class.
+ wc.cbClsExtra = 0; // No per-class extra data.
+ wc.cbWndExtra = 0; // No per-window extra data.
+ wc.hInstance = (HINSTANCE) hInstance; // Application that owns the class.
+ wc.hIcon = LoadIcon((HINSTANCE) hInstance, TEXT("SimpSvr"));
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
+
+ wc.lpszMenuName = TEXT("SimpSvrMENU"); // Name of menu resource in .RC file.
+ wc.lpszClassName = TEXT("SimpSvrWClass"); // Name used in call to CreateWindow.
+
+ if (!RegisterClass(&wc))
+ return FALSE;
+
+ wc.style = CS_VREDRAW | CS_HREDRAW; // Class style(s).
+ wc.lpfnWndProc = DocWndProc; // Function to retrieve messages for
+ // windows of this class.
+ wc.cbClsExtra = 0; // No per-class extra data.
+ wc.cbWndExtra = 0; // No per-window extra data.
+ wc.hInstance = (HINSTANCE) hInstance; // Application that owns the class.
+ wc.hIcon = NULL;
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
+ wc.lpszMenuName = NULL;
+
+ wc.lpszClassName = TEXT("DocWClass"); // Name used in call to CreateWindow.
+
+ // Register the window class and return success/failure code.
+
+ if (!RegisterClass(&wc))
+ return FALSE;
+
+ return (RegisterHatchWindowClass((HINSTANCE) hInstance));
+}
+
+//**********************************************************************
+//
+// CSimpSvrApp::fInitInstance
+//
+// Purpose:
+//
+// Instance initialization.
+//
+// Parameters:
+//
+// HANDLE hInstance - App. Instance Handle.
+//
+// int nCmdShow - Show parameter from WinMain
+//
+// Return Value:
+//
+// TRUE - Initialization Successful
+// FALSE - Initialization Failed.
+//
+//
+// Function Calls:
+// Function Location
+//
+// CreateWindow Windows API
+// InvalidateRect Windows API
+// ShowWindow Windows API
+// UpdateWindow Windows API
+// CoRegisterClassObject OLE API
+// OleBuildVersion OLE API
+// OleInitialize OLE API
+// CSimpSvrDoc::CreateObject DOC.CPP
+//
+// Comments:
+//
+// Note that successful Initalization of the OLE libraries
+// is remembered so the UnInit is only called if needed.
+//
+//********************************************************************
+
+BOOL CSimpSvrApp::fInitInstance (HANDLE hInstance, int nCmdShow,
+ CClassFactory FAR * lpClassFactory)
+{
+ m_hInst = (HINSTANCE) hInstance;
+
+#ifndef WIN32
+ /* Since OLE is part of the operating system in Win32, we don't need to
+ * check the version number in Win32.
+ */
+ DWORD dwVer = OleBuildVersion();
+
+ // check to see if we are compatible with this version of the libraries
+ if (HIWORD(dwVer) != rmm || LOWORD(dwVer) < rup)
+ {
+#ifdef _DEBUG
+ TestDebugOut("WARNING: Incompatible OLE library version\r\n");
+#else
+ return FALSE;
+#endif
+ }
+
+#endif // WIN32
+
+ // initialize the libraries
+ if (OleInitialize(NULL) == NOERROR)
+ m_fInitialized = TRUE;
+
+ // Load our accelerators
+ if ((m_hAccel = LoadAccelerators(m_hInst, TEXT("SimpsvrAccel"))) == NULL)
+ {
+ // Load failed so abort
+ TestDebugOut(TEXT("ERROR: Accelerator Table Load FAILED\r\n"));
+ return FALSE;
+ }
+
+
+ // Create the "application" windows
+ m_hAppWnd = CreateWindow (TEXT("SimpSvrWClass"),
+ TEXT("Simple OLE 2.0 Server"),
+ WS_OVERLAPPEDWINDOW,
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ NULL,
+ NULL,
+ (HINSTANCE) hInstance,
+ NULL);
+
+ if (!m_hAppWnd)
+ return FALSE;
+
+ // Because there default call control behavior tosses messages
+ // which cause intermittent failures of the test, we install a
+ // message filter to get around the problem.
+ IMessageFilter *pmf = OleStdMsgFilter_Create(m_hAppWnd,
+ TEXT("Simple OLE 2.0 Server"), SimpsvrMsgCallBack, NULL);
+
+ if (pmf == NULL)
+ {
+ // this call failed so we are hosed. So fail the whole thing
+ TestDebugOut(
+ TEXT("CSimpSvrApp::fInitInstance OleStdMsgFilter_Create fails\n"));
+ return FALSE;
+ }
+
+ HRESULT hr = CoRegisterMessageFilter(pmf, NULL);
+
+ if (FAILED(hr))
+ {
+ // this call failed so we are hosed. So fail the whole thing
+ TestDebugOut(
+ TEXT("CSimpSvrApp::fInitInstance CoRegisterMessageFilter fails\n"));
+ return FALSE;
+ }
+
+ // The message filter keeps a reference to this object so we don't have
+ // to remember anything about it -- except of course to deregister it.
+ pmf->Release();
+
+ // if not started by OLE, then show the Window, and create a "fake" object, else
+ // Register a pointer to IClassFactory so that OLE can instruct us to make an
+ // object at the appropriate time.
+ if (!m_fStartByOle)
+ {
+ ShowAppWnd(nCmdShow);
+ m_lpDoc->CreateObject(IID_IOleObject, (LPVOID FAR *)&m_OleObject);
+ InvalidateRect(m_lpDoc->GethDocWnd(), NULL, TRUE);
+ }
+ else
+ {
+ lpClassFactory = new CClassFactory(this);
+
+ if (!lpClassFactory)
+ {
+ /* Memory allocation fails
+ */
+ return(FALSE);
+ }
+
+ // shouldn't pass an API an object with a zero ref count
+ lpClassFactory->AddRef();
+
+ if (
+ CoRegisterClassObject(GUID_SIMPLE,
+ (IUnknown FAR *)lpClassFactory,
+ CLSCTX_LOCAL_SERVER,
+ REGCLS_SINGLEUSE,
+ &m_dwRegisterClass) != S_OK
+ )
+ TestDebugOut(TEXT("CSimpSvrApp::fInitInstance \
+ CoRegisterClassObject fails\n"));
+
+ // remove artificial Ref. count
+ lpClassFactory->Release();
+ }
+
+ return m_fInitialized;
+}
+
+
+//+-------------------------------------------------------------------------
+//
+// Member: CSimpSvrApp::HandleDrawItem (public)
+//
+// Synopsis: Handles the Draw Item message for the owner draw menu for color
+//
+// Arguments: [lpdis] -- pointer to draw item structure
+//
+// Algorithm: If the request is to draw the item, we create a solid brush
+// based on the color for the menu. Make a copy of the rectangle
+// input. Finally, we shrink the rectangle in size and then fill
+// it with the color.
+//
+// History: dd-mmm-yy Author Comment
+// 02-May-94 ricksa author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+void CSimpSvrApp::HandleDrawItem(LPDRAWITEMSTRUCT lpdis)
+{
+ HBRUSH hbr;
+ RECT rc;
+
+ if (lpdis->itemAction == ODA_DRAWENTIRE)
+ {
+ // Paint the color item in the color requested.
+ hbr = CreateSolidBrush(lpdis->itemData);
+ CopyRect((LPRECT)&rc, (LPRECT)&lpdis->rcItem);
+ InflateRect((LPRECT)&rc, -10, -10);
+ FillRect(lpdis->hDC, &rc, hbr);
+ DeleteObject(hbr);
+ }
+}
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Member: CSimpSvrApp::HandleChangeColors (public)
+//
+// Synopsis: Handles change between owner draw and regular menu
+//
+// Algorithm: Reset the checked state of the menu item. If it is an owner
+// draw menu requested, then we reset all the menu items to that.
+// Otherwise, we set it to the reqular menu items.
+//
+// History: dd-mmm-yy Author Comment
+// 02-May-94 ricksa author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+void CSimpSvrApp::HandleChangeColors(void)
+{
+ // Get a handle to the Colors menu
+ HMENU hMenu = m_lpDoc->GetColorMenu();
+
+ // Get the current state of the item
+ BOOL fOwnerDraw = GetMenuState(hMenu, IDM_COLOROWNERDR, MF_BYCOMMAND)
+ & MF_CHECKED;
+
+ // Toggle the state of the item.
+ CheckMenuItem(hMenu, IDM_COLOROWNERDR,
+ MF_BYCOMMAND | (fOwnerDraw ? MF_UNCHECKED : MF_CHECKED));
+
+ if (!fOwnerDraw)
+ {
+ // Change the items to owner-draw items. Pass the RGB value for the
+ // color as the application-supplied data. This makes it easier for
+ // us to draw the items.
+ ModifyMenu(hMenu, IDM_RED, MF_OWNERDRAW | MF_BYCOMMAND, IDM_RED,
+ (LPSTR) RGB (255,0,0));
+ ModifyMenu(hMenu, IDM_GREEN, MF_OWNERDRAW | MF_BYCOMMAND, IDM_GREEN,
+ (LPSTR)RGB (0,255,0));
+ ModifyMenu(hMenu, IDM_BLUE, MF_OWNERDRAW | MF_BYCOMMAND, IDM_BLUE,
+ (LPSTR)RGB (0,0,255));
+ }
+ else
+ {
+ // Change the items to normal text items. */
+ ModifyMenu(hMenu, IDM_RED, MF_BYCOMMAND, IDM_RED, "Red");
+ ModifyMenu(hMenu, IDM_GREEN, MF_BYCOMMAND, IDM_GREEN, "Green");
+ ModifyMenu(hMenu, IDM_BLUE, MF_BYCOMMAND, IDM_BLUE, "Blue");
+ }
+}
+
+
+//**********************************************************************
+//
+// CSimpSvrApp::lCommandHandler
+//
+// Purpose:
+//
+// Handles the processing of WM_COMMAND.
+//
+// Parameters:
+//
+// HWND hWnd - Handle to the application Window
+//
+// UINT message - message (always WM_COMMAND)
+//
+// WPARAM wParam - Same as passed to the WndProc
+//
+// LPARAM lParam - Same as passed to the WndProc
+//
+// Return Value:
+//
+// NULL
+//
+// Function Calls:
+// Function Location
+//
+// GetClientRect Windows API
+// MessageBox Windows API
+// DialogBox Windows API
+// MakeProcInstance Windows API
+// FreeProcInstance Windows API
+// SendMessage Windows API
+// DefWindowProc Windows API
+// InvalidateRect Windows API
+// CSimpSvrDoc::InsertObject DOC.CPP
+// CSimpSvrObj::SetColor OBJ.CPP
+// CSimpSvrObj::RotateColor OBJ.CPP
+//
+//
+//********************************************************************
+
+long CSimpSvrApp::lCommandHandler (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ // In Win32, the upper word of wParam is the notify code. Since we
+ // don't care about this code, we dump it.
+ wParam = LOWORD(wParam);
+
+ switch (wParam) {
+ // bring up the About box
+ case IDM_ABOUT:
+ {
+#ifdef WIN32
+ DialogBox(m_hInst, // current instance
+ TEXT("AboutBox"), // resource to use
+ m_hAppWnd, // parent handle
+ About); // About() instance address
+#else
+ FARPROC lpProcAbout = MakeProcInstance((FARPROC)About, m_hInst);
+
+ DialogBox(m_hInst, // current instance
+ TEXT("AboutBox"), // resource to use
+ m_hAppWnd, // parent handle
+ lpProcAbout); // About() instance address
+
+ FreeProcInstance(lpProcAbout);
+#endif // WIN32
+
+ break;
+ }
+
+ // exit the application
+ case IDM_EXIT:
+ SendMessage(hWnd, WM_SYSCOMMAND, SC_CLOSE, 0L);
+ break;
+
+ case IDM_RED:
+ m_lpDoc->GetObj()->SetColor (128, 0, 0);
+ InvalidateRect(m_lpDoc->GethDocWnd(), NULL, TRUE);
+ break;
+
+ case IDM_GREEN:
+ m_lpDoc->GetObj()->SetColor (0,128, 0);
+ InvalidateRect(m_lpDoc->GethDocWnd(), NULL, TRUE);
+ break;
+
+ case IDM_BLUE:
+ m_lpDoc->GetObj()->SetColor (0, 0, 128);
+ InvalidateRect(m_lpDoc->GethDocWnd(), NULL, TRUE);
+ break;
+
+ case IDM_COLOROWNERDR:
+ HandleChangeColors();
+ break;
+
+ default:
+ return (DefWindowProc(hWnd, message, wParam, lParam));
+ } // end of switch
+ return NULL;
+}
+
+//**********************************************************************
+//
+// CSimpSvrApp::lSizeHandler
+//
+// Purpose:
+//
+// Handles the WM_SIZE message
+//
+// Parameters:
+//
+// HWND hWnd - Handle to the application Window
+//
+// UINT message - message (always WM_SIZE)
+//
+// WPARAM wParam - Same as passed to the WndProc
+//
+// LPARAM lParam - Same as passed to the WndProc
+//
+// Return Value:
+//
+// LONG - returned from the "document" resizing
+//
+// Function Calls:
+// Function Location
+//
+// GetClientRect Windows API
+// CSimpSvrDoc::lResizeDoc DOC.CPP
+//
+//
+//********************************************************************
+
+long CSimpSvrApp::lSizeHandler (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ RECT rect;
+
+ GetClientRect(m_hAppWnd, &rect);
+ return m_lpDoc->lResizeDoc(&rect);
+}
+
+//**********************************************************************
+//
+// CSimpSvrApp::lCreateDoc
+//
+// Purpose:
+//
+// Handles the creation of a document.
+//
+// Parameters:
+//
+// HWND hWnd - Handle to the application Window
+//
+// UINT message - message (always WM_CREATE)
+//
+// WPARAM wParam - Same as passed to the WndProc
+//
+// LPARAM lParam - Same as passed to the WndProc
+//
+// Return Value:
+//
+// NULL
+//
+// Function Calls:
+// Function Location
+//
+// GetClientRect Windows API
+// CSimpSvrDoc::Create DOC.CPP
+//
+//
+//********************************************************************
+
+long CSimpSvrApp::lCreateDoc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ RECT rect;
+
+ GetClientRect(hWnd, &rect);
+
+ m_lpDoc = CSimpSvrDoc::Create(this, &rect, hWnd);
+
+ return NULL;
+}
+
+
+
+//**********************************************************************
+//
+// CSimpSvrApp::PaintApp
+//
+// Purpose:
+//
+// Handles the painting of the doc window.
+//
+//
+// Parameters:
+//
+// HDC hDC - hDC to the Doc Window.
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// CSimpSvrDoc::PaintDoc DOC.CPP
+//
+//
+//
+//********************************************************************
+
+void CSimpSvrApp::PaintApp (HDC hDC)
+{
+
+ // if we supported multiple documents, we would enumerate
+ // through each of the open documents and call paint.
+
+ if (m_lpDoc)
+ m_lpDoc->PaintDoc(hDC);
+
+}
+
+//**********************************************************************
+//
+// CSimpSvrApp::ParseCmdLine
+//
+// Purpose:
+//
+// Determines if the app was started by OLE
+//
+//
+// Parameters:
+//
+// LPSTR lpCmdLine - Pointer to the command line
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// lstrlen Windows API
+// lstrcmp Windows API
+//
+//
+// Comments:
+//
+// Parses the command line looking for the -Embedding or /Embedding
+// flag.
+//
+//********************************************************************
+
+void CSimpSvrApp::ParseCmdLine(LPSTR lpCmdLine)
+{
+ CHAR szTemp[255];
+
+ m_fStartByOle = TRUE;
+
+ ::ParseCmdLine (lpCmdLine, &m_fStartByOle, szTemp);
+
+}
+
+//**********************************************************************
+//
+// CSimpSvrApp::SetStatusText
+//
+// Purpose:
+//
+// Blanks out the text in the status bar
+//
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// CSimpSvrDoc::SetStatusText DOC.CPP
+//
+//
+//********************************************************************
+
+void CSimpSvrApp::SetStatusText()
+{
+ m_lpDoc->SetStatusText();
+}
+
+
+//**********************************************************************
+//
+// CSimpSvrApp::IsInPlaceActive
+//
+// Purpose:
+//
+// Safely determines from the app level if currently inplace active.
+//
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// TRUE - Inplace active
+// FALSE - Not Inplace active
+//
+// Function Calls:
+// Function Location
+//
+// CSimpSvrDoc::GetObject DOC.H
+// CSimpSvrObj:IsInPlaceActive OBJ.H
+//
+//
+//********************************************************************
+
+BOOL CSimpSvrApp::IsInPlaceActive()
+{
+ BOOL retval = FALSE;
+
+ if (m_lpDoc)
+ if (m_lpDoc->GetObj())
+ retval = m_lpDoc->GetObj()->IsInPlaceActive();
+
+ return retval;
+}
+
+//**********************************************************************
+//
+// CSimpSvrApp::ShowAppWnd
+//
+// Purpose:
+//
+// Shows the Application Window
+//
+// Parameters:
+//
+// int nCmdShow - Window State
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// ShowWindow Windows API
+// UpdateWindow Windows API
+// CoLockObjectExternal OLE API
+//
+//********************************************************************
+
+void CSimpSvrApp::ShowAppWnd(int nCmdShow)
+{
+ if (CoLockObjectExternal(this, TRUE, FALSE) != S_OK)
+ TestDebugOut(TEXT("CSimpSvrApp::ShowAppWnd \
+ CoLockObjectExternal fails\n"));
+ ShowWindow (m_hAppWnd, nCmdShow);
+ UpdateWindow (m_hAppWnd);
+}
+
+//**********************************************************************
+//
+// CSimpSvrApp::ShowAppWnd
+//
+// Purpose:
+//
+// Hides the Application Window
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// ShowWindow Windows API
+// CoLockObjectExternal OLE API
+//
+//********************************************************************
+
+void CSimpSvrApp::HideAppWnd()
+{
+ if (CoLockObjectExternal(this, FALSE, TRUE) != S_OK)
+ TestDebugOut(TEXT("CSimpSvrApp::HideAppWnd \
+ CoLockObjectExternal fails\n"));
+ ShowWindow (m_hAppWnd, SW_HIDE);
+}
+
+
diff --git a/private/oleutest/simpsvr/app.h b/private/oleutest/simpsvr/app.h
new file mode 100644
index 000000000..3c1c9f656
--- /dev/null
+++ b/private/oleutest/simpsvr/app.h
@@ -0,0 +1,87 @@
+//**********************************************************************
+// File name: app.h
+//
+// Definition of CSimpSvrApp
+//
+// Copyright (c) 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+
+#if !defined( _APP_H_)
+#define _APP_H_
+
+class CSimpSvrDoc;
+interface CClassFactory;
+
+class CSimpSvrApp : public IUnknown
+{
+private:
+
+ int m_nCount; // reference count
+
+ HINSTANCE m_hInst; // application instance
+ BOOL m_fStartByOle; // TRUE if app started by OLE
+ DWORD m_dwRegisterClass; // returned by RegisterClassFactory
+
+ LPOLEOBJECT m_OleObject; // pointer to "dummy" object
+
+
+ CSimpSvrDoc FAR * m_lpDoc; // pointer to document object
+ BOOL m_fInitialized; // OLE initialization flag
+
+ RECT nullRect; // used in inplace negotiation
+
+ // Convert to/from owner draw menus
+ void HandleChangeColors(void);
+
+
+public:
+
+ HWND m_hAppWnd; // main window handle
+
+ HACCEL m_hAccel; // Accelerators
+
+
+ // IUnknown Interfaces
+ STDMETHODIMP QueryInterface(REFIID riid, LPVOID FAR* ppvObj);
+ STDMETHODIMP_(ULONG) AddRef();
+ STDMETHODIMP_(ULONG) Release();
+
+ // Initialization methods
+
+ CSimpSvrApp(); // Constructor
+ ~CSimpSvrApp(); // Destructor
+
+
+ BOOL fInitApplication (HANDLE hInstance);
+ BOOL fInitInstance (HANDLE hInstance, int nCmdShow, CClassFactory FAR * lpClassFactory);
+
+ // Message handling methods
+
+ long lCommandHandler (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
+ long lSizeHandler (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
+ long lCreateDoc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
+ void PaintApp(HDC hDC);
+ void HandleDrawItem(LPDRAWITEMSTRUCT lpdis);
+
+ // Utility functions
+ void ParseCmdLine(LPSTR lpCmdLine);
+ void SetStatusText();
+ BOOL IsInPlaceActive();
+ void ShowAppWnd(int nCmdShow=SW_SHOWNORMAL);
+ void HideAppWnd();
+
+
+ // member variable access
+ inline HWND GethAppWnd() { return m_hAppWnd; };
+ inline HINSTANCE GethInst() { return m_hInst; };
+ inline BOOL IsStartedByOle() { return m_fStartByOle; };
+ inline BOOL IsInitialized() { return m_fInitialized; };
+ inline DWORD GetRegisterClass() { return m_dwRegisterClass; };
+ inline CSimpSvrDoc FAR * GetDoc() { return m_lpDoc; };
+ inline void ClearDoc() { m_lpDoc = NULL; };
+ inline LPOLEOBJECT GetOleObject() { return m_OleObject; };
+
+ friend interface CClassFactory; // make the contained class a friend
+};
+
+#endif
diff --git a/private/oleutest/simpsvr/bang.ico b/private/oleutest/simpsvr/bang.ico
new file mode 100644
index 000000000..90fe0f220
--- /dev/null
+++ b/private/oleutest/simpsvr/bang.ico
Binary files differ
diff --git a/private/oleutest/simpsvr/daytona/makefile b/private/oleutest/simpsvr/daytona/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/oleutest/simpsvr/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/simpsvr/daytona/sources b/private/oleutest/simpsvr/daytona/sources
new file mode 100644
index 000000000..59f3f7fbc
--- /dev/null
+++ b/private/oleutest/simpsvr/daytona/sources
@@ -0,0 +1,42 @@
+TARGETNAME=SIMPSVR
+TARGETTYPE=PROGRAM
+TARGETPATH=OBJ
+TARGETLIBS= \
+ $(GUI32_LIBS) \
+ $(WIN32_LIBS) \
+ $(CRT_LIBS) \
+ $(NT_CRT) \
+ $(LIBRARY_PATH)\ole32.lib \
+ $(LIBRARY_PATH)\shell32.lib \
+ $(LIBRARY_PATH)\comdlg32.lib \
+ ..\..\letest\ole2ui\daytona\obj\*\ole2u32a.lib \
+ $(LIBRARY_PATH)\uuid.lib
+
+BLDCRT=1
+UMTYPE=windows
+UMENTRY=winmain
+#UMLIBS= \
+# ..\..\libs\daytona\*\common.lib
+
+INCLUDES=..;..\..\inc;..\..\letest\ole2ui
+
+C_DEFINES=-DWIN32 -DDEBUG -DINC_OLE2 -DCLIENT -DWINDOWS
+
+NTDEBUG=ntsd
+NTDEBUGTYPE=both
+MSC_OPTIMIZATION=/Od
+
+SOURCES= \
+..\APP.CPP \
+..\DOC.CPP \
+..\ICF.CPP \
+..\IDO.CPP \
+..\IEC.CPP \
+..\IOIPAO.CPP \
+..\IOIPO.CPP \
+..\IOO.CPP \
+..\IPS.CPP \
+..\OBJ.CPP \
+..\PRE.CPP \
+..\SIMPSVR.CPP \
+..\SIMPSVR.RC
diff --git a/private/oleutest/simpsvr/debug.log b/private/oleutest/simpsvr/debug.log
new file mode 100644
index 000000000..8ac64d636
--- /dev/null
+++ b/private/oleutest/simpsvr/debug.log
@@ -0,0 +1 @@
+NULL CLSID @ 135250 doesn't support debug dumping
diff --git a/private/oleutest/simpsvr/default.ico b/private/oleutest/simpsvr/default.ico
new file mode 100644
index 000000000..4542c57d3
--- /dev/null
+++ b/private/oleutest/simpsvr/default.ico
Binary files differ
diff --git a/private/oleutest/simpsvr/depend.mk b/private/oleutest/simpsvr/depend.mk
new file mode 100644
index 000000000..e2bbcbe83
--- /dev/null
+++ b/private/oleutest/simpsvr/depend.mk
@@ -0,0 +1,271 @@
+#
+# Built automatically
+#
+
+#
+# Source files
+#
+
+$(OBJDIR)\simpsvr.obj $(OBJDIR)\simpsvr.lst: .\simpsvr.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\ole2ver.h $(CAIROLE)\h\export\oleguid.h \
+ $(CAIROLE)\h\export\scode.h $(CAIROLE)\h\export\storage.h \
+ $(COMMON)\ih\winnot.h $(COMMONINC)\disptype.h $(COMMONINC)\stgprop.h \
+ $(CRTINC)\assert.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)\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\ole2ui.h ..\ole2ui\olestd.h .\app.h .\doc.h .\icf.h \
+ .\ido.h .\iec.h .\ioipao.h .\ioipo.h .\ioo.h .\ips.h .\obj.h \
+ .\pre.h .\resource.h .\simpsvr.h
+
+$(OBJDIR)\pre.obj $(OBJDIR)\pre.lst: .\pre.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\ole2ver.h \
+ $(CAIROLE)\h\export\oleguid.h $(CAIROLE)\h\export\scode.h \
+ $(CAIROLE)\h\export\storage.h $(COMMON)\ih\winnot.h \
+ $(COMMONINC)\disptype.h $(COMMONINC)\stgprop.h $(CRTINC)\assert.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)\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\ole2ui.h ..\ole2ui\olestd.h .\pre.h \
+ .\resource.h .\simpsvr.h
+
+$(OBJDIR)\obj.obj $(OBJDIR)\obj.lst: .\obj.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\ole2ver.h \
+ $(CAIROLE)\h\export\oleguid.h $(CAIROLE)\h\export\scode.h \
+ $(CAIROLE)\h\export\storage.h $(COMMON)\ih\winnot.h \
+ $(COMMONINC)\disptype.h $(COMMONINC)\stgprop.h $(CRTINC)\assert.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)\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\ole2ui.h ..\ole2ui\olestd.h .\app.h \
+ .\doc.h .\icf.h .\ido.h .\iec.h .\ioipao.h .\ioipo.h .\ioo.h \
+ .\ips.h .\obj.h .\pre.h .\resource.h .\simpsvr.h
+
+$(OBJDIR)\ips.obj $(OBJDIR)\ips.lst: .\ips.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\ole2ver.h \
+ $(CAIROLE)\h\export\oleguid.h $(CAIROLE)\h\export\scode.h \
+ $(CAIROLE)\h\export\storage.h $(COMMON)\ih\winnot.h \
+ $(COMMONINC)\disptype.h $(COMMONINC)\stgprop.h $(CRTINC)\assert.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)\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\ole2ui.h ..\ole2ui\olestd.h .\app.h \
+ .\doc.h .\ido.h .\iec.h .\ioipao.h .\ioipo.h .\ioo.h .\ips.h \
+ .\obj.h .\pre.h .\resource.h .\simpsvr.h
+
+$(OBJDIR)\ioo.obj $(OBJDIR)\ioo.lst: .\ioo.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\ole2ver.h \
+ $(CAIROLE)\h\export\oleguid.h $(CAIROLE)\h\export\scode.h \
+ $(CAIROLE)\h\export\storage.h $(COMMON)\ih\winnot.h \
+ $(COMMONINC)\disptype.h $(COMMONINC)\stgprop.h $(CRTINC)\assert.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)\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\ole2ui.h ..\ole2ui\olestd.h .\app.h \
+ .\doc.h .\ido.h .\iec.h .\ioipao.h .\ioipo.h .\ioo.h .\ips.h \
+ .\obj.h .\pre.h .\resource.h .\simpsvr.h
+
+$(OBJDIR)\ioipo.obj $(OBJDIR)\ioipo.lst: .\ioipo.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\ole2ver.h $(CAIROLE)\h\export\oleguid.h \
+ $(CAIROLE)\h\export\scode.h $(CAIROLE)\h\export\storage.h \
+ $(COMMON)\ih\winnot.h $(COMMONINC)\disptype.h $(COMMONINC)\stgprop.h \
+ $(CRTINC)\math.h $(CRTINC)\assert.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)\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\ole2ui.h \
+ ..\ole2ui\olestd.h .\app.h .\doc.h .\ido.h .\iec.h .\ioipao.h \
+ .\ioipo.h .\ioo.h .\ips.h .\obj.h .\pre.h .\resource.h .\simpsvr.h
+
+$(OBJDIR)\ioipao.obj $(OBJDIR)\ioipao.lst: .\ioipao.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\ole2ver.h $(CAIROLE)\h\export\oleguid.h \
+ $(CAIROLE)\h\export\scode.h $(CAIROLE)\h\export\storage.h \
+ $(COMMON)\ih\winnot.h $(COMMONINC)\disptype.h $(COMMONINC)\stgprop.h \
+ $(CRTINC)\assert.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)\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\ole2ui.h \
+ ..\ole2ui\olestd.h .\app.h .\doc.h .\ido.h .\iec.h .\ioipao.h \
+ .\ioipo.h .\ioo.h .\ips.h .\obj.h .\pre.h .\resource.h .\simpsvr.h
+
+$(OBJDIR)\iec.obj $(OBJDIR)\iec.lst: .\iec.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\ole2ver.h \
+ $(CAIROLE)\h\export\oleguid.h $(CAIROLE)\h\export\scode.h \
+ $(CAIROLE)\h\export\storage.h $(COMMON)\ih\winnot.h \
+ $(COMMONINC)\disptype.h $(COMMONINC)\stgprop.h $(CRTINC)\assert.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)\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\ole2ui.h ..\ole2ui\olestd.h .\app.h \
+ .\doc.h .\ido.h .\iec.h .\ioipao.h .\ioipo.h .\ioo.h .\ips.h \
+ .\obj.h .\pre.h .\resource.h .\simpsvr.h
+
+$(OBJDIR)\ido.obj $(OBJDIR)\ido.lst: .\ido.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\ole2ver.h \
+ $(CAIROLE)\h\export\oleguid.h $(CAIROLE)\h\export\scode.h \
+ $(CAIROLE)\h\export\storage.h $(COMMON)\ih\winnot.h \
+ $(COMMONINC)\disptype.h $(COMMONINC)\stgprop.h $(CRTINC)\assert.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)\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\ole2ui.h ..\ole2ui\olestd.h .\app.h \
+ .\doc.h .\ido.h .\iec.h .\ioipao.h .\ioipo.h .\ioo.h .\ips.h \
+ .\obj.h .\pre.h .\resource.h .\simpsvr.h
+
+$(OBJDIR)\icf.obj $(OBJDIR)\icf.lst: .\icf.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\ole2ver.h \
+ $(CAIROLE)\h\export\oleguid.h $(CAIROLE)\h\export\scode.h \
+ $(CAIROLE)\h\export\storage.h $(COMMON)\ih\winnot.h \
+ $(COMMONINC)\disptype.h $(COMMONINC)\stgprop.h $(CRTINC)\assert.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)\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\ole2ui.h ..\ole2ui\olestd.h .\app.h \
+ .\doc.h .\icf.h .\pre.h .\resource.h .\simpsvr.h
+
+$(OBJDIR)\doc.obj $(OBJDIR)\doc.lst: .\doc.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\ole2ver.h \
+ $(CAIROLE)\h\export\oleguid.h $(CAIROLE)\h\export\scode.h \
+ $(CAIROLE)\h\export\storage.h $(COMMON)\ih\winnot.h \
+ $(COMMONINC)\disptype.h $(COMMONINC)\stgprop.h $(CRTINC)\assert.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)\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\ole2ui.h ..\ole2ui\olestd.h .\app.h \
+ .\doc.h .\ido.h .\iec.h .\ioipao.h .\ioipo.h .\ioo.h .\ips.h \
+ .\obj.h .\pre.h .\resource.h .\simpsvr.h
+
+$(OBJDIR)\app.obj $(OBJDIR)\app.lst: .\app.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\ole2ver.h \
+ $(CAIROLE)\h\export\oleguid.h $(CAIROLE)\h\export\scode.h \
+ $(CAIROLE)\h\export\storage.h $(COMMON)\ih\winnot.h \
+ $(COMMONINC)\disptype.h $(COMMONINC)\stgprop.h $(CRTINC)\assert.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)\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\ole2ui.h ..\ole2ui\olestd.h .\app.h \
+ .\doc.h .\icf.h .\ido.h .\iec.h .\ioipao.h .\ioipo.h .\ioo.h \
+ .\ips.h .\obj.h .\pre.h .\resource.h .\simpsvr.h
+
diff --git a/private/oleutest/simpsvr/dirs b/private/oleutest/simpsvr/dirs
new file mode 100644
index 000000000..e0e16d167
--- /dev/null
+++ b/private/oleutest/simpsvr/dirs
@@ -0,0 +1,3 @@
+DIRS=
+OPTIONAL_DIRS= \
+ daytona
diff --git a/private/oleutest/simpsvr/doc.cpp b/private/oleutest/simpsvr/doc.cpp
new file mode 100644
index 000000000..ccc4c053d
--- /dev/null
+++ b/private/oleutest/simpsvr/doc.cpp
@@ -0,0 +1,688 @@
+//**********************************************************************
+// File name: DOC.CPP
+//
+// Implementation file for CSimpSvrDoc.
+//
+// Functions:
+//
+// See DOC.H for Class Definition
+//
+// Copyright (c) 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+
+#include "pre.h"
+#include "obj.h"
+#include "app.h"
+#include "doc.h"
+
+//**********************************************************************
+//
+// CSimpSvrDoc::Create
+//
+// Purpose:
+//
+// Creation for the CSimpSvrDoc Class
+//
+// Parameters:
+//
+// CSimpSvrApp FAR * lpApp - Pointer to the CSimpSvrApp Class
+//
+// LPRECT lpRect - Client area rect of "frame" window
+//
+// HWND hWnd - Window Handle of "frame" window
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// StgCreateDocfile OLE API
+// CreateWindow Windows API
+// ShowWindow Windows API
+// UpdateWindow Windows API
+// CSimpSvrDoc::CSimpSvrDoc DOC.CPP
+// CreateHatchWindow OLE2UI
+//
+// Comments:
+//
+// This routine was added so that failure could be returned
+// from object creation.
+//
+//********************************************************************
+
+CSimpSvrDoc FAR * CSimpSvrDoc::Create(CSimpSvrApp FAR *lpApp, LPRECT lpRect,HWND hWnd)
+{
+ CSimpSvrDoc FAR * lpTemp = new CSimpSvrDoc(lpApp, hWnd);
+
+ if (!lpTemp)
+ return NULL;
+
+ // create the document Window
+ lpTemp->m_hDocWnd = CreateWindow(
+ TEXT("DocWClass"),
+ NULL,
+ WS_CHILD | WS_CLIPSIBLINGS,
+ lpRect->left,
+ lpRect->top,
+ lpRect->right,
+ lpRect->bottom,
+ hWnd,
+ NULL,
+ lpApp->GethInst(),
+ NULL);
+
+ if (!lpTemp->m_hDocWnd)
+ goto error;
+
+ lpTemp->ShowDocWnd();
+
+ lpTemp->m_hHatchWnd = CreateHatchWindow( lpTemp->m_hDocWnd, lpApp->GethInst());
+
+ lpTemp->HideHatchWnd();
+
+ return (lpTemp);
+
+error:
+ delete (lpTemp);
+ return NULL;
+
+}
+
+//**********************************************************************
+//
+// CSimpSvrDoc::CSimpSvrDoc
+//
+// Purpose:
+//
+// Constructor for the CSimpSvrDoc Class
+//
+// Parameters:
+//
+// CSimpSvrApp FAR * lpApp - Pointer to the CSimpSvrApp Class
+//
+// HWND hWnd - Window Handle of "frame" window
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// GetMenu Windows API
+// GetSubMenu Windows API
+//
+// Comments:
+//
+//********************************************************************
+
+CSimpSvrDoc::CSimpSvrDoc(CSimpSvrApp FAR * lpApp,HWND hWnd)
+{
+ TestDebugOut(TEXT("In CSimpSvrDoc's Constructor\r\n"));
+ m_lpApp = lpApp;
+ m_nCount = 0;
+ m_lpObj = NULL;
+
+ // set up menu handles
+ m_hMainMenu = GetMenu(hWnd);
+ m_hColorMenu = GetSubMenu(m_hMainMenu, 1);
+ m_hHelpMenu = GetSubMenu(m_hMainMenu, 2);
+
+
+}
+
+//**********************************************************************
+//
+// CSimpSvrDoc::~CSimpSvrDoc
+//
+// Purpose:
+//
+// Destructor for CSimpSvrDoc
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// DestroyWindow Windows API
+// CSimpSvrApp::ClearDoc APP.CPP
+//
+// Comments:
+//
+//********************************************************************
+
+CSimpSvrDoc::~CSimpSvrDoc()
+{
+ TestDebugOut(TEXT("In CSimpSvrDoc's Destructor\r\n"));
+
+ // Clear the Doc object pointer so that the SimpSvrApp won't be able
+ // to access invalid objects. (same for the SimpSvrObj)
+ if (m_lpApp)
+ m_lpApp->ClearDoc();
+
+ if (m_lpObj)
+ m_lpObj->ClearDoc();
+
+ DestroyWindow(m_hHatchWnd);
+ DestroyWindow(m_hDocWnd);
+}
+
+
+//**********************************************************************
+//
+// CSimpSvrDoc::QueryInterface
+//
+// Purpose:
+//
+// Return a pointer to a requested interface
+//
+// Parameters:
+//
+// REFIID riid - ID of interface to be returned
+// LPVOID FAR* ppvObj - Location to return the interface
+//
+// Return Value:
+//
+// E_NOINTERFACE - Always
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// CSimpSvrApp::QueryInterface APP.CPP
+//
+// Comments:
+//
+// Since the document could contain multiple objects, all
+// interfaces except those associated with the document should
+// be returned. In this implementation, there are no doc level
+// interfaces.
+//
+//********************************************************************
+
+STDMETHODIMP CSimpSvrDoc::QueryInterface(REFIID riid, LPVOID FAR* ppvObj)
+{
+ TestDebugOut(TEXT("In CSimpSvrDoc::QueryInterface\r\n"));
+
+ SCODE sc = E_NOINTERFACE;
+
+ if (IsEqualIID(riid, IID_IUnknown))
+ {
+ AddRef();
+ *ppvObj = this;
+ sc = S_OK;
+ }
+
+ return ResultFromScode(sc);
+}
+
+//**********************************************************************
+//
+// CSimpSvrDoc::AddRef
+//
+// Purpose:
+//
+// Increments the document level reference count
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// UINT - The current reference count on the document
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// CSimpSvrApp::AddRef APP.CPP
+//
+// Comments:
+//
+// The reference count at this level reflects the total ref.
+// count of all interfaces on all objects contained within
+// this document. Note that it also "trickles up" the
+// ref count to the app level.
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) CSimpSvrDoc::AddRef()
+{
+ TestDebugOut(TEXT("In CSimpSvrDoc::AddRef\r\n"));
+ // AddRef the app, but return the doc count
+ m_lpApp->AddRef();
+
+ return ++m_nCount;
+}
+
+//**********************************************************************
+//
+// CSimpSvrDoc::Release
+//
+// Purpose:
+//
+// Decrements the document level reference count
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// UINT - The current reference count on the document
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// CSimpSvrApp::Release APP.CPP
+//
+// Comments:
+//
+// The reference count at this level reflects the total ref.
+// count of all interfaces on all objects contained within
+// this document. Note that it also "trickles up" the
+// ref count to the app level.
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) CSimpSvrDoc::Release()
+{
+ TestDebugOut(TEXT("In CSimpSvrDoc::Release\r\n"));
+ // Release the app, but return the app count
+ m_lpApp->Release();
+
+ if (--m_nCount== 0)
+ {
+ delete this;
+ return(0);
+ }
+ return m_nCount;
+}
+
+//**********************************************************************
+//
+// CSimpSvrDoc::lResizeDoc
+//
+// Purpose:
+//
+// Resizes the document
+//
+// Parameters:
+//
+// LPRECT lpRect - The size of the client are of the "frame"
+// Window.
+//
+// Return Value:
+//
+// NULL
+//
+// Function Calls:
+// Function Location
+//
+// MoveWindow Windows API
+//
+//
+//********************************************************************
+
+long CSimpSvrDoc::lResizeDoc(LPRECT lpRect)
+{
+ MoveWindow(m_hDocWnd, lpRect->left, lpRect->top, lpRect->right, lpRect->bottom, TRUE);
+ return NULL;
+}
+
+
+//**********************************************************************
+//
+// CSimpSvrDoc::PaintDoc
+//
+// Purpose:
+//
+// Paints the Document
+//
+// Parameters:
+//
+// HDC hDC - hDC of the document Window
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// CSimpSvrObj::Draw OBJ.CPP
+// CSimpSvrObj::GetDataAdviseHolder OBJ.H
+// CSimpSvrObj::GetDataObject OBJ.H
+// CSimpAppObj::IsStartedByOle APP.CPP
+// IDataAdviseHolder::SendOnDataChange OLE API
+//
+//
+//********************************************************************
+
+void CSimpSvrDoc::PaintDoc (HDC hDC)
+{
+
+ // if the object hasn't been created yet, then don't draw
+ if (m_lpObj)
+ m_lpObj->Draw(hDC,FALSE);
+ else
+ return;
+
+ // Sending a data change every time we paint, but only if we
+ // were started by OLE
+ if (m_lpApp->IsStartedByOle())
+ m_lpObj->SendOnDataChange( );
+}
+
+
+
+//**********************************************************************
+//
+// CSimpSvrDoc::CreateObject
+//
+// Purpose:
+// Handles the creation of a SimpSvrObj.
+//
+// Parameters:
+//
+//
+// Return Value:
+//
+// S_OK if the function succeeds, otherwise E_FAIL
+//
+// Function Calls:
+// Function Location
+//
+// CSimpSvrObj::CSimpSvrObj OBJ.CPP
+// CSimpSvrOjb::QueryInterface OBJ.CPP
+//
+//
+//********************************************************************
+
+HRESULT CSimpSvrDoc::CreateObject(REFIID riid, LPVOID FAR *ppvObject)
+{
+ SCODE sc = E_FAIL;
+
+ m_lpObj = new CSimpSvrObj(this);
+
+ if (m_lpObj)
+ {
+ m_lpObj->QueryInterface(riid, ppvObject);
+ sc = S_OK;
+ }
+
+ return ResultFromScode(sc);
+}
+
+//**********************************************************************
+//
+// CSimpSvrDoc::Close
+//
+// Purpose:
+//
+// Closes the object
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// CSimpSvrObj::AddRef OBJ.CPP
+// CSimpSvrObj::Release OBJ.CPP
+// CSimpSvrObj::IsInPlaceActive OBJ.H
+// CSimpSvrObj::GetOleInPlaceObject OBJ.H
+// CSimpSvrObj::ClearOleClientSite OBJ.H
+// CSimpSvrObj::GetDataAdviseHolder OBJ.H
+// CSimpSvrObj::GetOleClientSite OBJ.H
+// CSimpSvrObj::ClearDataAdviseHolder OBJ.H
+// CSimpSvrObj::GetOleAdviseHolder OBJ.H
+// CSimpSvrObj::ClearOleAdviseHolder OBJ.H
+// IOleInPlaceObject::InPlaceDeactivate Container
+// IOleClientSite::SaveObject Container
+// IOleClientSite::OnShowWindow Container
+// IOleClientSite::Release Container
+// IDataAdviseHolder::SendOnDataChange OLE
+// IDataAdviseHolder::Release OLE
+// IOleAdviseHolder::SendOnClose OLE
+// IOleAdviseHolder::Release OLE
+//
+//
+//********************************************************************
+
+void CSimpSvrDoc::Close()
+{
+ TestDebugOut(TEXT("In CSimpSvrDoc::Close() \r\n"));
+
+ m_lpObj->AddRef(); // hold object alive
+
+ // if the object is currently inplace active, then deactivate
+ if (m_lpObj->IsInPlaceActive())
+ m_lpObj->GetOleInPlaceObject()->InPlaceDeactivate();
+
+ // unregister from the ROT...
+ if (m_lpObj->GetRotRegister())
+ {
+ LPRUNNINGOBJECTTABLE lpRot;
+
+ if (GetRunningObjectTable (0, &lpRot) == NOERROR )
+ {
+ lpRot->Revoke(m_lpObj->GetRotRegister());
+ lpRot->Release();
+ }
+ }
+
+ // if we have a clientsite, instruct it to save the object
+ if (m_lpObj->GetOleClientSite())
+ {
+ m_lpObj->GetOleClientSite()->SaveObject();
+ m_lpObj->GetOleClientSite()->OnShowWindow(FALSE);
+ }
+
+ // Do a final SendOnDataChange for those containers that have specified the
+ // ADF_DATAONSTOP flag.
+ if (m_lpObj->GetDataAdviseHolder())
+ {
+ m_lpObj->GetDataAdviseHolder()->SendOnDataChange( m_lpObj->GetDataObject(), 0, ADVF_DATAONSTOP);
+ }
+
+
+ // Tell the container that we are shutting down.
+ if (m_lpObj->GetOleAdviseHolder())
+ {
+ m_lpObj->GetOleAdviseHolder()->SendOnClose();
+ }
+
+ // release our streams and storage
+ m_lpObj->GetPersistStorage()->ReleaseStreamsAndStorage();
+
+ // Disconnect the object. NOTE: This call should not do anything
+ // unless the container has cause a GP Fault or some other problem
+ // has occured...
+ TestDebugOut(TEXT("*** Before CoDisconnectObject *** \r\n"));
+
+ CoDisconnectObject((LPUNKNOWN)m_lpObj, 0);
+
+ TestDebugOut(TEXT("*** After CoDisconnectObject *** \r\n"));
+
+ m_lpObj->Release(); // let object close
+
+}
+
+
+//**********************************************************************
+//
+// CSimpSvrDoc::SetStatusText
+//
+// Purpose:
+//
+// Sets the Container's status bar text
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// CSimpSvrObj::IsInPlaceActive OBJ.CPP
+// IOleInPlaceFrame::SetStatusText Container
+//
+// Comments:
+//
+// Even though there is no status line in this sample, this
+// method must be called on WM_MENUSELECT to clear the last
+// message in the status line.
+//
+//********************************************************************
+
+void CSimpSvrDoc::SetStatusText()
+{
+ if (m_lpObj->IsInPlaceActive())
+ m_lpObj->GetInPlaceFrame()->SetStatusText(OLESTR("\0"));
+
+}
+
+//**********************************************************************
+//
+// CSimpSvrDoc::ShowDocWnd
+//
+// Purpose:
+//
+// Shows the Document Window
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// ShowWindow Windows API
+// UpdateWindow Windows API
+//
+// Comments:
+//
+//********************************************************************
+
+void CSimpSvrDoc::ShowDocWnd()
+{
+ ShowWindow(m_hDocWnd, SW_SHOWNORMAL); // Show the window
+ UpdateWindow(m_hDocWnd); // Sends WM_PAINT message
+}
+
+//**********************************************************************
+//
+// CSimpSvrDoc::ShowHatchWnd
+//
+// Purpose:
+//
+// Shows the hatch Window
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// ShowWindow Windows API
+//
+// Comments:
+//
+//********************************************************************
+
+void CSimpSvrDoc::ShowHatchWnd()
+{
+ ShowWindow(m_hHatchWnd, SW_SHOW);
+}
+
+//**********************************************************************
+//
+// CSimpSvrDoc::HideDocWnd
+//
+// Purpose:
+//
+// Hides the DocumentWindow
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// ShowWindow Windows API
+//
+// Comments:
+//
+//********************************************************************
+
+void CSimpSvrDoc::HideDocWnd()
+{
+ ShowWindow(m_hDocWnd, SW_HIDE);
+}
+
+//**********************************************************************
+//
+// CSimpSvrDoc::HideHatchWnd
+//
+// Purpose:
+//
+// Hides the Hatch Window
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// ShowWindow Windows API
+//
+// Comments:
+//
+//********************************************************************
+
+void CSimpSvrDoc::HideHatchWnd()
+{
+ ShowWindow(m_hHatchWnd, SW_HIDE);
+}
diff --git a/private/oleutest/simpsvr/doc.h b/private/oleutest/simpsvr/doc.h
new file mode 100644
index 000000000..15c8d40bc
--- /dev/null
+++ b/private/oleutest/simpsvr/doc.h
@@ -0,0 +1,70 @@
+//**********************************************************************
+// File name: doc.h
+//
+// Definition of CSimpSvrDoc
+//
+// Copyright (c) 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+
+#if !defined( _DOC_H_ )
+#define _DOC_H_
+
+class CSimpSvrApp;
+class CSimpSvrObj;
+
+class CSimpSvrDoc : IUnknown
+{
+private:
+ int m_nCount;
+
+ CSimpSvrApp FAR * m_lpApp;
+ CSimpSvrObj FAR * m_lpObj;
+ HMENU m_hMainMenu;
+ HMENU m_hColorMenu;
+ HMENU m_hHelpMenu;
+
+ HWND m_hDocWnd;
+ HWND m_hHatchWnd;
+
+public:
+ static CSimpSvrDoc FAR * Create(CSimpSvrApp FAR *lpApp, LPRECT lpRect,HWND hWnd);
+
+ CSimpSvrDoc();
+ CSimpSvrDoc(CSimpSvrApp FAR *lpApp, HWND hWnd);
+ ~CSimpSvrDoc();
+
+// IUnknown Interfaces
+ STDMETHODIMP QueryInterface(REFIID riid, LPVOID FAR* ppvObj);
+ STDMETHODIMP_(ULONG) AddRef();
+ STDMETHODIMP_(ULONG) Release();
+
+ long lResizeDoc(LPRECT lpRect);
+ long lAddVerbs();
+
+ BOOL Load(LPTSTR lpszFileName);
+ void PaintDoc(HDC hDC);
+ void lButtonDown(WPARAM wParam,LPARAM lParam);
+
+ HRESULT CreateObject(REFIID riid, LPVOID FAR *ppvObject);
+
+ void Close();
+ void SetStatusText();
+ void ShowDocWnd();
+ void ShowHatchWnd();
+ void CSimpSvrDoc::HideDocWnd();
+ void CSimpSvrDoc::HideHatchWnd();
+
+// member access
+ inline HMENU GetMainMenu() { return m_hMainMenu; };
+ inline HMENU GetColorMenu() { return m_hColorMenu; };
+ inline HMENU GetHelpMenu() { return m_hHelpMenu; } ;
+ inline HWND GethDocWnd() { return m_hDocWnd; };
+ inline HWND GethHatchWnd() { return m_hHatchWnd; };
+ inline HWND GethAppWnd() { return m_lpApp->GethAppWnd(); };
+ inline CSimpSvrApp FAR * GetApp() { return m_lpApp; };
+ inline CSimpSvrObj FAR * GetObj() { return m_lpObj; };
+ inline void ClearObj() { m_lpObj = NULL; };
+
+};
+
+#endif
diff --git a/private/oleutest/simpsvr/filelist.mk b/private/oleutest/simpsvr/filelist.mk
new file mode 100644
index 000000000..2c1337a49
--- /dev/null
+++ b/private/oleutest/simpsvr/filelist.mk
@@ -0,0 +1,71 @@
+############################################################################
+#
+# 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 = simpsvr.exe
+RELEASE = 0
+TARGET_DESCRIPTION = "$(PLATFORM) $(BUILDTYPE) Simple Server"
+
+
+#
+# Source files. Remember to prefix each name with .\
+#
+
+CFILES =
+CPPFILES = .\simpsvr.cpp \
+ .\app.cpp \
+ .\doc.cpp \
+ .\icf.cpp \
+ .\ido.cpp \
+ .\iec.cpp \
+ .\ioipao.cpp \
+ .\ioipo.cpp \
+ .\ioo.cpp \
+ .\ips.cpp \
+ .\obj.cpp \
+ .\pre.cpp
+RCFILES = .\simpsvr.rc
+
+#
+# Libraries and other object files to link.
+#
+OBJFILES =
+LIBS = $(CAIROLE)\ilib\$(OBJDIR)\ole232.lib \
+ $(CAIROLE)\ilib\$(OBJDIR)\storag32.lib \
+ $(CAIROLE)\ilib\$(OBJDIR)\compob32.lib \
+ ..\ole2ui\$(OBJDIR)\ole2uixd.lib
+
+DEFFILE = .\simpsvr.def
+
+
+#
+# Precompiled headers.
+#
+
+PXXFILE =
+PFILE =
+CINC = -I..\ole2ui -I..\ole2ui\resource\usa \
+ -I..\ole2ui\resource\static
+!if "$(EXPORT)"=="0"
+CINC = $(CINC) -I$(CAIROLE)\h -I$(CAIROLE)\common
+!else
+CINC = $(CINC) -I$(CAIROLE)\h\export
+!endif
+
+CFLAGS=/D_DEBUG
+
+# For Chicago Build
+!if "$(OPSYS)"=="DOS"
+CFLAGS=$(CFLAGS) /D_INC_OLE
+!endif
+
diff --git a/private/oleutest/simpsvr/icf.cpp b/private/oleutest/simpsvr/icf.cpp
new file mode 100644
index 000000000..4f2403411
--- /dev/null
+++ b/private/oleutest/simpsvr/icf.cpp
@@ -0,0 +1,228 @@
+//**********************************************************************
+// File name: ICF.CPP
+//
+// Implementation file for the CClassFactory Class
+//
+// Functions:
+//
+// See icf.h for a list of member functions.
+//
+// Copyright (c) 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+
+#include "pre.h"
+#include "app.h"
+#include "doc.h"
+#include "icf.h"
+
+//**********************************************************************
+//
+// CClassFactory::QueryInterface
+//
+// Purpose:
+// Used for interface negotiation
+//
+// Parameters:
+//
+// REFIID riid - Interface being queried for.
+//
+// LPVOID FAR *ppvObj - Out pointer for the interface.
+//
+// Return Value:
+//
+// S_OK - Success
+// E_NOINTERFACE - Failure
+//
+// Function Calls:
+// Function Location
+//
+// CClassFactory::AddRef ICF.CPP
+//
+//********************************************************************
+
+STDMETHODIMP CClassFactory::QueryInterface ( REFIID riid, LPVOID FAR* ppvObj)
+{
+ TestDebugOut(TEXT("In CClassFactory::QueryInterface\r\n"));
+
+ SCODE sc = S_OK;
+
+ if (IsEqualIID(riid, IID_IUnknown) ||
+ IsEqualIID(riid, IID_IClassFactory) )
+ *ppvObj = this;
+ else
+ {
+ *ppvObj = NULL;
+ sc = E_NOINTERFACE;
+ }
+
+ if (*ppvObj)
+ ((LPUNKNOWN)*ppvObj)->AddRef();
+
+ // pass it on to the Application object
+ return ResultFromScode(sc);
+}
+
+//**********************************************************************
+//
+// CClassFactory::AddRef
+//
+// Purpose:
+//
+// Increments the reference count on CClassFactory and the application
+// object.
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// The Reference count on CClassFactory
+//
+// Function Calls:
+// Function Location
+//
+// OuputDebugString Windows API
+//
+//********************************************************************
+
+
+STDMETHODIMP_(ULONG) CClassFactory::AddRef ()
+{
+ TestDebugOut(TEXT("In CClassFactory::AddRef\r\n"));
+
+ return ++m_nCount;
+}
+
+//**********************************************************************
+//
+// CClassFactory::Release
+//
+// Purpose:
+//
+// Decrements the reference count of CClassFactory and the
+// application object.
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// The new reference count
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+//********************************************************************
+
+
+STDMETHODIMP_(ULONG) CClassFactory::Release ()
+{
+ TestDebugOut(TEXT("In CClassFactory::Release\r\n"));
+
+ if (--m_nCount== 0)
+ {
+ delete this;
+ return(0);
+ }
+ return m_nCount;
+}
+
+
+//**********************************************************************
+//
+// CClassFactory::CreateInstance
+//
+// Purpose:
+//
+// Instantiates a new OLE object
+//
+// Parameters:
+//
+// LPUNKNOWN pUnkOuter - Pointer to the controlling unknown
+//
+// REFIID riid - The interface type to fill in ppvObject
+//
+// LPVOID FAR* ppvObject - Out pointer for the object
+//
+// Return Value:
+//
+// S_OK - Creation was successful
+// CLASS_E_NOAGGREGATION - Tried to be created as part of an aggregate
+//
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// CSimpSvrDoc::CreateObject DOC.CPP
+//
+//********************************************************************
+
+STDMETHODIMP CClassFactory::CreateInstance ( LPUNKNOWN pUnkOuter,
+ REFIID riid,
+ LPVOID FAR* ppvObject)
+{
+ HRESULT hErr;
+
+ TestDebugOut(TEXT("In CClassFactory::CreateInstance\r\n"));
+
+ // need to NULL the out parameter
+ *ppvObject = NULL;
+
+ // we don't support aggregation...
+ if (pUnkOuter)
+ {
+ hErr = ResultFromScode(CLASS_E_NOAGGREGATION);
+ goto error;
+ }
+
+ hErr = m_lpApp->m_lpDoc->CreateObject(riid, ppvObject);
+
+error:
+ return hErr;
+}
+
+//**********************************************************************
+//
+// CClassFactory::LockServer
+//
+// Purpose:
+// To lock the server and keep an open object application in memory
+//
+// Parameters:
+//
+// BOOL fLock - TRUE to lock the server, FALSE to unlock it
+//
+// Return Value:
+//
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// CoLockObjectExternal OLE API
+// ResultFromScode OLE API
+//
+//
+//********************************************************************
+
+STDMETHODIMP CClassFactory::LockServer ( BOOL fLock)
+{
+ HRESULT hRes;
+
+ TestDebugOut(TEXT("In CClassFactory::LockServer\r\n"));
+
+ if ((hRes=CoLockObjectExternal(m_lpApp, fLock, TRUE)) != S_OK)
+ {
+ TestDebugOut(TEXT("CClassFactory::LockServer \
+ CoLockObjectExternal fails\n"));
+ return(hRes);
+ }
+
+ return ResultFromScode( S_OK);
+}
diff --git a/private/oleutest/simpsvr/icf.h b/private/oleutest/simpsvr/icf.h
new file mode 100644
index 000000000..302428d8e
--- /dev/null
+++ b/private/oleutest/simpsvr/icf.h
@@ -0,0 +1,46 @@
+//**********************************************************************
+// File name: icf.h
+//
+// Definition of CClassFactory
+//
+// Copyright (c) 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+
+#if !defined( _ICF_H_)
+#define _ICF_H_
+
+class CSimpSvrApp;
+
+interface CClassFactory : IClassFactory
+{
+private:
+ int m_nCount; // reference count
+ CSimpSvrApp FAR * m_lpApp;
+
+public:
+ CClassFactory::CClassFactory(CSimpSvrApp FAR * lpApp)
+ {
+ TestDebugOut(TEXT("In CClassFactory's Constructor\r\n"));
+ m_lpApp = lpApp;
+ m_nCount = 0;
+ };
+ CClassFactory::~CClassFactory()
+ {
+ TestDebugOut(TEXT("In CClassFactory's Destructor\r\n"));
+ };
+
+ // IUnknown Methods
+
+ STDMETHODIMP QueryInterface (REFIID riid, LPVOID FAR* ppvObj);
+ STDMETHODIMP_(ULONG) AddRef ();
+ STDMETHODIMP_(ULONG) Release ();
+
+ STDMETHODIMP CreateInstance (LPUNKNOWN pUnkOuter,
+ REFIID riid,
+ LPVOID FAR* ppvObject);
+ STDMETHODIMP LockServer ( BOOL fLock);
+
+};
+
+#endif
+
diff --git a/private/oleutest/simpsvr/ido.cpp b/private/oleutest/simpsvr/ido.cpp
new file mode 100644
index 000000000..bed297507
--- /dev/null
+++ b/private/oleutest/simpsvr/ido.cpp
@@ -0,0 +1,529 @@
+//**********************************************************************
+// File name: IDO.CPP
+//
+// Implementation file for the CDataObject Class
+//
+// Functions:
+//
+// See ido.h for a list of member functions.
+//
+// Copyright (c) 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+
+#include "pre.h"
+#include "obj.h"
+#include "ido.h"
+#include "app.h"
+#include "doc.h"
+
+//**********************************************************************
+//
+// CDataObject::QueryInterface
+//
+// Purpose:
+// Used for interface negotiation
+//
+// Parameters:
+//
+// REFIID riid - Interface being queried for.
+//
+// LPVOID FAR *ppvObj - Out pointer for the interface.
+//
+// Return Value:
+//
+// S_OK - Success
+// E_NOINTERFACE - Failure
+//
+// Function Calls:
+// Function Location
+//
+// CSimpSvrObj::QueryInterface OBJ.CPP
+//
+//********************************************************************
+
+
+STDMETHODIMP CDataObject::QueryInterface ( REFIID riid, LPVOID FAR* ppvObj)
+{
+ TestDebugOut(TEXT("In CDataObject::QueryInterface\r\n"));
+
+ return m_lpObj->QueryInterface(riid, ppvObj);
+}
+
+//**********************************************************************
+//
+// CDataObject::AddRef
+//
+// Purpose:
+//
+// Increments the reference count on CSimpSvrObj. CDataObject is
+// a nested class of CSimpSvrObj, so we don't need a separate
+// reference count for CDataObject. We can just use the reference
+// count of CSimpSvrObj.
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// The new Reference count on CSimpSvrObject
+//
+// Function Calls:
+// Function Location
+//
+// OuputDebugString Windows API
+// CSimpSvrObj::AddRef OBJ.CPP
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) CDataObject::AddRef ()
+{
+ TestDebugOut(TEXT("In CDataObject::AddRef\r\n"));
+
+ return( m_lpObj->AddRef() );
+}
+
+//**********************************************************************
+//
+// CDataObject::Release
+//
+// Purpose:
+//
+// Decrements the reference count on CSimpSvrObj. CDataObject is
+// a nested class of CSimpSvrObj, so we don't need a separate
+// reference count for CDataObject. We can just use the reference
+// count of CSimpSvrObj.
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// The new reference count of the CSimpSvrObj.
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// CSimpSvrObj::Release OBJ.CPP
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) CDataObject::Release ()
+{
+ TestDebugOut(TEXT("In CDataObject::Release\r\n"));
+
+ return( m_lpObj->Release() );
+}
+
+//**********************************************************************
+//
+// CDataObject::QueryGetData
+//
+// Purpose:
+//
+// Called to determine if our object supports a particular
+// FORMATETC.
+//
+// Parameters:
+//
+// LPFORMATETC pformatetc - Pointer to the FORMATETC being queried for.
+//
+// Return Value:
+//
+// DATA_E_FORMATETC - The FORMATETC is not supported
+// S_OK - The FORMATETC is supported.
+//
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// ResultFromScode OLE API
+//
+//********************************************************************
+
+
+STDMETHODIMP CDataObject::QueryGetData ( LPFORMATETC pformatetc )
+{
+ SCODE sc = DATA_E_FORMATETC;
+
+ TestDebugOut(TEXT("In CDataObject::QueryGetData\r\n"));
+
+ // check the validity of the formatetc.
+ if ( (pformatetc->cfFormat == CF_METAFILEPICT) &&
+ (pformatetc->dwAspect == DVASPECT_CONTENT) &&
+ (pformatetc->tymed == TYMED_MFPICT) )
+ sc = S_OK;
+
+ return ResultFromScode(sc);
+}
+
+//**********************************************************************
+//
+// CDataObject::DAdvise
+//
+// Purpose:
+//
+// Called by the container when it would like to be notified of
+// changes in the object data.
+//
+// Parameters:
+//
+// FORMATETC FAR* pFormatetc - The format the container is interested in.
+//
+// DWORD advf - The type of advise to be set up.
+//
+// LPADVISESINK pAdvSink - Pointer to the containers IAdviseSink
+//
+// DWORD FAR* pdwConnection - Out parameter to return a unique connection id.
+//
+// Return Value:
+//
+// passed on from IDataAdviseHolder
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// CreateDataAdviseHolder OLE API
+// IDataAdviseHolder::Advise OLE API
+//
+//
+//********************************************************************
+
+
+STDMETHODIMP CDataObject::DAdvise ( FORMATETC FAR* pFormatetc, DWORD advf,
+ LPADVISESINK pAdvSink, DWORD FAR* pdwConnection)
+{
+ HRESULT hRes;
+
+ TestDebugOut(TEXT("In CDataObject::DAdvise\r\n"));
+
+ // if no DataAdviseHolder has been created, then create one.
+ if (!m_lpObj->m_lpDataAdviseHolder)
+ {
+ hRes=CreateDataAdviseHolder(&m_lpObj->m_lpDataAdviseHolder);
+ if (hRes != S_OK)
+ {
+ TestDebugOut(TEXT("CDataObject::DAdvise \
+ cannot CreateDataAdviseHolder\n"));
+ return(hRes);
+ }
+ }
+
+ // pass on to the DataAdviseHolder
+ return m_lpObj->m_lpDataAdviseHolder->Advise( this, pFormatetc, advf,
+ pAdvSink, pdwConnection);
+}
+
+//**********************************************************************
+//
+// CDataObject::GetData
+//
+// Purpose:
+//
+// Returns the data in the format specified in pformatetcIn.
+//
+// Parameters:
+//
+// LPFORMATETC pformatetcIn - The format requested by the caller
+//
+// LPSTGMEDIUM pmedium - The medium requested by the caller
+//
+// Return Value:
+//
+// DATA_E_FORMATETC - Format not supported
+// S_OK - Success
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// CSimpSvrObj::GetMetaFilePict() OBJ.CPP
+// ResultFromScode OLE API
+//
+//********************************************************************
+
+STDMETHODIMP CDataObject::GetData ( LPFORMATETC pformatetcIn, LPSTGMEDIUM pmedium )
+{
+ SCODE sc = DATA_E_FORMATETC;
+
+ TestDebugOut(TEXT("In CDataObject::GetData\r\n"));
+
+ // Check to the FORMATETC and fill pmedium if valid.
+ if ( (pformatetcIn->cfFormat == CF_METAFILEPICT) &&
+ (pformatetcIn->dwAspect == DVASPECT_CONTENT) &&
+ (pformatetcIn->tymed & TYMED_MFPICT) )
+ {
+ HANDLE hmfPict = m_lpObj->GetMetaFilePict();
+ pmedium->tymed = TYMED_MFPICT;
+ pmedium->hGlobal = hmfPict;
+ pmedium->pUnkForRelease = NULL;
+ sc = S_OK;
+ }
+
+ return ResultFromScode( sc );
+}
+
+//**********************************************************************
+//
+// CDataObject::DUnadvise
+//
+// Purpose:
+//
+// Breaks down an Advise connection.
+//
+// Parameters:
+//
+// DWORD dwConnection - Advise connection ID.
+//
+// Return Value:
+//
+// Returned from the DataAdviseHolder.
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// IDataAdviseHolder::Unadvise OLE
+//
+//********************************************************************
+
+STDMETHODIMP CDataObject::DUnadvise ( DWORD dwConnection)
+{
+ TestDebugOut(TEXT("In CDataObject::DUnadvise\r\n"));
+
+ return m_lpObj->m_lpDataAdviseHolder->Unadvise(dwConnection);
+}
+
+//**********************************************************************
+//
+// CDataObject::GetDataHere
+//
+// Purpose:
+//
+// Called to get a data format in a caller supplied location
+//
+// Parameters:
+//
+// LPFORMATETC pformatetc - FORMATETC requested
+//
+// LPSTGMEDIUM pmedium - Medium to return the data
+//
+// Return Value:
+//
+// DATA_E_FORMATETC - We don't support the requested format
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+// Comments:
+//
+// In this simple implementation, we don't really support this
+// method, we just always return DATA_E_FORMATETC.
+//
+//********************************************************************
+
+
+STDMETHODIMP CDataObject::GetDataHere ( LPFORMATETC pformatetc,
+ LPSTGMEDIUM pmedium )
+{
+ TestDebugOut(TEXT("In CDataObject::GetDataHere\r\n"));
+ return ResultFromScode( DATA_E_FORMATETC);
+}
+
+//**********************************************************************
+//
+// CDataObject::GetCanonicalFormatEtc
+//
+// Purpose:
+//
+// Returns a FORMATETC that is equivalent to the one passed in.
+//
+// Parameters:
+//
+// LPFORMATETC pformatetc - FORMATETC to be tested.
+//
+// LPFORMATETC pformatetcOut - Out ptr for returned FORMATETC.
+//
+// Return Value:
+//
+// DATA_S_SAMEFORMATETC - Use the same formatetc as was passed.
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// CoGetMalloc OLE API
+// IMalloc::Alloc OLE
+// IMalloc::Release OLE
+// _fmemcpy C run-time
+//
+//********************************************************************
+
+
+STDMETHODIMP CDataObject::GetCanonicalFormatEtc ( LPFORMATETC pformatetc,
+ LPFORMATETC pformatetcOut)
+{
+ HRESULT hresult;
+ TestDebugOut(TEXT("In CDataObject::GetCanonicalFormatEtc\r\n"));
+
+ if (!pformatetcOut)
+ return ResultFromScode(E_INVALIDARG);
+
+ /* OLE2NOTE: we must make sure to set all out parameters to NULL. */
+ pformatetcOut->ptd = NULL;
+
+ if (!pformatetc)
+ return ResultFromScode(E_INVALIDARG);
+
+ // OLE2NOTE: we must validate that the format requested is supported
+ if ((hresult = QueryGetData(pformatetc)) != NOERROR)
+ return hresult;
+
+ /* OLE2NOTE: an app that is insensitive to target device (as
+ ** SimpSvr 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.
+ */
+
+ *pformatetcOut = *pformatetc;
+ if (pformatetc->ptd == NULL)
+ return ResultFromScode(DATA_S_SAMEFORMATETC);
+ else
+ {
+ pformatetcOut->ptd = NULL;
+ return NOERROR;
+ }
+}
+
+//**********************************************************************
+//
+// CDataObject::SetData
+//
+// Purpose:
+//
+// Called to set the data for the object.
+//
+// Parameters:
+//
+// LPFORMATETC pformatetc - the format of the data being passed
+//
+// STGMEDIUM FAR * pmedium - the location of the data.
+//
+// BOOL fRelease - Defines the ownership of the medium
+//
+// Return Value:
+//
+// DATA_E_FORMATETC - Not a valid FORMATETC for this object
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+// Comments:
+//
+// This simple object does not support having its data set, so an
+// error value is always returned.
+//
+//********************************************************************
+
+
+STDMETHODIMP CDataObject::SetData ( LPFORMATETC pformatetc, STGMEDIUM FAR * pmedium,
+ BOOL fRelease)
+{
+ TestDebugOut(TEXT("In CDataObject::SetData\r\n"));
+ return ResultFromScode( DATA_E_FORMATETC );
+}
+
+//**********************************************************************
+//
+// CDataObject::EnumFormatEtc
+//
+// Purpose:
+//
+// Enumerates the formats supported by this object.
+//
+// Parameters:
+//
+// DWORD dwDirection - Order of enumeration.
+//
+// LPENUMFORMATETC FAR* ppenumFormatEtc - Place to return a pointer
+// to the enumerator.
+//
+// Return Value:
+//
+// OLE_S_USEREG - Indicates that OLE should consult the REG DB
+// to enumerate the formats.
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+// Comments:
+//
+// This simple implementation just returns OLE_SUSEREG
+//
+//********************************************************************
+
+
+STDMETHODIMP CDataObject::EnumFormatEtc ( DWORD dwDirection,
+ LPENUMFORMATETC FAR* ppenumFormatEtc)
+{
+ TestDebugOut(TEXT("In CDataObject::EnumFormatEtc\r\n"));
+ // need to NULL the out parameter
+ *ppenumFormatEtc = NULL;
+ return ResultFromScode( OLE_S_USEREG );
+}
+
+//**********************************************************************
+//
+// CDataObject::EnumDAdvise
+//
+// Purpose:
+//
+// Returns an enumerator that enumerates all of the advises
+// set up on this data object.
+//
+// Parameters:
+//
+// LPENUMSTATDATA FAR* ppenumAdvise - An out ptr in which to
+// return the enumerator.
+//
+// Return Value:
+//
+// Passed back from IDataAdviseHolder::EnumAdvise
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// IDAtaAdviseHolder::EnumAdvise OLE
+//
+// Comments:
+//
+// This just delegates to the DataAdviseHolder.
+//
+//********************************************************************
+
+
+STDMETHODIMP CDataObject::EnumDAdvise ( LPENUMSTATDATA FAR* ppenumAdvise)
+{
+ TestDebugOut(TEXT("In CDataObject::EnumDAdvise\r\n"));
+ // need to NULL the out parameter
+ *ppenumAdvise = NULL;
+
+ return m_lpObj->m_lpDataAdviseHolder->EnumAdvise(ppenumAdvise);
+}
+
+
diff --git a/private/oleutest/simpsvr/ido.h b/private/oleutest/simpsvr/ido.h
new file mode 100644
index 000000000..be46b1ecf
--- /dev/null
+++ b/private/oleutest/simpsvr/ido.h
@@ -0,0 +1,51 @@
+//**********************************************************************
+// File name: ido.h
+//
+// Definition of CDataObject
+//
+// Copyright (c) 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+#if !defined( _IDO_H_)
+#define _IDO_H_
+
+
+#include <ole2.h>
+#include "obj.h"
+
+class CSimpSvrObj;
+
+interface CDataObject : public IDataObject
+{
+private:
+ CSimpSvrObj FAR * m_lpObj;
+
+public:
+ CDataObject::CDataObject(CSimpSvrObj FAR * lpSimpSvrObj)
+ {
+ m_lpObj = lpSimpSvrObj;
+ };
+
+ CDataObject::~CDataObject() {};
+
+ STDMETHODIMP QueryInterface (REFIID riid, LPVOID FAR* ppvObj);
+ STDMETHODIMP_(ULONG) AddRef ();
+ STDMETHODIMP_(ULONG) Release ();
+
+ STDMETHODIMP DAdvise ( FORMATETC FAR* pFormatetc, DWORD advf,
+ LPADVISESINK pAdvSink, DWORD FAR* pdwConnection);
+ STDMETHODIMP DUnadvise ( DWORD dwConnection);
+ STDMETHODIMP EnumDAdvise ( LPENUMSTATDATA FAR* ppenumAdvise);
+ STDMETHODIMP EnumFormatEtc ( DWORD dwDirection,
+ LPENUMFORMATETC FAR* ppenumFormatEtc);
+ STDMETHODIMP GetCanonicalFormatEtc ( LPFORMATETC pformatetc,
+ LPFORMATETC pformatetcOut);
+ STDMETHODIMP GetData ( LPFORMATETC pformatetcIn, LPSTGMEDIUM pmedium );
+ STDMETHODIMP GetDataHere ( LPFORMATETC pformatetc, LPSTGMEDIUM pmedium );
+ STDMETHODIMP QueryGetData ( LPFORMATETC pformatetc );
+ STDMETHODIMP SetData ( LPFORMATETC pformatetc, STGMEDIUM FAR * pmedium,
+ BOOL fRelease);
+
+
+};
+
+#endif
diff --git a/private/oleutest/simpsvr/iec.cpp b/private/oleutest/simpsvr/iec.cpp
new file mode 100644
index 000000000..0a53df994
--- /dev/null
+++ b/private/oleutest/simpsvr/iec.cpp
@@ -0,0 +1,197 @@
+//**********************************************************************
+// File name: IEC.CPP
+//
+// Implementation file for the CExternalConnection Class
+//
+// Functions:
+//
+// See iec.h for a list of member functions.
+//
+// Copyright (c) 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+
+#include "pre.h"
+#include "obj.h"
+#include "iec.h"
+#include "app.h"
+#include "doc.h"
+
+//**********************************************************************
+//
+// CExternalConnection::QueryInterface
+//
+// Purpose:
+// Used for interface negotiation
+//
+// Parameters:
+//
+// REFIID riid - Interface being queried for.
+//
+// LPVOID FAR *ppvObj - Out pointer for the interface.
+//
+// Return Value:
+//
+// S_OK - Success
+// E_NOINTERFACE - Failure
+//
+// Function Calls:
+// Function Location
+//
+// CSimpSvrObj::QueryInterface OBJ.CPP
+//
+//********************************************************************
+
+STDMETHODIMP CExternalConnection::QueryInterface (REFIID riid, LPVOID FAR* ppvObj)
+{
+ TestDebugOut(TEXT("In CExternalConnection::QueryInterface\r\n"));
+
+ return m_lpObj->QueryInterface(riid, ppvObj);
+}
+
+//**********************************************************************
+//
+// CExternalConnection::AddRef
+//
+// Purpose:
+//
+// Increments the reference count on CSimpSvrObj object. Since
+// CExternalConnection is a nested class of CSimpSvrObj, we don't
+// need a separate reference count for CExternalConnection. We
+// can just use the reference count of CSimpSvrObj.
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// The new reference count of the CSimpSvrObj
+//
+// Function Calls:
+// Function Location
+//
+// OuputDebugString Windows API
+// CSimpSvrObj::AddRef OBJ.CPP
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) CExternalConnection::AddRef ()
+{
+ TestDebugOut(TEXT("In CExternalConnection::AddRef\r\n"));
+
+ return( m_lpObj->AddRef() );
+}
+
+//**********************************************************************
+//
+// CExternalConnection::Release
+//
+// Purpose:
+//
+// Decrements the reference count on CSimpSvrObj object. Since
+// CExternalConnection is a nested class of CSimpSvrObj, we don't
+// need a separate reference count for CExternalConnection. We
+// can just use the reference count of CSimpSvrObj.
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// The new reference count of CSimpSvrObj
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// CSimpSvrObj::Release OBJ.CPP
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) CExternalConnection::Release ()
+{
+ TestDebugOut(TEXT("In CExternalConnection::Release\r\n"));
+
+ return m_lpObj->Release();
+}
+
+//**********************************************************************
+//
+// CExternalConnection::AddConnection
+//
+// Purpose:
+//
+// Called when another connection is made to the object.
+//
+// Parameters:
+//
+// DWORD extconn - Type of connection
+//
+// DWORD reserved - Reserved
+//
+// Return Value:
+//
+// Strong connection count
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+//********************************************************************
+
+STDMETHODIMP_(DWORD) CExternalConnection::AddConnection (DWORD extconn, DWORD reserved)
+{
+ TestDebugOut(TEXT("In CExternalConnection::AddConnection\r\n"));
+
+ if (extconn & EXTCONN_STRONG)
+ return ++m_dwStrong;
+
+ return 0;
+}
+
+//**********************************************************************
+//
+// CExternalConnection::ReleaseConnection
+//
+// Purpose:
+//
+// Called when a connection to the object is released.
+//
+// Parameters:
+//
+// DWORD extconn - Type of Connection
+//
+// DWORD reserved - Reserved
+//
+// BOOL fLastReleaseCloses - Close flag
+//
+// Return Value:
+//
+// The new reference count
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// COleObject::Close IOO.CPP
+//
+//
+//********************************************************************
+
+STDMETHODIMP_(DWORD) CExternalConnection::ReleaseConnection (DWORD extconn, DWORD reserved, BOOL fLastReleaseCloses)
+{
+ TestDebugOut(TEXT("In CExternalConnection::ReleaseConnection\r\n"));
+
+ if (extconn & EXTCONN_STRONG)
+ {
+ DWORD dwSave = --m_dwStrong;
+
+ if (!m_dwStrong && fLastReleaseCloses)
+ m_lpObj->m_OleObject.Close(OLECLOSE_SAVEIFDIRTY);
+
+ return dwSave;
+ }
+ return 0;
+}
diff --git a/private/oleutest/simpsvr/iec.h b/private/oleutest/simpsvr/iec.h
new file mode 100644
index 000000000..a54f0f1c2
--- /dev/null
+++ b/private/oleutest/simpsvr/iec.h
@@ -0,0 +1,43 @@
+//**********************************************************************
+// File name: iec.h
+//
+// Definition of CExternalConnection
+//
+// Copyright (c) 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+#if !defined( _IEC_H_)
+#define _IEC_H_
+
+
+#include <ole2.h>
+#include "obj.h"
+
+class CSimpSvrObj;
+
+interface CExternalConnection : public IExternalConnection
+{
+private:
+ CSimpSvrObj FAR * m_lpObj; // Ptr to object
+ DWORD m_dwStrong; // Connection Count
+
+public:
+ CExternalConnection::CExternalConnection(CSimpSvrObj FAR * lpSimpSvrObj)
+ {
+ m_lpObj = lpSimpSvrObj;
+ m_dwStrong = 0;
+ };
+
+ CExternalConnection::~CExternalConnection() {};
+
+ // *** IUnknown methods ***
+ STDMETHODIMP QueryInterface (REFIID riid, LPVOID FAR* ppvObj);
+ STDMETHODIMP_(ULONG) AddRef ();
+ STDMETHODIMP_(ULONG) Release ();
+
+ // *** IExternalConnection methods ***
+ STDMETHODIMP_(DWORD) AddConnection (DWORD extconn, DWORD reserved);
+ STDMETHODIMP_(DWORD) ReleaseConnection (DWORD extconn, DWORD reserved, BOOL fLastReleaseCloses);
+};
+
+#endif
+
diff --git a/private/oleutest/simpsvr/ioipao.cpp b/private/oleutest/simpsvr/ioipao.cpp
new file mode 100644
index 000000000..7ac8a5799
--- /dev/null
+++ b/private/oleutest/simpsvr/ioipao.cpp
@@ -0,0 +1,404 @@
+//**********************************************************************
+// File name: IOIPAO.CPP
+//
+// Implementation file for the CClassFactory Class
+//
+// Functions:
+//
+// See ioipao.h for a list of member functions.
+//
+// Copyright (c) 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+
+#include "pre.h"
+#include "obj.h"
+#include "ioipao.h"
+#include "app.h"
+#include "doc.h"
+
+//**********************************************************************
+//
+// COleInPlaceActiveObject::QueryInterface
+//
+// Purpose:
+// Used for interface negotiation
+//
+// Parameters:
+//
+// REFIID riid - Interface being queried for.
+//
+// LPVOID FAR *ppvObj - Out pointer for the interface.
+//
+// Return Value:
+//
+// S_OK - Success
+// E_NOINTERFACE - Failure
+//
+// Function Calls:
+// Function Location
+//
+// CSimpSvrObj::QueryInterface OBJ.CPP
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleInPlaceActiveObject::QueryInterface ( REFIID riid, LPVOID FAR* ppvObj)
+{
+ TestDebugOut(TEXT("In COleInPlaceActiveObject::QueryInterface\r\n"));
+ // need to NULL the out parameter
+ return m_lpObj->QueryInterface(riid, ppvObj);
+}
+
+//**********************************************************************
+//
+// COleInPlaceActiveObject::AddRef
+//
+// Purpose:
+//
+// Increments the reference count on CSimpSvrObj. Since
+// COleInPlaceActiveObject is a nested class of CSimpSvrObj, we don't
+// need a separate reference count for COleInPlaceActiveObject. We
+// can use the reference count of CSimpSvrObj.
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// The new reference count on the CSimpSvrObj
+//
+// Function Calls:
+// Function Location
+//
+// OuputDebugString Windows API
+// CSimpSvrObj::AddRef OBJ.CPP
+//
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) COleInPlaceActiveObject::AddRef ()
+{
+ TestDebugOut(TEXT("In COleInPlaceActiveObject::AddRef\r\n"));
+
+ return m_lpObj->AddRef();
+}
+
+//**********************************************************************
+//
+// COleInPlaceActiveObject::Release
+//
+// Purpose:
+//
+// Decrements the reference count on CSimpSvrObj. Since
+// COleInPlaceActiveObject is a nested class of CSimpSvrObj, we don't
+// need a separate reference count for COleInPlaceActiveObject. We
+// can use the reference count of CSimpSvrObj.
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// The new reference count
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// CSimpSvrObj::Release OBJ.CPP
+//
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) COleInPlaceActiveObject::Release ()
+{
+ TestDebugOut(TEXT("In COleInPlaceActiveObject::Release\r\n"));
+
+ return m_lpObj->Release();
+}
+
+//**********************************************************************
+//
+// COleInPlaceActiveObject::OnDocWindowActivate
+//
+// Purpose:
+//
+// Called when the doc window (in an MDI App) is (de)activated.
+//
+// Parameters:
+//
+// BOOL fActivate - TRUE if activating, FALSE if deactivating
+//
+// Return Value:
+//
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// IOleInPlaceFrame::SetActiveObject Container
+// CSimpSvrObject::AddFrameLevelUI OBJ.CPP
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleInPlaceActiveObject::OnDocWindowActivate ( BOOL fActivate )
+{
+ TestDebugOut(TEXT("In COleInPlaceActiveObject::OnDocWindowActivate\r\n"));
+
+ // Activating?
+ if (fActivate)
+ m_lpObj->AddFrameLevelUI();
+
+ // No frame level tools to remove...
+
+ return ResultFromScode(S_OK);
+}
+
+//**********************************************************************
+//
+// COleInPlaceActiveObject::OnFrameWindowActivate
+//
+// Purpose:
+//
+// Called when the Frame window is (de)activating
+//
+// Parameters:
+//
+// BOOL fActivate - TRUE if activating, FALSE if Deactivating
+//
+// Return Value:
+//
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// SetFocus Windows API
+//
+//
+// Comments:
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleInPlaceActiveObject::OnFrameWindowActivate ( BOOL fActivate)
+{
+ TestDebugOut(TEXT("In COleInPlaceActiveObject::OnFrameWindowActivate\r\n"));
+
+ // set the focus to the object window if we are activating.
+/* if (fActivate)
+ SetFocus(m_lpObj->m_lpDoc->GethDocWnd()); */
+
+ return ResultFromScode( S_OK );
+}
+
+//**********************************************************************
+//
+// COleInPlaceActiveObject::GetWindow
+//
+// Purpose:
+//
+// Gets the objects Window Handle.
+//
+// Parameters:
+//
+// HWND FAR* lphwnd - Location to return the window handle.
+//
+// Return Value:
+//
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// CSimpSvrDoc::GethDocWnd DOC.H
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleInPlaceActiveObject::GetWindow ( HWND FAR* lphwnd)
+{
+ TestDebugOut(TEXT("In COleInPlaceActiveObject::GetWindow\r\n"));
+ // need to NULL the out parameter
+ *lphwnd = m_lpObj->m_lpDoc->GethDocWnd();
+ return ResultFromScode( S_OK );
+}
+
+//**********************************************************************
+//
+// COleInPlaceActiveObject::ContextSensitiveHelp
+//
+// Purpose:
+//
+// Used to implement Context Sensitive help
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// E_NOTIMPL
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+//
+// Comments:
+//
+// See TECHNOTES.WRI include with the OLE SDK for proper
+// implementation of this function.
+//
+//********************************************************************
+
+STDMETHODIMP COleInPlaceActiveObject::ContextSensitiveHelp ( BOOL fEnterMode )
+{
+ TestDebugOut(TEXT("In COleInPlaceActiveObject::ContextSensitiveHelp\r\n"));
+ return ResultFromScode( E_NOTIMPL);
+}
+
+//**********************************************************************
+//
+// COleInPlaceActiveObject::TranslateAccelerator
+//
+// Purpose:
+//
+// Used for translating accelerators in .DLL objects.
+//
+// Parameters:
+//
+// LPMSG lpmsg - Pointer to a message
+//
+// Return Value:
+//
+// S_FALSE
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+//
+// Comments:
+//
+// This method should never be called since we are implemented
+// in an executable.
+//
+//********************************************************************
+
+STDMETHODIMP COleInPlaceActiveObject::TranslateAccelerator ( LPMSG lpmsg)
+{
+ TestDebugOut(TEXT("In COleInPlaceActiveObject::TranslateAccelerator\r\n"));
+ // no accelerator table, return FALSE
+ return ResultFromScode( S_FALSE );
+}
+
+//**********************************************************************
+//
+// COleInPlaceActiveObject::ResizeBorder
+//
+// Purpose:
+//
+// Called when the border changes size.
+//
+// Parameters:
+//
+// LPCRECT lprectBorder - New Border
+//
+// LPOLEINPLACEUIWINDOW lpUIWindow - Pointer to UIWindow
+//
+// BOOL fFrameWindow - True if lpUIWindow is the
+// frame window.
+//
+// Return Value:
+//
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+//
+// Comments:
+//
+// Need to call SetBorderSpace again...
+//
+//********************************************************************
+
+STDMETHODIMP COleInPlaceActiveObject::ResizeBorder ( LPCRECT lprectBorder,
+ LPOLEINPLACEUIWINDOW lpUIWindow,
+ BOOL fFrameWindow)
+{
+ HRESULT hRes;
+
+ TestDebugOut(TEXT("In COleInPlaceActiveObject::ResizeBorder\r\n"));
+
+ // should always have an inplace frame...
+ if ((hRes=m_lpObj->GetInPlaceFrame()->SetBorderSpace(NULL)) != S_OK)
+ {
+ TestDebugOut(TEXT("COleInPlaceActiveObject::ResizeBorder \
+ SetBorderSpace fails\n"));
+ return(hRes);
+ }
+
+
+ // There will only be a UIWindow if in an MDI container
+ if (m_lpObj->GetUIWindow())
+ {
+ if((hRes=m_lpObj->GetUIWindow()->SetBorderSpace(NULL)) != S_OK)
+ {
+ TestDebugOut(TEXT("COleInPlaceActiveObject::ResizeBorder \
+ SetBorderSpace fails\n"));
+ return(hRes);
+ }
+ }
+
+ return ResultFromScode( S_OK );
+}
+
+//**********************************************************************
+//
+// COleInPlaceActiveObject::EnableModeless
+//
+// Purpose:
+//
+// Called to enable/disable modeless dialogs.
+//
+// Parameters:
+//
+// BOOL fEnable - TRUE to enable, FALSE to disable
+//
+// Return Value:
+//
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+//
+// Comments:
+//
+// Called by the container when a model dialog box is added/removed
+// from the screen. The appropriate action for a server application
+// is to disable/enable any modeless dialogs currently being displayed.
+// Since this application doesn't display any modeless dialogs,
+// this method is essentially ignored.
+//
+//********************************************************************
+
+STDMETHODIMP COleInPlaceActiveObject::EnableModeless ( BOOL fEnable)
+{
+ TestDebugOut(TEXT("In COleInPlaceActiveObject::EnableModeless\r\n"));
+ return ResultFromScode( S_OK );
+}
diff --git a/private/oleutest/simpsvr/ioipao.h b/private/oleutest/simpsvr/ioipao.h
new file mode 100644
index 000000000..d064e8a9e
--- /dev/null
+++ b/private/oleutest/simpsvr/ioipao.h
@@ -0,0 +1,48 @@
+//**********************************************************************
+// File name: IOIPAO.H
+//
+// Definition of COleInPlaceActiveObject
+//
+// Copyright (c) 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+
+#if !defined( _IOIPAO_H_)
+#define _IOIPAO_H_
+
+
+#include <ole2.h>
+#include "obj.h"
+
+class CSimpSvrObj;
+
+interface COleInPlaceActiveObject : public IOleInPlaceActiveObject
+{
+private:
+ CSimpSvrObj FAR * m_lpObj;
+
+public:
+ COleInPlaceActiveObject::COleInPlaceActiveObject(CSimpSvrObj FAR * lpSimpSvrObj)
+ {
+ m_lpObj = lpSimpSvrObj; // set up the back ptr
+ };
+ COleInPlaceActiveObject::~COleInPlaceActiveObject() {}; // destructor
+
+// IUnknown Methods
+
+ STDMETHODIMP QueryInterface (REFIID riid, LPVOID FAR* ppvObj);
+ STDMETHODIMP_(ULONG) AddRef ();
+ STDMETHODIMP_(ULONG) Release ();
+
+ STDMETHODIMP OnDocWindowActivate ( BOOL fActivate) ;
+ STDMETHODIMP OnFrameWindowActivate ( BOOL fActivate) ;
+ STDMETHODIMP GetWindow ( HWND FAR* lphwnd);
+ STDMETHODIMP ContextSensitiveHelp ( BOOL fEnterMode);
+ STDMETHODIMP TranslateAccelerator ( LPMSG lpmsg);
+ STDMETHODIMP ResizeBorder ( LPCRECT lprectBorder,
+ LPOLEINPLACEUIWINDOW lpUIWindow,
+ BOOL fFrameWindow);
+ STDMETHODIMP EnableModeless ( BOOL fEnable);
+
+};
+
+#endif
diff --git a/private/oleutest/simpsvr/ioipo.cpp b/private/oleutest/simpsvr/ioipo.cpp
new file mode 100644
index 000000000..c7379ab02
--- /dev/null
+++ b/private/oleutest/simpsvr/ioipo.cpp
@@ -0,0 +1,400 @@
+//**********************************************************************
+// File name: IOIPO.CPP
+//
+// Implementation file for the CClassFactory Class
+//
+// Functions:
+//
+// See ioipo.h for a list of member functions.
+//
+// Copyright (c) 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+
+#include "pre.h"
+#include "obj.h"
+#include "ioipo.h"
+#include "app.h"
+#include "doc.h"
+#include "math.h"
+
+//**********************************************************************
+//
+// COleInPlaceObject::QueryInterface
+//
+// Purpose:
+// Used for interface negotiation
+//
+// Parameters:
+//
+// REFIID riid - Interface being queried for.
+//
+// LPVOID FAR *ppvObj - Out pointer for the interface.
+//
+// Return Value:
+//
+// S_OK - Success
+// E_NOINTERFACE - Failure
+//
+// Function Calls:
+// Function Location
+//
+// CSimpSvrObj::QueryInterface OBJ.CPP
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleInPlaceObject::QueryInterface ( REFIID riid, LPVOID FAR* ppvObj)
+{
+ TestDebugOut(TEXT("In COleInPlaceObject::QueryInterface\r\n"));
+ // need to NULL the out parameter
+ *ppvObj = NULL;
+ return m_lpObj->QueryInterface(riid, ppvObj);
+}
+
+//**********************************************************************
+//
+// COleInPlaceObject::AddRef
+//
+// Purpose:
+//
+// Increments the reference count of CSimpSvrObj. Since
+// COleInPlaceObject is a nested class of CSimpSvrObj, we don't need
+// to have a separate reference count for COleInPlaceObject. We can
+// use the reference count of CSimpSvrObj.
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// The new reference count of CSimpSvrObj
+//
+// Function Calls:
+// Function Location
+//
+// OuputDebugString Windows API
+// CSimpSvrObj::AddRef OBJ.CPP
+//
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) COleInPlaceObject::AddRef ()
+{
+ TestDebugOut(TEXT("In COleInPlaceObject::AddRef\r\n"));
+ return m_lpObj->AddRef();
+}
+
+//**********************************************************************
+//
+// COleInPlaceObject::Release
+//
+// Purpose:
+//
+// Decrements the reference count of CSimpSvrObj. Since
+// COleInPlaceObject is a nested class of CSimpSvrObj, we don't need
+// to have a separate reference count for COleInPlaceObject. We can
+// use the reference count of CSimpSvrObj.
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// The new reference count of CSimpSvrObj
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// CSimpSvrObj::Release OBJ.CPP
+//
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) COleInPlaceObject::Release ()
+{
+ TestDebugOut(TEXT("In COleInPlaceObject::Release\r\n"));
+ return m_lpObj->Release();
+}
+
+//**********************************************************************
+//
+// COleInPlaceObject::InPlaceDeactivate
+//
+// Purpose:
+//
+// Called to deactivat the object
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+// NOERROR
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// IOleInPlaceSite::OnInPlaceDeactivate Container
+// IOleInPlaceSite::Release Container
+// CSimpSvrObj::DeactivateUI OBJ.CPP
+// CSimpSvrObj::DoInPlaceHide OBJ.CPP
+//
+//********************************************************************
+
+STDMETHODIMP COleInPlaceObject::InPlaceDeactivate()
+{
+ TestDebugOut(TEXT("In COleInPlaceObject::InPlaceDeactivate\r\n"));
+
+ // if not inplace active, return NOERROR
+ if (!m_lpObj->m_fInPlaceActive)
+ return NOERROR;
+
+ // clear inplace flag
+ m_lpObj->m_fInPlaceActive = FALSE;
+
+ // deactivate the UI
+ m_lpObj->DeactivateUI();
+ m_lpObj->DoInPlaceHide();
+
+ // tell the container that we are deactivating.
+ if (m_lpObj->m_lpIPSite)
+ {
+ HRESULT hRes;
+ if ((hRes=m_lpObj->m_lpIPSite->OnInPlaceDeactivate()) != S_OK)
+ {
+ TestDebugOut(TEXT("COleInPlaceObject::InPlaceDeactivate \
+ OnInPlaceDeactivate fails\n"));
+ }
+ m_lpObj->m_lpIPSite->Release();
+ m_lpObj->m_lpIPSite =NULL;
+ }
+
+ return ResultFromScode(S_OK);
+}
+
+//**********************************************************************
+//
+// COleInPlaceObject::UIDeactivate
+//
+// Purpose:
+//
+// Instructs us to remove our UI.
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// CSimpSvrObj::DeactivateUI OBJ.CPP
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleInPlaceObject::UIDeactivate()
+{
+ TestDebugOut(TEXT("In COleInPlaceObject::UIDeactivate\r\n"));
+
+ m_lpObj->DeactivateUI();
+
+ return ResultFromScode (S_OK);
+}
+
+//**********************************************************************
+//
+// COleInPlaceObject::SetObjectRects
+//
+// Purpose:
+//
+// Called when the container clipping region or the object position
+// changes.
+//
+// Parameters:
+//
+// LPCRECT lprcPosRect - New Position Rect.
+//
+// LPCRECT lprcClipRect - New Clipping Rect.
+//
+// Return Value:
+//
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// IntersectRect Windows API
+// OffsetRect Windows API
+// CopyRect Windows API
+// MoveWindow Windows API
+// CSimpSvrDoc::GethHatchWnd DOC.H
+// CSimpSvrDoc::gethDocWnd DOC.h
+// SetHatchWindowSize OLE2UI
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleInPlaceObject::SetObjectRects ( LPCRECT lprcPosRect, LPCRECT lprcClipRect)
+{
+ TestDebugOut(TEXT("In COleInPlaceObject::SetObjectRects\r\n"));
+
+ RECT resRect;
+ POINT pt;
+
+ // Get the intersection of the clipping rect and the position rect.
+ IntersectRect(&resRect, lprcPosRect, lprcClipRect);
+
+ m_lpObj->m_xOffset = abs (resRect.left - lprcPosRect->left);
+ m_lpObj->m_yOffset = abs (resRect.top - lprcPosRect->top);
+
+ m_lpObj->m_scale = (float)(lprcPosRect->right - lprcPosRect->left)/m_lpObj->m_size.x;
+
+ if (m_lpObj->m_scale == 0)
+ m_lpObj->m_scale = 1.0F;
+
+ TCHAR szBuffer[255];
+
+ wsprintf(szBuffer, TEXT("New Scale %3d\r\n"), m_lpObj->m_scale);
+
+ TestDebugOut(szBuffer);
+
+ // Adjust the size of the Hatch Window.
+ SetHatchWindowSize(m_lpObj->m_lpDoc->GethHatchWnd(),(LPRECT) lprcPosRect, (LPRECT) lprcClipRect, &pt);
+
+ // offset the rect
+ OffsetRect(&resRect, pt.x, pt.y);
+
+ CopyRect(&m_lpObj->m_posRect, lprcPosRect);
+
+ // Move the actual object window
+ MoveWindow(m_lpObj->m_lpDoc->GethDocWnd(),
+ resRect.left,
+ resRect.top,
+ resRect.right - resRect.left,
+ resRect.bottom - resRect.top,
+ TRUE);
+
+
+ return ResultFromScode( S_OK );
+}
+
+//**********************************************************************
+//
+// COleInPlaceObject::GetWindow
+//
+// Purpose:
+//
+// Returns the Window handle of the inplace object
+//
+// Parameters:
+//
+// HWND FAR* lphwnd - Out pointer in which to return the window
+// Handle.
+//
+// Return Value:
+//
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// CSimpleDoc::GethDocWnd DOC.H
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleInPlaceObject::GetWindow ( HWND FAR* lphwnd)
+{
+ TestDebugOut(TEXT("In COleInPlaceObject::GetWindow\r\n"));
+ *lphwnd = m_lpObj->m_lpDoc->GethDocWnd();
+
+ return ResultFromScode( S_OK );
+}
+
+//**********************************************************************
+//
+// COleInPlaceObject::ContextSensitiveHelp
+//
+// Purpose:
+//
+// Used in performing Context Sensitive Help
+//
+// Parameters:
+//
+// BOOL fEnterMode - Flag to determine if enter or exiting
+// Context Sensitive Help.
+//
+// Return Value:
+//
+// E_NOTIMPL
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+// Comments:
+//
+// This function is not implemented due to the fact that it is
+// beyond the scope of a simple object. All *real* applications
+// are going to want to implement this function, otherwise any
+// container that supports context sensitive help will not work
+// properly while the object is in place.
+//
+// See TECHNOTES.WRI include with the OLE SDK for details on
+// Implementing this method.
+//
+//********************************************************************
+
+STDMETHODIMP COleInPlaceObject::ContextSensitiveHelp ( BOOL fEnterMode)
+{
+ TestDebugOut(TEXT("In COleInPlaceObject::ContextSensitiveHelp\r\n"));
+ return ResultFromScode( E_NOTIMPL);
+}
+
+//**********************************************************************
+//
+// COleInPlaceObject::ReactivateAndUndo
+//
+// Purpose:
+//
+// Called when the container wants to undo the last edit made in
+// the object.
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// INPLACE_E_NOTUNDOABLE
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+// Comments:
+//
+// Since this server does not support undo, the value
+// INPLACE_E_NOTUNDOABLE is always returned.
+//
+//********************************************************************
+
+STDMETHODIMP COleInPlaceObject::ReactivateAndUndo ()
+{
+ TestDebugOut(TEXT("In COleInPlaceObject::ReactivateAndUndo\r\n"));
+ return ResultFromScode( INPLACE_E_NOTUNDOABLE );
+}
+
diff --git a/private/oleutest/simpsvr/ioipo.h b/private/oleutest/simpsvr/ioipo.h
new file mode 100644
index 000000000..da45b4254
--- /dev/null
+++ b/private/oleutest/simpsvr/ioipo.h
@@ -0,0 +1,43 @@
+//**********************************************************************
+// File name: ioipo.h
+//
+// Definition of COleInPlaceObject
+//
+// Copyright (c) 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+
+#if !defined( _IOIPO_H_)
+#define _IOIPO_H_
+
+
+#include <ole2.h>
+#include "obj.h"
+
+class CSimpSvrObj;
+
+interface COleInPlaceObject : public IOleInPlaceObject
+{
+private:
+ CSimpSvrObj FAR * m_lpObj;
+
+public:
+ COleInPlaceObject::COleInPlaceObject(CSimpSvrObj FAR * lpSimpSvrObj)
+ {
+ m_lpObj = lpSimpSvrObj;
+ };
+ COleInPlaceObject::~COleInPlaceObject() {};
+
+// IUnknown Methods
+ STDMETHODIMP QueryInterface (REFIID riid, LPVOID FAR* ppvObj);
+ STDMETHODIMP_(ULONG) AddRef ();
+ STDMETHODIMP_(ULONG) Release ();
+
+ STDMETHODIMP InPlaceDeactivate ();
+ STDMETHODIMP UIDeactivate () ;
+ STDMETHODIMP SetObjectRects ( LPCRECT lprcPosRect, LPCRECT lprcClipRect);
+ STDMETHODIMP GetWindow ( HWND FAR* lphwnd) ;
+ STDMETHODIMP ContextSensitiveHelp ( BOOL fEnterMode);
+ STDMETHODIMP ReactivateAndUndo ();
+};
+
+#endif
diff --git a/private/oleutest/simpsvr/ioo.cpp b/private/oleutest/simpsvr/ioo.cpp
new file mode 100644
index 000000000..8973969db
--- /dev/null
+++ b/private/oleutest/simpsvr/ioo.cpp
@@ -0,0 +1,1085 @@
+//**********************************************************************
+// File name: IOO.CPP
+//
+// Implementation file for the COleObject Class
+//
+// Functions:
+//
+// See ioo.h for a list of member functions.
+//
+// Copyright (c) 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+
+#include "pre.h"
+#include "obj.h"
+#include "ioo.h"
+#include "app.h"
+#include "doc.h"
+
+#define VERB_OPEN 1
+
+//**********************************************************************
+//
+// COleObject::QueryInterface
+//
+// Purpose:
+// Used for interface negotiation
+//
+// Parameters:
+//
+// REFIID riid - Interface being queried for.
+//
+// LPVOID FAR *ppvObj - Out pointer for the interface.
+//
+// Return Value:
+//
+// S_OK - Success
+// E_NOINTERFACE - Failure
+//
+// Function Calls:
+// Function Location
+//
+// CSimpSvrObj::QueryInterface OBJ.CPP
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleObject::QueryInterface ( REFIID riid, LPVOID FAR* ppvObj)
+{
+ TestDebugOut(TEXT("In COleObject::QueryInterface\r\n"));
+ return m_lpObj->QueryInterface(riid, ppvObj);
+}
+
+//**********************************************************************
+//
+// COleObject::AddRef
+//
+// Purpose:
+//
+// Increments the reference count on CSimpSvrObj. Since COleObject
+// is a nested class of CSimpSvrObj, we don't need an extra reference
+// count for COleObject. We can safely use the reference count of
+// CSimpSvrObj.
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// The new reference count on the CSimpSvrObj
+//
+// Function Calls:
+// Function Location
+//
+// OuputDebugString Windows API
+// CSimpSvrObj::AddRef OBJ.CPP
+//
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) COleObject::AddRef ()
+{
+ TestDebugOut(TEXT("In COleObject::AddRef\r\n"));
+ return m_lpObj->AddRef();
+}
+
+//**********************************************************************
+//
+// COleObject::Release
+//
+// Purpose:
+//
+// Decrements the reference count on CSimpSvrObj. Since COleObject
+// is a nested class of CSimpSvrObj, we don't need an extra reference
+// count for COleObject. We can safely use the reference count of
+// CSimpSvrObj.
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// The new reference count of CSimpSvrObj
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// CSimpSvrObj::Release OBJ.CPP
+//
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) COleObject::Release ()
+{
+ TestDebugOut(TEXT("In COleObject::Release\r\n"));
+ return m_lpObj->Release();
+}
+
+//**********************************************************************
+//
+// COleObject::SetClientSite
+//
+// Purpose:
+//
+// Called to notify the object of it's client site.
+//
+// Parameters:
+//
+// LPOLECLIENTSITE pClientSite - ptr to new client site
+//
+// Return Value:
+//
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// IOleClientSite::Release Container
+// IOleClientSite::AddRef Container
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleObject::SetClientSite ( LPOLECLIENTSITE pClientSite)
+{
+ TestDebugOut(TEXT("In COleObject::SetClientSite\r\n"));
+
+ // if we already have a client site, release it.
+ if (m_lpObj->m_lpOleClientSite)
+ {
+ m_lpObj->m_lpOleClientSite->Release();
+ m_lpObj->m_lpOleClientSite = NULL;
+ }
+
+ // store copy of the client site.
+ m_lpObj->m_lpOleClientSite = pClientSite;
+
+ // AddRef it so it doesn't go away.
+ if (m_lpObj->m_lpOleClientSite)
+ m_lpObj->m_lpOleClientSite->AddRef();
+
+ return ResultFromScode(S_OK);
+}
+
+//**********************************************************************
+//
+// COleObject::Advise
+//
+// Purpose:
+//
+// Called to set up an advise on the OLE object.
+//
+// Parameters:
+//
+// LPADVISESINK pAdvSink - ptr to the Advise Sink for notification
+//
+// DWORD FAR* pdwConnection - place to return the connection ID.
+//
+// Return Value:
+//
+// Passed back from IOleAdviseHolder::Advise.
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// CreateOleAdviseHolder OLE API
+// IOleAdviseHolder::Advise OLE
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleObject::Advise ( LPADVISESINK pAdvSink, DWORD FAR* pdwConnection)
+{
+ TestDebugOut(TEXT("In COleObject::Advise\r\n"));
+
+ // if we haven't made an OleAdviseHolder yet, make one.
+ if (!m_lpObj->m_lpOleAdviseHolder)
+ {
+ HRESULT hRes;
+ if ((hRes=CreateOleAdviseHolder(&m_lpObj->m_lpOleAdviseHolder))!=S_OK)
+ {
+ TestDebugOut(TEXT("CreateOleAdviseHolder fails\n"));
+ return(hRes);
+ }
+ }
+
+ // pass this call onto the OleAdviseHolder.
+ return m_lpObj->m_lpOleAdviseHolder->Advise(pAdvSink, pdwConnection);
+}
+
+//**********************************************************************
+//
+// COleObject::SetHostNames
+//
+// Purpose:
+//
+// Called to pass strings for Window titles.
+//
+// Parameters:
+//
+// LPCOLESTR szContainerApp - ptr to string describing Container App
+//
+// LPCOLESTR szContainerObj - ptr to string describing Object
+//
+// Return Value:
+//
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+// Comments:
+//
+// This routine is called so that the server application can
+// set the window title appropriately.
+//
+//********************************************************************
+
+STDMETHODIMP COleObject::SetHostNames ( LPCOLESTR szContainerApp, LPCOLESTR szContainerObj)
+{
+ TestDebugOut(TEXT("In COleObject::SetHostNames\r\n"));
+
+ return ResultFromScode( S_OK);
+}
+
+//**********************************************************************
+//
+// COleObject::DoVerb
+//
+// Purpose:
+//
+// Called by the container application to invoke a verb.
+//
+// Parameters:
+//
+// LONG iVerb - The value of the verb to be
+// invoked.
+//
+// LPMSG lpmsg - The message that caused the
+// verb to be invoked.
+//
+// LPOLECLIENTSITE pActiveSite - Ptr to the active client site.
+//
+// LONG lindex - Used in extended layout
+//
+// HWND hwndParent - This should be the window handle of
+// the window in which we are contained.
+// This value could be used to "fake"
+// inplace activation in a manner similar
+// to Video for Windows in OLE 1.0.
+//
+// LPCRECT lprcPosRect - The rectangle that contains the object
+// within hwndParent. Also used to
+// "fake" inplace activation.
+//
+// Return Value:
+//
+// OLE_E_NOTINPLACEACTIVE - Returned if attempted to undo while not
+// inplace active.
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// ShowWindow Windows API
+// CSimpSvrObj::DoInPlaceActivate OBJ.CPP
+// CSimpSvrObj::DoInPlaceHide OBJ.CPP
+// COleObject::OpenEdit IOO.CPP
+// CSimpSvrDoc::GethDocWnd DOC.H
+// COleInPlaceObj::InPlaceDeactivate IOIPO.CPP
+//
+// Comments:
+//
+// Be sure to look at TECHNOTES.WRI included with the OLE
+// SDK for a description of handling the inplace verbs
+// properly.
+//
+//********************************************************************
+
+STDMETHODIMP COleObject::DoVerb ( LONG iVerb,
+ LPMSG lpmsg,
+ LPOLECLIENTSITE pActiveSite,
+ LONG lindex,
+ HWND hwndParent,
+ LPCRECT lprcPosRect)
+{
+ TestDebugOut(TEXT("In COleObject::DoVerb\r\n"));
+
+ switch (iVerb)
+ {
+ case OLEIVERB_SHOW:
+ case OLEIVERB_PRIMARY:
+ if (m_fOpen)
+ SetFocus(m_lpObj->m_lpDoc->GethAppWnd());
+ else if (m_lpObj->DoInPlaceActivate(iVerb) == FALSE)
+ OpenEdit(pActiveSite);
+ break;
+
+ case OLEIVERB_UIACTIVATE:
+ if (m_fOpen)
+ return ResultFromScode (E_FAIL);
+
+ // inplace activate
+ if (!m_lpObj->DoInPlaceActivate(iVerb))
+ return ResultFromScode (E_FAIL);
+ break;
+
+ case OLEIVERB_DISCARDUNDOSTATE:
+ // don't have to worry about this situation as we don't
+ // support an undo state.
+ if (!m_lpObj->m_fInPlaceActive)
+ return ResultFromScode(OLE_E_NOT_INPLACEACTIVE);
+ break;
+
+ case OLEIVERB_HIDE:
+ // if inplace active, do an "inplace" hide, otherwise
+ // just hide the app window.
+ if (m_lpObj->m_fInPlaceActive)
+ {
+ // clear inplace flag
+ m_lpObj->m_fInPlaceActive = FALSE;
+
+ // deactivate the UI
+ m_lpObj->DeactivateUI();
+ m_lpObj->DoInPlaceHide();
+ }
+ else
+ m_lpObj->m_lpDoc->GetApp()->HideAppWnd();
+ break;
+
+ case OLEIVERB_OPEN:
+ case VERB_OPEN:
+ // if inplace active, deactivate
+ if (m_lpObj->m_fInPlaceActive)
+ m_lpObj->m_OleInPlaceObject.InPlaceDeactivate();
+
+ // open into another window.
+ OpenEdit(pActiveSite);
+ break;
+
+ default:
+ if (iVerb < 0)
+ return ResultFromScode(E_FAIL);
+ }
+
+ return ResultFromScode( S_OK);
+}
+
+//**********************************************************************
+//
+// COleObject::GetExtent
+//
+// Purpose:
+//
+// Returns the extent of the object.
+//
+// Parameters:
+//
+// DWORD dwDrawAspect - The aspect in which to get the size.
+//
+// LPSIZEL lpsizel - Out ptr to return the size.
+//
+// Return Value:
+// S_OK if the aspect is DVASPECT_CONTENT
+// E_FAIL otherwise
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// XformWidthInPixelsToHimetric OLE2UI
+// XformHeightInPixelsToHimetric OLE2UI
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleObject::GetExtent ( DWORD dwDrawAspect, LPSIZEL lpsizel)
+{
+ TestDebugOut(TEXT("In COleObject::GetExtent\r\n"));
+
+ SCODE sc = E_FAIL;
+
+ // Only DVASPECT_CONTENT is supported....
+ if (dwDrawAspect == DVASPECT_CONTENT)
+ {
+ sc = S_OK;
+
+ // return the correct size in HIMETRIC...
+ lpsizel->cx = XformWidthInPixelsToHimetric(NULL, m_lpObj->m_size.x);
+ lpsizel->cy = XformHeightInPixelsToHimetric(NULL, m_lpObj->m_size.y);
+ }
+
+ return ResultFromScode( sc );
+}
+
+//**********************************************************************
+//
+// COleObject::Update
+//
+// Purpose:
+//
+// Called to get the most up to date data
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// IDataAdviseHolder::SendOnDataChange OLE
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleObject::Update()
+{
+ TestDebugOut(TEXT("In COleObject::Update\r\n"));
+
+ // force an update
+ m_lpObj->SendOnDataChange();
+
+ return ResultFromScode( S_OK );
+}
+
+//**********************************************************************
+//
+// COleObject::Close
+//
+// Purpose:
+//
+// Called when the OLE object needs to be closed
+//
+// Parameters:
+//
+// DWORD dwSaveOption - Flags to instruct the server how to prompt
+// the user.
+//
+// Return Value:
+//
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// CSimpSvrDoc::Close DOC.CPP
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleObject::Close ( DWORD dwSaveOption)
+{
+ TestDebugOut(TEXT("In COleObject::Close\r\n"));
+
+ // delegate to the document object.
+ m_lpObj->m_lpDoc->Close();
+
+ return ResultFromScode( S_OK );
+}
+
+//**********************************************************************
+//
+// COleObject::Unadvise
+//
+// Purpose:
+//
+// Breaks down an OLE advise that has been set up on this object.
+//
+// Parameters:
+//
+// DWORD dwConnection - Connection that needs to be broken down
+//
+// Return Value:
+//
+// Passed back from IOleAdviseHolder::Unadvise
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// IOleAdviseHolder::Unadvise OLE
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleObject::Unadvise ( DWORD dwConnection)
+{
+ TestDebugOut(TEXT("In COleObject::Unadvise\r\n"));
+
+ // pass on to OleAdviseHolder.
+ return m_lpObj->m_lpOleAdviseHolder->Unadvise(dwConnection);
+}
+
+//**********************************************************************
+//
+// COleObject::EnumVerbs
+//
+// Purpose:
+//
+// Enumerates the verbs associated with this object.
+//
+// Parameters:
+//
+// LPENUMOLEVERB FAR* ppenumOleVerb - Out ptr in which to return
+// the enumerator
+//
+// Return Value:
+//
+// OLE_S_USEREG - Instructs OLE to use the verbs found in the
+// REG DB for this server.
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+// Comments:
+//
+// In a .DLL, an application cannot return OLE_S_USEREG. This is
+// due to the fact that the default object handler is not being
+// used, and the container is really making direct function calls
+// into the server .DLL.
+//
+//********************************************************************
+
+STDMETHODIMP COleObject::EnumVerbs ( LPENUMOLEVERB FAR* ppenumOleVerb)
+{
+ TestDebugOut(TEXT("In COleObject::EnumVerbs\r\n"));
+
+ return ResultFromScode( OLE_S_USEREG );
+}
+
+//**********************************************************************
+//
+// COleObject::GetClientSite
+//
+// Purpose:
+//
+// Called to get the current client site of the object.
+//
+// Parameters:
+//
+// LPOLECLIENTSITE FAR* ppClientSite - Out ptr in which to return the
+// client site.
+//
+// Return Value:
+//
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleObject::GetClientSite ( LPOLECLIENTSITE FAR* ppClientSite)
+{
+ TestDebugOut(TEXT("In COleObject::GetClientSite\r\n"));
+ *ppClientSite = m_lpObj->m_lpOleClientSite;
+ return ResultFromScode( S_OK );
+}
+
+//**********************************************************************
+//
+// COleObject::SetMoniker
+//
+// Purpose:
+//
+// Used to set the objects moniker
+//
+// Parameters:
+//
+// DWORD dwWhichMoniker - Type of moniker being set
+//
+// LPMONIKER pmk - Pointer to the moniker
+//
+// Return Value:
+// S_OK
+// E_FAIL if the Moniker cannot be set
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleObject::SetMoniker ( DWORD dwWhichMoniker, LPMONIKER pmk)
+{
+ TestDebugOut(TEXT("In COleObject::SetMoniker\r\n"));
+
+ LPMONIKER lpmk;
+ HRESULT hRes;
+
+ if (! m_lpObj->GetOleClientSite())
+ return ResultFromScode (E_FAIL);
+
+ if (m_lpObj->GetOleClientSite()->GetMoniker (OLEGETMONIKER_ONLYIFTHERE, OLEWHICHMK_OBJFULL, &lpmk) != NOERROR)
+ return ResultFromScode (E_FAIL);
+
+
+ if (m_lpObj->GetOleAdviseHolder())
+ {
+ if ((hRes=m_lpObj->GetOleAdviseHolder()->SendOnRename(lpmk))!=S_OK)
+ TestDebugOut(TEXT("SendOnRename fails\n"));
+ }
+
+ LPRUNNINGOBJECTTABLE lpRot;
+
+ if (GetRunningObjectTable(0, &lpRot) == NOERROR)
+ {
+ if (m_lpObj->m_dwRegister)
+ lpRot->Revoke(m_lpObj->m_dwRegister);
+
+ if ( ((hRes=lpRot->Register(0, m_lpObj, lpmk,
+ &m_lpObj->m_dwRegister))!=S_OK) ||
+ (hRes!=ResultFromScode(MK_S_MONIKERALREADYREGISTERED)))
+ TestDebugOut(TEXT("Running Object Table Register fails\n"));
+
+ lpRot->Release();
+ }
+
+
+ return ResultFromScode( S_OK );
+}
+
+//**********************************************************************
+//
+// COleObject::GetMoniker
+//
+// Purpose:
+// returns a moniker from the client site
+//
+// Parameters:
+//
+// DWORD dwAssign - Assignment for the moniker
+//
+// DWORD dwWhichMoniker - Which moniker to return
+//
+// LPMONIKER FAR* ppmk - An out ptr to return the moniker
+//
+// Return Value:
+//
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleObject::GetMoniker ( DWORD dwAssign, DWORD dwWhichMoniker,
+ LPMONIKER FAR* ppmk)
+{
+ TestDebugOut(TEXT("In COleObject::GetMoniker\r\n"));
+ // need to NULL the out parameter
+ *ppmk = NULL;
+
+ return m_lpObj->GetOleClientSite()->GetMoniker(OLEGETMONIKER_ONLYIFTHERE,
+ OLEWHICHMK_OBJFULL, ppmk);
+}
+
+//**********************************************************************
+//
+// COleObject::InitFromData
+//
+// Purpose:
+//
+// Initialize the object from the passed pDataObject.
+//
+// Parameters:
+//
+// LPDATAOBJECT pDataObject - Pointer to data transfer object
+// to be used in the initialization
+//
+// BOOL fCreation - TRUE if the object is currently being
+// created.
+//
+// DWORD dwReserved - Reserved
+//
+// Return Value:
+//
+// S_FALSE
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+// Comments:
+//
+// We don't support this functionality, so we will always return
+// error.
+//
+//********************************************************************
+
+STDMETHODIMP COleObject::InitFromData ( LPDATAOBJECT pDataObject,
+ BOOL fCreation,
+ DWORD dwReserved)
+{
+ TestDebugOut(TEXT("In COleObject::InitFromData\r\n"));
+
+ return ResultFromScode( S_FALSE );
+}
+
+//**********************************************************************
+//
+// COleObject::GetClipboardData
+//
+// Purpose:
+//
+// Returns an IDataObject that is the same as doing an OleSetClipboard
+//
+// Parameters:
+//
+// DWORD dwReserved - Reserved
+//
+// LPDATAOBJECT FAR* ppDataObject - Out ptr for the Data Object.
+//
+// Return Value:
+//
+// OLE_E_NOTSUPPORTED
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+// Comments:
+//
+// Support of this method is optional.
+//
+//********************************************************************
+
+STDMETHODIMP COleObject::GetClipboardData ( DWORD dwReserved,
+ LPDATAOBJECT FAR* ppDataObject)
+{
+ TestDebugOut(TEXT("In COleObject::GetClipboardData\r\n"));
+ // NULL the out ptr
+ *ppDataObject = NULL;
+ return ResultFromScode( E_NOTIMPL );
+}
+
+//**********************************************************************
+//
+// COleObject::IsUpToDate
+//
+// Purpose:
+//
+// Determines if an object is up to date
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+// Comments:
+//
+// Our embedded object is always up to date. This function is
+// particularly useful in linking situations.
+//
+//********************************************************************
+
+STDMETHODIMP COleObject::IsUpToDate()
+{
+ TestDebugOut(TEXT("In COleObject::IsUpToDate\r\n"));
+ return ResultFromScode( S_OK );
+}
+
+//**********************************************************************
+//
+// COleObject::GetUserClassID
+//
+// Purpose:
+//
+// Returns the applications CLSID
+//
+// Parameters:
+//
+// CLSID FAR* pClsid - Out ptr to return the CLSID
+//
+// Return Value:
+//
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// CPersistStorage::GetClassID IPS.CPP
+//
+// Comments:
+//
+// This function is just delegated to IPS::GetClassID.
+//
+//********************************************************************
+
+STDMETHODIMP COleObject::GetUserClassID ( CLSID FAR* pClsid)
+{
+ TestDebugOut(TEXT("In COleObject::GetUserClassID\r\n"));
+
+ return ( m_lpObj->m_PersistStorage.GetClassID(pClsid) );
+}
+
+//**********************************************************************
+//
+// COleObject::GetUserType
+//
+// Purpose:
+//
+// Used to get a user presentable id for this object
+//
+// Parameters:
+//
+// DWORD dwFormOfType - The ID requested
+//
+// LPOLESTR FAR* pszUserType - Out ptr to return the string
+//
+// Return Value:
+//
+// OLE_S_USEREG - Use the reg db to get these entries.
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+// Comment:
+// In this implementation, we delegate to the default handler's
+// implementation using the registration database to provide
+// the requested info.
+//
+//********************************************************************
+
+STDMETHODIMP COleObject::GetUserType ( DWORD dwFormOfType,
+ LPOLESTR FAR* pszUserType)
+{
+ TestDebugOut(TEXT("In COleObject::GetUserType\r\n"));
+
+ return ResultFromScode( OLE_S_USEREG );
+}
+
+//**********************************************************************
+//
+// COleObject::SetExtent
+//
+// Purpose:
+//
+// Called to set the extent of the object.
+//
+// Parameters:
+//
+// DWORD dwDrawAspect - Aspect to have its size set
+//
+// LPSIZEL lpsizel - New size of the object.
+//
+// Return Value:
+//
+// E_NOTIMPL - This function is not curently implemented.
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+// Comments:
+//
+// See TECHNOTES.WRI include with the OLE SDK for proper
+// implementation of this function.
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleObject::SetExtent ( DWORD dwDrawAspect, LPSIZEL lpsizel)
+{
+ TestDebugOut(TEXT("In COleObject::SetExtent\r\n"));
+ return ResultFromScode( E_NOTIMPL);
+}
+
+//**********************************************************************
+//
+// COleObject::EnumAdvise
+//
+// Purpose:
+//
+// Returns an enumerate which enumerates the outstanding advises
+// associated with this OLE object.
+//
+// Parameters:
+//
+// LPENUMSTATDATA FAR* ppenumAdvise - Out ptr in which to return
+// the enumerator.
+//
+// Return Value:
+//
+// Passed on from IOleAdviseHolder::EnumAdvise.
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// IOleAdviseHolder::EnumAdvise OLE
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleObject::EnumAdvise ( LPENUMSTATDATA FAR* ppenumAdvise)
+{
+ TestDebugOut(TEXT("In COleObject::EnumAdvise\r\n"));
+ // need to NULL the out parameter
+ *ppenumAdvise = NULL;
+
+ // pass on to the OLE Advise holder.
+ return m_lpObj->m_lpOleAdviseHolder->EnumAdvise(ppenumAdvise);
+}
+
+//**********************************************************************
+//
+// COleObject::GetMiscStatus
+//
+// Purpose:
+//
+// Return status information about the object
+//
+// Parameters:
+//
+// DWORD dwAspect - Aspect interested in.
+//
+// DWORD FAR* pdwStatus - Out ptr in which to return the bits.
+//
+// Return Value:
+//
+// OLE_S_USEREG - Use the reg db to get these entries.
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+// Comment:
+// In this implementation, we delegate to the default handler's
+// implementation using the registration database to provide
+// the requested info.
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleObject::GetMiscStatus ( DWORD dwAspect, DWORD FAR* pdwStatus)
+{
+ TestDebugOut(TEXT("In COleObject::GetMiscStatus\r\n"));
+ // need to NULL the out parameter
+ *pdwStatus = NULL;
+ return ResultFromScode( OLE_S_USEREG );
+}
+
+//**********************************************************************
+//
+// COleObject::SetColorScheme
+//
+// Purpose:
+//
+// Used to set the palette for the object to use.
+//
+// Parameters:
+//
+// LPLOGPALETTE lpLogpal - Pointer to the LOGPALETTE to be used.
+//
+// Return Value:
+//
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+// Comments:
+//
+// This server ignores this method.
+//
+//********************************************************************
+
+STDMETHODIMP COleObject::SetColorScheme ( LPLOGPALETTE lpLogpal)
+{
+ TestDebugOut(TEXT("In COleObject::SetColorScheme\r\n"));
+ return ResultFromScode( S_OK );
+}
+
+//**********************************************************************
+//
+// COleObject::OpenEdit
+//
+// Purpose:
+//
+// Used to Open the object into a seperate window.
+//
+// Parameters:
+//
+// LPOLECLIENTSITE pActiveSite - Pointer to the Active clientsite.
+//
+// Return Value:
+//
+// None.
+//
+// Function Calls:
+// Function Location
+//
+// IOleClientSite::OnShowWindow Container
+// ShowWindow Windows API
+// UpdateWindow Windows API
+// TestDebugOut Windows API
+// CSimpSvrDoc::GethAppWnd DOC.H
+// CSimpSvrDoc::GethHatchWnd DOC.H
+//
+//
+//********************************************************************
+
+void COleObject::OpenEdit(LPOLECLIENTSITE pActiveSite)
+{
+ if (m_lpObj->GetOleClientSite())
+ m_lpObj->GetOleClientSite()->ShowObject();
+
+
+ m_fOpen = TRUE;
+
+ // tell the site we are opening so the object can be hatched out.
+ if (m_lpObj->GetOleClientSite())
+ m_lpObj->GetOleClientSite()->OnShowWindow(TRUE);
+
+
+ m_lpObj->m_lpDoc->ShowDocWnd();
+
+ m_lpObj->m_lpDoc->HideHatchWnd();
+
+ // Show app window.
+ m_lpObj->m_lpDoc->GetApp()->ShowAppWnd();
+
+ SetFocus(m_lpObj->m_lpDoc->GethAppWnd());
+}
+
diff --git a/private/oleutest/simpsvr/ioo.h b/private/oleutest/simpsvr/ioo.h
new file mode 100644
index 000000000..39163311a
--- /dev/null
+++ b/private/oleutest/simpsvr/ioo.h
@@ -0,0 +1,71 @@
+//**********************************************************************
+// File name: ioo.h
+//
+// Definition of COleObject
+//
+// Copyright (c) 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+#if !defined( _IOO_H_)
+#define _IOO_H_
+
+
+#include <ole2.h>
+#include "obj.h"
+
+class CSimpSvrObj;
+
+interface COleObject : public IOleObject
+{
+private:
+ CSimpSvrObj FAR * m_lpObj;
+ BOOL m_fOpen;
+
+public:
+ COleObject::COleObject(CSimpSvrObj FAR * lpSimpSvrObj)
+ {
+ m_lpObj = lpSimpSvrObj;
+ m_fOpen = FALSE;
+ };
+ COleObject::~COleObject()
+ {
+ };
+ STDMETHODIMP QueryInterface (REFIID riid, LPVOID FAR* ppvObj);
+ STDMETHODIMP_(ULONG) AddRef ();
+ STDMETHODIMP_(ULONG) Release ();
+
+ STDMETHODIMP SetClientSite (LPOLECLIENTSITE pClientSite);
+ STDMETHODIMP Advise (LPADVISESINK pAdvSink, DWORD FAR* pdwConnection);
+ STDMETHODIMP SetHostNames ( LPCOLESTR szContainerApp, LPCOLESTR szContainerObj);
+ STDMETHODIMP DoVerb ( LONG iVerb,
+ LPMSG lpmsg,
+ LPOLECLIENTSITE pActiveSite,
+ LONG lindex,
+ HWND hwndParent,
+ LPCRECT lprcPosRect);
+ STDMETHODIMP GetExtent ( DWORD dwDrawAspect, LPSIZEL lpsizel);
+ STDMETHODIMP Update () ;
+ STDMETHODIMP Close ( DWORD dwSaveOption) ;
+ STDMETHODIMP Unadvise ( DWORD dwConnection);
+ STDMETHODIMP EnumVerbs ( LPENUMOLEVERB FAR* ppenumOleVerb) ;
+ STDMETHODIMP GetClientSite ( LPOLECLIENTSITE FAR* ppClientSite);
+ STDMETHODIMP SetMoniker ( DWORD dwWhichMoniker, LPMONIKER pmk);
+ STDMETHODIMP GetMoniker ( DWORD dwAssign, DWORD dwWhichMoniker,
+ LPMONIKER FAR* ppmk);
+ STDMETHODIMP InitFromData ( LPDATAOBJECT pDataObject,
+ BOOL fCreation,
+ DWORD dwReserved);
+ STDMETHODIMP GetClipboardData ( DWORD dwReserved,
+ LPDATAOBJECT FAR* ppDataObject);
+ STDMETHODIMP IsUpToDate ();
+ STDMETHODIMP GetUserClassID ( CLSID FAR* pClsid);
+ STDMETHODIMP GetUserType ( DWORD dwFormOfType, LPOLESTR FAR* pszUserType);
+ STDMETHODIMP SetExtent ( DWORD dwDrawAspect, LPSIZEL lpsizel);
+ STDMETHODIMP EnumAdvise ( LPENUMSTATDATA FAR* ppenumAdvise);
+ STDMETHODIMP GetMiscStatus ( DWORD dwAspect, DWORD FAR* pdwStatus);
+ STDMETHODIMP SetColorScheme ( LPLOGPALETTE lpLogpal);
+
+ void OpenEdit(LPOLECLIENTSITE pActiveSite);
+
+};
+
+#endif
diff --git a/private/oleutest/simpsvr/ips.cpp b/private/oleutest/simpsvr/ips.cpp
new file mode 100644
index 000000000..3e84b8aab
--- /dev/null
+++ b/private/oleutest/simpsvr/ips.cpp
@@ -0,0 +1,654 @@
+//**********************************************************************
+// File name: ips.cpp
+//
+// Implementation file for the CSimpSvrApp Class
+//
+// Functions:
+//
+// See ips.h for a list of member functions.
+//
+// Copyright (c) 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+
+#include "pre.h"
+#include "obj.h"
+#include "ips.h"
+#include "app.h"
+#include "doc.h"
+
+DEFINE_GUID(GUID_SIMPLE, 0xBCF6D4A0, 0xBE8C, 0x1068, 0xB6, 0xD4, 0x00, 0xDD, 0x01, 0x0C, 0x05, 0x09);
+
+//**********************************************************************
+//
+// CPersistStorage::QueryInterface
+//
+// Purpose:
+// Used for interface negotiation
+//
+// Parameters:
+//
+// REFIID riid - Interface being queried for.
+//
+// LPVOID FAR *ppvObj - Out pointer for the interface.
+//
+// Return Value:
+//
+// S_OK - Success
+// E_NOINTERFACE - Failure
+//
+// Function Calls:
+// Function Location
+//
+// CSimpSvrObj::QueryInterface OBJ.CPP
+//
+//
+//********************************************************************
+
+STDMETHODIMP CPersistStorage::QueryInterface ( REFIID riid, LPVOID FAR* ppvObj)
+{
+ TestDebugOut(TEXT("In CPersistStorage::QueryInterface\r\n"));
+ // need to NULL the out parameter
+ return m_lpObj->QueryInterface(riid, ppvObj);
+}
+
+//**********************************************************************
+//
+// CPersistStorage::AddRef
+//
+// Purpose:
+//
+// Increments the reference count on CSimpSvrObj. Since CPersistStorage
+// is a nested class of CSimpSvrObj, we don't need an extra reference
+// count for CPersistStorage. We can safely use the reference count of
+// CSimpSvrObj.
+//
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// The new reference count of CSimpSvrObj
+//
+// Function Calls:
+// Function Location
+//
+// OuputDebugString Windows API
+// CSimpSvrObj::AddRef OBJ.CPP
+//
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) CPersistStorage::AddRef ()
+{
+ TestDebugOut(TEXT("In CPersistStorage::AddRef\r\n"));
+ return m_lpObj->AddRef();
+}
+
+//**********************************************************************
+//
+// CPersistStorage::Release
+//
+// Purpose:
+//
+// Decrements the reference count on CSimpSvrObj. Since CPersistStorage
+// is a nested class of CSimpSvrObj, we don't need an extra reference
+// count for CPersistStorage. We can safely use the reference count of
+// CSimpSvrObj.
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// The new reference count of CSimpSvrObj
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// CSimpSvrObj::Release OBJ.CPP
+//
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) CPersistStorage::Release ()
+{
+ TestDebugOut(TEXT("In CPersistStorage::Release\r\n"));
+ return m_lpObj->Release();
+}
+
+//**********************************************************************
+//
+// CPersistStorage::InitNew
+//
+// Purpose:
+//
+// Used to give a new OLE object a ptr to its storage.
+//
+// Parameters:
+//
+// LPSTORAGE pStg - Pointer to the storage
+//
+// Return Value:
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// IStorage::Release OLE
+// IStorage::AddRef OLE
+//
+//
+//********************************************************************
+
+STDMETHODIMP CPersistStorage::InitNew (LPSTORAGE pStg)
+{
+ TestDebugOut(TEXT("In CPersistStorage::InitNew\r\n"));
+
+ // release any streams and storages that may be open
+ ReleaseStreamsAndStorage();
+
+ m_lpObj->m_lpStorage = pStg;
+
+ // AddRef the new Storage
+ if (m_lpObj->m_lpStorage)
+ m_lpObj->m_lpStorage->AddRef();
+
+ CreateStreams(m_lpObj->m_lpStorage);
+
+ return ResultFromScode(S_OK);
+}
+
+//**********************************************************************
+//
+// CPersistStorage::GetClassID
+//
+// Purpose:
+//
+// Returns the CLSID of this object.
+//
+// Parameters:
+//
+// LPCLSID lpClassID - Out ptr in which to return the CLSID
+//
+// Return Value:
+//
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+//
+//********************************************************************
+
+STDMETHODIMP CPersistStorage::GetClassID ( LPCLSID lpClassID)
+{
+ TestDebugOut(TEXT("In CPersistStorage::GetClassID\r\n"));
+
+ *lpClassID = GUID_SIMPLE;
+
+ return ResultFromScode( S_OK );
+}
+
+//**********************************************************************
+//
+// CPersistStorage::Save
+//
+// Purpose:
+//
+// Instructs the object to save itself into the storage.
+//
+// Parameters:
+//
+// LPSTORAGE pStgSave - Storage in which the object should be saved
+//
+// BOOL fSameAsLoad - TRUE if pStgSave is the same as the storage
+// that the object was originally created with.
+//
+// Return Value:
+//
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// CPersistStorage::InitNew IPS.CPP
+// CSimpSvrObj::SaveToStorage OBJ.CPP
+//
+//
+// Comments:
+//
+// A real app will want better error checking in this method.
+//
+//********************************************************************
+
+STDMETHODIMP CPersistStorage::Save ( LPSTORAGE pStgSave, BOOL fSameAsLoad)
+{
+ TestDebugOut(TEXT("In CPersistStorage::Save\r\n"));
+
+ // save the data
+ m_lpObj->SaveToStorage (pStgSave, fSameAsLoad);
+
+ m_lpObj->m_fSaveWithSameAsLoad = fSameAsLoad;
+ m_lpObj->m_fNoScribbleMode = TRUE;
+
+ return ResultFromScode( S_OK );
+}
+
+//**********************************************************************
+//
+// CPersistStorage::SaveCompleted
+//
+// Purpose:
+//
+// Called when the container is finished saving the object
+//
+// Parameters:
+//
+// LPSTORAGE pStgNew - ptr to the new storage
+//
+// Return Value:
+//
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+//
+//********************************************************************
+
+STDMETHODIMP CPersistStorage::SaveCompleted ( LPSTORAGE pStgNew)
+{
+ TestDebugOut(TEXT("In CPersistStorage::SaveCompleted\r\n"));
+
+ if (pStgNew)
+ {
+ ReleaseStreamsAndStorage();
+ m_lpObj->m_lpStorage = pStgNew;
+ m_lpObj->m_lpStorage->AddRef();
+ OpenStreams(pStgNew);
+ }
+
+
+ /* 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 ( pStgNew || m_lpObj->m_fSaveWithSameAsLoad)
+ {
+ if (m_lpObj->m_fNoScribbleMode)
+ if (
+ m_lpObj->GetOleAdviseHolder()->SendOnSave()!=S_OK
+ // normally would clear a
+ // dirty bit
+ )
+ TestDebugOut(TEXT("SendOnSave fails\n"));
+ m_lpObj->m_fSaveWithSameAsLoad = FALSE;
+ }
+
+ m_lpObj->m_fNoScribbleMode = FALSE;
+
+ return ResultFromScode( S_OK );
+}
+
+//**********************************************************************
+//
+// CPersistStorage::Load
+//
+// Purpose:
+//
+// Instructs the object to be loaded from storage.
+//
+// Parameters:
+//
+// LPSTORAGE pStg - Ptr to the storage in which to be loaded
+//
+// Return Value:
+//
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// CSimpSvrObj::LoadFromStorage OBJ.CPP
+//
+//
+// Comments:
+//
+// A real app will want better error checking in this method.
+//
+//********************************************************************
+
+STDMETHODIMP CPersistStorage::Load ( LPSTORAGE pStg)
+{
+ TestDebugOut(TEXT("In CPersistStorage::Load\r\n"));
+
+ // remember the storage
+ if (m_lpObj->m_lpStorage)
+ {
+ m_lpObj->m_lpStorage->Release();
+ m_lpObj->m_lpStorage = NULL;
+ }
+
+ m_lpObj->m_lpStorage = pStg;
+
+ m_lpObj->m_lpStorage->AddRef();
+
+ OpenStreams(m_lpObj->m_lpStorage);
+
+ m_lpObj->LoadFromStorage();
+
+
+ return ResultFromScode( S_OK );
+}
+
+
+//**********************************************************************
+//
+// CPersistStorage::IsDirty
+//
+// Purpose:
+//
+// Returns whether or not the object is dirty w/respect to its
+// Storage
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+//
+// Comments:
+//
+// This sample does not implement this function, although a
+// real application should.
+//
+//********************************************************************
+
+STDMETHODIMP CPersistStorage::IsDirty()
+{
+ TestDebugOut(TEXT("In CPersistStorage::IsDirty\r\n"));
+ return ResultFromScode( S_OK );
+}
+
+//**********************************************************************
+//
+// CPersistStorage::HandsOffStorage
+//
+// Purpose:
+//
+// Forces the object to release its handle to its storage.
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// IStorage::Release OLE
+//
+//********************************************************************
+
+STDMETHODIMP CPersistStorage::HandsOffStorage ()
+{
+ TestDebugOut(TEXT("In CPersistStorage::HandsOffStorage\r\n"));
+
+ ReleaseStreamsAndStorage();
+
+ return ResultFromScode( S_OK );
+}
+
+//**********************************************************************
+//
+// CPersistStorage::CreateStreams
+//
+// Purpose:
+//
+// Creates the streams that are held open for the object's lifetime.
+//
+// Parameters:
+//
+// LPSTORAGE lpStg - Storage in which to create the streams
+//
+// Return Value:
+//
+// none
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// IStorage::Release OLE
+// IStream::Release OLE
+// IStorage::CreateStream OLE
+//
+//
+//********************************************************************
+
+void CPersistStorage::CreateStreams(LPSTORAGE lpStg)
+{
+ if (m_lpObj->m_lpColorStm)
+ m_lpObj->m_lpColorStm->Release();
+
+ if (m_lpObj->m_lpSizeStm)
+ m_lpObj->m_lpSizeStm->Release();
+
+ // create a stream to save the colors
+ if (
+ lpStg->CreateStream ( OLESTR("RGB"),
+ STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_CREATE,
+ 0,
+ 0,
+ &m_lpObj->m_lpColorStm)
+ !=S_OK
+ )
+ TestDebugOut(TEXT("CreateStreams fails\n"));
+
+ // create a stream to save the size
+ if (
+ lpStg->CreateStream ( OLESTR("size"),
+ STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_CREATE,
+ 0,
+ 0,
+ &m_lpObj->m_lpSizeStm)
+ !=S_OK
+ )
+ TestDebugOut(TEXT("CreateStreams fails\n"));
+}
+
+//**********************************************************************
+//
+// CPersistStorage::OpenStreams
+//
+// Purpose:
+//
+// Opens the streams in a storage.
+//
+// Parameters:
+//
+// LPSTORAGE lpStg - Storage in which to open the streams.
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// IStream::Release OLE
+// IStorage::OpenStream OLE
+//
+//
+//********************************************************************
+
+void CPersistStorage::OpenStreams(LPSTORAGE lpStg)
+{
+ if (m_lpObj->m_lpColorStm)
+ m_lpObj->m_lpColorStm->Release();
+
+ if (m_lpObj->m_lpSizeStm)
+ m_lpObj->m_lpSizeStm->Release();
+
+ // open the color stream
+ if (
+ lpStg->OpenStream ( OLESTR("RGB"),
+ 0,
+ STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
+ 0,
+ &m_lpObj->m_lpColorStm)
+ !=S_OK
+ )
+ TestDebugOut(TEXT("OpenStream fails\n"));
+
+
+ // open the color stream
+ if (
+ lpStg->OpenStream ( OLESTR("size"),
+ 0,
+ STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
+ 0,
+ &m_lpObj->m_lpSizeStm)
+ !=S_OK
+ )
+ TestDebugOut(TEXT("OpenStream fails\n"));
+
+}
+
+//**********************************************************************
+//
+// CPersistStorage::ReleaseStreamsAndStorage
+//
+// Purpose:
+//
+// Releases the stream and storage ptrs
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+// None
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// IStream::Release OLE
+// IStorage::Release OLE
+//
+//********************************************************************
+
+void CPersistStorage::ReleaseStreamsAndStorage()
+{
+ if (m_lpObj->m_lpColorStm)
+ {
+ m_lpObj->m_lpColorStm->Release();
+ m_lpObj->m_lpColorStm = NULL;
+ }
+
+ if (m_lpObj->m_lpSizeStm)
+ {
+ m_lpObj->m_lpSizeStm->Release();
+ m_lpObj->m_lpSizeStm = NULL;
+ }
+
+ if (m_lpObj->m_lpStorage)
+ {
+ m_lpObj->m_lpStorage->Release();
+ m_lpObj->m_lpStorage = NULL;
+ }
+}
+
+//**********************************************************************
+//
+// CPersistStorage::CreateStreams
+//
+// Purpose:
+//
+// Creates temporary streams in a storage.
+//
+// Parameters:
+//
+// LPSTORAGE lpStg - Pointer to the storage
+//
+// LPSTREAM FAR* lplpTempColor - Color Stream
+//
+// LPSTREAM FAR* lplpTempSize - Size Stream
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// IStorage::Release OLE
+//
+//
+//********************************************************************
+
+void CPersistStorage::CreateStreams(LPSTORAGE lpStg,
+ LPSTREAM FAR* lplpTempColor,
+ LPSTREAM FAR* lplpTempSize)
+{
+ // create a stream to save the colors
+ if (
+ lpStg->CreateStream ( OLESTR("RGB"),
+ STGM_READWRITE | STGM_SHARE_EXCLUSIVE |
+ STGM_CREATE,
+ 0,
+ 0,
+ lplpTempColor)
+ !=S_OK
+ )
+ TestDebugOut(TEXT("CreateStreams fails\n"));
+
+ // create a stream to save the size
+ if (
+ lpStg->CreateStream ( OLESTR("size"),
+ STGM_READWRITE | STGM_SHARE_EXCLUSIVE |
+ STGM_CREATE,
+ 0,
+ 0,
+ lplpTempSize)
+ !=S_OK
+ )
+ TestDebugOut(TEXT("CreateStreams fails\n"));
+}
diff --git a/private/oleutest/simpsvr/ips.h b/private/oleutest/simpsvr/ips.h
new file mode 100644
index 000000000..b779691e1
--- /dev/null
+++ b/private/oleutest/simpsvr/ips.h
@@ -0,0 +1,50 @@
+//**********************************************************************
+// File name: ips.h
+//
+// Definition of CPersistStorage
+//
+// Copyright (c) 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+
+#if !defined( _IPS_H_)
+#define _IPS_H_
+
+
+#include <ole2.h>
+#include "obj.h"
+
+class CSimpSvrObj;
+
+interface CPersistStorage : IPersistStorage
+{
+private:
+ CSimpSvrObj FAR * m_lpObj;
+ BOOL m_fSameAsLoad;
+
+public:
+ CPersistStorage::CPersistStorage(CSimpSvrObj FAR * lpSimpSvrObj)
+ {
+ m_lpObj = lpSimpSvrObj;
+ };
+ CPersistStorage::~CPersistStorage() {};
+
+ STDMETHODIMP QueryInterface (REFIID riid, LPVOID FAR* ppvObj);
+ STDMETHODIMP_(ULONG) AddRef ();
+ STDMETHODIMP_(ULONG) Release ();
+
+ STDMETHODIMP InitNew (LPSTORAGE pStg);
+ STDMETHODIMP GetClassID ( LPCLSID lpClassID) ;
+ STDMETHODIMP Save ( LPSTORAGE pStgSave, BOOL fSameAsLoad) ;
+ STDMETHODIMP SaveCompleted ( LPSTORAGE pStgNew);
+ STDMETHODIMP Load ( LPSTORAGE pStg);
+ STDMETHODIMP IsDirty ();
+ STDMETHODIMP HandsOffStorage ();
+
+ void ReleaseStreamsAndStorage();
+ void OpenStreams(LPSTORAGE lpStg);
+ void CreateStreams(LPSTORAGE lpStg);
+ void CreateStreams(LPSTORAGE lpStg, LPSTREAM FAR *lpTempColor, LPSTREAM FAR *lpTempSize);
+
+};
+
+#endif
diff --git a/private/oleutest/simpsvr/makefile b/private/oleutest/simpsvr/makefile
new file mode 100644
index 000000000..21eedcbe0
--- /dev/null
+++ b/private/oleutest/simpsvr/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/simpsvr/makefile.new b/private/oleutest/simpsvr/makefile.new
new file mode 100644
index 000000000..375852f98
--- /dev/null
+++ b/private/oleutest/simpsvr/makefile.new
@@ -0,0 +1,198 @@
+# ============================================================================
+# File: M A K E F I L E
+#
+# NMAKE description file for the SIMPSVR (in-place server) sample
+#
+# This is a part of the Microsoft OLE 2.0 sample library.
+# Copyright (C) Microsoft Corporation, 1992-1993. All Rights Reserved.
+# ============================================================================
+#
+# Usage: NMAKE (build DEBUG exe)
+# NMAKE DEBUG=0 (build RELEASE exe)
+#
+# ============================================================================
+
+DEBUG=1
+WIN32=1
+MACHINE_TYPE=i386
+APPNAME=simpsvr
+LANG=USA
+
+OPSYS=NT1X
+EXPORT=1
+
+#############################################################################
+# The following needs to be changed when we ship the sample app. Plus the
+# locations of simpsvr.exe and the UI libraries. (Look for D_LIBS, R_LIBS,
+# and $(APPNAME).exe) Also, we don't need the EXPORT above.
+#
+
+!if "$(OPSYS)"=="NT1X"
+OBJDIR=OBJi1d
+
+# Location for NT SDK headers and libraries
+NT_INC_DIR=$(IMPORT)\$(OPSYS)\h\sdk;$(IMPORT)\$(OPSYS)\h\sdk\crt;
+NT_LIB_DIR=$(IMPORT)\$(OPSYS)\lib\$(OBJDIR)
+!else
+OBJDIR=OBJidd
+
+# Location for Chicago SDK headers and libraries
+NT_INC_DIR=$(IMPORT)\CHICAGO\h;$(IMPORT)\CHICAGO\h\crt;
+NT_LIB_DIR=$(IMPORT)\CHICAGO\lib
+!endif
+
+# path for OLE headers and libraries
+!if "$(EXPORT)"=="1"
+OLE232_INC_DIR=$(CAIROLE)\h\export;$(NT_INC_DIR)
+!else
+OLE232_INC_DIR=$(CAIROLE)\h;$(CAIROLE)\common;$(NT_INC_DIR)
+!endif # EXPORT
+
+OLE232_LIB_DIR=$(CAIROLE)\ilib\$(OBJDIR);$(NT_LIB_DIR)
+
+# location of the UI libraries
+OLE2UI_DIR=..\ole2ui
+OLE2UI_LIB_DIR=..\ole2ui\$(OBJDIR)
+
+# tools that we are using in this build
+CL=$(IMPORT)\n386\bin\cl
+LINK=$(COMMON)\bin\link
+RC=$(COMMON)\bin\rc
+
+# Ensure that "nmake clean" will pick this file to do the cleaning.
+NMAKE=nmake -f makefile.new
+
+# The location of resources from the UI library
+RES=RESOURCE
+
+#############################################################################
+
+GOAL: set_vars $(APPNAME).exe
+
+PCH=pre
+
+SRCS=$(PCH).cpp app.cpp $(APPNAME).cpp icf.cpp iec.cpp ioipo.cpp ips.cpp \
+ doc.cpp ido.cpp ioipao.cpp ioo.cpp obj.cpp
+
+INCS=$(PCH).h $(APPNAME).h obj.h ioipao.h ioipo.h ioo.h ips.h ido.h iec.h \
+ app.h doc.h
+
+OBJS=$(SRCS:cpp=obj)
+
+#############################################################################
+
+#
+# Set the resource directories. These are the directories where we pull our
+# resources from. You may need to change these to point to the proper location
+# of the OLE2UI resources, or just copy all the .DLG and .BMP files into your
+# project's directory.
+#
+
+!if "$(RES_DIRS)"==""
+RES_DIRS = $(OLE2UI_DIR)\$(RES)\STATIC;$(OLE2UI_DIR)\$(RES)\$(LANG)
+!endif
+
+!if "$(WIN32)"=="1"
+#
+# 32-bit C/C++ Compiler
+#
+G_LIBS=advapi32.lib crtdll.lib gdi32.lib kernel32.lib user32.lib ntdll.lib \
+ ole232.lib storag32.lib compob32.lib
+WIN32FLAGS= /DUNICODE /D_WINDOWS /D_UNICODE /DINC_OLE2 /D_MT /DSTRICT \
+ /Di386=1 /D_X86_=1
+# For Chicago Build
+!if "$(OPSYS)"=="DOS"
+WIN32FLAGS=$(WIN32FLAGS) /D_INC_OLE /DWIN32=200 /D_CHICAGO_=200
+!else
+WIN32FLAGS=$(WIN32FLAGS) /DWIN32=100
+!endif
+G_CPPFLAGS=/G4f /W3 /Zp8 /Gz $(WIN32FLAGS) /Gys /Yu$(PCH).h
+D_CPPFLAGS=/Z7 /Od /D_DEBUG /DDBG=1
+R_CPPFLAGS=/O1 /Gs /Ogit
+G_LINKFLAGS=/NOD /MACHINE:$(MACHINE_TYPE) /SECTION:.rsrc,r \
+ /SECTION:.guids,r /merge:.CRT=.data /STACK:16384
+D_LINKFLAGS=/DEBUGTYPE:both,fixup /DEBUG:mapped,full
+R_LINKFLAGS=/RELEASE
+D_LIBS=$(OLE2UI_DIR)\$(OBJDIR)\ole2uixd.lib #..\lib\moleuicd
+R_LIBS=$(OLE2UI_DIR)\$(OBJDIR)\ole2uix.lib #..\lib\moleuic
+!else
+#
+# 16-bit C/C++ Compiler
+#
+G_LIBS=ole2 compobj storage libw shell
+G_CPPFLAGS=/AM /G2 /W3 /Zp /Yu$(PCH).h /GA /GEs
+D_CPPFLAGS=/Zi /Od /f /D_DEBUG
+R_CPPFLAGS=/O1 /Gs
+G_LINKFLAGS=/NOD /ONERROR:NOEXE /NOE /BATCH /STACK:16384
+D_LINKFLAGS=/COD
+R_LINKFLAGS=/FAR /PACKC
+D_LIBS=mlibcew ..\lib\moleuicd
+R_LIBS=mlibcew ..\lib\moleuic
+!endif
+
+!if "$(DEBUG)"=="0"
+CPPFLAGS=$(G_CPPFLAGS) $(R_CPPFLAGS)
+LINKFLAGS=$(G_LINKFLAGS) $(R_LINKFLAGS)
+LIBS=$(R_LIBS) $(G_LIBS)
+!else
+CPPFLAGS=$(G_CPPFLAGS) $(D_CPPFLAGS)
+LINKFLAGS=$(G_LINKFLAGS) $(D_LINKFLAGS)
+LIBS=$(D_LIBS) $(G_LIBS)
+!endif #//DEBUG
+
+#############################################################################
+
+set_vars:
+ set INCLUDE=$(OLE232_INC_DIR);$(OLE2UI_DIR);$(INCLUDE)
+ set LIB=$(OLE232_LIB_DIR);$(OLE2UI_LIB_DIR);$(LIB)
+
+#############################################################################
+
+$(APPNAME).exe: $(OBJS) $(APPNAME).def $(APPNAME).res
+!if "$(WIN32)"=="1"
+ $(LINK) $(LINKFLAGS) @<<
+$(OBJS: = ^
+)
+$(LIBS: = ^
+)
+$(APPNAME).res
+/MAP:$(APPNAME).map
+/OUT:$(APPNAME).exe
+<<
+!else
+ $(LINK) $(LINKFLAGS) @<<
+$(OBJS: = +^
+),
+$(APPNAME),
+$(APPNAME),
+$(LIBS: = +^
+),
+$(APPNAME);
+<<
+ $(RC) /k /t $(APPNAME).res
+!endif
+
+$(PCH).obj: $(INCS) $(PCH).cpp
+ $(NMAKE) clean
+ $(CL) $(CPPFLAGS) /Yc$(PCH).h /c $(PCH).cpp
+
+.cpp.obj:
+ $(CL) @<<
+$(CPPFLAGS) /c $<
+<<
+
+$(APPNAME).res: resource.h $(APPNAME).h
+ $(RC) /r /I$(RES_DIRS) $(APPNAME).rc
+
+clean:
+ if exist $(APPNAME).exe erase $(APPNAME).exe
+ if exist *.pch erase *.pch
+ if exist *.obj erase *.obj
+ if exist *.sbr erase *.sbr
+ if exist *.pdb erase *.pdb
+ if exist *.map erase *.map
+ if exist *.res erase *.res
+ if exist *.aps erase *.aps
+ if exist *.bsc erase *.bsc
+ if exist *.wsp erase *.wsp
+ if exist *.vcw erase *.vcw
diff --git a/private/oleutest/simpsvr/obj.cpp b/private/oleutest/simpsvr/obj.cpp
new file mode 100644
index 000000000..586c20347
--- /dev/null
+++ b/private/oleutest/simpsvr/obj.cpp
@@ -0,0 +1,1151 @@
+//**********************************************************************
+// File name: obj.cpp
+//
+// Implementation file for the CSimpSvrApp Class
+//
+// Functions:
+//
+// See obj.h for a list of member functions.
+//
+// Copyright (c) 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+
+#include "pre.h"
+#include "obj.h"
+#include "ioo.h"
+#include "ido.h"
+#include "ips.h"
+#include "icf.h"
+#include "ioipao.h"
+#include "ioipo.h"
+#include "app.h"
+#include "doc.h"
+
+//**********************************************************************
+//
+// CSimpSvrObj::QueryInterface
+//
+// Purpose:
+//
+// Used for interface negotiation at the "Object" level.
+//
+// Parameters:
+//
+// REFIID riid - A reference to the interface that is
+// being queried.
+//
+// LPVOID FAR* ppvObj - An out parameter to return a pointer to
+// the interface.
+//
+// Return Value:
+//
+// S_OK - The interface is supported.
+// E_NOINTERFACE - The interface is not supported
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// ResultFromScode OLE API
+// IUnknown::AddRef OBJ.CPP, IOO.CPP, IDO.CPP, IPS.CPP
+// IOIPO.CPP, IOIPAO.CPP
+//
+//
+//********************************************************************
+
+STDMETHODIMP CSimpSvrObj::QueryInterface ( REFIID riid, LPVOID FAR* ppvObj)
+{
+ TestDebugOut(TEXT("In CSimpSvrObj::QueryInterface\r\n"));
+
+ SCODE sc = S_OK;
+
+ if (IsEqualIID(riid, IID_IUnknown))
+ *ppvObj = this;
+ else if (IsEqualIID(riid, IID_IOleObject))
+ *ppvObj = &m_OleObject;
+ else if (IsEqualIID(riid, IID_IDataObject))
+ *ppvObj = &m_DataObject;
+ else if ( IsEqualIID(riid, IID_IPersistStorage) ||
+ IsEqualIID(riid, IID_IPersist) )
+ *ppvObj = &m_PersistStorage;
+ else if (IsEqualIID(riid, IID_IOleInPlaceObject))
+ *ppvObj = &m_OleInPlaceObject;
+ else if (IsEqualIID(riid, IID_IOleInPlaceActiveObject))
+ *ppvObj = &m_OleInPlaceActiveObject;
+ else
+ if (IsEqualIID(riid, IID_IExternalConnection))
+ *ppvObj = &m_ExternalConnection;
+ else
+ {
+ *ppvObj = NULL;
+ sc = E_NOINTERFACE;
+ }
+
+ if (*ppvObj)
+ ((LPUNKNOWN)*ppvObj)->AddRef();
+
+ return ResultFromScode( sc );
+}
+
+//**********************************************************************
+//
+// CSimpSvrObj::AddRef
+//
+// Purpose:
+//
+// Adds to the reference count at the Object level.
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// ULONG - The new reference count of the Object.
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// CSimpSvrDoc::AddRef DOC.CPP
+//
+// Comments:
+//
+// Due to the reference counting model that is used in this
+// implementation, this reference count is the sum of the
+// reference counts on all interfaces. (ie IDataObject,
+// IExternalConnection, IPersistStorage, IOleInPlaceActiveObject,
+// IOleObject, IOleInPlaceObject)
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) CSimpSvrObj::AddRef ()
+{
+ TestDebugOut(TEXT("In CSimpSvrObj::AddRef\r\n"));
+
+ m_lpDoc->AddRef();
+
+ return ++m_nCount;
+}
+
+//**********************************************************************
+//
+// CSimpSvrObj::Release
+//
+// Purpose:
+//
+// Decrements the reference count at this level
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// ULONG - The new reference count of the object.
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// CSimpSvrDoc::Release DOC.CPP
+// CSimpSvrDoc::ClearObj DOC.H
+//
+// Comments:
+//
+// Due to the reference counting model that is used in this
+// implementation, this reference count is the sum of the
+// reference counts on all interfaces. (ie IDataObject,
+// IExternalConnection, IPersistStorage, IOleInPlaceActiveObject,
+// IOleObject, IOleInPlaceObject)
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) CSimpSvrObj::Release ()
+{
+ TestDebugOut(TEXT("In CSimpSvrObj::Release\r\n"));
+
+ /* The SimpSvrObj destructor needs to access SimpSvrDoc. We want to
+ * hold on to the SimpSvrDoc object until we have deleted our own.
+ */
+ CSimpSvrDoc *lpDoc=m_lpDoc;
+
+ if (--m_nCount== 0)
+ {
+ /* We still have Doc object. But SimpSvrObj object is going away.
+ * So, we need to clear the obj pointer in the Doc object.
+ */
+ lpDoc->ClearObj();
+
+ delete this;
+
+ lpDoc->Release();
+ return(0);
+ }
+
+ lpDoc->Release();
+ return m_nCount;
+}
+
+//**********************************************************************
+//
+// CSimpSvrObj::CSimpSvrObj
+//
+// Purpose:
+//
+// Constructor for CSimpSvrObj. Initialize the members variables
+//
+// Parameters:
+//
+// CSimpSvrDoc FAR * lpSimpSvrDoc - ptr to the doc object
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+//
+//********************************************************************
+#pragma warning (disable : 4355)
+ // "this" used in base initializer list warning. This
+ // can be disabled because we are not using "this" in
+ // the constructor for these objects, rather we are
+ // just storing it for future use...
+CSimpSvrObj::CSimpSvrObj(CSimpSvrDoc FAR * lpSimpSvrDoc) :
+ m_OleObject(this),
+ m_DataObject(this),
+ m_PersistStorage(this),
+ m_OleInPlaceActiveObject(this),
+ m_OleInPlaceObject(this),
+ m_ExternalConnection(this)
+#pragma warning (default : 4355) // Turn the warning back on
+
+{
+ m_lpDoc = lpSimpSvrDoc;
+ m_nCount = 0;
+ m_fInPlaceActive = FALSE;
+ m_fInPlaceVisible = FALSE;
+ m_fUIActive = FALSE;
+ m_hmenuShared = NULL;
+ m_hOleMenu = NULL;
+
+ m_dwRegister = 0;
+
+ m_lpFrame = NULL;
+ m_lpCntrDoc = NULL;
+
+ m_lpStorage = NULL;
+ m_lpColorStm = NULL;
+ m_lpSizeStm = NULL;
+ m_lpOleClientSite = NULL;
+ m_lpOleAdviseHolder = NULL;
+ m_lpDataAdviseHolder = NULL;
+ m_lpIPSite = NULL;
+
+ // The default object is red
+ m_red = 128;
+ m_green = 0;
+ m_blue = 0;
+
+ m_size.x = 100;
+ m_size.y = 100;
+
+ m_xOffset = 0;
+ m_yOffset = 0;
+
+ m_scale = 1.0F;
+
+ m_fSaveWithSameAsLoad = FALSE;
+ m_fNoScribbleMode = FALSE;
+
+}
+
+//**********************************************************************
+//
+// CSimpSvrObj::~CSimpSvrObj
+//
+// Purpose:
+//
+// Destructor for CSimpSvrObj
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+// None
+//
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// PostMessage Windows API
+// CSimpSvrDoc::GetApp DOC.H
+// CSimpSvrDoc::GethAppWnd DOC.H
+// CSimpSvrApp::IsStartedByOle APP.CPP
+// IDataAdviseHolder OLE
+// IOleAdviseHolder OLE
+// IOleClientSite OLE
+//
+// Comment:
+// We need to release the DataAdviseHolder, OleClientSite and
+// OleAdviseHolder if they are created by our CSimpSvrObj.
+//
+//
+//********************************************************************
+
+CSimpSvrObj::~CSimpSvrObj()
+{
+ TestDebugOut(TEXT("In CSimpSvrObj's Destructor \r\n"));
+
+ // if we were started by ole, post ourselves a close message
+ if (m_lpDoc->GetApp()->IsStartedByOle())
+ PostMessage(m_lpDoc->GethAppWnd(), WM_SYSCOMMAND, SC_CLOSE, 0L);
+
+ /* We need to release our Data Advise Holder when we destroy our
+ * object.
+ */
+ if (m_lpDataAdviseHolder)
+ {
+ m_lpDataAdviseHolder->Release();
+ }
+
+ if (m_lpOleAdviseHolder)
+ {
+ m_lpOleAdviseHolder->Release();
+ }
+
+ if (m_lpOleClientSite)
+ {
+ m_lpOleClientSite->Release();
+ }
+}
+
+//**********************************************************************
+//
+// CSimpSvrObj::Draw
+//
+// Purpose:
+//
+// Draws the object into an arbitrary DC
+//
+// Parameters:
+//
+// HDC hDC - DC to draw into
+//
+// Return Value:
+//
+// NONE
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// CreateBrushIndirect Windows API
+// SelectObject Windows API
+// Rectangle Windows API
+// DeleteObject Windows API
+//
+//
+//********************************************************************
+
+void CSimpSvrObj::Draw (HDC hDC, BOOL m_fMeta)
+{
+ LOGBRUSH lb;
+
+ TestDebugOut(TEXT("In CSimpSvrObj::Draw\r\n"));
+
+ TCHAR szBuffer[255];
+
+ wsprintf(szBuffer, TEXT("Drawing Scale %3d\r\n"),m_scale);
+
+ TestDebugOut(szBuffer);
+
+ if (!m_fMeta)
+ {
+ SetMapMode(hDC, MM_ANISOTROPIC);
+ SetWindowOrg(hDC, (int)(m_xOffset/m_scale), (int)(m_yOffset/m_scale));
+ SetWindowExt(hDC, m_size.x, m_size.y);
+ SetViewportExt(hDC, (int)(m_size.x*m_scale), (int)(m_size.y*m_scale));
+ }
+
+ // fill out a LOGBRUSH
+ lb.lbStyle = BS_SOLID;
+ lb.lbColor = RGB(m_red, m_green, m_blue);
+ lb.lbHatch = 0;
+
+ // create the brush
+ HBRUSH hBrush = CreateBrushIndirect(&lb);
+
+ // select the brush
+ HBRUSH hOldBrush = (HBRUSH) SelectObject(hDC, hBrush);
+ HPEN hPen = CreatePen(PS_INSIDEFRAME, 6, RGB(0, 0, 0));
+
+ HPEN hOldPen = (HPEN) SelectObject(hDC, hPen);
+
+ // draw the rectangle
+ Rectangle (hDC, 0, 0, m_size.x, m_size.y);
+
+ // restore the pen
+ hPen = (HPEN) SelectObject(hDC, hOldPen);
+
+ // free the pen
+ DeleteObject(hPen);
+
+ // restore the old brush
+ hBrush = (HBRUSH) SelectObject(hDC, hOldBrush);
+
+ // free the brush
+ DeleteObject(hBrush);
+}
+
+//**********************************************************************
+//
+// CSimpSvrObj::GetMetaFilePict
+//
+// Purpose:
+//
+// Returns a handle to a metafile representation of the object.
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// Handle to the metafile.
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// GlobalAlloc Windows API
+// GlobalLock Windows API
+// SetWindowOrg Windows API
+// SetWindowExt Windows API
+// CreateMetaFile Windows API
+// CloseMetaFile Windows API
+// GlobalUnlock Windows API
+// XformWidthInPixelsToHimetric OLE2UI
+// XformHeightInPixelsToHimetric OLE2UI
+// CSimpSvrObj::Draw OBJ.CPP
+//
+//
+//********************************************************************
+
+HANDLE CSimpSvrObj::GetMetaFilePict()
+{
+ HANDLE hMFP;
+ METAFILEPICT FAR * lpMFP;
+ POINT pt;
+
+ TestDebugOut(TEXT("In CSimpSvrObj::GetMetaFilePict\r\n"));
+
+ // allocate the memory for the METAFILEPICT structure
+ hMFP = GlobalAlloc (GMEM_SHARE | GHND, sizeof (METAFILEPICT) );
+ if (!hMFP)
+ {
+ /* GlobalAlloc fails. Cannot allocate global memory.
+ */
+ return(NULL);
+ }
+ lpMFP = (METAFILEPICT FAR*) GlobalLock(hMFP);
+ if (!lpMFP)
+ {
+ /* Cannot lock the allocated memory.
+ */
+ return(NULL);
+ }
+
+ // get the size of the object in HIMETRIC
+ pt.x = XformWidthInPixelsToHimetric(NULL, m_size.x);
+ pt.y = XformHeightInPixelsToHimetric(NULL, m_size.y);
+
+ // fill out the METAFILEPICT structure
+ lpMFP->mm = MM_ANISOTROPIC;
+ lpMFP->xExt = pt.x;
+ lpMFP->yExt = pt.y;
+
+ // Create the metafile
+ HDC hDC = CreateMetaFile(NULL);
+
+ if (hDC)
+ {
+ SetWindowOrg (hDC, 0, 0);
+ SetWindowExt (hDC, m_size.x,
+ m_size.y);
+
+ Draw(hDC);
+
+ lpMFP->hMF = CloseMetaFile(hDC);
+ }
+
+ // unlock the metafilepict
+ GlobalUnlock(hMFP);
+
+ return hMFP;
+}
+
+
+//**********************************************************************
+//
+// CSimpSvrObj::SaveToStorage
+//
+// Purpose:
+//
+// Saves the object to the passed storage
+//
+// Parameters:
+//
+// LPSTORAGE lpStg - Storage in which to save the object
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// IStorage::CreateStream OLE
+// IStream::Write OLE
+// IStream::Release OLE
+//
+// Comments:
+//
+// A real app will want to do better error checking / returning
+//
+//********************************************************************
+
+void CSimpSvrObj::SaveToStorage (LPSTORAGE lpStg, BOOL fSameAsLoad)
+{
+ TestDebugOut(TEXT("In CSimpSvrObj::SaveToStorage\r\n"));
+
+ LPSTREAM lpTempColor, lpTempSize;
+
+ if (!fSameAsLoad)
+ m_PersistStorage.CreateStreams( lpStg, &lpTempColor, &lpTempSize);
+ else
+ {
+ lpTempColor = m_lpColorStm;
+ lpTempColor->AddRef();
+ lpTempSize = m_lpSizeStm;
+ lpTempSize->AddRef();
+ }
+
+ ULARGE_INTEGER uli;
+
+ uli.LowPart = 0;
+ uli.HighPart = 0;
+
+ if ( lpTempColor->SetSize(uli) != S_OK )
+ goto EXIT; // we don't want to proceed further if fails
+ if ( lpTempSize->SetSize(uli) != S_OK )
+ goto EXIT;
+
+ LARGE_INTEGER li;
+
+ li.LowPart = 0;
+ li.HighPart = 0;
+
+ if ( lpTempColor->Seek(li, STREAM_SEEK_SET, NULL) != S_OK )
+ goto EXIT;
+ if ( lpTempSize->Seek(li, STREAM_SEEK_SET, NULL) != S_OK )
+ goto EXIT;
+
+ // write the colors to the stream
+ if ( lpTempColor->Write(&m_red, sizeof(m_red), NULL) != S_OK )
+ goto EXIT;
+ if ( lpTempColor->Write(&m_green, sizeof(m_green), NULL) != S_OK )
+ goto EXIT;
+ if ( lpTempColor->Write(&m_blue, sizeof(m_blue), NULL) != S_OK )
+ goto EXIT;
+
+ // write the size to the stream
+ if ( lpTempSize->Write(&m_size, sizeof(m_size), NULL) != S_OK )
+ goto EXIT;
+
+ TestDebugOut(TEXT("SaveToStorage exits normally\n"));
+
+EXIT:
+ lpTempColor->Release();
+ lpTempSize->Release();
+}
+
+//**********************************************************************
+//
+// CSimpSvrObj::LoadFromStorage
+//
+// Purpose:
+//
+// Loads the object from the passed storage
+//
+// Parameters:
+//
+// LPSTORAGE lpStg - Storage in which to load the object from
+//
+// Return Value:
+//
+// None.
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// IStorage::OpenStream OLE
+// IStream::Read OLE
+// IStream::Release OLE
+//
+//
+//********************************************************************
+
+void CSimpSvrObj::LoadFromStorage ()
+{
+ TestDebugOut(TEXT("In CSimpSvrObj::LoadFromStorage\r\n"));
+
+ // Read the colors
+ if ( m_lpColorStm->Read(&m_red, sizeof(m_red), NULL) != S_OK )
+ return;
+ if ( m_lpColorStm->Read(&m_green, sizeof(m_green), NULL) != S_OK )
+ return;
+ if ( m_lpColorStm->Read(&m_blue, sizeof(m_blue), NULL) != S_OK )
+ return;
+
+ // read the size
+ if ( m_lpSizeStm->Read(&m_size, sizeof(m_size), NULL) != S_OK )
+ return;
+
+ TestDebugOut(TEXT("LoadFromStorage exits normally\n"));
+
+}
+
+//**********************************************************************
+//
+// CSimpSvrObj::DoInPlaceActivate
+//
+// Purpose:
+//
+// Does the inplace activation for the object
+//
+// Parameters:
+//
+// LONG lVerb - Verb that caused this function to be called
+//
+// Return Value:
+//
+// TRUE/FALSE depending on success or failure.
+//
+// Function Calls:
+// Function Location
+//
+// IOleClientSite::QueryInterface Container
+// IOleClientSite::ShowObject Container
+// IOleInPlaceSite::CanInPlaceActivate Container
+// IOleInPlaceSite::Release Container
+// IOleInPlaceSite::OnInPlaceActivate Container
+// IOleInPlaceSite::GetWindow Container
+// IOleInPlaceSite::GetWindowContext Container
+// IOleInPlaceSite::OnUIActivate Container
+// IOleInPlaceSite::Release Container
+// IOleInPlaceFrame::SetActiveObject Container
+// IOleInPlaceUIWindow::SetActiveObject Container
+// TestDebugOut Windows API
+// ShowWindow Windows API
+// SetParent Windows API
+// IntersectRect Windows API
+// OffsetRect Windows API
+// MoveWindow Windows API
+// CopyRect Windows API
+// SetFocus Windows API
+// SetHatchWindowSize OLE2UI
+// CSimpSvrObj::AssembleMenus OBJ.CPP
+// CSimpSvrObj::AddFrameLevelUI OBJ.CPP
+//
+//
+// Comments:
+//
+// Be sure to read TECHNOTES.WRI included with the OLE SDK
+// for details on implementing inplace activation.
+//
+//********************************************************************
+
+BOOL CSimpSvrObj::DoInPlaceActivate (LONG lVerb)
+{
+ BOOL retval = FALSE;
+ RECT posRect, clipRect;
+
+
+ TestDebugOut(TEXT("In CSimpSvrObj::DoInPlaceActivate\r\n"));
+
+ // if not currently in place active
+ if (!m_fInPlaceActive)
+ {
+ // get the inplace site
+ if (m_lpOleClientSite->QueryInterface(IID_IOleInPlaceSite,
+ (LPVOID FAR *)&m_lpIPSite) != NOERROR)
+ goto error;
+
+
+ // if the inplace site could not be obtained, or refuses to inplace
+ // activate then goto error.
+ if (m_lpIPSite == NULL || m_lpIPSite->CanInPlaceActivate() != NOERROR)
+ {
+ if (m_lpIPSite)
+ m_lpIPSite->Release();
+ m_lpIPSite = NULL;
+ goto error;
+ }
+
+ // tell the site that we are activating.
+ if (m_lpIPSite->OnInPlaceActivate() != S_OK)
+ TestDebugOut(TEXT("OnInPlaceActivate fails\n"));
+
+ m_fInPlaceActive = TRUE;
+ }
+
+ // if not currently inplace visibl
+ if (!m_fInPlaceVisible)
+ {
+ m_fInPlaceVisible = TRUE;
+
+ // get the window handle of the site
+ if (m_lpIPSite->GetWindow(&m_hWndParent) != S_OK)
+ TestDebugOut(TEXT("GetWindow fails\n"));
+
+ // get window context from the container
+ m_FrameInfo.cb = sizeof(OLEINPLACEFRAMEINFO);
+ if (m_lpIPSite->GetWindowContext ( &m_lpFrame,
+ &m_lpCntrDoc,
+ &posRect,
+ &clipRect,
+ &m_FrameInfo) != S_OK)
+ TestDebugOut(TEXT("GetWindowContext fails\n"));
+
+ if (sizeof(OLEINPLACEFRAMEINFO) != m_FrameInfo.cb)
+ {
+ TestDebugOut(TEXT("WARNING! GetWindowContext call "
+ "modified FrameInfo.cb!\n"));
+ }
+
+
+ // show the hatch window
+ m_lpDoc->ShowHatchWnd();
+
+ // Set the parenting
+ SetParent (m_lpDoc->GethHatchWnd(), m_hWndParent);
+ SetParent (m_lpDoc->GethDocWnd(), m_lpDoc->GethHatchWnd());
+
+ // tell the client site to show the object
+ if (m_lpOleClientSite->ShowObject() != S_OK)
+ TestDebugOut(TEXT("ShowObject fails\n"));
+
+ RECT resRect;
+
+ // figure out the "real" size of the object
+ IntersectRect(&resRect, &posRect, &clipRect);
+ CopyRect(&m_posRect, &posRect);
+
+ POINT pt;
+
+ // adjust our hatch window size
+ SetHatchWindowSize ( m_lpDoc->GethHatchWnd(),
+ &resRect,
+ &posRect,
+ &pt);
+
+ // calculate the actual object rect inside the hatchwnd.
+ OffsetRect (&resRect, pt.x, pt.y);
+
+ // move the object window
+ MoveWindow(m_lpDoc->GethDocWnd(),
+ resRect.left,
+ resRect.top,
+ resRect.right - resRect.left,
+ resRect.bottom - resRect.top,
+ FALSE);
+
+ // create the combined window
+ AssembleMenus();
+ }
+
+ // if not UIActive
+ if (!m_fUIActive)
+ {
+ m_fUIActive = TRUE;
+
+ // tell the inplace site that we are activating
+ m_lpIPSite->OnUIActivate();
+
+ // set the focus to our object window
+ SetFocus(m_lpDoc->GethDocWnd());
+
+ // set the active object on the frame
+ if (m_lpFrame->SetActiveObject(&m_OleInPlaceActiveObject,
+ OLESTR("Simple OLE 2.0 Server")) != S_OK)
+ TestDebugOut(TEXT("SetActiveObject fails\n"));
+
+ // set the active object on the Doc, if available.
+ if (m_lpCntrDoc)
+ if (m_lpCntrDoc->SetActiveObject(&m_OleInPlaceActiveObject,
+ OLESTR("Simple OLE 2.0 Server")) != S_OK)
+ TestDebugOut(TEXT("SetActiveObjet fails\n"));
+
+ // add the frame level UI.
+ AddFrameLevelUI();
+ }
+
+ retval = TRUE;
+error:
+ return retval;
+}
+
+//**********************************************************************
+//
+// CSimpSvrObj::AssembleMenus
+//
+// Purpose:
+//
+// Creates the combined menus used during inplace activation.
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// CreateMenu Windows API
+// IOleInPlaceFrame::InsertMenus Container
+// InsertMenu Windows API
+// DestroyMenu Windows API
+// OleCreateMenuDescriptor OLE API
+//
+//
+//********************************************************************
+
+void CSimpSvrObj::AssembleMenus()
+{
+ TestDebugOut(TEXT("In CSimpSvrObj::AssembleMenus\r\n"));
+ OLEMENUGROUPWIDTHS menugroupwidths;
+
+ m_hmenuShared = NULL;
+
+ // Create the menu resource
+ m_hmenuShared = CreateMenu();
+
+ // have the contaner insert its menus
+ if (m_lpFrame->InsertMenus (m_hmenuShared, &menugroupwidths) == NOERROR)
+ {
+ int nFirstGroup = (int) menugroupwidths.width[0];
+
+ // insert the server menus
+ InsertMenu( m_hmenuShared, nFirstGroup, MF_BYPOSITION | MF_POPUP,
+ (UINT)m_lpDoc->GetColorMenu(), TEXT("&Color"));
+ menugroupwidths.width[1] = 1;
+ menugroupwidths.width[3] = 0;
+ menugroupwidths.width[5] = 0;
+ }
+ else
+ {
+ // Destroy the menu resource
+ DestroyMenu(m_hmenuShared);
+ m_hmenuShared = NULL;
+ }
+
+ // tell OLE to create the menu descriptor
+ m_hOleMenu = OleCreateMenuDescriptor(m_hmenuShared, &menugroupwidths);
+ if (!m_hOleMenu)
+ TestDebugOut(TEXT("OleCreateMenuDescriptor fails\n"));
+}
+
+//**********************************************************************
+//
+// CSimpSvrObj::AddFrameLevelUI
+//
+// Purpose:
+//
+// Adds the Frame level user interface
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// IOleInPlaceFrame::SetMenu Container
+// IOleInPlaceFrame::SetBorderSpace Container
+// IOleInPlaceUIWindow::SetBorderSpace Container
+// CSimpSvrDoc::GethDocWnd DOC.H
+//
+//
+//********************************************************************
+
+void CSimpSvrObj::AddFrameLevelUI()
+{
+ TestDebugOut(TEXT("In CSimpSvrObj::AddFrameLevelUI\r\n"));
+
+ // add the combined menu
+ if ( m_lpFrame->SetMenu(m_hmenuShared, m_hOleMenu,
+ m_lpDoc->GethDocWnd()) != S_OK )
+ return;
+
+ // do hatched border
+ SetParent (m_lpDoc->GethHatchWnd(), m_hWndParent);
+ SetParent (m_lpDoc->GethDocWnd(), m_lpDoc->GethHatchWnd());
+
+ // set the border space. Normally we would negotiate for toolbar
+ // space at this point. Since this server doesn't have a toolbar,
+ // this isn't needed...
+ if (m_lpFrame)
+ if (m_lpFrame->SetBorderSpace(NULL) != S_OK)
+ return;
+
+ if (m_lpCntrDoc)
+ if (m_lpCntrDoc->SetBorderSpace(NULL) != S_OK)
+ return;
+
+ TestDebugOut(TEXT("AddFrameLevelUI exits\n"));
+
+}
+
+//**********************************************************************
+//
+// CSimpSvrObj::DoInPlaceHide
+//
+// Purpose:
+//
+// Hides the object while inplace actvie
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// SetParent Windows API
+// CSimpSvrDoc::GethDocWnd DOC.H
+// CSimpSvrDoc::GethAppWnd DOC.H
+// CSimpSvrDoc::GethHatchWnd DOC.H
+// CSimpSvrObj::DisassembleMenus OBJ.CPP
+// IOleInPlaceFrame::Release Container
+// IOleInPlaceUIWindow::Release Container
+//
+//
+// Comments:
+//
+// Be sure to read TECHNOTES.WRI included with the OLE SDK
+// for details on implementing inplace activation.
+//
+//********************************************************************
+
+void CSimpSvrObj::DoInPlaceHide()
+{
+ TestDebugOut(TEXT("In CSimpSvrObj::DoInPlaceHide\r\n"));
+
+ // if we aren't inplace visible, then this routine is a NOP,
+ if (!m_fInPlaceVisible)
+ return;
+
+ m_fInPlaceVisible = FALSE;
+
+ // change the parenting
+ SetParent (m_lpDoc->GethDocWnd(), m_lpDoc->GethAppWnd());
+ SetParent (m_lpDoc->GethHatchWnd(),m_lpDoc->GethDocWnd());
+
+ // rip down the combined menus
+ DisassembleMenus();
+
+ // release the inplace frame
+ m_lpFrame->Release();
+
+ m_lpFrame = NULL; // only holding one ref. to frame.
+
+ // release the UIWindow if it is there.
+ if (m_lpCntrDoc)
+ m_lpCntrDoc->Release();
+
+ m_lpCntrDoc = NULL;
+
+}
+
+//**********************************************************************
+//
+// CSimpSvrObj::DisassembleMenus
+//
+// Purpose:
+//
+// Disassembles the combined menus used in inplace activation
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// OleDestroyMenuDescriptor OLE API
+// RemoveMenu Windows API
+// IOleInPlaceFrame::RemoveMenus Container
+// DestroyMenu Windows API
+//
+// Comments:
+//
+// Be sure to read TECHNOTES.WRI included with the OLE SDK
+// for details on implementing inplace activation.
+//
+//********************************************************************
+
+void CSimpSvrObj::DisassembleMenus()
+{
+ // destroy the menu descriptor
+ OleDestroyMenuDescriptor(m_hOleMenu);
+
+ if (m_hmenuShared)
+ {
+ // remove the menus that we added
+ RemoveMenu( m_hmenuShared, 1, MF_BYPOSITION);
+
+ // have the container remove its menus
+ if (m_lpFrame->RemoveMenus(m_hmenuShared) != S_OK)
+ TestDebugOut(TEXT("RemoveMenus fails\n"));
+
+ // Destroy the menu resource
+ DestroyMenu(m_hmenuShared);
+
+ m_hmenuShared = NULL;
+ }
+}
+
+//**********************************************************************
+//
+// CSimpSvrObj::SendOnDataChange
+//
+// Purpose:
+//
+// Uses the data advise holder to send a data change, then updates
+// the ROT to note the time of change.
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// IDataAdviseHolder::SendOnDataChange OLE API
+// GetRunningObjectTable OLE API
+// CoFileTimeNow OLE API
+// IRunningObjectTable::NoteChangeTime OLE API
+//
+//
+//********************************************************************
+
+void CSimpSvrObj::SendOnDataChange()
+{
+ if (m_lpDataAdviseHolder)
+ if (m_lpDataAdviseHolder->SendOnDataChange( (LPDATAOBJECT)
+ &m_DataObject, 0, 0))
+ TestDebugOut(TEXT("SendOnDataChange fails\n"));
+
+ LPRUNNINGOBJECTTABLE lpRot;
+
+ GetRunningObjectTable(0, &lpRot);
+
+ if ( lpRot && m_dwRegister)
+ {
+
+ FILETIME ft;
+ CoFileTimeNow(&ft);
+
+ lpRot->NoteChangeTime(m_dwRegister, &ft);
+
+ lpRot->Release();
+ }
+}
+
+
+//**********************************************************************
+//
+// CSimpSvrObj::DeactivateUI
+//
+// Purpose:
+//
+// Breaks down the inplace ui
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// SetParent Windows API
+// IOleInPlaceUIWindow::SetActiveObject Container
+// IOleInPlaceFrame::SetActiveObject Container
+// IOleInPlaceSite::UIDeactivate Container
+//
+//
+//********************************************************************
+
+void CSimpSvrObj::DeactivateUI()
+{
+ // if not UI active, or no pointer to IOleInPlaceFrame, then
+ // return NOERROR
+ if (!(m_fUIActive || m_lpFrame))
+ return;
+ else
+ {
+ m_fUIActive = FALSE;
+
+ // remove hatching
+ SetParent (m_lpDoc->GethDocWnd(), m_lpDoc->GethAppWnd());
+ SetParent (m_lpDoc->GethHatchWnd(),m_lpDoc->GethDocWnd());
+
+ // if in an MDI container, call SetActiveObject on the DOC.
+ if (m_lpCntrDoc)
+ if (m_lpCntrDoc->SetActiveObject(NULL, NULL) != S_OK)
+ TestDebugOut(TEXT("Fail in SetActiveObject\n"));
+
+ if (m_lpFrame->SetActiveObject(NULL, NULL) != S_OK)
+ TestDebugOut(TEXT("Fail in SetActiveObject\n"));
+
+ // tell the container that our UI is going away.
+ if (m_lpIPSite)
+ if (m_lpIPSite->OnUIDeactivate(FALSE) != S_OK)
+ TestDebugOut(TEXT("Fail in OnUIDeactivate\n"));
+ }
+}
+
diff --git a/private/oleutest/simpsvr/obj.h b/private/oleutest/simpsvr/obj.h
new file mode 100644
index 000000000..e7258802f
--- /dev/null
+++ b/private/oleutest/simpsvr/obj.h
@@ -0,0 +1,141 @@
+//**********************************************************************
+// File name: obj.h
+//
+// Definition of CSimpSvrObj
+//
+// Copyright (c) 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+
+#if !defined( _OBJ_H_)
+#define _OBJ_H_
+
+#include "ioipao.h"
+#include "ioipo.h"
+#include "ioo.h"
+#include "ips.h"
+#include "ido.h"
+#include "iec.h"
+
+class CSimpSvrDoc;
+interface COleObject;
+interface CPersistStorage;
+interface CDataObject;
+interface COleInPlaceActiveObject;
+interface COleInPlaceObject;
+interface CExternalConnection;
+
+class CSimpSvrObj : public IUnknown
+{
+private:
+ CSimpSvrDoc FAR * m_lpDoc; // Back pointer
+ int m_nCount; // reference count
+ BOOL m_fInPlaceActive; // Used during InPlace Negotiation
+ BOOL m_fInPlaceVisible; // " " " " " " " " "
+ BOOL m_fUIActive; // " " " " " " " " "
+ HMENU m_hmenuShared; // " " " " " " " " "
+ HOLEMENU m_hOleMenu; // " " " " " " " " "
+ RECT m_posRect; // " " " " " " " " "
+ OLEINPLACEFRAMEINFO m_FrameInfo;
+ BOOL m_fSaveWithSameAsLoad;
+ BOOL m_fNoScribbleMode;
+
+ DWORD m_dwRegister; // Registered in ROT
+
+ int m_red, m_green, m_blue; // current color
+ POINT m_size; // current size
+ int m_xOffset;
+ int m_yOffset;
+ float m_scale;
+
+ HWND m_hWndParent; // parent window handle
+
+ // interfaces used
+ LPSTORAGE m_lpStorage;
+ LPSTREAM m_lpColorStm, m_lpSizeStm;
+ LPOLECLIENTSITE m_lpOleClientSite; // IOleClientSite
+ LPOLEADVISEHOLDER m_lpOleAdviseHolder; // IOleAdviseHolder
+ LPDATAADVISEHOLDER m_lpDataAdviseHolder; // IDataAdviseHolder
+ LPOLEINPLACEFRAME m_lpFrame; // IOleInPlaceFrame
+ LPOLEINPLACEUIWINDOW m_lpCntrDoc; // IOleInPlaceUIWindow
+ LPOLEINPLACESITE m_lpIPSite; // IOleInPlaceSite
+
+ // interface implemented
+ COleObject m_OleObject; // IOleObject
+ CPersistStorage m_PersistStorage; // IPersistStorage
+ CDataObject m_DataObject; // IDataObject
+ COleInPlaceActiveObject m_OleInPlaceActiveObject; // IOleInPlaceActiveObject
+ COleInPlaceObject m_OleInPlaceObject; // IOleInPlaceObject
+ CExternalConnection m_ExternalConnection;
+
+public:
+ STDMETHODIMP QueryInterface (REFIID riid, LPVOID FAR* ppvObj);
+ STDMETHODIMP_(ULONG) AddRef ();
+ STDMETHODIMP_(ULONG) Release ();
+
+// construction/destruction
+ CSimpSvrObj(CSimpSvrDoc FAR * lpSimpSvrDoc);
+ ~CSimpSvrObj();
+
+// utility functions
+ void Draw(HDC hDC, BOOL fMetaDC = TRUE);
+ void PaintObj(HDC hDC);
+ void lButtonDown(WPARAM wParam,LPARAM lParam);
+ HANDLE GetMetaFilePict();
+ void SaveToStorage (LPSTORAGE lpStg, BOOL fSameAsLoad);
+ void LoadFromStorage ();
+
+// visual editing helper functions
+ BOOL DoInPlaceActivate (LONG lVerb);
+ void AssembleMenus();
+ void AddFrameLevelUI();
+ void DoInPlaceHide();
+ void DisassembleMenus();
+ void SendOnDataChange();
+ void DeactivateUI();
+
+// member variable access
+ inline BOOL IsInPlaceActive() { return m_fInPlaceActive; };
+ inline BOOL IsInPlaceVisible() { return m_fInPlaceVisible; };
+ inline BOOL IsUIActive() { return m_fUIActive; };
+ inline HWND GetParent() { return m_hWndParent; };
+ inline LPSTORAGE GetStorage() { return m_lpStorage; };
+ inline LPOLECLIENTSITE GetOleClientSite() { return m_lpOleClientSite; };
+ inline LPDATAADVISEHOLDER GetDataAdviseHolder() { return m_lpDataAdviseHolder; };
+ inline LPOLEADVISEHOLDER GetOleAdviseHolder() { return m_lpOleAdviseHolder; };
+ inline LPOLEINPLACEFRAME GetInPlaceFrame() { return m_lpFrame; };
+ inline LPOLEINPLACEUIWINDOW GetUIWindow() { return m_lpCntrDoc; };
+ inline LPOLEINPLACESITE GetInPlaceSite() { return m_lpIPSite; };
+ inline COleObject FAR * GetOleObject() { return &m_OleObject; };
+ inline CPersistStorage FAR * GetPersistStorage() { return &m_PersistStorage; };
+ inline CDataObject FAR * GetDataObject() { return &m_DataObject; };
+ inline COleInPlaceActiveObject FAR * GetOleInPlaceActiveObject() { return &m_OleInPlaceActiveObject; };
+ inline COleInPlaceObject FAR * GetOleInPlaceObject() { return &m_OleInPlaceObject; };
+ inline void ClearOleClientSite() { m_lpOleClientSite = NULL; };
+ inline void ClearDataAdviseHolder() { m_lpDataAdviseHolder = NULL; };
+ inline void ClearOleAdviseHolder() { m_lpOleAdviseHolder = NULL; };
+ inline LPRECT GetPosRect() { return &m_posRect; };
+ inline LPPOINT GetSize() { return &m_size; };
+ inline LPOLEINPLACEFRAMEINFO GetFrameInfo() {return &m_FrameInfo;};
+ inline DWORD GetRotRegister() { return m_dwRegister; };
+ inline void ClearDoc() { m_lpDoc = NULL; };
+
+ // member manipulation
+ inline void SetColor (int nRed, int nGreen, int nBlue)
+ { m_red = nRed; m_green = nGreen; m_blue = nBlue; };
+
+ inline void RotateColor()
+ { m_red+=10; m_green+=10; m_blue+=10;};
+
+
+// all of the interface implementations should be friends of this
+// class
+friend interface COleObject;
+friend interface CPersistStorage;
+friend interface CDataObject;
+friend interface COleInPlaceActiveObject;
+friend interface COleInPlaceObject;
+friend interface CExternalConnection;
+
+};
+#endif
+
diff --git a/private/oleutest/simpsvr/pre.cpp b/private/oleutest/simpsvr/pre.cpp
new file mode 100644
index 000000000..9603f4089
--- /dev/null
+++ b/private/oleutest/simpsvr/pre.cpp
@@ -0,0 +1,9 @@
+//**********************************************************************
+// File name: pre.cpp
+//
+// Used for precompiled headers
+//
+// Copyright (c) 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+
+#include "pre.h"
diff --git a/private/oleutest/simpsvr/pre.h b/private/oleutest/simpsvr/pre.h
new file mode 100644
index 000000000..a4354e08b
--- /dev/null
+++ b/private/oleutest/simpsvr/pre.h
@@ -0,0 +1,29 @@
+//**********************************************************************
+// File name: pre.h
+//
+// Used for precompiled headers
+//
+// Copyright (c) 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+
+#if !defined( _PRE_H_)
+#define _PRE_H_
+
+#include <windows.h>
+
+#include <ole2.h>
+#include <ole2ui.h>
+#include <assert.h>
+#include <string.h>
+#include "simpsvr.h"
+#include "resource.h"
+extern "C" void TestDebugOut(LPSTR psz);
+#ifndef WIN32
+/* Since OLE is part of the operating system in Win32, we don't need to
+ * check the version number in Win32.
+ */
+#include <ole2ver.h>
+#endif // WIN32
+
+
+#endif
diff --git a/private/oleutest/simpsvr/readme.txt b/private/oleutest/simpsvr/readme.txt
new file mode 100644
index 000000000..47995de7b
--- /dev/null
+++ b/private/oleutest/simpsvr/readme.txt
@@ -0,0 +1,32 @@
+Simpsvr
+--------
+This sample is the simplest OLE 2.0 object that can be written and
+still support the visual editing feature. The object that this server
+supports is a colored square with a black border.
+
+See the MAKEFILE for compilation instructions.
+
+
+Simple Server Objects Overview
+------------------------------
+Simple server consists of three main objects. The top level is CSimpSvrApp,
+under which is CSimpSvrDoc, and the innermost level is CSimpSvrObj.CSimpSvrApp
+is used to hold all the main window information. (eg. handle to the main
+window, handles to the main, color, and help menus and the application
+instance) Therefore, CSimpSvrApp always exists as long as the simple server
+application is alive. The CSimpSvrApp instantiates the Class Factory, if
+simple server is started as embedding. (ie. started by OLE) The next level
+object is CSimpSvrDoc object. It is instantiated by the time CSimpSvrApp is
+created. It manipulates the document window and also the hatch window.
+(See OLE2UI for detail on the hatch window) The CSimpSvrObj, the innermost
+simple server object, shows six OLE interfaces implementations in its nested
+classes. The six OLE interfaces demonstrated are IOleObject, IPersistStorage,
+IDataObject,IOleInPlaceActiveObject,IOleInPlaceObject,and IExternalConnection.
+These six interfaces are implemented as different classes namely: COleObject,
+CPersistStorage, CDataObject, COleInPlaceActiveObject, COleInPlaceObject,
+and CExternalConnection. The CSimpSvrObj handles the drawing of the object
+and all the OLE connections between the container and the server.
+
+
+
+ \ No newline at end of file
diff --git a/private/oleutest/simpsvr/resource.h b/private/oleutest/simpsvr/resource.h
new file mode 100644
index 000000000..33ab749ae
--- /dev/null
+++ b/private/oleutest/simpsvr/resource.h
@@ -0,0 +1,32 @@
+//{{NO_DEPENDENCIES}}
+// App Studio generated include file.
+// Used by SIMPSVR.RC
+//
+#define IDM_OPEN 102
+#define IDM_SAVE 103
+#define IDM_SAVEAS 104
+#define IDM_PRINT 105
+#define IDM_EXIT 106
+#define IDM_UNDO 107
+#define IDM_CUT 108
+#define IDM_COPY 109
+#define IDM_PASTE 110
+#define ID_EDIT_INSERTOBJECT 111
+#define IDM_INSERTOBJECT 111
+#define IDM_NEW 112
+#define IDM_RED 113
+#define IDM_GREEN 114
+#define IDM_BLUE 115
+#define IDM_COLOROWNERDR 116
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+
+#define _APS_NEXT_RESOURCE_VALUE 101
+#define _APS_NEXT_COMMAND_VALUE 117
+#define _APS_NEXT_CONTROL_VALUE 1000
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/private/oleutest/simpsvr/simpsvr.cpp b/private/oleutest/simpsvr/simpsvr.cpp
new file mode 100644
index 000000000..deedbae65
--- /dev/null
+++ b/private/oleutest/simpsvr/simpsvr.cpp
@@ -0,0 +1,454 @@
+//**********************************************************************
+// File name: simpsvr.cpp
+//
+// Main source file for the simple OLE 2.0 server
+//
+// Functions:
+//
+// WinMain - Program entry point
+// MainWndProc - Processes messages for the frame window
+// About - Processes messages for the about dialog
+// DocWndProc - Processes messages for the doc window
+//
+// Copyright (c) 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+
+#include "pre.h"
+#include "obj.h"
+#include "app.h"
+#include "doc.h"
+#include "icf.h"
+#include <stdlib.h>
+#include <testmess.h>
+
+#define MEASUREITEMWIDTH 40
+#define MEASUREITEMHEIGHT 40
+
+// This line is needed for the debug utilities in OLE2UI
+extern "C" {
+ OLEDBGDATA_MAIN(TEXT("SIMPSVR"))
+}
+
+BOOL fBeVerbose = FALSE;
+extern "C"
+void TestDebugOut(LPSTR psz)
+{
+ if (fBeVerbose)
+ {
+ OutputDebugStringA(psz);
+ }
+}
+
+CSimpSvrApp FAR * lpCSimpSvrApp;
+CClassFactory FAR * lpClassFactory;
+
+//**********************************************************************
+//
+// WinMain
+//
+// Purpose:
+//
+// Program entry point
+//
+// Parameters:
+//
+// HANDLE hInstance - Instance handle for this instance
+//
+// HANDLE hPrevInstance - Instance handle for the last instance
+//
+// LPSTR lpCmdLine - Pointer to the command line
+//
+// int nCmdShow - Window State
+//
+// Return Value:
+//
+// msg.wParam
+//
+// Function Calls:
+// Function Location
+//
+// CSimpSvrApp::CSimpSvrApp APP.CPP
+// CSimpSvrApp::fInitApplication APP.CPP
+// CSimpSvrApp::fInitInstance APP.CPP
+// CSimpSvrApp::HandleAccelerators APP.CPP
+// CSimpSvrApp::~CSimpSvrApp APP.CPP
+// OleUIInitialize OLE2UI
+// OleUIUninitialize OLE2UI
+// GetMessage Windows API
+// TranslateMessage Windows API
+// DispatchMessage Windows API
+//
+//
+//********************************************************************
+
+int PASCAL WinMain
+#ifdef WIN32
+ (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
+#else
+ (HANDLE hInstance, HANDLE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
+#endif
+{
+ MSG msg;
+ fBeVerbose = GetProfileInt("OLEUTEST","BeVerbose",0);
+
+ if(fBeVerbose == 0)
+ {
+ fBeVerbose = GetProfileInt("OLEUTEST","simpsvr",0);
+ }
+
+ TestDebugOut(TEXT("Starting Simpsvr.....\n"));
+
+ // recommended size for OLE apps
+ SetMessageQueue(96);
+
+ lpCSimpSvrApp = new CSimpSvrApp;
+
+ if (!lpCSimpSvrApp)
+ {
+ /* memory allocation error. We cannot carry on.
+ */
+ MessageBox(NULL, TEXT("Out of Memory"), TEXT("SimpSvr"),
+ MB_SYSTEMMODAL | MB_ICONHAND);
+ return(FALSE);
+ }
+
+ lpCSimpSvrApp->AddRef(); // need the app ref. count at 1 to hold the
+ // app alive.
+
+ lpCSimpSvrApp->ParseCmdLine(lpCmdLine);
+
+ // app initialization
+ if (!hPrevInstance)
+ if (!lpCSimpSvrApp->fInitApplication(hInstance))
+ {
+ // We need to release CSimpSvrApp before we go away
+ lpCSimpSvrApp->Release();
+ return (FALSE);
+ }
+
+ // instance initialization
+ if (!lpCSimpSvrApp->fInitInstance(hInstance, nCmdShow, lpClassFactory))
+ {
+ // We need to release CSimpSvrApp before we go away
+ lpCSimpSvrApp->Release();
+ return (FALSE);
+ }
+
+ /* Initialization required for OLE 2 UI library. This call is
+ ** needed ONLY if we are using the static link version of the UI
+ ** library. If we are using the DLL version, we should NOT call
+ ** this function in our application.
+ ** The 3rd and 4th parameters passed the OleUIInitialize
+ ** function are strings which are used to name two custom
+ ** control classes used by the OLE2UI library. These strings
+ ** must be unique for each application that uses the OLE2UI
+ ** library. These strings are typically composed by combining
+ ** the APPNAME with a suffix in order to be unique for a
+ ** particular application. The special symbols "SZCLASSICONBOX"
+ ** and "SZCLASSRESULTIMAGE" are used define these strings. These
+ ** symbols must be defined in a header file that is included
+ ** both in this file AND the resource file that included the
+ ** "OLE2UI.RC" resoure file. These symbols should be used in the
+ ** call to OleUIInitialize and are referenced in the INSOBJ.DLG
+ ** and PASTESPL.DLG resouce files of the OLE2UI library.
+ */
+ if (!OleUIInitialize(hInstance, hPrevInstance, TEXT(SZCLASSICONBOX),
+ TEXT(SZCLASSRESULTIMAGE)))
+ {
+ OleDbgOut(TEXT("Could not initialize OLEUI library\n"));
+
+ // We need to release CSimpSvrApp before we go away
+ lpCSimpSvrApp->Release();
+
+ return FALSE;
+ }
+
+ // message loop
+ while (GetMessage(&msg, NULL, NULL, NULL))
+ {
+ // Is this an accelerator for us? -- Remember that this server
+ // only has one window and only processes one object at a time.
+ if (TranslateAccelerator(lpCSimpSvrApp->GethAppWnd(),
+ lpCSimpSvrApp->m_hAccel, &msg))
+ {
+ // Yes -- so we can loop for the next message
+ continue;
+ }
+
+ if (lpCSimpSvrApp->IsInPlaceActive())
+ {
+ // Only key messages need to be sent to OleTranslateAccelerator.
+ // Any other message would result in an extra FAR call to occur
+ // for that message processing...
+
+ if ((msg.message >= WM_KEYFIRST) && (msg.message <= WM_KEYLAST))
+ {
+ // OleTranslateAccelerator MUST be called, even though this
+ // application does not have an accelerator table. This has
+ // to be done in order for the mneumonics for the top level
+ // menu items to work properly.
+
+ if (OleTranslateAccelerator(
+ lpCSimpSvrApp->GetDoc()->GetObj()->GetInPlaceFrame(),
+ lpCSimpSvrApp->GetDoc()->GetObj()->GetFrameInfo(),
+ &msg) == NOERROR)
+ {
+ continue;
+ }
+ }
+ }
+
+ TranslateMessage(&msg); /* Translates virtual key codes */
+ DispatchMessage(&msg); /* Dispatches message to window */
+ }
+
+ // De-initialization for UI libraries. Just like OleUIInitialize, this
+ // funciton is needed ONLY if we are using the static link version of the
+ // OLE UI library.
+ OleUIUninitialize();
+
+ return (msg.wParam); /* Returns the value from PostQuitMessage */
+}
+
+
+//**********************************************************************
+//
+// MainWndProc
+//
+// Purpose:
+//
+// Processes messages for the main frame window
+//
+// Parameters:
+//
+// HWND hWnd - Window handle for frame window
+//
+// UINT message - Message value
+//
+// WPARAM wParam - Message info
+//
+// LPARAM lParam - Message info
+//
+// Return Value:
+//
+// long
+//
+// Function Calls:
+// Function Location
+//
+// CSimpSvrApp::lCommandHandler APP.CPP
+// CSimpSvrApp::DestroyDocs APP.CPP
+// CSimpSvrApp::lCreateDoc APP.CPP
+// CSimpSvrApp::lSizeHandler APP.CPP
+// CGameDoc::lAddVerbs DOC.CPP
+// PostQuitMessage Windows API
+// DefWindowProc Windows API
+//
+//
+//********************************************************************
+
+long FAR PASCAL EXPORT MainWndProc(HWND hWnd,UINT message,WPARAM wParam,
+ LPARAM lParam)
+{
+
+ switch (message)
+ {
+ case WM_CLOSE:
+ TestDebugOut(TEXT("*** In WM_CLOSE *** \r\n"));
+
+ // if there is still a document
+ if (lpCSimpSvrApp->GetDoc())
+
+ // if there is still an object within a document
+ if (lpCSimpSvrApp->GetDoc()->GetObj())
+ // this case occurs if there is still
+ // an outstanding Ref count on the object
+ // when the app is trying to go away.
+ // typically this case will occur in
+ // the "open" editing mode.
+ //
+ // Close the document
+ lpCSimpSvrApp->GetDoc()->Close();
+
+ // hide the app window
+ lpCSimpSvrApp->HideAppWnd();
+
+ // if we were started by ole, unregister the class factory,
+ // otherwise remove the ref count on our dummy OLE object
+ if (lpCSimpSvrApp->IsStartedByOle())
+ {
+ if (CoRevokeClassObject(lpCSimpSvrApp->GetRegisterClass())
+ != S_OK)
+ TestDebugOut(TEXT("Fail in CoRevokeClassObject\n"));
+ }
+ else
+ lpCSimpSvrApp->GetOleObject()->Release();
+
+ lpCSimpSvrApp->Release(); // This should close the app.
+
+ break;
+
+ case WM_COMMAND: // message: command from application menu
+ return lpCSimpSvrApp->lCommandHandler(hWnd, message,
+ wParam, lParam);
+ break;
+
+ case WM_CREATE:
+ return lpCSimpSvrApp->lCreateDoc(hWnd, message, wParam, lParam);
+ break;
+
+ case WM_DESTROY: // message: window being destroyed
+ PostQuitMessage(0);
+ break;
+
+ case WM_MEASUREITEM:
+ ((LPMEASUREITEMSTRUCT)lParam)->itemWidth = MEASUREITEMWIDTH;
+ ((LPMEASUREITEMSTRUCT)lParam)->itemHeight = MEASUREITEMHEIGHT;
+ break;
+
+ case WM_DRAWITEM:
+ lpCSimpSvrApp->HandleDrawItem((LPDRAWITEMSTRUCT) lParam);
+ break;
+
+ case WM_SIZE:
+ return lpCSimpSvrApp->lSizeHandler(hWnd, message, wParam, lParam);
+
+ default: // Passes it on if unproccessed
+ return (DefWindowProc(hWnd, message, wParam, lParam));
+ }
+ return (NULL);
+}
+
+
+//**********************************************************************
+//
+// About
+//
+// Purpose:
+//
+// Processes dialog box messages
+//
+// Parameters:
+//
+// HWND hWnd - Window handle for dialog box
+//
+// UINT message - Message value
+//
+// WPARAM wParam - Message info
+//
+// LPARAM lParam - Message info
+//
+// Return Value:
+//
+//
+// Function Calls:
+// Function Location
+//
+// EndDialog Windows API
+//
+//
+//********************************************************************
+
+BOOL
+#ifdef WIN32
+ CALLBACK
+#else
+ FAR PASCAL EXPORT
+#endif
+ About(HWND hDlg,UINT message,WPARAM wParam,LPARAM lParam)
+{
+ switch (message)
+ {
+ case WM_INITDIALOG: /* message: initialize dialog box */
+ return (TRUE);
+
+ case WM_COMMAND: /* message: received a command */
+ if (wParam == IDOK /* "OK" box selected? */
+ || wParam == IDCANCEL) /* System menu close command? */
+ {
+ EndDialog(hDlg, TRUE); /* Exits the dialog box */
+ return (TRUE);
+ }
+ break;
+ }
+ return (FALSE); /* Didn't process a message */
+}
+
+//**********************************************************************
+//
+// DocWndProc
+//
+// Purpose:
+//
+// Processes dialog box messages
+//
+// Parameters:
+//
+// HWND hWnd - Window handle for doc window
+//
+// UINT message - Message value
+//
+// WPARAM wParam - Message info
+//
+// LPARAM lParam - Message info
+//
+// Return Value:
+//
+// Function Calls:
+// Function Location
+//
+// CSimpSvrApp::PaintApp APP.CPP
+// BeginPaint Windows API
+// EndPaint Windows API
+// DefWindowProc Windows API
+// IOleObject::QueryInterface Object
+// IOleInPlaceObject::UIDeactivate Object
+// IOleObject::DoVerb Object
+// IOleInPlaceObject::Release Object
+//
+//
+//********************************************************************
+
+long FAR PASCAL EXPORT DocWndProc(HWND hWnd,UINT message,WPARAM wParam,
+ LPARAM lParam)
+{
+ HDC hDC;
+ PAINTSTRUCT ps;
+
+ switch (message)
+ {
+ case WM_COMMAND: // message: command from application menu
+ return lpCSimpSvrApp->lCommandHandler(hWnd, message,
+ wParam, lParam);
+ break;
+
+ case WM_PAINT:
+ hDC = BeginPaint(hWnd, &ps);
+
+ // tell the app class to paint itself
+ if (lpCSimpSvrApp)
+ lpCSimpSvrApp->PaintApp (hDC);
+
+ EndPaint(hWnd, &ps);
+ break;
+
+ case WM_MENUSELECT:
+ lpCSimpSvrApp->SetStatusText();
+ break;
+
+ case WM_MEASUREITEM:
+ ((LPMEASUREITEMSTRUCT)lParam)->itemWidth = MEASUREITEMWIDTH;
+ ((LPMEASUREITEMSTRUCT)lParam)->itemHeight = MEASUREITEMHEIGHT;
+ break;
+
+ case WM_DRAWITEM:
+ lpCSimpSvrApp->HandleDrawItem((LPDRAWITEMSTRUCT) lParam);
+ break;
+
+
+ default: /* Passes it on if unproccessed */
+ return (DefWindowProc(hWnd, message, wParam, lParam));
+ }
+ return (NULL);
+}
+
diff --git a/private/oleutest/simpsvr/simpsvr.def b/private/oleutest/simpsvr/simpsvr.def
new file mode 100644
index 000000000..b0bba115b
--- /dev/null
+++ b/private/oleutest/simpsvr/simpsvr.def
@@ -0,0 +1,26 @@
+; module-definition file for generic -- used by LINK.EXE
+
+NAME SIMPSVR ; application's module name
+
+DESCRIPTION 'Sample Microsoft Windows Application'
+
+EXETYPE WINDOWS ; required for all Windows applications
+
+STUB 'WINSTUB.EXE' ; Generates error message if application
+ ; is run without Windows
+
+;CODE can be moved in memory and discarded/reloaded
+CODE PRELOAD MOVEABLE DISCARDABLE
+
+;DATA must be MULTIPLE if program can be invoked more than once
+DATA PRELOAD MOVEABLE MULTIPLE
+
+
+HEAPSIZE 1024
+STACKSIZE 16000
+
+
+; All functions that will be called by any Windows routine
+; MUST be exported.
+
+
diff --git a/private/oleutest/simpsvr/simpsvr.h b/private/oleutest/simpsvr/simpsvr.h
new file mode 100644
index 000000000..df252579a
--- /dev/null
+++ b/private/oleutest/simpsvr/simpsvr.h
@@ -0,0 +1,49 @@
+//**********************************************************************
+// File name: simpsvr.h
+//
+// Copyright (c) 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+#define IDM_ABOUT 100
+#define IDM_INSERT 101
+#define IDM_VERB0 1000
+
+int PASCAL WinMain
+#ifdef WIN32
+ (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow);
+#else
+ (HANDLE hInstance, HANDLE hPrevInstance, LPSTR lpCmdLine, int nCmdShow);
+#endif
+
+BOOL InitApplication(HANDLE hInstance);
+BOOL InitInstance(HANDLE hInstance, int nCmdShow);
+long FAR PASCAL EXPORT MainWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
+long FAR PASCAL EXPORT DocWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
+#ifdef WIN32
+BOOL CALLBACK About(HWND hDlg, UINT message, WORD wParam, LONG lParam);
+#else
+BOOL FAR PASCAL EXPORT About(HWND hDlg, UINT message, WORD wParam, LONG lParam);
+#endif
+
+#define SZCLASSICONBOX "SimpSvrIBClass"
+#define SZCLASSRESULTIMAGE "SimpSvrRIClass"
+
+#ifdef WIN32
+ // The following functions are all obsolete in Win32.
+ // By using the following macros, we can use the app in both Win16 and
+ // Win32
+ #define SetWindowOrg(h,x,y) SetWindowOrgEx((h),(x),(y),NULL)
+ #define SetWindowExt(h,x,y) SetWindowExtEx((h),(x),(y),NULL)
+ #define SetViewportExt(h,x,y) SetViewportExtEx((h),(x),(y),NULL)
+ #ifndef EXPORT
+ #define EXPORT
+ #endif
+#else
+
+ #ifndef EXPORT
+ // _export is obsolete in Win32
+ #define EXPORT _export
+ #endif
+
+#endif
+
+
diff --git a/private/oleutest/simpsvr/simpsvr.ico b/private/oleutest/simpsvr/simpsvr.ico
new file mode 100644
index 000000000..f351bc754
--- /dev/null
+++ b/private/oleutest/simpsvr/simpsvr.ico
Binary files differ
diff --git a/private/oleutest/simpsvr/simpsvr.mak b/private/oleutest/simpsvr/simpsvr.mak
new file mode 100644
index 000000000..213722358
--- /dev/null
+++ b/private/oleutest/simpsvr/simpsvr.mak
@@ -0,0 +1,439 @@
+# Microsoft Visual C++ generated build script - Do not modify
+
+PROJ = SIMPSVR
+DEBUG = 1
+PROGTYPE = 0
+CALLER =
+ARGS =
+DLLS =
+D_RCDEFINES = /d_DEBUG
+R_RCDEFINES = /dNDEBUG
+ORIGIN = MSVC
+ORIGIN_VER = 1.00
+PROJPATH = C:\OLE2SAMP\SIMPSVR\
+USEMFC = 0
+CC = cl
+CPP = cl
+CXX = cl
+CCREATEPCHFLAG =
+CPPCREATEPCHFLAG = /YcPRE.H
+CUSEPCHFLAG =
+CPPUSEPCHFLAG = /YuPRE.H
+FIRSTC =
+FIRSTCPP = PRE.CPP
+RC = rc
+CFLAGS_D_WEXE = /nologo /G2 /W3 /Zi /AM /Od /D "_DEBUG" /FR /GA /Fd"BMGAME.PDB"
+CFLAGS_R_WEXE = /nologo /G2 /W3 /AM /O1 /D "NDEBUG" /FR /GA /Fp"BMGAME.PCH"
+LFLAGS_D_WEXE = /NOLOGO /NOD /ALIGN:16 /ONERROR:NOEXE /CO
+LFLAGS_R_WEXE = /NOLOGO /NOD /ALIGN:16 /ONERROR:NOEXE
+LIBS_D_WEXE = oldnames libw mlibcew ole2 storage ole2uixd commdlg.lib shell.lib
+LIBS_R_WEXE = oldnames libw mlibcew ole2 storage outlui commdlg.lib shell.lib
+RCFLAGS = /nologo
+RESFLAGS = /nologo /k
+RUNFLAGS =
+DEFFILE = SIMPSVR.DEF
+OBJS_EXT =
+LIBS_EXT =
+!if "$(DEBUG)" == "1"
+CFLAGS = $(CFLAGS_D_WEXE)
+LFLAGS = $(LFLAGS_D_WEXE)
+LIBS = $(LIBS_D_WEXE)
+MAPFILE = nul
+RCDEFINES = $(D_RCDEFINES)
+!else
+CFLAGS = $(CFLAGS_R_WEXE)
+LFLAGS = $(LFLAGS_R_WEXE)
+LIBS = $(LIBS_R_WEXE)
+MAPFILE = nul
+RCDEFINES = $(R_RCDEFINES)
+!endif
+!if [if exist MSVC.BND del MSVC.BND]
+!endif
+SBRS = PRE.SBR \
+ ICF.SBR \
+ IDO.SBR \
+ IOIPAO.SBR \
+ IOIPO.SBR \
+ IOO.SBR \
+ IPS.SBR \
+ OBJ.SBR \
+ SIMPSVR.SBR \
+ DOC.SBR \
+ IEC.SBR \
+ APP.SBR
+
+
+APP_DEP = c:\ole2samp\simpsvr\pre.h \
+ c:\ole2samp\release\ole2.h \
+ c:\ole2samp\release\compobj.h \
+ c:\ole2samp\release\scode.h \
+ c:\ole2samp\release\initguid.h \
+ c:\ole2samp\release\coguid.h \
+ c:\ole2samp\release\oleguid.h \
+ c:\ole2samp\release\dvobj.h \
+ c:\ole2samp\release\storage.h \
+ c:\ole2samp\release\moniker.h \
+ c:\ole2samp\release\ole2ui.h \
+ c:\ole2samp\release\olestd.h \
+ c:\ole2samp\simpsvr\simpsvr.h \
+ c:\ole2samp\release\ole2ver.h \
+ c:\ole2samp\simpsvr\obj.h \
+ c:\ole2samp\simpsvr\ioipao.h \
+ c:\ole2samp\simpsvr\ioipo.h \
+ c:\ole2samp\simpsvr\ioo.h \
+ c:\ole2samp\simpsvr\ips.h \
+ c:\ole2samp\simpsvr\ido.h \
+ c:\ole2samp\simpsvr\iec.h \
+ c:\ole2samp\simpsvr\app.h \
+ c:\ole2samp\simpsvr\doc.h \
+ c:\ole2samp\simpsvr\icf.h
+
+
+ICF_DEP = c:\ole2samp\simpsvr\pre.h \
+ c:\ole2samp\release\ole2.h \
+ c:\ole2samp\release\compobj.h \
+ c:\ole2samp\release\scode.h \
+ c:\ole2samp\release\initguid.h \
+ c:\ole2samp\release\coguid.h \
+ c:\ole2samp\release\oleguid.h \
+ c:\ole2samp\release\dvobj.h \
+ c:\ole2samp\release\storage.h \
+ c:\ole2samp\release\moniker.h \
+ c:\ole2samp\release\ole2ui.h \
+ c:\ole2samp\release\olestd.h \
+ c:\ole2samp\simpsvr\simpsvr.h \
+ c:\ole2samp\release\ole2ver.h \
+ c:\ole2samp\simpsvr\app.h \
+ c:\ole2samp\simpsvr\doc.h \
+ c:\ole2samp\simpsvr\icf.h
+
+
+IDO_DEP = c:\ole2samp\simpsvr\pre.h \
+ c:\ole2samp\release\ole2.h \
+ c:\ole2samp\release\compobj.h \
+ c:\ole2samp\release\scode.h \
+ c:\ole2samp\release\initguid.h \
+ c:\ole2samp\release\coguid.h \
+ c:\ole2samp\release\oleguid.h \
+ c:\ole2samp\release\dvobj.h \
+ c:\ole2samp\release\storage.h \
+ c:\ole2samp\release\moniker.h \
+ c:\ole2samp\release\ole2ui.h \
+ c:\ole2samp\release\olestd.h \
+ c:\ole2samp\simpsvr\simpsvr.h \
+ c:\ole2samp\release\ole2ver.h \
+ c:\ole2samp\simpsvr\obj.h \
+ c:\ole2samp\simpsvr\ioipao.h \
+ c:\ole2samp\simpsvr\ioipo.h \
+ c:\ole2samp\simpsvr\ioo.h \
+ c:\ole2samp\simpsvr\ips.h \
+ c:\ole2samp\simpsvr\ido.h \
+ c:\ole2samp\simpsvr\iec.h \
+ c:\ole2samp\simpsvr\app.h \
+ c:\ole2samp\simpsvr\doc.h
+
+
+IOIPAO_DEP = c:\ole2samp\simpsvr\pre.h \
+ c:\ole2samp\release\ole2.h \
+ c:\ole2samp\release\compobj.h \
+ c:\ole2samp\release\scode.h \
+ c:\ole2samp\release\initguid.h \
+ c:\ole2samp\release\coguid.h \
+ c:\ole2samp\release\oleguid.h \
+ c:\ole2samp\release\dvobj.h \
+ c:\ole2samp\release\storage.h \
+ c:\ole2samp\release\moniker.h \
+ c:\ole2samp\release\ole2ui.h \
+ c:\ole2samp\release\olestd.h \
+ c:\ole2samp\simpsvr\simpsvr.h \
+ c:\ole2samp\release\ole2ver.h \
+ c:\ole2samp\simpsvr\obj.h \
+ c:\ole2samp\simpsvr\ioipao.h \
+ c:\ole2samp\simpsvr\ioipo.h \
+ c:\ole2samp\simpsvr\ioo.h \
+ c:\ole2samp\simpsvr\ips.h \
+ c:\ole2samp\simpsvr\ido.h \
+ c:\ole2samp\simpsvr\iec.h \
+ c:\ole2samp\simpsvr\app.h \
+ c:\ole2samp\simpsvr\doc.h
+
+
+IOIPO_DEP = c:\ole2samp\simpsvr\pre.h \
+ c:\ole2samp\release\ole2.h \
+ c:\ole2samp\release\compobj.h \
+ c:\ole2samp\release\scode.h \
+ c:\ole2samp\release\initguid.h \
+ c:\ole2samp\release\coguid.h \
+ c:\ole2samp\release\oleguid.h \
+ c:\ole2samp\release\dvobj.h \
+ c:\ole2samp\release\storage.h \
+ c:\ole2samp\release\moniker.h \
+ c:\ole2samp\release\ole2ui.h \
+ c:\ole2samp\release\olestd.h \
+ c:\ole2samp\simpsvr\simpsvr.h \
+ c:\ole2samp\release\ole2ver.h \
+ c:\ole2samp\simpsvr\obj.h \
+ c:\ole2samp\simpsvr\ioipao.h \
+ c:\ole2samp\simpsvr\ioipo.h \
+ c:\ole2samp\simpsvr\ioo.h \
+ c:\ole2samp\simpsvr\ips.h \
+ c:\ole2samp\simpsvr\ido.h \
+ c:\ole2samp\simpsvr\iec.h \
+ c:\ole2samp\simpsvr\app.h \
+ c:\ole2samp\simpsvr\doc.h
+
+
+IOO_DEP = c:\ole2samp\simpsvr\pre.h \
+ c:\ole2samp\release\ole2.h \
+ c:\ole2samp\release\compobj.h \
+ c:\ole2samp\release\scode.h \
+ c:\ole2samp\release\initguid.h \
+ c:\ole2samp\release\coguid.h \
+ c:\ole2samp\release\oleguid.h \
+ c:\ole2samp\release\dvobj.h \
+ c:\ole2samp\release\storage.h \
+ c:\ole2samp\release\moniker.h \
+ c:\ole2samp\release\ole2ui.h \
+ c:\ole2samp\release\olestd.h \
+ c:\ole2samp\simpsvr\simpsvr.h \
+ c:\ole2samp\release\ole2ver.h \
+ c:\ole2samp\simpsvr\obj.h \
+ c:\ole2samp\simpsvr\ioipao.h \
+ c:\ole2samp\simpsvr\ioipo.h \
+ c:\ole2samp\simpsvr\ioo.h \
+ c:\ole2samp\simpsvr\ips.h \
+ c:\ole2samp\simpsvr\ido.h \
+ c:\ole2samp\simpsvr\iec.h \
+ c:\ole2samp\simpsvr\app.h \
+ c:\ole2samp\simpsvr\doc.h
+
+
+IPS_DEP = c:\ole2samp\simpsvr\pre.h \
+ c:\ole2samp\release\ole2.h \
+ c:\ole2samp\release\compobj.h \
+ c:\ole2samp\release\scode.h \
+ c:\ole2samp\release\initguid.h \
+ c:\ole2samp\release\coguid.h \
+ c:\ole2samp\release\oleguid.h \
+ c:\ole2samp\release\dvobj.h \
+ c:\ole2samp\release\storage.h \
+ c:\ole2samp\release\moniker.h \
+ c:\ole2samp\release\ole2ui.h \
+ c:\ole2samp\release\olestd.h \
+ c:\ole2samp\simpsvr\simpsvr.h \
+ c:\ole2samp\release\ole2ver.h \
+ c:\ole2samp\simpsvr\obj.h \
+ c:\ole2samp\simpsvr\ioipao.h \
+ c:\ole2samp\simpsvr\ioipo.h \
+ c:\ole2samp\simpsvr\ioo.h \
+ c:\ole2samp\simpsvr\ips.h \
+ c:\ole2samp\simpsvr\ido.h \
+ c:\ole2samp\simpsvr\iec.h \
+ c:\ole2samp\simpsvr\app.h \
+ c:\ole2samp\simpsvr\doc.h
+
+
+OBJ_DEP = c:\ole2samp\simpsvr\pre.h \
+ c:\ole2samp\release\ole2.h \
+ c:\ole2samp\release\compobj.h \
+ c:\ole2samp\release\scode.h \
+ c:\ole2samp\release\initguid.h \
+ c:\ole2samp\release\coguid.h \
+ c:\ole2samp\release\oleguid.h \
+ c:\ole2samp\release\dvobj.h \
+ c:\ole2samp\release\storage.h \
+ c:\ole2samp\release\moniker.h \
+ c:\ole2samp\release\ole2ui.h \
+ c:\ole2samp\release\olestd.h \
+ c:\ole2samp\simpsvr\simpsvr.h \
+ c:\ole2samp\release\ole2ver.h \
+ c:\ole2samp\simpsvr\obj.h \
+ c:\ole2samp\simpsvr\ioipao.h \
+ c:\ole2samp\simpsvr\ioipo.h \
+ c:\ole2samp\simpsvr\ioo.h \
+ c:\ole2samp\simpsvr\ips.h \
+ c:\ole2samp\simpsvr\ido.h \
+ c:\ole2samp\simpsvr\iec.h \
+ c:\ole2samp\simpsvr\icf.h \
+ c:\ole2samp\simpsvr\app.h \
+ c:\ole2samp\simpsvr\doc.h
+
+
+SIMPSVR_DEP = c:\ole2samp\simpsvr\pre.h \
+ c:\ole2samp\release\ole2.h \
+ c:\ole2samp\release\compobj.h \
+ c:\ole2samp\release\scode.h \
+ c:\ole2samp\release\initguid.h \
+ c:\ole2samp\release\coguid.h \
+ c:\ole2samp\release\oleguid.h \
+ c:\ole2samp\release\dvobj.h \
+ c:\ole2samp\release\storage.h \
+ c:\ole2samp\release\moniker.h \
+ c:\ole2samp\release\ole2ui.h \
+ c:\ole2samp\release\olestd.h \
+ c:\ole2samp\simpsvr\simpsvr.h \
+ c:\ole2samp\release\ole2ver.h \
+ c:\ole2samp\simpsvr\obj.h \
+ c:\ole2samp\simpsvr\ioipao.h \
+ c:\ole2samp\simpsvr\ioipo.h \
+ c:\ole2samp\simpsvr\ioo.h \
+ c:\ole2samp\simpsvr\ips.h \
+ c:\ole2samp\simpsvr\ido.h \
+ c:\ole2samp\simpsvr\iec.h \
+ c:\ole2samp\simpsvr\app.h \
+ c:\ole2samp\simpsvr\doc.h \
+ c:\ole2samp\simpsvr\icf.h
+
+
+SIMPSVR_RCDEP = c:\ole2samp\simpsvr\simpsvr.h
+
+
+DOC_DEP = c:\ole2samp\simpsvr\pre.h \
+ c:\ole2samp\release\ole2.h \
+ c:\ole2samp\release\compobj.h \
+ c:\ole2samp\release\scode.h \
+ c:\ole2samp\release\initguid.h \
+ c:\ole2samp\release\coguid.h \
+ c:\ole2samp\release\oleguid.h \
+ c:\ole2samp\release\dvobj.h \
+ c:\ole2samp\release\storage.h \
+ c:\ole2samp\release\moniker.h \
+ c:\ole2samp\release\ole2ui.h \
+ c:\ole2samp\release\olestd.h \
+ c:\ole2samp\simpsvr\simpsvr.h \
+ c:\ole2samp\release\ole2ver.h \
+ c:\ole2samp\simpsvr\obj.h \
+ c:\ole2samp\simpsvr\ioipao.h \
+ c:\ole2samp\simpsvr\ioipo.h \
+ c:\ole2samp\simpsvr\ioo.h \
+ c:\ole2samp\simpsvr\ips.h \
+ c:\ole2samp\simpsvr\ido.h \
+ c:\ole2samp\simpsvr\iec.h \
+ c:\ole2samp\simpsvr\app.h \
+ c:\ole2samp\simpsvr\doc.h
+
+
+IEC_DEP = c:\ole2samp\simpsvr\pre.h \
+ c:\ole2samp\release\ole2.h \
+ c:\ole2samp\release\compobj.h \
+ c:\ole2samp\release\scode.h \
+ c:\ole2samp\release\initguid.h \
+ c:\ole2samp\release\coguid.h \
+ c:\ole2samp\release\oleguid.h \
+ c:\ole2samp\release\dvobj.h \
+ c:\ole2samp\release\storage.h \
+ c:\ole2samp\release\moniker.h \
+ c:\ole2samp\release\ole2ui.h \
+ c:\ole2samp\release\olestd.h \
+ c:\ole2samp\simpsvr\simpsvr.h \
+ c:\ole2samp\release\ole2ver.h \
+ c:\ole2samp\simpsvr\obj.h \
+ c:\ole2samp\simpsvr\ioipao.h \
+ c:\ole2samp\simpsvr\ioipo.h \
+ c:\ole2samp\simpsvr\ioo.h \
+ c:\ole2samp\simpsvr\ips.h \
+ c:\ole2samp\simpsvr\ido.h \
+ c:\ole2samp\simpsvr\iec.h \
+ c:\ole2samp\simpsvr\app.h \
+ c:\ole2samp\simpsvr\doc.h
+
+
+PRE_DEP = c:\ole2samp\simpsvr\pre.h \
+ c:\ole2samp\release\ole2.h \
+ c:\ole2samp\release\compobj.h \
+ c:\ole2samp\release\scode.h \
+ c:\ole2samp\release\initguid.h \
+ c:\ole2samp\release\coguid.h \
+ c:\ole2samp\release\oleguid.h \
+ c:\ole2samp\release\dvobj.h \
+ c:\ole2samp\release\storage.h \
+ c:\ole2samp\release\moniker.h \
+ c:\ole2samp\release\ole2ui.h \
+ c:\ole2samp\release\olestd.h \
+ c:\ole2samp\simpsvr\simpsvr.h \
+ c:\ole2samp\release\ole2ver.h
+
+
+all: $(PROJ).EXE $(PROJ).BSC
+
+PRE.OBJ: PRE.CPP $(PRE_DEP)
+ $(CPP) $(CFLAGS) $(CPPCREATEPCHFLAG) /c PRE.CPP
+
+ICF.OBJ: ICF.CPP $(ICF_DEP)
+ $(CPP) $(CFLAGS) $(CPPUSEPCHFLAG) /c ICF.CPP
+
+IDO.OBJ: IDO.CPP $(IDO_DEP)
+ $(CPP) $(CFLAGS) $(CPPUSEPCHFLAG) /c IDO.CPP
+
+IOIPAO.OBJ: IOIPAO.CPP $(IOIPAO_DEP)
+ $(CPP) $(CFLAGS) $(CPPUSEPCHFLAG) /c IOIPAO.CPP
+
+IOIPO.OBJ: IOIPO.CPP $(IOIPO_DEP)
+ $(CPP) $(CFLAGS) $(CPPUSEPCHFLAG) /c IOIPO.CPP
+
+IOO.OBJ: IOO.CPP $(IOO_DEP)
+ $(CPP) $(CFLAGS) $(CPPUSEPCHFLAG) /c IOO.CPP
+
+IPS.OBJ: IPS.CPP $(IPS_DEP)
+ $(CPP) $(CFLAGS) $(CPPUSEPCHFLAG) /c IPS.CPP
+
+OBJ.OBJ: OBJ.CPP $(OBJ_DEP)
+ $(CPP) $(CFLAGS) $(CPPUSEPCHFLAG) /c OBJ.CPP
+
+SIMPSVR.OBJ: SIMPSVR.CPP $(SIMPSVR_DEP)
+ $(CPP) $(CFLAGS) $(CPPUSEPCHFLAG) /c SIMPSVR.CPP
+
+SIMPSVR.RES: SIMPSVR.RC $(SIMPSVR_RCDEP)
+ $(RC) $(RCFLAGS) $(RCDEFINES) -r SIMPSVR.RC
+
+DOC.OBJ: DOC.CPP $(DOC_DEP)
+ $(CPP) $(CFLAGS) $(CPPUSEPCHFLAG) /c DOC.CPP
+
+IEC.OBJ: IEC.CPP $(IEC_DEP)
+ $(CPP) $(CFLAGS) $(CPPUSEPCHFLAG) /c IEC.CPP
+
+APP.OBJ: APP.CPP $(APP_DEP)
+ $(CPP) $(CFLAGS) $(CPPUSEPCHFLAG) /c APP.CPP
+
+
+$(PROJ).EXE:: SIMPSVR.RES
+
+$(PROJ).EXE:: PRE.OBJ ICF.OBJ IDO.OBJ IOIPAO.OBJ IOIPO.OBJ IOO.OBJ IPS.OBJ OBJ.OBJ \
+ SIMPSVR.OBJ DOC.OBJ IEC.OBJ APP.OBJ $(OBJS_EXT) $(DEFFILE)
+ echo >NUL @<<$(PROJ).CRF
+PRE.OBJ +
+ICF.OBJ +
+IDO.OBJ +
+IOIPAO.OBJ +
+IOIPO.OBJ +
+IOO.OBJ +
+IPS.OBJ +
+OBJ.OBJ +
+SIMPSVR.OBJ +
+DOC.OBJ +
+IEC.OBJ +
+APP.OBJ +
+$(OBJS_EXT)
+$(PROJ).EXE
+$(MAPFILE)
+c:\ole2samp\release\+
+c:\msvc\lib\+
+c:\msvc\mfc\lib\+
+$(LIBS)
+$(DEFFILE);
+<<
+ link $(LFLAGS) @$(PROJ).CRF
+ $(RC) $(RESFLAGS) SIMPSVR.RES $@
+ @copy $(PROJ).CRF MSVC.BND
+
+$(PROJ).EXE:: SIMPSVR.RES
+ if not exist MSVC.BND $(RC) $(RESFLAGS) SIMPSVR.RES $@
+
+run: $(PROJ).EXE
+ $(PROJ) $(RUNFLAGS)
+
+
+$(PROJ).BSC: $(SBRS)
+ bscmake @<<
+/o$@ $(SBRS)
+<<
diff --git a/private/oleutest/simpsvr/simpsvr.prj b/private/oleutest/simpsvr/simpsvr.prj
new file mode 100644
index 000000000..74893721a
--- /dev/null
+++ b/private/oleutest/simpsvr/simpsvr.prj
Binary files differ
diff --git a/private/oleutest/simpsvr/simpsvr.rc b/private/oleutest/simpsvr/simpsvr.rc
new file mode 100644
index 000000000..13ba8d6ee
--- /dev/null
+++ b/private/oleutest/simpsvr/simpsvr.rc
@@ -0,0 +1,111 @@
+//Microsoft App Studio generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#define APSTUDIO_HIDDEN_SYMBOLS
+#include "windows.h"
+#undef APSTUDIO_HIDDEN_SYMBOLS
+#include "simpsvr.h"
+#include "ole2ui.rc"
+
+/////////////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+SimpSvr icon simpsvr.ico
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// Menu
+//
+
+SIMPSVRMENU MENU DISCARDABLE
+BEGIN
+ POPUP "&File"
+ BEGIN
+ MENUITEM "E&xit", IDM_EXIT
+ END
+ POPUP "&Color"
+ BEGIN
+ MENUITEM "&Owner Draw Colors", IDM_COLOROWNERDR
+ MENUITEM SEPARATOR
+ MENUITEM "&Red", IDM_RED
+ MENUITEM "&Green", IDM_GREEN
+ MENUITEM "&Blue", IDM_BLUE
+ END
+ POPUP "&Help"
+ BEGIN
+ MENUITEM "&About Simpsvr...", IDM_ABOUT
+ END
+END
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+ABOUTBOX DIALOG DISCARDABLE 22, 17, 144, 75
+STYLE DS_MODALFRAME | WS_CAPTION | WS_SYSMENU
+CAPTION "Simple OLE 2.0 Server"
+FONT 8, "System"
+BEGIN
+ CTEXT "Microsoft Windows",-1,0,5,144,8
+ CTEXT "Simple OLE 2.0 Server",-1,0,14,144,8
+ CTEXT "Version 1.0",-1,0,34,144,8
+ DEFPUSHBUTTON "OK",IDOK,53,59,32,14,WS_GROUP
+END
+
+SimpsvrAccel ACCELERATORS
+ BEGIN
+ "^b", IDM_BLUE
+ "^r", IDM_RED
+ "^g", IDM_GREEN
+ VK_F12, IDM_ABOUT, VIRTKEY, CONTROL
+ END
+
+#ifdef APSTUDIO_INVOKED
+//////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "#define APSTUDIO_HIDDEN_SYMBOLS\r\n"
+ "#include ""windows.h""\r\n"
+ "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n"
+ "#include ""simpsvr.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+/////////////////////////////////////////////////////////////////////////////////////
+#endif // APSTUDIO_INVOKED
+
+
+#ifndef APSTUDIO_INVOKED
+////////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
+
diff --git a/private/oleutest/simpsvr/strings.rc b/private/oleutest/simpsvr/strings.rc
new file mode 100644
index 000000000..f3f8c415a
--- /dev/null
+++ b/private/oleutest/simpsvr/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/stgdrt/daytona/makefile b/private/oleutest/stgdrt/daytona/makefile
new file mode 100644
index 000000000..14f79b701
--- /dev/null
+++ b/private/oleutest/stgdrt/daytona/makefile
@@ -0,0 +1 @@
+!include $(NTMAKEENV)\makefile.def
diff --git a/private/oleutest/stgdrt/daytona/sources b/private/oleutest/stgdrt/daytona/sources
new file mode 100644
index 000000000..858eb6c92
--- /dev/null
+++ b/private/oleutest/stgdrt/daytona/sources
@@ -0,0 +1,87 @@
+!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:
+
+ Drew Bliss (DrewB) 21-Dec-1993
+
+!ENDIF
+
+MAJORCOMP= cairole
+MINORCOMP= stg
+
+#
+# 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= stgdrt
+
+#
+# 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=..\..\..\ole32\ih;..\..\..\ole32\common\daytona;\
+ ..\..\..\cinc;..\..\..\ole32\stg\h;..
+
+BLDCRT= 1
+USE_CRTDLL= 1
+
+C_DEFINES= \
+ $(C_DEFINES) \
+ -DFLAT \
+ -DUNICODE \
+ -D_UNICODE \
+ -DINC_OLE2 \
+ -DWIN32=100 \
+ -DNOEXCEPTIONS
+
+SOURCES= \
+ ..\drt.cxx\
+ ..\tests.cxx\
+ ..\illeg.cxx\
+ ..\util.cxx\
+ ..\wrap.cxx\
+ ..\strlist.cxx\
+ ..\drtguid.cxx\
+ ..\ilb.cxx
+
+UMTYPE= console
+UMAPPL=
+UMTEST=
+UMLIBS= \
+ ..\..\assert\daytona\obj\*\assert.lib \
+ $(BASEDIR)\public\sdk\lib\*\ole32.lib\
+ $(BASEDIR)\public\sdk\lib\*\kernel32.lib\
+ $(BASEDIR)\public\sdk\lib\*\user32.lib\
+ $(BASEDIR)\public\sdk\lib\*\advapi32.lib
+
+#PRECOMPILED_INCLUDE= ..\headers.cxx
+
+PRECOMPILED_OPTION=
+PRECOMPILED_TARGET=
+PRECOMPILED_CXX=
diff --git a/private/oleutest/stgdrt/dirs b/private/oleutest/stgdrt/dirs
new file mode 100644
index 000000000..d57788212
--- /dev/null
+++ b/private/oleutest/stgdrt/dirs
@@ -0,0 +1,38 @@
+!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:
+
+ Drew Bliss (DrewB) 21-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/stgdrt/drt.cxx b/private/oleutest/stgdrt/drt.cxx
new file mode 100644
index 000000000..3406452c5
--- /dev/null
+++ b/private/oleutest/stgdrt/drt.cxx
@@ -0,0 +1,305 @@
+//+--------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1992.
+//
+// File: drt.cxx
+//
+// Contents: DRT main routine
+//
+// History: 22-Sep-92 DrewB Created
+//
+//---------------------------------------------------------------
+
+#include "headers.cxx"
+#pragma hdrstop
+
+#include "tests.hxx"
+#include "illeg.hxx"
+
+// Test flags and type
+typedef ULONG FLAGS;
+
+#define TF_NONE 0x00000000
+
+// Suppression flags
+#define TF_SUPPRESS 0x0000FFFF
+#define TFS_ILLEGITIMATE 0x00000001
+#define TFS_16BIT 0x00000002
+
+// Enabling flags
+#define TF_ENABLE 0xFFFF0000
+#define TFE_DIRECT 0x00010000
+#define TFE_TRANSACTED 0x00020000
+#define TFE_INDEPENDENT 0x00040000
+#define TFE_ANY (TFE_DIRECT | TFE_TRANSACTED | TFE_INDEPENDENT)
+
+// Pointer to a test function
+typedef void (*TestFn)(void);
+
+static struct
+{
+ char *pszName;
+ char *pszDesc;
+ TestFn tfn;
+ FLAGS flags;
+} tests[] =
+{
+ "Create", "Creation",
+ t_create, TFE_ANY,
+ "Open", "Opening",
+ t_open, TFE_ANY,
+ "AddRef", "AddRef/Release",
+ t_addref, TFE_ANY,
+ "TModify", "Transacted modify/Commit/Revert",
+ t_tmodify, TFE_TRANSACTED | TFE_INDEPENDENT,
+ "DModify", "Direct modifications",
+ t_dmodify, TFE_DIRECT,
+ "Stat", "Stat",
+ t_stat, TFE_ANY,
+ "Stream", "Stream operations",
+ t_stream, TFE_ANY,
+ "Enum", "Enumerator operations",
+ t_enum, TFE_ANY,
+ "StgCopyTo", "IStorage::CopyTo",
+ t_stgcopyto, TFE_ANY,
+ "MoveCopy", "IStorage::MoveElementTo",
+ t_movecopy, TFE_ANY,
+ "Marshal", "IMarshal operations",
+ t_marshal, TFE_ANY,
+ "ILockBytes", "ILockBytes usage",
+ t_ilb, TFE_ANY,
+ "StgMisc", "Miscellaneous Stg functions",
+ t_stgmisc, TFE_ANY,
+
+ "IllStg", "Illegitimate IStorage calls",
+ i_storage, TFE_ANY | TFS_ILLEGITIMATE,
+ "IllStm", "Illegitimate IStream calls",
+ i_stream, TFE_ANY | TFS_ILLEGITIMATE,
+ "IllEnum", "Illegitimate enumerator calls",
+ i_enum, TFE_ANY | TFS_ILLEGITIMATE
+};
+#define NTESTS (sizeof(tests)/sizeof(tests[0]))
+
+DWORD dwTransacted = 0;
+DWORD dwRootDenyWrite = STGM_SHARE_DENY_WRITE;
+BOOL fVerbose = FALSE;
+BOOL fOfs = FALSE;
+OLECHAR atcDrtDocfile[_MAX_PATH];
+
+static BOOL fRun[NTESTS];
+#ifdef FLAT
+static FLAGS flTests = TF_NONE;
+#else
+static FLAGS flTests = TF_NONE | TFS_16BIT;
+#endif
+
+static void Initialize(void)
+{
+ SCODE sc;
+
+ SetData();
+#if WIN32 == 300
+ if (FAILED(sc = DfGetScode(CoInitializeEx(NULL, COINIT_MULTITHREADED))))
+ error(EXIT_UNKNOWN,
+ "CoInitializeEx failed with sc = 0x%lX\n", sc);
+#else
+ if (FAILED(sc = DfGetScode(CoInitialize(NULL))))
+ error(EXIT_UNKNOWN,
+ "CoInitialize failed with sc = 0x%lX\n", sc);
+#endif
+}
+
+static void Uninitialize(void)
+{
+ UnsetData();
+ CoUninitialize();
+}
+
+static int FindTest(char *pszName)
+{
+ int i, cchName;
+
+ cchName = strlen(pszName);
+ for (i = 0; i<NTESTS; i++)
+ if (!_strnicmp(pszName, tests[i].pszName, cchName))
+ return i;
+ return -1;
+}
+
+static void RunTests(void)
+{
+ int i;
+
+ for (i = 0; i<NTESTS; i++)
+ // For a test to run:
+ // 1) fRun[test] must be TRUE
+ // 2) No suppression flags can be set that are not set in flTests
+ // 3) At least one enabling flag must be set that is set in flTests
+ if (fRun[i] &&
+ (tests[i].flags & ~flTests & TF_SUPPRESS) == 0 &&
+ (tests[i].flags & flTests & TF_ENABLE) != 0)
+ {
+ out("\n----- Test #%2d - %s -----\n", i+1, tests[i].pszDesc);
+ tests[i].tfn();
+ CheckMemory();
+ CleanData();
+ }
+}
+
+static void Usage(void)
+{
+ int i;
+
+ printf("Usage: drt [options]\n");
+ printf("Options are:\n");
+ printf(" -h - This message\n");
+ printf(" -d - Suppress direct tests\n");
+ printf(" -t - Suppress transacted tests\n");
+ printf(" -w - Suppress independent tests\n");
+ printf(" -i - Enable illegitimate tests\n");
+ printf(" -v - Display test output\n");
+#if WIN32 == 300
+ printf(" -o - Enable tests to run on OFS\n");
+#endif
+ printf(" -y<kind> - Control debug output (a, d, m, i, M, L)\n");
+ printf(" -#[+|-]<number> - Turn test <number> on (+) or off (-)\n");
+ printf(" No number means all\n");
+ printf(" -n[+|-]<prefix> - Turn test <prefix> on or off\n");
+ printf(" -N<file> - Set file to use for tests\n");
+ printf("Prefix can be any prefix of:\n");
+ for (i = 0; i<NTESTS; i++)
+ printf(" %s\n", tests[i].pszName);
+ exit(1);
+}
+
+int _CRTAPI1 main(int argc, char **argv)
+{
+ int i, iTest;
+ BOOL fDirect = TRUE, fTrans = TRUE, fIndep = TRUE;
+
+ SetDebug(0x101, 0x101);
+ for (i = 0; i<NTESTS; i++)
+ fRun[i] = TRUE;
+ ATOOLE("drt.dfl", atcDrtDocfile, _MAX_PATH);
+ while (--argc>0)
+ {
+ if (**++argv == '-')
+ {
+ switch(argv[0][1])
+ {
+ case '#':
+ if (sscanf(argv[0]+3, "%d", &iTest) != 1)
+ iTest = -1;
+ else
+ iTest--;
+ for (i = 0; i<NTESTS; i++)
+ if (iTest == -1 || iTest == i)
+ fRun[i] = argv[0][2] == '+';
+ break;
+ case 'd':
+ fDirect = FALSE;
+ break;
+ case 'i':
+ flTests |= TFS_ILLEGITIMATE;
+ break;
+ case 'n':
+ iTest = FindTest(argv[0]+3);
+ if (iTest >= 0)
+ fRun[iTest] = argv[0][2] == '+';
+ break;
+ case 'N':
+ ATOOLE(argv[0]+2, atcDrtDocfile, _MAX_PATH);
+ break;
+ case 't':
+ fTrans = FALSE;
+ break;
+ case 'v':
+ fVerbose = TRUE;
+ break;
+ case 'w':
+ fIndep = FALSE;
+ break;
+ case 'y':
+ switch(argv[0][2])
+ {
+ case 'a':
+ SetDebug(0xffffffff, 0xffffffff);
+ break;
+ case 'd':
+ SetDebug(0xffffffff, 0x101);
+ break;
+ case 'm':
+ SetDebug(0x101, 0xffffffff);
+ break;
+ case 'i':
+ SetDebug(0x101, 0x101);
+ break;
+ case 'M':
+ SetDebug(0x01100000, 0);
+ break;
+ case 'L':
+ SetDebug(0x00100000, 0);
+ break;
+ }
+ break;
+#if WIN32 == 300
+ case 'o':
+ fOfs = TRUE;
+ break;
+#endif
+ case 'h':
+ default:
+ Usage();
+ }
+ }
+ else
+ Usage();
+ }
+
+ Initialize();
+
+ if (fDirect)
+ {
+ out("\n---------- Direct ----------\n");
+ dwTransacted = 0;
+ dwRootDenyWrite = STGM_SHARE_EXCLUSIVE;
+ flTests |= TFE_DIRECT;
+ RunTests();
+ flTests &= ~TFE_DIRECT;
+ }
+
+#if WIN32 == 300
+ if (fTrans && !fOfs) // turn off transacted tests for OFS
+#else
+ if (fTrans)
+#endif
+ {
+ out("\n---------- Transacted ----------\n");
+ dwTransacted = STGM_TRANSACTED;
+ dwRootDenyWrite = STGM_SHARE_DENY_WRITE;
+ flTests |= TFE_TRANSACTED;
+ RunTests();
+ flTests &= ~TFE_TRANSACTED;
+ }
+
+#if WIN32 == 300
+ if (fIndep && !fOfs) // turn off transacted tests for OFS
+#else
+ if (fIndep)
+#endif
+ {
+ out("\n---------- Independent ----------\n");
+ dwTransacted = STGM_TRANSACTED;
+ dwRootDenyWrite = STGM_SHARE_DENY_NONE;
+ flTests |= TFE_INDEPENDENT;
+ RunTests();
+ flTests &= ~TFE_INDEPENDENT;
+ }
+
+ printf("Storage DRT - PASSED\n");
+
+ Uninitialize();
+
+ return(0);
+}
diff --git a/private/oleutest/stgdrt/drt.hxx b/private/oleutest/stgdrt/drt.hxx
new file mode 100644
index 000000000..dfd95a1a5
--- /dev/null
+++ b/private/oleutest/stgdrt/drt.hxx
@@ -0,0 +1,110 @@
+//+--------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1992.
+//
+// File: drt.hxx
+//
+// Contents: DRT header
+//
+// History: 22-Sep-92 DrewB Created
+//
+//---------------------------------------------------------------
+
+#ifndef __DRT_HXX__
+#define __DRT_HXX__
+
+//#include <dfmsp.hxx> // remove dependency on internal header file
+#define OLEWIDECHAR
+#define DfGetScode(hr) GetScode(hr)
+typedef DWORD LPSTGSECURITY;
+// [later] typedef LPSECURITY_ATTRIBUTES LPSTGSECURITY;
+#define ULIGetLow(li) ((li).LowPart)
+#define ULIGetHigh(li) ((li).HighPart)
+
+// Exit codes
+#define EXIT_BADSC 1
+#define EXIT_OOM 2
+#define EXIT_UNKNOWN 3
+
+#define STR(x) OLESTR(x)
+
+#ifdef UNICODE
+#ifndef ATOT
+#define ATOT(psz, ptcs, max) mbstowcs(ptcs, psz, max)
+#endif
+#ifndef TTOA
+#define TTOA(ptcs, psz, max) wcstombs(psz, ptcs, max)
+#endif
+#else
+#ifndef ATOT
+#define ATOT(psz, ptcs) strcpy(ptcs, psz)
+#endif
+#ifndef TTOA
+#define TTOA(ptcs, psz) strcpy(psz, ptcs)
+#endif
+#endif
+
+#ifdef OLEWIDECHAR
+
+//typedef WCHAR TCHAR;
+
+#ifndef ATOOLE
+#define ATOOLE(psz, ptcs, max) mbstowcs(ptcs, psz, max)
+#endif
+#ifndef OLETOA
+#define OLETOA(ptcs, psz, max) wcstombs(psz, ptcs, max)
+#endif
+
+#ifndef olecscmp
+#define olecscmp wcscmp
+#endif
+#ifndef olecscpy
+#define olecscpy wcscpy
+#endif
+#ifndef olecslen
+#define olecslen wcslen
+#endif
+#ifndef olecsprintf
+#define olecsprintf swprintf
+#endif
+
+#else
+
+typedef char TCHAR;
+
+#ifndef ATOOLE
+#define ATOOLE(psz, ptcs) strcpy(ptcs, psz)
+#endif
+#ifndef OLETOA
+#define OLETOA(ptcs, psz) strcpy(psz, ptcs)
+#endif
+
+#ifndef olecscmp
+#define olecscmp strcmp
+#endif
+#ifndef olecscpy
+#define olecscpy strcpy
+#endif
+#ifndef olecslen
+#define olecslen strlen
+#endif
+#ifndef olecsprintf
+#define olecsprintf sprintf
+#endif
+
+#endif
+
+#define DRTDF atcDrtDocfile
+#define MARSHALDF STR("dup.dfl")
+
+#define ROOTP(x) ((x) | dwTransacted | dwRootDenyWrite)
+#define STGP(x) ((x) | dwTransacted | STGM_SHARE_EXCLUSIVE)
+#define STMP(x) ((x) | STGM_SHARE_EXCLUSIVE)
+
+extern DWORD dwTransacted, dwRootDenyWrite;
+extern BOOL fVerbose;
+extern BOOL fOfs;
+extern OLECHAR atcDrtDocfile[];
+
+#endif // #ifndef __DRT_HXX__
diff --git a/private/oleutest/stgdrt/drtguid.cxx b/private/oleutest/stgdrt/drtguid.cxx
new file mode 100644
index 000000000..f28bcfda5
--- /dev/null
+++ b/private/oleutest/stgdrt/drtguid.cxx
@@ -0,0 +1,26 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: drtguid.cxx
+//
+// Contents: Define GUIDs needed by the DRT
+//
+// History: 04-Nov-93 DrewB Created
+//
+//----------------------------------------------------------------------------
+
+#include "headers.cxx"
+#pragma hdrstop
+
+#include <initguid.h>
+
+#if WIN32 == 100 || WIN32 == 200
+DEFINE_GUID(GUID_NULL, 0L, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+
+DEFINE_OLEGUID(IID_IUnknown, 0x00000000L, 0, 0);
+DEFINE_OLEGUID(IID_ILockBytes, 0x0000000aL, 0, 0);
+DEFINE_OLEGUID(IID_IStorage, 0x0000000bL, 0, 0);
+DEFINE_OLEGUID(IID_IStream, 0x0000000cL, 0, 0);
+#endif
diff --git a/private/oleutest/stgdrt/headers.cxx b/private/oleutest/stgdrt/headers.cxx
new file mode 100644
index 000000000..4d43f4712
--- /dev/null
+++ b/private/oleutest/stgdrt/headers.cxx
@@ -0,0 +1,33 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1992.
+//
+// File: headers.cxx
+//
+// Contents: Precompiled headers
+//
+// History: 05-Nov-92 AlexT Created
+//
+//--------------------------------------------------------------------------
+
+#include <memory.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+
+#include <windows.h>
+#include <ole2.h>
+
+#ifdef _CAIRO_
+#define _DCOM_
+#define _CAIROSTG_
+#include <oleext.h>
+#endif
+
+#include <debnot.h>
+
+#include <drt.hxx>
+#include <wrap.hxx>
+#include <util.hxx>
+#include <strlist.hxx>
diff --git a/private/oleutest/stgdrt/ilb.cxx b/private/oleutest/stgdrt/ilb.cxx
new file mode 100644
index 000000000..805009f81
--- /dev/null
+++ b/private/oleutest/stgdrt/ilb.cxx
@@ -0,0 +1,422 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1992.
+//
+// File: ilbmem.cx
+//
+// Contents: ILockBytes memory implementation
+//
+// Classes: CMapBytes
+//
+// History: 06-Nov-92 AlexT Created
+//
+//--------------------------------------------------------------------------
+
+#include "headers.cxx"
+#pragma hdrstop
+
+#include <memory.h>
+#include <ilb.hxx>
+
+#if DBG == 1
+
+DECLARE_INFOLEVEL(ol);
+
+#endif
+
+//+-------------------------------------------------------------------------
+//
+// Member: CMapBytes::CMapBytes, public
+//
+// Synopsis: constructor
+//
+// Effects: initialize member variables
+//
+// Derivation: ILockBytes
+//
+// History: 06-Nov-92 AlexT Created
+//
+// Notes: Returns a fully initialized CMapBytes (ref count == 1)
+//
+//--------------------------------------------------------------------------
+
+CMapBytes::CMapBytes(void)
+{
+ _ulSize = 0;
+ _pv = 0;
+
+ _ulRef = 1;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Member: CMapBytes::QueryInterface, public
+//
+// Arguments: [riid] - interface id
+// [ppvObj] - place holder for interface
+//
+// Returns: Always fails
+//
+// Derivation: ILockBytes
+//
+// History: 06-Nov-92 AlexT Created
+//
+// Notes: Not used in tests
+//
+//--------------------------------------------------------------------------
+
+STDMETHODIMP CMapBytes::QueryInterface(REFIID riid, LPVOID FAR* ppvObj)
+{
+ *ppvObj = NULL;
+ return ResultFromScode(STG_E_INVALIDFUNCTION);
+}
+
+//+-------------------------------------------------------------------------
+//
+// Member: CMapBytes::AddRef, public
+//
+// Synopsis: add reference
+//
+// Returns: post reference count
+//
+// Derivation: ILockBytes
+//
+// History: 06-Nov-92 AlexT Created
+//
+//--------------------------------------------------------------------------
+
+STDMETHODIMP_(ULONG) CMapBytes::AddRef(void)
+{
+ AtomicInc(&_ulRef);
+ return(_ulRef);
+}
+
+//+-------------------------------------------------------------------------
+//
+// Member: CMapBytes::Release, public
+//
+// Synopsis: release reference
+//
+// Effects: deletes object when reference count reaches zero
+//
+// Returns: post reference count
+//
+// Derivation: ILockBytes
+//
+// History: 06-Nov-92 AlexT Created
+//
+//--------------------------------------------------------------------------
+
+STDMETHODIMP_(ULONG) CMapBytes::Release(void)
+{
+ AtomicDec(&_ulRef);
+
+ if (_ulRef > 0)
+ return(_ulRef);
+
+ free(_pv);
+
+ delete this;
+
+ return(0);
+}
+
+//+-------------------------------------------------------------------------
+//
+// Member: CMapBytes::ReadAt
+//
+// Synopsis: Reads bytes from memory
+//
+// Arguments: [ulOffset] - byte offset
+// [pv] - input buffer
+// [cb] - count of bytes to read
+// [pcbRead] - count of bytes read
+//
+// Returns: SCODE
+//
+// Modifies: pv, pcbRead
+//
+// Derivation: ILockBytes
+//
+// History: 30-Oct-92 AlexT Created
+//
+//--------------------------------------------------------------------------
+
+STDMETHODIMP CMapBytes::ReadAt(ULARGE_INTEGER uliOffset,
+ VOID HUGEP *pv,
+ ULONG cb,
+ ULONG *pcbRead)
+{
+ olAssert(ULIGetHigh(uliOffset) == 0);
+
+ ULONG ulOffset = ULIGetLow(uliOffset);
+ if (ulOffset >= _ulSize)
+ {
+ // truncate read
+ cb = 0;
+ }
+ else if (cb > (_ulSize - ulOffset))
+ {
+ // truncate range that exceeds size
+ cb = _ulSize - ulOffset;
+ }
+
+ memcpy(pv, (void*)(((BYTE*)_pv) + ulOffset), (size_t) cb);
+ *pcbRead = cb;
+ return NOERROR;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Member: CMapBytes::WriteAt, public
+//
+// Synopsis: Writes bytes to memory
+//
+// Effects: May change memory size
+//
+// Arguments: [uliOffset] - byte offset
+// [pv] - output buffer
+// [cb] - count of bytes to write
+// [pcbWritten] - count of bytes written
+//
+// Returns: SCODE
+//
+// Modifies: pcbWritten
+//
+// Derivation: ILockBytes
+//
+// History: 06-Nov-92 AlexT Created
+//
+// Notes: This implementation doesn't write partial buffers.
+//
+//--------------------------------------------------------------------------
+
+STDMETHODIMP CMapBytes::WriteAt(ULARGE_INTEGER uliOffset,
+ VOID const HUGEP *pv,
+ ULONG cb,
+ ULONG FAR *pcbWritten)
+{
+ olAssert(ULIGetHigh(uliOffset) == 0);
+
+ ULONG ulOffset = ULIGetLow(uliOffset);
+ HRESULT hr;
+
+ if (ulOffset + cb > _ulSize)
+ {
+ // increase memory buffer to accomodate write
+
+ ULARGE_INTEGER uliSize;
+
+ ULISetHigh(uliSize, 0);
+ ULISetLow(uliSize, ulOffset + cb);
+ hr = SetSize(uliSize);
+
+ if (FAILED(DfGetScode(hr)))
+ {
+ // don't bother writing partial buffers
+
+ *pcbWritten = 0;
+ return hr;
+ }
+ }
+
+ memcpy((void *)(((BYTE*)_pv) + ulOffset), pv, (size_t) cb);
+ *pcbWritten = cb;
+ return NOERROR;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Member: CMapBytes::Flush, public
+//
+// Synopsis: flushes memory - not appropriate for this implementation
+//
+// Effects: none
+//
+// Returns: SUCCESS_SUCCESS
+//
+// Derivation: ILockBytes
+//
+// History: 06-Nov-92 AlexT Created
+//
+//--------------------------------------------------------------------------
+
+STDMETHODIMP CMapBytes::Flush(void)
+{
+ return NOERROR;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Member: CMapBytes::GetSize, public
+//
+// Synopsis: gets memory buffer size
+//
+// Arguments: [pcb] - size place holder
+//
+// Returns: SUCCESS_SUCCESS
+//
+// Modifies: pcb
+//
+// Derivation: ILockBytes
+//
+// History: 06-Nov-92 AlexT Created
+//
+//--------------------------------------------------------------------------
+
+STDMETHODIMP CMapBytes::GetSize(ULARGE_INTEGER FAR *pcb)
+{
+ ULISetHigh(*pcb, 0);
+ ULISetLow(*pcb, _ulSize);
+ return NOERROR;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Member: CMapBytes::SetSize, public
+//
+// Synopsis: sets memory buffer size
+//
+// Effects: may change buffer size
+//
+// Arguments: [ulicb] - new memory size
+//
+// Returns: SCODE
+//
+// Derivation: ILockBytes
+//
+// Algorithm: realloc the buffer
+//
+// History: 06-Nov-92 AlexT Created
+//
+//--------------------------------------------------------------------------
+
+STDMETHODIMP CMapBytes::SetSize(ULARGE_INTEGER ulicb)
+{
+ olAssert(ULIGetHigh(ulicb) == 0);
+
+ ULONG cb = ULIGetLow(ulicb);
+
+ if (cb == _ulSize)
+ return NOERROR;
+
+ void *pv = realloc(_pv, (size_t) cb);
+
+ if ((cb > 0) && (pv == NULL))
+ {
+ // Unable to allocate memory
+ // Leave current memory and size alone
+
+ return ResultFromScode(E_OUTOFMEMORY);
+ }
+
+ _pv = pv;
+ _ulSize = cb;
+
+ return NOERROR;
+}
+
+//+-------------------------------------------------------------------------
+//
+// Member: CMapBytes::LockRegion, public
+//
+// Synopsis: not supported (intentionally)
+//
+// Effects: asserts if called
+//
+// Arguments: [libOffset] - lock range offset
+// [cb] - lock range size
+// [dwLockType] - lock type
+//
+// Returns: STG_E_INVALIDFUNCTION
+//
+// Derivation: ILockBytes
+//
+// History: 06-Nov-92 AlexT Created
+//
+//--------------------------------------------------------------------------
+
+STDMETHODIMP CMapBytes::LockRegion(ULARGE_INTEGER libOffset,
+ ULARGE_INTEGER cb,
+ DWORD dwLockType)
+{
+ olAssert(0 && "Can't lock CMapBytes");
+ return ResultFromScode(STG_E_INVALIDFUNCTION);
+}
+
+//+-------------------------------------------------------------------------
+//
+// Member: CMapBytes::UnLockRegion, public
+//
+// Synopsis: not supported (intentionally)
+//
+// Effects: asserts if called
+//
+// Arguments: [libOffset] - lock range offset
+// [cb] - lock range size
+// [dwLockType] - lock type
+//
+// Returns: STG_E_INVALIDFUNCTION
+//
+// Derivation: ILockBytes
+//
+// History: 06-Nov-92 AlexT Created
+//
+//--------------------------------------------------------------------------
+
+STDMETHODIMP CMapBytes::UnlockRegion(ULARGE_INTEGER libOffset,
+ ULARGE_INTEGER cb,
+ DWORD dwLockType)
+{
+ olAssert(0 && "Can't unlock CMapBytes");
+ return ResultFromScode(STG_E_INVALIDFUNCTION);
+}
+
+//+-------------------------------------------------------------------------
+//
+// Member: CMapBytes::Stat, public
+//
+// Synopsis: Provide instance information
+//
+// Arguments: [pstatstg] - status buffer
+// [grfStatFlag] - status flags
+//
+// Returns: SCODE
+//
+// Modifies: pstatstg
+//
+// Derivation: ILockBytes
+//
+// History: 06-Nov-92 AlexT Created
+//
+// Notes: No time stamps
+//
+//--------------------------------------------------------------------------
+
+STDMETHODIMP CMapBytes::Stat(STATSTG FAR *pstatstg, DWORD grfStatFlag)
+{
+ memset(pstatstg, 0, sizeof(STATSTG));
+
+ if ((grfStatFlag & STATFLAG_NONAME) == 0)
+ {
+ static char const abName[] = "Memory";
+
+ HRESULT hr;
+
+ if (FAILED(DfGetScode(hr = drtMemAlloc(sizeof(abName),
+ (void **) &pstatstg->pwcsName))))
+ return hr;
+
+ memcpy(pstatstg->pwcsName, abName, sizeof(abName));
+ }
+
+ pstatstg->type = STGTY_LOCKBYTES;
+
+ ULISetHigh(pstatstg->cbSize, 0);
+ ULISetLow(pstatstg->cbSize, _ulSize);
+
+ pstatstg->grfMode = STGM_READWRITE | STGM_DIRECT | STGM_SHARE_EXCLUSIVE;
+
+ return NOERROR;
+}
diff --git a/private/oleutest/stgdrt/ilb.hxx b/private/oleutest/stgdrt/ilb.hxx
new file mode 100644
index 000000000..189dbc1d6
--- /dev/null
+++ b/private/oleutest/stgdrt/ilb.hxx
@@ -0,0 +1,75 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1992.
+//
+// File: ilbmem.hxx
+//
+// Contents: ILockBytes memory implementation
+//
+// Classes: CMapBytes
+//
+// History: 30-Oct-92 AlexT Created
+//
+//--------------------------------------------------------------------------
+
+#ifndef __ILB_HXX__
+
+//#include <dfmsp.hxx> // Pick up UL64 support
+#define ULISetLow(li, v) ((li).LowPart = (v))
+#define ULISetHigh(li, v) ((li).HighPart = (v))
+#define ULIGetLow(li) ((li).LowPart)
+#define ULIGetHigh(li) ((li).HighPart)
+#define AtomicInc(lp) InterlockedIncrement(lp)
+#define AtomicDec(lp) InterlockedDecrement(lp)
+
+#if DBG == 1
+
+DECLARE_DEBUG(ol);
+
+#define olDebugOut(parms) olInlineDebugOut parms
+#define olAssert(exp) Win4Assert(exp)
+
+#else // DBG != 1
+
+#define olDebugOut(parms)
+#define olAssert(exp)
+
+#endif // DBG == 1
+
+class CMapBytes : public ILockBytes
+{
+public:
+ CMapBytes(void);
+
+ STDMETHOD(QueryInterface) (REFIID riid, LPVOID FAR* ppvObj);
+ STDMETHOD_(ULONG,AddRef) (void);
+ STDMETHOD_(ULONG,Release) (void);
+
+ STDMETHOD(ReadAt) (ULARGE_INTEGER ulOffset,
+ VOID HUGEP *pv,
+ ULONG cb,
+ ULONG FAR *pcbRead);
+ STDMETHOD(WriteAt) (ULARGE_INTEGER ulOffset,
+ VOID const HUGEP *pv,
+ ULONG cb,
+ ULONG FAR *pcbWritten);
+ STDMETHOD(Flush) (void);
+ STDMETHOD(GetSize) (ULARGE_INTEGER FAR *pcb);
+ STDMETHOD(SetSize) (ULARGE_INTEGER cb);
+ STDMETHOD(LockRegion) (ULARGE_INTEGER libOffset,
+ ULARGE_INTEGER cb,
+ DWORD dwLockType);
+ STDMETHOD(UnlockRegion) (ULARGE_INTEGER libOffset,
+ ULARGE_INTEGER cb,
+ DWORD dwLockType);
+
+ STDMETHOD(Stat) (STATSTG FAR *pstatstg, DWORD grfStatFlag);
+
+private:
+ LONG _ulRef; // reference count
+ ULONG _ulSize; // memory map size
+ void FAR *_pv; // memory map
+};
+
+#endif // #ifndef __ILB_HXX__
diff --git a/private/oleutest/stgdrt/illeg.cxx b/private/oleutest/stgdrt/illeg.cxx
new file mode 100644
index 000000000..7553a13a5
--- /dev/null
+++ b/private/oleutest/stgdrt/illeg.cxx
@@ -0,0 +1,148 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1992.
+//
+// File: illeg.cxx
+//
+// Contents: Illegitimate tests
+//
+// History: 17-Nov-92 DrewB Created
+//
+//----------------------------------------------------------------------------
+
+#include "headers.cxx"
+#pragma hdrstop
+
+#include <io.h>
+#include <fcntl.h>
+#include <sys\types.h>
+#include <sys\stat.h>
+
+#include "illeg.hxx"
+
+void i_storage(void)
+{
+ WStorage *pwstg;
+ IStorage *pstg, *pstg2;
+ IStream *pstm;
+
+ IllResult("StgCreateDocfile with NULL ppstg",
+ StgCreateDocfile(NULL, 0, 0, NULL));
+ IllResult("StgCreateDocfile with non-zero reserved",
+ StgCreateDocfile(NULL, 0, 1, &pstg));
+ IllResult("StgCreateDocfile with illegal permissions",
+ StgCreateDocfile(NULL, 0, 0, &pstg));
+
+ int fd;
+ fd = _creat(OlecsOut(DRTDF), _S_IREAD);
+ if (fd<0)
+ error(EXIT_BADSC, "Unable to create file '%s'\n", OlecsOut(DRTDF));
+ _close(fd);
+ IllResult("StgCreateDocfile with STGM_WRITE over read-only file",
+ StgCreateDocfile(DRTDF, ROOTP(STGM_READWRITE), 0, &pstg));
+ _chmod(OlecsOut(DRTDF), _S_IREAD | _S_IWRITE);
+
+ IllResult("StgOpenStorage with NULL ppstg",
+ StgOpenStorage(NULL, NULL, 0, NULL, 0, NULL));
+ IllResult("StgOpenStorage with NULL name",
+ StgOpenStorage(NULL, NULL, 0, NULL, 0, &pstg));
+ IllResult("StgOpenStorage with illegal permissions",
+ StgOpenStorage(DRTDF, NULL, 0xffffffff, NULL, 0, &pstg));
+ IllResult("StgOpenStorage with non-zero reserved",
+ StgOpenStorage(DRTDF, NULL, ROOTP(STGM_READWRITE), NULL,
+ 1, &pstg));
+#if WIN32 != 300
+ // This will work on Cairo because it will open a file storage
+ IllResult("StgOpenStorage on non-docfile",
+ StgOpenStorage(DRTDF, NULL, ROOTP(STGM_READWRITE), NULL,
+ 0, &pstg));
+#endif
+
+ WStgCreateDocfile(DRTDF, ROOTP(STGM_READWRITE) | STGM_CREATE, 0, &pwstg);
+ pstg = pwstg->GetI();
+ IllResult("OpenStream that doesn't exist",
+ pstg->OpenStream(STR("NoName"), 0, STMP(STGM_READWRITE),
+ 0, &pstm));
+ IllResult("OpenStorage that doesn't exist",
+ pstg->OpenStorage(STR("NoName"), NULL, STGP(STGM_READWRITE),
+ NULL, 0, &pstg2));
+ pwstg->Unwrap();
+}
+
+#define STREAMSIZE 128
+
+void i_stream(void)
+{
+ WStorage *pwstg;
+ WStream *pwstm;
+ IStream *pstm;
+ BYTE bBuffer[STREAMSIZE];
+ ULONG cbRead;
+ LARGE_INTEGER liSeek;
+ ULARGE_INTEGER uliPos;
+ ULARGE_INTEGER uliSize;
+ ULARGE_INTEGER cb;
+
+ WStgCreateDocfile(DRTDF, ROOTP(STGM_READWRITE), 0, &pwstg);
+ pwstg->CreateStream(STR("Stream"), STMP(STGM_READ), 0, 0, &pwstm);
+ pstm = pwstm->GetI();
+
+ IllResult("Read with NULL buffer",
+ pstm->Read(NULL, STREAMSIZE, NULL));
+ fExitOnFail = FALSE;
+ pwstm->Read(bBuffer, STREAMSIZE, &cbRead);
+ fExitOnFail = TRUE;
+ if (cbRead != 0)
+ error(EXIT_BADSC, "Read %lu bytes on zero-length stream\n", cbRead);
+
+ IllResult("Write with NULL buffer",
+ pstm->Write(NULL, STREAMSIZE, NULL));
+ IllResult("Write on read-only stream",
+ pstm->Write(bBuffer, STREAMSIZE, NULL));
+
+ LISet32(liSeek, 0);
+ IllResult("Seek with invalid origin",
+ pstm->Seek(liSeek, (DWORD)(~STREAM_SEEK_SET), NULL));
+#pragma warning(disable:4245)
+ // LISet32 in objbase.h has a bug that issues warning for negative values
+ LISet32(liSeek, -1);
+#pragma warning(default:4245)
+ IllResult("Seek before beginning",
+ pstm->Seek(liSeek, STREAM_SEEK_CUR, NULL));
+
+ ULISet32(uliSize, STREAMSIZE);
+ IllResult("SetSize on read-only stream",
+ pstm->SetSize(uliSize));
+
+ ULISet32(uliPos, 0);
+ ULISet32(cb, STREAMSIZE);
+ IllResult("LockRegion attempt",
+ pstm->LockRegion(uliPos, cb, LOCK_ONLYONCE));
+ IllResult("UnlockRegion attempt",
+ pstm->UnlockRegion(uliPos, cb, LOCK_ONLYONCE));
+
+ pwstm->Unwrap();
+ pwstg->Unwrap();
+}
+
+void i_enum(void)
+{
+ WStorage *pwstg;
+ IStorage *pstg;
+ IEnumSTATSTG *penm;
+
+ WStgCreateDocfile(DRTDF, ROOTP(STGM_READWRITE), 0, &pwstg);
+ pstg = pwstg->GetI();
+
+ IllResult("EnumElements with NULL ppenm",
+ pstg->EnumElements(0, NULL, 0, NULL));
+ IllResult("EnumElements with non-zero reserved1",
+ pstg->EnumElements(1, NULL, 0, &penm));
+ IllResult("EnumElements with non-zero reserved2",
+ pstg->EnumElements(0, (void *)1, 0, &penm));
+ IllResult("EnumElements with non-zero reserved3",
+ pstg->EnumElements(0, NULL, 1, &penm));
+
+ pwstg->Unwrap();
+}
diff --git a/private/oleutest/stgdrt/illeg.hxx b/private/oleutest/stgdrt/illeg.hxx
new file mode 100644
index 000000000..615560b84
--- /dev/null
+++ b/private/oleutest/stgdrt/illeg.hxx
@@ -0,0 +1,21 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1992.
+//
+// File: illeg.hxx
+//
+// Contents: Illegitimate tests header
+//
+// History: 17-Nov-92 DrewB Created
+//
+//----------------------------------------------------------------------------
+
+#ifndef __ILLEG_HXX__
+#define __ILLEG_HXX__
+
+void i_storage(void);
+void i_stream(void);
+void i_enum(void);
+
+#endif // #ifndef __ILLEG_HXX__
diff --git a/private/oleutest/stgdrt/strlist.cxx b/private/oleutest/stgdrt/strlist.cxx
new file mode 100644
index 000000000..3afc14d9c
--- /dev/null
+++ b/private/oleutest/stgdrt/strlist.cxx
@@ -0,0 +1,148 @@
+//+--------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1992.
+//
+// File: strlist.cxx
+//
+// Contents: CStrList implementation
+//
+// History: 24-Sep-92 DrewB Created
+//
+//---------------------------------------------------------------
+
+#include "headers.cxx"
+#pragma hdrstop
+
+#include <string.h>
+
+//+--------------------------------------------------------------
+//
+// Member: CStrList::CStrList, public
+//
+// Synopsis: Ctor
+//
+// History: 24-Sep-92 DrewB Created
+//
+//---------------------------------------------------------------
+
+CStrList::CStrList(void)
+{
+ _pseHead = NULL;
+}
+
+//+--------------------------------------------------------------
+//
+// Member: CStrList::~CStrList, public
+//
+// Synopsis: Dtor
+//
+// History: 24-Sep-92 DrewB Created
+//
+//---------------------------------------------------------------
+
+CStrList::~CStrList(void)
+{
+ Empty();
+}
+
+//+--------------------------------------------------------------
+//
+// Member: CStrList::Add, public
+//
+// Synopsis: Adds a string to the list
+//
+// Arguments: [ptcs] - String
+//
+// Returns: Pointer to entry or NULL
+//
+// History: 24-Sep-92 DrewB Created
+//
+//---------------------------------------------------------------
+
+SStrEntry *CStrList::Add(OLECHAR *ptcs)
+{
+ SStrEntry *pse;
+
+ // One char of string already counted in sizeof
+ pse = (SStrEntry *)new
+ char[sizeof(SStrEntry)+olecslen(ptcs)*sizeof(OLECHAR)];
+ if (pse == NULL)
+ return NULL;
+ pse->pseNext = _pseHead;
+ pse->psePrev = NULL;
+ if (_pseHead)
+ _pseHead->psePrev = pse;
+ _pseHead = pse;
+ olecscpy(pse->atc, ptcs);
+ return pse;
+}
+
+//+--------------------------------------------------------------
+//
+// Member: CStrList::Remove, public
+//
+// Synopsis: Removes an entry from the list
+//
+// Arguments: [pse] - Entry
+//
+// History: 24-Sep-92 DrewB Created
+//
+//---------------------------------------------------------------
+
+void CStrList::Remove(SStrEntry *pse)
+{
+ if (pse->psePrev)
+ pse->psePrev->pseNext = pse->pseNext;
+ else
+ _pseHead = pse->pseNext;
+ if (pse->pseNext)
+ pse->pseNext->psePrev = pse->psePrev;
+ delete pse;
+}
+
+//+--------------------------------------------------------------
+//
+// Member: CStrList::Find, public
+//
+// Synopsis: Attempts to find a string in the list
+//
+// Arguments: [ptcs] - String
+//
+// Returns: Entry or NULL
+//
+// History: 24-Sep-92 DrewB Created
+//
+//---------------------------------------------------------------
+
+SStrEntry *CStrList::Find(OLECHAR *ptcs)
+{
+ SStrEntry *pse;
+
+ for (pse = _pseHead; pse; pse = pse->pseNext)
+ if (!olecscmp(ptcs, pse->atc))
+ return pse;
+ return NULL;
+}
+
+//+--------------------------------------------------------------
+//
+// Member: CStrList::Empty, public
+//
+// Synopsis: Frees all elements in list
+//
+// History: 24-Sep-92 DrewB Created
+//
+//---------------------------------------------------------------
+
+void CStrList::Empty(void)
+{
+ SStrEntry *pse;
+
+ while (_pseHead)
+ {
+ pse = _pseHead->pseNext;
+ delete _pseHead;
+ _pseHead = pse;
+ }
+}
diff --git a/private/oleutest/stgdrt/strlist.hxx b/private/oleutest/stgdrt/strlist.hxx
new file mode 100644
index 000000000..4e0824be6
--- /dev/null
+++ b/private/oleutest/stgdrt/strlist.hxx
@@ -0,0 +1,49 @@
+//+--------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1992.
+//
+// File: strlist.hxx
+//
+// Contents: CStrList header
+//
+// Classes: CStrList
+//
+// History: 24-Sep-92 DrewB Created
+//
+//---------------------------------------------------------------
+
+#ifndef __STRLIST_HXX__
+#define __STRLIST_HXX__
+
+#include <drt.hxx>
+
+struct SStrEntry
+{
+ SStrEntry *pseNext, *psePrev;
+ union
+ {
+ void *pv;
+ unsigned long dw;
+ } user;
+ OLECHAR atc[1]; // Actually contains the whole string
+};
+
+class CStrList
+{
+public:
+ CStrList(void);
+ ~CStrList(void);
+
+ SStrEntry *Add(OLECHAR *ptcs);
+ void Remove(SStrEntry *pse);
+ SStrEntry *Find(OLECHAR *ptcs);
+ void Empty(void);
+
+ SStrEntry *GetHead(void) { return _pseHead; }
+
+private:
+ SStrEntry *_pseHead;
+};
+
+#endif // #ifndef __STRLIST_HXX__
diff --git a/private/oleutest/stgdrt/tests.cxx b/private/oleutest/stgdrt/tests.cxx
new file mode 100644
index 000000000..f033a6b7b
--- /dev/null
+++ b/private/oleutest/stgdrt/tests.cxx
@@ -0,0 +1,812 @@
+//+--------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1992.
+//
+// File: tests.cxx
+//
+// Contents: DRT tests
+//
+// History: 23-Sep-92 DrewB Created
+//
+//---------------------------------------------------------------
+
+#include "headers.cxx"
+#pragma hdrstop
+
+#include "tests.hxx"
+#include "ilb.hxx"
+
+void t_create(void)
+{
+ WStorage *pstgRoot, *pstgChild, *pstgChild2;
+ WStream *pstm;
+
+ WStgCreateDocfile(DRTDF, ROOTP(WSTG_READWRITE) | WSTG_CREATE,
+ 0, &pstgRoot);
+ pstgRoot->CreateStorage(STR("Child"), STGP(WSTG_READWRITE), 0, 0,
+ &pstgChild);
+ pstgChild->CreateStorage(STR("Child2"), STGP(WSTG_READWRITE), 0, 0,
+ &pstgChild2);
+ pstgChild2->CreateStream(STR("Stream"), STMP(WSTG_READWRITE), 0, 0,
+ &pstm);
+ pstm->Unwrap();
+ pstgChild2->Commit(0);
+ pstgChild2->Unwrap();
+ pstgChild->Commit(0);
+ pstgChild->Unwrap();
+ VerifyStructure(pstgRoot->GetI(), "dChild(dChild2(sStream))");
+ pstgRoot->Unwrap();
+}
+
+void t_open(void)
+{
+ WStorage *pstgRoot, *pstgChild, *pstgChild2;
+ WStream *pstm;
+
+ WStgCreateDocfile(DRTDF, ROOTP(WSTG_READWRITE) | WSTG_CREATE,
+ 0, &pstgRoot);
+ CreateStructure(pstgRoot->GetI(), "dChild(dChild2(sStream))");
+ pstgRoot->Commit(0);
+ pstgRoot->Unwrap();
+
+ WStgOpenStorage(DRTDF, NULL, ROOTP(WSTG_READWRITE), NULL,
+ 0, &pstgRoot);
+ pstgRoot->OpenStorage(STR("Child"), NULL, STGP(WSTG_READWRITE), NULL, 0,
+ &pstgChild);
+ pstgChild->OpenStorage(STR("Child2"), NULL, STGP(WSTG_READWRITE), NULL, 0,
+ &pstgChild2);
+ pstgChild2->OpenStream(STR("Stream"), NULL, STMP(WSTG_READWRITE), 0,
+ &pstm);
+ pstm->Unwrap();
+ pstgChild2->Unwrap();
+ pstgChild->Unwrap();
+ pstgRoot->Unwrap();
+}
+
+void t_addref(void)
+{
+ WStorage *pstg;
+ WStream *pstm;
+ ULONG ul;
+
+ WStgCreateDocfile(DRTDF, ROOTP(WSTG_READWRITE) | WSTG_CREATE,
+ 0, &pstg);
+ pstg->CreateStream(STR("Stream"), STMP(WSTG_READWRITE), 0, 0, &pstm);
+#ifndef FLAT
+ if ((ul = pstm->AddRef()) != 2)
+ error(EXIT_BADSC, "Wrong reference count - %lu\n", ul);
+ if ((ul = pstm->Release()) != 1)
+ error(EXIT_BADSC, "Wrong reference count - %lu\n", ul);
+ pstm->Unwrap();
+ if ((ul = pstg->AddRef()) != 2)
+ error(EXIT_BADSC, "Wrong reference count - %lu\n", ul);
+ if ((ul = pstg->Release()) != 1)
+ error(EXIT_BADSC, "Wrong reference count - %lu\n", ul);
+#else
+ if ((ul = pstm->AddRef()) <= 0)
+ error(EXIT_BADSC, "Wrong reference count - %lu\n", ul);
+ if ((ul = pstm->Release()) <= 0)
+ error(EXIT_BADSC, "Wrong reference count - %lu\n", ul);
+ pstm->Unwrap();
+ if ((ul = pstg->AddRef()) <= 0)
+ error(EXIT_BADSC, "Wrong reference count - %lu\n", ul);
+ if ((ul = pstg->Release()) <= 0)
+ error(EXIT_BADSC, "Wrong reference count - %lu\n", ul);
+#endif
+ pstg->Unwrap();
+}
+
+void t_tmodify(void)
+{
+ WStorage *pstgRoot, *pstgChild, *pstgChild2;
+ WStream *pstm;
+
+ // This test must use transacted mode to reproduce the
+ // expected behavior
+ ForceTransacted();
+
+ WStgCreateDocfile(DRTDF, ROOTP(WSTG_READWRITE) | WSTG_CREATE,
+ 0, &pstgRoot);
+ pstgRoot->CreateStorage(STR("Child"), STGP(WSTG_READWRITE), 0,
+ 0, &pstgChild);
+ pstgChild->CreateStorage(STR("Child2"), STGP(WSTG_READWRITE), 0,
+ 0, &pstgChild2);
+ pstgChild2->CreateStream(STR("Stream"), STMP(WSTG_READWRITE), 0, 0, &pstm);
+ pstm->Unwrap();
+ pstgChild2->Commit(0);
+ VerifyStructure(pstgChild2->GetI(), "sStream");
+
+ // Test renaming a closed stream
+ pstgChild2->RenameElement(STR("Stream"), STR("RenamedStream"));
+ VerifyStructure(pstgChild2->GetI(), "sRenamedStream");
+
+ // Test rename reversion
+ pstgChild2->Revert();
+ VerifyStructure(pstgChild2->GetI(), "sStream");
+
+ // Test destruction of closed object
+ pstgChild2->DestroyElement(STR("Stream"));
+ pstgChild2->Commit(0);
+
+ // Test create of previously deleted object
+ pstgChild2->CreateStream(STR("Stream"), STMP(WSTG_READWRITE), 0, 0, &pstm);
+ pstgChild2->Commit(0);
+ VerifyStructure(pstgChild2->GetI(), "sStream");
+
+#if 0
+ // 08/11/93 - Renaming open children no longer allowed
+ // Test renaming an open stream
+ pstgChild2->RenameElement(STR("Stream"), STR("RenamedStream"));
+ VerifyStructure(pstgChild2->GetI(), "sRenamedStream");
+#endif
+
+ pstgChild2->Revert();
+ VerifyStructure(pstgChild2->GetI(), "sStream");
+ pstgChild2->DestroyElement(STR("Stream"));
+ pstgChild2->Commit(0);
+ pstm->Unwrap();
+
+ pstgChild2->Unwrap();
+ VerifyStructure(pstgChild->GetI(), "dChild2()");
+
+ // Test rename of storage
+ pstgChild->RenameElement(STR("Child2"), STR("RenamedChild"));
+ pstgChild->CreateStream(STR("Stream"), STMP(WSTG_READWRITE), 0, 0,
+ &pstm);
+ pstm->Unwrap();
+ pstgChild->DestroyElement(STR("Stream"));
+ pstgChild->Commit(0);
+
+ // Test SetElementTimes
+ FILETIME tm;
+ STATSTG stat;
+
+ tm.dwLowDateTime = 0x12345678;
+ tm.dwHighDateTime = 0x01bcdef0;
+
+ // Set when element not open
+ pstgChild->SetElementTimes(STR("RenamedChild"), &tm, NULL, NULL);
+ pstgChild->SetElementTimes(STR("RenamedChild"), NULL, &tm, NULL);
+ pstgChild->SetElementTimes(STR("RenamedChild"), NULL, NULL, &tm);
+
+ pstgChild->OpenStorage(STR("RenamedChild"), NULL, STGP(WSTG_READWRITE),
+ NULL, 0, &pstgChild2);
+ pstgChild2->Stat(&stat, STATFLAG_NONAME);
+ if (!IsEqualTime(stat.ctime, tm) ||
+ !IsEqualTime(stat.mtime, tm))
+ error(EXIT_BADSC, "Times don't match those set by SetElementTimes\n");
+
+ // Test SetClass and SetStateBits
+ pstgChild2->SetClass(IID_IStorage);
+ fExitOnFail = FALSE;
+ pstgChild2->SetStateBits(0xff00ff00, 0xffffffff);
+ pstgChild2->SetStateBits(0x00880088, 0xeeeeeeee);
+ fExitOnFail = TRUE;
+ pstgChild2->Stat(&stat, STATFLAG_NONAME);
+ if (!IsEqualCLSID(stat.clsid, IID_IStorage))
+ error(EXIT_BADSC, "Class ID set to %s\n", GuidText(&stat.clsid));
+ if (stat.grfStateBits != 0x11881188)
+ errorprint("State bits set improperly: has %lX vs. %lX\n",
+ stat.grfStateBits, 0x11881188);
+ pstgChild2->Revert();
+ pstgChild2->Stat(&stat, STATFLAG_NONAME);
+ if (!IsEqualCLSID(stat.clsid, CLSID_NULL))
+ error(EXIT_BADSC, "Class ID reverted to %s\n", GuidText(&stat.clsid));
+ if (stat.grfStateBits != 0)
+ errorprint("State bits reverted improperly: has %lX vs. %lX\n",
+ stat.grfStateBits, 0);
+ pstgChild2->Unwrap();
+
+ pstgChild->Unwrap();
+ VerifyStructure(pstgRoot->GetI(), "dChild(dRenamedChild())");
+ pstgRoot->Revert();
+ VerifyStructure(pstgRoot->GetI(), "");
+ pstgRoot->Commit(0);
+ VerifyStructure(pstgRoot->GetI(), "");
+ pstgRoot->Unwrap();
+ Unforce();
+}
+
+void t_dmodify(void)
+{
+ WStorage *pstgRoot, *pstgChild, *pstgChild2;
+ WStream *pstm;
+ ULONG cbSize1, cbSize2;
+
+ // This test must use direct mode to reproduce the
+ // expected behavior
+ ForceDirect();
+
+ WStgCreateDocfile(DRTDF, ROOTP(WSTG_READWRITE) | WSTG_CREATE,
+ 0, &pstgRoot);
+ pstgRoot->CreateStorage(STR("Child"), STGP(WSTG_READWRITE), 0,
+ 0, &pstgChild);
+ pstgChild->CreateStorage(STR("Child2"), STGP(WSTG_READWRITE), 0,
+ 0, &pstgChild2);
+ pstgChild2->CreateStream(STR("Stream"), STMP(WSTG_READWRITE), 0, 0, &pstm);
+ pstm->Unwrap();
+ VerifyStructure(pstgChild2->GetI(), "sStream");
+
+ // Test renaming a closed stream
+ pstgChild2->RenameElement(STR("Stream"), STR("RenamedStream"));
+ VerifyStructure(pstgChild2->GetI(), "sRenamedStream");
+
+ // Test destroying a stream
+ pstgChild2->DestroyElement(STR("RenamedStream"));
+
+#if 0
+ // 08/11/93 - Renaming open child no longer allowed
+ // Test renaming an open stream
+ pstgChild2->CreateStream(STR("Stream"), STMP(WSTG_READWRITE), 0, 0, &pstm);
+ VerifyStructure(pstgChild2->GetI(), "sStream");
+ pstgChild2->RenameElement(STR("Stream"), STR("RenamedStream"));
+ VerifyStructure(pstgChild2->GetI(), "sRenamedStream");
+ pstgChild2->DestroyElement(STR("RenamedStream"));
+ pstm->Unwrap();
+#endif
+
+ pstgChild2->Unwrap();
+ VerifyStructure(pstgChild->GetI(), "dChild2()");
+
+ // Test renaming a storage
+ pstgChild->RenameElement(STR("Child2"), STR("RenamedChild"));
+ pstgChild->CreateStream(STR("Stream"), STMP(WSTG_READWRITE), 0, 0,
+ &pstm);
+ pstm->Unwrap();
+ pstgChild->DestroyElement(STR("Stream"));
+
+ // Test SetElementTimes
+ FILETIME tm;
+ STATSTG stat;
+
+ tm.dwLowDateTime = 0x12345678;
+ tm.dwHighDateTime = 0x01bcdef0;
+
+ // Set when element not open
+ pstgChild->SetElementTimes(STR("RenamedChild"), &tm, NULL, NULL);
+ pstgChild->SetElementTimes(STR("RenamedChild"), NULL, &tm, NULL);
+ pstgChild->SetElementTimes(STR("RenamedChild"), NULL, NULL, &tm);
+
+ pstgChild->OpenStorage(STR("RenamedChild"), NULL, STMP(WSTG_READWRITE),
+ NULL, 0, &pstgChild2);
+ pstgChild2->Stat(&stat, STATFLAG_NONAME);
+ if (!IsEqualTime(stat.ctime, tm) ||
+ !IsEqualTime(stat.mtime, tm))
+ error(EXIT_BADSC, "Times don't match those set by SetElementTimes\n");
+
+ // Test SetClass and SetStateBits
+ pstgChild2->SetClass(IID_IStorage);
+ fExitOnFail = FALSE;
+ pstgChild2->SetStateBits(0xff00ff00, 0xffffffff);
+ pstgChild2->SetStateBits(0x00880088, 0xeeeeeeee);
+ fExitOnFail = TRUE;
+ pstgChild2->Stat(&stat, STATFLAG_NONAME);
+ if (!IsEqualCLSID(stat.clsid, IID_IStorage))
+ error(EXIT_BADSC, "Class ID set improperly\n");
+ if (stat.grfStateBits != 0x11881188)
+ errorprint("State bits set improperly: has %lX vs. %lX\n",
+ stat.grfStateBits, 0x11881188);
+ pstgChild2->Unwrap();
+
+ pstgChild->Unwrap();
+ VerifyStructure(pstgRoot->GetI(), "dChild(dRenamedChild())");
+ pstgRoot->Revert();
+ VerifyStructure(pstgRoot->GetI(), "dChild(dRenamedChild())");
+ pstgRoot->Commit(0);
+ VerifyStructure(pstgRoot->GetI(), "dChild(dRenamedChild())");
+ pstgRoot->DestroyElement(STR("Child"));
+ VerifyStructure(pstgRoot->GetI(), "");
+
+ // Verify that space is reclaimed after modifications
+ pstgRoot->CreateStream(STR("Stream"), STMP(WSTG_READWRITE), 0, 0, &pstm);
+ pstm->SetSize(65536);
+ pstm->Unwrap();
+ cbSize1 = Length(DRTDF);
+ pstgRoot->DestroyElement(STR("Stream"));
+ pstgRoot->CreateStream(STR("Stream"), STMP(WSTG_READWRITE), 0, 0, &pstm);
+ pstm->SetSize(65536);
+ pstm->Unwrap();
+ cbSize2 = Length(DRTDF);
+ if (cbSize1 != cbSize2)
+ error(EXIT_BADSC, "Space is not being reclaimed, original %lu, "
+ "now %lu\n", cbSize1, cbSize2);
+
+ pstgRoot->Unwrap();
+
+ WStgCreateDocfile(NULL, ROOTP(WSTG_READWRITE) | WSTG_CREATE |
+ WSTG_DELETEONRELEASE, 0, &pstgRoot);
+
+ // removal cases
+ // 1) no right child
+
+ CreateStructure(pstgRoot->GetI(), "d64,d32");
+ VerifyStructure(pstgRoot->GetI(), "d64,d32");
+ pstgRoot->DestroyElement(STR("64"));
+ VerifyStructure(pstgRoot->GetI(), "d32");
+
+ // 2) right child has no left child
+
+ CreateStructure(pstgRoot->GetI(), "d64");
+ VerifyStructure(pstgRoot->GetI(), "d32,d64");
+ pstgRoot->DestroyElement(STR("32"));
+ VerifyStructure(pstgRoot->GetI(), "d64");
+
+ // 3) right child has left child
+
+ CreateStructure(pstgRoot->GetI(), "d96,d80");
+ VerifyStructure(pstgRoot->GetI(), "d64,d80,d96");
+ pstgRoot->DestroyElement(STR("64"));
+ VerifyStructure(pstgRoot->GetI(), "d80,d96");
+
+ // 4) right child's left child has children
+
+ CreateStructure(pstgRoot->GetI(), "d88,d84,d92");
+ VerifyStructure(pstgRoot->GetI(), "d80,d84,d88,d92,d96");
+ pstgRoot->DestroyElement(STR("80"));
+ VerifyStructure(pstgRoot->GetI(), "d84,d88,d92,d96");
+
+ pstgRoot->Unwrap();
+
+ Unforce();
+}
+
+void t_stat(void)
+{
+ WStorage *pstgRoot, *pstgChild;
+ WStream *pstm;
+ STATSTG stat;
+
+ WStgCreateDocfile(DRTDF, ROOTP(WSTG_READWRITE) | WSTG_CREATE,
+ 0, &pstgRoot);
+ pstgRoot->CreateStorage(STR("Child"), STGP(WSTG_READWRITE), 0, 0,
+ &pstgChild);
+ pstgChild->CreateStream(STR("Stream"), STMP(WSTG_READWRITE), 0, 0, &pstm);
+
+ pstm->Stat(&stat, 0);
+ VerifyStat(&stat, STR("Stream"), STGTY_STREAM, STMP(WSTG_READWRITE));
+ drtMemFree(stat.pwcsName);
+
+ pstm->Stat(&stat, STATFLAG_NONAME);
+ VerifyStat(&stat, NULL, STGTY_STREAM, STMP(WSTG_READWRITE));
+
+ pstm->Unwrap();
+
+ pstgChild->Stat(&stat, 0);
+ VerifyStat(&stat, STR("Child"), STGTY_STORAGE, STGP(WSTG_READWRITE));
+ drtMemFree(stat.pwcsName);
+
+ pstgChild->Stat(&stat, STATFLAG_NONAME);
+ VerifyStat(&stat, NULL, STGTY_STORAGE, STGP(WSTG_READWRITE));
+
+ pstgChild->Unwrap();
+
+ pstgRoot->Stat(&stat, 0);
+ OLECHAR atcFullPath[_MAX_PATH];
+ GetFullPath(DRTDF, atcFullPath);
+ VerifyStat(&stat, atcFullPath, STGTY_STORAGE, ROOTP(WSTG_READWRITE));
+ drtMemFree(stat.pwcsName);
+
+ pstgRoot->Stat(&stat, STATFLAG_NONAME);
+ VerifyStat(&stat, NULL, STGTY_STORAGE, ROOTP(WSTG_READWRITE));
+
+ pstgRoot->Unwrap();
+}
+
+static char NUMBERS[] = "12345678901234567890123456789012345678901234567890";
+
+void t_stream(void)
+{
+ WStorage *pstg;
+ WStream *pstm, *pstmC;
+ char buf[sizeof(NUMBERS)*2];
+ ULONG cb, ulPos;
+
+ WStgCreateDocfile(DRTDF, ROOTP(WSTG_READWRITE) | WSTG_CREATE, 0, &pstg);
+ pstg->CreateStream(STR("Stream"), STMP(WSTG_READWRITE), 0, 0, &pstm);
+ pstm->Write(NUMBERS, sizeof(NUMBERS), &cb);
+ pstm->Commit(0);
+ pstm->Seek(0, WSTM_SEEK_SET, &ulPos);
+ if (ulPos != 0)
+ error(EXIT_BADSC, "Incorrect seek, ptr is %lu\n", ulPos);
+ pstm->Read(buf, sizeof(NUMBERS), &cb);
+ if (strcmp(buf, NUMBERS))
+ error(EXIT_BADSC, "Incorrect stream contents\n");
+ pstm->SetSize(sizeof(NUMBERS)/2);
+ pstm->Seek(0, WSTM_SEEK_SET, NULL);
+ fExitOnFail = FALSE;
+ pstm->Read(buf, sizeof(NUMBERS), &cb);
+ fExitOnFail = TRUE;
+ if (cb != sizeof(NUMBERS)/2)
+ error(EXIT_BADSC, "SetSize failed to size stream properly\n");
+ if (memcmp(buf, NUMBERS, sizeof(NUMBERS)/2))
+ error(EXIT_BADSC, "SetSize corrupted contents\n");
+ pstm->Clone(&pstmC);
+ pstm->Seek(0, WSTM_SEEK_SET, NULL);
+ pstm->CopyTo(pstmC, sizeof(NUMBERS)/2, NULL, NULL);
+ pstm->Seek(0, WSTM_SEEK_SET, NULL);
+ pstm->CopyTo(pstmC, sizeof(NUMBERS)&~1, NULL, NULL);
+ pstm->Seek(0, WSTM_SEEK_SET, NULL);
+ pstm->Read(buf, (sizeof(NUMBERS)&~1)*2, &cb);
+ if (memcmp(buf, NUMBERS, sizeof(NUMBERS)/2) ||
+ memcmp(buf+sizeof(NUMBERS)/2, NUMBERS, sizeof(NUMBERS)/2) ||
+ memcmp(buf+(sizeof(NUMBERS)&~1), NUMBERS, sizeof(NUMBERS)/2) ||
+ memcmp(buf+3*(sizeof(NUMBERS)/2), NUMBERS, sizeof(NUMBERS)/2))
+ error(EXIT_BADSC, "Stream contents incorrect\n");
+ pstmC->Unwrap();
+ pstm->Unwrap();
+ pstg->Unwrap();
+}
+
+// Number of entries for enumeration test
+#define ENUMENTRIES 10
+
+// Flag indicating a name has already shown up in enumeration,
+// must not conflict with STGTY_*
+#define ENTRY_SEEN 0x100
+
+// Check the validity of an enumeration element
+static void elt_check(STATSTG *pstat, CStrList *psl)
+{
+ SStrEntry *pse;
+
+ pse = psl->Find(pstat->pwcsName);
+ if (pse == NULL)
+ error(EXIT_BADSC, "Spurious element '%s'\n", pstat->pwcsName);
+ else if ((pse->user.dw & ~ENTRY_SEEN) != pstat->type)
+ error(EXIT_BADSC, "Element '%s' has wrong type - "
+ "has %lX vs. %lX\n", pstat->pwcsName, pstat->type,
+ pse->user.dw & ~ENTRY_SEEN);
+ else if (pse->user.dw & ENTRY_SEEN)
+ error(EXIT_BADSC, "Element '%s' has already been seen\n",
+ pstat->pwcsName);
+ pse->user.dw |= ENTRY_SEEN;
+}
+
+// Do final validity checks for enumeration
+static void enum_list_check(CStrList *psl)
+{
+ SStrEntry *pse;
+
+ for (pse = psl->GetHead(); pse; pse = pse->pseNext)
+ {
+ if ((pse->user.dw & ENTRY_SEEN) == 0)
+ error(EXIT_BADSC, "Element '%s' not found\n", pse->atc);
+ pse->user.dw &= ~ENTRY_SEEN;
+ }
+}
+
+void t_enum(void)
+{
+ int i;
+ OLECHAR atcName[CWCSTORAGENAME];
+ WStorage *pstg, *pstg2;
+ WStream *pstm;
+ SStrEntry *pse;
+ CStrList sl;
+
+ // Create some entries to enumerate
+ WStgCreateDocfile(DRTDF, ROOTP(WSTG_READWRITE) | WSTG_CREATE, 0, &pstg);
+ for (i = 0; i<ENUMENTRIES; i++)
+ {
+ olecsprintf(atcName, STR("Name%d"), rand());
+ pse = sl.Add(atcName);
+ if (rand()%100 < 50)
+ {
+ pse->user.dw = STGTY_STORAGE;
+ pstg->CreateStorage(atcName, STGP(WSTG_READWRITE), 0, 0, &pstg2);
+ pstg2->Unwrap();
+ }
+ else
+ {
+ pse->user.dw = STGTY_STREAM;
+ pstg->CreateStream(atcName, STMP(WSTG_READWRITE), 0, 0, &pstm);
+ pstm->Unwrap();
+ }
+ }
+
+ WEnumSTATSTG *penm;
+ STATSTG stat[2*ENUMENTRIES];
+ SCODE sc;
+
+ // Test plain, single element enumeration
+ pstg->EnumElements(0, NULL, 0, &penm);
+ for (;;)
+ {
+ sc = DfGetScode(penm->Next(1, stat, NULL));
+ if (sc == S_FALSE)
+ break;
+ elt_check(stat, &sl);
+ drtMemFree(stat->pwcsName);
+
+ }
+ enum_list_check(&sl);
+
+ ULONG cFound;
+
+ // Test rewind and multiple element enumeration with too many elements
+ penm->Reset();
+ sc = DfGetScode(penm->Next(ENUMENTRIES*2, stat, &cFound));
+ if (sc != S_FALSE)
+ error(EXIT_BADSC, "Enumerator returned %s (%lX) instead of "
+ "S_FALSE\n", ScText(sc), sc);
+ if (cFound != ENUMENTRIES)
+ error(EXIT_BADSC, "Enumerator found %lu entries instead of "
+ "%d entries\n", cFound, ENUMENTRIES);
+ for (; cFound > 0; cFound--)
+ {
+ elt_check(&stat[cFound-1], &sl);
+ drtMemFree(stat[cFound-1].pwcsName);
+ }
+ enum_list_check(&sl);
+
+ // Test skip and multiple enumeration with exact number of elements
+ penm->Reset();
+ penm->Skip(ENUMENTRIES/2);
+ sc = DfGetScode(penm->Next(ENUMENTRIES-ENUMENTRIES/2, stat, &cFound));
+ if (sc != S_OK)
+ error(EXIT_BADSC, "Enumerator returned %s (%lX) instead of "
+ "S_OK\n", ScText(sc), sc);
+ if (cFound != ENUMENTRIES-ENUMENTRIES/2)
+ error(EXIT_BADSC, "Enumerator found %lu entries instead of "
+ "%d entries\n", cFound, ENUMENTRIES-ENUMENTRIES/2);
+ for (; cFound > 0; cFound--)
+ {
+ elt_check(&stat[cFound-1], &sl);
+ drtMemFree(stat[cFound-1].pwcsName);
+ }
+ sc = DfGetScode(penm->Next(1, stat, NULL));
+ if (sc != S_FALSE)
+ error(EXIT_BADSC, "Enumerator returned %s (%lX) instead of "
+ "S_FALSE\n", ScText(sc), sc);
+
+ penm->Unwrap();
+ pstg->Unwrap();
+}
+
+#define SCT_CLASSID IID_ILockBytes
+#define SCT_STATEBITS 0xfef1f0f0
+
+void t_stgcopyto(void)
+{
+ WStorage *pstgFrom, *pstgTo;
+ STATSTG statFrom, statTo;
+
+ WStgCreateDocfile(NULL, ROOTP(WSTG_READWRITE) | WSTG_CREATE |
+ WSTG_DELETEONRELEASE, 0, &pstgFrom);
+ pstgFrom->Stat(&statFrom, 0);
+
+ // Set some interesting values to make sure they're copied
+ pstgFrom->SetClass(SCT_CLASSID);
+ fExitOnFail = FALSE;
+ pstgFrom->SetStateBits(SCT_STATEBITS, 0xffffffff);
+ fExitOnFail = TRUE;
+
+ WStgCreateDocfile(NULL, ROOTP(WSTG_READWRITE) | WSTG_CREATE |
+ WSTG_DELETEONRELEASE, 0, &pstgTo);
+ CreateStructure(pstgFrom->GetI(), "dA(dB(dC(sA,sB,sC),sCs),sBs),sAs");
+ CreateStructure(pstgTo->GetI(), "dA(dY(sZ),sBs)");
+
+ pstgFrom->CopyTo(0, NULL, NULL, pstgTo);
+
+ VerifyStructure(pstgTo->GetI(),
+ "dA(dB(dC(sA,sB,sC),sCs),dY(sZ),sBs),sAs");
+ pstgTo->Stat(&statTo, 0);
+ if (!IsEqualCLSID(statTo.clsid, SCT_CLASSID))
+ error(EXIT_BADSC, "Class ID mismatch after copy\n");
+ if (statTo.grfStateBits != SCT_STATEBITS)
+ errorprint("State bits mismatch: has %lX vs. %lX\n",
+ statTo.grfStateBits, SCT_STATEBITS);
+
+ pstgFrom->Unwrap();
+ pstgTo->Unwrap();
+ if (Exists(statFrom.pwcsName))
+ error(EXIT_BADSC, "Storage '%s' not deleted\n", statFrom.pwcsName);
+ drtMemFree(statFrom.pwcsName);
+ if (Exists(statTo.pwcsName))
+ error(EXIT_BADSC, "Storage '%s' not deleted\n", statTo.pwcsName);
+ drtMemFree(statTo.pwcsName);
+}
+
+#define MARSHAL_STM STR("Marshal")
+
+void do_marshal(WStorage *pstg, WStream *pstm)
+{
+ WStorage *pstgMarshal;
+ WStream *pstmMarshal;
+
+ WStgCreateDocfile(MARSHALDF, ROOTP(WSTG_READWRITE) | WSTG_CREATE,
+ 0, &pstgMarshal);
+ pstgMarshal->CreateStream(MARSHAL_STM, STMP(WSTG_READWRITE), 0, 0,
+ &pstmMarshal);
+ WCoMarshalInterface(pstmMarshal, IID_IStorage, pstg->GetI(), 0, NULL,
+ MSHLFLAGS_NORMAL);
+ WCoMarshalInterface(pstmMarshal, IID_IStream, pstm->GetI(), 0, NULL,
+ MSHLFLAGS_NORMAL);
+ WCoMarshalInterface(pstmMarshal, IID_IUnknown, pstg->GetI(), 0, NULL,
+ MSHLFLAGS_NORMAL);
+ WCoMarshalInterface(pstmMarshal, IID_IUnknown, pstm->GetI(), 0, NULL,
+ MSHLFLAGS_NORMAL);
+ pstmMarshal->Unwrap();
+ pstgMarshal->Commit(0);
+ pstgMarshal->Unwrap();
+}
+
+static char STREAM_DATA[] = "This is data to be written";
+
+void do_unmarshal(WStorage **ppstg, WStream **ppstm,
+ IUnknown **ppstg2, IUnknown **ppstm2)
+{
+ IStorage *pistg;
+ WStorage *pstgMarshal;
+ WStream *pstmMarshal;
+ IStream *pistm;
+
+ WStgOpenStorage(MARSHALDF, NULL, ROOTP(WSTG_READWRITE), NULL, 0,
+ &pstgMarshal);
+ pstgMarshal->OpenStream(MARSHAL_STM, NULL, STMP(WSTG_READWRITE), 0,
+ &pstmMarshal);
+ WCoUnmarshalInterface(pstmMarshal, IID_IStorage, (void **)&pistg);
+ *ppstg = WStorage::Wrap(pistg);
+ WCoUnmarshalInterface(pstmMarshal, IID_IStream, (void **)&pistm);
+ *ppstm = WStream::Wrap(pistm);
+ WCoUnmarshalInterface(pstmMarshal, IID_IUnknown, (void **)ppstg2);
+ WCoUnmarshalInterface(pstmMarshal, IID_IUnknown, (void **)ppstm2);
+ pstmMarshal->Unwrap();
+ pstgMarshal->Unwrap();
+}
+
+void t_marshal(void)
+{
+ WStorage *pstg, *pstgM;
+ WStream *pstm, *pstmM;
+ IUnknown *pstgM2, *pstmM2;
+ ULONG cbRead, cbWritten;
+ char buf[sizeof(STREAM_DATA)];
+
+ WStgCreateDocfile(DRTDF, ROOTP(WSTG_READWRITE) | WSTG_CREATE |
+ WSTG_DELETEONRELEASE, 0, &pstg);
+ pstg->CreateStream(STR("Stream"), STMP(WSTG_READWRITE), 0, 0, &pstm);
+ pstm->Write(STREAM_DATA, sizeof(STREAM_DATA), &cbWritten);
+ CreateStructure(pstg->GetI(), "dChild(dChild(sStream))");
+
+ do_marshal(pstg, pstm);
+ do_unmarshal(&pstgM, &pstmM, &pstgM2, &pstmM2);
+ pstm->Unwrap();
+ pstg->Unwrap();
+
+ pstmM->Seek(0, WSTM_SEEK_SET, NULL);
+ pstmM->Read(buf, sizeof(STREAM_DATA), &cbRead);
+ if (strcmp(buf, STREAM_DATA))
+ error(EXIT_BADSC, "Stream data mismatch\n");
+ pstmM->Unwrap();
+ pstmM2->Release();
+
+ VerifyStructure(pstgM->GetI(), "dChild(dChild(sStream)),sStream");
+ pstgM->Unwrap();
+ pstgM2->Release();
+}
+
+void t_stgmisc(void)
+{
+ WStorage *pstg;
+ SCODE sc;
+ STATSTG stat;
+
+ // Can't make this call in transacted mode because we want
+ // the storage signature to make it into the file right away
+ WStgCreateDocfile(DRTDF, WSTG_READWRITE | WSTG_CREATE |
+ WSTG_SHARE_EXCLUSIVE, 0, &pstg);
+ if (!fOfs)
+ {
+ sc = DfGetScode(WStgIsStorageFile(DRTDF));
+ if (sc == S_FALSE)
+ error(EXIT_BADSC, "Open file - Should be a storage object\n");
+ pstg->Unwrap();
+ sc = DfGetScode(WStgIsStorageFile(DRTDF));
+ if (sc == S_FALSE)
+ error(EXIT_BADSC, "Closed file - Should be a storage object\n");
+ }
+ WStgCreateDocfile(NULL, ROOTP(WSTG_READWRITE) | WSTG_CREATE |
+ WSTG_DELETEONRELEASE, 0, &pstg);
+ pstg->Stat(&stat, 0);
+ if (!Exists(stat.pwcsName))
+ error(EXIT_BADSC, "Storage '%s' not created\n", stat.pwcsName);
+ pstg->Unwrap();
+ if (Exists(stat.pwcsName))
+ error(EXIT_BADSC, "Storage '%s' not deleted on release\n",
+ stat.pwcsName);
+ drtMemFree(stat.pwcsName);
+}
+
+void t_ilb(void)
+{
+ WStorage *pstg;
+ SCODE sc;
+ // create an ILockBytes
+
+ ILockBytes *pilb = new CMapBytes();
+ if (pilb == NULL)
+ error(EXIT_BADSC, "Unable to allocate an ILockBytes\n");
+
+ // create a storage on the ILockBytes
+
+ WStgCreateDocfileOnILockBytes(pilb,
+ WSTG_READWRITE |
+ WSTG_CREATE |
+ WSTG_SHARE_EXCLUSIVE,
+ 0, &pstg);
+
+ // verify the ILockBytes
+
+ sc = DfGetScode(WStgIsStorageILockBytes(pilb));
+ if (sc == S_FALSE)
+ error(EXIT_BADSC, "Open ILockBytes - Should be a storage object\n");
+
+ // release the storage
+
+ pstg->Unwrap();
+
+ // verify the ILockBytes
+
+ sc = DfGetScode(WStgIsStorageILockBytes(pilb));
+
+ if (sc == S_FALSE)
+ error(EXIT_BADSC, "Released ILockBytes - Should be a storage object\n");
+
+ // open the ILockBytes
+
+ WStgOpenStorageOnILockBytes(pilb, NULL, ROOTP(WSTG_READWRITE),
+ NULL, 0, &pstg);
+
+
+ // release the storage
+
+ pstg->Unwrap();
+
+ // release the ILockBytes
+
+ pilb->Release();
+}
+
+void t_movecopy(void)
+{
+ WStorage *pstgFrom, *pstgTo;
+ STATSTG statFrom, statTo;
+
+ // create a source
+ WStgCreateDocfile(NULL, ROOTP(WSTG_READWRITE) | WSTG_CREATE |
+ WSTG_DELETEONRELEASE, 0, &pstgFrom);
+ pstgFrom->Stat(&statFrom, 0);
+
+ // create a destination
+ WStgCreateDocfile(NULL, ROOTP(WSTG_READWRITE) | WSTG_CREATE |
+ WSTG_DELETEONRELEASE, 0, &pstgTo);
+ pstgTo->Stat(&statTo, 0);
+
+ // populate source
+ CreateStructure(pstgFrom->GetI(), "dA(dB(dC(sA,sB,sC),sCs),sBs),sAs");
+
+ // move a storage
+ pstgFrom->MoveElementTo(STR("A"), pstgTo, STR("M"), STGMOVE_MOVE);
+ VerifyStructure(pstgFrom->GetI(),
+ "sAs");
+ VerifyStructure(pstgTo->GetI(),
+ "dM(dB(dC(sA,sB,sC),sCs),sBs)");
+
+ // copy a stream
+ pstgFrom->MoveElementTo(STR("As"), pstgTo, STR("Bs"), STGMOVE_COPY);
+ VerifyStructure(pstgFrom->GetI(),
+ "sAs");
+ VerifyStructure(pstgTo->GetI(),
+ "dM(dB(dC(sA,sB,sC),sCs),sBs),sBs");
+
+ pstgFrom->Unwrap();
+ pstgTo->Unwrap();
+ if (Exists(statFrom.pwcsName))
+ error(EXIT_BADSC, "Storage '%s' not deleted\n", statFrom.pwcsName);
+ drtMemFree(statFrom.pwcsName);
+ if (Exists(statTo.pwcsName))
+ error(EXIT_BADSC, "Storage '%s' not deleted\n", statTo.pwcsName);
+ drtMemFree(statTo.pwcsName);
+}
diff --git a/private/oleutest/stgdrt/tests.hxx b/private/oleutest/stgdrt/tests.hxx
new file mode 100644
index 000000000..ad9176cda
--- /dev/null
+++ b/private/oleutest/stgdrt/tests.hxx
@@ -0,0 +1,31 @@
+//+--------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1992.
+//
+// File: tests.hxx
+//
+// Contents: DRT tests header
+//
+// History: 23-Sep-92 DrewB Created
+//
+//---------------------------------------------------------------
+
+#ifndef __TESTS_HXX__
+#define __TESTS_HXX__
+
+void t_create(void);
+void t_open(void);
+void t_addref(void);
+void t_tmodify(void);
+void t_dmodify(void);
+void t_stat(void);
+void t_stream(void);
+void t_enum(void);
+void t_stgcopyto(void);
+void t_marshal(void);
+void t_stgmisc(void);
+void t_ilb(void);
+void t_movecopy(void);
+
+#endif // #ifndef __TESTS_HXX__
diff --git a/private/oleutest/stgdrt/util.cxx b/private/oleutest/stgdrt/util.cxx
new file mode 100644
index 000000000..1d73a000b
--- /dev/null
+++ b/private/oleutest/stgdrt/util.cxx
@@ -0,0 +1,587 @@
+//+--------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1992.
+//
+// File: util.cxx
+//
+// Contents: DRT support routines
+//
+// History: 22-Sep-92 DrewB Created
+//
+//---------------------------------------------------------------
+
+#include "headers.cxx"
+#pragma hdrstop
+
+#include <stdarg.h>
+#include <direct.h>
+#include <io.h>
+
+#if DBG == 1
+#include <dfdeb.hxx>
+#endif
+
+#define DEFAULT_DATA_DIR "."
+
+BOOL fExitOnFail = TRUE;
+
+char szOrigDir[_MAX_PATH] = ".";
+
+// Preserve the current directory and change
+// directory into the data directory
+void SetData(void)
+{
+ char *pszDataDir;
+
+ _getcwd(szOrigDir, _MAX_PATH);
+ pszDataDir = getenv("DRTDATA");
+ if (pszDataDir == NULL)
+ pszDataDir = DEFAULT_DATA_DIR;
+ _chdir(pszDataDir);
+}
+
+// Clean up the data directory
+void CleanData(void)
+{
+ _unlink(OlecsOut(DRTDF));
+ _unlink(OlecsOut(MARSHALDF));
+}
+
+// Restore the original directory
+void UnsetData(void)
+{
+ _chdir(szOrigDir);
+}
+
+// Output a message if fVerbose is true
+void out(char *fmt, ...)
+{
+ va_list args;
+
+ if (fVerbose)
+ {
+ va_start(args, fmt);
+ vprintf(fmt, args);
+ va_end(args);
+ }
+}
+
+// internal error print
+void _errorprint (char *fmt, va_list args)
+{
+#if !defined(FLAT) || defined(FPRINTF_WORKS)
+ fprintf(stderr, "** Fatal error **: ");
+ vfprintf(stderr, fmt, args);
+#else
+ printf("** Fatal error **: ");
+ vprintf(fmt, args);
+#endif
+}
+
+// error print
+void errorprint (char *fmt, ...)
+{
+ va_list args;
+
+ va_start (args, fmt);
+
+ _errorprint (fmt, args);
+
+ va_end (args);
+}
+
+// Print out an error message and terminate the DRT
+void error(int code, char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+
+ _errorprint (fmt, args);
+
+ va_end(args);
+ CleanData();
+ UnsetData();
+ exit(code);
+}
+
+
+// Converts a TCHAR string to a char pointer in a temporary buffer
+// This implementation treats the conversion buffer as a circular
+// buffer so more than one string can be held (depending on the size
+// of the strings)
+
+#define BUFSIZE 1024
+
+char *OlecsOut(OLECHAR const *ptcs)
+{
+#ifdef OLEWIDECHAR
+ static char szBuffer[BUFSIZE];
+ static char *pszBuf = szBuffer;
+ char *pszTmp;
+
+ if (ptcs == NULL)
+ return NULL;
+ if (wcslen(ptcs) >= (size_t)(BUFSIZE-(pszBuf-szBuffer)))
+ pszBuf = szBuffer;
+ wcstombs(pszBuf, ptcs, BUFSIZE);
+ szBuffer[BUFSIZE-1] = 0;
+ pszTmp = pszBuf;
+ pszBuf += strlen(pszBuf)+1;
+ return pszTmp;
+#else
+ return (char *)ptcs;
+#endif
+}
+
+typedef struct
+{
+ SCODE sc;
+ char *text;
+} StatusCodeText;
+
+static StatusCodeText scodes[] =
+{
+ S_OK, "S_OK",
+ S_FALSE, "S_FALSE",
+ STG_E_INVALIDFUNCTION, "STG_E_INVALIDFUNCTION",
+ STG_E_FILENOTFOUND, "STG_E_FILENOTFOUND",
+ STG_E_PATHNOTFOUND, "STG_E_PATHNOTFOUND",
+ STG_E_TOOMANYOPENFILES, "STG_E_TOOMANYOPENFILES",
+ STG_E_ACCESSDENIED, "STG_E_ACCESSDENIED",
+ STG_E_INVALIDHANDLE, "STG_E_INVALIDHANDLE",
+ STG_E_INSUFFICIENTMEMORY, "STG_E_INSUFFICIENTMEMORY",
+ STG_E_INVALIDPOINTER, "STG_E_INVALIDPOINTER",
+ STG_E_NOMOREFILES, "STG_E_NOMOREFILES",
+ STG_E_DISKISWRITEPROTECTED, "STG_E_DISKISWRITEPROTECTED",
+ STG_E_SEEKERROR, "STG_E_SEEKERROR",
+ STG_E_WRITEFAULT, "STG_E_WRITEFAULT",
+ STG_E_READFAULT, "STG_E_READFAULT",
+ STG_E_SHAREVIOLATION, "STG_E_SHAREVIOLATION",
+ STG_E_LOCKVIOLATION, "STG_E_LOCKVIOLATION",
+ STG_E_FILEALREADYEXISTS, "STG_E_FILEALREADYEXISTS",
+ STG_E_INVALIDPARAMETER, "STG_E_INVALIDPARAMETER",
+ STG_E_MEDIUMFULL, "STG_E_MEDIUMFULL",
+ STG_E_ABNORMALAPIEXIT, "STG_E_ABNORMALAPIEXIT",
+ STG_E_INVALIDHEADER, "STG_E_INVALIDHEADER",
+ STG_E_INVALIDNAME, "STG_E_INVALIDNAME",
+ STG_E_UNKNOWN, "STG_E_UNKNOWN",
+ STG_E_UNIMPLEMENTEDFUNCTION, "STG_E_UNIMPLEMENTEDFUNCTION",
+ STG_E_INVALIDFLAG, "STG_E_INVALIDFLAG",
+ STG_E_INUSE, "STG_E_INUSE",
+ STG_E_NOTCURRENT, "STG_E_NOTCURRENT",
+ STG_E_REVERTED, "STG_E_REVERTED",
+ STG_E_CANTSAVE, "STG_E_CANTSAVE",
+ STG_E_OLDFORMAT, "STG_E_OLDFORMAT",
+ STG_E_OLDDLL, "STG_E_OLDDLL",
+ STG_E_SHAREREQUIRED, "STG_E_SHAREREQUIRED",
+ STG_E_NOTFILEBASEDSTORAGE, "STG_E_NOTFILEBASEDSTORAGE",
+ STG_E_EXTANTMARSHALLINGS, "STG_E_EXTANTMARSHALLINGS",
+ STG_S_CONVERTED, "STG_S_CONVERTED"
+};
+#define NSCODETEXT (sizeof(scodes)/sizeof(scodes[0]))
+
+// Convert a status code to text
+char *ScText(SCODE sc)
+{
+ int i;
+
+ for (i = 0; i<NSCODETEXT; i++)
+ if (scodes[i].sc == sc)
+ return scodes[i].text;
+ return "?";
+}
+
+// Output a call result and check for failure
+HRESULT Result(HRESULT hr)
+{
+ SCODE sc;
+
+ sc = DfGetScode(hr);
+ out(" - %s (0x%lX)\n", ScText(sc), sc);
+ if (FAILED(sc) && fExitOnFail)
+ error(EXIT_BADSC, "Unexpected call failure\n");
+ return hr;
+}
+
+// Perform Result() when the expectation is failure
+HRESULT IllResult(char *pszText, HRESULT hr)
+{
+ SCODE sc;
+
+ sc = DfGetScode(hr);
+ out("%s - %s (0x%lX)\n", pszText, ScText(sc), sc);
+ if (SUCCEEDED(sc) && fExitOnFail)
+ error(EXIT_BADSC, "Unexpected call success\n");
+ return hr;
+}
+
+// DEBUG - Check for memory leaks
+void CheckMemory(void)
+{
+#if DBG == 1
+ if (fVerbose || DfGetMemAlloced() != 0)
+ {
+ out("Memory held: %lu bytes\n", DfGetMemAlloced());
+ if (DfGetMemAlloced() != 0)
+ {
+ DfPrintAllocs();
+ error(EXIT_BADSC, "Memory leak\n");
+ }
+ }
+#endif
+}
+
+// DEBUG - Set the debugging level
+void SetDebug(ULONG ulDf, ULONG ulMsf)
+{
+#if DBG == 1
+ DfDebug(ulDf, ulMsf);
+#endif
+}
+
+// Check whether a given storage has a certain
+// structure or not
+// Structure is given as a string with elements:
+// <Type><Name><Options>[,...]
+// Type - d for docfile and s for stream
+// Name - Characters up to a '(' or ','
+// Options - For a docfile, you can specify a recursive check
+// in parentheses
+//
+// Example: dDocfile(sStream,dDocfile)
+char *VerifyStructure(IStorage *pstg, char *pszStructure)
+{
+ char szName[CWCSTORAGENAME], *psz;
+ IStorage *pstgChild;
+ char chType;
+ SCODE sc;
+ CStrList sl;
+ SStrEntry *pse;
+ IEnumSTATSTG *penm;
+ STATSTG stat;
+ OLECHAR atcName[CWCSTORAGENAME];
+
+ if (FAILED(sc = DfGetScode(pstg->EnumElements(0, NULL, 0, &penm))))
+ error(EXIT_BADSC, "VerifyStructure: Unable to create enumerator - "
+ "%s (0x%lX)\n", ScText(sc), sc);
+ for (;;)
+ {
+ sc = DfGetScode(penm->Next(1, &stat, NULL));
+ if (sc == S_FALSE)
+ break;
+ else if (FAILED(sc))
+ error(EXIT_BADSC, "VerifyStructure: Unable to enumerate - "
+ "%s (0x%lX)\n", ScText(sc), sc);
+ pse = sl.Add(stat.pwcsName);
+ if (pse == NULL)
+ error(EXIT_OOM, "VerifyStructure: Unable to allocate string\n");
+ pse->user.dw = stat.type;
+ drtMemFree(stat.pwcsName);
+ }
+ penm->Release();
+ while (*pszStructure && *pszStructure != ')')
+ {
+ chType = *pszStructure++;
+ psz = szName;
+ while (*pszStructure && *pszStructure != '(' &&
+ *pszStructure != ')' && *pszStructure != ',')
+ *psz++ = *pszStructure++;
+ *psz = 0;
+ ATOOLE(szName, atcName, CWCSTORAGENAME);
+ pse = sl.Find(atcName);
+ if (pse == NULL)
+ error(EXIT_BADSC, "VerifyStructure: '%s' not found\n", szName);
+ switch(chType)
+ {
+ case 'd':
+ if (pse->user.dw != STGTY_STORAGE)
+ error(EXIT_BADSC, "VerifyStructure: '%s' is not a storage\n",
+ szName);
+ sc = DfGetScode(pstg->OpenStorage(atcName, NULL,
+ STGP(STGM_READWRITE), NULL,
+ 0, &pstgChild));
+ if (FAILED(sc))
+ error(EXIT_BADSC, "VerifyStructure: can't open storage "
+ "'%s' - %s\n", szName, ScText(sc));
+ if (*pszStructure == '(')
+ pszStructure = VerifyStructure(pstgChild, pszStructure+1)+1;
+ pstgChild->Release();
+ break;
+ case 's':
+ if (pse->user.dw != STGTY_STREAM)
+ error(EXIT_BADSC, "VerifyStructure: '%s' is not a stream\n",
+ szName);
+ break;
+ }
+ sl.Remove(pse);
+ if (*pszStructure == ',')
+ pszStructure++;
+ }
+ for (pse = sl.GetHead(); pse; pse = pse->pseNext)
+ error(EXIT_BADSC, "VerifyStructure: additional member '%s'\n",
+ OlecsOut(pse->atc));
+ return pszStructure;
+}
+
+// Creates a structure using the same syntax
+// as VerifyStructure
+char *CreateStructure(IStorage *pstg, char *pszStructure)
+{
+ char szName[CWCSTORAGENAME], *psz;
+ IStorage *pstgChild;
+ IStream *pstmChild;
+ char chType;
+ SCODE sc;
+ OLECHAR atcName[CWCSTORAGENAME];
+
+ while (*pszStructure && *pszStructure != ')')
+ {
+ chType = *pszStructure++;
+ psz = szName;
+ while (*pszStructure && *pszStructure != '(' &&
+ *pszStructure != ')' && *pszStructure != ',')
+ *psz++ = *pszStructure++;
+ *psz = 0;
+ ATOOLE(szName, atcName, CWCSTORAGENAME);
+ switch(chType)
+ {
+ case 'd':
+ sc = DfGetScode(pstg->CreateStorage(atcName, STGP(STGM_READWRITE),
+ 0, 0, &pstgChild));
+ if (FAILED(sc))
+ error(EXIT_BADSC, "CreateStructure: can't create storage "
+ "'%s' - %s\n", szName, ScText(sc));
+ if (*pszStructure == '(')
+ pszStructure = CreateStructure(pstgChild, pszStructure+1)+1;
+ pstgChild->Release();
+ break;
+ case 's':
+ sc = DfGetScode(pstg->CreateStream(atcName, STMP(STGM_READWRITE),
+ 0, 0, &pstmChild));
+ if (FAILED(sc))
+ error(EXIT_BADSC, "CreateStructure: can't create stream "
+ "'%s' - %s\n", szName, ScText(sc));
+ pstmChild->Release();
+ break;
+ }
+ if (*pszStructure == ',')
+ pszStructure++;
+ }
+ pstg->Commit(0);
+ return pszStructure;
+}
+
+// Verifies the fields of a STATSTG
+void VerifyStat(STATSTG *pstat, OLECHAR *ptcsName, DWORD type, DWORD grfMode)
+{
+ if (ptcsName == NULL)
+ {
+ if (pstat->pwcsName != NULL)
+ error(EXIT_BADSC, "Stat name should be NULL - is %p\n",
+ pstat->pwcsName);
+ }
+ else if (olecscmp(pstat->pwcsName, ptcsName))
+ error(EXIT_BADSC, "Stat name mismatch - has '%s' vs. '%s'\n",
+ OlecsOut(pstat->pwcsName), OlecsOut(ptcsName));
+ if (pstat->type != type)
+ error(EXIT_BADSC, "Stat type mismatch - has %lu vs. %lu\n",
+ pstat->type, type);
+ if (pstat->grfMode != grfMode)
+ error(EXIT_BADSC, "Stat mode mismatch - has 0x%lX vs. 0x%lX\n",
+ pstat->grfMode, grfMode);
+}
+
+// Checks on a file's existence
+BOOL Exists(OLECHAR *file)
+{
+ OFSTRUCT of;
+
+#ifndef OLEWIDECHAR
+ return OpenFile(file, &of, OF_EXIST | OF_SHARE_DENY_NONE) !=
+ HFILE_ERROR ? TRUE : FALSE;
+#else
+ char szName[_MAX_PATH];
+ wcstombs(szName, file, _MAX_PATH);
+ return OpenFile(szName, &of, OF_EXIST | OF_SHARE_DENY_NONE) !=
+ HFILE_ERROR ? TRUE : FALSE;
+#endif
+}
+
+// Gets a file's length
+ULONG Length(OLECHAR *file)
+{
+ ULONG cb;
+
+#ifndef WIN32
+
+ OFSTRUCT of;
+ int hf;
+ hf = OpenFile(file, &of, OF_READ | OF_SHARE_DENY_NONE);
+ if (hf == HFILE_ERROR)
+ error(EXIT_BADSC, "Length: Unable to open '%s'\n", OlecsOut(file));
+ cb = (ULONG)_llseek(hf, 0, SEEK_END);
+ if (cb == (ULONG)HFILE_ERROR)
+ error(EXIT_BADSC, "Length: Unable to get length for '%s'\n",
+ OlecsOut(file));
+ _lclose(hf);
+
+#else
+
+ // use WIN32 APIs
+
+ HANDLE hf;
+
+#if !defined(UNICODE)
+
+ // Chicago - call ANSI CreateFile
+
+ char szName[_MAX_PATH];
+ if (wcstombs(szName, file, _MAX_PATH) == (size_t)-1)
+ return 0;
+
+ hf = CreateFile (
+ szName,
+ GENERIC_READ,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL
+ );
+
+#else
+
+ hf = CreateFile (
+ file,
+ GENERIC_READ,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL
+ );
+
+#endif // !defined(UNICODE)
+
+ if (hf == INVALID_HANDLE_VALUE)
+ error(EXIT_BADSC, "Length: Unable to open '%s'\n", OlecsOut(file));
+ cb = (ULONG)GetFileSize(hf, NULL);
+ if (cb == (ULONG)0xFFFFFFFF)
+ error(EXIT_BADSC, "Length: Unable to get length for '%s'\n",
+ OlecsOut(file));
+ CloseHandle(hf);
+
+#endif // !WIN32
+
+ return cb;
+}
+
+// Original mode when a new mode is forced
+// Used by ForceDirect, ForceTransacted and Unforce
+static DWORD dwTransOld;
+static DWORD dwRDWOld;
+
+// Forces direct mode to be active
+// Note: this uses a static variable so it can\'t be nested
+void ForceDirect(void)
+{
+ dwTransOld = dwTransacted;
+ dwTransacted = STGM_DIRECT;
+ dwRDWOld = dwRootDenyWrite;
+ dwRootDenyWrite = STGM_SHARE_EXCLUSIVE;
+}
+
+// Forces transacted mode similarly to ForceDirect
+void ForceTransacted(void)
+{
+ dwTransOld = dwTransacted;
+ dwRDWOld = dwRootDenyWrite;
+ dwTransacted = STGM_TRANSACTED;
+}
+
+// Returns to the original mode after a ForceDirect or ForceTransacted
+void Unforce(void)
+{
+ dwTransacted = dwTransOld;
+ dwRootDenyWrite = dwRDWOld;
+}
+
+// Equality for FILETIME
+BOOL IsEqualTime(FILETIME ttTime, FILETIME ttCheck)
+{
+ // File times can be off by as much as 2 seconds due to FAT rounding
+ LONGLONG tmTime = *(LONGLONG *)&ttTime;
+ LONGLONG tmCheck = *(LONGLONG *)&ttCheck;
+ LONGLONG tmDelta = tmTime - tmCheck;
+
+ return tmDelta < 20000000i64 && tmDelta > -2i64 ;
+}
+
+// Get a fully qualified path for a file name
+void GetFullPath(OLECHAR *file, OLECHAR *path)
+{
+#ifndef UNICODE
+ char buf[_MAX_PATH];
+ OFSTRUCT of;
+
+ OLETOA(file, buf, _MAX_PATH);
+ OpenFile(buf, &of, OF_PARSE);
+ ATOOLE((char *)of.szPathName, path, _MAX_PATH);
+#else
+ OLECHAR *ptcsFile;
+
+ GetFullPathName(file, _MAX_PATH, path, &ptcsFile);
+#endif
+}
+
+// Memory helper functions
+
+HRESULT drtMemAlloc(ULONG ulcb, void **ppv)
+{
+ HRESULT hr;
+ IMalloc *pMalloc = NULL;
+
+ if (SUCCEEDED(DfGetScode(hr = CoGetMalloc(MEMCTX_TASK, &pMalloc))))
+ {
+ *ppv = pMalloc->Alloc(ulcb);
+ pMalloc->Release();
+
+ if (*ppv == NULL)
+ return ResultFromScode(E_OUTOFMEMORY);
+ }
+
+ return hr;
+}
+
+void drtMemFree(void *pv)
+{
+ IMalloc FAR* pMalloc;
+ if (SUCCEEDED(GetScode(CoGetMalloc(MEMCTX_TASK, &pMalloc))))
+ {
+ pMalloc->Free(pv);
+ pMalloc->Release();
+ }
+}
+
+#pragma pack(1)
+struct SplitGuid
+{
+ DWORD dw1;
+ WORD w1;
+ WORD w2;
+ BYTE b[8];
+};
+#pragma pack()
+
+char *GuidText(GUID const *pguid)
+{
+ static char buf[39];
+ SplitGuid *psg = (SplitGuid *)pguid;
+
+ sprintf(buf, "{%08lX-%04hX-%04hX-%02X%02X-%02X%02X%02X%02X%02X%02X}",
+ psg->dw1, psg->w1, psg->w2, psg->b[0], psg->b[1], psg->b[2],
+ psg->b[3], psg->b[4], psg->b[5], psg->b[6], psg->b[7]);
+ return buf;
+}
diff --git a/private/oleutest/stgdrt/util.hxx b/private/oleutest/stgdrt/util.hxx
new file mode 100644
index 000000000..028eae57d
--- /dev/null
+++ b/private/oleutest/stgdrt/util.hxx
@@ -0,0 +1,45 @@
+//+--------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1992.
+//
+// File: util.hxx
+//
+// Contents: DRT support functions
+//
+// History: 22-Sep-92 DrewB Created
+//
+//---------------------------------------------------------------
+
+#ifndef __UTIL_HXX__
+#define __UTIL_HXX__
+
+extern BOOL fExitOnFail;
+
+void SetData(void);
+void CleanData(void);
+void UnsetData(void);
+void out(char *fmt, ...);
+void error(int code, char *fmt, ...);
+void errorprint(char *fmt, ...);
+char *OlecsOut(OLECHAR const *ptcs);
+char *ScText(SCODE sc);
+HRESULT Result(HRESULT hr);
+HRESULT IllResult(char *pszText, HRESULT hr);
+void CheckMemory(void);
+void SetDebug(ULONG ulDf, ULONG ulMsf);
+char *VerifyStructure(IStorage *pstg, char *pszStructure);
+char *CreateStructure(IStorage *pstg, char *pszStructure);
+void VerifyStat(STATSTG *pstat, OLECHAR *ptcsName, DWORD type, DWORD grfMode);
+BOOL Exists(OLECHAR *file);
+ULONG Length(OLECHAR *file);
+void ForceDirect(void);
+void ForceTransacted(void);
+void Unforce(void);
+BOOL IsEqualTime(FILETIME ttTime, FILETIME ttCheck);
+void GetFullPath(OLECHAR *file, OLECHAR *path);
+HRESULT drtMemAlloc(ULONG ulcb, void **ppv);
+void drtMemFree(void *pv);
+char *GuidText(GUID const *pguid);
+
+#endif // #ifndef __UTIL_HXX__
diff --git a/private/oleutest/stgdrt/wrap.cxx b/private/oleutest/stgdrt/wrap.cxx
new file mode 100644
index 000000000..9267c997d
--- /dev/null
+++ b/private/oleutest/stgdrt/wrap.cxx
@@ -0,0 +1,707 @@
+//+--------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1992.
+//
+// File: wrap.cxx
+//
+// Contents: Wrapper implementations
+//
+// History: 22-Sep-92 DrewB Created
+//
+//---------------------------------------------------------------
+
+#include "headers.cxx"
+#pragma hdrstop
+
+#include <dfentry.hxx>
+
+// Retrieve interface pointer for possibly NULL objects
+#define SAFEI(obj) ((obj) ? (obj)->GetI() : NULL)
+
+//+--------------------------------------------------------------
+//
+// IStorage wrappers
+//
+// History: 23-Sep-92 DrewB Created
+//
+//---------------------------------------------------------------
+
+WStorage *WStorage::Wrap(IStorage *pistg)
+{
+ WStorage *wstg;
+
+ wstg = new WStorage(pistg);
+ if (wstg == NULL)
+ error(EXIT_OOM, "Unable to wrap IStorage\n");
+ return wstg;
+}
+
+WStorage::WStorage(IStorage *pstg)
+{
+ // Note: takes ownership of pstg
+ _pstg = pstg;
+}
+
+WStorage::~WStorage(void)
+{
+ if (_pstg)
+ Release();
+}
+
+void WStorage::Unwrap(void)
+{
+ delete this;
+}
+
+HRESULT WStorage::QueryInterface(REFIID riid, void **ppvObj)
+{
+ out("IStorage %p::QueryInterface(riid, %p)", _pstg, ppvObj);
+ return Result(_pstg->QueryInterface(riid, ppvObj));
+}
+
+ULONG WStorage::AddRef(void)
+{
+ ULONG ul;
+
+ ul = _pstg->AddRef();
+ out("IStorage %p::AddRef() - %lu\n", _pstg, ul);
+ return ul;
+}
+
+ULONG WStorage::Release(void)
+{
+ ULONG ul;
+
+ ul = _pstg->Release();
+ out("IStorage %p::Release() - %lu\n", _pstg, ul);
+ if (ul == 0)
+ _pstg = NULL;
+ return ul;
+}
+
+HRESULT WStorage::CreateStream(const OLECHAR * pwcsName,
+ const DWORD grfMode,
+ DWORD reserved1,
+ DWORD reserved2,
+ WStream **ppstm)
+{
+ HRESULT hr;
+ IStream *pistm;
+
+ out("IStorage %p::CreateStream(%s, 0x%lX, %lu, %lu, %p)", _pstg,
+ OlecsOut(pwcsName), grfMode, reserved1, reserved2, ppstm);
+ hr = Result(_pstg->CreateStream(pwcsName, grfMode, reserved1,
+ reserved2, &pistm));
+ *ppstm = WStream::Wrap(pistm);
+ return hr;
+}
+
+HRESULT WStorage::OpenStream(const OLECHAR * pwcsName,
+ void *reserved1,
+ const DWORD grfMode,
+ DWORD reserved2,
+ WStream **ppstm)
+{
+ HRESULT hr;
+ IStream *pistm;
+
+ out("IStorage %p::OpenStream(%s, %p, 0x%lX, %lu, %p)", _pstg,
+ OlecsOut(pwcsName), reserved1, grfMode, reserved2, ppstm);
+ hr = Result(_pstg->OpenStream(pwcsName, reserved1, grfMode,
+ reserved2, &pistm));
+ *ppstm = WStream::Wrap(pistm);
+ return hr;
+}
+
+HRESULT WStorage::CreateStorage(const OLECHAR * pwcsName,
+ const DWORD grfMode,
+ DWORD reserved1,
+ DWORD reserved2,
+ WStorage **ppstg)
+{
+ HRESULT hr;
+ IStorage *pistg;
+
+ out("IStorage %p::CreateStorage(%s, 0x%lX, %lu, %lu, %p)", _pstg,
+ OlecsOut(pwcsName), grfMode, reserved1, reserved2, ppstg);
+ hr = Result(_pstg->CreateStorage(pwcsName, grfMode, reserved1,
+ reserved2, &pistg));
+ *ppstg = WStorage::Wrap(pistg);
+ return hr;
+}
+
+HRESULT WStorage::OpenStorage(const OLECHAR * pwcsName,
+ WStorage *pstgPriority,
+ const DWORD grfMode,
+ SNB snbExclude,
+ DWORD reserved,
+ WStorage **ppstg)
+{
+ HRESULT hr;
+ IStorage *pistg;
+
+ out("IStorage %p::OpenStorage(%s, %p, 0x%lX, %p, %lu, %p)", _pstg,
+ OlecsOut(pwcsName), SAFEI(pstgPriority), grfMode,
+ snbExclude, reserved, ppstg);
+ hr = Result(_pstg->OpenStorage(pwcsName, SAFEI(pstgPriority),
+ grfMode, snbExclude,
+ reserved, &pistg));
+ *ppstg = WStorage::Wrap(pistg);
+ return hr;
+}
+
+HRESULT WStorage::CopyTo(DWORD ciidExclude,
+ IID *rgiidExclude,
+ SNB snbExclude,
+ WStorage *pstgDest)
+{
+ out("IStorage %p::CopyTo(%lu, %p, %p, %p)", _pstg, ciidExclude,
+ rgiidExclude, snbExclude, pstgDest->GetI());
+ return Result(_pstg->CopyTo(ciidExclude, rgiidExclude, snbExclude,
+ pstgDest->GetI()));
+}
+
+HRESULT WStorage::MoveElementTo(OLECHAR const FAR* lpszName,
+ WStorage FAR *pstgDest,
+ OLECHAR const FAR* lpszNewName,
+ DWORD grfFlags)
+{
+ out("IStorage %p::MoveElementTo(%p, %p, %p, %lu)", _pstg, lpszName,
+ pstgDest->GetI(), lpszNewName, grfFlags);
+ return Result(_pstg->MoveElementTo(lpszName, pstgDest->GetI(),
+ lpszNewName, grfFlags));
+}
+
+HRESULT WStorage::Commit(const DWORD grfCommitFlags)
+{
+ out("IStorage %p::Commit(0x%lX)", _pstg, grfCommitFlags);
+ return Result(_pstg->Commit(grfCommitFlags));
+}
+
+HRESULT WStorage::Revert(void)
+{
+ out("IStorage %p::Revert()", _pstg);
+ return Result(_pstg->Revert());
+}
+
+HRESULT WStorage::EnumElements(DWORD reserved1,
+ void *reserved2,
+ DWORD reserved3,
+ WEnumSTATSTG **ppenm)
+{
+ HRESULT hr;
+ IEnumSTATSTG *pienm;
+
+ out("IStorage %p::EnumElements(%lu, %p, %lu, %p)", _pstg,
+ reserved1, reserved2, reserved3, ppenm);
+ hr = Result(_pstg->EnumElements(reserved1, reserved2, reserved3, &pienm));
+ *ppenm = WEnumSTATSTG::Wrap(pienm);
+ return hr;
+}
+
+HRESULT WStorage::DestroyElement(const OLECHAR * pwcsName)
+{
+ out("IStorage %p::DestroyElement(%s)", _pstg, OlecsOut(pwcsName));
+ return Result(_pstg->DestroyElement(pwcsName));
+}
+
+HRESULT WStorage::RenameElement(const OLECHAR * pwcsOldName,
+ const OLECHAR * pwcsNewName)
+{
+ out("IStorage %p::RenameElement(%s, %s)", _pstg, OlecsOut(pwcsOldName),
+ OlecsOut(pwcsNewName));
+ return Result(_pstg->RenameElement(pwcsOldName, pwcsNewName));
+}
+
+HRESULT WStorage::SetElementTimes(const OLECHAR *lpszName,
+ FILETIME const *pctime,
+ FILETIME const *patime,
+ FILETIME const *pmtime)
+{
+ out("IStorage %p::SetElementTimes(%s, %p, %p, %p)", _pstg,
+ OlecsOut(lpszName), pctime, patime, pmtime);
+ return Result(_pstg->SetElementTimes(lpszName, pctime, patime, pmtime));
+}
+
+HRESULT WStorage::SetClass(REFCLSID clsid)
+{
+ out("IStorage %p::SetClass(%s)", _pstg, GuidText(&clsid));
+ return Result(_pstg->SetClass(clsid));
+}
+
+HRESULT WStorage::SetStateBits(DWORD grfStateBits, DWORD grfMask)
+{
+ out("IStorage %p::SetStateBits(0x%lX, 0x%lX)", _pstg, grfStateBits,
+ grfMask);
+ return Result(_pstg->SetStateBits(grfStateBits, grfMask));
+}
+
+HRESULT WStorage::Stat(STATSTG *pstatstg, DWORD grfStatFlag)
+{
+ out("IStorage %p::Stat(%p, %lu)", _pstg, pstatstg, grfStatFlag);
+ return Result(_pstg->Stat(pstatstg, grfStatFlag));
+}
+
+//+--------------------------------------------------------------
+//
+// IStream wrappers
+//
+// History: 23-Sep-92 DrewB Created
+//
+//---------------------------------------------------------------
+
+WStream *WStream::Wrap(IStream *pistm)
+{
+ WStream *wstm;
+
+ wstm = new WStream(pistm);
+ if (wstm == NULL)
+ error(EXIT_OOM, "Unable to wrap IStream\n");
+ return wstm;
+}
+
+WStream::WStream(IStream *pstm)
+{
+ // Note: takes ownership of pstm
+ _pstm = pstm;
+}
+
+WStream::~WStream(void)
+{
+ if (_pstm)
+ Release();
+}
+
+void WStream::Unwrap(void)
+{
+ delete this;
+}
+
+HRESULT WStream::QueryInterface(REFIID riid, void **ppvObj)
+{
+ out("IStream %p::QueryInterface(riid, %p)", _pstm, ppvObj);
+ return Result(_pstm->QueryInterface(riid, ppvObj));
+}
+
+ULONG WStream::AddRef(void)
+{
+ ULONG ul;
+
+ ul = _pstm->AddRef();
+ out("IStream %p::AddRef() - %lu\n", _pstm, ul);
+ return ul;
+}
+
+ULONG WStream::Release(void)
+{
+ ULONG ul;
+
+ ul = _pstm->Release();
+ out("IStream %p::Release() - %lu\n", _pstm, ul);
+ if (ul == 0)
+ _pstm = NULL;
+ return ul;
+}
+
+HRESULT WStream::Read(VOID *pv, ULONG cb, ULONG *pcbRead)
+{
+ HRESULT hr;
+
+ out("IStream %p::Read(%p, %lu, %p)", _pstm, pv, cb, pcbRead);
+ hr = _pstm->Read(pv, cb, pcbRead);
+ if (pcbRead)
+ out(" - %lu bytes", *pcbRead);
+ Result(hr);
+ if (pcbRead && *pcbRead != cb && fExitOnFail)
+ error(EXIT_BADSC, "Couldn't read data\n");
+ return hr;
+}
+
+HRESULT WStream::Write(VOID *pv, ULONG cb, ULONG *pcbWritten)
+{
+ HRESULT hr;
+
+ out("IStream %p::Write(%p, %lu, %p)", _pstm, pv, cb, pcbWritten);
+ hr = _pstm->Write(pv, cb, pcbWritten);
+ if (pcbWritten)
+ out(" - %lu bytes", *pcbWritten);
+ Result(hr);
+ if (pcbWritten && *pcbWritten != cb && fExitOnFail)
+ error(EXIT_BADSC, "Couldn't write data\n");
+ return hr;
+}
+
+HRESULT WStream::Seek(LONG dlibMove,
+ DWORD dwOrigin,
+ ULONG *plibNewPosition)
+{
+ HRESULT hr;
+ LARGE_INTEGER dlib;
+ ULARGE_INTEGER plib;
+
+ out("IStream %p::Seek(%ld, %lu, %p)", _pstm, dlibMove, dwOrigin,
+ plibNewPosition);
+ LISet32(dlib, dlibMove);
+ hr = _pstm->Seek(dlib, dwOrigin, &plib);
+ if (plibNewPosition)
+ {
+ *plibNewPosition = ULIGetLow(plib);
+ out(" - ptr %lu", *plibNewPosition);
+ }
+ return Result(hr);
+}
+
+HRESULT WStream::SetSize(ULONG libNewSize)
+{
+ ULARGE_INTEGER lib;
+
+ out("IStream %p::SetSize(%lu)", _pstm, libNewSize);
+ ULISet32(lib, libNewSize);
+ return Result(_pstm->SetSize(lib));
+}
+
+HRESULT WStream::Commit(const DWORD dwFlags)
+{
+ out("IStream %p:Commit(%lu)", _pstm, dwFlags);
+ return Result(_pstm->Commit(dwFlags));
+}
+
+HRESULT WStream::CopyTo(WStream *pstm,
+ ULONG cb,
+ ULONG *pcbRead,
+ ULONG *pcbWritten)
+{
+ ULARGE_INTEGER lcb, pcbr, pcbw;
+ HRESULT hr;
+
+ out("IStream %p::CopyTo(%p, %lu, %p, %p)", _pstm, pstm->GetI(), cb,
+ pcbRead, pcbWritten);
+ ULISet32(lcb, cb);
+ hr = Result(_pstm->CopyTo(pstm->GetI(), lcb, &pcbr, &pcbw));
+ if (pcbRead)
+ *pcbRead = ULIGetLow(pcbr);
+ if (pcbWritten)
+ *pcbWritten = ULIGetLow(pcbw);
+ return hr;
+}
+
+HRESULT WStream::Stat(STATSTG *pstatstg, DWORD grfStatFlag)
+{
+ out("IStream %p::Stat(%p, %lu)", _pstm, pstatstg, grfStatFlag);
+ return Result(_pstm->Stat(pstatstg, grfStatFlag));
+}
+
+HRESULT WStream::Clone(WStream * *ppstm)
+{
+ HRESULT hr;
+ IStream *pistm;
+
+ out("IStream %p::Clone(%p)", _pstm, ppstm);
+ hr = Result(_pstm->Clone(&pistm));
+ *ppstm = WStream::Wrap(pistm);
+ return hr;
+}
+
+//+--------------------------------------------------------------
+//
+// IEnumSTATSTG wrappers
+//
+// History: 24-Sep-92 DrewB Created
+//
+//---------------------------------------------------------------
+
+WEnumSTATSTG *WEnumSTATSTG::Wrap(IEnumSTATSTG *pienm)
+{
+ WEnumSTATSTG *wenm;
+
+ wenm = new WEnumSTATSTG(pienm);
+ if (wenm == NULL)
+ error(EXIT_OOM, "Unable to wrap IEnumSTATSTG\n");
+ return wenm;
+}
+
+WEnumSTATSTG::WEnumSTATSTG(IEnumSTATSTG *penm)
+{
+ // Note: takes ownership of penm
+ _penm = penm;
+}
+
+WEnumSTATSTG::~WEnumSTATSTG(void)
+{
+ if (_penm)
+ Release();
+}
+
+void WEnumSTATSTG::Unwrap(void)
+{
+ delete this;
+}
+
+HRESULT WEnumSTATSTG::QueryInterface(REFIID riid, void **ppvObj)
+{
+ out("IEnumSTATSTG %p::QueryInterface(riid, %p)", _penm, ppvObj);
+ return Result(_penm->QueryInterface(riid, ppvObj));
+}
+
+ULONG WEnumSTATSTG::AddRef(void)
+{
+ ULONG ul;
+
+ ul = _penm->AddRef();
+ out("IEnumSTATSTG %p::AddRef() - %lu\n", _penm, ul);
+ return ul;
+}
+
+ULONG WEnumSTATSTG::Release(void)
+{
+ ULONG ul;
+
+ ul = _penm->Release();
+ out("IEnumSTATSTG %p::Release() - %lu\n", _penm, ul);
+ if (ul == 0)
+ _penm = NULL;
+ return ul;
+}
+
+HRESULT WEnumSTATSTG::Next(ULONG celt, STATSTG rgelt[], ULONG *pceltFetched)
+{
+ out("IEnumSTATSTG %p::Next(%lu, rgelt, %p)", _penm, celt, pceltFetched);
+ return Result(_penm->Next(celt, rgelt, pceltFetched));
+}
+
+HRESULT WEnumSTATSTG::Skip(ULONG celt)
+{
+ out("IEnumSTATSTG %p::Skip(%lu)", _penm, celt);
+ return Result(_penm->Skip(celt));
+}
+
+HRESULT WEnumSTATSTG::Reset(void)
+{
+ out("IEnumSTATSTG %p::Reset()", _penm);
+ return Result(_penm->Reset());
+}
+
+HRESULT WEnumSTATSTG::Clone(WEnumSTATSTG **ppenm)
+{
+ HRESULT hr;
+ IEnumSTATSTG *pienm;
+
+ out("IEnumSTATSTG %p::Clone(%p)", _penm, ppenm);
+ hr = Result(_penm->Clone(&pienm));
+ *ppenm = WEnumSTATSTG::Wrap(pienm);
+ return hr;
+}
+
+//+--------------------------------------------------------------
+//
+// IMarshal wrappers
+//
+// History: 23-Sep-92 DrewB Created
+//
+//---------------------------------------------------------------
+
+WMarshal *WMarshal::Wrap(IMarshal *pimsh)
+{
+ WMarshal *wmsh;
+
+ wmsh = new WMarshal(pimsh);
+ if (wmsh == NULL)
+ error(EXIT_OOM, "Unable to wrap IMarshal\n");
+ return wmsh;
+}
+
+WMarshal::WMarshal(IMarshal *pmsh)
+{
+ // Note: takes ownership of pmsh
+ _pmsh = pmsh;
+}
+
+WMarshal::~WMarshal(void)
+{
+ if (_pmsh)
+ Release();
+}
+
+void WMarshal::Unwrap(void)
+{
+ delete this;
+}
+
+HRESULT WMarshal::QueryInterface(REFIID riid, void **ppvObj)
+{
+ out("IMarshal %p::QueryInterface(riid, %p)", _pmsh, ppvObj);
+ return Result(_pmsh->QueryInterface(riid, ppvObj));
+}
+
+ULONG WMarshal::AddRef(void)
+{
+ ULONG ul;
+
+ ul = _pmsh->AddRef();
+ out("IMarshal %p::AddRef() - %lu\n", _pmsh, ul);
+ return ul;
+}
+
+ULONG WMarshal::Release(void)
+{
+ ULONG ul;
+
+ ul = _pmsh->Release();
+ out("IMarshal %p::Release() - %lu\n", _pmsh, ul);
+ if (ul == 0)
+ _pmsh = NULL;
+ return ul;
+}
+
+HRESULT WMarshal::MarshalInterface(WStream * pStm,
+ REFIID riid,
+ LPVOID pv,
+ DWORD dwDestContext,
+ LPVOID pvDestContext,
+ DWORD mshlflags)
+{
+ out("IMarshal %p::MarshalInterface(%p, riid, %p, %lu, %lu, %lu)",
+ _pmsh, pStm->GetI(), pv, dwDestContext, pvDestContext, mshlflags);
+ return Result(_pmsh->MarshalInterface(pStm->GetI(), riid, pv,
+#ifdef OLDMARSHAL
+ dwDestContext
+#ifdef NEWMARSHAL
+ , mshlflags
+#endif
+ ));
+#else
+ dwDestContext,
+ pvDestContext,
+ mshlflags));
+#endif
+}
+
+//+--------------------------------------------------------------
+//
+// Root level wrappers
+//
+// History: 23-Sep-92 DrewB Created
+//
+//---------------------------------------------------------------
+
+HRESULT WStgCreateDocfile(const OLECHAR * pwcsName,
+ const DWORD grfMode,
+ DWORD reserved,
+ WStorage * *ppstgOpen)
+{
+ HRESULT hr;
+ IStorage *pistg;
+
+#ifndef _CAIRO_
+ out("StgCreateDocfile(%s, 0x%lX, %lu, %p)", OlecsOut(pwcsName), grfMode,
+ reserved, ppstgOpen);
+
+ hr = Result(StgCreateDocfile(pwcsName, grfMode,
+ reserved, &pistg));
+#else ELSE == 300
+ out("StgCreateStorage(%s, 0x%lX, %lu, %p)", OlecsOut(pwcsName), grfMode,
+ reserved, ppstgOpen);
+
+ hr = Result(StgCreateStorage(pwcsName, grfMode,
+ STGFMT_DOCUMENT,
+ (LPSECURITY_ATTRIBUTES)reserved, &pistg));
+#endif
+
+ *ppstgOpen = WStorage::Wrap(pistg);
+ return hr;
+}
+
+HRESULT WStgCreateDocfileOnILockBytes(ILockBytes *plkbyt,
+ const DWORD grfMode,
+ DWORD reserved,
+ WStorage * *ppstgOpen)
+{
+ HRESULT hr;
+ IStorage *pistg;
+
+ out("StgCreateDocfileOnILockBytes(%p, 0x%lX, %lu, %p)",
+ plkbyt, grfMode, reserved, ppstgOpen);
+ hr = Result(StgCreateDocfileOnILockBytes(plkbyt, grfMode,
+ reserved, &pistg));
+ *ppstgOpen = WStorage::Wrap(pistg);
+ return hr;
+}
+
+HRESULT WStgOpenStorage(const OLECHAR * pwcsName,
+ WStorage *pstgPriority,
+ const DWORD grfMode,
+ SNB snbExclude,
+ DWORD reserved,
+ WStorage * *ppstgOpen)
+{
+ HRESULT hr;
+ IStorage *pistg;
+
+ out("StgOpenStorage(%s, %p, 0x%lX, %p, %lu, %p)", OlecsOut(pwcsName),
+ SAFEI(pstgPriority), grfMode, snbExclude, reserved, ppstgOpen);
+ hr = Result(StgOpenStorage(pwcsName, SAFEI(pstgPriority), grfMode,
+ snbExclude,
+ reserved, &pistg));
+
+ *ppstgOpen = WStorage::Wrap(pistg);
+ return hr;
+}
+
+HRESULT WStgOpenStorageOnILockBytes(ILockBytes *plkbyt,
+ WStorage *pstgPriority,
+ const DWORD grfMode,
+ SNB snbExclude,
+ DWORD reserved,
+ WStorage * *ppstgOpen)
+{
+ HRESULT hr;
+ IStorage *pistg;
+
+ out("StgOpenStorageOnILockBytes(%p, %p, 0x%lX, %p, %lu, %p)",
+ plkbyt, SAFEI(pstgPriority), grfMode, snbExclude, reserved,
+ ppstgOpen);
+ hr = Result(StgOpenStorageOnILockBytes(plkbyt, SAFEI(pstgPriority),
+ grfMode, snbExclude, reserved,
+ &pistg));
+ *ppstgOpen = WStorage::Wrap(pistg);
+ return hr;
+}
+
+HRESULT WStgIsStorageFile(const OLECHAR * pwcsName)
+{
+ out("StgIsStorageFile(%s)", OlecsOut(pwcsName));
+ return Result(StgIsStorageFile(pwcsName));
+}
+
+HRESULT WStgIsStorageILockBytes(ILockBytes * plkbyt)
+{
+ out("StgIsStorageILockBytes(%p)", plkbyt);
+ return Result(StgIsStorageILockBytes(plkbyt));
+}
+
+HRESULT WCoMarshalInterface(WStream *pStm,
+ REFIID iid,
+ IUnknown *pUnk,
+ DWORD dwDestContext,
+ LPVOID pvDestContext,
+ DWORD mshlflags)
+{
+ out("CoMarshalInterface(%p, iid, %p, %lu, %p, %lX)", pStm->GetI(),
+ pUnk, dwDestContext, pvDestContext, mshlflags);
+#ifdef OLDMARSHAL
+ return Result(CoMarshalInterface(pStm->GetI(), iid, pUnk, dwDestContext,
+ mshlflags));
+#else
+ return Result(CoMarshalInterface(pStm->GetI(), iid, pUnk, dwDestContext,
+ pvDestContext, mshlflags));
+#endif
+}
+
+HRESULT WCoUnmarshalInterface(WStream *pStm,
+ REFIID riid,
+ LPVOID *ppv)
+{
+ out("CoUnmarshalInterface(%p, iid, %p)", pStm->GetI(), ppv);
+ return Result(CoUnmarshalInterface(pStm->GetI(), riid, ppv));
+}
diff --git a/private/oleutest/stgdrt/wrap.hxx b/private/oleutest/stgdrt/wrap.hxx
new file mode 100644
index 000000000..487fa44b8
--- /dev/null
+++ b/private/oleutest/stgdrt/wrap.hxx
@@ -0,0 +1,377 @@
+//+--------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1992.
+//
+// File: wrap.hxx
+//
+// Contents: Interface wrappers for test
+//
+// Classes: WStorage, WStream, WLockBytes, WEnmSTATSTG
+//
+// History: 22-Sep-92 DrewB Created
+//
+// Notes: These wrappers function in legitimate cases only,
+// they are not intended for testing illegitimate
+// calls.
+// QueryInterface does not return wrapped objects.
+//
+//---------------------------------------------------------------
+
+#ifndef __WRAP_HXX__
+#define __WRAP_HXX__
+
+/* Storage instantiation modes */
+#define WSTG_DIRECT 0x00000000L
+#define WSTG_TRANSACTED 0x00010000L
+
+#define WSTG_READ 0x00000000L
+#define WSTG_WRITE 0x00000001L
+#define WSTG_READWRITE 0x00000002L
+
+#define WSTG_SHARE_DENY_NONE 0x00000040L
+#define WSTG_SHARE_DENY_READ 0x00000030L
+#define WSTG_SHARE_DENY_WRITE 0x00000020L
+#define WSTG_SHARE_EXCLUSIVE 0x00000010L
+
+#define WSTG_PRIORITY 0x00040000L
+#define WSTG_DELETEONRELEASE 0x04000000L
+
+#define WSTG_CREATE 0x00001000L
+#define WSTG_CONVERT 0x00020000L
+#define WSTG_FAILIFTHERE 0x00000000L
+
+/* Storage commit types */
+typedef enum
+{
+ WSTGC_OVERWRITE = 1,
+ WSTGC_ONLYIFCURRENT = 2
+} WSTGC;
+
+typedef enum
+{
+ WSTM_SEEK_SET = 0,
+ WSTM_SEEK_CUR = 1,
+ WSTM_SEEK_END = 2
+} WSTMS;
+
+typedef enum
+{
+ WLOCK_WRITE = 1,
+ WLOCK_EXCLUSIVE = 2,
+ WLOCK_ONLYONCE = 3
+} WLOCKTYPE;
+
+//+--------------------------------------------------------------
+//
+// Class: WUnknown
+//
+// Purpose: Replacement for IUnknown
+//
+// History: 22-Sep-92 DrewB Created
+//
+//---------------------------------------------------------------
+
+interface WUnknown
+{
+public:
+ virtual HRESULT QueryInterface(REFIID riid, LPVOID * ppvObj) = 0;
+ virtual ULONG AddRef(void) = 0;
+ virtual ULONG Release(void) = 0;
+};
+
+//+--------------------------------------------------------------
+//
+// Class: WEnumSTATSTG
+//
+// Purpose: Wrapper for IEnumSTATSTG
+//
+// History: 22-Sep-92 DrewB Created
+//
+//---------------------------------------------------------------
+
+interface WEnumSTATSTG : public WUnknown
+{
+public:
+ WEnumSTATSTG(IEnumSTATSTG *penm);
+ ~WEnumSTATSTG(void);
+
+ IEnumSTATSTG *GetI(void) { return _penm; }
+ static WEnumSTATSTG *Wrap(IEnumSTATSTG *penm);
+ void Unwrap(void);
+
+ virtual HRESULT QueryInterface(REFIID riid, LPVOID * ppvObj);
+ virtual ULONG AddRef(void);
+ virtual ULONG Release(void);
+
+ HRESULT Next(ULONG celt, STATSTG rgelt[], ULONG *pceltFetched);
+ HRESULT Skip(ULONG celt);
+ HRESULT Reset(void);
+ HRESULT Clone(WEnumSTATSTG **ppenm);
+
+private:
+ IEnumSTATSTG *_penm;
+};
+
+//+--------------------------------------------------------------
+//
+// Class: WLockBytes
+//
+// Purpose: Wrapper for ILockBytes
+//
+// History: 22-Sep-92 DrewB Created
+//
+//---------------------------------------------------------------
+
+interface WLockBytes : public WUnknown
+{
+public:
+ WLockBytes(ILockBytes *plkb);
+ ~WLockBytes(void);
+
+ ILockBytes *GetI(void) { return _plkb; }
+ static WLockBytes Wrap(ILockBytes *plkb);
+ void Unwrap(void);
+
+ virtual HRESULT QueryInterface(REFIID riid, LPVOID * ppvObj);
+ virtual ULONG AddRef(void);
+ virtual ULONG Release(void);
+
+ HRESULT ReadAt(ULONG ulOffset,
+ VOID *pv,
+ ULONG cb,
+ ULONG *pcbRead);
+ HRESULT WriteAt(ULONG ulOffset,
+ VOID *pv,
+ ULONG cb,
+ ULONG *pcbWritten);
+ HRESULT Flush(void);
+ HRESULT GetSize(ULONG *pcb);
+ HRESULT SetSize(ULONG cb);
+ HRESULT LockRegion(ULONG libOffset,
+ ULONG cb,
+ DWORD dwLockType);
+ HRESULT UnlockRegion(ULONG libOffset,
+ ULONG cb,
+ DWORD dwLockType);
+ HRESULT Stat(STATSTG *pstatstg, DWORD grfStatFlag);
+
+private:
+ ILockBytes *_plkb;
+};
+
+//+--------------------------------------------------------------
+//
+// Class: WMarshal
+//
+// Purpose: Wrapper for IMarshal
+//
+// History: 24-Sep-92 DrewB Created
+//
+//---------------------------------------------------------------
+
+interface WStream;
+
+interface WMarshal : public WUnknown
+{
+public:
+ WMarshal(IMarshal *pmsh);
+ ~WMarshal(void);
+
+ IMarshal *GetI(void) { return _pmsh; }
+ static WMarshal *Wrap(IMarshal *pmsh);
+ void Unwrap(void);
+
+ virtual HRESULT QueryInterface(REFIID riid, LPVOID * ppvObj);
+ virtual ULONG AddRef(void);
+ virtual ULONG Release(void);
+
+ HRESULT GetUnmarshalClass(REFIID riid,
+ LPVOID pv,
+ DWORD dwDestContext,
+ LPVOID pvDestContext,
+ DWORD mshlflags,
+ CLSID * pCid);
+ HRESULT GetMarshalSizeMax(REFIID riid,
+ LPVOID pv,
+ DWORD dwDestContext,
+ LPVOID pvDestContext,
+ DWORD mshlflags,
+ DWORD * pSize);
+ HRESULT MarshalInterface(WStream * pStm,
+ REFIID riid,
+ LPVOID pv,
+ DWORD dwDestContext,
+ LPVOID pvDestContext,
+ DWORD mshlflags);
+ HRESULT UnmarshalInterface(WStream * pStm,
+ REFIID riid,
+ LPVOID * ppv);
+ HRESULT ReleaseMarshalData(WStream * pStm);
+ HRESULT DisconnectObject(DWORD dwReserved);
+
+private:
+ IMarshal *_pmsh;
+};
+
+//+--------------------------------------------------------------
+//
+// Class: WStream
+//
+// Purpose: Wrapper for IStream
+//
+// History: 22-Sep-92 DrewB Created
+//
+//---------------------------------------------------------------
+
+interface WStream : public WUnknown
+{
+public:
+ WStream(IStream *pstm);
+ ~WStream(void);
+
+ IStream *GetI(void) { return _pstm; }
+ static WStream *Wrap(IStream *pstm);
+ void Unwrap(void);
+
+ virtual HRESULT QueryInterface(REFIID riid, LPVOID * ppvObj);
+ virtual ULONG AddRef(void);
+ virtual ULONG Release(void);
+
+ HRESULT Read(VOID *pv, ULONG cb, ULONG *pcbRead);
+ HRESULT Write(VOID *pv,
+ ULONG cb,
+ ULONG *pcbWritten);
+ HRESULT Seek(LONG dlibMove,
+ DWORD dwOrigin,
+ ULONG *plibNewPosition);
+ HRESULT SetSize(ULONG libNewSize);
+ HRESULT CopyTo(WStream *pstm,
+ ULONG cb,
+ ULONG *pcbRead,
+ ULONG *pcbWritten);
+ HRESULT Commit(const DWORD grfCommitFlags);
+ HRESULT Revert(void);
+ HRESULT LockRegion(ULONG libOffset,
+ ULONG cb,
+ const DWORD dwLockType);
+ HRESULT UnlockRegion(ULONG libOffset,
+ ULONG cb,
+ const DWORD dwLockType);
+ HRESULT Stat(STATSTG *pstatstg, DWORD grfStatFlag);
+ HRESULT Clone(WStream * *ppstm);
+
+private:
+ IStream *_pstm;
+};
+
+//+--------------------------------------------------------------
+//
+// Class: WStorage
+//
+// Purpose: Wrapper for IStorage
+//
+// History: 22-Sep-92 DrewB Created
+//
+//---------------------------------------------------------------
+
+interface WStorage : public WUnknown
+{
+public:
+ WStorage(IStorage *pstg);
+ ~WStorage(void);
+
+ IStorage *GetI(void) { return _pstg; }
+ static WStorage *Wrap(IStorage *pstg);
+ void Unwrap(void);
+
+ virtual HRESULT QueryInterface(REFIID riid, LPVOID * ppvObj);
+ virtual ULONG AddRef(void);
+ virtual ULONG Release(void);
+
+ HRESULT CreateStream(const OLECHAR * pwcsName,
+ const DWORD grfMode,
+ DWORD reserved1,
+ DWORD reserved2,
+ WStream **ppstm);
+ HRESULT OpenStream(const OLECHAR * pwcsName,
+ void *reserved1,
+ const DWORD grfMode,
+ DWORD reserved2,
+ WStream **ppstm);
+ HRESULT CreateStorage(const OLECHAR * pwcsName,
+ const DWORD grfMode,
+ DWORD reserved1,
+ DWORD reserved2,
+ WStorage **ppstg);
+ HRESULT OpenStorage(const OLECHAR * pwcsName,
+ WStorage *pstgPriority,
+ const DWORD grfMode,
+ SNB snbExclude,
+ DWORD reserved,
+ WStorage **ppstg);
+ HRESULT CopyTo(DWORD ciidExclude,
+ IID *rgiidExclude,
+ SNB snbExclude,
+ WStorage *pstgDest);
+ HRESULT MoveElementTo(OLECHAR const FAR* lpszName,
+ WStorage FAR *pstgDest,
+ OLECHAR const FAR* lpszNewName,
+ DWORD grfFlags);
+ HRESULT Commit(const DWORD grfCommitFlags);
+ HRESULT Revert(void);
+ HRESULT EnumElements(DWORD reserved1,
+ void *reserved2,
+ DWORD reserved3,
+ WEnumSTATSTG **ppenm);
+ HRESULT DestroyElement(const OLECHAR * pwcsName);
+ HRESULT RenameElement(const OLECHAR * pwcsOldName,
+ const OLECHAR * pwcsNewName);
+ HRESULT SetElementTimes(const OLECHAR *lpszName,
+ FILETIME const *pctime,
+ FILETIME const *patime,
+ FILETIME const *pmtime);
+ HRESULT SetClass(REFCLSID clsid);
+ HRESULT SetStateBits(DWORD grfStateBits, DWORD grfMask);
+ HRESULT Stat(STATSTG *pstatstg, DWORD grfStatFlag);
+
+private:
+ IStorage *_pstg;
+};
+
+/****** Storage API Prototypes ********************************************/
+
+HRESULT WStgCreateDocfile(const OLECHAR * pwcsName,
+ const DWORD grfMode,
+ DWORD reserved,
+ WStorage * *ppstgOpen);
+HRESULT WStgCreateDocfileOnILockBytes(ILockBytes *plkbyt,
+ const DWORD grfMode,
+ DWORD reserved,
+ WStorage * *ppstgOpen);
+HRESULT WStgOpenStorage(const OLECHAR * pwcsName,
+ WStorage *pstgPriority,
+ const DWORD grfMode,
+ SNB snbExclude,
+ DWORD reserved,
+ WStorage * *ppstgOpen);
+HRESULT WStgOpenStorageOnILockBytes(ILockBytes *plkbyt,
+ WStorage *pstgPriority,
+ const DWORD grfMode,
+ SNB snbExclude,
+ DWORD reserved,
+ WStorage * *ppstgOpen);
+HRESULT WStgIsStorageFile(const OLECHAR * pwcsName);
+HRESULT WStgIsStorageILockBytes(ILockBytes * plkbyt);
+
+HRESULT WCoMarshalInterface(WStream *pStm,
+ REFIID iid,
+ IUnknown *pUnk,
+ DWORD dwDestContext,
+ LPVOID pvDestContext,
+ DWORD mshlflags);
+HRESULT WCoUnmarshalInterface(WStream *pStm,
+ REFIID riid,
+ LPVOID *ppv);
+
+#endif // #ifndef __WRAP_HXX__
diff --git a/private/oleutest/trktest/bill.sr2 b/private/oleutest/trktest/bill.sr2
new file mode 100644
index 000000000..ebf897892
--- /dev/null
+++ b/private/oleutest/trktest/bill.sr2
Binary files differ
diff --git a/private/oleutest/trktest/dirs b/private/oleutest/trktest/dirs
new file mode 100644
index 000000000..79f3a3109
--- /dev/null
+++ b/private/oleutest/trktest/dirs
@@ -0,0 +1,10 @@
+!IF 0
+
+Copyright (c) 1995 Microsoft Corporation
+
+!ENDIF
+
+DIRS=
+
+OPTIONAL_DIRS=
+
diff --git a/private/oleutest/trktest/trk1.bat b/private/oleutest/trktest/trk1.bat
new file mode 100644
index 000000000..0523961e6
--- /dev/null
+++ b/private/oleutest/trktest/trk1.bat
@@ -0,0 +1,34 @@
+
+set source=bill.sr2
+if not exist c:\trktest md c:\trktest >nul
+copy %source% c:\trktest\%source% >nul
+trktest /t c:\trktest\%source% >trktest.log
+if errorlevel 1 goto t_err
+trktest /c c:\trktest\client c:\trktest\%source% 0 >>trktest.log
+if errorlevel 1 goto c_err
+if not exist c:\trktest\foo md c:\trktest\foo >nul
+move c:\trktest\%source% c:\trktest\foo >nul
+trktest /r c:\trktest\client c:\trktest\foo\%source% 0 n >>trktest.log
+if errorlevel 1 goto r_err
+del c:\trktest\foo\%source% >nul
+trktest /r c:\trktest\client c:\trktest\foo\%source% 800401EA n >>trktest.log
+if errorlevel 1 goto r_err
+echo Passed Tracking
+goto done
+:c_err
+echo Failed to create link
+goto fail
+:r_err
+echo Failed to resolve link
+goto fail
+:t_err
+echo Failed to touch source
+goto fail
+:done
+if exist c:\trktest\foo\%source% del c:\trktest\foo\%source% >nul
+if exist c:\trktest\%source% del c:\trktest\%source% >nul
+if exist c:\trktest\foo rd c:\trktest\foo >nul
+if exist c:\trktest rd c:\trktest >nul
+:fail
+
+
diff --git a/private/oleutest/trktest/trktest.cxx b/private/oleutest/trktest/trktest.cxx
new file mode 100644
index 000000000..ab4d41003
--- /dev/null
+++ b/private/oleutest/trktest/trktest.cxx
@@ -0,0 +1,216 @@
+#include <windows.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+WCHAR *Convert(char *psz)
+{ int c;
+ WCHAR *pwsz = new WCHAR [ c = strlen(psz) + 1 ];
+ if (pwsz)
+ mbstowcs(pwsz, psz, c);
+ return pwsz;
+}
+
+#define CHECKNE(hr, stat, string, errRet) \
+if (hr != stat) { iLine = __LINE__; pszErr = string; goto errRet; }
+
+HRESULT TouchFile(WCHAR *pwszSource)
+{
+ FILETIME ftc;
+ SYSTEMTIME st;
+
+ GetSystemTime(&st);
+ SystemTimeToFileTime(&st, &ftc);
+ return StgSetTimes(pwszSource, &ftc, NULL, NULL);
+}
+
+HRESULT CreateLink(WCHAR *pwszClient, WCHAR *pwszSource)
+{
+ HRESULT hr;
+ IBindCtx *pbc=NULL;
+ ULONG ulEaten;
+ IMoniker *pmkSource=NULL;
+ IStorage *pstg=NULL;
+ IOleObject *poo=NULL;
+ IMoniker *pmkThis=NULL;
+ IMoniker *pmkLink=NULL;
+ IPersistStorage *pps=NULL;
+ char *pszErr;
+ int iLine=0;
+
+ hr = CreateFileMoniker(pwszClient, &pmkThis);
+ CHECKNE(hr, S_OK, "CreateFileMoniker", errRet);
+ hr = CreateItemMoniker(L"!", L"Link", &pmkLink);
+ CHECKNE(hr, S_OK, "CreateItemMoniker", errRet);
+ hr = StgCreateDocfile(pwszClient, STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
+ 0, &pstg);
+ CHECKNE(hr, S_OK, "StgCreateDocfile", errRet);
+ hr = CreateBindCtx(0, &pbc);
+ CHECKNE(hr, S_OK, "CreateBindCtx", errRet);
+ hr = MkParseDisplayName(pbc, pwszSource, &ulEaten, &pmkSource);
+ CHECKNE(hr, S_OK, "MkParseDisplayName", errRet);
+ hr = OleCreateLink(pmkSource, IID_IOleObject, OLERENDER_NONE, NULL, NULL, pstg, (void**)&poo);
+ CHECKNE(hr, S_OK, "OleCreateLink", errRet);
+ hr = poo->SetMoniker(OLEWHICHMK_CONTAINER, pmkThis);
+ CHECKNE(hr, S_OK, "SetMonikerOLEWHICHMK_CONTAINER", errRet);
+ hr = poo->SetMoniker(OLEWHICHMK_OBJREL, pmkLink);
+ CHECKNE(hr, S_OK, "SetMonikerOLEWHICHMK_OBJREL", errRet);
+ hr = poo->QueryInterface(IID_IPersistStorage, (void**)&pps);
+ CHECKNE(hr, S_OK, "QueryInterface(IID_IPersistStorage", errRet);
+ hr = OleSave(pps, pstg, TRUE);
+ CHECKNE(hr, S_OK, "OleSave", errRet);
+
+errRet:
+ if (hr != S_OK)
+ printf("CreateLink at %s line %d with hr=%08x\n", pszErr, iLine, hr);
+
+ if (pbc) pbc->Release();
+ if (pmkSource) pmkSource->Release();
+ if (pstg) pstg->Release();
+ if (poo) poo->Release();
+ if (pmkThis) pmkThis->Release();
+ if (pmkLink) pmkLink->Release();
+ if (pps) pps->Release();
+
+ return hr;
+}
+
+HRESULT ResolveLink(WCHAR *pwszClient, WCHAR *pwszSource, BOOL fReSave)
+{
+ HRESULT hr;
+ IStorage *pstg = NULL;
+ IOleLink *pol = NULL;
+ WCHAR *pwszSourceFound = NULL;
+ IPersistStorage *pps = NULL;
+ char *pszErr;
+ int iLine;
+
+ hr = StgOpenStorage(pwszClient, NULL, STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
+ NULL, 0, &pstg);
+ CHECKNE(hr, S_OK, "StgOpenStorage(pwszClient", errRet);
+ hr = OleLoad(pstg, IID_IOleLink, NULL, (void**)&pol);
+ CHECKNE(hr, S_OK, "OleLoad(pstg, IID_IOleLink", errRet);
+ hr = pol->BindToSource(0, NULL);
+ CHECKNE(hr, S_OK, "pol->BindToSource", errRet);
+ hr = pol->GetSourceDisplayName(&pwszSourceFound);
+ CHECKNE(hr, S_OK, "pol->GetSourceDisplayName", errRet);
+ if (wcsicmp(pwszSourceFound, pwszSource) != 0)
+ {
+ printf("SourceFound=%ls, SourceExpected=%ls\n", pwszSourceFound, pwszSource);
+ pszErr = "'path compare'";
+ hr = E_FAIL;
+ goto errRet;
+ }
+
+ if (fReSave)
+ {
+ hr = pol->QueryInterface(IID_IPersistStorage, (void**)&pps);
+ CHECKNE(hr, S_OK, "pol->QueryInterface(IID_IPersistStorage", errRet);
+ hr = OleSave(pps, pstg, TRUE);
+ CHECKNE(hr, S_OK, "OleSave(pps, pstg, TRUE)", errRet);
+ }
+
+errRet:
+ if (hr != S_OK)
+ printf("ResolveLink at %s line %d with hr=%08x\n", pszErr, iLine, hr);
+
+ CoTaskMemFree(pwszSourceFound);
+ if (pol) pol->Release();
+ if (pstg) pstg->Release();
+ if (pps) pps->Release();
+ return hr;
+}
+
+int __cdecl main(int argc, char **argv)
+{
+ char * pszExit = "TEST FAILED.";
+ int iExit = 1;
+ WCHAR *pwszClient = NULL;
+ WCHAR *pwszSource = NULL;
+ HRESULT hr=E_FAIL;
+ BOOL fArgsOk = FALSE;
+ HRESULT hrExpected=S_OK;
+
+ CoInitialize(NULL);
+ OleInitialize(NULL);
+
+ if (argc >= 3)
+ {
+ pwszClient = Convert(argv[2]);
+ }
+
+ if (argc >= 5)
+ {
+ pwszSource = Convert(argv[3]);
+ sscanf(argv[4], "%x", &hrExpected);
+ if (!pwszClient || !pwszSource)
+ {
+ pszExit = "Out of memory.";
+ goto errExit;
+ }
+ }
+
+ if (argc == 3)
+ {
+ if (stricmp(argv[1], "/t") == 0 || stricmp(argv[1], "-t") == 0)
+ {
+ // touch file creation date
+ hr = TouchFile(pwszClient);
+ fArgsOk = TRUE;
+ }
+ }
+ else
+ if (argc == 5)
+ {
+ if (stricmp(argv[1], "/c") == 0 || stricmp(argv[1], "-c") == 0)
+ {
+ // create link
+ hr = CreateLink(pwszClient, pwszSource);
+ fArgsOk = TRUE;
+ }
+ }
+ else
+ if (argc == 6)
+ {
+ if (stricmp(argv[1], "/r") == 0 || stricmp(argv[1], "-r") == 0)
+ {
+ // resolve link
+ hr = ResolveLink(pwszClient, pwszSource, argv[5][0] == 's');
+ fArgsOk = TRUE;
+ }
+ }
+
+ if (!fArgsOk)
+ {
+ pszExit = "Usage: /c client source expected_status -- create .lts file linked to source\n"
+ " /r client expected_source expected_status save/nosave -- resolve .lts file, checked linked to source\n"
+ " expected_source is ignored(but required) if not found during resolve.\n"
+ " /t source -- change the creation date\n";
+
+ }
+ else
+ {
+ if (hrExpected != hr)
+ {
+ printf("Expected status = %08X, actual status = %08X\n",
+ hrExpected,
+ hr);
+ }
+ else
+ {
+ pszExit = "TEST PASSED.";
+ iExit = 0;
+ }
+ }
+
+errExit:
+
+ OleUninitialize();
+ CoUninitialize();
+
+ delete pwszClient;
+ delete pwszSource;
+
+ puts(pszExit);
+
+ return iExit;
+}
diff --git a/private/oleutest/utests16/makefile.inc b/private/oleutest/utests16/makefile.inc
new file mode 100644
index 000000000..daaf0ac61
--- /dev/null
+++ b/private/oleutest/utests16/makefile.inc
@@ -0,0 +1,330 @@
+# 16-bit makefile
+#
+# Copyright (c) 1991, Microsoft Corporation
+#
+# History:
+#
+# 18-Feb-1994 KevinRo
+# 24-Feb-1994 DrewB, added OBJDIR and some other niceties from win40.mk
+#
+
+.SUFFIXES:
+.SUFFIXES: .c .cxx .cpp .asm .h .inc .obj .lst
+.SUFFIXES: .sys .exe .com .map .sym .def .lib .rc .res
+
+!if "$(TARGET)" == ""
+!error TARGET must be defined
+!endif
+
+OUTNUL= 1>nul 2>nul
+
+!if "$(NTDEBUG)" != "" && "$(NTDEBUG)" != "retail"
+OBJDIR = objd
+!else
+OBJDIR = objr
+!endif
+
+# Build up lists of files to produce from sources
+
+!if "$(CFILES)" != ""
+OBJFILES = $(OBJFILES) $(CFILES:.c=.obj)
+!endif
+!if "$(CXXFILES)" != ""
+OBJFILES = $(OBJFILES) $(CXXFILES:.cxx=.obj)
+!endif
+!if "$(CPPFILES)" != ""
+OBJFILES = $(OBJFILES) $(CPPFILES:.cpp=.obj)
+!endif
+
+!if "$(ASMFILES)" != ""
+OBJFILES = $(OBJFILES) $(ASMFILES:.asm=.obj)
+!endif
+
+!if "$(RCFILES)" != ""
+RESFILES = $(RCFILES:.rc=.res)
+!endif
+
+# Replace .\ with $(OBJDIR)
+# Unfortunately we can't do this directly so we have to explicitly check
+# the value of OBJDIR
+
+!if "$(OBJDIR)" == "objd"
+OBJFILES = $(OBJFILES:.\=objd\)
+RESFILES = $(RESFILES:.\=objd\)
+
+!elseif "$(OBJDIR)" == "objr"
+OBJFILES = $(OBJFILES:.\=objr\)
+RESFILES = $(RESFILES:.\=objr\)
+
+!else
+!error Unknown OBJDIR: $(OBJDIR)
+!endif
+
+# Default target
+
+all: $(OBJDIR)\$(TARGET)
+
+# Determine target type and base name
+
+# Is it a DLL?
+TARGETBASE=$(TARGET:.dll=)
+!if "$(TARGETBASE)" != "$(TARGET)"
+TARGETTYPE=dll
+!else
+
+# Is it an EXE?
+TARGETBASE=$(TARGET:.exe=)
+! if "$(TARGETBASE)" != "$(TARGET)"
+TARGETTYPE=exe
+! else
+
+# Is it a LIB?
+TARGETBASE=$(TARGET:.lib=)
+! if "$(TARGETBASE)" != "$(TARGET)"
+TARGETTYPE=lib
+! endif
+! endif
+!endif
+
+!if "$(TARGETTYPE)" == ""
+!error Unknown target type for "$(TARGET)"
+!endif
+
+!if "$(BUILDDETAILS)" != ""
+BLDKEEP= KEEP
+!endif
+
+OLETHUNK= $(_NTDRIVE)$(_NTROOT)\private\ole32\olethunk
+OLE16= $(OLETHUNK)\ole16
+
+RCINC = $(RCINC) -i$(OLE16)\inc
+INCS = -I$(OLE16)\inc -I$(OLETHUNK)\h -I$(_NTDRIVE)$(_NTROOT)\private\cinc
+
+
+PATH = $(OLE16)\tools;$(PATH)
+LINK = link16
+RC = rc16
+CL = cl16
+IMPLIB = implib
+LIBUTIL = lib16
+MAPSYM = mapsym
+MASM = masm
+
+DEFINES = -DWOW
+
+AOBJ = -Mx -t $(DEFINES) $(INCS)
+
+!if "$(TARGETTYPE)" == "exe"
+CW16 = -GA
+!else
+CW16 = -GD
+DEFINES = $(DEFINES) -D_WINDLL
+!endif
+
+CW16 = $(CW16) -G2 -AL $(DEFINES) $(INCS) /NMSEG_CODE
+
+LFLAGS = $(LFLAGS) /nod /noe /map:0 /align:16
+
+!if "$(NTDEBUG)" != "" && "$(NTDEBUG)" != "retail"
+
+DEFINES = $(DEFINES) -DDBG=1 -DDEVL=1
+
+!if "$(NTDEBUGTYPE)" == "windbg"
+AOBJ = $(AOBJ) -Zi
+CW16 = $(CW16) /Odi /Zip /FA
+LFLAGS = $(LFLAGS) /CO
+!else
+AOBJ = $(AOBJ) -Zd
+CW16 = $(CW16) /Odi /Zd
+LFLAGS = $(LFLAGS) /LI
+!endif
+
+!else
+CW16 = $(CW16) /Os /Zp /Gs
+DEFINES = $(DEFINES) -DDBG=0 -DDEVL=1
+!endif
+
+!if "$(TARGETTYPE)" == "dll"
+W16LIBS = $(OLE16)\lib\ldllcew.lib
+!else
+!if "$(QUICKWINDOWS)" != ""
+W16LIBS = $(OLE16)\lib\llibcewq.lib
+!else
+W16LIBS = $(OLE16)\lib\llibcew.lib
+!endif
+!endif
+
+W16LIBS = $(W16LIBS) $(OLE16)\lib\libw.lib
+
+!if "$(TARGETTYPE)" == "dll" || "$(TARGETTYPE)" == "exe"
+LIBS = $(LIBS) $(W16LIBS)
+!endif
+
+.asm{$(OBJDIR)}.obj:
+ @-md $(OBJDIR) $(OUTNUL)
+ $(MASM) $(AOBJ) $*,$*;
+
+.asm.lst:
+ @-md $(OBJDIR) $(OUTNUL)
+ $(MASM) $(AOBJ) -l $*,nul,$*.lst;
+
+
+.c{$(OBJDIR)}.obj:
+ @-md $(OBJDIR) $(OUTNUL)
+ $(CL) -c -nologo @<<$*.rsp
+$(CW16: =
+)
+-Fo$*.obj
+$<
+<<$(BLDKEEP)
+
+.c.lst:
+ @-md $(OBJDIR) $(OUTNUL)
+ $(CL) -c -nologo @<<$(OBJDIR)\$*.rsp
+$(CW16: =
+)
+-Fonul
+-Fc$*.lst
+$<
+<<$(BLDKEEP)
+
+.cxx{$(OBJDIR)}.obj:
+ @-md $(OBJDIR) $(OUTNUL)
+ $(CL) -c -nologo @<<$*.rsp
+$(CW16: =
+)
+-Fo$*.obj
+-Tp$<
+<<$(BLDKEEP)
+
+.cxx.lst:
+ @-md $(OBJDIR) $(OUTNUL)
+ $(CL) -c -nologo @<<$(OBJDIR)\$*.rsp
+$(CW16: =
+)
+-Fc$*.lst
+-Fonul
+-Tp$<
+<<$(BLDKEEP)
+
+.cxx.pp:
+ @-md $(OBJDIR) $(OUTNUL)
+ $(CL) -c -nologo @<<$(OBJDIR)\$*.rsp > $*.pp
+$(CW16: =
+)
+-E
+-Fonul
+-Tp$<
+<<$(BLDKEEP)
+
+
+.cpp{$(OBJDIR)}.obj:
+ @-md $(OBJDIR) $(OUTNUL)
+ $(CL) -c -nologo @<<$*.rsp
+$(CW16: =
+)
+-Fo$*.obj
+-Tp$<
+<<$(BLDKEEP)
+
+.cpp.lst:
+ @-md $(OBJDIR) $(OUTNUL)
+ $(CL) -c -nologo @<<$(OBJDIR)\$*.rsp
+$(CW16: =
+)
+-Fc$*.lst
+-Fonul
+-Tp$<
+<<$(BLDKEEP)
+
+.cpp.pp:
+ @-md $(OBJDIR) $(OUTNUL)
+ $(CL) -c -nologo @<<$(OBJDIR)\$*.rsp > $*.pp
+$(CW16: =
+)
+-E
+-Fonul
+-Tp$<
+<<$(BLDKEEP)
+
+
+.def{$(OBJDIR)}.lib:
+ @-md $(OBJDIR) $(OUTNUL)
+ $(IMPLIB) $*.lib $<
+
+{$(OBJDIR)}.map{$(OBJDIR)}.sym:
+ @-md $(OBJDIR) $(OUTNUL)
+ $(MAPSYM) $<
+
+.rc{$(OBJDIR)}.res:
+ @-md $(OBJDIR) $(OUTNUL)
+ $(RC) -r $(RCINC) -fo $*.res $<
+
+
+cleanup:
+ if exist $(OBJDIR)\*.lrf del $(OBJDIR)\*.lrf
+ if exist $(OBJDIR)\*.obj del $(OBJDIR)\*.obj
+ if exist $(OBJDIR)\*.exe del $(OBJDIR)\*.exe
+ if exist $(OBJDIR)\*.map del $(OBJDIR)\*.map
+ if exist $(OBJDIR)\*.sym del $(OBJDIR)\*.sym
+ if exist $(OBJDIR)\*.res del $(OBJDIR)\*.res
+
+clean: cleanup
+
+!if "$(TARGETTYPE)" == "dll"
+
+$(OBJDIR)\$(TARGETBASE).lib: $(TARGETBASE).def
+
+$(OBJDIR)\$(TARGET) $(OBJDIR)\$(TARGETBASE).map: $(OBJFILES) $(RESFILES) \
+ $(TARGETBASE).def $(OBJDIR)\$(TARGETBASE).lib $(LIBS)
+ @-md $(OBJDIR) $(OUTNUL)
+ $(LINK) $(LFLAGS) @<<$(OBJDIR)\$(TARGETBASE).rsp
+$(OBJFILES: =+^
+)
+$(OBJDIR)\$(TARGET)
+$(OBJDIR)\$(TARGETBASE).map
+$(LIBS: =+^
+)
+$(TARGETBASE).def
+<<$(BLDKEEP)
+ $(MAPSYM) -o $(OBJDIR)\$(TARGETBASE).sym $(OBJDIR)\$(TARGETBASE).map
+!if "$(RCFILES)" != ""
+ $(RC) -t $(OBJDIR)\$(TARGETBASE).res $(OBJDIR)\$(TARGET)
+!endif
+
+!elseif "$(TARGETTYPE)" == "lib"
+
+$(OBJDIR)\$(TARGET): $(OBJFILES) $(LIBS)
+ @-md $(OBJDIR) $(OUTNUL)
+ -del $@ $(OUTNUL)
+ $(LIBUTIL) @<<$*.lnb
+$(OBJDIR)\$(TARGET)
+y
+$(OBJFILES: = &^
+)&
+$(LIBS: = &^
+)&
+
+$*.lls
+<<$(BLDKEEP)
+
+!elseif "$(TARGETTYPE)" == "exe"
+
+$(OBJDIR)\$(TARGET) $(OBJDIR)\$(TARGETBASE).map: $(OBJFILES) $(RESFILES) \
+ $(TARGETBASE).def $(LIBS)
+ @-md $(OBJDIR) $(OUTNUL)
+ $(LINK) $(LFLAGS) @<<$(OBJDIR)\$(TARGETBASE).rsp
+$(OBJFILES: =+^
+)
+$(OBJDIR)\$(TARGET)
+$(OBJDIR)\$(TARGETBASE).map
+$(LIBS: =+^
+)
+$(TARGETBASE).def
+<<$(BLDKEEP)
+!if "$(RCFILES)" != ""
+ $(RC) -t $(OBJDIR)\$(TARGETBASE).res $(OBJDIR)\$(TARGET)
+!endif
+ $(MAPSYM) -o $(OBJDIR)\$(TARGETBASE).sym $(OBJDIR)\$(TARGETBASE).map
+
+!endif
diff --git a/private/oleutest/utests16/ole2ui/ole2ui.h b/private/oleutest/utests16/ole2ui/ole2ui.h
new file mode 100644
index 000000000..4691c005b
--- /dev/null
+++ b/private/oleutest/utests16/ole2ui/ole2ui.h
@@ -0,0 +1,918 @@
+/*
+ * 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
+ */
+
+/* NOTE: All dialog and string resource ID's defined in this file are
+ * in the range:
+ * 32248 - 32504 (0x7DF8 - 0x7EF8)
+*/
+
+
+#ifndef _OLE2UI_H_
+#define _OLE2UI_H_
+
+#ifndef RC_INVOKED
+#pragma message ("Including OLE2UI.H from " __FILE__)
+#endif //RC_INVOKED
+
+#ifdef WIN32
+#define _INC_OLE
+#define __RPC_H__
+#endif
+
+#if !defined(__cplusplus) && !defined( __TURBOC__)
+#define NONAMELESSUNION // use strict ANSI standard (for DVOBJ.H)
+#endif
+
+#include <windows.h>
+#include <shellapi.h>
+#include <ole2.h>
+#include <string.h>
+#include <dlgs.h> //For fileopen dlg; standard include
+#include "olestd.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
+#define _fstrcpy strcpy
+#define _fstrlen strlen
+#define _fstrrchr strrchr
+#define _fstrtok strtok
+#define lstrcpyn strncpy
+
+// BUGBUG32: isspace function does not seem to work properly
+#undef isspace
+#define isspace(j) (j==' ' || j=='\t' || j=='\n')
+#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);
+STDAPI_(BOOL) OleUIUninitialize(void);
+
+#if !defined( SZCLASSICONBOX )
+#define SZCLASSICONBOX "ole2uiIBCls"
+#endif
+
+#if !defined( SZCLASSRESULTIMAGE )
+#define SZCLASSRESULTIMAGE "ole2uiRICls"
+#endif
+
+// object count, used to support DllCanUnloadNow and OleUICanUnloadNow
+extern DWORD g_dwObjectCount;
+
+STDAPI OleUICanUnloadNow(void);
+STDAPI OleUILockLibrary(BOOL fLock);
+
+
+//Dialog Identifiers as passed in Help messages to identify the source.
+#define IDD_INSERTOBJECT 32248
+#define IDD_CHANGEICON 32249
+#define IDD_CONVERT 32250
+#define IDD_PASTESPECIAL 32251
+#define IDD_EDITLINKS 32252
+#define IDD_FILEOPEN 32253
+#define IDD_BUSY 32254
+#define IDD_UPDATELINKS 32255
+#define IDD_CANNOTUPDATELINK 32256
+#define IDD_CHANGESOURCE 32257
+#define IDD_INSERTFILEBROWSE 32258
+#define IDD_CHANGEICONBROWSE 32259
+
+// The following Dialogs are message dialogs used by OleUIPromptUser API
+#define IDD_LINKSOURCEUNAVAILABLE 32260
+#define IDD_SERVERNOTREG 32261
+#define IDD_LINKTYPECHANGED 32262
+#define IDD_SERVERNOTFOUND 32263
+#define IDD_OUTOFMEMORY 32264
+
+// Stringtable identifers
+#define IDS_OLE2UIUNKNOWN 32300
+#define IDS_OLE2UILINK 32301
+#define IDS_OLE2UIOBJECT 32302
+#define IDS_OLE2UIEDIT 32303
+#define IDS_OLE2UICONVERT 32304
+#define IDS_OLE2UIEDITLINKCMD_1VERB 32305
+#define IDS_OLE2UIEDITOBJECTCMD_1VERB 32306
+#define IDS_OLE2UIEDITLINKCMD_NVERB 32307
+#define IDS_OLE2UIEDITOBJECTCMD_NVERB 32308
+#define IDS_OLE2UIEDITNOOBJCMD 32309
+// def. icon label (usu. "Document")
+#define IDS_DEFICONLABEL 32310
+#define IDS_OLE2UIPASTELINKEDTYPE 32311
+
+
+#define IDS_FILTERS 32320
+#define IDS_ICONFILTERS 32321
+#define IDS_BROWSE 32322
+
+//Resource identifiers for bitmaps
+#define IDB_RESULTSEGA 32325
+#define IDB_RESULTSVGA 32326
+#define IDB_RESULTSHIRESVGA 32327
+
+
+//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 "OLEUI_MSG_HELP"
+#define SZOLEUI_MSG_ENDDIALOG "OLEUI_MSG_ENDDIALOG"
+#define SZOLEUI_MSG_BROWSE "OLEUI_MSG_BROWSE"
+#define SZOLEUI_MSG_CHANGEICON "OLEUI_MSG_CHANGEICON"
+#define SZOLEUI_MSG_CLOSEBUSYDIALOG "OLEUI_MSG_CLOSEBUSYDIALOG"
+#define SZOLEUI_MSG_FILEOKSTRING "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
+#define IDHELP 1038
+
+// Static text control (use this instead of -1 so things work correctly for
+// localization
+#define ID_STATIC 98
+
+//Maximum key size we read from the RegDB.
+#define OLEUI_CCHKEYMAX 256 // make any changes to this in geticon.c too
+
+//Maximum verb length and length of Object menu
+#define OLEUI_CCHVERBMAX 32
+#define OLEUI_OBJECTMENUMAX 256
+
+//Maximum MS-DOS pathname.
+#define OLEUI_CCHPATHMAX 256 // make any changes to this in geticon.c too
+#define OLEUI_CCHFILEMAX 13
+
+//Icon label length
+#define OLEUI_CCHLABELMAX 40 // make any changes to this in geticon.c too
+
+//Length of the CLSID string
+#define OLEUI_CCHCLSIDSTRING 39
+
+
+/*
+ * 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,
+ LPSTR lpszShortType,
+ HMENU hMenu,
+ UINT uPos,
+ UINT uIDVerbMin,
+ UINT uIDVerbMax,
+ BOOL bAddConvert,
+ UINT idConvert,
+ HMENU FAR *lphMenu);
+
+//Metafile utility functions
+STDAPI_(HGLOBAL) OleUIMetafilePictFromIconAndLabel(HICON, LPSTR, LPSTR, UINT);
+STDAPI_(void) OleUIMetafilePictIconFree(HGLOBAL);
+STDAPI_(BOOL) OleUIMetafilePictIconDraw(HDC, LPRECT, HGLOBAL, BOOL);
+STDAPI_(UINT) OleUIMetafilePictExtractLabel(HGLOBAL, LPSTR, UINT, LPDWORD);
+STDAPI_(HICON) OleUIMetafilePictExtractIcon(HGLOBAL);
+STDAPI_(BOOL) OleUIMetafilePictExtractIconSource(HGLOBAL,LPSTR,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
+ LPCSTR lpszCaption; //Dialog caption bar contents
+ LPFNOLEUIHOOK lpfnHook; //Hook callback
+ LPARAM lCustData; //Custom data to pass to hook
+ HINSTANCE hInstance; //Instance for customized template name
+ LPCSTR 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
+ LPSTR 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 32400
+#define IDS_IORESULTNEWICON 32401
+#define IDS_IORESULTFROMFILE1 32402
+#define IDS_IORESULTFROMFILE2 32403
+#define IDS_IORESULTFROMFILEICON2 32404
+#define IDS_IORESULTLINKFILE1 32405
+#define IDS_IORESULTLINKFILE2 32406
+#define IDS_IORESULTLINKFILEICON1 32407
+#define IDS_IORESULTLINKFILEICON2 32408
+
+/*************************************************************************
+** 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
+ LPCSTR lpszCaption; //Dialog caption bar contents
+ LPFNOLEUIHOOK lpfnHook; //Hook callback
+ LPARAM lCustData; //Custom data to pass to hook
+ HINSTANCE hInstance; //Instance for customized template name
+ LPCSTR 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 32410
+#define IDS_PSPASTEOBJECT 32411
+#define IDS_PSPASTEOBJECTASICON 32412
+#define IDS_PSPASTELINKDATA 32413
+#define IDS_PSPASTELINKOBJECT 32414
+#define IDS_PSPASTELINKOBJECTASICON 32415
+#define IDS_PSNONOLE 32416
+#define IDS_PSUNKNOWNTYPE 32417
+#define IDS_PSUNKNOWNSRC 32418
+#define IDS_PSUNKNOWNAPP 32419
+
+
+/*************************************************************************
+** 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,
+ LPSTR lpszDisplayName,
+ ULONG lenFileName,
+ ULONG FAR* pchEaten,
+ BOOL fValidateSource) PURE;
+ STDMETHOD(GetLinkSource) (THIS_
+ DWORD dwLink,
+ LPSTR FAR* lplpszDisplayName,
+ ULONG FAR* lplenFileName,
+ LPSTR FAR* lplpszFullLinkType,
+ LPSTR 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
+ LPCSTR lpszCaption; //Dialog caption bar contents
+ LPFNOLEUIHOOK lpfnHook; //Hook callback
+ LPARAM lCustData; //Custom data to pass to hook
+ HINSTANCE hInstance; //Instance for customized template name
+ LPCSTR 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
+ LPCSTR lpszCaption; //Dialog caption bar contents
+ LPFNOLEUIHOOK lpfnHook; //Hook callback
+ LPARAM lCustData; //Custom data to pass to hook
+ HINSTANCE hInstance; //Instance for customized template name
+ LPCSTR 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
+ char 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 32430
+#define IDS_CIINVALIDFILE 32431
+#define IDS_CIFILEACCESS 32432
+#define IDS_CIFILESHARE 32433
+#define IDS_CIFILEOPENFAIL 32434
+
+
+
+/*************************************************************************
+** 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
+ LPCSTR lpszCaption; //Dialog caption bar contents
+ LPFNOLEUIHOOK lpfnHook; //Hook callback
+ LPARAM lCustData; //Custom data to pass to hook
+ HINSTANCE hInstance; //Instance for customized template name
+ LPCSTR 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.
+ LPSTR 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)
+ LPSTR 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 32440
+#define IDS_CVRESULTCONVERTTO 32441
+#define IDS_CVRESULTNOCHANGE 32442
+#define IDS_CVRESULTDISPLAYASICON 32443
+#define IDS_CVRESULTACTIVATEAS 32444
+#define IDS_CVRESULTACTIVATEDIFF 32445
+
+
+/*************************************************************************
+** 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
+ LPCSTR lpszCaption; //Dialog caption bar contents
+ LPFNOLEUIHOOK lpfnHook; //Hook callback
+ LPARAM lCustData; //Custom data to pass to hook
+ HINSTANCE hInstance; //Instance for customized template name
+ LPCSTR 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 32447
+#define IDS_BZRESULTTEXTNOTRESPONDING 32448
+
+// Links dialog stringtable defines
+#define IDS_LINK_AUTO 32450
+#define IDS_LINK_MANUAL 32451
+#define IDS_LINK_UNKNOWN 32452
+#define IDS_LINKS 32453
+#define IDS_FAILED 32454
+#define IDS_CHANGESOURCE 32455
+#define IDS_INVALIDSOURCE 32456
+#define IDS_ERR_GETLINKSOURCE 32457
+#define IDS_ERR_GETLINKUPDATEOPTIONS 32458
+#define IDS_ERR_ADDSTRING 32459
+#define IDS_CHANGEADDITIONALLINKS 32460
+#define IDS_CLOSE 32461
+
+
+/*************************************************************************
+** 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(WORD 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,
+ LPSTR 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/utests16/ole2ui/ole2ui.rc b/private/oleutest/utests16/ole2ui/ole2ui.rc
new file mode 100644
index 000000000..8317edcd6
--- /dev/null
+++ b/private/oleutest/utests16/ole2ui/ole2ui.rc
@@ -0,0 +1,40 @@
+/*
+ * 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
+#include "ole2ui.h"
+
+//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 "RES\OLE2UI.RCV"
+#endif
diff --git a/private/oleutest/utests16/ole2ui/res/localole.h b/private/oleutest/utests16/ole2ui/res/localole.h
new file mode 100644
index 000000000..a66c97e0b
--- /dev/null
+++ b/private/oleutest/utests16/ole2ui/res/localole.h
@@ -0,0 +1,1001 @@
+/*
+ * 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
+ */
+
+
+#define NONAMELESSUNION // use strict ANSI standard (for DVOBJ.H)
+
+#ifndef _OLE2UI_H_
+#define _OLE2UI_H_
+
+#ifndef RC_INVOKED
+#pragma message ("Including OLE2UI.H from " __FILE__)
+#endif //RC_INVOKED
+
+#include <windows.h>
+#include <shellapi.h>
+#include <ole2.h>
+#include <string.h>
+#include "olestd.h"
+#include "uiclass.h"
+// -- see below
+
+#ifdef __TURBOC__
+#define _getcwd getcwd
+#define _itoa itoa
+#define __max max
+#define _find_t find_t
+#endif // __TURBOC__
+
+/*
+ * Initialization / Uninitialization routines. OleUIInitialize
+ * MUST be called prior to using any functions in OLE2UI.
+ */
+
+STDAPI_(BOOL) OleUIInitialize(HINSTANCE);
+STDAPI_(BOOL) OleUIUnInitialize(void); // Must be called when completed using functions in OLE2UI
+
+//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_LINKSOURCEUNAVAILABLE 1007
+#define IDD_CANNOTUPDATELINK 1008
+#define IDD_SERVERNOTREG 1009
+#define IDD_LINKTYPECHANGED 1010
+#define IDD_SERVERNOTFOUND 1011
+#define IDD_UPDATELINKS 1012
+#define IDD_OUTOFMEMORY 1013
+
+#define IDOK 1
+#define IDCANCEL 2
+
+// 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
+#define IDS_DEFICONLABEL 310 // def. icon label (usu. "Document")
+
+
+#define IDS_FILTERS 64
+#define IDS_ICONFILTERS 65
+
+//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 "OLEUI_MSG_HELP"
+#define SZOLEUI_MSG_ENDDIALOG "OLEUI_MSG_ENDDIALOG"
+#define SZOLEUI_MSG_BROWSE "OLEUI_MSG_BROWSE"
+#define SZOLEUI_MSG_CHANGEICON "OLEUI_MSG_CHANGEICON"
+#define SZOLEUI_MSG_CLOSEBUSYDIALOG "OLEUI_MSG_CLOSEBUSYDIALOG"
+#define SZOLEUI_MSG_FILEOKSTRING "OLEUI_MSG_FILEOKSTRING"
+
+// Define the classname strings. The strings below define the custom
+// control classnames for the controls used in the UI dialogs.
+//
+// **************************************************************
+// These classnames must be distinct for each application
+// which uses this library, or your application will generate an
+// fatal error under the debugging version of Windows 3.1.
+// **************************************************************
+//
+// The MAKEFILE for this library automatically generates a file
+// uiclass.h which contains distinct definitions for these
+// classname strings, as long as you use a distinct name when
+// you build the library. See the MAKEFILE for more information
+// on setting the name of the library.
+
+#define SZCLASSICONBOX OLEUICLASS1
+#define SZCLASSRESULTIMAGE OLEUICLASS2
+
+#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
+#define IDHELP 1038
+
+// Static text control (use this instead of -1 so things work correctly for
+// localization
+#define ID_STATIC 98
+
+//Maximum key size we read from the RegDB.
+#define OLEUI_CCHKEYMAX 256 // make any changes to this in geticon.c too
+
+//Maximum verb length and length of Object menu
+#define OLEUI_CCHVERBMAX 32
+#define OLEUI_OBJECTMENUMAX 64
+
+//Maximum MS-DOS pathname.
+#define OLEUI_CCHPATHMAX 256 // make any changes to this in geticon.c too
+#define OLEUI_CCHFILEMAX 13
+
+//Icon label length
+#define OLEUI_CCHLABELMAX 40 // make any changes to this in geticon.c too
+
+//Length of the CLSID string
+#define OLEUI_CCHCLSIDSTRING 39
+
+
+/*
+ * 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,
+ LPSTR lpszShortType,
+ HMENU hMenu,
+ UINT uPos,
+ UINT uIDVerbMin,
+ BOOL bAddConvert,
+ UINT idConvert,
+ HMENU FAR *lphMenu);
+
+//Metafile utility functions
+STDAPI_(HGLOBAL) OleUIMetafilePictFromIconAndLabel(HICON, LPSTR, LPSTR, UINT);
+STDAPI_(void) OleUIMetafilePictIconFree(HGLOBAL);
+STDAPI_(BOOL) OleUIMetafilePictIconDraw(HDC, LPRECT, HGLOBAL, BOOL);
+STDAPI_(UINT) OleUIMetafilePictExtractLabel(HGLOBAL, LPSTR, UINT, LPDWORD);
+STDAPI_(HICON) OleUIMetafilePictExtractIcon(HGLOBAL);
+STDAPI_(BOOL) OleUIMetafilePictExtractIconSource(HGLOBAL,LPSTR,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
+ LPCSTR lpszCaption; //Dialog caption bar contents
+ LPFNOLEUIHOOK lpfnHook; //Hook callback
+ LPARAM lCustData; //Custom data to pass to hook
+ HINSTANCE hInstance; //Instance for customized template name
+ LPCSTR 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
+ LPSTR 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
+
+
+//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
+ LPCSTR lpszCaption; //Dialog caption bar contents
+ LPFNOLEUIHOOK lpfnHook; //Hook callback
+ LPARAM lCustData; //Custom data to pass to hook
+ HINSTANCE hInstance; //Instance for customized template name
+ LPCSTR 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 information.
+ int cPasteEntries; //Number 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
+
+ //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
+ } 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
+
+
+//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,
+ LPSTR lpszDisplayName,
+ ULONG lenFileName,
+ ULONG FAR* pchEaten,
+ BOOL fValidateSource) PURE;
+ STDMETHOD(GetLinkSource) (THIS_
+ DWORD dwLink,
+ LPSTR FAR* lplpszDisplayName,
+ ULONG FAR* lplenFileName,
+ LPSTR FAR* lplpszFullLinkType,
+ LPSTR 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
+ LPCSTR lpszCaption; //Dialog caption bar contents
+ LPFNOLEUIHOOK lpfnHook; //Hook callback
+ LPARAM lCustData; //Custom data to pass to hook
+ HINSTANCE hInstance; //Instance for customized template name
+ LPCSTR 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
+
+// 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_HELP 207
+#define ID_EL_COL1 223
+#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
+ LPCSTR lpszCaption; //Dialog caption bar contents
+ LPFNOLEUIHOOK lpfnHook; //Hook callback
+ LPARAM lCustData; //Custom data to pass to hook
+ HINSTANCE hInstance; //Instance for customized template name
+ LPCSTR 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
+ char 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
+ LPCSTR lpszCaption; //Dialog caption bar contents
+ LPFNOLEUIHOOK lpfnHook; //Hook callback
+ LPARAM lCustData; //Custom data to pass to hook
+ HINSTANCE hInstance; //Instance for customized template name
+ LPCSTR 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.
+ LPSTR lpszUserType; //IN: 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)
+
+ } OLEUICONVERT, *POLEUICONVERT, FAR *LPOLEUICONVERT;
+
+
+//API prototype
+STDAPI_(UINT) OleUIConvert(LPOLEUICONVERT);
+
+//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
+
+
+//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_HELP 151
+#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
+ LPCSTR lpszCaption; //Dialog caption bar contents
+ LPFNOLEUIHOOK lpfnHook; //Hook callback
+ LPARAM lCustData; //Custom data to pass to hook
+ HINSTANCE hInstance; //Instance for customized template name
+ LPCSTR 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
+
+
+/*************************************************************************
+** PROMPT USER DIALOGS
+*************************************************************************/
+#define ID_PU_LINKS 900
+#define ID_PU_TEXT 901
+#define ID_PU_CONVERT 902
+#define ID_PU_HELP 903
+#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, ...);
+STDAPI_(BOOL) OleUIUpdateLinks(
+ LPOLEUILINKCONTAINER lpOleUILinkCntr,
+ HWND hwndParent,
+ LPSTR 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
+
+
+/* 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_
+/*****************************************************************************\
+* *
+* dlgs.h - Common dialog's dialog element ID numbers *
+* *
+* Version 1.0 *
+* *
+* Copyright (c) 1992, Microsoft Corp. All rights reserved. *
+* *
+\*****************************************************************************/
+
+#ifndef _INC_DLGS
+#define _INC_DLGS
+
+#define ctlFirst 0x0400
+#define ctlLast 0x04ff
+ /* Push buttons */
+#define psh1 0x0400
+#define psh2 0x0401
+#define psh3 0x0402
+#define psh4 0x0403
+#define psh5 0x0404
+#define psh6 0x0405
+#define psh7 0x0406
+#define psh8 0x0407
+#define psh9 0x0408
+#define psh10 0x0409
+#define psh11 0x040a
+#define psh12 0x040b
+#define psh13 0x040c
+#define psh14 0x040d
+#define psh15 0x040e
+#define pshHelp psh15
+#define psh16 0x040f
+ /* Checkboxes */
+#define chx1 0x0410
+#define chx2 0x0411
+#define chx3 0x0412
+#define chx4 0x0413
+#define chx5 0x0414
+#define chx6 0x0415
+#define chx7 0x0416
+#define chx8 0x0417
+#define chx9 0x0418
+#define chx10 0x0419
+#define chx11 0x041a
+#define chx12 0x041b
+#define chx13 0x041c
+#define chx14 0x041d
+#define chx15 0x041e
+#define chx16 0x041f
+ /* Radio buttons */
+#define rad1 0x0420
+#define rad2 0x0421
+#define rad3 0x0422
+#define rad4 0x0423
+#define rad5 0x0424
+#define rad6 0x0425
+#define rad7 0x0426
+#define rad8 0x0427
+#define rad9 0x0428
+#define rad10 0x0429
+#define rad11 0x042a
+#define rad12 0x042b
+#define rad13 0x042c
+#define rad14 0x042d
+#define rad15 0x042e
+#define rad16 0x042f
+ /* Groups, frames, rectangles, and icons */
+#define grp1 0x0430
+#define grp2 0x0431
+#define grp3 0x0432
+#define grp4 0x0433
+#define frm1 0x0434
+#define frm2 0x0435
+#define frm3 0x0436
+#define frm4 0x0437
+#define rct1 0x0438
+#define rct2 0x0439
+#define rct3 0x043a
+#define rct4 0x043b
+#define ico1 0x043c
+#define ico2 0x043d
+#define ico3 0x043e
+#define ico4 0x043f
+ /* Static text */
+#define stc1 0x0440
+#define stc2 0x0441
+#define stc3 0x0442
+#define stc4 0x0443
+#define stc5 0x0444
+#define stc6 0x0445
+#define stc7 0x0446
+#define stc8 0x0447
+#define stc9 0x0448
+#define stc10 0x0449
+#define stc11 0x044a
+#define stc12 0x044b
+#define stc13 0x044c
+#define stc14 0x044d
+#define stc15 0x044e
+#define stc16 0x044f
+#define stc17 0x0450
+#define stc18 0x0451
+#define stc19 0x0452
+#define stc20 0x0453
+#define stc21 0x0454
+#define stc22 0x0455
+#define stc23 0x0456
+#define stc24 0x0457
+#define stc25 0x0458
+#define stc26 0x0459
+#define stc27 0x045a
+#define stc28 0x045b
+#define stc29 0x045c
+#define stc30 0x045d
+#define stc31 0x045e
+#define stc32 0x045f
+ /* Listboxes */
+#define lst1 0x0460
+#define lst2 0x0461
+#define lst3 0x0462
+#define lst4 0x0463
+#define lst5 0x0464
+#define lst6 0x0465
+#define lst7 0x0466
+#define lst8 0x0467
+#define lst9 0x0468
+#define lst10 0x0469
+#define lst11 0x046a
+#define lst12 0x046b
+#define lst13 0x046c
+#define lst14 0x046d
+#define lst15 0x046e
+#define lst16 0x046f
+ /* Combo boxes */
+#define cmb1 0x0470
+#define cmb2 0x0471
+#define cmb3 0x0472
+#define cmb4 0x0473
+#define cmb5 0x0474
+#define cmb6 0x0475
+#define cmb7 0x0476
+#define cmb8 0x0477
+#define cmb9 0x0478
+#define cmb10 0x0479
+#define cmb11 0x047a
+#define cmb12 0x047b
+#define cmb13 0x047c
+#define cmb14 0x047d
+#define cmb15 0x047e
+#define cmb16 0x047f
+ /* Edit controls */
+#define edt1 0x0480
+#define edt2 0x0481
+#define edt3 0x0482
+#define edt4 0x0483
+#define edt5 0x0484
+#define edt6 0x0485
+#define edt7 0x0486
+#define edt8 0x0487
+#define edt9 0x0488
+#define edt10 0x0489
+#define edt11 0x048a
+#define edt12 0x048b
+#define edt13 0x048c
+#define edt14 0x048d
+#define edt15 0x048e
+#define edt16 0x048f
+ /* Scroll bars */
+#define scr1 0x0490
+#define scr2 0x0491
+#define scr3 0x0492
+#define scr4 0x0493
+#define scr5 0x0494
+#define scr6 0x0495
+#define scr7 0x0496
+#define scr8 0x0497
+
+/* These dialog resource ordinals really start at 0x0600, but the
+ * RC Compiler can't handle hex for resource IDs, hence the decimal.
+ */
+#define FILEOPENORD 1536
+#define MULTIFILEOPENORD 1537
+#define PRINTDLGORD 1538
+#define PRNSETUPDLGORD 1539
+#define FINDDLGORD 1540
+#define REPLACEDLGORD 1541
+#define FONTDLGORD 1542
+#define FORMATDLGORD31 1543
+#define FORMATDLGORD30 1544
+
+#endif /* !_INC_DLGS */
diff --git a/private/oleutest/utests16/ole2ui/res/ole2ui.rcv b/private/oleutest/utests16/ole2ui/res/ole2ui.rcv
new file mode 100644
index 000000000..a083a822f
--- /dev/null
+++ b/private/oleutest/utests16/ole2ui/res/ole2ui.rcv
@@ -0,0 +1,90 @@
+/*
+ * OLE2UI.RCV
+ *
+ * Version resource file for the OLE 2.0 UI Support DLL.
+ *
+ * Copyright (c)1992-1993 Microsoft Corporation, All Rights Reserved.
+ *
+ * This file contains the non-localized version data, the U.S. English
+ * translation of the localized version data, and templates for the data
+ * that needs to be translated. Note that no text in this file should be
+ * translated. The text that has to be translated is in the file verlocal.h
+ * in the appropriate language subdirectory.
+ */
+
+
+#include <ver.h>
+#include "verlocal.h"
+
+//Default is nodebug
+#ifndef DEBUG
+#define VER_DEBUG 0
+#else
+#define VER_DEBUG VS_FF_DEBUG
+#endif
+
+VS_VERSION_INFO VERSIONINFO
+#ifdef PUBLISHER
+ FILEVERSION 1,0,0,0
+#else
+ FILEVERSION 2,0,0,0
+#endif
+ PRODUCTVERSION 2,0,0,0
+ FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
+ FILEFLAGS VER_DEBUG
+ FILEOS VOS_DOS_WINDOWS16
+ FILETYPE VFT_DLL
+ FILESUBTYPE VFT2_UNKNOWN
+
+ BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904E4"
+ BEGIN
+ VALUE "CompanyName", "Microsoft Corporation\0", "\0"
+#ifdef PUBLISHER
+ VALUE "FileVersion", "1.00\0", "\0"
+ VALUE "InternalName", "PUBOLEUI", "\0"
+ VALUE "OriginalFilename","PUBOLEUI.DLL", "\0"
+ VALUE "ProductName", "Microsoft Publisher for Windows 2.0", "\0"
+ VALUE "ProductVersion", "2.00\0"
+#else
+ VALUE "FileVersion", "2.00\0", "\0"
+ VALUE "InternalName", "OLE2UI", "\0"
+ VALUE "OriginalFilename","OLE2UI.DLL", "\0"
+ VALUE "ProductName", "Microsoft Windows(TM) OLE 2.0 User Interface Support", "\0"
+ VALUE "ProductVersion", "2.00\0"
+#endif
+ VALUE "FileDescription", "Microsoft Windows(TM) OLE 2.0 User Interface Support", "\0"
+ VALUE "LegalCopyright", "Copyright \251 1992-1993 Microsoft Corp. All rights reserved.", "\0"
+ END
+
+#ifdef VER_LOC
+ /* Template for the localized version data. Only used for
+ non-USA versions. */
+ BLOCK szTranslation /* Language and codepage */
+ BEGIN
+ VALUE "CompanyName", szzCompanyName
+#ifdef PUBLISHER
+ VALUE "FileVersion", "1.00\0", "\0"
+ VALUE "InternalName", "PUBOLEUI", "\0"
+ VALUE "OriginalFilename","PUBOLEUI.DLL", "\0"
+ VALUE "ProductVersion", "2.00\0"
+#else
+ VALUE "FileVersion", "2.00\0", "\0"
+ VALUE "InternalName", "OLE2UI", "\0"
+ VALUE "OriginalFilename","OLE2UI.DLL", "\0"
+ VALUE "ProductVersion", "2.00\0"
+#endif
+ VALUE "FileDescription", szzFileDescription
+ VALUE "LegalCopyright", szzLegalCopyright
+ VALUE "ProductName", szzProductName
+ END
+#endif
+ END
+
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", wLanguage, 0x04E4
+ END
+ END
diff --git a/private/oleutest/utests16/ole2ui/res/usa/bang.ico b/private/oleutest/utests16/ole2ui/res/usa/bang.ico
new file mode 100644
index 000000000..90fe0f220
--- /dev/null
+++ b/private/oleutest/utests16/ole2ui/res/usa/bang.ico
Binary files differ
diff --git a/private/oleutest/utests16/ole2ui/res/usa/busy.dlg b/private/oleutest/utests16/ole2ui/res/usa/busy.dlg
new file mode 100644
index 000000000..cb691c168
--- /dev/null
+++ b/private/oleutest/utests16/ole2ui/res/usa/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 Sans Serif"
+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/utests16/ole2ui/res/usa/convert.dlg b/private/oleutest/utests16/ole2ui/res/usa/convert.dlg
new file mode 100644
index 000000000..68ea83d3a
--- /dev/null
+++ b/private/oleutest/utests16/ole2ui/res/usa/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 Sans Serif"
+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/utests16/ole2ui/res/usa/default.ico b/private/oleutest/utests16/ole2ui/res/usa/default.ico
new file mode 100644
index 000000000..4542c57d3
--- /dev/null
+++ b/private/oleutest/utests16/ole2ui/res/usa/default.ico
Binary files differ
diff --git a/private/oleutest/utests16/ole2ui/res/usa/egares.bmp b/private/oleutest/utests16/ole2ui/res/usa/egares.bmp
new file mode 100644
index 000000000..e9dbb065a
--- /dev/null
+++ b/private/oleutest/utests16/ole2ui/res/usa/egares.bmp
Binary files differ
diff --git a/private/oleutest/utests16/ole2ui/res/usa/fileopen.dlg b/private/oleutest/utests16/ole2ui/res/usa/fileopen.dlg
new file mode 100644
index 000000000..8d0b52c1a
--- /dev/null
+++ b/private/oleutest/utests16/ole2ui/res/usa/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 Sans Serif"
+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/utests16/ole2ui/res/usa/hivgares.bmp b/private/oleutest/utests16/ole2ui/res/usa/hivgares.bmp
new file mode 100644
index 000000000..0011166da
--- /dev/null
+++ b/private/oleutest/utests16/ole2ui/res/usa/hivgares.bmp
Binary files differ
diff --git a/private/oleutest/utests16/ole2ui/res/usa/icon.dlg b/private/oleutest/utests16/ole2ui/res/usa/icon.dlg
new file mode 100644
index 000000000..9d25d1dec
--- /dev/null
+++ b/private/oleutest/utests16/ole2ui/res/usa/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 Sans Serif"
+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/utests16/ole2ui/res/usa/insobj.dlg b/private/oleutest/utests16/ole2ui/res/usa/insobj.dlg
new file mode 100644
index 000000000..1a51a5205
--- /dev/null
+++ b/private/oleutest/utests16/ole2ui/res/usa/insobj.dlg
@@ -0,0 +1,52 @@
+//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 Sans Serif"
+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/utests16/ole2ui/res/usa/links.dlg b/private/oleutest/utests16/ole2ui/res/usa/links.dlg
new file mode 100644
index 000000000..3682e4cf1
--- /dev/null
+++ b/private/oleutest/utests16/ole2ui/res/usa/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 Sans Serif"
+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, 12, 66, 14
+ PUSHBUTTON "&Update Now", ID_EL_UPDATENOW, 249, 36, 66, 14
+ PUSHBUTTON "&Open Source", ID_EL_OPENSOURCE, 249, 54, 66, 14,
+ WS_GROUP
+ PUSHBUTTON "&Change Source...", ID_EL_CHANGESOURCE, 249, 72, 66, 14,
+ WS_GROUP
+ PUSHBUTTON "&Break Link", ID_EL_CANCELLINK, 249, 96, 66, 14
+ PUSHBUTTON "&Help", ID_OLEUIHELP, 249, 138, 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/utests16/ole2ui/res/usa/pastespl.dlg b/private/oleutest/utests16/ole2ui/res/usa/pastespl.dlg
new file mode 100644
index 000000000..bea203b80
--- /dev/null
+++ b/private/oleutest/utests16/ole2ui/res/usa/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 Sans Serif"
+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/utests16/ole2ui/res/usa/prompt.dlg b/private/oleutest/utests16/ole2ui/res/usa/prompt.dlg
new file mode 100644
index 000000000..28047bc5b
--- /dev/null
+++ b/private/oleutest/utests16/ole2ui/res/usa/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 Sans Serif"
+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 Sans Serif"
+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 Sans Serif"
+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 Sans Serif"
+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 Sans Serif"
+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 Sans Serif"
+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 Sans Serif"
+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/utests16/ole2ui/res/usa/strings.rc b/private/oleutest/utests16/ole2ui/res/usa/strings.rc
new file mode 100644
index 000000000..f3f8c415a
--- /dev/null
+++ b/private/oleutest/utests16/ole2ui/res/usa/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/utests16/ole2ui/res/usa/verlocal.h b/private/oleutest/utests16/ole2ui/res/usa/verlocal.h
new file mode 100644
index 000000000..92b7000c8
--- /dev/null
+++ b/private/oleutest/utests16/ole2ui/res/usa/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/utests16/ole2ui/res/usa/vgares.bmp b/private/oleutest/utests16/ole2ui/res/usa/vgares.bmp
new file mode 100644
index 000000000..496902f9f
--- /dev/null
+++ b/private/oleutest/utests16/ole2ui/res/usa/vgares.bmp
Binary files differ
diff --git a/private/oleutest/utests16/ole2ui/strings.rc b/private/oleutest/utests16/ole2ui/strings.rc
new file mode 100644
index 000000000..f3f8c415a
--- /dev/null
+++ b/private/oleutest/utests16/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/utests16/simpdnd/app.cpp b/private/oleutest/utests16/simpdnd/app.cpp
new file mode 100644
index 000000000..174ea4b19
--- /dev/null
+++ b/private/oleutest/utests16/simpdnd/app.cpp
@@ -0,0 +1,710 @@
+//**********************************************************************
+// File name: app.cpp
+//
+// Implementation file for the CSimpleApp Class
+//
+// Functions:
+//
+// See app.h for a list of member functions.
+//
+// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+
+#include "pre.h"
+#include "iocs.h"
+#include "ias.h"
+#include "app.h"
+#include "site.h"
+#include "doc.h"
+#include <testmess.h>
+
+//**********************************************************************
+//
+// CSimpleApp::CSimpleApp()
+//
+// Purpose:
+//
+// Constructor for CSimpleApp
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// SetRectEmpty Windows API
+//
+// Comments:
+//
+//********************************************************************
+CSimpleApp::CSimpleApp()
+{
+ TestDebugOut("In CSimpleApp's Constructor \r\n");
+
+ // Set Ref Count
+ m_nCount = 0;
+
+ // clear members
+ m_hAppWnd = NULL;
+ m_hDriverWnd = NULL;
+ m_hInst = NULL;
+ m_lpDoc = NULL;
+
+ // clear flags
+ m_fInitialized = FALSE;
+}
+
+//**********************************************************************
+//
+// CSimpleApp::~CSimpleApp()
+//
+// Purpose:
+//
+// Destructor for CSimpleApp Class.
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// OleUninitialize OLE API
+//
+// Comments:
+//
+//********************************************************************
+
+CSimpleApp::~CSimpleApp()
+{
+ TestDebugOut("In CSimpleApp's Destructor\r\n");
+
+ // need to uninit the library...
+ if (m_fInitialized)
+ OleUninitialize();
+}
+
+//**********************************************************************
+//
+// CSimpleApp::DestroyDocs()
+//
+// Purpose:
+//
+// Destroys all of the open documents in the application (Only one
+// since this is an SDI app, but could easily be modified to
+// support MDI).
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// Comments:
+//
+//********************************************************************
+
+void CSimpleApp::DestroyDocs()
+{
+ m_lpDoc->Close(); // we have only 1 document
+}
+
+//**********************************************************************
+//
+// CSimpleApp::QueryInterface
+//
+// Purpose:
+//
+// Used for interface negotiation at the Frame level.
+//
+// Parameters:
+//
+// REFIID riid - A reference to the interface that is
+// being queried.
+//
+// LPVOID FAR* ppvObj - An out parameter to return a pointer to
+// the interface.
+//
+// Return Value:
+//
+// S_OK - The interface is supported.
+// S_FALSE - The interface is not supported
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// ResultFromScode OLE API
+//
+// Comments:
+//
+//********************************************************************
+
+STDMETHODIMP CSimpleApp::QueryInterface(REFIID riid, LPVOID FAR* ppvObj)
+{
+ TestDebugOut("In CSimpleApp::QueryInterface\r\n");
+
+ *ppvObj = NULL; // must set out pointer parameters to NULL
+
+ // Not a supported interface
+ return ResultFromScode(E_NOINTERFACE);
+}
+
+//**********************************************************************
+//
+// CSimpleApp::AddRef
+//
+// Purpose:
+//
+// Adds to the reference count at the Application level.
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// ULONG - The new reference count of the application.
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+// Comments:
+//
+// Due to the reference counting model that is used in this
+// implementation, this reference count is the sum of the
+// reference counts on all interfaces of all objects open
+// in the application.
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) CSimpleApp::AddRef()
+{
+ TestDebugOut("In CSimpleApp::AddRef\r\n");
+ return ++m_nCount;
+}
+
+//**********************************************************************
+//
+// CSimpleApp::Release
+//
+// Purpose:
+//
+// Decrements the reference count at this level
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// ULONG - The new reference count of the application.
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+// Comments:
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) CSimpleApp::Release()
+{
+ TestDebugOut("In CSimpleApp::Release\r\n");
+
+ if (--m_nCount == 0) {
+ delete this;
+ return 0;
+ }
+ return m_nCount;
+}
+
+//**********************************************************************
+//
+// CSimpleApp::fInitApplication
+//
+// Purpose:
+//
+// Initializes the application
+//
+// Parameters:
+//
+// HANDLE hInstance - Instance handle of the application.
+//
+// Return Value:
+//
+// TRUE - Application was successfully initialized.
+// FALSE - Application could not be initialized
+//
+// Function Calls:
+// Function Location
+//
+// LoadIcon Windows API
+// LoadCursor Windows API
+// GetStockObject Windows API
+// RegisterClass Windows API
+//
+// Comments:
+//
+//********************************************************************
+
+BOOL CSimpleApp::fInitApplication(HANDLE hInstance)
+{
+ WNDCLASS wc;
+
+ // Fill in window class structure with parameters that describe the
+ // main window.
+
+ wc.style = NULL; // Class style(s).
+ wc.lpfnWndProc = MainWndProc; // Function to retrieve messages for
+ // windows of this class.
+ wc.cbClsExtra = 0; // No per-class extra data.
+ wc.cbWndExtra = 0; // No per-window extra data.
+ wc.hInstance = hInstance; // Application that owns the class.
+ wc.hIcon = LoadIcon(hInstance,"SimpDnd");
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wc.hbrBackground = GetStockObject(WHITE_BRUSH);
+ wc.lpszMenuName = "SIMPLEMENU"; // Name of menu resource in .RC file.
+ wc.lpszClassName = "SimpDndAppWClass"; // Name used in CreateWindow call.
+
+ if (!RegisterClass(&wc))
+ return FALSE;
+
+ wc.style = CS_DBLCLKS; // Class style(s). allow DBLCLK's
+ wc.lpfnWndProc = DocWndProc; // Function to retrieve messages for
+ // windows of this class.
+ wc.cbClsExtra = 0; // No per-class extra data.
+ wc.cbWndExtra = 0; // No per-window extra data.
+ wc.hInstance = hInstance; // Application that owns the class.
+ wc.hIcon = NULL;
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wc.hbrBackground = GetStockObject(WHITE_BRUSH);
+ wc.lpszMenuName = NULL;
+ wc.lpszClassName = "SimpDndDocWClass"; // Name used in CreateWindow call.
+
+ // Register the window class and return success/failure code.
+
+ return (RegisterClass(&wc));
+}
+
+//**********************************************************************
+//
+// CSimpleApp::fInitInstance
+//
+// Purpose:
+//
+// Instance initialization.
+//
+// Parameters:
+//
+// HANDLE hInstance - App. Instance Handle.
+//
+// int nCmdShow - Show parameter from WinMain
+//
+// Return Value:
+//
+// TRUE - Initialization Successful
+// FALSE - Initialization Failed.
+//
+//
+// Function Calls:
+// Function Location
+//
+// CreateWindow Windows API
+// ShowWindow Windows API
+// UpdateWindow Windows API
+// OleBuildVersion OLE API
+// OleInitialize OLE API
+//
+// Comments:
+//
+// Note that successful Initalization of the OLE libraries
+// is remembered so the UnInit is only called if needed.
+//
+//********************************************************************
+
+BOOL CSimpleApp::fInitInstance (HANDLE hInstance, int nCmdShow)
+{
+ DWORD dwVer = OleBuildVersion();
+ LPMALLOC lpMalloc = NULL;
+
+#ifdef NO
+ // check to see if we are compatible with this version of the libraries
+ if (HIWORD(dwVer) != rmm || LOWORD(dwVer) < rup) {
+#ifdef _DEBUG
+ TestDebugOut("WARNING: Incompatible OLE library version\r\n");
+#else
+ return FALSE;
+#endif
+ }
+
+#endif
+
+#if defined( _DEBUG )
+ /* OLE2NOTE: Use a special debug allocator to help track down
+ ** memory leaks.
+ */
+ OleStdCreateDbAlloc(0, &lpMalloc);
+#endif
+
+ if (OleInitialize(lpMalloc) == NOERROR)
+ m_fInitialized = TRUE;
+
+#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->Release();
+#endif
+
+ m_hInst = hInstance;
+
+ // Create the "application" windows
+ m_hAppWnd = CreateWindow ("SimpDndAppWClass",
+ "Simple OLE 2.0 Drag/Drop Container",
+ WS_OVERLAPPEDWINDOW,
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ NULL,
+ NULL,
+ hInstance,
+ NULL);
+
+ if (!m_hAppWnd)
+ return FALSE;
+
+ // if we have been launched by the test driver, tell it our window handle
+
+ if( m_hDriverWnd )
+ {
+ PostMessage(m_hDriverWnd, WM_TESTREG, (WPARAM)m_hAppWnd, 0);
+ }
+
+ // delay before dragging should start, in milliseconds
+ m_nDragDelay = GetProfileInt(
+ "windows",
+ "DragDelay",
+ DD_DEFDRAGDELAY
+ );
+
+ // minimum distance (radius) before drag should start, in pixels
+ m_nDragMinDist = GetProfileInt(
+ "windows",
+ "DragMinDist",
+ DD_DEFDRAGMINDIST
+ );
+
+ // delay before scrolling, in milliseconds
+ m_nScrollDelay = GetProfileInt(
+ "windows",
+ "DragScrollDelay",
+ DD_DEFSCROLLDELAY
+ );
+
+ // inset-width of the hot zone, in pixels
+ m_nScrollInset = GetProfileInt(
+ "windows",
+ "DragScrollInset",
+ DD_DEFSCROLLINSET
+ );
+
+ // scroll interval, in milliseconds
+ m_nScrollInterval = GetProfileInt(
+ "windows",
+ "DragScrollInterval",
+ DD_DEFSCROLLINTERVAL
+ );
+
+ ShowWindow (m_hAppWnd, nCmdShow);
+ UpdateWindow (m_hAppWnd);
+
+ return m_fInitialized;
+}
+
+//**********************************************************************
+//
+// CSimpleApp::lCommandHandler
+//
+// Purpose:
+//
+// Handles the processing of WM_COMMAND.
+//
+// Parameters:
+//
+// HWND hWnd - Handle to the application Window
+//
+// UINT message - message (always WM_COMMAND)
+//
+// WPARAM wParam - Same as passed to the WndProc
+//
+// LPARAM lParam - Same as passed to the WndProc
+//
+// Return Value:
+//
+// NULL
+//
+// Function Calls:
+// Function Location
+//
+// IOleObject::DoVerb Object
+// GetClientRect Windows API
+// MessageBox Windows API
+// DialogBox Windows API
+// MakeProcInstance Windows API
+// FreeProcInstance Windows API
+// SendMessage Windows API
+// DefWindowProc Windows API
+// CSimpleDoc::InsertObject DOC.CPP
+//
+// Comments:
+//
+//********************************************************************
+
+long CSimpleApp::lCommandHandler (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ RECT rect;
+
+ // see if the command is a verb selections
+ if (wParam >= IDM_VERB0)
+ {
+ // get the rectangle of the object
+ m_lpDoc->m_lpSite->GetObjRect(&rect);
+
+ m_lpDoc->m_lpSite->m_lpOleObject->DoVerb(
+ wParam - IDM_VERB0, NULL,
+ &m_lpDoc->m_lpSite->m_OleClientSite, -1,
+ m_lpDoc->m_hDocWnd, &rect);
+ }
+ else
+ {
+ switch (wParam) {
+ // bring up the About box
+ case IDM_ABOUT:
+ {
+ FARPROC lpProcAbout = MakeProcInstance((FARPROC)About, m_hInst);
+
+ DialogBox(m_hInst, // current instance
+ "AboutBox", // resource to use
+ m_hAppWnd, // parent handle
+ lpProcAbout); // About() instance address
+
+ FreeProcInstance(lpProcAbout);
+ break;
+ }
+
+ // bring up the InsertObject Dialog
+ case IDM_INSERTOBJECT:
+ m_lpDoc->InsertObject();
+ break;
+
+ // Copy the object to the Clipboard
+ case IDM_COPY:
+ m_lpDoc->CopyObjectToClip();
+ break;
+
+ // exit the application
+ case IDM_EXIT:
+ SendMessage(hWnd, WM_SYSCOMMAND, SC_CLOSE, 0L);
+ break;
+
+ case IDM_NEW:
+ m_lpDoc->Close();
+ m_lpDoc = NULL;
+ lCreateDoc(hWnd, 0, 0, 0);
+ break;
+
+ default:
+ return (DefWindowProc(hWnd, message, wParam, lParam));
+ } // end of switch
+ } // end of else
+ return NULL;
+}
+
+//**********************************************************************
+//
+// CSimpleApp::lSizeHandler
+//
+// Purpose:
+//
+// Handles the WM_SIZE message
+//
+// Parameters:
+//
+// HWND hWnd - Handle to the application Window
+//
+// UINT message - message (always WM_SIZE)
+//
+// WPARAM wParam - Same as passed to the WndProc
+//
+// LPARAM lParam - Same as passed to the WndProc
+//
+// Return Value:
+//
+// LONG - returned from the "document" resizing
+//
+// Function Calls:
+// Function Location
+//
+// GetClientRect Windows API
+// CSimpleDoc::lResizeDoc DOC.CPP
+//
+// Comments:
+//
+//********************************************************************
+
+long CSimpleApp::lSizeHandler (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ RECT rect;
+
+ GetClientRect(m_hAppWnd, &rect);
+ return m_lpDoc->lResizeDoc(&rect);
+}
+
+//**********************************************************************
+//
+// CSimpleApp::lCreateDoc
+//
+// Purpose:
+//
+// Handles the creation of a document.
+//
+// Parameters:
+//
+// HWND hWnd - Handle to the application Window
+//
+// UINT message - message (always WM_CREATE)
+//
+// WPARAM wParam - Same as passed to the WndProc
+//
+// LPARAM lParam - Same as passed to the WndProc
+//
+// Return Value:
+//
+// NULL
+//
+// Function Calls:
+// Function Location
+//
+// GetClientRect Windows API
+// CSimpleDoc::CSimpleDoc DOC.CPP
+//
+// Comments:
+//
+//********************************************************************
+
+long CSimpleApp::lCreateDoc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ RECT rect;
+
+ GetClientRect(hWnd, &rect);
+
+ m_lpDoc = CSimpleDoc::Create(this, &rect, hWnd);
+
+ return NULL;
+}
+
+//**********************************************************************
+//
+// CSimpleApp::HandleAccelerators
+//
+// Purpose:
+//
+// To properly handle accelerators in the Message Loop
+//
+// Parameters:
+//
+// LPMSG lpMsg - A pointer to the message structure.
+//
+// Return Value:
+//
+// TRUE - The accelerator was handled
+// FALSE - The accelerator was not handled
+//
+// Function Calls:
+// Function Location
+//
+// Comments:
+//
+//********************************************************************
+
+BOOL CSimpleApp::HandleAccelerators(LPMSG lpMsg)
+{
+ BOOL retval = FALSE;
+
+ // we do not have any accelerators
+
+ return retval;
+}
+
+//**********************************************************************
+//
+// CSimpleApp::PaintApp
+//
+// Purpose:
+//
+// Handles the painting of the doc window.
+//
+//
+// Parameters:
+//
+// HDC hDC - hDC to the Doc Window.
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// CSimpleDoc::PaintDoc DOC.CPP
+//
+// Comments:
+//
+// This is an app level function in case we want to do palette
+// management.
+//
+//********************************************************************
+
+void CSimpleApp::PaintApp (HDC hDC)
+{
+ // at this level, we could enumerate through all of the
+ // visible objects in the application, so that a palette
+ // that best fits all of the objects can be built.
+
+ // This app is designed to take on the same palette
+ // functionality that was provided in OLE 1.0, the palette
+ // of the last object drawn is realized. Since we only
+ // support one object at a time, it shouldn't be a big
+ // deal.
+
+ // if we supported multiple documents, we would enumerate
+ // through each of the open documents and call paint.
+
+ if (m_lpDoc)
+ m_lpDoc->PaintDoc(hDC);
+
+}
diff --git a/private/oleutest/utests16/simpdnd/app.h b/private/oleutest/utests16/simpdnd/app.h
new file mode 100644
index 000000000..0205e06ef
--- /dev/null
+++ b/private/oleutest/utests16/simpdnd/app.h
@@ -0,0 +1,63 @@
+//**********************************************************************
+// File name: app.h
+//
+// Definition of CSimpleApp
+//
+// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+
+#if !defined( _APP_H_)
+#define _APP_H_
+
+#include <ole2.h>
+
+class CSimpleDoc;
+
+class CSimpleApp : public IUnknown
+{
+public:
+
+ int m_nCount; // reference count
+ HWND m_hAppWnd; // main window handle
+ HWND m_hDriverWnd; // window handle for the driver app.
+ HINSTANCE m_hInst; // application instance
+ CSimpleDoc FAR * m_lpDoc; // pointer to document object
+ BOOL m_fInitialized; // OLE initialization flag
+ HMENU m_hMainMenu;
+ HMENU m_hFileMenu;
+ HMENU m_hEditMenu;
+ HMENU m_hHelpMenu;
+ HMENU m_hCascadeMenu; // OLE object's verb
+
+
+ // Drag/Drop related fields
+ 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)
+
+ CSimpleApp(); // Constructor
+ ~CSimpleApp(); // Destructor
+
+ // IUnknown Interfaces
+ STDMETHODIMP QueryInterface(REFIID riid, LPVOID FAR* ppvObj);
+ STDMETHODIMP_(ULONG) AddRef();
+ STDMETHODIMP_(ULONG) Release();
+
+ // Initialization methods
+
+ BOOL fInitApplication (HANDLE hInstance);
+ BOOL fInitInstance (HANDLE hInstance, int nCmdShow);
+
+ // Message handling methods
+
+ long lCommandHandler (HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam);
+ long lSizeHandler (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
+ long lCreateDoc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
+ BOOL HandleAccelerators (LPMSG lpMsg);
+ void PaintApp(HDC hDC);
+ void DestroyDocs();
+};
+
+#endif // _APP_H_
diff --git a/private/oleutest/utests16/simpdnd/doc.cpp b/private/oleutest/utests16/simpdnd/doc.cpp
new file mode 100644
index 000000000..722280d55
--- /dev/null
+++ b/private/oleutest/utests16/simpdnd/doc.cpp
@@ -0,0 +1,722 @@
+//**********************************************************************
+// File name: DOC.CPP
+//
+// Implementation file for CSimpleDoc.
+//
+// Functions:
+//
+// See DOC.H for Class Definition
+//
+// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+
+#include "pre.h"
+#include "iocs.h"
+#include "ias.h"
+#include "app.h"
+#include "site.h"
+#include "doc.h"
+#include "idt.h"
+#include "dxferobj.h"
+
+//**********************************************************************
+//
+// CSimpleDoc::Create
+//
+// Purpose:
+//
+// Creation for the CSimpleDoc Class
+//
+// Parameters:
+//
+// CSimpleApp FAR * lpApp - Pointer to the CSimpleApp Class
+//
+// LPRECT lpRect - Client area rect of "frame" window
+//
+// HWND hWnd - Window Handle of "frame" window
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// StgCreateDocfile OLE API
+// RegisterDragDrop OLE API
+// CoLockObjectExternal OLE API
+// CreateWindow Windows API
+// ShowWindow Windows API
+// UpdateWindow Windows API
+//
+// Comments:
+//
+// This routine was added so that failure could be returned
+// from object creation.
+//
+//********************************************************************
+
+CSimpleDoc FAR * CSimpleDoc::Create(CSimpleApp FAR *lpApp, LPRECT lpRect,HWND hWnd)
+{
+ CSimpleDoc FAR * lpTemp = new CSimpleDoc(lpApp, hWnd);
+
+ if (!lpTemp)
+ return NULL;
+
+ // create storage for the doc.
+ HRESULT hErr = StgCreateDocfile (
+ NULL, // generate temp name
+ STGM_READWRITE | STGM_TRANSACTED | STGM_SHARE_EXCLUSIVE,
+ 0, &lpTemp->m_lpStorage);
+
+ if (hErr != NOERROR)
+ goto error;
+
+ // create the document Window
+ lpTemp->m_hDocWnd = CreateWindow(
+ "SimpDndDocWClass",
+ NULL,
+ WS_CHILD | WS_CLIPCHILDREN,
+ lpRect->left,
+ lpRect->top,
+ lpRect->right,
+ lpRect->bottom,
+ hWnd,
+ NULL,
+ lpApp->m_hInst,
+ NULL);
+
+ if (!lpTemp->m_hDocWnd)
+ goto error;
+
+ ShowWindow(lpTemp->m_hDocWnd, SW_SHOWNORMAL); // Show the window
+ UpdateWindow(lpTemp->m_hDocWnd); // Sends WM_PAINT message
+
+ // Ensable InsertObject menu choice
+ EnableMenuItem( lpApp->m_hEditMenu, 1, MF_BYPOSITION | MF_ENABLED);
+ // Disable Copy menu choice
+ EnableMenuItem( lpApp->m_hEditMenu, 0, MF_BYPOSITION | MF_DISABLED | MF_GRAYED);
+
+ // It is *REQUIRED* to hold a strong LOCK on the object that is
+ // registered as drop target. this call will result in at least one
+ // ref count held on our document. later in CSimpleDoc::Close we will
+ // unlock this lock which will make our document's ref count go to 0.
+ // when the document's ref count goes to 0, it will be deleted.
+ CoLockObjectExternal (&lpTemp->m_DropTarget, TRUE, 0);
+
+ // Register our window as a DropTarget
+ RegisterDragDrop(lpTemp->m_hDocWnd, &lpTemp->m_DropTarget);
+ lpTemp->m_fRegDragDrop = TRUE;
+
+ return (lpTemp);
+
+error:
+ delete (lpTemp);
+ return NULL;
+
+}
+
+//**********************************************************************
+//
+// CSimpleDoc::Close
+//
+// Purpose:
+//
+// Close CSimpleDoc object.
+// when the document's reference count goes to 0, the document
+// will be destroyed.
+//
+// Parameters:
+//
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// RevokeDragDrop OLE API
+// CoLockObjectExternal OLE API
+// OleFlushClipboard OLE API
+// ShowWindow Windows API
+//
+// Comments:
+//
+//********************************************************************
+
+void CSimpleDoc::Close(void)
+{
+ TestDebugOut("In CSimpleDoc::Close\r\n");
+
+ ShowWindow(m_hDocWnd, SW_HIDE); // Hide the window
+
+ // Remove our data transfer object from clipboard if it is there.
+ // this will leave HGLOBAL based data behind on the clipboard
+ // including OLE 1.0 compatibility formats.
+ OleFlushClipboard();
+
+ // Revoke our window as a DropTarget
+ if (m_fRegDragDrop) {
+ RevokeDragDrop(m_hDocWnd);
+ m_fRegDragDrop = FALSE;
+ }
+
+ // Close the OLE object in our document
+ if (m_lpSite)
+ m_lpSite->CloseOleObject();
+
+ // Unlock the lock added in CSimpleDoc::Create. this will make
+ // the document's ref count go to 0, and the document will be deleted.
+ CoLockObjectExternal (&m_DropTarget, FALSE, TRUE);
+}
+
+//**********************************************************************
+//
+// CSimpleDoc::CSimpleDoc
+//
+// Purpose:
+//
+// Constructor for the CSimpleDoc Class
+//
+// Parameters:
+//
+// CSimpleApp FAR * lpApp - Pointer to the CSimpleApp Class
+//
+// HWND hWnd - Window Handle of "frame" window
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// GetMenu Windows API
+// GetSubMenu Windows API
+//
+// Comments:
+//
+//********************************************************************
+#pragma warning(disable : 4355) // turn off this warning. This warning
+ // tells us that we are passing this in
+ // an initializer, before "this" is through
+ // initializing. This is ok, because
+ // we just store the ptr in the other
+ // constructor
+
+CSimpleDoc::CSimpleDoc(CSimpleApp FAR * lpApp,HWND hWnd)
+ : m_DropTarget(this), m_DropSource(this)
+#pragma warning (default : 4355) // Turn the warning back on
+{
+ TestDebugOut("In CSimpleDoc's Constructor\r\n");
+ m_lpApp = lpApp;
+ m_lpSite = NULL;
+ m_nCount = 0;
+ // set up menu handles
+ lpApp->m_hMainMenu = GetMenu(hWnd);
+ lpApp->m_hFileMenu = GetSubMenu(lpApp->m_hMainMenu, 0);
+ lpApp->m_hEditMenu = GetSubMenu(lpApp->m_hMainMenu, 1);
+ lpApp->m_hHelpMenu = GetSubMenu(lpApp->m_hMainMenu, 2);
+ lpApp->m_hCascadeMenu = NULL;
+ m_fModifiedMenu = FALSE;
+
+ // drag/drop related stuff
+ m_fRegDragDrop = FALSE; // is doc registered as drop target?
+ m_fLocalDrag = FALSE; // is doc source of the drag
+ m_fLocalDrop = FALSE; // was doc target of the drop
+ m_fCanDropCopy = FALSE; // is Drag/Drop copy/move possible?
+ m_fCanDropLink = FALSE; // is Drag/Drop link possible?
+ m_fDragLeave = FALSE; // has drag left
+ m_fPendingDrag = FALSE; // LButtonDown--possible drag pending
+ m_ptButDown.x = m_ptButDown.y = 0; // LButtonDown coordinates
+}
+
+//**********************************************************************
+//
+// CSimpleDoc::~CSimpleDoc
+//
+// Purpose:
+//
+// Destructor for CSimpleDoc
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// CSimpleSite::Release SITE.CPP
+// IStorage::Release OLE API
+//
+// Comments:
+//
+//********************************************************************
+
+CSimpleDoc::~CSimpleDoc()
+{
+ TestDebugOut("In CSimpleDoc's Destructor\r\n");
+
+ // Release all pointers we hold to the OLE object. also release
+ // the ref count added in CSimpleSite::Create. this will make
+ // the Site's ref count go to 0, and the Site will be deleted.
+ if (m_lpSite) {
+ m_lpSite->UnloadOleObject();
+ m_lpSite->Release();
+ m_lpSite = NULL;
+ }
+
+ // Release the Storage
+ if (m_lpStorage) {
+ m_lpStorage->Release();
+ m_lpStorage = NULL;
+ }
+
+ // if the edit menu was modified, remove the menu item and
+ // destroy the popup if it exists
+ if (m_fModifiedMenu)
+ {
+ int nCount = GetMenuItemCount(m_lpApp->m_hEditMenu);
+ RemoveMenu(m_lpApp->m_hEditMenu, nCount-1, MF_BYPOSITION);
+ if (m_lpApp->m_hCascadeMenu)
+ DestroyMenu(m_lpApp->m_hCascadeMenu);
+ }
+
+ DestroyWindow(m_hDocWnd);
+}
+
+
+//**********************************************************************
+//
+// CSimpleDoc::QueryInterface
+//
+// Purpose:
+//
+// Return a pointer to a requested interface
+//
+// Parameters:
+//
+// REFIID riid - ID of interface to be returned
+// LPVOID FAR* ppvObj - Location to return the interface
+//
+// Return Value:
+//
+// S_OK - Interface supported
+// E_NOINTERFACE - Interface NOT supported
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// ResultFromScode OLE API
+//
+// Comments:
+//
+//********************************************************************
+
+STDMETHODIMP CSimpleDoc::QueryInterface(REFIID riid, LPVOID FAR* ppvObj)
+{
+ TestDebugOut("In CSimpleDoc::QueryInterface\r\n");
+
+ *ppvObj = NULL; // must set out pointer parameters to NULL
+
+ // looking for IUnknown
+ if ( riid == IID_IUnknown)
+ {
+ AddRef();
+ *ppvObj = this;
+ return ResultFromScode(S_OK);
+ }
+
+ // looking for IDropTarget
+ if ( riid == IID_IDropTarget)
+ {
+ m_DropTarget.AddRef();
+ *ppvObj=&m_DropTarget;
+ return ResultFromScode(S_OK);
+ }
+
+ // looking for IDropSource
+ if ( riid == IID_IDropSource)
+ {
+ m_DropSource.AddRef();
+ *ppvObj=&m_DropSource;
+ return ResultFromScode(S_OK);
+ }
+
+ // Not a supported interface
+ return ResultFromScode(E_NOINTERFACE);
+}
+
+//**********************************************************************
+//
+// CSimpleDoc::AddRef
+//
+// Purpose:
+//
+// Increments the document reference count
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// UINT - The current reference count on the document
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// CSimpleApp::AddRef APP.CPP
+//
+// Comments:
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) CSimpleDoc::AddRef()
+{
+ TestDebugOut("In CSimpleDoc::AddRef\r\n");
+ return ++m_nCount;
+}
+
+//**********************************************************************
+//
+// CSimpleDoc::Release
+//
+// Purpose:
+//
+// Decrements the document reference count
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// UINT - The current reference count on the document
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+// Comments:
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) CSimpleDoc::Release()
+{
+ TestDebugOut("In CSimpleDoc::Release\r\n");
+
+ if (--m_nCount == 0) {
+ delete this;
+ return 0;
+ }
+ return m_nCount;
+}
+
+//**********************************************************************
+//
+// CSimpleDoc::InsertObject
+//
+// Purpose:
+//
+// Inserts a new object to this document
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// CSimpleSite::CSimpleSite SITE.CPP
+// CSimpleSite::InitObject SITE.CPP
+// memset C Runtime
+// OleUIInsertObject OUTLUI function
+// CSimpleDoc::DisableInsertObject DOC.CPP
+//
+// Comments:
+//
+// This implementation only allows one object to be inserted
+// into a document. Once the object has been inserted, then
+// the Insert Object menu choice is greyed out, to prevent
+// the user from inserting another.
+//
+//********************************************************************
+
+void CSimpleDoc::InsertObject()
+{
+ OLEUIINSERTOBJECT io;
+ UINT iret;
+ char szFile[OLEUI_CCHPATHMAX];
+
+ m_lpSite = CSimpleSite::Create(this);
+
+ // clear the structure
+ _fmemset(&io, 0, sizeof(OLEUIINSERTOBJECT));
+
+ // fill the structure
+ io.cbStruct = sizeof(OLEUIINSERTOBJECT);
+ io.dwFlags = IOF_SELECTCREATENEW |
+ IOF_DISABLELINK | IOF_DISABLEDISPLAYASICON |
+ IOF_CREATENEWOBJECT | IOF_CREATEFILEOBJECT;
+ io.hWndOwner = m_hDocWnd;
+ io.lpszCaption = (LPSTR)"Insert Object";
+ io.iid = IID_IOleObject;
+ io.oleRender = OLERENDER_DRAW;
+ io.lpIOleClientSite = &m_lpSite->m_OleClientSite;
+ io.lpIStorage = m_lpSite->m_lpObjStorage;
+ io.ppvObj = (LPVOID FAR *)&m_lpSite->m_lpOleObject;
+ io.lpszFile = szFile;
+ io.cchFile = sizeof(szFile);
+ _fmemset((LPSTR)szFile, 0, sizeof(szFile));
+
+ // call OUTLUI to do all the hard work
+ iret = OleUIInsertObject(&io);
+
+ if (iret == OLEUI_OK)
+ {
+ m_lpSite->InitObject((BOOL)(io.dwFlags & IOF_SELECTCREATENEW));
+ // disable Insert Object menu item
+ DisableInsertObject();
+ }
+ else
+ {
+ m_lpSite->Release();
+ m_lpSite = NULL;
+ m_lpStorage->Revert();
+ }
+
+}
+
+//**********************************************************************
+//
+// CSimpleDoc::lResizeDoc
+//
+// Purpose:
+//
+// Resizes the document
+//
+// Parameters:
+//
+// LPRECT lpRect - The size of the client are of the "frame"
+// Window.
+//
+// Return Value:
+//
+// NULL
+//
+// Function Calls:
+// Function Location
+//
+// MoveWindow Windows API
+//
+// Comments:
+//
+//********************************************************************
+
+long CSimpleDoc::lResizeDoc(LPRECT lpRect)
+{
+ MoveWindow(
+ m_hDocWnd,
+ lpRect->left, lpRect->top,
+ lpRect->right, lpRect->bottom, TRUE);
+
+ return NULL;
+}
+
+//**********************************************************************
+//
+// CSimpleDoc::lAddVerbs
+//
+// Purpose:
+//
+// Adds the objects verbs to the edit menu.
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// NULL
+//
+// Function Calls:
+// Function Location
+//
+// GetMenuItemCount Windows API
+// OleUIAddVerbMenu OUTLUI function
+//
+// Comments:
+//
+//********************************************************************
+
+long CSimpleDoc::lAddVerbs(void)
+{
+ // m_fModifiedMenu is TRUE if the menu has already been modified
+ // once. Since we only support one obect every time the application
+ // is run, then once the menu is modified, it doesn't have
+ // to be done again.
+ if (m_lpSite && !m_fModifiedMenu)
+ {
+ int nCount = GetMenuItemCount(m_lpApp->m_hEditMenu);
+
+ OleUIAddVerbMenu ( m_lpSite->m_lpOleObject,
+ NULL,
+ m_lpApp->m_hEditMenu,
+ nCount + 1,
+ IDM_VERB0,
+ 0, // no maximum verb IDM enforced
+ FALSE,
+ 1,
+ &m_lpApp->m_hCascadeMenu);
+
+ m_fModifiedMenu = TRUE;
+ }
+ return (NULL);
+}
+
+//**********************************************************************
+//
+// CSimpleDoc::PaintDoc
+//
+// Purpose:
+//
+// Paints the Document
+//
+// Parameters:
+//
+// HDC hDC - hDC of the document Window
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// CSimpleSite::PaintObj SITE.CPP
+//
+// Comments:
+//
+//********************************************************************
+
+void CSimpleDoc::PaintDoc (HDC hDC)
+{
+ // if we supported multiple objects, then we would enumerate
+ // the objects and call paint on each of them from here.
+
+ if (m_lpSite)
+ m_lpSite->PaintObj(hDC);
+
+}
+
+//**********************************************************************
+//
+// CSimpleDoc::DisableInsertObject
+//
+// Purpose:
+//
+// Disable the ability to insert a new object in this document.
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// RevokeDragDrop OLE API
+// EnableMenuItem Windows API
+//
+// Comments:
+//
+// This implementation only allows one object to be inserted
+// into a document. Once the object has been inserted, then
+// the Insert Object menu choice is greyed out, to prevent
+// the user from inserting another. Also we revoke ourself as
+// a potential drop target.
+//
+//********************************************************************
+
+void CSimpleDoc::DisableInsertObject(void)
+{
+ // Disable InsertObject menu choice
+ EnableMenuItem( m_lpApp->m_hEditMenu, 1, MF_BYPOSITION | MF_DISABLED | MF_GRAYED);
+ // Enable Copy menu choice
+ EnableMenuItem( m_lpApp->m_hEditMenu, 0, MF_BYPOSITION | MF_ENABLED);
+
+ // We no longer accept dropping of objects
+ if (m_fRegDragDrop) {
+ RevokeDragDrop(m_hDocWnd);
+ m_fRegDragDrop = FALSE;
+ }
+}
+
+//**********************************************************************
+//
+// CSimpleDoc::CopyObjectToClip
+//
+// Purpose:
+//
+// Copy the embedded OLE object to the clipboard
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// CDataXferObj::Create DXFEROBJ.CPP
+// CDataXferObj::QueryInterface DXFEROBJ.CPP
+// OleSetClipboard OLE API
+//
+// Comments:
+//
+// This implementation only allows one object to be inserted
+// into a document. Once the object has been inserted, then
+// the Copy menu choice is enabled.
+//
+//********************************************************************
+
+void CSimpleDoc::CopyObjectToClip(void)
+{
+ LPDATAOBJECT lpDataObj;
+
+ // Create a data transfer object by cloning the existing OLE object
+ CDataXferObj FAR* pDataXferObj = CDataXferObj::Create(m_lpSite,NULL);
+ if (! pDataXferObj) {
+ MessageBox(NULL,"Out-of-memory","SimpDnD",MB_SYSTEMMODAL|MB_ICONHAND);
+ return;
+ }
+ // initially obj is created with 0 refcnt. this QI will make it go to 1.
+ pDataXferObj->QueryInterface(IID_IDataObject, (LPVOID FAR*)&lpDataObj);
+
+ // put out data transfer object on the clipboard. this API will AddRef.
+ OleSetClipboard(lpDataObj);
+
+ // Give ownership of data transfer object to clipboard
+ pDataXferObj->Release();
+}
diff --git a/private/oleutest/utests16/simpdnd/doc.h b/private/oleutest/utests16/simpdnd/doc.h
new file mode 100644
index 000000000..f1703d582
--- /dev/null
+++ b/private/oleutest/utests16/simpdnd/doc.h
@@ -0,0 +1,70 @@
+//**********************************************************************
+// File name: doc.h
+//
+// Definition of CSimpleDoc
+//
+// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+
+#if !defined( _DOC_H_ )
+#define _DOC_H_
+
+#include "idt.h"
+#include "ids.h"
+
+class CSimpleSite;
+class CSimpleApp;
+
+class CSimpleDoc : public IUnknown
+{
+public:
+ int m_nCount; // reference count
+ LPSTORAGE m_lpStorage; // IStorage* pointer for Doc
+ BOOL m_fModifiedMenu; // is object's verb menu on menu
+
+ // Drag/Drop related fields
+ 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
+
+ CSimpleSite FAR * m_lpSite;
+ CSimpleApp FAR * m_lpApp;
+
+ HWND m_hDocWnd;
+
+ CDropTarget m_DropTarget;
+ CDropSource m_DropSource;
+
+ static CSimpleDoc FAR* Create(CSimpleApp FAR *lpApp, LPRECT lpRect,
+ HWND hWnd);
+
+ void Close(void);
+
+ CSimpleDoc();
+ CSimpleDoc(CSimpleApp FAR *lpApp, HWND hWnd);
+ ~CSimpleDoc();
+
+ // IUnknown Interface
+ STDMETHODIMP QueryInterface(REFIID riid, LPVOID FAR* ppvObj);
+ STDMETHODIMP_(ULONG) AddRef();
+ STDMETHODIMP_(ULONG) Release();
+
+ void InsertObject(void);
+ void DisableInsertObject(void);
+ long lResizeDoc(LPRECT lpRect);
+ long lAddVerbs(void);
+ void PaintDoc(HDC hDC);
+
+ // Drag/Drop and clipboard support methods
+ void CopyObjectToClip(void);
+ BOOL QueryDrag(POINT pt);
+ DWORD DoDragDrop(void);
+ void Scroll(DWORD dwScrollDir) { /*...scroll Doc here...*/ }
+};
+
+#endif // _DOC_H_
diff --git a/private/oleutest/utests16/simpdnd/dxferobj.cpp b/private/oleutest/utests16/simpdnd/dxferobj.cpp
new file mode 100644
index 000000000..91f2a5fe4
--- /dev/null
+++ b/private/oleutest/utests16/simpdnd/dxferobj.cpp
@@ -0,0 +1,574 @@
+//**********************************************************************
+// File name: DXFEROBJ.CPP
+//
+// Implementation file for CDataXferObj, data transfer object
+// implementation of IDataObject interface.
+//
+// Functions:
+//
+// See DXFEROBJ.H for class definition
+//
+// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+
+#include "pre.h"
+#include "enumfetc.h"
+#include <assert.h>
+#include "dxferobj.h"
+#include "site.h"
+
+CLIPFORMAT g_cfEmbeddedObject = RegisterClipboardFormat(CF_EMBEDDEDOBJECT);
+CLIPFORMAT g_cfObjectDescriptor =RegisterClipboardFormat(CF_OBJECTDESCRIPTOR);
+
+// List of formats offered by our data transfer object via EnumFormatEtc
+static FORMATETC s_arrGetFmtEtcs[] =
+{
+ { g_cfEmbeddedObject, NULL, DVASPECT_CONTENT, -1, TYMED_ISTORAGE},
+ { g_cfObjectDescriptor, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL},
+ { CF_METAFILEPICT, NULL, DVASPECT_CONTENT, -1, TYMED_MFPICT}
+};
+
+
+//**********************************************************************
+//
+// CDataXferObj::Create
+//
+// Purpose:
+//
+// Creation routine for CDataXferObj
+//
+// Parameters:
+//
+// CSimpleSite FAR *lpSite - Pointer to source CSimpleSite
+// this is the container site of the
+// source OLE object to be transfered
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// StgCreateDocfile OLE API
+// assert C Runtime
+//
+// Comments:
+// reference count of CDataXferObj will be 0 on return.
+//
+//********************************************************************
+
+CDataXferObj FAR * CDataXferObj::Create(
+ CSimpleSite FAR *lpSite,
+ POINTL FAR* pPointl
+)
+{
+ CDataXferObj FAR * lpTemp = new CDataXferObj();
+
+ if (!lpTemp)
+ return NULL;
+
+ // create a sub-storage for the object
+ HRESULT hErr = StgCreateDocfile(
+ NULL,
+ STGM_READWRITE | STGM_DIRECT | STGM_SHARE_EXCLUSIVE |
+ STGM_DELETEONRELEASE,
+ 0,
+ &lpTemp->m_lpObjStorage);
+
+ assert(hErr == NOERROR);
+
+ if (hErr != NOERROR)
+ {
+ delete lpTemp;
+ return NULL;
+ }
+
+ // Clone the source object
+ if (lpSite->m_lpOleObject) {
+ // Object is loaded; ask the object to save into the new storage
+ LPPERSISTSTORAGE pPersistStorage;
+
+ lpSite->m_lpOleObject->QueryInterface(IID_IPersistStorage,
+ (LPVOID FAR*)&pPersistStorage);
+ assert(pPersistStorage);
+ OleSave(pPersistStorage, lpTemp->m_lpObjStorage, FALSE);
+
+ // pass NULL so that object application won't forget the real stg
+ pPersistStorage->SaveCompleted(NULL);
+ pPersistStorage->Release();
+ } else {
+ // Object not loaded so use cheaper IStorage CopyTo operation
+ lpSite->m_lpObjStorage->CopyTo(0, NULL, NULL, lpTemp->m_lpObjStorage);
+ }
+
+ OleLoad(lpTemp->m_lpObjStorage, IID_IOleObject, NULL,
+ (LPVOID FAR*)&lpTemp->m_lpOleObject);
+ assert(lpTemp->m_lpOleObject);
+
+ lpTemp->m_sizel = lpSite->m_sizel;
+ if (pPointl)
+ lpTemp->m_pointl = *pPointl;
+ else
+ lpTemp->m_pointl.x = lpTemp->m_pointl.y = 0;
+ return lpTemp;
+}
+
+//**********************************************************************
+//
+// CDataXferObj::CDataXferObj
+//
+// Purpose:
+//
+// Constructor for CDataXferObj
+//
+// Parameters:
+//
+// CSimpleDoc FAR *lpDoc - Pointer to CSimpleDoc
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// Comments:
+//
+//********************************************************************
+
+CDataXferObj::CDataXferObj (void)
+{
+ // clear the reference count
+ m_nCount = 0;
+
+ m_lpObjStorage = NULL;
+ m_lpOleObject = NULL;
+ m_sizel.cx = m_sizel.cy = 0;
+ m_pointl.x = m_pointl.y = 0;
+}
+
+//**********************************************************************
+//
+// CDataXferObj::~CDataXferObj
+//
+// Purpose:
+//
+// Destructor for CDataXferObj
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// IOleObject::Release Object
+// IStorage::Release OLE API
+//
+// Comments:
+//
+//********************************************************************
+
+CDataXferObj::~CDataXferObj ()
+{
+ TestDebugOut ("In CDataXferObj's Destructor \r\n");
+
+ if (m_lpOleObject)
+ {
+ m_lpOleObject->Release();
+ m_lpOleObject = NULL;
+
+ // Release the storage for this object
+ m_lpObjStorage->Release();
+ m_lpObjStorage = NULL;
+ }
+}
+
+
+
+//**********************************************************************
+//
+// CDataXferObj::QueryInterface
+//
+// Purpose:
+//
+// Used for interface negotiation of the CDataXferObj instance
+//
+// Parameters:
+//
+// REFIID riid - A reference to the interface that is
+// being queried.
+//
+// LPVOID FAR* ppvObj - An out parameter to return a pointer to
+// the interface.
+//
+// Return Value:
+//
+// S_OK - The interface is supported.
+// E_NOINTERFACE - The interface is not supported
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// IsEqualIID OLE API
+// ResultFromScode OLE API
+// CDataXferObj::AddRef DXFEROBJ.CPP
+//
+// Comments:
+//
+//
+//********************************************************************
+
+STDMETHODIMP CDataXferObj::QueryInterface(REFIID riid, LPVOID FAR* ppvObj)
+{
+ TestDebugOut("In CDataXferObj::QueryInterface\r\n");
+
+ if ( riid == IID_IUnknown || riid == IID_IDataObject)
+ {
+ AddRef();
+ *ppvObj = this;
+ return NOERROR;
+ }
+
+ // unknown interface requested
+ *ppvObj = NULL; // must set out pointer parameters to NULL
+ return ResultFromScode(E_NOINTERFACE);
+}
+
+//**********************************************************************
+//
+// CDataXferObj::AddRef
+//
+// Purpose:
+//
+// Increments the reference count of the CDataXferObj instance
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// ULONG - The new reference count of the object
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+// Comments:
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) CDataXferObj::AddRef()
+{
+ TestDebugOut("In CDataXferObj::AddRef\r\n");
+
+ return ++m_nCount;
+}
+
+//**********************************************************************
+//
+// CDataXferObj::Release
+//
+// Purpose:
+//
+// Decrements the reference count of the CDataXferObj object
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// ULONG - The new reference count of the object.
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+// Comments:
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) CDataXferObj::Release()
+{
+ TestDebugOut("In CDataXferObj::Release\r\n");
+
+ if (--m_nCount == 0) {
+ delete this;
+ return 0;
+ }
+ return m_nCount;
+}
+
+
+/********************************************************************
+** This IDataObject implementation is used for data transfer.
+**
+** The following methods are NOT supported for data transfer:
+** IDataObject::SetData -- return E_NOTIMPL
+** IDataObject::DAdvise -- return OLE_E_ADVISENOTSUPPORTED
+** ::DUnadvise
+** ::EnumDAdvise
+** IDataObject::GetCanonicalFormatEtc -- return E_NOTIMPL
+** (NOTE: must set pformatetcOut->ptd = NULL)
+*********************************************************************/
+
+
+//**********************************************************************
+//
+// CDataXferObj::QueryGetData
+//
+// Purpose:
+//
+// Called to determine if our object supports a particular
+// FORMATETC.
+//
+// Parameters:
+//
+// LPFORMATETC pformatetc - Pointer to the FORMATETC being queried for.
+//
+// Return Value:
+//
+// DV_E_FORMATETC - The FORMATETC is not supported
+// S_OK - The FORMATETC is supported.
+//
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// ResultFromScode OLE API
+//
+// Comments:
+// we support the following formats:
+// "Embedded Object"
+// "Object Descriptor"
+// CF_METAFILEPICT
+//
+//********************************************************************
+STDMETHODIMP CDataXferObj::QueryGetData (LPFORMATETC pformatetc)
+{
+ SCODE sc = DV_E_FORMATETC;
+
+ TestDebugOut("In CDataXferObj::QueryGetData\r\n");
+
+ // check the validity of the formatetc.
+
+ if ( (pformatetc->cfFormat == g_cfEmbeddedObject) &&
+ (pformatetc->dwAspect == DVASPECT_CONTENT) &&
+ (pformatetc->tymed == TYMED_ISTORAGE) )
+ sc = S_OK;
+
+ else if ( (pformatetc->cfFormat == g_cfObjectDescriptor) &&
+ (pformatetc->dwAspect == DVASPECT_CONTENT) &&
+ (pformatetc->tymed == TYMED_HGLOBAL) )
+ sc = S_OK;
+
+ else if ( (pformatetc->cfFormat == CF_METAFILEPICT) &&
+ (pformatetc->dwAspect == DVASPECT_CONTENT) &&
+ (pformatetc->tymed == TYMED_MFPICT) )
+ sc = S_OK;
+
+ return ResultFromScode(sc);
+}
+
+
+STDMETHODIMP CDataXferObj::EnumFormatEtc(
+ DWORD dwDirection,
+ LPENUMFORMATETC FAR* ppenumFormatEtc
+)
+{
+ SCODE sc = E_NOTIMPL;
+
+ TestDebugOut("In CDataXferObj::EnumFormatEtc\r\n");
+ *ppenumFormatEtc = NULL;
+
+ if (dwDirection == DATADIR_GET) {
+ *ppenumFormatEtc = OleStdEnumFmtEtc_Create(
+ sizeof(s_arrGetFmtEtcs)/sizeof(s_arrGetFmtEtcs[0]),
+ s_arrGetFmtEtcs);
+ if (*ppenumFormatEtc == NULL)
+ sc = E_OUTOFMEMORY;
+ else
+ sc = S_OK;
+ }
+ return ResultFromScode(sc);
+}
+
+
+//**********************************************************************
+//
+// CDataXferObj::GetData
+//
+// Purpose:
+//
+// Returns the data in the format specified in pformatetcIn.
+//
+// Parameters:
+//
+// LPFORMATETC pformatetcIn - The format requested by the caller
+//
+// LPSTGMEDIUM pmedium - The medium requested by the caller
+//
+// Return Value:
+//
+// DV_E_FORMATETC - Format not supported
+// S_OK - Success
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// OleStdGetOleObjectData OLE2UI API
+// OleStdGetMetafilePictFromOleObject OLE2UI API
+// ResultFromScode OLE API
+//
+// Comments:
+// we support GetData for the following formats:
+// "Embedded Object"
+// "Object Descriptor"
+// CF_METAFILEPICT
+//
+//********************************************************************
+
+STDMETHODIMP CDataXferObj::GetData (
+ LPFORMATETC pformatetcIn,
+ LPSTGMEDIUM pmedium
+)
+{
+ SCODE sc = DV_E_FORMATETC;
+
+ TestDebugOut("In CDataXferObj::GetData\r\n");
+
+ // we must set all out pointer parameters to NULL. */
+ pmedium->tymed = TYMED_NULL;
+ pmedium->pUnkForRelease = NULL; // we transfer ownership to caller
+ pmedium->hGlobal = NULL;
+
+ // Check the FORMATETC and fill pmedium if valid.
+ if ( (pformatetcIn->cfFormat == g_cfEmbeddedObject) &&
+ (pformatetcIn->dwAspect == DVASPECT_CONTENT) &&
+ (pformatetcIn->tymed == TYMED_ISTORAGE) ) {
+ LPPERSISTSTORAGE pPersistStorage;
+
+ /* render CF_EMBEDDEDOBJECT by asking the object to save
+ ** into a temporary, DELETEONRELEASE IStorage allocated by us.
+ */
+ m_lpOleObject->QueryInterface(
+ IID_IPersistStorage, (LPVOID FAR*)&pPersistStorage);
+ assert(pPersistStorage);
+ HRESULT hrErr = OleStdGetOleObjectData(
+ pPersistStorage,
+ pformatetcIn,
+ pmedium,
+ FALSE /* fUseMemory -- (use file-base stg) */
+ );
+ pPersistStorage->Release();
+ sc = GetScode( hrErr );
+
+ } else if ( (pformatetcIn->cfFormat == g_cfObjectDescriptor) &&
+ (pformatetcIn->dwAspect == DVASPECT_CONTENT) &&
+ (pformatetcIn->tymed == TYMED_HGLOBAL) ) {
+
+ // render CF_OBJECTDESCRIPTOR data
+ pmedium->hGlobal = OleStdGetObjectDescriptorDataFromOleObject(
+ m_lpOleObject,
+ "Simple OLE 2.0 Container", // string to identify source
+ DVASPECT_CONTENT,
+ m_pointl,
+ (LPSIZEL)&m_sizel
+ );
+ if (! pmedium->hGlobal)
+ sc = E_OUTOFMEMORY;
+ else {
+ pmedium->tymed = TYMED_HGLOBAL;
+ sc = S_OK;
+ }
+
+ } else if ( (pformatetcIn->cfFormat == CF_METAFILEPICT) &&
+ (pformatetcIn->dwAspect == DVASPECT_CONTENT) &&
+ (pformatetcIn->tymed == TYMED_MFPICT) ) {
+
+ // render CF_METAFILEPICT by drawing the object into a metafile DC
+ pmedium->hGlobal = OleStdGetMetafilePictFromOleObject(
+ m_lpOleObject, DVASPECT_CONTENT, NULL, pformatetcIn->ptd);
+ if (! pmedium->hGlobal)
+ sc = E_OUTOFMEMORY;
+ else {
+ pmedium->tymed = TYMED_MFPICT;
+ sc = S_OK;
+ }
+ }
+
+ return ResultFromScode( sc );
+}
+
+//**********************************************************************
+//
+// CDataXferObj::GetDataHere
+//
+// Purpose:
+//
+// Called to get a data format in a caller supplied location
+//
+// Parameters:
+//
+// LPFORMATETC pformatetc - FORMATETC requested
+//
+// LPSTGMEDIUM pmedium - Medium to return the data
+//
+// Return Value:
+//
+// DATA_E_FORMATETC - We don't support the requested format
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// OleStdGetOleObjectData OLE2UI API
+//
+// Comments:
+//
+//********************************************************************
+
+STDMETHODIMP CDataXferObj::GetDataHere (
+ LPFORMATETC pformatetc,
+ LPSTGMEDIUM pmedium
+)
+{
+ SCODE sc = DV_E_FORMATETC;
+
+ TestDebugOut("In CDataXferObj::GetDataHere\r\n");
+
+ // NOTE: pmedium is an IN parameter. we should NOT set
+ // pmedium->pUnkForRelease to NULL
+
+ // Check the FORMATETC and fill pmedium if valid.
+ if ( (pformatetc->cfFormat == g_cfEmbeddedObject) &&
+ (pformatetc->dwAspect == DVASPECT_CONTENT) &&
+ (pformatetc->tymed == TYMED_ISTORAGE) ) {
+ LPPERSISTSTORAGE pPersistStorage;
+
+ /* render CF_EMBEDDEDOBJECT by asking the object to save
+ ** into the IStorage allocated by the caller.
+ */
+ m_lpOleObject->QueryInterface(
+ IID_IPersistStorage, (LPVOID FAR*)&pPersistStorage);
+ assert(pPersistStorage);
+ HRESULT hrErr = OleStdGetOleObjectData(
+ pPersistStorage, pformatetc, pmedium,0 /*fUseMemory--N/A*/ );
+ pPersistStorage->Release();
+ sc = GetScode( hrErr );
+ }
+ return ResultFromScode( sc );
+}
diff --git a/private/oleutest/utests16/simpdnd/dxferobj.h b/private/oleutest/utests16/simpdnd/dxferobj.h
new file mode 100644
index 000000000..5b468b394
--- /dev/null
+++ b/private/oleutest/utests16/simpdnd/dxferobj.h
@@ -0,0 +1,57 @@
+//**********************************************************************
+// File name: dxferobj.h
+//
+// Definition of CDataXferObj
+//
+// Copyright (c) 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+
+#if !defined( _DATAXFEROBJ_H_)
+#define _DATAXFEROBJ_H_
+
+class CSimpleSite;
+
+interface CDataObject;
+
+class CDataXferObj : public IDataObject
+{
+private:
+ int m_nCount; // reference count
+ SIZEL m_sizel;
+ POINTL m_pointl;
+ LPSTORAGE m_lpObjStorage;
+ LPOLEOBJECT m_lpOleObject;
+
+ // construction/destruction
+ CDataXferObj();
+ ~CDataXferObj();
+
+public:
+ STDMETHODIMP QueryInterface (REFIID riid, LPVOID FAR* ppvObj);
+ STDMETHODIMP_(ULONG) AddRef ();
+ STDMETHODIMP_(ULONG) Release ();
+
+ STDMETHODIMP DAdvise ( FORMATETC FAR* pFormatetc, DWORD advf,
+ LPADVISESINK pAdvSink, DWORD FAR* pdwConnection)
+ { return ResultFromScode(OLE_E_ADVISENOTSUPPORTED); }
+ STDMETHODIMP DUnadvise ( DWORD dwConnection)
+ { return ResultFromScode(OLE_E_ADVISENOTSUPPORTED); }
+ STDMETHODIMP EnumDAdvise ( LPENUMSTATDATA FAR* ppenumAdvise)
+ { return ResultFromScode(OLE_E_ADVISENOTSUPPORTED); }
+ STDMETHODIMP EnumFormatEtc ( DWORD dwDirection,
+ LPENUMFORMATETC FAR* ppenumFormatEtc);
+ STDMETHODIMP GetCanonicalFormatEtc ( LPFORMATETC pformatetc,
+ LPFORMATETC pformatetcOut)
+ { pformatetcOut->ptd = NULL; return ResultFromScode(E_NOTIMPL); }
+ STDMETHODIMP GetData (LPFORMATETC pformatetcIn, LPSTGMEDIUM pmedium );
+ STDMETHODIMP GetDataHere (LPFORMATETC pformatetc, LPSTGMEDIUM pmedium);
+ STDMETHODIMP QueryGetData (LPFORMATETC pformatetc );
+ STDMETHODIMP SetData (LPFORMATETC pformatetc, STGMEDIUM FAR * pmedium,
+ BOOL fRelease)
+ { return ResultFromScode(E_NOTIMPL); }
+
+ static CDataXferObj FAR* Create(CSimpleSite FAR* lpSite,
+ POINTL FAR* pPointl);
+
+};
+#endif // _DATAXFEROBJ_H_
diff --git a/private/oleutest/utests16/simpdnd/ias.cpp b/private/oleutest/utests16/simpdnd/ias.cpp
new file mode 100644
index 000000000..52e593e20
--- /dev/null
+++ b/private/oleutest/utests16/simpdnd/ias.cpp
@@ -0,0 +1,316 @@
+//**********************************************************************
+// File name: IAS.CPP
+//
+// Implementation file of CAdviseSink
+//
+//
+// Functions:
+//
+// See IAS.H for Class Definition
+//
+// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+
+#include "pre.h"
+#include "iocs.h"
+#include "ias.h"
+#include "app.h"
+#include "site.h"
+#include "doc.h"
+
+//**********************************************************************
+//
+// CAdviseSink::QueryInterface
+//
+// Purpose:
+//
+// Returns a pointer to a requested interface.
+//
+// Parameters:
+//
+// REFIID riid - The requested interface
+//
+// LPVOID FAR* ppvObj - Place to return the interface
+//
+// Return Value:
+//
+// HRESULT from CSimpleSite::QueryInterface
+//
+// Function Calls:
+// Function Location
+//
+// CSimpleSite::QueryInterface SITE.CPP
+// TestDebugOut Windows API
+//
+// Comments:
+//
+// This function simply delegates to the Object class, which is
+// aware of the supported interfaces.
+//
+//********************************************************************
+
+STDMETHODIMP CAdviseSink::QueryInterface(REFIID riid, LPVOID FAR* ppvObj)
+{
+ TestDebugOut("In IAS::QueryInterface\r\n");
+
+ // delegate to the document Object
+ return m_pSite->QueryInterface(riid, ppvObj);
+}
+
+//**********************************************************************
+//
+// CAdviseSink::AddRef
+//
+// Purpose:
+//
+// Increments the reference count on this interface
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// The current reference count on this interface.
+//
+// Function Calls:
+// Function Location
+//
+// CSimpleSite::AddReff SITE.CPP
+// TestDebugOut Windows API
+//
+// Comments:
+//
+// This function adds one to the ref count of the interface,
+// and calls then calls CSimpleSite to increment its ref.
+// count.
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) CAdviseSink::AddRef()
+{
+ TestDebugOut("In IAS::AddRef\r\n");
+
+ // increment the interface reference count (for debugging only)
+ ++m_nCount;
+
+ // delegate to the container Site
+ return m_pSite->AddRef();
+}
+
+//**********************************************************************
+//
+// CAdviseSink::Release
+//
+// Purpose:
+//
+// Decrements the reference count on this interface
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// The current reference count on this interface.
+//
+// Function Calls:
+// Function Location
+//
+// CSimpleSite::Release SITE.CPP
+// TestDebugOut Windows API
+//
+// Comments:
+//
+// This function subtracts one from the ref count of the interface,
+// and calls then calls CSimpleSite to decrement its ref.
+// count.
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) CAdviseSink::Release()
+{
+ TestDebugOut("In IAS::Release\r\n");
+
+ // decrement the interface reference count (for debugging only)
+ m_nCount--;
+
+ // delegate to the container Site
+ return m_pSite->Release();
+}
+
+//**********************************************************************
+//
+// CAdviseSink::OnDataChange
+//
+// Purpose:
+//
+// Not Implemented (needs to be stubbed out)
+//
+// Parameters:
+//
+// Not Implemented (needs to be stubbed out)
+//
+// Return Value:
+//
+// Not Implemented (needs to be stubbed out)
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+// Comments:
+//
+// Not Implemented (needs to be stubbed out)
+//
+//********************************************************************
+
+STDMETHODIMP_(void) CAdviseSink::OnDataChange (FORMATETC FAR* pFormatetc, STGMEDIUM FAR* pStgmed)
+{
+ TestDebugOut("In IAS::OnDataChange\r\n");
+}
+
+//**********************************************************************
+//
+// CAdviseSink::OnViewChange
+//
+// Purpose:
+//
+// Notifies us that the view has changed and needs to be updated.
+//
+// Parameters:
+//
+// DWORD dwAspect - Aspect that has changed
+//
+// LONG lindex - Index that has changed
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// InvalidateRect Windows API
+// IViewObject2::GetExtent Object
+//
+// Comments:
+//
+//********************************************************************
+
+STDMETHODIMP_(void) CAdviseSink::OnViewChange (DWORD dwAspect, LONG lindex)
+{
+ LPVIEWOBJECT2 lpViewObject2;
+ TestDebugOut("In IAS::OnViewChange\r\n");
+
+ // get a pointer to IViewObject2
+ HRESULT hErr = m_pSite->m_lpOleObject->QueryInterface(
+ IID_IViewObject2,(LPVOID FAR *)&lpViewObject2);
+
+ if (hErr == NOERROR) {
+ // get extent of the object
+ // NOTE: this method will never be remoted; it can be called w/i this async method
+ lpViewObject2->GetExtent(DVASPECT_CONTENT, -1 , NULL, &m_pSite->m_sizel);
+ lpViewObject2->Release();
+ }
+
+ InvalidateRect(m_pSite->m_lpDoc->m_hDocWnd, NULL, TRUE);
+}
+
+//**********************************************************************
+//
+// CAdviseSink::OnRename
+//
+// Purpose:
+//
+// Not Implemented (needs to be stubbed out)
+//
+// Parameters:
+//
+// Not Implemented (needs to be stubbed out)
+//
+// Return Value:
+//
+// Not Implemented (needs to be stubbed out)
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+// Comments:
+//
+// Not Implemented (needs to be stubbed out)
+//
+//********************************************************************
+
+STDMETHODIMP_(void) CAdviseSink::OnRename (LPMONIKER pmk)
+{
+ TestDebugOut("In IAS::OnRename\r\n");
+}
+
+//**********************************************************************
+//
+// CAdviseSink::OnSave
+//
+// Purpose:
+//
+// Not Implemented (needs to be stubbed out)
+//
+// Parameters:
+//
+// Not Implemented (needs to be stubbed out)
+//
+// Return Value:
+//
+// Not Implemented (needs to be stubbed out)
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+// Comments:
+//
+// Not Implemented (needs to be stubbed out)
+//
+//********************************************************************
+
+STDMETHODIMP_(void) CAdviseSink::OnSave ()
+{
+ TestDebugOut("In IAS::OnSave\r\n");
+}
+
+//**********************************************************************
+//
+// CAdviseSink::OnClose
+//
+// Purpose:
+//
+// Not Implemented (needs to be stubbed out)
+//
+// Parameters:
+//
+// Not Implemented (needs to be stubbed out)
+//
+// Return Value:
+//
+// Not Implemented (needs to be stubbed out)
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+// Comments:
+//
+// Not Implemented (needs to be stubbed out)
+//
+//********************************************************************
+
+STDMETHODIMP_(void) CAdviseSink::OnClose()
+{
+ TestDebugOut("In IAS::OnClose\r\n");
+}
diff --git a/private/oleutest/utests16/simpdnd/ias.h b/private/oleutest/utests16/simpdnd/ias.h
new file mode 100644
index 000000000..3d948f5dc
--- /dev/null
+++ b/private/oleutest/utests16/simpdnd/ias.h
@@ -0,0 +1,44 @@
+//**********************************************************************
+// File name: IAS.H
+//
+// Definition of CAdviseSink
+//
+// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+#if !defined( _IAS_H_ )
+#define _IAS_H_
+
+#include <assert.h>
+
+class CSimpleSite;
+
+interface CAdviseSink : public IAdviseSink
+{
+ int m_nCount;
+ CSimpleSite FAR * m_pSite;
+
+ CAdviseSink(CSimpleSite FAR * pSite) {
+ TestDebugOut("In IAS's constructor\r\n");
+ m_pSite = pSite;
+ m_nCount = 0;
+ };
+
+ ~CAdviseSink() {
+ TestDebugOut("In IAS's destructor\r\n");
+ assert(m_nCount == 0);
+ } ;
+
+ STDMETHODIMP QueryInterface (REFIID riid, LPVOID FAR* ppv);
+ STDMETHODIMP_(ULONG) AddRef ();
+ STDMETHODIMP_(ULONG) Release ();
+
+ // *** IAdviseSink methods ***
+ STDMETHODIMP_(void) OnDataChange (FORMATETC FAR* pFormatetc, STGMEDIUM FAR* pStgmed);
+ STDMETHODIMP_(void) OnViewChange (DWORD dwAspect, LONG lindex);
+ STDMETHODIMP_(void) OnRename (LPMONIKER pmk);
+ STDMETHODIMP_(void) OnSave ();
+ STDMETHODIMP_(void) OnClose ();
+};
+
+
+#endif
diff --git a/private/oleutest/utests16/simpdnd/ids.cpp b/private/oleutest/utests16/simpdnd/ids.cpp
new file mode 100644
index 000000000..35870af83
--- /dev/null
+++ b/private/oleutest/utests16/simpdnd/ids.cpp
@@ -0,0 +1,330 @@
+//**********************************************************************
+// File name: IDS.CPP
+//
+// Implementation file for CDropSource
+//
+// Functions:
+//
+// See IDS.H for class definition
+//
+// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+
+#include "pre.h"
+#include "doc.h"
+#include "site.h"
+#include "dxferobj.h"
+
+
+//**********************************************************************
+//
+// CSimpleDoc::QueryDrag
+//
+// Purpose:
+//
+// Check to see if Drag operation should be initiated based on the
+// current position of the mouse.
+//
+// Parameters:
+//
+// POINT pt - position of mouse
+//
+// Return Value:
+//
+// BOOL - TRUE if drag should take place,
+// else FALSE
+//
+// Function Calls:
+// Function Location
+//
+// CSimpleSite::GetObjRect SITE.CPP
+// PtInRect Windows API
+//
+// Comments:
+//
+//********************************************************************
+
+BOOL CSimpleDoc::QueryDrag(POINT pt)
+{
+ // if pt is within rect of object, then start drag
+ if (m_lpSite)
+ {
+ RECT rect;
+ m_lpSite->GetObjRect(&rect);
+ return ( PtInRect(&rect, pt) ? TRUE : FALSE );
+ }
+ else
+ return FALSE;
+}
+
+
+//**********************************************************************
+//
+// CSimpleDoc::DoDragDrop
+//
+// Purpose:
+//
+// Actually perform a drag/drop operation with the current
+// selection in the source document.
+//
+// Parameters:
+//
+// none.
+//
+// Return Value:
+//
+// DWORD - returns the result effect of the
+// drag/drop operation:
+// DROPEFFECT_NONE,
+// DROPEFFECT_COPY,
+// DROPEFFECT_MOVE, or
+// DROPEFFECT_LINK
+//
+// Function Calls:
+// Function Location
+//
+// CDataXferObj::Create DXFEROBJ.CPP
+// CDataXferObj::QueryInterface DXFEROBJ.CPP
+// CDataXferObj::Release DXFEROBJ.CPP
+// DoDragDrop OLE API
+// TestDebugOut Windows API
+//
+// Comments:
+//
+//********************************************************************
+
+DWORD CSimpleDoc::DoDragDrop (void)
+{
+ DWORD dwEffect = 0;
+ LPDATAOBJECT lpDataObj;
+
+ TestDebugOut("In CSimpleDoc::DoDragDrop\r\n");
+
+ // Create a data transfer object by cloning the existing OLE object
+ CDataXferObj FAR* pDataXferObj = CDataXferObj::Create(m_lpSite,NULL);
+
+ if (! pDataXferObj) {
+ MessageBox(NULL,"Out-of-memory","SimpDnD",MB_SYSTEMMODAL|MB_ICONHAND);
+ return DROPEFFECT_NONE;
+ }
+
+ // initially obj is created with 0 refcnt. this QI will make it go to 1.
+ pDataXferObj->QueryInterface(IID_IDataObject, (LPVOID FAR*)&lpDataObj);
+ assert(lpDataObj);
+
+ m_fLocalDrop = FALSE;
+ m_fLocalDrag = TRUE;
+
+ ::DoDragDrop ( lpDataObj,
+ &m_DropSource,
+ DROPEFFECT_COPY, // we only allow copy
+ &dwEffect
+ );
+
+ m_fLocalDrag = FALSE;
+
+ /* if after the Drag/Drop modal (mouse capture) loop is finished
+ ** and a drag MOVE operation was performed, then we must delete
+ ** the selection that was dragged.
+ */
+ if ( (dwEffect & DROPEFFECT_MOVE) != 0 ) {
+ // ... delete source object here (we do NOT support MOVE)
+ }
+
+ pDataXferObj->Release(); // this should destroy the DataXferObj
+ return dwEffect;
+}
+
+
+
+//**********************************************************************
+//
+// CDropSource::QueryInterface
+//
+// Purpose:
+//
+// Return a pointer to a requested interface
+//
+// Parameters:
+//
+// REFIID riid - ID of interface to be returned
+// LPVOID FAR* ppvObj - Location to return the interface
+//
+// Return Value:
+//
+// S_OK - Interface supported
+// E_NOINTERFACE - Interface NOT supported
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// CSimpleDoc::QueryInterface DOC.CPP
+//
+// Comments:
+//
+//********************************************************************
+
+STDMETHODIMP CDropSource::QueryInterface(REFIID riid, LPVOID FAR* ppvObj)
+{
+ TestDebugOut("In IDS::QueryInterface\r\n");
+
+ // delegate to the document
+ return m_pDoc->QueryInterface(riid, ppvObj);
+}
+
+
+//**********************************************************************
+//
+// CDropSource::AddRef
+//
+// Purpose:
+//
+// Increments the reference count on this interface
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// The current reference count on this interface.
+//
+// Function Calls:
+// Function Location
+//
+// CSimpleObj::AddReff OBJ.CPP
+// TestDebugOut Windows API
+//
+// Comments:
+//
+// This function adds one to the ref count of the interface,
+// and calls then calls CSimpleDoc to increment its ref.
+// count.
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) CDropSource::AddRef()
+{
+ TestDebugOut("In IDS::AddRef\r\n");
+
+ // increment the interface reference count (for debugging only)
+ ++m_nCount;
+
+ // delegate to the document Object
+ return m_pDoc->AddRef();
+}
+
+//**********************************************************************
+//
+// CDropSource::Release
+//
+// Purpose:
+//
+// Decrements the reference count on this interface
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// The current reference count on this interface.
+//
+// Function Calls:
+// Function Location
+//
+// CSimpleObj::Release OBJ.CPP
+// TestDebugOut Windows API
+//
+// Comments:
+//
+// This function subtracts one from the ref count of the interface,
+// and calls then calls CSimpleDoc to decrement its ref.
+// count.
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) CDropSource::Release()
+{
+ TestDebugOut("In IDS::Release\r\n");
+
+ // decrement the interface reference count (for debugging only)
+ --m_nCount;
+
+ // delegate to the document object
+ return m_pDoc->Release();
+}
+
+//**********************************************************************
+//
+// CDropSource::QueryContinueDrag
+//
+// Purpose:
+//
+// Called to determine if a drop should take place or be canceled.
+//
+// Parameters:
+//
+// BOOL fEscapePressed - TRUE if ESCAPE key has been pressed
+// DWORD grfKeyState - key state
+//
+// Return Value:
+//
+// DRAGDROP_S_CANCEL - drag operation should be canceled
+// DRAGDROP_S_DROP - drop operation should be performed
+// S_OK - dragging should continue
+//
+//
+// Function Calls:
+// Function Location
+//
+// ResultFromScode OLE API
+//
+// Comments:
+//
+//********************************************************************
+
+STDMETHODIMP CDropSource::QueryContinueDrag (
+ BOOL fEscapePressed,
+ DWORD grfKeyState
+)
+{
+ if (fEscapePressed)
+ return ResultFromScode(DRAGDROP_S_CANCEL);
+ else if (!(grfKeyState & MK_LBUTTON))
+ return ResultFromScode(DRAGDROP_S_DROP);
+ else
+ return NOERROR;
+}
+
+
+//**********************************************************************
+//
+// CDropSource::GiveFeedback
+//
+// Purpose:
+//
+// Called to set cursor feedback
+//
+// Parameters:
+//
+// DWORD dwEffect - drop operation to give feedback for
+//
+// Return Value:
+//
+// DRAGDROP_S_USEDEFAULTCURSORS - tells OLE to use standard cursors
+//
+// Function Calls:
+// Function Location
+//
+// ResultFromScode OLE API
+//
+// Comments:
+//
+//********************************************************************
+
+STDMETHODIMP CDropSource::GiveFeedback (DWORD dwEffect)
+{
+ return ResultFromScode(DRAGDROP_S_USEDEFAULTCURSORS);
+}
diff --git a/private/oleutest/utests16/simpdnd/ids.h b/private/oleutest/utests16/simpdnd/ids.h
new file mode 100644
index 000000000..0046c1b51
--- /dev/null
+++ b/private/oleutest/utests16/simpdnd/ids.h
@@ -0,0 +1,43 @@
+//**********************************************************************
+// File name: ids.h
+//
+// Definition of CDropSource
+//
+// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+#if !defined( _IDS_H_ )
+#define _IDS_H_
+
+#include <assert.h>
+
+class CSimpleDoc;
+
+interface CDropSource : public IDropSource
+{
+ int m_nCount;
+ CSimpleDoc FAR * m_pDoc;
+
+ CDropSource(CSimpleDoc FAR * pDoc) {
+ TestDebugOut("In IDS's constructor\r\n");
+ m_pDoc = pDoc;
+ m_nCount = 0;
+ };
+
+ ~CDropSource() {
+ TestDebugOut("In IDS's destructor\r\n");
+ } ;
+
+ STDMETHODIMP QueryInterface (REFIID riid, LPVOID FAR* ppv);
+ STDMETHODIMP_(ULONG) AddRef ();
+ STDMETHODIMP_(ULONG) Release ();
+
+ // *** IDropSource methods ***
+ STDMETHODIMP QueryContinueDrag (BOOL fEscapePressed, DWORD grfKeyState);
+ STDMETHODIMP GiveFeedback (DWORD dwEffect);
+
+private:
+
+};
+
+
+#endif
diff --git a/private/oleutest/utests16/simpdnd/idt.cpp b/private/oleutest/utests16/simpdnd/idt.cpp
new file mode 100644
index 000000000..006dcc117
--- /dev/null
+++ b/private/oleutest/utests16/simpdnd/idt.cpp
@@ -0,0 +1,814 @@
+//**********************************************************************
+// File name: IDT.CPP
+//
+// Implementation file for CDropTarget
+//
+// Functions:
+//
+// See IDT.H for class definition
+//
+// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+
+#include "pre.h"
+#include "iocs.h"
+#include "ias.h"
+#include "app.h"
+#include "site.h"
+#include "doc.h"
+#include "idt.h"
+
+extern CLIPFORMAT g_cfObjectDescriptor;
+
+
+//**********************************************************************
+//
+// CDropTarget::QueryDrop
+//
+// Purpose:
+//
+// Check if the desired drop operation (identified by the given key
+// state) is possible at the current mouse position (pointl).
+//
+// Parameters:
+//
+// DWORD grfKeyState - current key state
+// POINTL pointl - position of mouse
+// BOOL fDragScroll - TRUE if drag scrolling cursor should
+// be shown.
+// LPDWORD pdwEffect - (OUT) drag effect that should occur
+//
+// Return Value:
+//
+// BOOL - TRUE if drop could take place,
+// else FALSE
+//
+// Function Calls:
+// Function Location
+//
+// OleStdGetDropEffect OLE2UI API
+//
+// Comments:
+//
+//********************************************************************
+
+BOOL CDropTarget::QueryDrop (
+ DWORD grfKeyState,
+ POINTL pointl,
+ BOOL fDragScroll,
+ LPDWORD pdwEffect
+)
+{
+ DWORD dwScrollEffect = 0L;
+ DWORD dwOKEffects = *pdwEffect;
+
+ /* 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 (! m_fCanDropCopy && ! m_fCanDropLink)
+ 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
+ */
+
+ *pdwEffect = OleStdGetDropEffect(grfKeyState);
+ if (*pdwEffect == 0) {
+ // No modifier keys given. Try in order MOVE, COPY, LINK.
+ if ((DROPEFFECT_MOVE & dwOKEffects) && m_fCanDropCopy)
+ *pdwEffect = DROPEFFECT_MOVE;
+ else if ((DROPEFFECT_COPY & dwOKEffects) && m_fCanDropCopy)
+ *pdwEffect = DROPEFFECT_COPY;
+ else if ((DROPEFFECT_LINK & dwOKEffects) && m_fCanDropLink)
+ *pdwEffect = DROPEFFECT_LINK;
+ else
+ goto dropeffect_none;
+ } else {
+ /* OLE2NOTE: we should check if the drag source application allows
+ ** the desired drop effect.
+ */
+ if (!(*pdwEffect & dwOKEffects))
+ goto dropeffect_none;
+
+ if ((*pdwEffect == DROPEFFECT_COPY || *pdwEffect == DROPEFFECT_MOVE)
+ && ! m_fCanDropCopy)
+ goto dropeffect_none;
+
+ if (*pdwEffect == DROPEFFECT_LINK && ! m_fCanDropLink)
+ goto dropeffect_none;
+ }
+
+ *pdwEffect |= dwScrollEffect;
+ return TRUE;
+
+dropeffect_none:
+
+ *pdwEffect = DROPEFFECT_NONE;
+ return FALSE;
+}
+
+
+//**********************************************************************
+//
+// CDropTarget::QueryDrop
+//
+// Purpose:
+//
+// Check to see if Drag scroll operation should be initiated.
+//
+// Parameters:
+//
+// POINTL pointl - position of mouse
+//
+// Return Value:
+//
+// BOOL - TRUE if scroll cursor should be given
+// else FALSE
+//
+// Function Calls:
+// Function Location
+//
+// ScreenToClient WINDOWS API
+// GetClientRect WINDOWS API
+//
+// Comments:
+// 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 CDropTarget::DoDragScroll (POINTL pointl)
+{
+ DWORD dwScrollDir = SCROLLDIR_NULL;
+ DWORD dwTime = GetCurrentTime();
+ int nScrollInset = m_pDoc->m_lpApp->m_nScrollInset;
+ int nScrollDelay = m_pDoc->m_lpApp->m_nScrollDelay;
+ int nScrollInterval = m_pDoc->m_lpApp->m_nScrollInterval;
+ POINT point;
+ RECT rect;
+
+ point.x = (int)pointl.x;
+ point.y = (int)pointl.y;
+
+ ScreenToClient( m_pDoc->m_hDocWnd, &point);
+ GetClientRect ( m_pDoc->m_hDocWnd, (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;
+ else if (rect.left <= point.x && point.x <= (rect.left+nScrollInset))
+ dwScrollDir = SCROLLDIR_LEFT;
+ else if ((rect.right-nScrollInset) <= point.x && point.x <= rect.right)
+ dwScrollDir = SCROLLDIR_RIGHT;
+
+ if (m_dwTimeEnterScrollArea) {
+
+ /* cursor was already in Scroll Area */
+
+ if (! dwScrollDir) {
+ /* cusor moved OUT of scroll area.
+ ** clear "EnterScrollArea" time.
+ */
+ m_dwTimeEnterScrollArea = 0L;
+ m_dwNextScrollTime = 0L;
+ m_dwLastScrollDir = SCROLLDIR_NULL;
+
+ } else if (dwScrollDir != m_dwLastScrollDir) {
+ /* cusor moved into a different direction scroll area.
+ ** reset "EnterScrollArea" time to start a new 50ms delay.
+ */
+ m_dwTimeEnterScrollArea = dwTime;
+ m_dwNextScrollTime = dwTime + (DWORD)nScrollDelay;
+ m_dwLastScrollDir = dwScrollDir;
+
+ } else if (dwTime && dwTime >= m_dwNextScrollTime) {
+ m_pDoc->Scroll ( dwScrollDir ); // Scroll document now
+ m_dwNextScrollTime = dwTime + (DWORD)nScrollInterval;
+ }
+ } else {
+ if (dwScrollDir) {
+ /* cusor moved INTO a scroll area.
+ ** reset "EnterScrollArea" time to start a new 50ms delay.
+ */
+ m_dwTimeEnterScrollArea = dwTime;
+ m_dwNextScrollTime = dwTime + (DWORD)nScrollDelay;
+ m_dwLastScrollDir = dwScrollDir;
+ }
+ }
+
+ return (dwScrollDir ? TRUE : FALSE);
+}
+
+
+// Support functions/macros
+#define SetTopLeft(rc, pt) \
+ ((rc)->top = (pt)->y,(rc)->left = (pt)->x)
+#define SetBottomRight(rc, pt) \
+ ((rc)->bottom = (pt)->y,(rc)->right = (pt)->x)
+#define OffsetPoint(pt, dx, dy) \
+ ((pt)->x += dx, (pt)->y += dy)
+
+
+/* HighlightRect
+** -------------
+** Invert rectangle on screen. used for drop target feedback.
+*/
+
+static int HighlightRect(HWND hwnd, HDC hdc, LPRECT rc)
+{
+ POINT pt1, pt2;
+ int old = SetROP2(hdc, R2_NOT);
+ HPEN hpen;
+ HGDIOBJ hold;
+
+ pt1.x = rc->left;
+ pt1.y = rc->top;
+ pt2.x = rc->right;
+ pt2.y = rc->bottom;
+
+ ScreenToClient(hwnd, &pt1);
+ ScreenToClient(hwnd, &pt2);
+
+ hold = SelectObject(hdc, GetStockObject(HOLLOW_BRUSH));
+ hpen = SelectObject(hdc, CreatePen(PS_SOLID, 2,
+ GetSysColor(COLOR_ACTIVEBORDER)));
+
+ Rectangle(hdc, pt1.x, pt1.y, pt2.x, pt2.y);
+
+ SetROP2(hdc, old);
+
+ hold = SelectObject(hdc, hold);
+ hpen = SelectObject(hdc, hpen);
+
+ DeleteObject(hpen);
+
+ return 0;
+}
+
+
+//**********************************************************************
+//
+// CDropTarget::InitDragFeedback
+//
+// Purpose:
+//
+// Initialize data used to draw drop target feedback.
+// As feedback we draw a rectangle the size of the object.
+//
+// Parameters:
+//
+// LPDATAOBJECT pDataObj - IDataObject from Drop source
+// POINTL pointl - position of mouse
+//
+// Return Value:
+//
+// none.
+//
+// Function Calls:
+// Function Location
+//
+// IDataObject::GetData Object
+// XformSizeInHimetricToPixels OLE2UI Library
+// GlobalLock WINDOWS API
+// GlobalUnlock WINDOWS API
+// ReleaseStgMedium OLE2 API
+// OffsetPoint IDT.CPP
+// SetTopLeft IDT.CPP
+// SetBottomRight IDT.CPP
+//
+// Comments:
+// In order to known the size of the object before the object
+// is actually dropped, we render CF_OBJECTDESCRIPTOR format.
+// this data format tells us both the size of the object as
+// well as which aspect is the object is displayed as in the
+// source. if the object is currently displayed as DVASPECT_ICON
+// then we want to create the object also as DVASPECT_ICON.
+//
+//********************************************************************
+
+void CDropTarget::InitDragFeedback(LPDATAOBJECT pDataObj, POINTL pointl)
+{
+ FORMATETC fmtetc;
+ STGMEDIUM stgmed;
+ POINT pt;
+ int height, width;
+ HRESULT hrErr;
+
+ height = width = 100; // some default values
+ pt.x = (int)pointl.x;
+ pt.y = (int)pointl.y;
+
+ // do a GetData for CF_OBJECTDESCRIPTOR format to get the size of the
+ // object as displayed in the source. using this size, initialize the
+ // size for the drag feedback rectangle.
+ fmtetc.cfFormat = g_cfObjectDescriptor;
+ fmtetc.ptd = NULL;
+ fmtetc.lindex = -1;
+ fmtetc.dwAspect = DVASPECT_CONTENT;
+ fmtetc.tymed = TYMED_HGLOBAL;
+
+ hrErr = pDataObj->GetData(&fmtetc, &stgmed);
+ if (hrErr == NOERROR) {
+ LPOBJECTDESCRIPTOR pOD=(LPOBJECTDESCRIPTOR)GlobalLock(stgmed.hGlobal);
+ if (pOD != NULL) {
+ XformSizeInHimetricToPixels(NULL, &pOD->sizel, &pOD->sizel);
+
+ width = (int)pOD->sizel.cx;
+ height = (int)pOD->sizel.cy;
+ m_dwSrcAspect = pOD->dwDrawAspect;
+ }
+
+ GlobalUnlock(stgmed.hGlobal);
+ ReleaseStgMedium(&stgmed);
+ }
+
+ m_ptLast = pt;
+ m_fDragFeedbackDrawn = FALSE;
+
+ OffsetPoint(&pt, -(width/2), -(height/2));
+ SetTopLeft(&m_rcDragRect, &pt);
+
+ OffsetPoint(&pt, width, height);
+ SetBottomRight(&m_rcDragRect, &pt);
+}
+
+
+//**********************************************************************
+//
+// CDropTarget::UndrawDragFeedback
+//
+// Purpose:
+//
+// Erase any drop target feedback.
+// As feedback we draw a rectangle the size of the object.
+//
+// Parameters:
+//
+// none.
+//
+// Return Value:
+//
+// none.
+//
+// Function Calls:
+// Function Location
+//
+// GetDC WINDOWS API
+// ReleaseDC WINDOWS API
+// GlobalUnlock WINDOWS API
+// HighlightRect IDT.CPP
+//
+// Comments:
+// In order to known the size of the object before the object
+// is actually dropped, we render CF_OBJECTDESCRIPTOR format.
+// this data format tells us both the size of the object as
+// well as which aspect is the object is displayed as in the
+// source. if the object is currently displayed as DVASPECT_ICON
+// then we want to create the object also as DVASPECT_ICON.
+//
+//********************************************************************
+
+void CDropTarget::UndrawDragFeedback( void )
+{
+ if (m_fDragFeedbackDrawn) {
+ m_fDragFeedbackDrawn = FALSE;
+ HDC hDC = GetDC(m_pDoc->m_hDocWnd);
+ HighlightRect(m_pDoc->m_hDocWnd, hDC, &m_rcDragRect);
+ ReleaseDC(m_pDoc->m_hDocWnd, hDC);
+ }
+}
+
+
+//**********************************************************************
+//
+// CDropTarget::DrawDragFeedback
+//
+// Purpose:
+//
+// Compute new position of drop target feedback rectangle and
+// erase old rectangle and draw new rectangle.
+// As feedback we draw a rectangle the size of the object.
+//
+// Parameters:
+//
+// POINTL pointl - position of mouse
+//
+// Return Value:
+//
+// none.
+//
+// Function Calls:
+// Function Location
+//
+// OffsetPoint IDT.CPP
+// HighlightRect IDT.CPP
+// GetDC WINDOWS API
+// ReleaseDC WINDOWS API
+//
+// Comments:
+//
+//********************************************************************
+
+void CDropTarget::DrawDragFeedback( POINTL pointl )
+{
+ POINT ptDiff;
+
+ ptDiff.x = (int)pointl.x - m_ptLast.x;
+ ptDiff.y = (int)pointl.y - m_ptLast.y;
+
+ if (m_fDragFeedbackDrawn && (ptDiff.x == 0 && ptDiff.y == 0))
+ return; // mouse did not move; leave rectangle as drawn
+
+ HDC hDC = GetDC(m_pDoc->m_hDocWnd);
+ if (m_fDragFeedbackDrawn) {
+ m_fDragFeedbackDrawn = FALSE;
+ HighlightRect(m_pDoc->m_hDocWnd, hDC, &m_rcDragRect);
+ }
+
+ OffsetRect(&m_rcDragRect, ptDiff.x, ptDiff.y);
+ HighlightRect(m_pDoc->m_hDocWnd, hDC, &m_rcDragRect);
+ m_fDragFeedbackDrawn = TRUE;
+ m_ptLast.x = (int)pointl.x;
+ m_ptLast.y = (int)pointl.y;
+ ReleaseDC(m_pDoc->m_hDocWnd, hDC);
+}
+
+
+//**********************************************************************
+//
+// CDropTarget::QueryInterface
+//
+// Purpose:
+//
+// Return a pointer to a requested interface
+//
+// Parameters:
+//
+// REFIID riid - ID of interface to be returned
+// LPVOID FAR* ppvObj - Location to return the interface
+//
+// Return Value:
+//
+// S_OK - Interface supported
+// E_NOINTERFACE - Interface NOT supported
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// CSimpleDoc::QueryInterface DOC.CPP
+//
+// Comments:
+//
+//********************************************************************
+
+STDMETHODIMP CDropTarget::QueryInterface(REFIID riid, LPVOID FAR* ppvObj)
+{
+ TestDebugOut("In IDT::QueryInterface\r\n");
+
+ // delegate to the document
+ return m_pDoc->QueryInterface(riid, ppvObj);
+}
+
+
+//**********************************************************************
+//
+// CDropTarget::AddRef
+//
+// Purpose:
+//
+// Increments the reference count on this interface
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// The current reference count on this interface.
+//
+// Function Calls:
+// Function Location
+//
+// CSimpleDoc::AddReff DOC.CPP
+// TestDebugOut Windows API
+//
+// Comments:
+//
+// This function adds one to the ref count of the interface,
+// and calls then calls CSimpleObj to increment its ref.
+// count.
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) CDropTarget::AddRef()
+{
+ TestDebugOut("In IDT::AddRef\r\n");
+
+ // increment the interface reference count (for debugging only)
+ ++m_nCount;
+
+ // delegate to the document Object
+ return m_pDoc->AddRef();
+}
+
+//**********************************************************************
+//
+// CDropTarget::Release
+//
+// Purpose:
+//
+// Decrements the reference count on this interface
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// The current reference count on this interface.
+//
+// Function Calls:
+// Function Location
+//
+// CSimpleDoc::Release DOC.CPP
+// TestDebugOut Windows API
+//
+// Comments:
+//
+// This function subtracts one from the ref count of the interface,
+// and calls then calls CSimpleDoc to decrement its ref.
+// count.
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) CDropTarget::Release()
+{
+ TestDebugOut("In IDT::Release\r\n");
+
+ // decrement the interface reference count (for debugging only)
+ --m_nCount;
+
+ // delegate to the document object
+ return m_pDoc->Release();
+}
+
+
+//**********************************************************************
+//
+// CDropTarget::DragEnter
+//
+// Purpose:
+//
+// Called when the mouse first enters our DropTarget window
+//
+// Parameters:
+//
+// LPDATAOBJECT pDataObj - IDataObject from Drop source
+// DWORD grfKeyState - current key state
+// POINTL pointl - position of mouse
+// LPDWORD pdwEffect - (IN-OUT) drag effect that should occur
+// ON INPUT, this is dwOKEffects that source
+// passed to DoDragDrop API.
+// ON OUTPUT, this is the effect that we
+// want to take effect (used to determine
+// cursor feedback).
+//
+// Return Value:
+//
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// OleQueryCreateFromData OLE2 API
+// DoDragScroll IDT.CPP
+// QueryDrop IDT.CPP
+// InitDragFeedback IDT.CPP
+// DrawDragFeedback IDT.CPP
+// UndrawDragFeedback IDT.CPP
+//
+// Comments:
+// Callee should honor the dwEffects as passed in to determine
+// if the caller allows DROPEFFECT_MOVE.
+//
+//********************************************************************
+
+STDMETHODIMP CDropTarget::DragEnter (LPDATAOBJECT pDataObj, DWORD grfKeyState, POINTL pointl, LPDWORD pdwEffect)
+{
+ TestDebugOut("In IDT::DragEnter\r\n");
+
+ /* Determine if the drag source data object offers a data format
+ ** that we understand. we accept only creating embedded objects.
+ */
+ m_fCanDropCopy = ((OleQueryCreateFromData(pDataObj) == NOERROR) ?
+ TRUE : FALSE);
+ m_fCanDropLink = FALSE; // linking NOT supported in this simple sample
+
+ if (m_fCanDropCopy || m_fCanDropLink)
+ InitDragFeedback(pDataObj, pointl);
+
+ BOOL fDragScroll = DoDragScroll ( pointl );
+
+ if (QueryDrop(grfKeyState,pointl,fDragScroll,pdwEffect))
+ DrawDragFeedback( pointl );
+
+ return NOERROR;
+}
+
+
+//**********************************************************************
+//
+// CDropTarget::DragOver
+//
+// Purpose:
+//
+// Called when the mouse moves, key state changes, or a time
+// interval passes while the mouse is still within our DropTarget
+// window.
+//
+// Parameters:
+//
+// DWORD grfKeyState - current key state
+// POINTL pointl - position of mouse
+// LPDWORD pdwEffect - (IN-OUT) drag effect that should occur
+// ON INPUT, this is dwOKEffects that source
+// passed to DoDragDrop API.
+// ON OUTPUT, this is the effect that we
+// want to take effect (used to determine
+// cursor feedback).
+//
+// Return Value:
+//
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// DoDragScroll IDT.CPP
+// QueryDrop IDT.CPP
+// DrawDragFeedback IDT.CPP
+// UndrawDragFeedback IDT.CPP
+//
+// Comments:
+// Callee should honor the dwEffects as passed in to determine
+// if the caller allows DROPEFFECT_MOVE. OLE pulses the DragOver
+// calls in order that the DropTarget can implement drag scrolling
+//
+//********************************************************************
+
+STDMETHODIMP CDropTarget::DragOver (DWORD grfKeyState, POINTL pointl, LPDWORD pdwEffect)
+{
+ TestDebugOut("In IDT::DragOver\r\n");
+
+ BOOL fDragScroll = DoDragScroll ( pointl );
+
+ if (QueryDrop(grfKeyState,pointl,fDragScroll,pdwEffect))
+ DrawDragFeedback( pointl );
+ else
+ UndrawDragFeedback();
+
+ return NOERROR;
+}
+
+
+//**********************************************************************
+//
+// CDropTarget::DragLeave
+//
+// Purpose:
+//
+// Called when the mouse leaves our DropTarget window
+//
+// Parameters:
+//
+// none.
+//
+// Return Value:
+//
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// UndrawDragFeedback IDT.CPP
+// ResultFromScode OLE2 API
+//
+// Comments:
+//
+//********************************************************************
+
+STDMETHODIMP CDropTarget::DragLeave ()
+{
+ TestDebugOut("In IDT::DragLeave\r\n");
+
+ UndrawDragFeedback();
+
+ return ResultFromScode(S_OK);
+}
+
+
+//**********************************************************************
+//
+// CDropTarget::Drop
+//
+// Purpose:
+//
+// Called when a Drop operation should take place.
+//
+// Parameters:
+//
+// LPDATAOBJECT pDataObj - IDataObject from Drop source
+// DWORD grfKeyState - current key state
+// POINTL pointl - position of mouse
+// LPDWORD pdwEffect - (IN-OUT) drag effect that should occur
+// ON INPUT, this is dwOKEffects that source
+// passed to DoDragDrop API.
+// ON OUTPUT, this is the effect that we
+// want to take effect (used to determine
+// cursor feedback).
+//
+// Return Value:
+//
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// CSimpleSite::Create SITE.CPP
+// CSimpleSite::InitObject SITE.CPP
+// OleCreateFromData OLE2 API
+// DoDragScroll IDT.CPP
+// QueryDrop IDT.CPP
+// InitDragFeedback IDT.CPP
+// DrawDragFeedback IDT.CPP
+// UndrawDragFeedback IDT.CPP
+// GetScode OLE2 API
+// ResultFromScode OLE2 API
+//
+// Comments:
+// Callee should honor the dwEffects as passed in to determine
+// if the caller allows DROPEFFECT_MOVE.
+//
+//********************************************************************
+
+STDMETHODIMP CDropTarget::Drop (LPDATAOBJECT pDataObj, DWORD grfKeyState, POINTL pointl, LPDWORD pdwEffect)
+{
+ FORMATETC fmtetc;
+ SCODE sc = S_OK;
+
+ TestDebugOut("In IDT::Drop\r\n");
+
+ UndrawDragFeedback();
+
+ if (pDataObj && QueryDrop(grfKeyState,pointl,FALSE,pdwEffect))
+ {
+ m_pDoc->m_lpSite = CSimpleSite::Create(m_pDoc);
+ // keep same aspect as drop source
+ m_pDoc->m_lpSite->m_dwDrawAspect = m_dwSrcAspect;
+
+ // in order to specify a particular drawing Aspect we must
+ // pass a FORMATETC* to OleCreateFromData
+ fmtetc.cfFormat = NULL; // use whatever for drawing
+ fmtetc.ptd = NULL;
+ fmtetc.lindex = -1;
+ fmtetc.dwAspect = m_dwSrcAspect; // desired drawing aspect
+ fmtetc.tymed = TYMED_NULL;
+
+ HRESULT hrErr = OleCreateFromData (
+ pDataObj,
+ IID_IOleObject,
+ OLERENDER_DRAW,
+ &fmtetc,
+ &m_pDoc->m_lpSite->m_OleClientSite,
+ m_pDoc->m_lpSite->m_lpObjStorage,
+ (LPVOID FAR *)&m_pDoc->m_lpSite->m_lpOleObject);
+
+ if (hrErr == NOERROR)
+ {
+ m_pDoc->m_lpSite->InitObject(FALSE /* fCreateNew */);
+ m_pDoc->DisableInsertObject();
+ }
+ else
+ sc = GetScode(hrErr);
+ }
+
+ return ResultFromScode(sc);
+}
diff --git a/private/oleutest/utests16/simpdnd/idt.h b/private/oleutest/utests16/simpdnd/idt.h
new file mode 100644
index 000000000..50610d1e8
--- /dev/null
+++ b/private/oleutest/utests16/simpdnd/idt.h
@@ -0,0 +1,77 @@
+//**********************************************************************
+// File name: idt.h
+//
+// Definition of CDropTarget
+//
+// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+#if !defined( _IDT_H_ )
+#define _IDT_H_
+
+#include <assert.h>
+
+class CSimpleDoc;
+
+/* Flags to control direction for drag scrolling */
+typedef enum tagSCROLLDIR {
+ SCROLLDIR_NULL = 0,
+ SCROLLDIR_UP = 1,
+ SCROLLDIR_DOWN = 2,
+ SCROLLDIR_RIGHT = 3,
+ SCROLLDIR_LEFT = 4
+} SCROLLDIR;
+
+interface CDropTarget : public IDropTarget
+{
+ int m_nCount; // reference count
+ CSimpleDoc FAR * m_pDoc;
+ BOOL m_fCanDropCopy;
+ BOOL m_fCanDropLink;
+ DWORD m_dwSrcAspect;
+ RECT m_rcDragRect;
+ POINT m_ptLast;
+ BOOL m_fDragFeedbackDrawn;
+ DWORD m_dwTimeEnterScrollArea; // time of entering scroll border region
+ DWORD m_dwLastScrollDir; // current dir for drag scroll
+ DWORD m_dwNextScrollTime; // time for next scroll
+
+ CDropTarget(CSimpleDoc FAR * pDoc) {
+ TestDebugOut("In IDT's constructor\r\n");
+ m_pDoc = pDoc;
+ m_nCount = 0;
+ m_fCanDropCopy = FALSE;
+ m_fCanDropLink = FALSE;
+ m_fDragFeedbackDrawn = FALSE;
+ m_dwTimeEnterScrollArea = 0L;
+ m_dwNextScrollTime = 0L;
+ m_dwLastScrollDir = SCROLLDIR_NULL;
+ };
+
+ ~CDropTarget() {
+ TestDebugOut("In IDT's destructor\r\n");
+ assert(m_nCount == 0);
+ } ;
+
+ STDMETHODIMP QueryInterface (REFIID riid, LPVOID FAR* ppv);
+ STDMETHODIMP_(ULONG) AddRef ();
+ STDMETHODIMP_(ULONG) Release ();
+
+ // *** IDropTarget methods ***
+ STDMETHODIMP DragEnter (LPDATAOBJECT pDataObj, DWORD grfKeyState,
+ POINTL pt, LPDWORD pdwEffect);
+ STDMETHODIMP DragOver (DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect);
+ STDMETHODIMP DragLeave ();
+ STDMETHODIMP Drop (LPDATAOBJECT pDataObj, DWORD grfKeyState, POINTL pt,
+ LPDWORD pdwEffect);
+
+private:
+ // Drag/Drop support methods
+ BOOL QueryDrop (DWORD grfKeyState, POINTL pointl, BOOL fDragScroll,
+ LPDWORD lpdwEffect);
+ BOOL DoDragScroll( POINTL pointl );
+ void InitDragFeedback(LPDATAOBJECT pDataObj, POINTL pointl);
+ void DrawDragFeedback( POINTL pointl );
+ void UndrawDragFeedback( void );
+};
+
+#endif // _IDT_H_
diff --git a/private/oleutest/utests16/simpdnd/iocs.cpp b/private/oleutest/utests16/simpdnd/iocs.cpp
new file mode 100644
index 000000000..e4503f99d
--- /dev/null
+++ b/private/oleutest/utests16/simpdnd/iocs.cpp
@@ -0,0 +1,365 @@
+//**********************************************************************
+// File name: IOCS.CPP
+//
+// Implementation file for COleClientSite
+//
+// Functions:
+//
+// See IOCS.H for class definition
+//
+// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+
+#include "pre.h"
+#include "iocs.h"
+#include "ias.h"
+#include "app.h"
+#include "site.h"
+#include "doc.h"
+
+
+//**********************************************************************
+//
+// COleClientSite::QueryInterface
+//
+// Purpose:
+//
+// Used for interface negotiation at this interface
+//
+// Parameters:
+//
+// REFIID riid - A reference to the interface that is
+// being queried.
+//
+// LPVOID FAR* ppvObj - An out parameter to return a pointer to
+// the interface.
+//
+// Return Value:
+//
+// S_OK - The interface is supported.
+// E_NOINTERFACE - The interface is not supported
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// CSimpleSite::QueryInterface SITE.CPP
+//
+// Comments:
+//
+//********************************************************************
+
+STDMETHODIMP COleClientSite::QueryInterface(REFIID riid, LPVOID FAR* ppvObj)
+{
+ TestDebugOut("In IOCS::QueryInterface\r\n");
+
+ // delegate to the container Site
+ return m_pSite->QueryInterface(riid, ppvObj);
+}
+
+//**********************************************************************
+//
+// CSimpleApp::AddRef
+//
+// Purpose:
+//
+// Adds to the reference count at the interface level.
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// ULONG - The new reference count of the interface
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+// Comments:
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) COleClientSite::AddRef()
+{
+ TestDebugOut("In IOCS::AddRef\r\n");
+
+ // increment the interface reference count (for debugging only)
+ ++m_nCount;
+
+ // delegate to the container Site
+ return m_pSite->AddRef();
+}
+
+
+//**********************************************************************
+//
+// CSimpleApp::Release
+//
+// Purpose:
+//
+// Decrements the reference count at this level
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// ULONG - The new reference count of the interface.
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+// Comments:
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) COleClientSite::Release()
+{
+ TestDebugOut("In IOCS::Release\r\n");
+
+ // decrement the interface reference count (for debugging only)
+ --m_nCount;
+
+ // delegate to the container Site
+ return m_pSite->Release();
+}
+
+//**********************************************************************
+//
+// COleClientSite::SaveObject
+//
+// Purpose:
+//
+// Called by the object when it wants to be saved to persistant
+// storage
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// IOleObject::QueryInterface Object
+// IPersistStorage::SaveCompleted Object
+// IPersistStorage::Release Object
+// OleSave OLE API
+// ResultFromScode OLE API
+//
+// Comments:
+//
+//********************************************************************
+
+STDMETHODIMP COleClientSite::SaveObject()
+{
+ LPPERSISTSTORAGE lpPS;
+ SCODE sc = E_FAIL;
+
+ TestDebugOut("In IOCS::SaveObject\r\n");
+
+ // get a pointer to IPersistStorage
+ HRESULT hErr = m_pSite->m_lpOleObject->QueryInterface(IID_IPersistStorage, (LPVOID FAR *)&lpPS);
+
+ // save the object
+ if (hErr == NOERROR)
+ {
+ sc = GetScode( OleSave(lpPS, m_pSite->m_lpObjStorage, TRUE) );
+ lpPS->SaveCompleted(NULL);
+ lpPS->Release();
+ }
+
+ return ResultFromScode(sc);
+}
+
+//**********************************************************************
+//
+// COleClientSite::GetMoniker
+//
+// Purpose:
+//
+// Not Implemented
+//
+// Parameters:
+//
+// Not Implemented
+//
+// Return Value:
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+// Comments:
+//
+// This function is not implemented because we don't support
+// linking.
+//
+//********************************************************************
+
+STDMETHODIMP COleClientSite::GetMoniker(DWORD dwAssign, DWORD dwWhichMoniker, LPMONIKER FAR* ppmk)
+{
+ TestDebugOut("In IOCS::GetMoniker\r\n");
+
+ // need to null the out pointer
+ *ppmk = NULL;
+
+ return ResultFromScode(E_NOTIMPL);
+}
+
+//**********************************************************************
+//
+// COleClientSite::GetContainer
+//
+// Purpose:
+//
+// Not Implemented
+//
+// Parameters:
+//
+// Not Implemented
+//
+// Return Value:
+//
+// Not Implemented
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+// Comments:
+//
+// Not Implemented
+//
+//********************************************************************
+
+STDMETHODIMP COleClientSite::GetContainer(LPOLECONTAINER FAR* ppContainer)
+{
+ TestDebugOut("In IOCS::GetContainer\r\n");
+
+ // NULL the out pointer
+ *ppContainer = NULL;
+
+ return ResultFromScode(E_NOTIMPL);
+}
+
+//**********************************************************************
+//
+// COleClientSite::ShowObject
+//
+// Purpose:
+//
+// Not Implemented
+//
+// Parameters:
+//
+// Not Implemented
+//
+// Return Value:
+//
+// Not Implemented
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+// Comments:
+//
+// This function is not implemented because we don't support
+// linking.
+//
+//********************************************************************
+
+STDMETHODIMP COleClientSite::ShowObject()
+{
+ TestDebugOut("In IOCS::ShowObject\r\n");
+ return NOERROR;
+}
+
+//**********************************************************************
+//
+// COleClientSite::OnShowWindow
+//
+// Purpose:
+//
+// Object calls this method when it is opening/closing non-InPlace
+// Window
+//
+// Parameters:
+//
+// BOOL fShow - TRUE if Window is opening, FALSE if closing
+//
+// Return Value:
+//
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// InvalidateRect Windows API
+// ResultFromScode OLE API
+//
+// Comments:
+//
+//********************************************************************
+
+STDMETHODIMP COleClientSite::OnShowWindow(BOOL fShow)
+{
+ TestDebugOut("In IOCS::OnShowWindow\r\n");
+ m_pSite->m_fObjectOpen = fShow;
+ InvalidateRect(m_pSite->m_lpDoc->m_hDocWnd, NULL, TRUE);
+
+ // if object window is closing, then bring container window to top
+ if (! fShow) {
+ BringWindowToTop(m_pSite->m_lpDoc->m_hDocWnd);
+ SetFocus(m_pSite->m_lpDoc->m_hDocWnd);
+ }
+ return ResultFromScode(S_OK);
+}
+
+//**********************************************************************
+//
+// COleClientSite::RequestNewObjectLayout
+//
+// Purpose:
+//
+// Not Implemented
+//
+// Parameters:
+//
+// Not Implemented
+//
+// Return Value:
+//
+// Not Implemented
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+// Comments:
+//
+// Not Implemented
+//
+//********************************************************************
+
+STDMETHODIMP COleClientSite::RequestNewObjectLayout()
+{
+ TestDebugOut("In IOCS::RequestNewObjectLayout\r\n");
+ return ResultFromScode(E_NOTIMPL);
+}
diff --git a/private/oleutest/utests16/simpdnd/iocs.h b/private/oleutest/utests16/simpdnd/iocs.h
new file mode 100644
index 000000000..00b6fa742
--- /dev/null
+++ b/private/oleutest/utests16/simpdnd/iocs.h
@@ -0,0 +1,44 @@
+//**********************************************************************
+// File name: IOCS.H
+//
+// Definition of COleClientSite
+//
+// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+#if !defined( _IOCS_H_ )
+#define _IOCS_H_
+
+#include <assert.h>
+
+class CSimpleSite;
+
+interface COleClientSite : public IOleClientSite
+{
+ int m_nCount;
+ CSimpleSite FAR * m_pSite;
+
+ COleClientSite(CSimpleSite FAR * pSite) {
+ TestDebugOut("In IOCS's constructor\r\n");
+ m_pSite = pSite;
+ m_nCount = 0;
+ }
+
+ ~COleClientSite() {
+ TestDebugOut("In IOCS's destructor\r\n");
+ assert(m_nCount == 0);
+ }
+
+ STDMETHODIMP QueryInterface(REFIID riid, LPVOID FAR* ppvObj);
+ STDMETHODIMP_(ULONG) AddRef();
+ STDMETHODIMP_(ULONG) Release();
+
+ // *** IOleClientSite methods ***
+ STDMETHODIMP SaveObject();
+ STDMETHODIMP GetMoniker(DWORD dwAssign, DWORD dwWhichMoniker, LPMONIKER FAR* ppmk);
+ STDMETHODIMP GetContainer(LPOLECONTAINER FAR* ppContainer);
+ STDMETHODIMP ShowObject();
+ STDMETHODIMP OnShowWindow(BOOL fShow);
+ STDMETHODIMP RequestNewObjectLayout();
+};
+
+#endif
diff --git a/private/oleutest/utests16/simpdnd/makefile b/private/oleutest/utests16/simpdnd/makefile
new file mode 100644
index 000000000..fd3bc375b
--- /dev/null
+++ b/private/oleutest/utests16/simpdnd/makefile
@@ -0,0 +1,94 @@
+#//+---------------------------------------------------------------------------
+#//
+#// Microsoft Windows
+#// Copyright (C) Microsoft Corporation, 1992 - 1994.
+#//
+#// File: makefile
+#// Contents: makefile for 16 bit spdnd16 for OLETHUNK unit test.
+#//
+#// History: 06-16-94 terryru Created
+#//
+#//----------------------------------------------------------------------------
+
+
+!IFDEF USEBUILD
+
+# If using BUILD.EXE, 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
+
+!ELSE
+
+default: copy_bin
+
+TARGET = spdnd16.exe
+TARGETTYPE = EXE
+OLETHUNK = $(_NTDRIVE)$(_NTROOT)\private\cairole\olethunk
+
+
+RCINC=$(RCINC) -i..\ole2ui -i..\ole2ui\res\usa
+
+CDEFINES= -I..\ole32ui /GEs
+
+LFLAGS= /STACK:16384
+
+CPPFILES = \
+ .\APP.cpp \
+ .\DOC.cpp \
+ .\DXFEROBJ.cpp \
+ .\IAS.cpp \
+ .\IDS.cpp \
+ .\IDT.cpp \
+ .\IOCS.cpp \
+ .\PRE.cpp \
+ .\SIMPDND.cpp \
+ .\SITE.cpp \
+ .\TESTS.cpp
+
+RCFILES = \
+ .\spdnd16.rc
+
+LIBS = $(LIBS)\
+ $(OLE16)\lib\ole2.lib \
+ $(OLE16)\lib\storage.lib \
+ $(OLE16)\lib\compobj.lib \
+ $(OLE16)\lib\loleuic.lib \
+ $(OLE16)\lib\shell.lib
+
+
+!include ..\makefile.inc
+
+copy_bin: all
+ binplace $(OBJDIR)\spdnd16.exe
+ binplace $(OBJDIR)\spdnd16.sym
+ binplace $(OBJDIR)\spdnd16.map
+
+
+
+app.obj: APP.cpp
+
+doc.obj: DOC.cpp
+
+DXFEROBJ.obj: DXFEROBJ.cpp
+
+IAS.obj: IAS.cpp
+
+IDS.obj: IDS.cpp
+
+IDT.obj: IDT.cpp
+
+IOCS.obj: IOCS.cpp
+
+PRE.obj: PRE.cpp
+
+SIMPDND.obj: SIMPDND.cpp
+
+SITE.obj: SITE.cpp
+
+TESTS.obj: TESTS.cpp
+
+
+
+!ENDIF
diff --git a/private/oleutest/utests16/simpdnd/pre.cpp b/private/oleutest/utests16/simpdnd/pre.cpp
new file mode 100644
index 000000000..9603f4089
--- /dev/null
+++ b/private/oleutest/utests16/simpdnd/pre.cpp
@@ -0,0 +1,9 @@
+//**********************************************************************
+// File name: pre.cpp
+//
+// Used for precompiled headers
+//
+// Copyright (c) 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+
+#include "pre.h"
diff --git a/private/oleutest/utests16/simpdnd/pre.h b/private/oleutest/utests16/simpdnd/pre.h
new file mode 100644
index 000000000..c97f3ab85
--- /dev/null
+++ b/private/oleutest/utests16/simpdnd/pre.h
@@ -0,0 +1,23 @@
+//**********************************************************************
+// File name: pre.h
+//
+// Used for precompiled headers
+//
+// Copyright (c) 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+
+#if !defined( _PRE_H_)
+#define _PRE_H_
+
+#include <windows.h>
+#include <ole2.h>
+#include <ole2ui.h>
+#include <assert.h>
+#include <string.h>
+#include "simpdnd.h"
+#include "resource.h"
+#include <ole2ver.h>
+
+extern "C" void TestDebugOut(LPSTR psz);
+
+#endif
diff --git a/private/oleutest/utests16/simpdnd/readme.txt b/private/oleutest/utests16/simpdnd/readme.txt
new file mode 100644
index 000000000..d9334a0ae
--- /dev/null
+++ b/private/oleutest/utests16/simpdnd/readme.txt
@@ -0,0 +1,5 @@
+ Simple Drag and Drop Sample
+
+ This sample demonstrates an implementation of OLE 2 drag and drop.
+For information on compiling and building the sample, see the makefile in
+this directory.
diff --git a/private/oleutest/utests16/simpdnd/resource.h b/private/oleutest/utests16/simpdnd/resource.h
new file mode 100644
index 000000000..8c8b12041
--- /dev/null
+++ b/private/oleutest/utests16/simpdnd/resource.h
@@ -0,0 +1,29 @@
+//{{NO_DEPENDENCIES}}
+// App Studio generated include file.
+// Used by SIMPDND.RC
+//
+#define IDM_OPEN 102
+#define IDC_DRAGPENDING 102
+#define IDM_SAVE 103
+#define IDM_SAVEAS 104
+#define IDM_PRINT 105
+#define IDM_EXIT 106
+#define IDM_UNDO 107
+#define IDM_CUT 108
+#define IDM_COPY 109
+#define IDM_PASTE 110
+#define ID_EDIT_INSERTOBJECT 111
+#define IDM_INSERTOBJECT 111
+#define IDM_NEW 112
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+
+#define _APS_NEXT_RESOURCE_VALUE 103
+#define _APS_NEXT_COMMAND_VALUE 113
+#define _APS_NEXT_CONTROL_VALUE 1000
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/private/oleutest/utests16/simpdnd/simpdnd.cpp b/private/oleutest/utests16/simpdnd/simpdnd.cpp
new file mode 100644
index 000000000..4f2f692d1
--- /dev/null
+++ b/private/oleutest/utests16/simpdnd/simpdnd.cpp
@@ -0,0 +1,452 @@
+//**********************************************************************
+// File name: Simple.cpp
+//
+// Main source file for the Simple OLE 2.0 object container
+//
+// Functions:
+//
+// WinMain - Program entry point
+// MainWndProc - Processes messages for the frame window
+// About - Processes messages for the about dialog
+// DocWndProc - Processes messages for the doc window
+//
+// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+
+#include "pre.h"
+#include "iocs.h"
+#include "ias.h"
+#include "app.h"
+#include "site.h"
+#include "doc.h"
+#include <testmess.h>
+#include <stdlib.h>
+#include "tests.h"
+
+// This line is needed for the debug utilities in OLE2UI
+extern "C" {
+ OLEDBGDATA_MAIN("SIMPDND")
+}
+
+CSimpleApp FAR * lpCSimpleApp;
+BOOL fBeVerbose = FALSE;
+extern "C"
+void TestDebugOut(LPSTR psz)
+{
+ if (fBeVerbose)
+ {
+ OutputDebugString(psz);
+ }
+}
+
+//**********************************************************************
+//
+// WinMain
+//
+// Purpose:
+//
+// Program entry point
+//
+// Parameters:
+//
+// HANDLE hInstance - Instance handle for this instance
+//
+// HANDLE hPrevInstance - Instance handle for the last instance
+//
+// LPSTR lpCmdLine - Pointer to the command line
+//
+// int nCmdShow - Window State
+//
+// Return Value:
+//
+// msg.wParam
+//
+// Function Calls:
+// Function Location
+//
+// CSimpleApp::CSimpleApp APP.CPP
+// CSimpleApp::fInitApplication APP.CPP
+// CSimpleApp::fInitInstance APP.CPP
+// CSimpleApp::HandleAccelerators APP.CPP
+// CSimpleApp::~CSimpleApp APP.CPP
+// OleUIInitialize OLE2UI
+// OleUIUninitialize OLE2UI
+// GetMessage Windows API
+// TranslateMessage Windows API
+// DispatchMessage Windows API
+//
+// Comments:
+//
+//********************************************************************
+
+int PASCAL WinMain(HANDLE hInstance,HANDLE hPrevInstance,LPSTR lpCmdLine,int nCmdShow)
+
+{
+ LPSTR pszTemp;
+ MSG msg;
+ fBeVerbose = GetProfileInt("OLEUTEST","BeVerbose",0);
+
+ if(fBeVerbose == 0)
+ {
+ fBeVerbose = GetProfileInt("OLEUTEST","spdnd16",0);
+ }
+
+ // needed for LRPC to work properly...
+ SetMessageQueue(96);
+
+ lpCSimpleApp = new CSimpleApp;
+
+ // we will add one ref count on our App. later when we want to destroy
+ // the App object we will release this ref count. when the App's ref
+ // count goes to 0, it will be deleted.
+ lpCSimpleApp->AddRef();
+
+ // process the command line
+
+ if( (pszTemp = strstr(lpCmdLine, "-driver")) )
+ {
+ //we were launched by the test driver
+ lpCSimpleApp->m_hDriverWnd = (HWND)strtoul(pszTemp+8, NULL, 10);
+ }
+
+
+
+ // app initialization
+ if (!hPrevInstance)
+ if (!lpCSimpleApp->fInitApplication(hInstance))
+ return (FALSE);
+
+ // instance initialization
+ if (!lpCSimpleApp->fInitInstance(hInstance, nCmdShow))
+ return (FALSE);
+
+ /* Initialization required for OLE 2 UI library. This call is
+ ** needed ONLY if we are using the static link version of the UI
+ ** library. If we are using the DLL version, we should NOT call
+ ** this function in our application.
+ */
+ if (!OleUIInitialize(hInstance, hPrevInstance))
+ {
+ OleDbgOut("Could not initialize OLEUI library\n");
+ return FALSE;
+ }
+
+ // message loop
+ while (GetMessage(&msg, NULL, NULL, NULL))
+ if (!lpCSimpleApp->HandleAccelerators(&msg))
+ {
+ TranslateMessage(&msg); /* Translates virtual key codes */
+ DispatchMessage(&msg); /* Dispatches message to window */
+ }
+
+ // De-initialization for UI libraries. Just like OleUIInitialize, this
+ // funciton is needed ONLY if we are using the static link version of the
+ // OLE UI library.
+ OleUIUninitialize();
+
+ // Release the ref count added on the App above. this will make
+ // the App's ref count go to 0, and the App object will be deleted.
+ lpCSimpleApp->Release();
+
+ return (msg.wParam); /* Returns the value from PostQuitMessage */
+}
+
+
+//**********************************************************************
+//
+// MainWndProc
+//
+// Purpose:
+//
+// Processes messages for the frame window
+//
+// Parameters:
+//
+// HWND hWnd - Window handle for frame window
+//
+// UINT message - Message value
+//
+// WPARAM wParam - Message info
+//
+// LPARAM lParam - Message info
+//
+// Return Value:
+//
+// long
+//
+// Function Calls:
+// Function Location
+//
+// CSimpleApp::lCommandHandler APP.CPP
+// CSimpleApp::DestroyDocs APP.CPP
+// CSimpleApp::lCreateDoc APP.CPP
+// CSimpleApp::lSizeHandler APP.CPP
+// CSimpleDoc::lAddVerbs DOC.CPP
+// PostQuitMessage Windows API
+// DefWindowProc Windows API
+//
+// Comments:
+//
+//********************************************************************
+
+long FAR PASCAL _export MainWndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)
+
+{
+
+ switch (message)
+ {
+ case WM_TEST2:
+ StartTest2(lpCSimpleApp);
+ break;
+ case WM_TEST1:
+ StartTest1(lpCSimpleApp);
+ break;
+ case WM_CLOSE:
+ DestroyWindow(lpCSimpleApp->m_hAppWnd);
+ break;
+
+
+ case WM_COMMAND: // message: command from application menu
+ return lpCSimpleApp->lCommandHandler(hWnd, message, wParam, lParam);
+ break;
+
+ case WM_CREATE:
+ return lpCSimpleApp->lCreateDoc(hWnd, message, wParam, lParam);
+ break;
+
+ case WM_DESTROY: // message: window being destroyed
+ lpCSimpleApp->DestroyDocs(); // need to destroy the doc...
+ PostQuitMessage(0);
+ break;
+
+ case WM_INITMENUPOPUP:
+ // is this the edit menu?
+ if ( LOWORD(lParam) == 1)
+ return lpCSimpleApp->m_lpDoc->lAddVerbs();
+
+ break;
+
+ case WM_SIZE:
+ return lpCSimpleApp->lSizeHandler(hWnd, message, wParam, lParam);
+
+ default: // Passes it on if unproccessed
+ return (DefWindowProc(hWnd, message, wParam, lParam));
+ }
+ return (NULL);
+}
+
+
+//**********************************************************************
+//
+// About
+//
+// Purpose:
+//
+// Processes dialog box messages
+//
+// Parameters:
+//
+// HWND hWnd - Window handle for dialog box
+//
+// UINT message - Message value
+//
+// WPARAM wParam - Message info
+//
+// LPARAM lParam - Message info
+//
+// Return Value:
+//
+// Function Calls:
+// Function Location
+//
+// EndDialog Windows API
+//
+// Comments:
+//
+//********************************************************************
+
+BOOL FAR PASCAL _export About(HWND hDlg,unsigned message,WORD wParam,LONG lParam)
+
+{
+ switch (message) {
+ case WM_INITDIALOG: /* message: initialize dialog box */
+ return (TRUE);
+
+ case WM_COMMAND: /* message: received a command */
+ if (wParam == IDOK /* "OK" box selected? */
+ || wParam == IDCANCEL) { /* System menu close command? */
+ EndDialog(hDlg, TRUE); /* Exits the dialog box */
+ return (TRUE);
+ }
+ break;
+ }
+ return (FALSE); /* Didn't process a message */
+}
+
+//**********************************************************************
+//
+// DocWndProc
+//
+// Purpose:
+//
+// Processes dialog box messages
+//
+// Parameters:
+//
+// HWND hWnd - Window handle for doc window
+//
+// UINT message - Message value
+//
+// WPARAM wParam - Message info
+//
+// LPARAM lParam - Message info
+//
+// Return Value:
+//
+// Function Calls:
+// Function Location
+//
+// CSimpleApp::PaintApp APP.CPP
+// BeginPaint Windows API
+// EndPaint Windows API
+// DefWindowProc Windows API
+// IOleObject::QueryInterface Object
+// IOleObject::DoVerb Object
+// CSimpleSite::GetObjRect SITE.CPP
+// CSimpleDoc::QueryDrag DOC.CPP
+// CSimpleDoc::DoDragDrop DOC.CPP
+// SetTimer Windows API
+// KillTimer Windows API
+// SetCapture Windows API
+// ReleaseCapture Windows API
+//
+// Comments:
+//
+//********************************************************************
+
+long FAR PASCAL _export DocWndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)
+{
+ HDC hDC;
+ PAINTSTRUCT ps;
+
+ switch (message) {
+ case WM_PAINT:
+
+ hDC = BeginPaint(hWnd, &ps);
+
+ if (lpCSimpleApp)
+ lpCSimpleApp->PaintApp (hDC);
+
+ EndPaint(hWnd, &ps);
+ break;
+
+ case WM_LBUTTONDBLCLK:
+ {
+ POINT pt;
+
+ pt.x = (int)(short)LOWORD (lParam );
+ pt.y = (int)(short)HIWORD (lParam );
+
+ if (lpCSimpleApp->m_lpDoc->m_lpSite &&
+ lpCSimpleApp->m_lpDoc->m_lpSite->m_lpOleObject)
+ {
+ RECT rect;
+
+ lpCSimpleApp->m_lpDoc->m_lpSite->GetObjRect(&rect);
+
+ if ( PtInRect(&rect, pt) )
+ {
+ // Execute object's default verb
+ lpCSimpleApp->m_lpDoc->m_lpSite->m_lpOleObject->DoVerb(
+ OLEIVERB_PRIMARY, (LPMSG)&message,
+ &lpCSimpleApp->m_lpDoc->m_lpSite->m_OleClientSite,
+ -1, hWnd, &rect);
+ }
+ }
+ }
+ break;
+
+ case WM_LBUTTONDOWN:
+ {
+ POINT pt;
+
+ pt.x = (int)(short)LOWORD (lParam );
+ pt.y = (int)(short)HIWORD (lParam );
+
+ /* OLE2NOTE: check if this is a button down on the region
+ ** that is a handle to start a drag operation. for us,
+ ** this this is any where in the window. we
+ ** do NOT want to start a drag immediately; we want to
+ ** wait until the mouse moves a certain threshold. or a
+ ** certain amount of time has elapsed. if
+ ** LButtonUp comes before the drag is started, then
+ ** the fPendingDrag state is cleared. we must capture
+ ** the mouse to ensure the modal state is handled
+ ** properly.
+ */
+ if (lpCSimpleApp->m_lpDoc->QueryDrag(pt) )
+ {
+ lpCSimpleApp->m_lpDoc->m_fPendingDrag = TRUE;
+ lpCSimpleApp->m_lpDoc->m_ptButDown = pt;
+ SetTimer(hWnd, 1, lpCSimpleApp->m_nDragDelay, NULL);
+ SetCapture(hWnd);
+ }
+ break;
+ }
+
+ case WM_LBUTTONUP:
+
+ if (lpCSimpleApp->m_lpDoc->m_fPendingDrag)
+ {
+ /* ButtonUP came BEFORE distance/time threshholds were
+ ** exceeded. clear fPendingDrag state.
+ */
+ ReleaseCapture();
+ KillTimer(hWnd, 1);
+ lpCSimpleApp->m_lpDoc->m_fPendingDrag = FALSE;
+ }
+ break;
+
+ case WM_MOUSEMOVE:
+ {
+ if (lpCSimpleApp->m_lpDoc->m_fPendingDrag)
+ {
+ int x = (int)(short)LOWORD (lParam );
+ int y = (int)(short)HIWORD (lParam );
+ POINT pt = lpCSimpleApp->m_lpDoc->m_ptButDown;
+ int nDragMinDist = lpCSimpleApp->m_nDragMinDist;
+
+ if (! ( ((pt.x - nDragMinDist) <= x)
+ && (x <= (pt.x + nDragMinDist))
+ && ((pt.y - nDragMinDist) <= y)
+ && (y <= (pt.y + nDragMinDist)) ) )
+ {
+ // mouse moved beyond threshhold to start drag
+ ReleaseCapture();
+ KillTimer(hWnd, 1);
+ lpCSimpleApp->m_lpDoc->m_fPendingDrag = FALSE;
+
+ // perform the modal drag/drop operation.
+ lpCSimpleApp->m_lpDoc->DoDragDrop( );
+ }
+ }
+ break;
+ }
+
+ case WM_TIMER:
+ {
+ // drag time delay threshhold exceeded -- start drag
+ ReleaseCapture();
+ KillTimer(hWnd, 1);
+ lpCSimpleApp->m_lpDoc->m_fPendingDrag = FALSE;
+
+ // perform the modal drag/drop operation.
+ lpCSimpleApp->m_lpDoc->DoDragDrop( );
+ break;
+ }
+
+ default: /* Passes it on if unproccessed */
+ return (DefWindowProc(hWnd, message, wParam, lParam));
+ }
+ return (NULL);
+}
diff --git a/private/oleutest/utests16/simpdnd/simpdnd.h b/private/oleutest/utests16/simpdnd/simpdnd.h
new file mode 100644
index 000000000..d1f9c347a
--- /dev/null
+++ b/private/oleutest/utests16/simpdnd/simpdnd.h
@@ -0,0 +1,15 @@
+//**********************************************************************
+// File name: simpdnd.h
+//
+// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+#define IDM_ABOUT 100
+#define IDM_INSERT 101
+#define IDM_VERB0 1000
+
+int PASCAL WinMain(HANDLE hInstance,HANDLE hPrevInstance,LPSTR lpCmdLine,int nCmdShow);
+BOOL InitApplication(HANDLE hInstance);
+BOOL InitInstance(HANDLE hInstance, int nCmdShow);
+long FAR PASCAL _export MainWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
+long FAR PASCAL _export DocWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
+BOOL FAR PASCAL _export About(HWND hDlg, unsigned message, WORD wParam, LONG lParam);
diff --git a/private/oleutest/utests16/simpdnd/simpdnd.ico b/private/oleutest/utests16/simpdnd/simpdnd.ico
new file mode 100644
index 000000000..c5aceb582
--- /dev/null
+++ b/private/oleutest/utests16/simpdnd/simpdnd.ico
Binary files differ
diff --git a/private/oleutest/utests16/simpdnd/site.cpp b/private/oleutest/utests16/simpdnd/site.cpp
new file mode 100644
index 000000000..df2b2746e
--- /dev/null
+++ b/private/oleutest/utests16/simpdnd/site.cpp
@@ -0,0 +1,627 @@
+//**********************************************************************
+// File name: SITE.CPP
+//
+// Implementation file for CSimpleSite
+//
+// Functions:
+//
+// See SITE.H for class definition
+//
+// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+
+#include "pre.h"
+#include "iocs.h"
+#include "ias.h"
+#include "app.h"
+#include "site.h"
+#include "doc.h"
+
+//**********************************************************************
+//
+// CSimpleSite::Create
+//
+// Purpose:
+//
+// Creation routine for CSimpleSite
+//
+// Parameters:
+//
+// CSimpleDoc FAR *lpDoc - Pointer to CSimpleDoc
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// IStorage::CreateStorage OLE API
+// assert C Runtime
+//
+// Comments:
+//
+//********************************************************************
+
+CSimpleSite FAR * CSimpleSite::Create(CSimpleDoc FAR *lpDoc)
+{
+ CSimpleSite FAR * lpTemp = new CSimpleSite(lpDoc);
+
+ if (!lpTemp)
+ return NULL;
+
+ // create a sub-storage for the object
+ HRESULT hErr = lpDoc->m_lpStorage->CreateStorage( "Object",
+ STGM_READWRITE | STGM_TRANSACTED | STGM_SHARE_EXCLUSIVE,
+ 0,
+ 0,
+ &lpTemp->m_lpObjStorage);
+
+ assert(hErr == NOERROR);
+
+ if (hErr != NOERROR)
+ {
+ delete lpTemp;
+ return NULL;
+ }
+
+ // we will add one ref count on our Site. later when we want to destroy
+ // the Site object we will release this ref count. when the Site's ref
+ // count goes to 0, it will be deleted.
+ lpTemp->AddRef();
+
+ return lpTemp;
+}
+
+//**********************************************************************
+//
+// CSimpleSite::CSimpleSite
+//
+// Purpose:
+//
+// Constructor for CSimpleSite
+//
+// Parameters:
+//
+// CSimpleDoc FAR *lpDoc - Pointer to CSimpleDoc
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// Comments:
+//
+//********************************************************************
+#pragma warning(disable : 4355) // turn off this warning. This warning
+ // tells us that we are passing this in
+ // an initializer, before "this" is through
+ // initializing. This is ok, because
+ // we just store the ptr in the other
+ // constructors
+
+CSimpleSite::CSimpleSite (CSimpleDoc FAR *lpDoc) : m_OleClientSite(this),
+ m_AdviseSink(this)
+#pragma warning (default : 4355) // Turn the warning back on
+{
+ // remember the pointer to the doc
+ m_lpDoc = lpDoc;
+
+ // clear the reference count
+ m_nCount = 0;
+
+ m_dwDrawAspect = DVASPECT_CONTENT;
+ m_lpOleObject = NULL;
+ m_fObjectOpen = FALSE;
+}
+
+//**********************************************************************
+//
+// CSimpleSite::~CSimpleSite
+//
+// Purpose:
+//
+// Destructor for CSimpleSite
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// IOleObject::Release Object
+// IStorage::Release OLE API
+//
+// Comments:
+//
+//********************************************************************
+
+CSimpleSite::~CSimpleSite ()
+{
+ TestDebugOut ("In CSimpleSite's Destructor \r\n");
+
+ if (m_lpOleObject)
+ m_lpOleObject->Release();
+
+ if (m_lpObjStorage)
+ m_lpObjStorage->Release();
+}
+
+
+//**********************************************************************
+//
+// CSimpleSite::CloseOleObject
+//
+// Purpose:
+//
+// Call IOleObject::Close on the object of the CSimpleSite
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// IOleObject::Close Object
+//
+// Comments:
+//
+//********************************************************************
+
+void CSimpleSite::CloseOleObject (void)
+{
+ LPVIEWOBJECT lpViewObject = NULL;
+
+ TestDebugOut ("In CSimpleSite::CloseOleObject \r\n");
+
+ if (m_lpOleObject)
+ {
+ m_lpOleObject->Close(OLECLOSE_NOSAVE);
+ }
+}
+
+
+//**********************************************************************
+//
+// CSimpleSite::UnloadOleObject
+//
+// Purpose:
+//
+// Close and release all pointers to the object of the CSimpleSite
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// CSimpleSite::CloseOleObject SITE.CPP
+// IOleObject::QueryInterface Object
+// IViewObject::SetAdvise Object
+// IViewObject::Release Object
+// IStorage::Release OLE API
+//
+// Comments:
+//
+//********************************************************************
+
+void CSimpleSite::UnloadOleObject (void)
+{
+ TestDebugOut ("In CSimpleSite::UnloadOleObject \r\n");
+
+ if (m_lpOleObject)
+ {
+ LPVIEWOBJECT lpViewObject;
+ CloseOleObject(); // ensure object is closed; NOP if already closed
+
+ m_lpOleObject->QueryInterface(IID_IViewObject, (LPVOID FAR *)&lpViewObject);
+
+ if (lpViewObject)
+ {
+ // Remove the view advise
+ lpViewObject->SetAdvise(m_dwDrawAspect, 0, NULL);
+ lpViewObject->Release();
+ }
+
+ m_lpOleObject->Release();
+ m_lpOleObject = NULL;
+ }
+}
+
+
+//**********************************************************************
+//
+// CSimpleSite::QueryInterface
+//
+// Purpose:
+//
+// Used for interface negotiation of the container Site.
+//
+// Parameters:
+//
+// REFIID riid - A reference to the interface that is
+// being queried.
+//
+// LPVOID FAR* ppvObj - An out parameter to return a pointer to
+// the interface.
+//
+// Return Value:
+//
+// S_OK - The interface is supported.
+// S_FALSE - The interface is not supported
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// IsEqualIID OLE API
+// ResultFromScode OLE API
+// CSimpleSite::AddRef OBJ.CPP
+// COleClientSite::AddRef IOCS.CPP
+// CAdviseSink::AddRef IAS.CPP
+//
+// Comments:
+//
+//
+//********************************************************************
+
+STDMETHODIMP CSimpleSite::QueryInterface(REFIID riid, LPVOID FAR* ppvObj)
+{
+ TestDebugOut("In CSimpleSite::QueryInterface\r\n");
+
+ *ppvObj = NULL; // must set out pointer parameters to NULL
+
+ if ( riid == IID_IUnknown)
+ {
+ AddRef();
+ *ppvObj = this;
+ return ResultFromScode(S_OK);
+ }
+
+ if ( riid == IID_IOleClientSite)
+ {
+ m_OleClientSite.AddRef();
+ *ppvObj = &m_OleClientSite;
+ return ResultFromScode(S_OK);
+ }
+
+ if ( riid == IID_IAdviseSink)
+ {
+ m_AdviseSink.AddRef();
+ *ppvObj = &m_AdviseSink;
+ return ResultFromScode(S_OK);
+ }
+
+ // Not a supported interface
+ return ResultFromScode(E_NOINTERFACE);
+}
+
+//**********************************************************************
+//
+// CSimpleSite::AddRef
+//
+// Purpose:
+//
+// Increments the reference count of the container Site.
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// ULONG - The new reference count of the site.
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+// Comments:
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) CSimpleSite::AddRef()
+{
+ TestDebugOut("In CSimpleSite::AddRef\r\n");
+
+ return ++m_nCount;
+}
+
+//**********************************************************************
+//
+// CSimpleSite::Release
+//
+// Purpose:
+//
+// Decrements the reference count of the container Site
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// ULONG - The new reference count of the Site.
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+// Comments:
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) CSimpleSite::Release()
+{
+ TestDebugOut("In CSimpleSite::Release\r\n");
+
+ if (--m_nCount == 0) {
+ delete this;
+ return 0;
+ }
+ return m_nCount;
+}
+
+//**********************************************************************
+//
+// CSimpleSite::InitObject
+//
+// Purpose:
+//
+// Used to initialize a newly create object (can't be done in the
+// constructor).
+//
+// Parameters:
+//
+// BOOL fCreateNew - TRUE if insert NEW object
+// FALSE if create object FROM FILE
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// IOleObject::SetHostNames Object
+// IOleObject::QueryInterface Object
+// IViewObject2::GetExtent Object
+// IOleObject::DoVerb Object
+// IViewObject::SetAdvise Object
+// IViewObject::Release Object
+// GetClientRect Windows API
+// OleSetContainedObject OLE API
+//
+// Comments:
+//
+//********************************************************************
+
+HRESULT CSimpleSite::InitObject(BOOL fCreateNew)
+{
+ LPVIEWOBJECT2 lpViewObject2;
+ RECT rect;
+ HRESULT hRes;
+
+ // Set a View Advise
+ hRes = m_lpOleObject->QueryInterface(IID_IViewObject2,
+ (LPVOID FAR *)&lpViewObject2);
+ if (hRes == ResultFromScode(S_OK))
+ {
+ hRes = lpViewObject2->SetAdvise(m_dwDrawAspect, ADVF_PRIMEFIRST,
+ &m_AdviseSink);
+
+ if( FAILED(hRes))
+ {
+ goto errRtn;
+ }
+ // get the initial size of the object
+
+ hRes = lpViewObject2->GetExtent(m_dwDrawAspect, -1 /*lindex*/, NULL /*ptd*/,
+ &m_sizel);
+
+ //
+ // Is OK if the object is actually blank
+ //
+ if( FAILED(hRes) && (GetScode(hRes) != OLE_E_BLANK) )
+ {
+ goto errRtn;
+ }
+
+ lpViewObject2->Release();
+ }
+ GetObjRect(&rect); // get the rectangle of the object in pixels
+
+ // give the object the name of the container app/document
+ hRes = m_lpOleObject->SetHostNames("Simple Application",
+ "Simple OLE 2.0 Drag/Drop Container");
+
+ if( FAILED(hRes) )
+ {
+ goto errRtn;
+ }
+
+ // inform object handler/DLL object that it is used in the embedding
+ // container's context
+ if (OleSetContainedObject(m_lpOleObject, TRUE) != ResultFromScode(S_OK))
+ {
+ TestDebugOut("Fail in OleSetContainedObject\n");
+ }
+
+ if (fCreateNew)
+ {
+ // force new object to save to guarantee valid object in our storage.
+ // OLE 1.0 objects may close w/o saving. this is NOT necessary if the
+ // object is created FROM FILE; its data in storage is already valid.
+ m_OleClientSite.SaveObject();
+
+ // we only want to DoVerb(SHOW) if this is an InsertNew object.
+ // we should NOT DoVerb(SHOW) if the object is created FromFile.
+ hRes = m_lpOleObject->DoVerb(
+ OLEIVERB_SHOW,
+ NULL,
+ &m_OleClientSite,
+ -1,
+ m_lpDoc->m_hDocWnd,
+ &rect);
+ }
+
+errRtn:
+ return hRes;
+
+}
+
+//**********************************************************************
+//
+// CSimpleSite::PaintObj
+//
+// Purpose:
+//
+// Paints the object
+//
+// Parameters:
+//
+// HDC hDC - Device context of the document window
+//
+// Return Value:
+//
+// Function Calls:
+// Function Location
+//
+// IOleObject::QueryInterface Object
+// IViewObject::GetColorSet Object
+// IViewObject::Release Object
+// SetMapMode Windows API
+// LPtoDP Windows API
+// CreateHatchBrush Windows API
+// SelectObject Windows API
+// DeleteObject Windows API
+// CreatePalette Windows API
+// SelectPalette Windows API
+// RealizePalette Windows API
+// OleStdFree OUTLUI Function
+// OleDraw OLE API
+//
+// Comments:
+//
+//********************************************************************
+
+void CSimpleSite::PaintObj(HDC hDC)
+{
+RECT rect;
+
+ // need to check to make sure there is a valid object
+ // available. This is needed if there is a paint msg
+ // between the time that CSimpleSite is instantiated
+ // and OleUIInsertObject returns.
+ if (!m_lpOleObject)
+ return;
+
+ // convert it to pixels
+ GetObjRect(&rect);
+
+ LPLOGPALETTE pColorSet = NULL;
+ LPVIEWOBJECT lpView = NULL;
+
+ // get a pointer to IViewObject
+ m_lpOleObject->QueryInterface(IID_IViewObject,(LPVOID FAR *) &lpView);
+
+ // if the QI succeeds, get the LOGPALETTE for the object
+ if (lpView)
+ lpView->GetColorSet(m_dwDrawAspect, -1, NULL, NULL, NULL, &pColorSet);
+
+ HPALETTE hPal=NULL;
+ HPALETTE hOldPal=NULL;
+
+ // if a LOGPALETTE was returned (not guarateed), create the palette and
+ // realize it. NOTE: A smarter application would want to get the LOGPALETTE
+ // for each of its visible objects, and try to create a palette that
+ // satisfies all of the visible objects. ALSO: OleStdFree() is use to
+ // free the returned LOGPALETTE.
+ if ((pColorSet))
+ {
+ hPal = CreatePalette((const LPLOGPALETTE) pColorSet);
+ hOldPal = SelectPalette(hDC, hPal, FALSE);
+ RealizePalette(hDC);
+ OleStdFree(pColorSet);
+ }
+
+ // draw the object
+ OleDraw(m_lpOleObject, m_dwDrawAspect, hDC, &rect);
+
+ // if the object is open, draw a hatch rect.
+ if (m_fObjectOpen)
+ {
+ HBRUSH hBrush = CreateHatchBrush ( HS_BDIAGONAL, RGB(0,0,0) );
+ HBRUSH hOldBrush = SelectObject (hDC, hBrush);
+ SetROP2(hDC, R2_MASKPEN);
+ Rectangle (hDC, rect.left, rect.top, rect.right, rect.bottom);
+ SelectObject(hDC, hOldBrush);
+ DeleteObject(hBrush);
+ }
+
+ // if we created a palette, restore the old one, and destroy
+ // the object.
+ if (hPal)
+ {
+ SelectPalette(hDC,hOldPal,FALSE);
+ DeleteObject(hPal);
+ }
+
+ // if a view pointer was successfully returned, it needs to be released.
+ if (lpView)
+ lpView->Release();
+}
+
+//**********************************************************************
+//
+// CSimpleSite::GetObjRect
+//
+// Purpose:
+//
+// Retrieves the rect of the object in pixels
+//
+// Parameters:
+//
+// LPRECT lpRect - Rect structure filled with object's rect in pixels
+//
+// Return Value:
+//
+// Function Calls:
+// Function Location
+//
+// XformWidthInHimetricToPixels OUTLUI Function
+// XformHeightInHimetricToPixels OUTLUI Function
+//
+// Comments:
+//
+//********************************************************************
+
+void CSimpleSite::GetObjRect(LPRECT lpRect)
+{
+ // convert it to pixels
+ lpRect->left = lpRect->top = 0;
+ lpRect->right = XformWidthInHimetricToPixels(NULL,(int)m_sizel.cx);
+ lpRect->bottom = XformHeightInHimetricToPixels(NULL,(int)m_sizel.cy);
+}
diff --git a/private/oleutest/utests16/simpdnd/site.h b/private/oleutest/utests16/simpdnd/site.h
new file mode 100644
index 000000000..ebd3e5800
--- /dev/null
+++ b/private/oleutest/utests16/simpdnd/site.h
@@ -0,0 +1,47 @@
+//**********************************************************************
+// File name: SITE.H
+//
+// Definition of CSimpleSite
+//
+// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+#if !defined( _SITE_H_ )
+#define _SITE_H_
+
+#include <ole2.h>
+#include "ias.h"
+#include "iocs.h"
+
+class CSimpleDoc;
+
+class CSimpleSite : public IUnknown
+{
+public:
+ int m_nCount;
+ LPOLEOBJECT m_lpOleObject;
+ DWORD m_dwDrawAspect;
+ SIZEL m_sizel;
+ BOOL m_fObjectOpen;
+ LPSTORAGE m_lpObjStorage;
+
+ CAdviseSink m_AdviseSink;
+ COleClientSite m_OleClientSite;
+
+ CSimpleDoc FAR * m_lpDoc;
+
+ // IUnknown Interfaces
+ STDMETHODIMP QueryInterface(REFIID riid, LPVOID FAR* ppvObj);
+ STDMETHODIMP_(ULONG) AddRef();
+ STDMETHODIMP_(ULONG) Release();
+
+ HRESULT InitObject(BOOL fCreateNew);
+ static CSimpleSite FAR * Create(CSimpleDoc FAR *lpDoc);
+ CSimpleSite(CSimpleDoc FAR *lpDoc);
+ ~CSimpleSite();
+ void PaintObj(HDC hDC);
+ void GetObjRect(LPRECT lpRect);
+ void CloseOleObject(void);
+ void UnloadOleObject(void);
+};
+
+#endif // _SITE_H_
diff --git a/private/oleutest/utests16/simpdnd/spdnd16.def b/private/oleutest/utests16/simpdnd/spdnd16.def
new file mode 100644
index 000000000..5c3ffbd1a
--- /dev/null
+++ b/private/oleutest/utests16/simpdnd/spdnd16.def
@@ -0,0 +1,22 @@
+; module-definition file for generic -- used by LINK.EXE
+
+NAME SpDnd16 ; application's module name
+
+DESCRIPTION 'Sample Microsoft Windows Application'
+
+EXETYPE WINDOWS ; required for all Windows applications
+
+STUB 'WINSTUB.EXE' ; Generates error message if application
+ ; is run without Windows
+
+;CODE can be moved in memory and discarded/reloaded
+CODE PRELOAD MOVEABLE DISCARDABLE
+
+;DATA must be MULTIPLE if program can be invoked more than once
+DATA PRELOAD MOVEABLE MULTIPLE
+
+
+HEAPSIZE 1024
+
+; All functions that will be called by any Windows routine
+; MUST be exported.
diff --git a/private/oleutest/utests16/simpdnd/spdnd16.rc b/private/oleutest/utests16/simpdnd/spdnd16.rc
new file mode 100644
index 000000000..0ff7b797b
--- /dev/null
+++ b/private/oleutest/utests16/simpdnd/spdnd16.rc
@@ -0,0 +1,105 @@
+//Microsoft App Studio generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#define APSTUDIO_HIDDEN_SYMBOLS
+#include "windows.h"
+#undef APSTUDIO_HIDDEN_SYMBOLS
+#include "simpdnd.h"
+
+/////////////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+SIMPDND ICON DISCARDABLE "SIMPDND.ICO"
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// Menu
+//
+
+SIMPLEMENU MENU DISCARDABLE
+BEGIN
+ POPUP "&File"
+ BEGIN
+ MENUITEM "&New", IDM_NEW
+ MENUITEM SEPARATOR
+ MENUITEM "E&xit", IDM_EXIT
+ END
+ POPUP "&Edit"
+ BEGIN
+ MENUITEM "&Copy", IDM_COPY
+ MENUITEM "&Insert Object...", IDM_INSERTOBJECT
+ END
+ POPUP "&Other"
+ BEGIN
+ MENUITEM "&About Simple...", IDM_ABOUT
+ END
+END
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+ABOUTBOX DIALOG DISCARDABLE 22, 17, 144, 75
+STYLE DS_MODALFRAME | WS_CAPTION | WS_SYSMENU
+CAPTION "About SimpDnD"
+FONT 8, "System"
+BEGIN
+ CTEXT "Simple OLE 2.0",-1,0,5,144,8
+ CTEXT "Drag/Drop Container Application",-1,0,14,144,8
+ CTEXT "Version 2.01",-1,0,34,144,8
+ DEFPUSHBUTTON "OK",IDOK,53,59,32,14,WS_GROUP
+END
+
+#ifdef APSTUDIO_INVOKED
+//////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "#define APSTUDIO_HIDDEN_SYMBOLS\r\n"
+ "#include ""windows.h""\r\n"
+ "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n"
+ "#include ""simpdnd.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "#include ""ole2ui.rc""\r\n"
+ "\0"
+END
+
+/////////////////////////////////////////////////////////////////////////////////////
+#endif // APSTUDIO_INVOKED
+
+
+#ifndef APSTUDIO_INVOKED
+////////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+#include "ole2ui.rc"
+
+/////////////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
diff --git a/private/oleutest/utests16/simpdnd/tests.cpp b/private/oleutest/utests16/simpdnd/tests.cpp
new file mode 100644
index 000000000..81b554ac8
--- /dev/null
+++ b/private/oleutest/utests16/simpdnd/tests.cpp
@@ -0,0 +1,202 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: tests.cpp
+//
+// Contents: Implementations of the Upper Layer unit tests
+//
+// Classes:
+//
+// Functions: StartTest1
+//
+// History: dd-mmm-yy Author Comment
+// 07-Feb-94 alexgo author
+//
+//--------------------------------------------------------------------------
+
+#include "pre.h"
+#include "iocs.h"
+#include "ias.h"
+#include "app.h"
+#include "site.h"
+#include "doc.h"
+#include <testmess.h>
+
+#ifdef WIN32
+const CLSID CLSID_SimpleServer = {0xbcf6d4a0, 0xbe8c, 0x1068, { 0xb6, 0xd4,
+ 0x00, 0xdd, 0x01, 0x0c, 0x05, 0x09 }};
+#else
+const CLSID CLSID_SimpleServer = {0x9fb878d0, 0x6f88, 0x101b, { 0xbc, 0x65,
+ 0x00, 0x00, 0x0b, 0x65, 0xc7, 0xa6 }};
+#endif
+
+
+
+const CLSID CLSID_Paintbrush = {0x0003000a, 0, 0, { 0xc0, 0,0,0,0,0,0,0x46 }};
+
+//+-------------------------------------------------------------------------
+//
+// Function: StartTest1
+//
+// Synopsis: Starts unit test1, inserting a simple server object into
+// this (simpdnd) container.
+//
+// Effects:
+//
+// Arguments: pApp -- a pointer to the CSimpleApp that we're a part of
+//
+// Requires:
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 07-Feb-94 alexgo author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+void StartTest1( CSimpleApp *pApp )
+{
+ HRESULT hresult;
+ static FORMATETC formatetc;
+
+ //insert the simple server object
+
+ formatetc.dwAspect = DVASPECT_CONTENT;
+ formatetc.cfFormat = NULL;
+ formatetc.lindex = -1;
+
+ //need to create the client site
+
+ pApp->m_lpDoc->m_lpSite = CSimpleSite::Create(pApp->m_lpDoc);
+
+ hresult = OleCreate(CLSID_SimpleServer, IID_IOleObject,
+ OLERENDER_DRAW, &formatetc,
+ &pApp->m_lpDoc->m_lpSite->m_OleClientSite,
+ pApp->m_lpDoc->m_lpSite->m_lpObjStorage,
+ (void **)&(pApp->m_lpDoc->m_lpSite->m_lpOleObject));
+
+ if( hresult != NOERROR )
+ {
+ goto errRtn;
+ }
+
+ //initialize the object
+
+ hresult = pApp->m_lpDoc->m_lpSite->InitObject(TRUE);
+
+ if( hresult == NOERROR )
+ {
+ //tell it to paint itself, then we'll quit
+ PostMessage(pApp->m_lpDoc->m_hDocWnd, WM_PAINT, 0L, 0L);
+ PostMessage(pApp->m_hDriverWnd, WM_TESTEND, TEST_SUCCESS,
+ (LPARAM)hresult);
+ PostMessage(pApp->m_hAppWnd, WM_SYSCOMMAND, SC_CLOSE, 0L);
+ return;
+ }
+
+errRtn:
+ PostMessage(pApp->m_hDriverWnd, WM_TESTEND, TEST_FAILURE,
+ (LPARAM)hresult);
+ PostMessage(pApp->m_hAppWnd, WM_SYSCOMMAND, SC_CLOSE, 0L);
+ return;
+}
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: StartTest2
+//
+// Synopsis: Starts unit Test2, inserting a paintbrush object into
+// this (simpdnd) container.
+//
+// Effects:
+//
+// Arguments: pApp -- a pointer to the CSimpleApp that we're a part of
+//
+// Requires:
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Algorithm:
+//
+// History: dd-mmm-yy Author Comment
+// 24-May-94 kevinro & alexgo author
+//
+// Notes:
+//
+//--------------------------------------------------------------------------
+
+void StartTest2( CSimpleApp *pApp )
+{
+ HRESULT hresult;
+ static FORMATETC formatetc;
+
+ //insert the simple server object
+
+ formatetc.dwAspect = DVASPECT_CONTENT;
+ formatetc.cfFormat = NULL;
+ formatetc.lindex = -1;
+
+ //need to create the client site
+
+ pApp->m_lpDoc->m_lpSite = CSimpleSite::Create(pApp->m_lpDoc);
+
+ hresult = OleCreate(CLSID_Paintbrush, IID_IOleObject,
+ OLERENDER_DRAW, &formatetc,
+ &pApp->m_lpDoc->m_lpSite->m_OleClientSite,
+ pApp->m_lpDoc->m_lpSite->m_lpObjStorage,
+ (void **)&(pApp->m_lpDoc->m_lpSite->m_lpOleObject));
+
+ if( hresult != NOERROR )
+ {
+ goto errRtn;
+ }
+
+ //initialize the object
+
+ hresult = pApp->m_lpDoc->m_lpSite->InitObject(TRUE);
+
+ //
+ // The DDE layer is going to ignore all of the parameters except
+ // the verb index. The parameters here are mostly dummies.
+ //
+ if (hresult == NOERROR)
+ {
+ hresult = pApp->m_lpDoc->m_lpSite->m_lpOleObject->DoVerb(0,
+ NULL,
+ &(pApp->m_lpDoc->m_lpSite->m_OleClientSite),
+ -1,
+ NULL,
+ NULL);
+ }
+
+ if( hresult == NOERROR )
+ {
+ //tell it to paint itself, then we'll quit
+ PostMessage(pApp->m_lpDoc->m_hDocWnd, WM_PAINT, 0L, 0L);
+ PostMessage(pApp->m_hDriverWnd, WM_TESTEND, TEST_SUCCESS,
+ (LPARAM)hresult);
+ PostMessage(pApp->m_hAppWnd, WM_SYSCOMMAND, SC_CLOSE, 0L);
+ return;
+ }
+
+errRtn:
+ PostMessage(pApp->m_hDriverWnd, WM_TESTEND, TEST_FAILURE,
+ (LPARAM)hresult);
+ PostMessage(pApp->m_hAppWnd, WM_SYSCOMMAND, SC_CLOSE, 0L);
+ return;
+}
diff --git a/private/oleutest/utests16/simpdnd/tests.h b/private/oleutest/utests16/simpdnd/tests.h
new file mode 100644
index 000000000..30d3b1baa
--- /dev/null
+++ b/private/oleutest/utests16/simpdnd/tests.h
@@ -0,0 +1,27 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: tests.h
+//
+// Contents: Declarations for the unit test functions
+//
+// Classes:
+//
+// Functions:
+//
+// History: dd-mmm-yy Author Comment
+// 07-Feb-94 alexgo author
+//
+//--------------------------------------------------------------------------
+
+#ifndef __TESTS_H
+#define __TESTS_H
+
+void StartTest1(CSimpleApp *);
+void StartTest2(CSimpleApp *);
+
+#endif
+
+
diff --git a/private/oleutest/utests16/simpsvr/app.cpp b/private/oleutest/utests16/simpsvr/app.cpp
new file mode 100644
index 000000000..745349e13
--- /dev/null
+++ b/private/oleutest/utests16/simpsvr/app.cpp
@@ -0,0 +1,810 @@
+//**********************************************************************
+// File name: app.cpp
+//
+// Implementation file for the CSimpSvrApp Class
+//
+// Functions:
+//
+// See app.h for a list of member functions.
+//
+// Copyright (c) 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+
+#include "pre.h"
+#include "obj.h"
+#include "app.h"
+#include "doc.h"
+#include "icf.h"
+
+#include "initguid.h"
+
+#ifdef WIN32
+DEFINE_GUID(GUID_SIMPLE, 0xBCF6D4A0, 0xBE8C, 0x1068, 0xB6, 0xD4, 0x00, 0xDD, 0x01, 0x0C, 0x05, 0x09);
+#else
+DEFINE_GUID(GUID_SIMPLE, 0x9fb878d0, 0x6f88, 0x101b, 0xbc, 0x65, 0x00, 0x00, 0x0b, 0x65, 0xc7, 0xa6);
+#endif
+
+
+
+//**********************************************************************
+//
+// CSimpSvrApp::CSimpSvrApp()
+//
+// Purpose:
+//
+// Constructor for CSimpSvrApp
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// SetRectEmpty Windows API
+//
+// Comments:
+//
+//
+//********************************************************************
+
+CSimpSvrApp::CSimpSvrApp()
+{
+ TestDebugOut("In CSimpSvrApp's Constructor \r\n");
+
+ // Set Ref Count
+ m_nCount = 0;
+
+ // clear members
+ m_hAppWnd = NULL;
+ m_hInst = NULL;
+ m_lpDoc = NULL;
+
+ // clear flags
+ m_fInitialized = FALSE;
+
+ // used for inplace
+ SetRectEmpty(&nullRect);
+}
+
+//**********************************************************************
+//
+// CSimpSvrApp::~CSimpSvrApp()
+//
+// Purpose:
+//
+// Destructor for CSimpSvrApp Class.
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// DestroyWindow Windows API
+// CSimpSvrApp::IsInitialized APP.H
+// OleUninitialize OLE API
+//
+// Comments:
+//
+//********************************************************************
+
+CSimpSvrApp::~CSimpSvrApp()
+{
+ TestDebugOut("In CSimpSvrApp's Destructor\r\n");
+
+ // need to uninit the library...
+ if (IsInitialized())
+ OleUninitialize();
+
+ DestroyWindow(m_hAppWnd);
+}
+
+
+//**********************************************************************
+//
+// CSimpSvrApp::QueryInterface
+//
+// Purpose:
+//
+// Used for interface negotiation at the Application level.
+//
+// Parameters:
+//
+// REFIID riid - A reference to the interface that is
+// being queried.
+//
+// LPVOID FAR* ppvObj - An out parameter to return a pointer to
+// the interface.
+//
+// Return Value:
+//
+// S_OK - The interface is supported.
+// E_NOINTERFACE - The interface is not supported
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// ResultFromScode OLE API
+// IUnknown::AddRef APP.CPP
+//
+// Comments:
+//
+//
+//********************************************************************
+
+STDMETHODIMP CSimpSvrApp::QueryInterface(REFIID riid, LPVOID FAR* ppvObj)
+{
+ TestDebugOut("In CSimpSvrApp::QueryInterface\r\n");
+
+ SCODE sc = S_OK;
+
+ if (riid == IID_IUnknown)
+ *ppvObj = this;
+ else
+ {
+ *ppvObj = NULL;
+ sc = E_NOINTERFACE;
+ }
+
+ if (*ppvObj)
+ ((LPUNKNOWN)*ppvObj)->AddRef();
+
+ // asking for something we don't understand at this level.
+ return ResultFromScode(sc);
+}
+
+//**********************************************************************
+//
+// CSimpSvrApp::AddRef
+//
+// Purpose:
+//
+// Adds to the reference count at the Application level.
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// ULONG - The new reference count of the application.
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+// Comments:
+//
+// Due to the reference counting model that is used in this
+// implementation, this reference count is the sum of the
+// reference counts on all interfaces of all objects open
+// in the application.
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) CSimpSvrApp::AddRef()
+{
+ TestDebugOut("In CSimpSvrApp::AddRef\r\n");
+ return ++m_nCount;
+}
+
+//**********************************************************************
+//
+// CSimpSvrApp::Release
+//
+// Purpose:
+//
+// Decrements the reference count at this level
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// ULONG - The new reference count of the application.
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+// Comments:
+//
+// Due to the reference counting model that is used in this
+// implementation, this reference count is the sum of the
+// reference counts on all interfaces of all objects open
+// in the application.
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) CSimpSvrApp::Release()
+{
+ TestDebugOut("In CSimpSvrApp::Release\r\n");
+
+ if (--m_nCount == 0) {
+ delete this;
+ return 0;
+ }
+
+ return m_nCount;
+}
+
+//**********************************************************************
+//
+// CSimpSvrApp::fInitApplication
+//
+// Purpose:
+//
+// Initializes the application
+//
+// Parameters:
+//
+// HANDLE hInstance - Instance handle of the application.
+//
+// Return Value:
+//
+// TRUE - Application was successfully initialized.
+// FALSE - Application could not be initialized
+//
+// Function Calls:
+// Function Location
+//
+// LoadIcon Windows API
+// LoadCursor Windows API
+// GetStockObject Windows API
+// RegisterClass Windows API
+// RegisterHatchWindowClass OUTLUI.DLL
+//
+// Comments:
+//
+//********************************************************************
+
+BOOL CSimpSvrApp::fInitApplication(HANDLE hInstance)
+{
+ WNDCLASS wc;
+
+ // Fill in window class structure with parameters that describe the
+ // main window.
+
+ wc.style = NULL; // Class style(s).
+ wc.lpfnWndProc = MainWndProc; // Function to retrieve messages for
+ // windows of this class.
+ wc.cbClsExtra = 0; // No per-class extra data.
+ wc.cbWndExtra = 0; // No per-window extra data.
+ wc.hInstance = hInstance; // Application that owns the class.
+ wc.hIcon = LoadIcon(hInstance, "SimpSvr");
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wc.hbrBackground = GetStockObject(WHITE_BRUSH);
+ wc.lpszMenuName = "SimpSvrMENU"; // Name of menu resource in .RC file.
+ wc.lpszClassName = "SimpSvrWClass"; // Name used in call to CreateWindow.
+
+ if (!RegisterClass(&wc))
+ return FALSE;
+
+ wc.style = CS_VREDRAW | CS_HREDRAW; // Class style(s).
+ wc.lpfnWndProc = DocWndProc; // Function to retrieve messages for
+ // windows of this class.
+ wc.cbClsExtra = 0; // No per-class extra data.
+ wc.cbWndExtra = 0; // No per-window extra data.
+ wc.hInstance = hInstance; // Application that owns the class.
+ wc.hIcon = NULL;
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wc.hbrBackground = GetStockObject(WHITE_BRUSH);
+ wc.lpszMenuName = NULL;
+ wc.lpszClassName = "DocWClass"; // Name used in call to CreateWindow.
+
+ // Register the window class and return success/failure code.
+
+ if (!RegisterClass(&wc))
+ return FALSE;
+
+ return (RegisterHatchWindowClass(hInstance));
+}
+
+//**********************************************************************
+//
+// CSimpSvrApp::fInitInstance
+//
+// Purpose:
+//
+// Instance initialization.
+//
+// Parameters:
+//
+// HANDLE hInstance - App. Instance Handle.
+//
+// int nCmdShow - Show parameter from WinMain
+//
+// Return Value:
+//
+// TRUE - Initialization Successful
+// FALSE - Initialization Failed.
+//
+//
+// Function Calls:
+// Function Location
+//
+// CreateWindow Windows API
+// InvalidateRect Windows API
+// ShowWindow Windows API
+// UpdateWindow Windows API
+// CoRegisterClassObject OLE API
+// OleBuildVersion OLE API
+// OleInitialize OLE API
+// CSimpSvrDoc::CreateObject DOC.CPP
+//
+// Comments:
+//
+// Note that successful Initalization of the OLE libraries
+// is remembered so the UnInit is only called if needed.
+//
+//********************************************************************
+
+BOOL CSimpSvrApp::fInitInstance (HANDLE hInstance, int nCmdShow, CClassFactory FAR * lpClassFactory)
+{
+ m_hInst = hInstance;
+
+ DWORD dwVer = OleBuildVersion();
+
+ // check to see if we are compatible with this version of the libraries
+ if (HIWORD(dwVer) != rmm || LOWORD(dwVer) < rup)
+ TestDebugOut("*** WARNING: Not compatible with current libs ***\r\n");
+
+ // initialize the libraries
+ if (OleInitialize(NULL) == NOERROR)
+ m_fInitialized = TRUE;
+
+
+ // Create the "application" windows
+ m_hAppWnd = CreateWindow ("SimpSvrWClass",
+ "Simple OLE 2.0 Server",
+ WS_OVERLAPPEDWINDOW,
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ NULL,
+ NULL,
+ hInstance,
+ NULL);
+
+ if (!m_hAppWnd)
+ return FALSE;
+
+ // if not started by OLE, then show the Window, and create a "fake" object, else
+ // Register a pointer to IClassFactory so that OLE can instruct us to make an
+ // object at the appropriate time.
+ if (!m_fStartByOle)
+ {
+ ShowAppWnd(nCmdShow);
+ m_lpDoc->CreateObject(IID_IOleObject, (LPVOID FAR *)&m_OleObject);
+ InvalidateRect(m_lpDoc->GethDocWnd(), NULL, TRUE);
+ }
+ else
+ {
+ lpClassFactory = new CClassFactory(this);
+
+ // shouldn't pass an API an object with a zero ref count
+ lpClassFactory->AddRef();
+
+ CoRegisterClassObject(GUID_SIMPLE,(IUnknown FAR *)lpClassFactory, CLSCTX_LOCAL_SERVER, REGCLS_SINGLEUSE, &m_dwRegisterClass);
+
+ // remove artificial Ref. count
+ lpClassFactory->Release();
+ }
+
+ m_hMainMenu = GetMenu(m_hAppWnd);
+ m_hColorMenu = GetSubMenu(m_hMainMenu, 1);
+ m_hHelpMenu = GetSubMenu(m_hMainMenu, 2);
+
+
+ return m_fInitialized;
+}
+
+//**********************************************************************
+//
+// CSimpSvrApp::lCommandHandler
+//
+// Purpose:
+//
+// Handles the processing of WM_COMMAND.
+//
+// Parameters:
+//
+// HWND hWnd - Handle to the application Window
+//
+// UINT message - message (always WM_COMMAND)
+//
+// WPARAM wParam - Same as passed to the WndProc
+//
+// LPARAM lParam - Same as passed to the WndProc
+//
+// Return Value:
+//
+// NULL
+//
+// Function Calls:
+// Function Location
+//
+// GetClientRect Windows API
+// MessageBox Windows API
+// DialogBox Windows API
+// MakeProcInstance Windows API
+// FreeProcInstance Windows API
+// SendMessage Windows API
+// DefWindowProc Windows API
+// InvalidateRect Windows API
+// CSimpSvrDoc::InsertObject DOC.CPP
+// CSimpSvrObj::SetColor OBJ.CPP
+// CSimpSvrObj::RotateColor OBJ.CPP
+//
+// Comments:
+//
+//********************************************************************
+
+long CSimpSvrApp::lCommandHandler (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ switch (wParam) {
+ // bring up the About box
+ case IDM_ABOUT:
+ {
+ FARPROC lpProcAbout = MakeProcInstance((FARPROC)About, m_hInst);
+
+ DialogBox(m_hInst, // current instance
+ "AboutBox", // resource to use
+ m_hAppWnd, // parent handle
+ lpProcAbout); // About() instance address
+
+ FreeProcInstance(lpProcAbout);
+ break;
+ }
+
+ // exit the application
+ case IDM_EXIT:
+ SendMessage(hWnd, WM_SYSCOMMAND, SC_CLOSE, 0L);
+ break;
+
+ case IDM_RED:
+ m_lpDoc->GetObj()->SetColor (128, 0, 0);
+ InvalidateRect(m_lpDoc->GethDocWnd(), NULL, TRUE);
+ break;
+
+ case IDM_GREEN:
+ m_lpDoc->GetObj()->SetColor (0,128, 0);
+ InvalidateRect(m_lpDoc->GethDocWnd(), NULL, TRUE);
+ break;
+
+ case IDM_BLUE:
+ m_lpDoc->GetObj()->SetColor (0, 0, 128);
+ InvalidateRect(m_lpDoc->GethDocWnd(), NULL, TRUE);
+ break;
+
+ case IDM_ROTATE:
+ m_lpDoc->GetObj()->RotateColor();
+ InvalidateRect(m_lpDoc->GethDocWnd(), NULL, TRUE);
+ break;
+
+ default:
+ return (DefWindowProc(hWnd, message, wParam, lParam));
+ } // end of switch
+ return NULL;
+}
+
+//**********************************************************************
+//
+// CSimpSvrApp::lSizeHandler
+//
+// Purpose:
+//
+// Handles the WM_SIZE message
+//
+// Parameters:
+//
+// HWND hWnd - Handle to the application Window
+//
+// UINT message - message (always WM_SIZE)
+//
+// WPARAM wParam - Same as passed to the WndProc
+//
+// LPARAM lParam - Same as passed to the WndProc
+//
+// Return Value:
+//
+// LONG - returned from the "document" resizing
+//
+// Function Calls:
+// Function Location
+//
+// GetClientRect Windows API
+// CSimpSvrDoc::lResizeDoc DOC.CPP
+//
+// Comments:
+//
+//********************************************************************
+
+long CSimpSvrApp::lSizeHandler (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ RECT rect;
+
+ GetClientRect(m_hAppWnd, &rect);
+ return m_lpDoc->lResizeDoc(&rect);
+}
+
+//**********************************************************************
+//
+// CSimpSvrApp::lCreateDoc
+// d
+// Purpose:
+//
+// Handles the creation of a document.
+//
+// Parameters:
+//
+// HWND hWnd - Handle to the application Window
+//
+// UINT message - message (always WM_CREATE)
+//
+// WPARAM wParam - Same as passed to the WndProc
+//
+// LPARAM lParam - Same as passed to the WndProc
+//
+// Return Value:
+//
+// NULL
+//
+// Function Calls:
+// Function Location
+//
+// GetClientRect Windows API
+// CSimpSvrDoc::Create DOC.CPP
+//
+// Comments:
+//
+//********************************************************************
+
+long CSimpSvrApp::lCreateDoc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ RECT rect;
+
+ GetClientRect(hWnd, &rect);
+
+ m_lpDoc = CSimpSvrDoc::Create(this, &rect, hWnd);
+
+ return NULL;
+}
+
+
+
+//**********************************************************************
+//
+// CSimpSvrApp::PaintApp
+//
+// Purpose:
+//
+// Handles the painting of the doc window.
+//
+//
+// Parameters:
+//
+// HDC hDC - hDC to the Doc Window.
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// CSimpSvrDoc::PaintDoc DOC.CPP
+//
+// Comments:
+//
+//
+//********************************************************************
+
+void CSimpSvrApp::PaintApp (HDC hDC)
+{
+
+ // if we supported multiple documents, we would enumerate
+ // through each of the open documents and call paint.
+
+ if (m_lpDoc)
+ m_lpDoc->PaintDoc(hDC);
+
+}
+
+//**********************************************************************
+//
+// CSimpSvrApp::ParseCmdLine
+//
+// Purpose:
+//
+// Determines if the app was started by OLE
+//
+//
+// Parameters:
+//
+// LPSTR lpCmdLine - Pointer to the command line
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// lstrlen Windows API
+// lstrcmp Windows API
+//
+//
+// Comments:
+//
+// Parses the command line looking for the -Embedding or /Embedding
+// flag.
+//
+//********************************************************************
+
+void CSimpSvrApp::ParseCmdLine(LPSTR lpCmdLine)
+{
+ char szTemp[255];
+
+ m_fStartByOle = TRUE;
+
+ ::ParseCmdLine (lpCmdLine, &m_fStartByOle, szTemp);
+}
+
+//**********************************************************************
+//
+// CSimpSvrApp::SetStatusText
+//
+// Purpose:
+//
+// Blanks out the text in the status bar
+//
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// CSimpSvrDoc::SetStatusText DOC.CPP
+//
+//
+// Comments:
+//
+//
+//********************************************************************
+
+void CSimpSvrApp::SetStatusText()
+{
+ m_lpDoc->SetStatusText();
+}
+
+
+//**********************************************************************
+//
+// CSimpSvrApp::IsInPlaceActive
+//
+// Purpose:
+//
+// Safely determines from the app level if currently inplace active.
+//
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// TRUE - Inplace active
+// FALSE - Not Inplace active
+//
+// Function Calls:
+// Function Location
+//
+// CSimpSvrDoc::GetObject OBJ.H
+// CSimpSvrObj:IsInPlaceActive OBJ.H
+//
+//
+// Comments:
+//
+//
+//********************************************************************
+
+BOOL CSimpSvrApp::IsInPlaceActive()
+{
+ BOOL retval = FALSE;
+
+ if (m_lpDoc)
+ if (m_lpDoc->GetObj())
+ retval = m_lpDoc->GetObj()->IsInPlaceActive();
+
+ return retval;
+}
+
+//**********************************************************************
+//
+// CSimpSvrApp::ShowAppWnd
+//
+// Purpose:
+//
+// Shows the Application Window
+//
+// Parameters:
+//
+// int nCmdShow - Window State
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// ShowWindow Windows API
+// UpdateWindow Windows API
+// CoLockObjectExternal OLE API
+//
+// Comments:
+//
+//********************************************************************
+
+void CSimpSvrApp::ShowAppWnd(int nCmdShow)
+{
+ CoLockObjectExternal(this, TRUE, FALSE);
+ ShowWindow (m_hAppWnd, nCmdShow);
+ UpdateWindow (m_hAppWnd);
+}
+
+//**********************************************************************
+//
+// CSimpSvrApp::ShowAppWnd
+//
+// Purpose:
+//
+// Hides the Application Window
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// ShowWindow Windows API
+// CoLockObjectExternal OLE API
+//
+// Comments:
+//
+//********************************************************************
+
+void CSimpSvrApp::HideAppWnd()
+{
+ CoLockObjectExternal(this, FALSE, TRUE);
+ ShowWindow (m_hAppWnd, SW_HIDE);
+}
diff --git a/private/oleutest/utests16/simpsvr/app.h b/private/oleutest/utests16/simpsvr/app.h
new file mode 100644
index 000000000..2a8ecf351
--- /dev/null
+++ b/private/oleutest/utests16/simpsvr/app.h
@@ -0,0 +1,85 @@
+//**********************************************************************
+// File name: app.h
+//
+// Definition of CSimpSvrApp
+//
+// Copyright (c) 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+
+#if !defined( _APP_H_)
+#define _APP_H_
+
+class CSimpSvrDoc;
+interface CClassFactory;
+
+class CSimpSvrApp : public IUnknown
+{
+private:
+
+ int m_nCount; // reference count
+ HWND m_hAppWnd; // main window handle
+ HINSTANCE m_hInst; // application instance
+ BOOL m_fStartByOle; // TRUE if app started by OLE
+ DWORD m_dwRegisterClass; // returned by RegisterClassFactory
+
+ HMENU m_hMainMenu;
+ HMENU m_hColorMenu;
+ HMENU m_hHelpMenu;
+
+
+ LPOLEOBJECT m_OleObject; // pointer to "dummy" object
+
+
+ CSimpSvrDoc FAR * m_lpDoc; // pointer to document object
+ BOOL m_fInitialized; // OLE initialization flag
+
+ RECT nullRect; // used in inplace negotiation
+
+public:
+ // IUnknown Interfaces
+ STDMETHODIMP QueryInterface(REFIID riid, LPVOID FAR* ppvObj);
+ STDMETHODIMP_(ULONG) AddRef();
+ STDMETHODIMP_(ULONG) Release();
+
+ // Initialization methods
+
+ CSimpSvrApp(); // Constructor
+ ~CSimpSvrApp(); // Destructor
+
+
+ BOOL fInitApplication (HANDLE hInstance);
+ BOOL fInitInstance (HANDLE hInstance, int nCmdShow, CClassFactory FAR * lpClassFactory);
+
+ // Message handling methods
+
+ long lCommandHandler (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
+ long lSizeHandler (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
+ long lCreateDoc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
+ void PaintApp(HDC hDC);
+
+ // Utility functions
+ void ParseCmdLine(LPSTR lpCmdLine);
+ void SetStatusText();
+ BOOL IsInPlaceActive();
+ void ShowAppWnd(int nCmdShow=SW_SHOWNORMAL);
+ void HideAppWnd();
+
+
+ // member variable access
+ inline HWND GethAppWnd() { return m_hAppWnd; };
+ inline HINSTANCE GethInst() { return m_hInst; };
+ inline BOOL IsStartedByOle() { return m_fStartByOle; };
+ inline BOOL IsInitialized() { return m_fInitialized; };
+ inline DWORD GetRegisterClass() { return m_dwRegisterClass; };
+ inline CSimpSvrDoc FAR * GetDoc() { return m_lpDoc; };
+ inline void ClearDoc() { m_lpDoc = NULL; };
+ inline LPOLEOBJECT GetOleObject() { return m_OleObject; };
+ inline HMENU GetMainMenu() { return m_hMainMenu; };
+ inline HMENU GetColorMenu() { return m_hColorMenu; };
+ inline HMENU GetHelpMenu() { return m_hHelpMenu; } ;
+
+
+ friend interface CClassFactory; // make the contained class a friend
+};
+
+#endif
diff --git a/private/oleutest/utests16/simpsvr/doc.cpp b/private/oleutest/utests16/simpsvr/doc.cpp
new file mode 100644
index 000000000..eb2e4168a
--- /dev/null
+++ b/private/oleutest/utests16/simpsvr/doc.cpp
@@ -0,0 +1,693 @@
+//**********************************************************************
+// File name: DOC.CPP
+//
+// Implementation file for CSimpSvrDoc.
+//
+// Functions:
+//
+// See DOC.H for Class Definition
+//
+// Copyright (c) 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+
+#include "pre.h"
+#include "obj.h"
+#include "app.h"
+#include "doc.h"
+
+//**********************************************************************
+//
+// CSimpSvrDoc::Create
+//
+// Purpose:
+//
+// Creation for the CSimpSvrDoc Class
+//
+// Parameters:
+//
+// CSimpSvrApp FAR * lpApp - Pointer to the CSimpSvrApp Class
+//
+// LPRECT lpRect - Client area rect of "frame" window
+//
+// HWND hWnd - Window Handle of "frame" window
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// StgCreateDocfile OLE API
+// CreateWindow Windows API
+// ShowWindow Windows API
+// UpdateWindow Windows API
+// CSimpSvrDoc::CSimpSvrDoc DOC.CPP
+// CreateHatchWindow OLE2UI
+//
+// Comments:
+//
+// This routine was added so that failure could be returned
+// from object creation.
+//
+//********************************************************************
+
+CSimpSvrDoc FAR * CSimpSvrDoc::Create(CSimpSvrApp FAR *lpApp, LPRECT lpRect,HWND hWnd)
+{
+ CSimpSvrDoc FAR * lpTemp = new CSimpSvrDoc(lpApp, hWnd);
+
+ if (!lpTemp)
+ return NULL;
+
+ // create the document Window
+ lpTemp->m_hDocWnd = CreateWindow(
+ "DocWClass",
+ NULL,
+ WS_CHILD | WS_CLIPSIBLINGS,
+ lpRect->left,
+ lpRect->top,
+ lpRect->right,
+ lpRect->bottom,
+ hWnd,
+ NULL,
+ lpApp->GethInst(),
+ NULL);
+
+ if (!lpTemp->m_hDocWnd)
+ goto error;
+
+ lpTemp->ShowDocWnd();
+
+ lpTemp->m_hHatchWnd = CreateHatchWindow( lpTemp->m_hDocWnd, lpApp->GethInst());
+
+ lpTemp->HideHatchWnd();
+
+ return (lpTemp);
+
+error:
+ delete (lpTemp);
+ return NULL;
+
+}
+
+//**********************************************************************
+//
+// CSimpSvrDoc::CSimpSvrDoc
+//
+// Purpose:
+//
+// Constructor for the CSimpSvrDoc Class
+//
+// Parameters:
+//
+// CSimpSvrApp FAR * lpApp - Pointer to the CSimpSvrApp Class
+//
+// HWND hWnd - Window Handle of "frame" window
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// GetMenu Windows API
+// GetSubMenu Windows API
+//
+// Comments:
+//
+//********************************************************************
+
+CSimpSvrDoc::CSimpSvrDoc(CSimpSvrApp FAR * lpApp,HWND hWnd)
+{
+ TestDebugOut("In CSimpSvrDoc's Constructor\r\n");
+ m_lpApp = lpApp;
+ m_nCount = 0;
+ m_lpObj = NULL;
+ m_fClosing = FALSE;
+
+ // set up menu handles
+
+
+}
+
+//**********************************************************************
+//
+// CSimpSvrDoc::~CSimpSvrDoc
+//
+// Purpose:
+//
+// Destructor for CSimpSvrDoc
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// DestroyWindow Windows API
+// CSimpSvrApp::ClearDoc APP.CPP
+//
+// Comments:
+//
+//********************************************************************
+
+CSimpSvrDoc::~CSimpSvrDoc()
+{
+ TestDebugOut("In CSimpSvrDoc's Destructor\r\n");
+ m_lpApp->ClearDoc();
+ DestroyWindow(m_hHatchWnd);
+}
+
+
+//**********************************************************************
+//
+// CSimpSvrDoc::QueryInterface
+//
+// Purpose:
+//
+// Return a pointer to a requested interface
+//
+// Parameters:
+//
+// REFIID riid - ID of interface to be returned
+// LPVOID FAR* ppvObj - Location to return the interface
+//
+// Return Value:
+//
+// E_NOINTERFACE - Always
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// CSimpSvrApp::QueryInterface APP.CPP
+//
+// Comments:
+//
+// Since the document could contain multiple objects, all
+// interfaces except those associated with the document should
+// be returned. In this implementation, there are no doc level
+// interfaces.
+//
+//********************************************************************
+
+STDMETHODIMP CSimpSvrDoc::QueryInterface(REFIID riid, LPVOID FAR* ppvObj)
+{
+ TestDebugOut("In CSimpSvrDoc::QueryInterface\r\n");
+
+ SCODE sc = E_NOINTERFACE;
+
+ if ( (riid == IID_IUnknown) )
+ {
+ AddRef();
+ *ppvObj = this;
+ sc = S_OK;
+ }
+
+ return ResultFromScode(sc);
+}
+
+//**********************************************************************
+//
+// CSimpSvrDoc::AddRef
+//
+// Purpose:
+//
+// Increments the document level reference count
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// UINT - The current reference count on the document
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// CSimpSvrApp::AddRef APP.CPP
+//
+// Comments:
+//
+// The reference count at this level reflects the total ref.
+// count of all interfaces on all objects contained within
+// this document. Note that it also "trickles up" the
+// ref count to the app level.
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) CSimpSvrDoc::AddRef()
+{
+ TestDebugOut("In CSimpSvrDoc::AddRef\r\n");
+ // AddRef the app, but return the doc count
+ m_lpApp->AddRef();
+
+ return ++m_nCount;
+}
+
+//**********************************************************************
+//
+// CSimpSvrDoc::Release
+//
+// Purpose:
+//
+// Decrements the document level reference count
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// UINT - The current reference count on the document
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// CSimpSvrApp::Release APP.CPP
+//
+// Comments:
+//
+// The reference count at this level reflects the total ref.
+// count of all interfaces on all objects contained within
+// this document. Note that it also "trickles up" the
+// ref count to the app level.
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) CSimpSvrDoc::Release()
+{
+ TestDebugOut("In CSimpSvrDoc::Release\r\n");
+ // Release the app, but return the app count
+ m_lpApp->Release();
+
+ if (--m_nCount == 0) {
+ delete this;
+ return 0;
+ }
+
+ return m_nCount;
+}
+
+//**********************************************************************
+//
+// CSimpSvrDoc::lResizeDoc
+//
+// Purpose:
+//
+// Resizes the document
+//
+// Parameters:
+//
+// LPRECT lpRect - The size of the client are of the "frame"
+// Window.
+//
+// Return Value:
+//
+// NULL
+//
+// Function Calls:
+// Function Location
+//
+// MoveWindow Windows API
+//
+// Comments:
+//
+//********************************************************************
+
+long CSimpSvrDoc::lResizeDoc(LPRECT lpRect)
+{
+ MoveWindow(m_hDocWnd, lpRect->left, lpRect->top, lpRect->right, lpRect->bottom, TRUE);
+ return NULL;
+}
+
+
+//**********************************************************************
+//
+// CSimpSvrDoc::PaintDoc
+//
+// Purpose:
+//
+// Paints the Document
+//
+// Parameters:
+//
+// HDC hDC - hDC of the document Window
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// CSimpSvrObj::Draw OBJ.CPP
+// CSimpSvrObj::GetDataAdviseHolder OBJ.H
+// CSimpSvrObj::GetDataObject OBJ.H
+// CSimpAppObj::IsStartedByOle APP.CPP
+// IDataAdviseHolder::SendOnDataChange OLE API
+//
+// Comments:
+//
+//********************************************************************
+
+void CSimpSvrDoc::PaintDoc (HDC hDC)
+{
+
+ // if the object hasn't been created yet, then don't draw
+ if (m_lpObj)
+ m_lpObj->Draw(hDC,FALSE);
+ else
+ return;
+
+ // Sending a data change every time we paint, but only if we
+ // were started by OLE
+ if (m_lpApp->IsStartedByOle())
+ m_lpObj->SendOnDataChange( );
+}
+
+
+
+//**********************************************************************
+//
+// CSimpSvrDoc::CreateObject
+//
+// Purpose:
+//
+//
+// Parameters:
+//
+//
+// Return Value:
+//
+// NOERROR if the function succeeds, otherwise E_FAIL
+//
+// Function Calls:
+// Function Location
+//
+// CSimpSvrObj::CSimpSvrObj OBJ.CPP
+// CSimpSvrOjb::QueryInterface OBJ.CPP
+//
+// Comments:
+//
+//********************************************************************
+
+HRESULT CSimpSvrDoc::CreateObject(REFIID riid, LPVOID FAR *ppvObject)
+{
+ SCODE sc = E_FAIL;
+
+ m_lpObj = new CSimpSvrObj(this);
+
+ if (m_lpObj)
+ {
+ m_lpObj->QueryInterface(riid, ppvObject);
+ sc = S_OK;
+ }
+
+ return ResultFromScode(sc);
+}
+
+//**********************************************************************
+//
+// CSimpSvrDoc::Close
+//
+// Purpose:
+//
+// Closes the object
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// CSimpSvrObj::AddRef OBJ.CPP
+// CSimpSvrObj::Release OBJ.CPP
+// CSimpSvrObj::IsInPlaceActive OBJ.H
+// CSimpSvrObj::GetOleInPlaceObject OBJ.H
+// CSimpSvrObj::ClearOleClientSite OBJ.H
+// CSimpSvrObj::GetDataAdviseHolder OBJ.H
+// CSimpSvrObj::GetOleClientSite OBJ.H
+// CSimpSvrObj::ClearDataAdviseHolder OBJ.H
+// CSimpSvrObj::GetOleAdviseHolder OBJ.H
+// CSimpSvrObj::ClearOleAdviseHolder OBJ.H
+// IOleInPlaceObject::InPlaceDeactivate Container
+// IOleClientSite::SaveObject Container
+// IOleClientSite::OnShowWindow Container
+// IOleClientSite::Release Container
+// IDataAdviseHolder::SendOnDataChange OLE
+// IDataAdviseHolder::Release OLE
+// IOleAdviseHolder::SendOnClose OLE
+// IOleAdviseHolder::Release OLE
+//
+// Comments:
+//
+//********************************************************************
+
+void CSimpSvrDoc::Close()
+{
+ TestDebugOut("In CSimpSvrDoc::Close() \r\n");
+
+ m_lpObj->AddRef(); // hold object alive
+
+ if (m_fClosing)
+ return;
+
+ m_fClosing = TRUE;
+
+ // if the object is currently inplace active, then deactivate
+ if (m_lpObj->IsInPlaceActive())
+ m_lpObj->GetOleInPlaceObject()->InPlaceDeactivate();
+
+ // unregister from the ROT...
+ if (m_lpObj->GetRotRegister())
+ {
+ LPRUNNINGOBJECTTABLE lpRot;
+
+ if (GetRunningObjectTable (0, &lpRot) == NOERROR )
+ {
+ lpRot->Revoke(m_lpObj->GetRotRegister());
+ lpRot->Release();
+ }
+ }
+
+ // if we have a clientsite, instruct it to save the object
+ if (m_lpObj->GetOleClientSite())
+ {
+ m_lpObj->GetOleClientSite()->SaveObject();
+ m_lpObj->GetOleClientSite()->OnShowWindow(FALSE);
+ }
+
+ // Do a final SendOnDataChange for those containers that have specified the
+ // ADF_DATAONSTOP flag.
+ if (m_lpObj->GetDataAdviseHolder())
+ {
+ m_lpObj->GetDataAdviseHolder()->SendOnDataChange( m_lpObj->GetDataObject(), 0, ADVF_DATAONSTOP);
+ m_lpObj->GetDataAdviseHolder()->Release();
+ m_lpObj->ClearDataAdviseHolder();
+ }
+
+
+ // Tell the container that we are shutting down.
+ if (m_lpObj->GetOleAdviseHolder())
+ {
+ m_lpObj->GetOleAdviseHolder()->SendOnClose();
+ m_lpObj->GetOleAdviseHolder()->Release();
+ m_lpObj->ClearOleAdviseHolder();
+ }
+
+ if (m_lpObj->GetOleClientSite())
+ {
+ m_lpObj->GetOleClientSite()->Release();
+ m_lpObj->ClearOleClientSite();
+ }
+
+ // release our streams and storage
+ m_lpObj->GetPersistStorage()->ReleaseStreamsAndStorage();
+
+ // Disconnect the object. NOTE: This call should not do anything
+ // unless the container has cause a GP Fault or some other problem
+ // has occured...
+ TestDebugOut("*** Before CoDisconnectObject *** \r\n");
+ CoDisconnectObject((LPUNKNOWN)m_lpObj, 0);
+ TestDebugOut("*** After CoDisconnectObject *** \r\n");
+
+ m_lpObj->Release(); // let object close
+
+}
+
+
+//**********************************************************************
+//
+// CSimpSvrDoc::SetStatusText
+//
+// Purpose:
+//
+// Sets the Container's status bar text
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// CSimpSvrObj::IsInPlaceActive OBJ.CPP
+// IOleInPlaceFrame::SetStatusText Container
+//
+// Comments:
+//
+// Even though there is no status line in this sample, this
+// method must be called on WM_MENUSELECT to clear the last
+// message in the status line.
+//
+//********************************************************************
+
+void CSimpSvrDoc::SetStatusText()
+{
+ if (m_lpObj->IsInPlaceActive())
+ m_lpObj->GetInPlaceFrame()->SetStatusText("\0");
+}
+
+//**********************************************************************
+//
+// CSimpSvrDoc::ShowDocWnd
+//
+// Purpose:
+//
+// Shows the Document Window
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// ShowWindow Windows API
+// UpdateWindow Windows API
+//
+// Comments:
+//
+//********************************************************************
+
+void CSimpSvrDoc::ShowDocWnd()
+{
+ ShowWindow(m_hDocWnd, SW_SHOWNORMAL); // Show the window
+ UpdateWindow(m_hDocWnd); // Sends WM_PAINT message
+}
+
+//**********************************************************************
+//
+// CSimpSvrDoc::ShowHatchWnd
+//
+// Purpose:
+//
+// Shows the hatch Window
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// ShowWindow Windows API
+//
+// Comments:
+//
+//********************************************************************
+
+void CSimpSvrDoc::ShowHatchWnd()
+{
+ ShowWindow(m_hHatchWnd, SW_SHOW);
+}
+
+//**********************************************************************
+//
+// CSimpSvrDoc::HideDocWnd
+//
+// Purpose:
+//
+// Hides the DocumentWindow
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// ShowWindow Windows API
+//
+// Comments:
+//
+//********************************************************************
+
+void CSimpSvrDoc::HideDocWnd()
+{
+ ShowWindow(m_hDocWnd, SW_HIDE);
+}
+
+//**********************************************************************
+//
+// CSimpSvrDoc::HideHatchWnd
+//
+// Purpose:
+//
+// Hides the Hatch Window
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// ShowWindow Windows API
+//
+// Comments:
+//
+//********************************************************************
+
+void CSimpSvrDoc::HideHatchWnd()
+{
+ ShowWindow(m_hHatchWnd, SW_HIDE);
+}
diff --git a/private/oleutest/utests16/simpsvr/doc.h b/private/oleutest/utests16/simpsvr/doc.h
new file mode 100644
index 000000000..33d18e066
--- /dev/null
+++ b/private/oleutest/utests16/simpsvr/doc.h
@@ -0,0 +1,65 @@
+//**********************************************************************
+// File name: doc.h
+//
+// Definition of CSimpSvrDoc
+//
+// Copyright (c) 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+
+#if !defined( _DOC_H_ )
+#define _DOC_H_
+
+class CSimpSvrApp;
+class CSimpSvrObj;
+
+class CSimpSvrDoc : IUnknown
+{
+private:
+ int m_nCount;
+
+ CSimpSvrApp FAR * m_lpApp;
+ CSimpSvrObj FAR * m_lpObj;
+
+ HWND m_hDocWnd;
+ HWND m_hHatchWnd;
+ BOOL m_fClosing;
+
+public:
+ static CSimpSvrDoc FAR * Create(CSimpSvrApp FAR *lpApp, LPRECT lpRect,HWND hWnd);
+
+ CSimpSvrDoc();
+ CSimpSvrDoc(CSimpSvrApp FAR *lpApp, HWND hWnd);
+ ~CSimpSvrDoc();
+
+// IUnknown Interfaces
+ STDMETHODIMP QueryInterface(REFIID riid, LPVOID FAR* ppvObj);
+ STDMETHODIMP_(ULONG) AddRef();
+ STDMETHODIMP_(ULONG) Release();
+
+ long lResizeDoc(LPRECT lpRect);
+ long lAddVerbs();
+
+ BOOL Load(LPSTR lpszFileName);
+ void PaintDoc(HDC hDC);
+ void lButtonDown(WPARAM wParam,LPARAM lParam);
+
+ HRESULT CreateObject(REFIID riid, LPVOID FAR *ppvObject);
+
+ void Close();
+ void SetStatusText();
+ void ShowDocWnd();
+ void ShowHatchWnd();
+ void CSimpSvrDoc::HideDocWnd();
+ void CSimpSvrDoc::HideHatchWnd();
+
+// member access
+ inline HWND GethDocWnd() { return m_hDocWnd; };
+ inline HWND GethHatchWnd() { return m_hHatchWnd; };
+ inline HWND GethAppWnd() { return m_lpApp->GethAppWnd(); };
+ inline CSimpSvrApp FAR * GetApp() { return m_lpApp; };
+ inline CSimpSvrObj FAR * GetObj() { return m_lpObj; };
+ inline void ClearObj() { m_lpObj = NULL; };
+
+};
+
+#endif
diff --git a/private/oleutest/utests16/simpsvr/icf.cpp b/private/oleutest/utests16/simpsvr/icf.cpp
new file mode 100644
index 000000000..e68575e20
--- /dev/null
+++ b/private/oleutest/utests16/simpsvr/icf.cpp
@@ -0,0 +1,235 @@
+//**********************************************************************
+// File name: ICF.CPP
+//
+// Implementation file for the CClassFactory Class
+//
+// Functions:
+//
+// See icf.h for a list of member functions.
+//
+// Copyright (c) 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+
+#include "pre.h"
+#include "app.h"
+#include "doc.h"
+#include "icf.h"
+
+//**********************************************************************
+//
+// CClassFactory::QueryInterface
+//
+// Purpose:
+//
+//
+// Parameters:
+//
+// REFIID riid - Interface being queried for.
+//
+// LPVOID FAR *ppvObj - Out pointer for the interface.
+//
+// Return Value:
+//
+// S_OK - Success
+// E_NOINTERFACE - Failure
+//
+// Function Calls:
+// Function Location
+//
+// CSimpSvrApp::QueryInterface APP.CPP
+//
+// Comments:
+//
+//
+//********************************************************************
+
+STDMETHODIMP CClassFactory::QueryInterface ( REFIID riid, LPVOID FAR* ppvObj)
+{
+ TestDebugOut("In CClassFactory::QueryInterface\r\n");
+
+ SCODE sc = S_OK;
+
+ if ( (riid == IID_IUnknown) ||
+ (riid == IID_IClassFactory) )
+ *ppvObj = this;
+ else
+ {
+ *ppvObj = NULL;
+ sc = E_NOINTERFACE;
+ }
+
+ if (*ppvObj)
+ ((LPUNKNOWN)*ppvObj)->AddRef();
+
+ // pass it on to the Application object
+ return ResultFromScode(sc);
+};
+
+//**********************************************************************
+//
+// CClassFactory::AddRef
+//
+// Purpose:
+//
+// Increments the reference count on CClassFactory and the application
+// object.
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// The Reference count on CClassFactory
+//
+// Function Calls:
+// Function Location
+//
+// OuputDebugString Windows API
+//
+// Comments:
+//
+//
+//********************************************************************
+
+
+STDMETHODIMP_(ULONG) CClassFactory::AddRef ()
+{
+ TestDebugOut("In CClassFactory::AddRef\r\n");
+
+ return ++m_nCount;
+};
+
+//**********************************************************************
+//
+// CClassFactory::Release
+//
+// Purpose:
+//
+// Decrements the reference count of CClassFactory and the
+// application object.
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// The new reference count
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+// Comments:
+//
+//
+//********************************************************************
+
+
+STDMETHODIMP_(ULONG) CClassFactory::Release ()
+{
+ TestDebugOut("In CClassFactory::Release\r\n");
+
+ if (--m_nCount == 0) {
+ delete this;
+ return 0;
+ }
+
+ return m_nCount;
+};
+
+
+//**********************************************************************
+//
+// CClassFactory::CreateInstance
+//
+// Purpose:
+//
+// Instantiates a new OLE object
+//
+// Parameters:
+//
+// LPUNKNOWN pUnkOuter - Pointer to the controlling unknown
+//
+// REFIID riid - The interface type to fill in ppvObject
+//
+// LPVOID FAR* ppvObject - Out pointer for the object
+//
+// Return Value:
+//
+// S_OK - Creation was successful
+// CLASS_E_NOAGGREGATION - Tried to be created as part of an aggregate
+//
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// CSimpSvrDoc::CreateObject DOC.CPP
+//
+// Comments:
+//
+//
+//********************************************************************
+
+STDMETHODIMP CClassFactory::CreateInstance ( LPUNKNOWN pUnkOuter,
+ REFIID riid,
+ LPVOID FAR* ppvObject)
+{
+ HRESULT hErr;
+
+ TestDebugOut("In CClassFactory::CreateInstance\r\n");
+
+ // need to NULL the out parameter
+ *ppvObject = NULL;
+
+ // we don't support aggregation...
+ if (pUnkOuter)
+ {
+ hErr = ResultFromScode(CLASS_E_NOAGGREGATION);
+ goto error;
+ }
+
+ hErr = m_lpApp->m_lpDoc->CreateObject(riid, ppvObject);
+
+error:
+ return hErr;
+};
+
+//**********************************************************************
+//
+// CClassFactory::LockServer
+//
+// Purpose:
+//
+//
+// Parameters:
+//
+// BOOL fLock - TRUE to lock the server, FALSE to unlock it
+//
+// Return Value:
+//
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// CoLockObjectExternal OLE API
+// ResultFromScode OLE API
+//
+// Comments:
+//
+//
+//********************************************************************
+
+
+STDMETHODIMP CClassFactory::LockServer ( BOOL fLock)
+{
+ TestDebugOut("In CClassFactory::LockServer\r\n");
+ CoLockObjectExternal(m_lpApp, fLock, TRUE);
+
+ return ResultFromScode( S_OK);
+};
diff --git a/private/oleutest/utests16/simpsvr/icf.h b/private/oleutest/utests16/simpsvr/icf.h
new file mode 100644
index 000000000..93aa86e72
--- /dev/null
+++ b/private/oleutest/utests16/simpsvr/icf.h
@@ -0,0 +1,45 @@
+//**********************************************************************
+// File name: icf.h
+//
+// Definition of CClassFactory
+//
+// Copyright (c) 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+
+#if !defined( _ICF_H_)
+#define _ICF_H_
+
+class CSimpSvrApp;
+
+interface CClassFactory : IClassFactory
+{
+private:
+ int m_nCount; // reference count
+ CSimpSvrApp FAR * m_lpApp;
+
+public:
+ CClassFactory::CClassFactory(CSimpSvrApp FAR * lpApp)
+ {
+ TestDebugOut("In CClassFactory's Constructor\r\n");
+ m_lpApp = lpApp;
+ m_nCount = 0;
+ };
+ CClassFactory::~CClassFactory()
+ {
+ TestDebugOut("In CClassFactory's Destructor\r\n");
+ };
+
+ // IUnknown Methods
+
+ STDMETHODIMP QueryInterface (REFIID riid, LPVOID FAR* ppvObj);
+ STDMETHODIMP_(ULONG) AddRef ();
+ STDMETHODIMP_(ULONG) Release ();
+
+ STDMETHODIMP CreateInstance (LPUNKNOWN pUnkOuter,
+ REFIID riid,
+ LPVOID FAR* ppvObject);
+ STDMETHODIMP LockServer ( BOOL fLock);
+
+};
+
+#endif
diff --git a/private/oleutest/utests16/simpsvr/ido.cpp b/private/oleutest/utests16/simpsvr/ido.cpp
new file mode 100644
index 000000000..1a8ce2866
--- /dev/null
+++ b/private/oleutest/utests16/simpsvr/ido.cpp
@@ -0,0 +1,544 @@
+//**********************************************************************
+// File name: IDO.CPP
+//
+// Implementation file for the CDataObject Class
+//
+// Functions:
+//
+// See ido.h for a list of member functions.
+//
+// Copyright (c) 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+
+#include "pre.h"
+#include "obj.h"
+#include "ido.h"
+#include "app.h"
+#include "doc.h"
+
+//**********************************************************************
+//
+// CDataObject::QueryInterface
+//
+// Purpose:
+//
+//
+// Parameters:
+//
+// REFIID riid - Interface being queried for.
+//
+// LPVOID FAR *ppvObj - Out pointer for the interface.
+//
+// Return Value:
+//
+// S_OK - Success
+// E_NOINTERFACE - Failure
+//
+// Function Calls:
+// Function Location
+//
+// CSimpSvrObj::QueryInterface OBJ.CPP
+//
+// Comments:
+//
+//
+//********************************************************************
+
+
+STDMETHODIMP CDataObject::QueryInterface ( REFIID riid, LPVOID FAR* ppvObj)
+{
+ TestDebugOut("In CDataObject::QueryInterface\r\n");
+
+ return m_lpObj->QueryInterface(riid, ppvObj);
+};
+
+//**********************************************************************
+//
+// CDataObject::AddRef
+//
+// Purpose:
+//
+// Increments the reference count on CClassFactory and the application
+// object.
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// The Reference count on CDataObject
+//
+// Function Calls:
+// Function Location
+//
+// OuputDebugString Windows API
+// CSimpSvrObj::AddRef OBJ.CPP
+//
+// Comments:
+//
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) CDataObject::AddRef ()
+{
+ TestDebugOut("In CDataObject::AddRef\r\n");
+ ++m_nCount;
+ return m_lpObj->AddRef();
+};
+
+//**********************************************************************
+//
+// CDataObject::Release
+//
+// Purpose:
+//
+// Decrements the reference count of CDataObject
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// The new reference count
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// CSimpSvrObj::Release OBJ.CPP
+//
+// Comments:
+//
+//
+//********************************************************************
+
+
+STDMETHODIMP_(ULONG) CDataObject::Release ()
+{
+ TestDebugOut("In CDataObject::Release\r\n");
+ --m_nCount;
+ return m_lpObj->Release();
+};
+
+//**********************************************************************
+//
+// CDataObject::QueryGetData
+//
+// Purpose:
+//
+// Called to determine if our object supports a particular
+// FORMATETC.
+//
+// Parameters:
+//
+// LPFORMATETC pformatetc - Pointer to the FORMATETC being queried for.
+//
+// Return Value:
+//
+// DATA_E_FORMATETC - The FORMATETC is not supported
+// S_OK - The FORMATETC is supported.
+//
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// ResultFromScode OLE API
+//
+// Comments:
+//
+//
+//********************************************************************
+
+
+STDMETHODIMP CDataObject::QueryGetData ( LPFORMATETC pformatetc )
+{
+ SCODE sc = DATA_E_FORMATETC;
+
+ TestDebugOut("In CDataObject::QueryGetData\r\n");
+
+ // check the validity of the formatetc.
+ if ( (pformatetc->cfFormat == CF_METAFILEPICT) &&
+ (pformatetc->dwAspect == DVASPECT_CONTENT) &&
+ (pformatetc->tymed == TYMED_MFPICT) )
+ sc = S_OK;
+
+ return ResultFromScode(sc);
+};
+
+//**********************************************************************
+//
+// CDataObject::DAdvise
+//
+// Purpose:
+//
+// Called by the container when it would like to be notified of
+// changes in the object data.
+//
+// Parameters:
+//
+// FORMATETC FAR* pFormatetc - The format the container is interested in.
+//
+// DWORD advf - The type of advise to be set up.
+//
+// LPADVISESINK pAdvSink - Pointer to the containers IAdviseSink
+//
+// DWORD FAR* pdwConnection - Out parameter to return a unique connection id.
+//
+// Return Value:
+//
+// passed on from IDataAdviseHolder
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// CreateDataAdviseHolder OLE API
+// IDataAdviseHolder::Advise OLE API
+//
+// Comments:
+//
+//
+//********************************************************************
+
+
+STDMETHODIMP CDataObject::DAdvise ( FORMATETC FAR* pFormatetc, DWORD advf,
+ LPADVISESINK pAdvSink, DWORD FAR* pdwConnection)
+{
+ TestDebugOut("In CDataObject::DAdvise\r\n");
+
+ // if no DataAdviseHolder has been created, then create one.
+ if (!m_lpObj->m_lpDataAdviseHolder)
+ CreateDataAdviseHolder(&m_lpObj->m_lpDataAdviseHolder);
+
+ // pass on to the DataAdviseHolder
+ return m_lpObj->m_lpDataAdviseHolder->Advise( this, pFormatetc, advf,
+ pAdvSink, pdwConnection);
+}
+
+//**********************************************************************
+//
+// CDataObject::GetData
+//
+// Purpose:
+//
+// Returns the data in the format specified in pformatetcIn.
+//
+// Parameters:
+//
+// LPFORMATETC pformatetcIn - The format requested by the caller
+//
+// LPSTGMEDIUM pmedium - The medium requested by the caller
+//
+// Return Value:
+//
+// DATA_E_FORMATETC - Format not supported
+// S_OK - Success
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// CSimpSvrObj::GetMetaFilePict() OBJ.CPP
+// ResultFromScode OLE API
+//
+// Comments:
+//
+//
+//********************************************************************
+
+
+STDMETHODIMP CDataObject::GetData ( LPFORMATETC pformatetcIn, LPSTGMEDIUM pmedium )
+{
+ SCODE sc = DATA_E_FORMATETC;
+
+ TestDebugOut("In CDataObject::GetData\r\n");
+
+ // Check to the FORMATETC and fill pmedium if valid.
+ if ( (pformatetcIn->cfFormat == CF_METAFILEPICT) &&
+ (pformatetcIn->dwAspect == DVASPECT_CONTENT) &&
+ (pformatetcIn->tymed & TYMED_MFPICT) )
+ {
+ HANDLE hmfPict = m_lpObj->GetMetaFilePict();
+ pmedium->tymed = TYMED_MFPICT;
+ pmedium->hGlobal = hmfPict;
+ pmedium->pUnkForRelease = NULL;
+ sc = S_OK;
+ }
+
+ return ResultFromScode( sc );
+};
+
+//**********************************************************************
+//
+// CDataObject::DUnadvise
+//
+// Purpose:
+//
+// Breaks down an Advise connection.
+//
+// Parameters:
+//
+// DWORD dwConnection - Advise connection ID.
+//
+// Return Value:
+//
+// Returned from the DataAdviseHolder.
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// IDataAdviseHolder::Unadvise OLE
+//
+// Comments:
+//
+//
+//********************************************************************
+
+
+STDMETHODIMP CDataObject::DUnadvise ( DWORD dwConnection)
+{
+ TestDebugOut("In CDataObject::DUnadvise\r\n");
+
+ if (m_lpObj != NULL && m_lpObj->m_lpDataAdviseHolder != NULL)
+ {
+ return m_lpObj->m_lpDataAdviseHolder->Unadvise(dwConnection);
+ }
+
+ return ResultFromScode( E_UNEXPECTED);
+
+
+};
+
+//**********************************************************************
+//
+// CDataObject::GetDataHere
+//
+// Purpose:
+//
+// Called to get a data format in a caller supplied location
+//
+// Parameters:
+//
+// LPFORMATETC pformatetc - FORMATETC requested
+//
+// LPSTGMEDIUM pmedium - Medium to return the data
+//
+// Return Value:
+//
+// DATA_E_FORMATETC - We don't support the requested format
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+// Comments:
+//
+// In this simple implementation, we don't really support this
+// method, we just always return DATA_E_FORMATETC.
+//
+//********************************************************************
+
+
+STDMETHODIMP CDataObject::GetDataHere ( LPFORMATETC pformatetc,
+ LPSTGMEDIUM pmedium )
+{
+ TestDebugOut("In CDataObject::GetDataHere\r\n");
+ return ResultFromScode( DATA_E_FORMATETC);
+};
+
+//**********************************************************************
+//
+// CDataObject::GetCanonicalFormatEtc
+//
+// Purpose:
+//
+// Returns a FORMATETC that is equivalent to the one passed in.
+//
+// Parameters:
+//
+// LPFORMATETC pformatetc - FORMATETC to be tested.
+//
+// LPFORMATETC pformatetcOut - Out ptr for returned FORMATETC.
+//
+// Return Value:
+//
+// DATA_S_SAMEFORMATETC - Use the same formatetc as was passed.
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// CoGetMalloc OLE API
+// IMalloc::Alloc OLE
+// IMalloc::Release OLE
+// _fmemcpy C run-time
+//
+// Comments:
+//
+//
+//********************************************************************
+
+
+STDMETHODIMP CDataObject::GetCanonicalFormatEtc ( LPFORMATETC pformatetc,
+ LPFORMATETC pformatetcOut)
+{
+ HRESULT hresult;
+ TestDebugOut("In CDataObject::GetCanonicalFormatEtc\r\n");
+
+ if (!pformatetcOut)
+ return ResultFromScode(E_INVALIDARG);
+
+ /* OLE2NOTE: we must make sure to set all out parameters to NULL. */
+ pformatetcOut->ptd = NULL;
+
+ if (!pformatetc)
+ return ResultFromScode(E_INVALIDARG);
+
+ // OLE2NOTE: we must validate that the format requested is supported
+ if ((hresult = QueryGetData(pformatetc)) != NOERROR)
+ return hresult;
+
+ /* OLE2NOTE: an app that is insensitive to target device (as
+ ** SimpSvr 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.
+ */
+
+ *pformatetcOut = *pformatetc;
+ if (pformatetc->ptd == NULL)
+ return ResultFromScode(DATA_S_SAMEFORMATETC);
+ else
+ {
+ pformatetcOut->ptd = NULL;
+ return NOERROR;
+ }
+};
+
+//**********************************************************************
+//
+// CDataObject::SetData
+//
+// Purpose:
+//
+// Called to set the data for the object.
+//
+// Parameters:
+//
+// LPFORMATETC pformatetc - the format of the data being passed
+//
+// STGMEDIUM FAR * pmedium - the location of the data.
+//
+// BOOL fRelease - Defines the ownership of the medium
+//
+// Return Value:
+//
+// DATA_E_FORMATETC - Not a valid FORMATETC for this object
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+// Comments:
+//
+// This simple object does not support having its data set, so an
+// error value is always returned.
+//
+//********************************************************************
+
+
+STDMETHODIMP CDataObject::SetData ( LPFORMATETC pformatetc, STGMEDIUM FAR * pmedium,
+ BOOL fRelease)
+{
+ TestDebugOut("In CDataObject::SetData\r\n");
+ return ResultFromScode( DATA_E_FORMATETC );
+};
+
+//**********************************************************************
+//
+// CDataObject::EnumFormatEtc
+//
+// Purpose:
+//
+// Enumerates the formats supported by this object.
+//
+// Parameters:
+//
+// DWORD dwDirection - Order of enumeration.
+//
+// LPENUMFORMATETC FAR* ppenumFormatEtc - Place to return a pointer
+// to the enumerator.
+//
+// Return Value:
+//
+// OLE_S_USEREG - Indicates that OLE should consult the REG DB
+// to enumerate the formats.
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+// Comments:
+//
+//
+//********************************************************************
+
+
+STDMETHODIMP CDataObject::EnumFormatEtc ( DWORD dwDirection,
+ LPENUMFORMATETC FAR* ppenumFormatEtc)
+{
+ TestDebugOut("In CDataObject::EnumFormatEtc\r\n");
+ // need to NULL the out parameter
+ *ppenumFormatEtc = NULL;
+ return ResultFromScode( OLE_S_USEREG );
+};
+
+//**********************************************************************
+//
+// CDataObject::EnumDAdvise
+//
+// Purpose:
+//
+// Returns an enumerator that enumerates all of the advises
+// set up on this data object.
+//
+// Parameters:
+//
+// LPENUMSTATDATA FAR* ppenumAdvise - An out ptr in which to
+// return the enumerator.
+//
+// Return Value:
+//
+// Passed back from IDataAdviseHolder::EnumAdvise
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// IDAtaAdviseHolder::EnumAdvise OLE
+//
+// Comments:
+//
+// This just delegates to the DataAdviseHolder.
+//
+//********************************************************************
+
+
+STDMETHODIMP CDataObject::EnumDAdvise ( LPENUMSTATDATA FAR* ppenumAdvise)
+{
+ TestDebugOut("In CDataObject::EnumDAdvise\r\n");
+ // need to NULL the out parameter
+ *ppenumAdvise = NULL;
+
+ return m_lpObj->m_lpDataAdviseHolder->EnumAdvise(ppenumAdvise);
+};
diff --git a/private/oleutest/utests16/simpsvr/ido.h b/private/oleutest/utests16/simpsvr/ido.h
new file mode 100644
index 000000000..53897310d
--- /dev/null
+++ b/private/oleutest/utests16/simpsvr/ido.h
@@ -0,0 +1,53 @@
+//**********************************************************************
+// File name: ido.h
+//
+// Definition of CDataObject
+//
+// Copyright (c) 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+#if !defined( _IDO_H_)
+#define _IDO_H_
+
+
+#include <ole2.h>
+#include "obj.h"
+
+class CSimpSvrObj;
+
+interface CDataObject : public IDataObject
+{
+private:
+ CSimpSvrObj FAR * m_lpObj;
+ int m_nCount;
+
+public:
+ CDataObject::CDataObject(CSimpSvrObj FAR * lpSimpSvrObj)
+ {
+ m_lpObj = lpSimpSvrObj;
+ m_nCount = 0;
+ };
+
+ CDataObject::~CDataObject() {};
+
+ STDMETHODIMP QueryInterface (REFIID riid, LPVOID FAR* ppvObj);
+ STDMETHODIMP_(ULONG) AddRef ();
+ STDMETHODIMP_(ULONG) Release ();
+
+ STDMETHODIMP DAdvise ( FORMATETC FAR* pFormatetc, DWORD advf,
+ LPADVISESINK pAdvSink, DWORD FAR* pdwConnection);
+ STDMETHODIMP DUnadvise ( DWORD dwConnection);
+ STDMETHODIMP EnumDAdvise ( LPENUMSTATDATA FAR* ppenumAdvise);
+ STDMETHODIMP EnumFormatEtc ( DWORD dwDirection,
+ LPENUMFORMATETC FAR* ppenumFormatEtc);
+ STDMETHODIMP GetCanonicalFormatEtc ( LPFORMATETC pformatetc,
+ LPFORMATETC pformatetcOut);
+ STDMETHODIMP GetData ( LPFORMATETC pformatetcIn, LPSTGMEDIUM pmedium );
+ STDMETHODIMP GetDataHere ( LPFORMATETC pformatetc, LPSTGMEDIUM pmedium );
+ STDMETHODIMP QueryGetData ( LPFORMATETC pformatetc );
+ STDMETHODIMP SetData ( LPFORMATETC pformatetc, STGMEDIUM FAR * pmedium,
+ BOOL fRelease);
+
+
+};
+
+#endif
diff --git a/private/oleutest/utests16/simpsvr/iec.cpp b/private/oleutest/utests16/simpsvr/iec.cpp
new file mode 100644
index 000000000..c0421b767
--- /dev/null
+++ b/private/oleutest/utests16/simpsvr/iec.cpp
@@ -0,0 +1,212 @@
+//**********************************************************************
+// File name: IEC.CPP
+//
+// Implementation file for the CExternalConnection Class
+//
+// Functions:
+//
+// See iec.h for a list of member functions.
+//
+// Copyright (c) 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+
+#include "pre.h"
+#include "obj.h"
+#include "iec.h"
+#include "app.h"
+#include "doc.h"
+
+
+//**********************************************************************
+//
+// CExternalConnection::QueryInterface
+//
+// Purpose:
+//
+//
+// Parameters:
+//
+// REFIID riid - Interface being queried for.
+//
+// LPVOID FAR *ppvObj - Out pointer for the interface.
+//
+// Return Value:
+//
+// S_OK - Success
+// E_NOINTERFACE - Failure
+//
+// Function Calls:
+// Function Location
+//
+// CSimpSvrObj::QueryInterface OBJ.CPP
+//
+// Comments:
+//
+//
+//********************************************************************
+
+STDMETHODIMP CExternalConnection::QueryInterface (REFIID riid, LPVOID FAR* ppvObj)
+{
+ TestDebugOut("In CExternalConnection::QueryInterface\r\n");
+
+ return m_lpObj->QueryInterface(riid, ppvObj);
+}
+
+
+//**********************************************************************
+//
+// CExternalConnection::AddRef
+//
+// Purpose:
+//
+// Increments the reference count on CExternalConnection and the "object"
+// object.
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// The Reference count on the Object.
+//
+// Function Calls:
+// Function Location
+//
+// OuputDebugString Windows API
+// CSimpSvrObj::AddRef OBJ.CPP
+//
+// Comments:
+//
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) CExternalConnection::AddRef ()
+{
+ TestDebugOut("In CExternalConnection::AddRef\r\n");
+ ++m_nCount;
+ return m_lpObj->AddRef();
+};
+
+//**********************************************************************
+//
+// CExternalConnection::Release
+//
+// Purpose:
+//
+// Decrements the reference count of COleObject and the
+// "object" object.
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// The new reference count
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// CSimpSvrObj::Release OBJ.CPP
+//
+// Comments:
+//
+//
+//********************************************************************
+
+
+STDMETHODIMP_(ULONG) CExternalConnection::Release ()
+{
+ TestDebugOut("In CExternalConnection::Release\r\n");
+ --m_nCount;
+ return m_lpObj->Release();
+};
+
+
+
+//**********************************************************************
+//
+// CExternalConnection::AddConnection
+//
+// Purpose:
+//
+// Called when another connection is made to the object.
+//
+// Parameters:
+//
+// DWORD extconn - Type of connection
+//
+// DWORD reserved - Reserved
+//
+// Return Value:
+//
+// Strong connection count
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+// Comments:
+//
+//
+//********************************************************************
+
+STDMETHODIMP_(DWORD) CExternalConnection::AddConnection (DWORD extconn, DWORD reserved)
+{
+ TestDebugOut("In CExternalConnection::AddConnection\r\n");
+
+ if (extconn & EXTCONN_STRONG)
+ return ++m_dwStrong;
+
+ return 0;
+}
+
+//**********************************************************************
+//
+// CExternalConnection::ReleaseConnection
+//
+// Purpose:
+//
+// Called when a connection to the object is released.
+//
+// Parameters:
+//
+// DWORD extconn - Type of Connection
+//
+// DWORD reserved - Reserved
+//
+// BOOL fLastReleaseCloses - Close flag
+//
+// Return Value:
+//
+// The new reference count
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// COleObject::Close IOO.CPP
+//
+// Comments:
+//
+//
+//********************************************************************
+
+STDMETHODIMP_(DWORD) CExternalConnection::ReleaseConnection (DWORD extconn, DWORD reserved, BOOL fLastReleaseCloses)
+{
+ TestDebugOut("In CExternalConnection::ReleaseConnection\r\n");
+
+ if (extconn & EXTCONN_STRONG)
+ {
+ DWORD dwSave = --m_dwStrong;
+
+ if (!m_dwStrong && fLastReleaseCloses)
+ m_lpObj->m_OleObject.Close(OLECLOSE_SAVEIFDIRTY);
+
+ return dwSave;
+ }
+ return 0;
+}
diff --git a/private/oleutest/utests16/simpsvr/iec.h b/private/oleutest/utests16/simpsvr/iec.h
new file mode 100644
index 000000000..0b65035c8
--- /dev/null
+++ b/private/oleutest/utests16/simpsvr/iec.h
@@ -0,0 +1,44 @@
+//**********************************************************************
+// File name: iec.h
+//
+// Definition of CExternalConnection
+//
+// Copyright (c) 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+#if !defined( _IEC_H_)
+#define _IEC_H_
+
+
+#include <ole2.h>
+#include "obj.h"
+
+class CSimpSvrObj;
+
+interface CExternalConnection : public IExternalConnection
+{
+private:
+ CSimpSvrObj FAR * m_lpObj; // Ptr to object
+ int m_nCount; // Ref count
+ DWORD m_dwStrong; // Connection Count
+
+public:
+ CExternalConnection::CExternalConnection(CSimpSvrObj FAR * lpSimpSvrObj)
+ {
+ m_lpObj = lpSimpSvrObj;
+ m_nCount = 0;
+ m_dwStrong = 0;
+ };
+
+ CExternalConnection::~CExternalConnection() {};
+
+ // *** IUnknown methods ***
+ STDMETHODIMP QueryInterface (REFIID riid, LPVOID FAR* ppvObj);
+ STDMETHODIMP_(ULONG) AddRef ();
+ STDMETHODIMP_(ULONG) Release ();
+
+ // *** IExternalConnection methods ***
+ STDMETHODIMP_(DWORD) AddConnection (DWORD extconn, DWORD reserved);
+ STDMETHODIMP_(DWORD) ReleaseConnection (DWORD extconn, DWORD reserved, BOOL fLastReleaseCloses);
+};
+
+#endif
diff --git a/private/oleutest/utests16/simpsvr/ioipao.cpp b/private/oleutest/utests16/simpsvr/ioipao.cpp
new file mode 100644
index 000000000..0a85da592
--- /dev/null
+++ b/private/oleutest/utests16/simpsvr/ioipao.cpp
@@ -0,0 +1,400 @@
+//**********************************************************************
+// File name: IOIPAO.CPP
+//
+// Implementation file for the CClassFactory Class
+//
+// Functions:
+//
+// See ioipao.h for a list of member functions.
+//
+// Copyright (c) 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+
+#include "pre.h"
+#include "obj.h"
+#include "ioipao.h"
+#include "app.h"
+#include "doc.h"
+
+//**********************************************************************
+//
+// COleInPlaceActiveObject::QueryInterface
+//
+// Purpose:
+//
+//
+// Parameters:
+//
+// REFIID riid - Interface being queried for.
+//
+// LPVOID FAR *ppvObj - Out pointer for the interface.
+//
+// Return Value:
+//
+// S_OK - Success
+// E_NOINTERFACE - Failure
+//
+// Function Calls:
+// Function Location
+//
+// CSimpSvrObj::QueryInterface OBJ.CPP
+//
+// Comments:
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleInPlaceActiveObject::QueryInterface ( REFIID riid, LPVOID FAR* ppvObj)
+{
+ TestDebugOut("In COleInPlaceActiveObject::QueryInterface\r\n");
+ // need to NULL the out parameter
+ return m_lpObj->QueryInterface(riid, ppvObj);
+}
+
+//**********************************************************************
+//
+// COleInPlaceActiveObject::AddRef
+//
+// Purpose:
+//
+// Increments the reference count on COleInPlaceActiveObject and the
+// "object" object.
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// The Reference count on the "object" object.
+//
+// Function Calls:
+// Function Location
+//
+// OuputDebugString Windows API
+// CSimpSvrObj::AddRef OBJ.CPP
+//
+// Comments:
+//
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) COleInPlaceActiveObject::AddRef ()
+{
+ TestDebugOut("In COleInPlaceActiveObject::AddRef\r\n");
+
+ ++m_nCount;
+
+ return m_lpObj->AddRef();
+}
+
+//**********************************************************************
+//
+// COleInPlaceActiveObject::Release
+//
+// Purpose:
+//
+// Decrements the reference count of COleInPlaceActiveObject.
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// The new reference count
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// CSimpSvrObj::Release OBJ.CPP
+//
+// Comments:
+//
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) COleInPlaceActiveObject::Release ()
+{
+ TestDebugOut("In COleInPlaceActiveObject::Release\r\n");
+
+ --m_nCount;
+
+ return m_lpObj->Release();
+}
+
+//**********************************************************************
+//
+// COleInPlaceActiveObject::OnDocWindowActivate
+//
+// Purpose:
+//
+// Called when the doc window (in an MDI App) is (de)activated.
+//
+// Parameters:
+//
+// BOOL fActivate - TRUE if activating, FALSE if deactivating
+//
+// Return Value:
+//
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// IOleInPlaceFrame::SetActiveObject Container
+// CSimpSvrObject::AddFrameLevelUI OBJ.CPP
+//
+//
+// Comments:
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleInPlaceActiveObject::OnDocWindowActivate ( BOOL fActivate )
+{
+ TestDebugOut("In COleInPlaceActiveObject::OnDocWindowActivate\r\n");
+
+ // Activating?
+ if (fActivate)
+ m_lpObj->AddFrameLevelUI();
+
+ // No frame level tools to remove...
+
+ return ResultFromScode(S_OK);
+};
+
+//**********************************************************************
+//
+// COleInPlaceActiveObject::OnFrameWindowActivate
+//
+// Purpose:
+//
+// Called when the Frame window is (de)activating
+//
+// Parameters:
+//
+// BOOL fActivate - TRUE if activating, FALSE if Deactivating
+//
+// Return Value:
+//
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// SetFocus Windows API
+//
+//
+// Comments:
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleInPlaceActiveObject::OnFrameWindowActivate ( BOOL fActivate)
+{
+ TestDebugOut("In COleInPlaceActiveObject::OnFrameWindowActivate\r\n");
+
+ // set the focus to the object window if we are activating.
+/* if (fActivate)
+ SetFocus(m_lpObj->m_lpDoc->GethDocWnd()); */
+
+ return ResultFromScode( S_OK );
+};
+
+//**********************************************************************
+//
+// COleInPlaceActiveObject::GetWindow
+//
+// Purpose:
+//
+// Gets the objects Window Handle.
+//
+// Parameters:
+//
+// HWND FAR* lphwnd - Location to return the window handle.
+//
+// Return Value:
+//
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// CSimpSvrDoc::GethDocWnd DOC.H
+//
+//
+// Comments:
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleInPlaceActiveObject::GetWindow ( HWND FAR* lphwnd)
+{
+ TestDebugOut("In COleInPlaceActiveObject::GetWindow\r\n");
+ // need to NULL the out parameter
+ *lphwnd = m_lpObj->m_lpDoc->GethDocWnd();
+ return ResultFromScode( S_OK );
+};
+
+//**********************************************************************
+//
+// COleInPlaceActiveObject::ContextSensitiveHelp
+//
+// Purpose:
+//
+// Used to implement Context Sensitive help
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// E_NOTIMPL
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+//
+// Comments:
+//
+// See TECHNOTES.WRI include with the OLE SDK for proper
+// implementation of this function.
+//
+//********************************************************************
+
+STDMETHODIMP COleInPlaceActiveObject::ContextSensitiveHelp ( BOOL fEnterMode )
+{
+ TestDebugOut("In COleInPlaceActiveObject::ContextSensitiveHelp\r\n");
+ return ResultFromScode( E_NOTIMPL);
+};
+
+//**********************************************************************
+//
+// COleInPlaceActiveObject::TranslateAccelerator
+//
+// Purpose:
+//
+// Used for translating accelerators in .DLL objects.
+//
+// Parameters:
+//
+// LPMSG lpmsg - Pointer to a message
+//
+// Return Value:
+//
+// S_FALSE
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+//
+// Comments:
+//
+// This method should never be called since we are implemented
+// in an executable.
+//
+//********************************************************************
+
+STDMETHODIMP COleInPlaceActiveObject::TranslateAccelerator ( LPMSG lpmsg)
+{
+ TestDebugOut("In COleInPlaceActiveObject::TranslateAccelerator\r\n");
+ // no accelerator table, return FALSE
+ return ResultFromScode( S_FALSE );
+};
+
+//**********************************************************************
+//
+// COleInPlaceActiveObject::ResizeBorder
+//
+// Purpose:
+//
+// Called when the border changes size.
+//
+// Parameters:
+//
+// LPCRECT lprectBorder - New Border
+//
+// LPOLEINPLACEUIWINDOW lpUIWindow - Pointer to UIWindow
+//
+// BOOL fFrameWindow - True if lpUIWindow is the
+// frame window.
+//
+// Return Value:
+//
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+//
+// Comments:
+//
+// Need to call SetBorderSpace again...
+//
+//********************************************************************
+
+STDMETHODIMP COleInPlaceActiveObject::ResizeBorder ( LPCRECT lprectBorder,
+ LPOLEINPLACEUIWINDOW lpUIWindow,
+ BOOL fFrameWindow)
+{
+ TestDebugOut("In COleInPlaceActiveObject::ResizeBorder\r\n");
+
+ // should always have an inplace frame...
+ m_lpObj->GetInPlaceFrame()->SetBorderSpace(NULL);
+
+ // There will only be a UIWindow if in an MDI container
+ if (m_lpObj->GetUIWindow())
+ m_lpObj->GetUIWindow()->SetBorderSpace(NULL);
+
+ return ResultFromScode( S_OK );
+};
+
+//**********************************************************************
+//
+// COleInPlaceActiveObject::EnableModeless
+//
+// Purpose:
+//
+// Called to enable/disable modeless dialogs.
+//
+// Parameters:
+//
+// BOOL fEnable - TRUE to enable, FALSE to disable
+//
+// Return Value:
+//
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+//
+// Comments:
+//
+// Called by the container when a model dialog box is added/removed
+// from the screen. The appropriate action for a server application
+// is to disable/enable any modeless dialogs currently being displayed.
+// Since this application doesn't display any modeless dialogs,
+// this method is essentially ignored.
+//
+//********************************************************************
+
+STDMETHODIMP COleInPlaceActiveObject::EnableModeless ( BOOL fEnable)
+{
+ TestDebugOut("In COleInPlaceActiveObject::EnableModeless\r\n");
+ return ResultFromScode( S_OK );
+};
diff --git a/private/oleutest/utests16/simpsvr/ioipao.h b/private/oleutest/utests16/simpsvr/ioipao.h
new file mode 100644
index 000000000..05a5c51c7
--- /dev/null
+++ b/private/oleutest/utests16/simpsvr/ioipao.h
@@ -0,0 +1,50 @@
+//**********************************************************************
+// File name: IOIPAO.H
+//
+// Definition of COleInPlaceActiveObject
+//
+// Copyright (c) 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+
+#if !defined( _IOIPAO_H_)
+#define _IOIPAO_H_
+
+
+#include <ole2.h>
+#include "obj.h"
+
+class CSimpSvrObj;
+
+interface COleInPlaceActiveObject : public IOleInPlaceActiveObject
+{
+private:
+ CSimpSvrObj FAR * m_lpObj;
+ int m_nCount;
+
+public:
+ COleInPlaceActiveObject::COleInPlaceActiveObject(CSimpSvrObj FAR * lpSimpSvrObj)
+ {
+ m_lpObj = lpSimpSvrObj; // set up the back ptr
+ m_nCount = 0; // clear the ref count.
+ };
+ COleInPlaceActiveObject::~COleInPlaceActiveObject() {}; // destructor
+
+// IUnknown Methods
+
+ STDMETHODIMP QueryInterface (REFIID riid, LPVOID FAR* ppvObj);
+ STDMETHODIMP_(ULONG) AddRef ();
+ STDMETHODIMP_(ULONG) Release ();
+
+ STDMETHODIMP OnDocWindowActivate ( BOOL fActivate) ;
+ STDMETHODIMP OnFrameWindowActivate ( BOOL fActivate) ;
+ STDMETHODIMP GetWindow ( HWND FAR* lphwnd);
+ STDMETHODIMP ContextSensitiveHelp ( BOOL fEnterMode);
+ STDMETHODIMP TranslateAccelerator ( LPMSG lpmsg);
+ STDMETHODIMP ResizeBorder ( LPCRECT lprectBorder,
+ LPOLEINPLACEUIWINDOW lpUIWindow,
+ BOOL fFrameWindow);
+ STDMETHODIMP EnableModeless ( BOOL fEnable);
+
+};
+
+#endif
diff --git a/private/oleutest/utests16/simpsvr/ioipo.cpp b/private/oleutest/utests16/simpsvr/ioipo.cpp
new file mode 100644
index 000000000..310c945c6
--- /dev/null
+++ b/private/oleutest/utests16/simpsvr/ioipo.cpp
@@ -0,0 +1,413 @@
+//**********************************************************************
+// File name: IOIPO.CPP
+//
+// Implementation file for the CClassFactory Class
+//
+// Functions:
+//
+// See ioipo.h for a list of member functions.
+//
+// Copyright (c) 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+
+#include "pre.h"
+#include "obj.h"
+#include "ioipo.h"
+#include "app.h"
+#include "doc.h"
+#include "math.h"
+
+//**********************************************************************
+//
+// COleInPlaceObject::QueryInterface
+//
+// Purpose:
+//
+//
+// Parameters:
+//
+// REFIID riid - Interface being queried for.
+//
+// LPVOID FAR *ppvObj - Out pointer for the interface.
+//
+// Return Value:
+//
+// S_OK - Success
+// E_NOINTERFACE - Failure
+//
+// Function Calls:
+// Function Location
+//
+// CSimpSvrObj::QueryInterface OBJ.CPP
+//
+// Comments:
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleInPlaceObject::QueryInterface ( REFIID riid, LPVOID FAR* ppvObj)
+{
+ TestDebugOut("In COleInPlaceObject::QueryInterface\r\n");
+ // need to NULL the out parameter
+ *ppvObj = NULL;
+ return m_lpObj->QueryInterface(riid, ppvObj);
+}
+
+//**********************************************************************
+//
+// COleInPlaceObject::AddRef
+//
+// Purpose:
+//
+// Increments the reference count on COleInPlaceObject and the "object"
+// object.
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// The Reference count on the Object
+//
+// Function Calls:
+// Function Location
+//
+// OuputDebugString Windows API
+// CSimpSvrObj::AddRef OBJ.CPP
+//
+// Comments:
+//
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) COleInPlaceObject::AddRef ()
+{
+ TestDebugOut("In COleInPlaceObject::AddRef\r\n");
+ ++m_nCount;
+ return m_lpObj->AddRef();
+}
+
+//**********************************************************************
+//
+// COleInPlaceObject::Release
+//
+// Purpose:
+//
+// Decrements the reference count of COleInPlaceObject and the
+// object.
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// The new reference count
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// CSimpSvrObj::Release OBJ.CPP
+//
+// Comments:
+//
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) COleInPlaceObject::Release ()
+{
+ TestDebugOut("In COleInPlaceObject::Release\r\n");
+ --m_nCount;
+ return m_lpObj->Release();
+}
+
+//**********************************************************************
+//
+// COleInPlaceObject::InPlaceDeactivate
+//
+// Purpose:
+//
+// Called to deactivat the object
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+//
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// IOleClientSite::QueryInterface Container
+// IOleInPlaceSite::OnInPlaceDeactivate Container
+// IOleInPlaceSite::Release Container
+//
+// Comments:
+//
+//
+//********************************************************************
+
+
+STDMETHODIMP COleInPlaceObject::InPlaceDeactivate()
+{
+ TestDebugOut("In COleInPlaceObject::InPlaceDeactivate\r\n");
+
+ // if not inplace active, return NOERROR
+ if (!m_lpObj->m_fInPlaceActive)
+ return NOERROR;
+
+ // clear inplace flag
+ m_lpObj->m_fInPlaceActive = FALSE;
+
+ // deactivate the UI
+ m_lpObj->DeactivateUI();
+ m_lpObj->DoInPlaceHide();
+
+ // tell the container that we are deactivating.
+ if (m_lpObj->m_lpIPSite)
+ {
+ m_lpObj->m_lpIPSite->OnInPlaceDeactivate();
+ m_lpObj->m_lpIPSite->Release();
+ m_lpObj->m_lpIPSite =NULL;
+ }
+
+ return ResultFromScode(S_OK);
+}
+
+//**********************************************************************
+//
+// COleInPlaceObject::UIDeactivate
+//
+// Purpose:
+//
+// Instructs us to remove our UI.
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// NOERROR
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// IOleInPlaceUIWindow::SetActiveObject Container
+// IOleInPlaceFrame::SetActiveObject Container
+// IOleClientSite::QueryInterface Container
+// IOleInPlaceSite::OnUIDeactivate Container
+// IOleInPlaceSite::Release Container
+// CSimpSvrObj::DoInPlaceHide OBJ.H
+// IDataAdviseHolder::SendOnDataChange OLE
+//
+//
+// Comments:
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleInPlaceObject::UIDeactivate()
+{
+ TestDebugOut("In COleInPlaceObject::UIDeactivate\r\n");
+
+ m_lpObj->DeactivateUI();
+
+ return ResultFromScode (S_OK);
+}
+
+//**********************************************************************
+//
+// COleInPlaceObject::SetObjectRects
+//
+// Purpose:
+//
+// Called when the container clipping region or the object position
+// changes.
+//
+// Parameters:
+//
+// LPCRECT lprcPosRect - New Position Rect.
+//
+// LPCRECT lprcClipRect - New Clipping Rect.
+//
+// Return Value:
+//
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// IntersectRect Windows API
+// OffsetRect Windows API
+// CopyRect Windows API
+// MoveWindow Windows API
+// CSimpSvrDoc::GethHatchWnd DOC.H
+// CSimpSvrDoc::gethDocWnd DOC.h
+// SetHatchWindowSize OLE2UI
+//
+// Comments:
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleInPlaceObject::SetObjectRects ( LPCRECT lprcPosRect, LPCRECT lprcClipRect)
+{
+ TestDebugOut("In COleInPlaceObject::SetObjectRects\r\n");
+
+ RECT resRect;
+ POINT pt;
+
+ // Get the intersection of the clipping rect and the position rect.
+ IntersectRect(&resRect, lprcPosRect, lprcClipRect);
+
+ m_lpObj->m_xOffset = abs (resRect.left - lprcPosRect->left);
+ m_lpObj->m_yOffset = abs (resRect.top - lprcPosRect->top);
+
+ m_lpObj->m_scale = (float)(lprcPosRect->right - lprcPosRect->left)/m_lpObj->m_size.x;
+
+ if (m_lpObj->m_scale == 0)
+ m_lpObj->m_scale = 1;
+
+ char szBuffer[255];
+ wsprintf(szBuffer,"New Scale %3d\r\n",m_lpObj->m_scale);
+ TestDebugOut(szBuffer);
+
+ // Adjust the size of the Hatch Window.
+ SetHatchWindowSize(m_lpObj->m_lpDoc->GethHatchWnd(),(LPRECT) lprcPosRect, (LPRECT) lprcClipRect, &pt);
+
+ // offset the rect
+ OffsetRect(&resRect, pt.x, pt.y);
+
+ CopyRect(&m_lpObj->m_posRect, lprcPosRect);
+
+ // Move the actual object window
+ MoveWindow(m_lpObj->m_lpDoc->GethDocWnd(),
+ resRect.left,
+ resRect.top,
+ resRect.right - resRect.left,
+ resRect.bottom - resRect.top,
+ TRUE);
+
+
+ return ResultFromScode( S_OK );
+};
+
+//**********************************************************************
+//
+// COleInPlaceObject::GetWindow
+//
+// Purpose:
+//
+// Returns the Window handle of the inplace object
+//
+// Parameters:
+//
+// HWND FAR* lphwnd - Out pointer in which to return the window
+// Handle.
+//
+// Return Value:
+//
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// CSimpleDoc::GethDocWnd DOC.H
+//
+// Comments:
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleInPlaceObject::GetWindow ( HWND FAR* lphwnd)
+{
+ TestDebugOut("In COleInPlaceObject::GetWindow\r\n");
+ *lphwnd = m_lpObj->m_lpDoc->GethDocWnd();
+
+ return ResultFromScode( S_OK );
+};
+
+//**********************************************************************
+//
+// COleInPlaceObject::ContextSensitiveHelp
+//
+// Purpose:
+//
+// Used in performing Context Sensitive Help
+//
+// Parameters:
+//
+// BOOL fEnterMode - Flag to determine if enter or exiting
+// Context Sensitive Help.
+//
+// Return Value:
+//
+// E_NOTIMPL
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+// Comments:
+//
+// This function is not implemented due to the fact that it is
+// beyond the scope of a simple object. All *real* applications
+// are going to want to implement this function, otherwise any
+// container that supports context sensitive help will not work
+// properly while the object is in place.
+//
+// See TECHNOTES.WRI include with the OLE SDK for details on
+// Implementing this method.
+//
+//********************************************************************
+
+STDMETHODIMP COleInPlaceObject::ContextSensitiveHelp ( BOOL fEnterMode)
+{
+ TestDebugOut("In COleInPlaceObject::ContextSensitiveHelp\r\n");
+ return ResultFromScode( E_NOTIMPL);
+};
+
+//**********************************************************************
+//
+// COleInPlaceObject::ReactivateAndUndo
+//
+// Purpose:
+//
+// Called when the container wants to undo the last edit made in
+// the object.
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// INPLACE_E_NOTUNDOABLE
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+// Comments:
+//
+// Since this server does not support undo, the value
+// INPLACE_E_NOTUNDOABLE is always returned.
+//
+//********************************************************************
+
+STDMETHODIMP COleInPlaceObject::ReactivateAndUndo ()
+{
+ TestDebugOut("In COleInPlaceObject::ReactivateAndUndo\r\n");
+ return ResultFromScode( INPLACE_E_NOTUNDOABLE );
+};
diff --git a/private/oleutest/utests16/simpsvr/ioipo.h b/private/oleutest/utests16/simpsvr/ioipo.h
new file mode 100644
index 000000000..a30ebd171
--- /dev/null
+++ b/private/oleutest/utests16/simpsvr/ioipo.h
@@ -0,0 +1,45 @@
+//**********************************************************************
+// File name: ioipo.h
+//
+// Definition of COleInPlaceObject
+//
+// Copyright (c) 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+
+#if !defined( _IOIPO_H_)
+#define _IOIPO_H_
+
+
+#include <ole2.h>
+#include "obj.h"
+
+class CSimpSvrObj;
+
+interface COleInPlaceObject : public IOleInPlaceObject
+{
+private:
+ CSimpSvrObj FAR * m_lpObj;
+ int m_nCount;
+
+public:
+ COleInPlaceObject::COleInPlaceObject(CSimpSvrObj FAR * lpSimpSvrObj)
+ {
+ m_lpObj = lpSimpSvrObj;
+ m_nCount = 0;
+ };
+ COleInPlaceObject::~COleInPlaceObject() {};
+
+// IUnknown Methods
+ STDMETHODIMP QueryInterface (REFIID riid, LPVOID FAR* ppvObj);
+ STDMETHODIMP_(ULONG) AddRef ();
+ STDMETHODIMP_(ULONG) Release ();
+
+ STDMETHODIMP InPlaceDeactivate ();
+ STDMETHODIMP UIDeactivate () ;
+ STDMETHODIMP SetObjectRects ( LPCRECT lprcPosRect, LPCRECT lprcClipRect);
+ STDMETHODIMP GetWindow ( HWND FAR* lphwnd) ;
+ STDMETHODIMP ContextSensitiveHelp ( BOOL fEnterMode);
+ STDMETHODIMP ReactivateAndUndo ();
+};
+
+#endif
diff --git a/private/oleutest/utests16/simpsvr/ioo.cpp b/private/oleutest/utests16/simpsvr/ioo.cpp
new file mode 100644
index 000000000..b8cfb1ffa
--- /dev/null
+++ b/private/oleutest/utests16/simpsvr/ioo.cpp
@@ -0,0 +1,1082 @@
+//**********************************************************************
+// File name: IOO.CPP
+//
+// Implementation file for the COleObject Class
+//
+// Functions:
+//
+// See ioo.h for a list of member functions.
+//
+// Copyright (c) 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+
+#include "pre.h"
+#include "obj.h"
+#include "ioo.h"
+#include "app.h"
+#include "doc.h"
+
+#define VERB_OPEN 1
+
+//**********************************************************************
+//
+// COleObject::QueryInterface
+//
+// Purpose:
+//
+//
+// Parameters:
+//
+// REFIID riid - Interface being queried for.
+//
+// LPVOID FAR *ppvObj - Out pointer for the interface.
+//
+// Return Value:
+//
+// S_OK - Success
+// E_NOINTERFACE - Failure
+//
+// Function Calls:
+// Function Location
+//
+// CSimpSvrObj::QueryInterface OBJ.CPP
+//
+// Comments:
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleObject::QueryInterface ( REFIID riid, LPVOID FAR* ppvObj)
+{
+ TestDebugOut("In COleObject::QueryInterface\r\n");
+ return m_lpObj->QueryInterface(riid, ppvObj);
+}
+
+//**********************************************************************
+//
+// COleObject::AddRef
+//
+// Purpose:
+//
+// Increments the reference count on COleObject and the "object"
+// object.
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// The Reference count on the Object.
+//
+// Function Calls:
+// Function Location
+//
+// OuputDebugString Windows API
+// CSimpSvrObj::AddRef OBJ.CPP
+//
+// Comments:
+//
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) COleObject::AddRef ()
+{
+ TestDebugOut("In COleObject::AddRef\r\n");
+ ++m_nCount;
+ return m_lpObj->AddRef();
+}
+
+//**********************************************************************
+//
+// COleObject::Release
+//
+// Purpose:
+//
+// Decrements the reference count of COleObject and the
+// "object" object.
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// The new reference count
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// CSimpSvrObj::Release OBJ.CPP
+//
+// Comments:
+//
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) COleObject::Release ()
+{
+ TestDebugOut("In COleObject::Release\r\n");
+ --m_nCount;
+ return m_lpObj->Release();
+}
+
+//**********************************************************************
+//
+// COleObject::SetClientSite
+//
+// Purpose:
+//
+// Called to notify the object of it's client site.
+//
+// Parameters:
+//
+// LPOLECLIENTSITE pClientSite - ptr to new client site
+//
+// Return Value:
+//
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// IOleClientSite::Release Container
+// IOleClientSite::AddRef Container
+//
+// Comments:
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleObject::SetClientSite ( LPOLECLIENTSITE pClientSite)
+{
+ TestDebugOut("In COleObject::SetClientSite\r\n");
+
+ // if we already have a client site, release it.
+ if (m_lpObj->m_lpOleClientSite)
+ {
+ m_lpObj->m_lpOleClientSite->Release();
+ m_lpObj->m_lpOleClientSite = NULL;
+ }
+
+ // store copy of the client site.
+ m_lpObj->m_lpOleClientSite = pClientSite;
+
+ // AddRef it so it doesn't go away.
+ if (m_lpObj->m_lpOleClientSite)
+ m_lpObj->m_lpOleClientSite->AddRef();
+
+ return ResultFromScode(S_OK);
+}
+
+//**********************************************************************
+//
+// COleObject::Advise
+//
+// Purpose:
+//
+// Called to set up an advise on the OLE object.
+//
+// Parameters:
+//
+// LPADVISESINK pAdvSink - ptr to the Advise Sink for notification
+//
+// DWORD FAR* pdwConnection - place to return the connection ID.
+//
+// Return Value:
+//
+// Passed back from IOleAdviseHolder::Advise.
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// CreateOleAdviseHolder OLE API
+// IOleAdviseHolder::Advise OLE
+//
+// Comments:
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleObject::Advise ( LPADVISESINK pAdvSink, DWORD FAR* pdwConnection)
+{
+ TestDebugOut("In COleObject::Advise\r\n");
+
+ // if we haven't made an OleAdviseHolder yet, make one.
+ if (!m_lpObj->m_lpOleAdviseHolder)
+ CreateOleAdviseHolder(&m_lpObj->m_lpOleAdviseHolder);
+
+ // pass this call onto the OleAdviseHolder.
+ return m_lpObj->m_lpOleAdviseHolder->Advise(pAdvSink, pdwConnection);
+}
+
+//**********************************************************************
+//
+// COleObject::SetHostNames
+//
+// Purpose:
+//
+// Called to pass strings for Window titles.
+//
+// Parameters:
+//
+// LPCSTR szContainerApp - ptr to string describing Container App
+//
+// LPCSTR szContainerObj - ptr to string describing Object
+//
+// Return Value:
+//
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+// Comments:
+//
+// This routine is called so that the server application can
+// set the window title appropriately.
+//
+//********************************************************************
+
+STDMETHODIMP COleObject::SetHostNames ( LPCSTR szContainerApp, LPCSTR szContainerObj)
+{
+ TestDebugOut("In COleObject::SetHostNames\r\n");
+
+ return ResultFromScode( S_OK);
+};
+
+//**********************************************************************
+//
+// COleObject::DoVerb
+//
+// Purpose:
+//
+// Called by the container application to invoke a verb.
+//
+// Parameters:
+//
+// LONG iVerb - The value of the verb to be
+// invoked.
+//
+// LPMSG lpmsg - The message that caused the
+// verb to be invoked.
+//
+// LPOLECLIENTSITE pActiveSite - Ptr to the active client site.
+//
+// LONG lindex - Used in extended layout
+//
+// HWND hwndParent - This should be the window handle of
+// the window in which we are contained.
+// This value could be used to "fake"
+// inplace activation in a manner similar
+// to Video for Windows in OLE 1.0.
+//
+// LPCRECT lprcPosRect - The rectangle that contains the object
+// within hwndParent. Also used to
+// "fake" inplace activation.
+//
+// Return Value:
+//
+// OLE_E_NOTINPLACEACTIVE - Returned if attempted to undo while not
+// inplace active.
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// ShowWindow Windows API
+// CSimpSvrObj::DoInPlaceActivate OBJ.CPP
+// CSimpSvrObj::DoInPlaceHide OBJ.CPP
+// COleObject::OpenEdit IOO.CPP
+// CSimpSvrDoc::GethDocWnd DOC.H
+// COleInPlaceObj::InPlaceDeactivate IOIPO.CPP
+//
+// Comments:
+//
+// Be sure to look at TECHNOTES.WRI included with the OLE
+// SDK for a description of handling the inplace verbs
+// properly.
+//
+//********************************************************************
+
+STDMETHODIMP COleObject::DoVerb ( LONG iVerb,
+ LPMSG lpmsg,
+ LPOLECLIENTSITE pActiveSite,
+ LONG lindex,
+ HWND hwndParent,
+ LPCRECT lprcPosRect)
+{
+ TestDebugOut("In COleObject::DoVerb\r\n");
+
+ switch (iVerb)
+ {
+ case OLEIVERB_SHOW:
+ case OLEIVERB_PRIMARY:
+ if (m_fOpen)
+ SetFocus(m_lpObj->m_lpDoc->GethAppWnd());
+ else if (m_lpObj->DoInPlaceActivate(iVerb) == FALSE)
+ OpenEdit(pActiveSite);
+ break;
+
+ case OLEIVERB_UIACTIVATE:
+ if (m_fOpen)
+ return ResultFromScode (E_FAIL);
+
+ // inplace activate
+ if (!m_lpObj->DoInPlaceActivate(iVerb))
+ return ResultFromScode (E_FAIL);
+ break;
+
+ case OLEIVERB_DISCARDUNDOSTATE:
+ // don't have to worry about this situation as we don't
+ // support an undo state.
+ if (!m_lpObj->m_fInPlaceActive)
+ return ResultFromScode(OLE_E_NOT_INPLACEACTIVE);
+ break;
+
+ case OLEIVERB_HIDE:
+ // if inplace active, do an "inplace" hide, otherwise
+ // just hide the app window.
+ if (m_lpObj->m_fInPlaceActive)
+ {
+ m_lpObj->DeactivateUI();
+ m_lpObj->DoInPlaceHide();
+ }
+ else
+ m_lpObj->m_lpDoc->GetApp()->HideAppWnd();
+ break;
+
+ case OLEIVERB_OPEN:
+ case VERB_OPEN:
+ // if inplace active, deactivate
+ if (m_lpObj->m_fInPlaceActive)
+ m_lpObj->m_OleInPlaceObject.InPlaceDeactivate();
+
+ // open into another window.
+ OpenEdit(pActiveSite);
+ break;
+
+ default:
+ if (iVerb < 0)
+ return ResultFromScode(E_FAIL);
+ }
+
+ return ResultFromScode( S_OK);
+};
+
+//**********************************************************************
+//
+// COleObject::GetExtent
+//
+// Purpose:
+//
+// Returns the extent of the object.
+//
+// Parameters:
+//
+// DWORD dwDrawAspect - The aspect in which to get the size.
+//
+// LPSIZEL lpsizel - Out ptr to return the size.
+//
+// Return Value:
+//
+//
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// XformWidthInPixelsToHimetric OLE2UI
+// XformHeightInPixelsToHimetric OLE2UI
+//
+// Comments:
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleObject::GetExtent ( DWORD dwDrawAspect, LPSIZEL lpsizel)
+{
+ TestDebugOut("In COleObject::GetExtent\r\n");
+
+ SCODE sc = E_FAIL;
+
+ // Only DVASPECT_CONTENT is supported....
+ if (dwDrawAspect == DVASPECT_CONTENT)
+ {
+ sc = S_OK;
+
+ // return the correct size in HIMETRIC...
+ lpsizel->cx = XformWidthInPixelsToHimetric(NULL, m_lpObj->m_size.x);
+ lpsizel->cy = XformHeightInPixelsToHimetric(NULL, m_lpObj->m_size.y);
+ }
+
+ return ResultFromScode( sc );
+};
+
+//**********************************************************************
+//
+// COleObject::Update
+//
+// Purpose:
+//
+// Called to get the most up to date data
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// IDataAdviseHolder::SendOnDataChange OLE
+//
+// Comments:
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleObject::Update()
+{
+ TestDebugOut("In COleObject::Update\r\n");
+
+ // force an update
+ m_lpObj->SendOnDataChange();
+
+ return ResultFromScode( S_OK );
+};
+
+//**********************************************************************
+//
+// COleObject::Close
+//
+// Purpose:
+//
+// Called when the OLE object needs to be closed
+//
+// Parameters:
+//
+// DWORD dwSaveOption - Flags to instruct the server how to prompt
+// the user.
+//
+// Return Value:
+//
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// CSimpSvrDoc::Close DOC.CPP
+//
+// Comments:
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleObject::Close ( DWORD dwSaveOption)
+{
+ TestDebugOut("In COleObject::Close\r\n");
+
+ // delegate to the document object.
+ m_lpObj->m_lpDoc->Close();
+
+ return ResultFromScode( S_OK );
+};
+
+//**********************************************************************
+//
+// COleObject::Unadvise
+//
+// Purpose:
+//
+// Breaks down an OLE advise that has been set up on this object.
+//
+// Parameters:
+//
+// DWORD dwConnection - Connection that needs to be broken down
+//
+// Return Value:
+//
+// Passed back from IOleAdviseHolder::Unadvise
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// IOleAdviseHolder::Unadvise OLE
+//
+// Comments:
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleObject::Unadvise ( DWORD dwConnection)
+{
+ TestDebugOut("In COleObject::Unadvise\r\n");
+
+ // pass on to OleAdviseHolder.
+ return m_lpObj->m_lpOleAdviseHolder->Unadvise(dwConnection);
+};
+
+//**********************************************************************
+//
+// COleObject::EnumVerbs
+//
+// Purpose:
+//
+// Enumerates the verbs associated with this object.
+//
+// Parameters:
+//
+// LPENUMOLEVERB FAR* ppenumOleVerb - Out ptr in which to return
+// the enumerator
+//
+// Return Value:
+//
+// OLE_S_USEREG - Instructs OLE to use the verbs found in the
+// REG DB for this server.
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+// Comments:
+//
+// In a .DLL, an application cannot return OLE_S_USEREG. This is
+// due to the fact that the default object handler is not being
+// used, and the container is really making direct function calls
+// into the server .DLL.
+//
+//********************************************************************
+
+STDMETHODIMP COleObject::EnumVerbs ( LPENUMOLEVERB FAR* ppenumOleVerb)
+{
+ TestDebugOut("In COleObject::EnumVerbs\r\n");
+
+ return ResultFromScode( OLE_S_USEREG );
+};
+
+//**********************************************************************
+//
+// COleObject::GetClientSite
+//
+// Purpose:
+//
+// Called to get the current client site of the object.
+//
+// Parameters:
+//
+// LPOLECLIENTSITE FAR* ppClientSite - Out ptr in which to return the
+// client site.
+//
+// Return Value:
+//
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+// Comments:
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleObject::GetClientSite ( LPOLECLIENTSITE FAR* ppClientSite)
+{
+ TestDebugOut("In COleObject::GetClientSite\r\n");
+ *ppClientSite = m_lpObj->m_lpOleClientSite;
+ return ResultFromScode( S_OK );
+}
+
+//**********************************************************************
+//
+// COleObject::SetMoniker
+//
+// Purpose:
+//
+// Used to set the objects moniker
+//
+// Parameters:
+//
+// DWORD dwWhichMoniker - Type of moniker being set
+//
+// LPMONIKER pmk - Pointer to the moniker
+//
+// Return Value:
+//
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+// Comments:
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleObject::SetMoniker ( DWORD dwWhichMoniker, LPMONIKER pmk)
+{
+ TestDebugOut("In COleObject::SetMoniker\r\n");
+
+ LPMONIKER lpmk;
+
+ if (! m_lpObj->GetOleClientSite())
+ return ResultFromScode (E_FAIL);
+
+ if (m_lpObj->GetOleClientSite()->GetMoniker (OLEGETMONIKER_ONLYIFTHERE, OLEWHICHMK_OBJFULL, &lpmk) != NOERROR)
+ return ResultFromScode (E_FAIL);
+
+
+ if (m_lpObj->GetOleAdviseHolder())
+ m_lpObj->GetOleAdviseHolder()->SendOnRename(lpmk);
+
+ LPRUNNINGOBJECTTABLE lpRot;
+
+ if (GetRunningObjectTable(0, &lpRot) == NOERROR)
+ {
+ if (m_lpObj->m_dwRegister)
+ lpRot->Revoke(m_lpObj->m_dwRegister);
+
+ lpRot->Register(0, m_lpObj, lpmk, &m_lpObj->m_dwRegister);
+
+ lpRot->Release();
+ }
+
+
+ return ResultFromScode( S_OK );
+};
+
+//**********************************************************************
+//
+// COleObject::GetMoniker
+//
+// Purpose:
+//
+////
+// Parameters:
+//
+// DWORD dwAssign - Assignment for the moniker
+//
+// DWORD dwWhichMoniker - Which moniker to return
+//
+// LPMONIKER FAR* ppmk - An out ptr to return the moniker
+//
+// Return Value:
+//
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+// Comments:
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleObject::GetMoniker ( DWORD dwAssign, DWORD dwWhichMoniker,
+ LPMONIKER FAR* ppmk)
+{
+ TestDebugOut("In COleObject::GetMoniker\r\n");
+ // need to NULL the out parameter
+ *ppmk = NULL;
+
+ return m_lpObj->GetOleClientSite()->GetMoniker (OLEGETMONIKER_ONLYIFTHERE, OLEWHICHMK_OBJFULL, ppmk);
+};
+
+//**********************************************************************
+//
+// COleObject::InitFromData
+//
+// Purpose:
+//
+// Initialize the object from the passed pDataObject.
+//
+// Parameters:
+//
+// LPDATAOBJECT pDataObject - Pointer to data transfer object
+// to be used in the initialization
+//
+// BOOL fCreation - TRUE if the object is currently being
+// created.
+//
+// DWORD dwReserved - Reserved
+//
+// Return Value:
+//
+// S_FALSE
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+// Comments:
+//
+// We don't support this functionality, so we will always return
+// error.
+//
+//********************************************************************
+
+STDMETHODIMP COleObject::InitFromData ( LPDATAOBJECT pDataObject,
+ BOOL fCreation,
+ DWORD dwReserved)
+{
+ TestDebugOut("In COleObject::InitFromData\r\n");
+
+ return ResultFromScode( S_FALSE );
+};
+
+//**********************************************************************
+//
+// COleObject::GetClipboardData
+//
+// Purpose:
+//
+// Returns an IDataObject that is the same as doing an OleSetClipboard
+//
+// Parameters:
+//
+// DWORD dwReserved - Reserved
+//
+// LPDATAOBJECT FAR* ppDataObject - Out ptr for the Data Object.
+//
+// Return Value:
+//
+// OLE_E_NOTSUPPORTED
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+// Comments:
+//
+// Support of this method is optional.
+//
+//********************************************************************
+
+STDMETHODIMP COleObject::GetClipboardData ( DWORD dwReserved,
+ LPDATAOBJECT FAR* ppDataObject)
+{
+ TestDebugOut("In COleObject::GetClipboardData\r\n");
+ // NULL the out ptr
+ *ppDataObject = NULL;
+ return ResultFromScode( E_NOTIMPL );
+};
+
+//**********************************************************************
+//
+// COleObject::IsUpToDate
+//
+// Purpose:
+//
+// Determines if an object is up to date
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+// Comments:
+//
+// Our embedded object is always up to date. This function is
+// particularly useful in linking situations.
+//
+//********************************************************************
+
+STDMETHODIMP COleObject::IsUpToDate()
+{
+ TestDebugOut("In COleObject::IsUpToDate\r\n");
+ return ResultFromScode( S_OK );
+};
+
+//**********************************************************************
+//
+// COleObject::GetUserClassID
+//
+// Purpose:
+//
+// Returns the applications CLSID
+//
+// Parameters:
+//
+// CLSID FAR* pClsid - Out ptr to return the CLSID
+//
+// Return Value:
+//
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// CPersistStorage::GetClassID IPS.CPP
+//
+// Comments:
+//
+// This function is just delegated to IPS::GetClassID.
+//
+//********************************************************************
+
+STDMETHODIMP COleObject::GetUserClassID ( CLSID FAR* pClsid)
+{
+ TestDebugOut("In COleObject::GetUserClassID\r\n");
+
+ m_lpObj->m_PersistStorage.GetClassID(pClsid);
+ return ResultFromScode( S_OK );
+};
+
+//**********************************************************************
+//
+// COleObject::GetUserType
+//
+// Purpose:
+//
+// Used to get a user presentable id for this object
+//
+// Parameters:
+//
+// DWORD dwFormOfType - The ID requested
+//
+// LPSTR FAR* pszUserType - Out ptr to return the string
+//
+// Return Value:
+//
+// OLE_S_USEREG - Use the reg db to get these entries.
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+// Comments:
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleObject::GetUserType ( DWORD dwFormOfType, LPSTR FAR* pszUserType)
+{
+ TestDebugOut("In COleObject::GetUserType\r\n");
+
+ return ResultFromScode( OLE_S_USEREG );
+};
+
+//**********************************************************************
+//
+// COleObject::SetExtent
+//
+// Purpose:
+//
+// Called to set the extent of the object.
+//
+// Parameters:
+//
+// DWORD dwDrawAspect - Aspect to have its size set
+//
+// LPSIZEL lpsizel - New size of the object.
+//
+// Return Value:
+//
+// E_NOTIMPL - This function is not curently implemented.
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+// Comments:
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleObject::SetExtent ( DWORD dwDrawAspect, LPSIZEL lpsizel)
+{
+ TestDebugOut("In COleObject::SetExtent\r\n");
+ return ResultFromScode( E_NOTIMPL);
+};
+
+//**********************************************************************
+//
+// COleObject::EnumAdvise
+//
+// Purpose:
+//
+// Returns an enumerate which enumerates the outstanding advises
+// associated with this OLE object.
+//
+// Parameters:
+//
+// LPENUMSTATDATA FAR* ppenumAdvise - Out ptr in which to return
+// the enumerator.
+//
+// Return Value:
+//
+// Passed on from IOleAdviseHolder::EnumAdvise.
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// IOleAdviseHolder::EnumAdvise OLE
+//
+// Comments:
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleObject::EnumAdvise ( LPENUMSTATDATA FAR* ppenumAdvise)
+{
+ TestDebugOut("In COleObject::EnumAdvise\r\n");
+ // need to NULL the out parameter
+ *ppenumAdvise = NULL;
+
+ // pass on to the OLE Advise holder.
+ return m_lpObj->m_lpOleAdviseHolder->EnumAdvise(ppenumAdvise);
+};
+
+//**********************************************************************
+//
+// COleObject::GetMiscStatus
+//
+// Purpose:
+//
+// Return status information about the object
+//
+// Parameters:
+//
+// DWORD dwAspect - Aspect interested in.
+//
+// DWORD FAR* pdwStatus - Out ptr in which to return the bits.
+//
+// Return Value:
+//
+// CO_E_READREGDB - Tell the library to use the reg DB.
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+// Comments:
+//
+//
+//********************************************************************
+
+STDMETHODIMP COleObject::GetMiscStatus ( DWORD dwAspect, DWORD FAR* pdwStatus)
+{
+ TestDebugOut("In COleObject::GetMiscStatus\r\n");
+ // need to NULL the out parameter
+ *pdwStatus = NULL;
+ return ResultFromScode( OLE_S_USEREG );
+};
+
+//**********************************************************************
+//
+// COleObject::SetColorScheme
+//
+// Purpose:
+//
+// Used to set the palette for the object to use.
+//
+// Parameters:
+//
+// LPLOGPALETTE lpLogpal - Pointer to the LOGPALETTE to be used.
+//
+// Return Value:
+//
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+// Comments:
+//
+// This server ignores this method.
+//
+//********************************************************************
+
+STDMETHODIMP COleObject::SetColorScheme ( LPLOGPALETTE lpLogpal)
+{
+ TestDebugOut("In COleObject::SetColorScheme\r\n");
+ return ResultFromScode( S_OK );
+};
+
+//**********************************************************************
+//
+// COleObject::OpenEdit
+//
+// Purpose:
+//
+// Used to Open the object into a seperate window.
+//
+// Parameters:
+//
+// LPOLECLIENTSITE pActiveSite - Pointer to the Active clientsite.
+//
+// Return Value:
+//
+// None.
+//
+// Function Calls:
+// Function Location
+//
+// IOleClientSite::OnShowWindow Container
+// ShowWindow Windows API
+// UpdateWindow Windows API
+// TestDebugOut Windows API
+// CSimpSvrDoc::GethAppWnd DOC.H
+// CSimpSvrDoc::GethHatchWnd DOC.H
+//
+// Comments:
+//
+//
+//********************************************************************
+
+void COleObject::OpenEdit(LPOLECLIENTSITE pActiveSite)
+{
+ if (m_lpObj->GetOleClientSite())
+ m_lpObj->GetOleClientSite()->ShowObject();
+
+
+ m_fOpen = TRUE;
+
+ // tell the site we are opening so the object can be hatched out.
+ if (m_lpObj->GetOleClientSite())
+ m_lpObj->GetOleClientSite()->OnShowWindow(TRUE);
+
+
+ m_lpObj->m_lpDoc->ShowDocWnd();
+
+ m_lpObj->m_lpDoc->HideHatchWnd();
+
+ // Show app window.
+ m_lpObj->m_lpDoc->GetApp()->ShowAppWnd();
+
+ SetFocus(m_lpObj->m_lpDoc->GethAppWnd());
+}
diff --git a/private/oleutest/utests16/simpsvr/ioo.h b/private/oleutest/utests16/simpsvr/ioo.h
new file mode 100644
index 000000000..89856b104
--- /dev/null
+++ b/private/oleutest/utests16/simpsvr/ioo.h
@@ -0,0 +1,73 @@
+//**********************************************************************
+// File name: ioo.h
+//
+// Definition of COleObject
+//
+// Copyright (c) 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+#if !defined( _IOO_H_)
+#define _IOO_H_
+
+
+#include <ole2.h>
+#include "obj.h"
+
+class CSimpSvrObj;
+
+interface COleObject : public IOleObject
+{
+private:
+ CSimpSvrObj FAR * m_lpObj;
+ int m_nCount;
+ BOOL m_fOpen;
+
+public:
+ COleObject::COleObject(CSimpSvrObj FAR * lpSimpSvrObj)
+ {
+ m_lpObj = lpSimpSvrObj;
+ m_nCount = 0;
+ m_fOpen = FALSE;
+ };
+ COleObject::~COleObject()
+ {
+ };
+ STDMETHODIMP QueryInterface (REFIID riid, LPVOID FAR* ppvObj);
+ STDMETHODIMP_(ULONG) AddRef ();
+ STDMETHODIMP_(ULONG) Release ();
+
+ STDMETHODIMP SetClientSite (LPOLECLIENTSITE pClientSite);
+ STDMETHODIMP Advise (LPADVISESINK pAdvSink, DWORD FAR* pdwConnection);
+ STDMETHODIMP SetHostNames ( LPCSTR szContainerApp, LPCSTR szContainerObj);
+ STDMETHODIMP DoVerb ( LONG iVerb,
+ LPMSG lpmsg,
+ LPOLECLIENTSITE pActiveSite,
+ LONG lindex,
+ HWND hwndParent,
+ LPCRECT lprcPosRect);
+ STDMETHODIMP GetExtent ( DWORD dwDrawAspect, LPSIZEL lpsizel);
+ STDMETHODIMP Update () ;
+ STDMETHODIMP Close ( DWORD dwSaveOption) ;
+ STDMETHODIMP Unadvise ( DWORD dwConnection);
+ STDMETHODIMP EnumVerbs ( LPENUMOLEVERB FAR* ppenumOleVerb) ;
+ STDMETHODIMP GetClientSite ( LPOLECLIENTSITE FAR* ppClientSite);
+ STDMETHODIMP SetMoniker ( DWORD dwWhichMoniker, LPMONIKER pmk);
+ STDMETHODIMP GetMoniker ( DWORD dwAssign, DWORD dwWhichMoniker,
+ LPMONIKER FAR* ppmk);
+ STDMETHODIMP InitFromData ( LPDATAOBJECT pDataObject,
+ BOOL fCreation,
+ DWORD dwReserved);
+ STDMETHODIMP GetClipboardData ( DWORD dwReserved,
+ LPDATAOBJECT FAR* ppDataObject);
+ STDMETHODIMP IsUpToDate ();
+ STDMETHODIMP GetUserClassID ( CLSID FAR* pClsid);
+ STDMETHODIMP GetUserType ( DWORD dwFormOfType, LPSTR FAR* pszUserType);
+ STDMETHODIMP SetExtent ( DWORD dwDrawAspect, LPSIZEL lpsizel);
+ STDMETHODIMP EnumAdvise ( LPENUMSTATDATA FAR* ppenumAdvise);
+ STDMETHODIMP GetMiscStatus ( DWORD dwAspect, DWORD FAR* pdwStatus);
+ STDMETHODIMP SetColorScheme ( LPLOGPALETTE lpLogpal);
+
+ void OpenEdit(LPOLECLIENTSITE pActiveSite);
+
+};
+
+#endif
diff --git a/private/oleutest/utests16/simpsvr/ips.cpp b/private/oleutest/utests16/simpsvr/ips.cpp
new file mode 100644
index 000000000..fe695cb18
--- /dev/null
+++ b/private/oleutest/utests16/simpsvr/ips.cpp
@@ -0,0 +1,651 @@
+//**********************************************************************
+// File name: ips.cpp
+//
+// Implementation file for the CSimpSvrApp Class
+//
+// Functions:
+//
+// See ips.h for a list of member functions.
+//
+// Copyright (c) 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+
+#include "pre.h"
+#include "obj.h"
+#include "ips.h"
+#include "app.h"
+#include "doc.h"
+
+#include <storage.h>
+
+#ifdef WIN32
+DEFINE_GUID(GUID_SIMPLE, 0xBCF6D4A0, 0xBE8C, 0x1068, 0xB6, 0xD4, 0x00, 0xDD, 0x01, 0x0C, 0x05, 0x09);
+#else
+DEFINE_GUID(GUID_SIMPLE, 0x9fb878d0, 0x6f88, 0x101b, 0xbc, 0x65, 0x00, 0x00, 0x0b, 0x65, 0xc7, 0xa6);
+#endif
+
+//**********************************************************************
+//
+// CPersistStorage::QueryInterface
+//
+// Purpose:
+//
+//
+// Parameters:
+//
+// REFIID riid - Interface being queried for.
+//
+// LPVOID FAR *ppvObj - Out pointer for the interface.
+//
+// Return Value:
+//
+// S_OK - Success
+// E_NOINTERFACE - Failure
+//
+// Function Calls:
+// Function Location
+//
+// CSimpSvrObj::QueryInterface OBJ.CPP
+//
+// Comments:
+//
+//
+//********************************************************************
+
+STDMETHODIMP CPersistStorage::QueryInterface ( REFIID riid, LPVOID FAR* ppvObj)
+{
+ TestDebugOut("In CPersistStorage::QueryInterface\r\n");
+ // need to NULL the out parameter
+ return m_lpObj->QueryInterface(riid, ppvObj);
+};
+
+//**********************************************************************
+//
+// CPersistStorage::AddRef
+//
+// Purpose:
+//
+// Increments the reference count on CPersistStorage and the "object"
+// object.
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// The Reference count on the Object.
+//
+// Function Calls:
+// Function Location
+//
+// OuputDebugString Windows API
+// CSimpSvrObj::AddRef OBJ.CPP
+//
+// Comments:
+//
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) CPersistStorage::AddRef ()
+{
+ TestDebugOut("In CPersistStorage::AddRef\r\n");
+ ++m_nCount;
+ return m_lpObj->AddRef();
+};
+
+//**********************************************************************
+//
+// CPersistStorage::Release
+//
+// Purpose:
+//
+// Decrements the reference count of CPersistStorage and the
+// "object" object.
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// The new reference count
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// CSimpSvrObj::Release OBJ.CPP
+//
+// Comments:
+//
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) CPersistStorage::Release ()
+{
+ TestDebugOut("In CPersistStorage::Release\r\n");
+ --m_nCount;
+ return m_lpObj->Release();
+};
+
+//**********************************************************************
+//
+// CPersistStorage::InitNew
+//
+// Purpose:
+//
+// Used to give a new OLE object a ptr to its storage.
+//
+// Parameters:
+//
+// LPSTORAGE pStg - Pointer to the storage
+//
+// Return Value:
+//
+//
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// IStorage::Release OLE
+// IStorage::AddRef OLE
+//
+//
+// Comments:
+//
+//
+//********************************************************************
+
+STDMETHODIMP CPersistStorage::InitNew (LPSTORAGE pStg)
+{
+ TestDebugOut("In CPersistStorage::InitNew\r\n");
+
+ // release any streams and storages that may be open
+ ReleaseStreamsAndStorage();
+
+ m_lpObj->m_lpStorage = pStg;
+
+ // AddRef the new Storage
+ if (m_lpObj->m_lpStorage)
+ m_lpObj->m_lpStorage->AddRef();
+
+ CreateStreams(m_lpObj->m_lpStorage);
+
+ return ResultFromScode(S_OK);
+}
+
+//**********************************************************************
+//
+// CPersistStorage::GetClassID
+//
+// Purpose:
+//
+// Returns the CLSID of this object.
+//
+// Parameters:
+//
+// LPCLSID lpClassID - Out ptr in which to return the CLSID
+//
+// Return Value:
+//
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+//
+// Comments:
+//
+//
+//********************************************************************
+
+STDMETHODIMP CPersistStorage::GetClassID ( LPCLSID lpClassID)
+{
+ TestDebugOut("In CPersistStorage::GetClassID\r\n");
+
+ *lpClassID = GUID_SIMPLE;
+
+ return ResultFromScode( S_OK );
+};
+
+//**********************************************************************
+//
+// CPersistStorage::Save
+//
+// Purpose:
+//
+// Instructs the object to save itself into the storage.
+//
+// Parameters:
+//
+// LPSTORAGE pStgSave - Storage in which the object should be saved
+//
+// BOOL fSameAsLoad - TRUE if pStgSave is the same as the storage
+// that the object was originally created with.
+//
+// Return Value:
+//
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// CPersistStorage::InitNew IPS.CPP
+// CSimpSvrObj::SaveToStorage OBJ.CPP
+//
+//
+// Comments:
+//
+// A real app will want better error checking in this method.
+//
+//********************************************************************
+
+STDMETHODIMP CPersistStorage::Save ( LPSTORAGE pStgSave, BOOL fSameAsLoad)
+{
+ TestDebugOut("In CPersistStorage::Save\r\n");
+
+ // save the data
+ m_lpObj->SaveToStorage (pStgSave, fSameAsLoad);
+
+ m_lpObj->m_fSaveWithSameAsLoad = fSameAsLoad;
+ m_lpObj->m_fNoScribbleMode = TRUE;
+
+ return ResultFromScode( S_OK );
+};
+
+//**********************************************************************
+//
+// CPersistStorage::SaveCompleted
+//
+// Purpose:
+//
+// Called when the container is finished saving the object
+//
+// Parameters:
+//
+// LPSTORAGE pStgNew - ptr to the new storage
+//
+// Return Value:
+//
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+//
+// Comments:
+//
+//
+//********************************************************************
+
+STDMETHODIMP CPersistStorage::SaveCompleted ( LPSTORAGE pStgNew)
+{
+ TestDebugOut("In CPersistStorage::SaveCompleted\r\n");
+
+ if (pStgNew)
+ {
+ ReleaseStreamsAndStorage();
+ m_lpObj->m_lpStorage = pStgNew;
+ m_lpObj->m_lpStorage->AddRef();
+ OpenStreams(pStgNew);
+ }
+
+
+ /* 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 ( pStgNew || m_lpObj->m_fSaveWithSameAsLoad)
+ {
+ if (m_lpObj->m_fNoScribbleMode)
+ m_lpObj->GetOleAdviseHolder()->SendOnSave(); // normally would clear a
+ // dirty bit
+ m_lpObj->m_fSaveWithSameAsLoad = FALSE;
+ }
+
+ m_lpObj->m_fNoScribbleMode = FALSE;
+
+ return ResultFromScode( S_OK );
+};
+
+//**********************************************************************
+//
+// CPersistStorage::Load
+//
+// Purpose:
+//
+// Instructs the object to be loaded from storage.
+//
+// Parameters:
+//
+// LPSTORAGE pStg - Ptr to the storage in which to be loaded
+//
+// Return Value:
+//
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// CSimpSvrObj::LoadFromStorage OBJ.CPP
+//
+//
+// Comments:
+//
+// A real app will want better error checking in this method.
+//
+//********************************************************************
+
+STDMETHODIMP CPersistStorage::Load ( LPSTORAGE pStg)
+{
+ TestDebugOut("In CPersistStorage::Load\r\n");
+
+ // remember the storage
+ if (m_lpObj->m_lpStorage)
+ {
+ m_lpObj->m_lpStorage->Release();
+ m_lpObj->m_lpStorage = NULL;
+ }
+
+ m_lpObj->m_lpStorage = pStg;
+
+ m_lpObj->m_lpStorage->AddRef();
+
+ OpenStreams(m_lpObj->m_lpStorage);
+
+ m_lpObj->LoadFromStorage();
+
+
+ return ResultFromScode( S_OK );
+};
+
+
+//**********************************************************************
+//
+// CPersistStorage::IsDirty
+//
+// Purpose:
+//
+// Returns whether or not the object is dirty w/respect to its
+// Storage
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+//
+// Comments:
+//
+// This sample does not implement this function, although a
+// real application should.
+//
+//********************************************************************
+
+STDMETHODIMP CPersistStorage::IsDirty()
+{
+ TestDebugOut("In CPersistStorage::IsDirty\r\n");
+ return ResultFromScode( S_OK );
+};
+
+//**********************************************************************
+//
+// CPersistStorage::HandsOffStorage
+//
+// Purpose:
+//
+// Forces the object to release its handle to its storage.
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// IStorage::Release OLE
+//
+// Comments:
+//
+//
+//********************************************************************
+
+STDMETHODIMP CPersistStorage::HandsOffStorage ()
+{
+ TestDebugOut("In CPersistStorage::HandsOffStorage\r\n");
+
+ ReleaseStreamsAndStorage();
+
+ return ResultFromScode( S_OK );
+};
+
+//**********************************************************************
+//
+// CPersistStorage::CreateStreams
+//
+// Purpose:
+//
+// Creates the streams that are held open for the object's lifetime.
+//
+// Parameters:
+//
+// LPSTORAGE lpStg - Storage in which to create the streams
+//
+// Return Value:
+//
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// IStorage::Release OLE
+// IStream::Release OLE
+// IStorage::CreateStream OLE
+//
+// Comments:
+//
+//
+//********************************************************************
+
+void CPersistStorage::CreateStreams(LPSTORAGE lpStg)
+{
+ if (m_lpObj->m_lpColorStm)
+ m_lpObj->m_lpColorStm->Release();
+
+ if (m_lpObj->m_lpSizeStm)
+ m_lpObj->m_lpSizeStm->Release();
+
+ // create a stream to save the colors
+ lpStg->CreateStream ( "RGB",
+ STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_CREATE,
+ 0,
+ 0,
+ &m_lpObj->m_lpColorStm);
+
+ // create a stream to save the size
+ lpStg->CreateStream ( "size",
+ STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_CREATE,
+ 0,
+ 0,
+ &m_lpObj->m_lpSizeStm);
+}
+
+//**********************************************************************
+//
+// CPersistStorage::OpenStreams
+//
+// Purpose:
+//
+// Opens the streams in a storage.
+//
+// Parameters:
+//
+// LPSTORAGE lpStg - Storage in which to open the streams.
+//
+// Return Value:
+//
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// IStorage::Release OLE
+//
+// Comments:
+//
+//
+//********************************************************************
+
+void CPersistStorage::OpenStreams(LPSTORAGE lpStg)
+{
+ if (m_lpObj->m_lpColorStm)
+ m_lpObj->m_lpColorStm->Release();
+
+ if (m_lpObj->m_lpSizeStm)
+ m_lpObj->m_lpSizeStm->Release();
+
+ // open the color stream
+ lpStg->OpenStream ( "RGB",
+ 0,
+ STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
+ 0,
+ &m_lpObj->m_lpColorStm);
+
+ // open the color stream
+ lpStg->OpenStream ( "size",
+ 0,
+ STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
+ 0,
+ &m_lpObj->m_lpSizeStm);
+}
+
+//**********************************************************************
+//
+// CPersistStorage::ReleaseStreamsAndStorage
+//
+// Purpose:
+//
+// Releases the stream and storage ptrs
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// IStorage::Release OLE
+//
+// Comments:
+//
+//
+//********************************************************************
+
+void CPersistStorage::ReleaseStreamsAndStorage()
+{
+ if (m_lpObj->m_lpColorStm)
+ {
+ m_lpObj->m_lpColorStm->Release();
+ m_lpObj->m_lpColorStm = NULL;
+ }
+
+ if (m_lpObj->m_lpSizeStm)
+ {
+ m_lpObj->m_lpSizeStm->Release();
+ m_lpObj->m_lpSizeStm = NULL;
+ }
+
+ if (m_lpObj->m_lpStorage)
+ {
+ m_lpObj->m_lpStorage->Release();
+ m_lpObj->m_lpStorage = NULL;
+ }
+}
+
+//**********************************************************************
+//
+// CPersistStorage::CreateStreams
+//
+// Purpose:
+//
+// Creates temporary streams in a storage.
+//
+// Parameters:
+//
+// LPSTORAGE lpStg - Pointer to the storage
+//
+// LPSTREAM FAR* lplpTempColor - Color Stream
+//
+// LPSTREAM FAR* lplpTempSize - Size Stream
+//
+// Return Value:
+//
+// S_OK
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// IStorage::Release OLE
+//
+// Comments:
+//
+//
+//********************************************************************
+
+void CPersistStorage::CreateStreams(LPSTORAGE lpStg, LPSTREAM FAR* lplpTempColor,LPSTREAM FAR* lplpTempSize)
+{
+ // create a stream to save the colors
+ lpStg->CreateStream ( "RGB",
+ STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_CREATE,
+ 0,
+ 0,
+ lplpTempColor);
+
+ // create a stream to save the size
+ lpStg->CreateStream ( "size",
+ STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_CREATE,
+ 0,
+ 0,
+ lplpTempSize);
+
+}
diff --git a/private/oleutest/utests16/simpsvr/ips.h b/private/oleutest/utests16/simpsvr/ips.h
new file mode 100644
index 000000000..20f543ab5
--- /dev/null
+++ b/private/oleutest/utests16/simpsvr/ips.h
@@ -0,0 +1,53 @@
+//**********************************************************************
+// File name: ips.h
+//
+// Definition of CPersistStorage
+//
+// Copyright (c) 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+
+#if !defined( _IPS_H_)
+#define _IPS_H_
+
+
+#include <ole2.h>
+#include <storage.h>
+#include "obj.h"
+
+class CSimpSvrObj;
+
+interface CPersistStorage : IPersistStorage
+{
+private:
+ CSimpSvrObj FAR * m_lpObj;
+ int m_nCount;
+ BOOL m_fSameAsLoad;
+
+public:
+ CPersistStorage::CPersistStorage(CSimpSvrObj FAR * lpSimpSvrObj)
+ {
+ m_lpObj = lpSimpSvrObj;
+ m_nCount = 0;
+ };
+ CPersistStorage::~CPersistStorage() {};
+
+ STDMETHODIMP QueryInterface (REFIID riid, LPVOID FAR* ppvObj);
+ STDMETHODIMP_(ULONG) AddRef ();
+ STDMETHODIMP_(ULONG) Release ();
+
+ STDMETHODIMP InitNew (LPSTORAGE pStg);
+ STDMETHODIMP GetClassID ( LPCLSID lpClassID) ;
+ STDMETHODIMP Save ( LPSTORAGE pStgSave, BOOL fSameAsLoad) ;
+ STDMETHODIMP SaveCompleted ( LPSTORAGE pStgNew);
+ STDMETHODIMP Load ( LPSTORAGE pStg);
+ STDMETHODIMP IsDirty ();
+ STDMETHODIMP HandsOffStorage ();
+
+ void ReleaseStreamsAndStorage();
+ void OpenStreams(LPSTORAGE lpStg);
+ void CreateStreams(LPSTORAGE lpStg);
+ void CreateStreams(LPSTORAGE lpStg, LPSTREAM FAR *lpTempColor, LPSTREAM FAR *lpTempSize);
+
+};
+
+#endif
diff --git a/private/oleutest/utests16/simpsvr/makefile b/private/oleutest/utests16/simpsvr/makefile
new file mode 100644
index 000000000..62ed10bc3
--- /dev/null
+++ b/private/oleutest/utests16/simpsvr/makefile
@@ -0,0 +1,98 @@
+#//+---------------------------------------------------------------------------
+#//
+#// Microsoft Windows
+#// Copyright (C) Microsoft Corporation, 1992 - 1994.
+#//
+#// File: makefile
+#// Contents: makefile for 16 bit spsvr16 for OLETHUNK unit test.
+#//
+#// History: 06-16-94 terryru Created
+#//
+#//----------------------------------------------------------------------------
+
+
+!IFDEF USEBUILD
+
+# If using BUILD.EXE, 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
+
+!ELSE
+
+default: copy_bin
+
+TARGET = spsvr16.exe
+TARGETTYPE = EXE
+OLETHUNK = $(_NTDRIVE)$(_NTROOT)\private\cairole\olethunk
+
+RCINC=$(RCINC) -i..\ole2ui -i..\ole2ui\res\usa
+
+CDEFINES= -I..\ole2ui /GEs
+
+LFLAGS=/STACK:16384
+
+CPPFILES = \
+ .\app.cpp \
+ .\doc.cpp \
+ .\icf.cpp \
+ .\ido.cpp \
+ .\iec.cpp \
+ .\ioipao.cpp \
+ .\ioipo.cpp \
+ .\ioo.cpp \
+ .\ips.cpp \
+ .\obj.cpp \
+ .\pre.cpp \
+ .\simpsvr.cpp
+
+
+
+
+
+
+
+
+RCFILES = \
+ .\spsvr16.rc
+
+
+
+LIBS = $(LIBS)\
+ $(OLE16)\lib\ole2.lib \
+ $(OLE16)\lib\storage.lib \
+ $(OLE16)\lib\loleuic.lib \
+ $(OLE16)\lib\compobj.lib \
+ $(OLE16)\lib\shell.lib
+
+!include ..\makefile.inc
+
+
+!if "$(NTDEBUG)" != "" && "$(NTDEBUG)" != "retail"
+LIBS = $(LIBS) $(OLETHUNK)\debnot\$(OBJDIR)\debnot.lib
+!endif
+
+
+copy_bin: all
+ binplace $(OBJDIR)\spsvr16.exe
+ binplace $(OBJDIR)\spsvr16.sym
+ binplace $(OBJDIR)\spsvr16.map
+
+
+
+app.obj: app.cpp
+doc.obj: doc.cpp
+icf.obj: icf.cpp
+ido.obj: ido.cpp
+iec.obj: iec.cpp
+ioipao.obj: ioipao.cpp
+ioipo.obj: ioipo.cpp
+ioo.obj: ioo.cpp
+ips.obj: ips.cpp
+obj.obj: obj.cpp
+pre.obj: pre.cpp
+simpsvr.obj: simpsvr.cpp
+
+
+!ENDIF
diff --git a/private/oleutest/utests16/simpsvr/obj.cpp b/private/oleutest/utests16/simpsvr/obj.cpp
new file mode 100644
index 000000000..6125baee3
--- /dev/null
+++ b/private/oleutest/utests16/simpsvr/obj.cpp
@@ -0,0 +1,1057 @@
+//**********************************************************************
+// File name: obj.cpp
+//
+// Implementation file for the CSimpSvrApp Class
+//
+// Functions:
+//
+// See obj.h for a list of member functions.
+//
+// Copyright (c) 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+
+#include "pre.h"
+#include "obj.h"
+#include "ioo.h"
+#include "ido.h"
+#include "ips.h"
+#include "icf.h"
+#include "ioipao.h"
+#include "ioipo.h"
+#include "app.h"
+#include "doc.h"
+
+//**********************************************************************
+//
+// CSimpSvrObj::QueryInterface
+//
+// Purpose:
+//
+// Used for interface negotiation at the "Object" level.
+//
+// Parameters:
+//
+// REFIID riid - A reference to the interface that is
+// being queried.
+//
+// LPVOID FAR* ppvObj - An out parameter to return a pointer to
+// the interface.
+//
+// Return Value:
+//
+// S_OK - The interface is supported.
+// E_NOINTERFACE - The interface is not supported
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// ResultFromScode OLE API
+// IUnknown::AddRef OBJ.CPP, IOO.CPP, IDO.CPP, IPS.CPP
+// IOIPO.CPP, IOIPAO.CPP
+//
+// Comments:
+//
+//
+//********************************************************************
+
+STDMETHODIMP CSimpSvrObj::QueryInterface ( REFIID riid, LPVOID FAR* ppvObj)
+{
+ TestDebugOut("In CSimpSvrObj::QueryInterface\r\n");
+
+ SCODE sc = S_OK;
+
+ if (riid == IID_IUnknown)
+ *ppvObj = this;
+ else if (riid == IID_IOleObject)
+ *ppvObj = &m_OleObject;
+ else if (riid == IID_IDataObject)
+ *ppvObj = &m_DataObject;
+ else if ( (riid == IID_IPersistStorage) || (riid == IID_IPersist) )
+ *ppvObj = &m_PersistStorage;
+ else if (riid == IID_IOleInPlaceObject)
+ *ppvObj = &m_OleInPlaceObject;
+ else if (riid == IID_IOleInPlaceActiveObject)
+ *ppvObj = &m_OleInPlaceActiveObject;
+ else if (riid == IID_IExternalConnection)
+ *ppvObj = &m_ExternalConnection;
+ else
+ {
+ *ppvObj = NULL;
+ sc = E_NOINTERFACE;
+ }
+
+ if (*ppvObj)
+ ((LPUNKNOWN)*ppvObj)->AddRef();
+
+ return ResultFromScode( sc );
+};
+
+//**********************************************************************
+//
+// CSimpSvrObj::AddRef
+//
+// Purpose:
+//
+// Adds to the reference count at the Object level.
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// ULONG - The new reference count of the Object.
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+// Comments:
+//
+// Due to the reference counting model that is used in this
+// implementation, this reference count is the sum of the
+// reference counts on all interfaces
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) CSimpSvrObj::AddRef ()
+{
+ TestDebugOut("In CSimpSvrObj::AddRef\r\n");
+
+ m_lpDoc->AddRef();
+
+ return ++m_nCount;
+};
+
+//**********************************************************************
+//
+// CSimpSvrObj::Release
+//
+// Purpose:
+//
+// Decrements the reference count at this level
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// ULONG - The new reference count of the object.
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+//
+// Comments:
+//
+// Due to the reference counting model that is used in this
+// implementation, this reference count is the sum of the
+// reference counts on all interfaces
+//
+//********************************************************************
+
+STDMETHODIMP_(ULONG) CSimpSvrObj::Release ()
+{
+ TestDebugOut("In CSimpSvrObj::Release\r\n");
+
+ m_lpDoc->Release();
+
+ if (--m_nCount == 0) {
+ delete this;
+ return 0;
+ }
+
+ return m_nCount;
+};
+
+//**********************************************************************
+//
+// CSimpSvrObj::CSimpSvrObj
+//
+// Purpose:
+//
+// Constructor for CSimpSvrObj
+//
+// Parameters:
+//
+// CSimpSvrDoc FAR * lpSimpSvrDoc - ptr to the doc object
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+//
+// Comments:
+//
+//
+//********************************************************************
+#pragma warning (disable : 4355) // "this" used in base initializer list warning. This
+ // can be disabled because we are not using "this" in
+ // the constructor for these objects, rather we are
+ // just storing it for future use...
+CSimpSvrObj::CSimpSvrObj(CSimpSvrDoc FAR * lpSimpSvrDoc) : m_OleObject(this),
+ m_DataObject(this),
+ m_PersistStorage(this),
+ m_OleInPlaceActiveObject(this),
+ m_OleInPlaceObject(this),
+ m_ExternalConnection(this)
+#pragma warning (default : 4355) // Turn the warning back on
+
+{
+ m_lpDoc = lpSimpSvrDoc;
+ m_nCount = 0;
+ m_fInPlaceActive = FALSE;
+ m_fInPlaceVisible = FALSE;
+ m_fUIActive = FALSE;
+ m_hmenuShared = NULL;
+ m_hOleMenu = NULL;
+
+ m_dwRegister = 0;
+
+ m_lpFrame = NULL;
+ m_lpCntrDoc = NULL;
+
+ m_lpStorage = NULL;
+ m_lpColorStm = NULL;
+ m_lpSizeStm = NULL;
+ m_lpOleClientSite = NULL;
+ m_lpOleAdviseHolder = NULL;
+ m_lpDataAdviseHolder = NULL;
+ m_lpIPSite = NULL;
+
+ m_red = 128;
+ m_green = 0;
+ m_blue = 0;
+
+ m_size.x = 100;
+ m_size.y = 100;
+
+ m_xOffset = 0;
+ m_yOffset = 0;
+
+ m_scale = 1;
+
+ m_fSaveWithSameAsLoad = FALSE;
+ m_fNoScribbleMode = FALSE;
+
+}
+
+//**********************************************************************
+//
+// CSimpSvrObj::~CSimpSvrObj
+//
+// Purpose:
+//
+// Destructor for CSimpSvrObj
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+//
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// PostMessage Windows API
+// CSimpSvrDoc::GetApp DOC.H
+// CSimpSvrDoc::GethAppWnd DOC.H
+// CSimpSvrDoc::ClearObj DOC.H
+// CSimpSvrApp::IsStartedByOle APP.CPP
+//
+// Comments:
+//
+//
+//********************************************************************
+
+CSimpSvrObj::~CSimpSvrObj()
+{
+ TestDebugOut("In CSimpSvrObj's Destructor \r\n");
+
+ // if we were started by ole, post ourselves a close message
+ if (m_lpDoc->GetApp()->IsStartedByOle())
+ PostMessage(m_lpDoc->GethAppWnd(), WM_SYSCOMMAND, SC_CLOSE, 0L);
+
+ // clear the OBJ ptr in the doc class
+ m_lpDoc->ClearObj();
+
+}
+
+//**********************************************************************
+//
+// CSimpSvrObj::Draw
+//
+// Purpose:
+//
+// Draws the object into an arbitrary DC
+//
+// Parameters:
+//
+// HDC hDC - DC to draw into
+//
+// Return Value:
+//
+// NONE
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// CreateBrushIndirect Windows API
+// SelectObject Windows API
+// Rectangle Windows API
+// DeleteObject Windows API
+//
+// Comments:
+//
+//
+//********************************************************************
+
+void CSimpSvrObj::Draw (HDC hDC, BOOL m_fMeta)
+{
+ LOGBRUSH lb;
+
+ TestDebugOut("In CSimpSvrObj::Draw\r\n");
+
+ char szBuffer[255];
+ wsprintf(szBuffer,"Drawing Scale %3d\r\n",m_scale);
+ TestDebugOut(szBuffer);
+
+ if (!m_fMeta)
+ {
+ SetMapMode(hDC, MM_ANISOTROPIC);
+ SetWindowOrg(hDC, (int)(m_xOffset/m_scale), (int)(m_yOffset/m_scale));
+ SetWindowExt(hDC, m_size.x, m_size.y);
+ SetViewportExt(hDC, (int)(m_size.x*m_scale), (int)(m_size.y*m_scale));
+ }
+
+ // fill out a LOGBRUSH
+ lb.lbStyle = BS_SOLID;
+ lb.lbColor = RGB(m_red, m_green, m_blue);
+ lb.lbHatch = 0;
+
+ // create the brush
+ HBRUSH hBrush = CreateBrushIndirect(&lb);
+
+ // select the brush
+ HBRUSH hOldBrush = SelectObject(hDC, hBrush);
+ HPEN hPen = CreatePen(PS_INSIDEFRAME, 6, RGB(0, 0, 0));
+
+ HPEN hOldPen = SelectObject(hDC, hPen);
+
+ // draw the rectangle
+ Rectangle (hDC, 0, 0, m_size.x, m_size.y);
+
+ // restore the pen
+ hPen = SelectObject(hDC, hOldPen);
+
+ // free the pen
+ DeleteObject(hPen);
+
+ // restore the old brush
+ hBrush = SelectObject(hDC, hOldBrush);
+
+ // free the brush
+ DeleteObject(hBrush);
+}
+
+//**********************************************************************
+//
+// CSimpSvrObj::GetMetaFilePict
+//
+// Purpose:
+//
+// Returns a handle to a metafile representation of the object.
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// Handle to the metafile.
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// GlobalAlloc Windows API
+// GlobalLock Windows API
+// SetWindowOrg Windows API
+// SetWindowExt Windows API
+// CreateMetaFile Windows API
+// CloseMetaFile Windows API
+// GlobalUnlock Windows API
+// XformWidthInPixelsToHimetric OLE2UI
+// XformHeightInPixelsToHimetric OLE2UI
+// CSimpSvrObj::Draw OBJ.CPP
+//
+// Comments:
+//
+//
+//********************************************************************
+
+HANDLE CSimpSvrObj::GetMetaFilePict()
+{
+ HANDLE hMFP;
+ METAFILEPICT FAR * lpMFP;
+ POINT pt;
+
+ TestDebugOut("In CSimpSvrObj::GetMetaFilePict\r\n");
+
+ // allocate the memory for the METAFILEPICT structure
+ hMFP = GlobalAlloc (GMEM_SHARE | GHND, sizeof (METAFILEPICT) );
+ lpMFP = (METAFILEPICT FAR*) GlobalLock(hMFP);
+
+ // get the size of the object in HIMETRIC
+ pt.x = XformWidthInPixelsToHimetric(NULL, m_size.x);
+ pt.y = XformHeightInPixelsToHimetric(NULL, m_size.y);
+
+ // fill out the METAFILEPICT structure
+ lpMFP->mm = MM_ANISOTROPIC;
+ lpMFP->xExt = pt.x;
+ lpMFP->yExt = pt.y;
+
+ // Create the metafile
+ HDC hDC = CreateMetaFile(NULL);
+
+ SetWindowOrg (hDC, 0, 0);
+ SetWindowExt (hDC, m_size.x,
+ m_size.y);
+
+ Draw(hDC);
+
+ lpMFP->hMF = CloseMetaFile(hDC);
+
+ // unlock the metafilepict
+ GlobalUnlock(hMFP);
+
+ return hMFP;
+}
+
+
+//**********************************************************************
+//
+// CSimpSvrObj::SaveToStorage
+//
+// Purpose:
+//
+// Saves the object to the passed storage
+//
+// Parameters:
+//
+// LPSTORAGE lpStg - Storage in which to save the object
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// IStorage::CreateStream OLE
+// IStream::Write OLE
+// IStream::Release OLE
+//
+// Comments:
+//
+// A real app will want to do better error checking / returning
+//
+//********************************************************************
+
+void CSimpSvrObj::SaveToStorage (LPSTORAGE lpStg, BOOL fSameAsLoad)
+{
+ TestDebugOut("In CSimpSvrObj::SaveToStorage\r\n");
+
+ LPSTREAM lpTempColor, lpTempSize;
+
+ if (!fSameAsLoad)
+ m_PersistStorage.CreateStreams( lpStg, &lpTempColor, &lpTempSize);
+ else
+ {
+ lpTempColor = m_lpColorStm;
+ lpTempColor->AddRef();
+ lpTempSize = m_lpSizeStm;
+ lpTempSize->AddRef();
+ }
+
+ ULARGE_INTEGER uli;
+
+ uli.LowPart = 0;
+ uli.HighPart = 0;
+
+ lpTempColor->SetSize(uli);
+ lpTempSize->SetSize(uli);
+
+ LARGE_INTEGER li;
+
+ li.LowPart = 0;
+ li.HighPart = 0;
+
+ lpTempColor->Seek(li, STREAM_SEEK_SET, NULL);
+ lpTempSize->Seek(li, STREAM_SEEK_SET, NULL);
+
+ // write the colors to the stream
+ lpTempColor->Write(&m_red, sizeof(m_red), NULL);
+ lpTempColor->Write(&m_green, sizeof(m_green), NULL);
+ lpTempColor->Write(&m_blue, sizeof(m_blue), NULL);
+
+ // write the size to the stream
+ lpTempSize->Write(&m_size, sizeof(m_size), NULL);
+
+ lpTempColor->Release();
+ lpTempSize->Release();
+}
+
+//**********************************************************************
+//
+// CSimpSvrObj::LoadFromStorage
+//
+// Purpose:
+//
+// Loads the object from the passed storage
+//
+// Parameters:
+//
+// LPSTORAGE lpStg - Storage in which to load the object from
+//
+// Return Value:
+//
+// None.
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// IStorage::OpenStream OLE
+// IStream::Read OLE
+// IStream::Release OLE
+//
+// Comments:
+//
+//
+//********************************************************************
+
+void CSimpSvrObj::LoadFromStorage ()
+{
+ TestDebugOut("In CSimpSvrObj::LoadFromStorage\r\n");
+
+ // Read the colors
+ m_lpColorStm->Read(&m_red, sizeof(m_red), NULL);
+ m_lpColorStm->Read(&m_green, sizeof(m_green), NULL);
+ m_lpColorStm->Read(&m_blue, sizeof(m_blue), NULL);
+
+ // read the size
+ m_lpSizeStm->Read(&m_size, sizeof(m_size), NULL);
+
+}
+
+//**********************************************************************
+//
+// CSimpSvrObj::DoInPlaceActivate
+//
+// Purpose:
+//
+// Does the inplace activation for the object
+//
+// Parameters:
+//
+// LONG lVerb - Verb that caused this function to be called
+//
+// Return Value:
+//
+// TRUE/FALSE depending on success or failure.
+//
+// Function Calls:
+// Function Location
+//
+// IOleClientSite::QueryInterface Container
+// IOleClientSite::ShowObject Container
+// IOleInPlaceSite::CanInPlaceActivate Container
+// IOleInPlaceSite::Release Container
+// IOleInPlaceSite::OnInPlaceActivate Container
+// IOleInPlaceSite::GetWindow Container
+// IOleInPlaceSite::GetWindowContext Container
+// IOleInPlaceSite::OnUIActivate Container
+// IOleInPlaceSite::Release Container
+// IOleInPlaceFrame::SetActiveObject Container
+// IOleInPlaceUIWindow::SetActiveObject Container
+// TestDebugOut Windows API
+// ShowWindow Windows API
+// SetParent Windows API
+// IntersectRect Windows API
+// OffsetRect Windows API
+// MoveWindow Windows API
+// CopyRect Windows API
+// SetFocus Windows API
+// SetHatchWindowSize OLE2UI
+// CSimpSvrObj::AssembleMenus OBJ.CPP
+// CSimpSvrObj::AddFrameLevelUI OBJ.CPP
+//
+//
+// Comments:
+//
+// Be sure to read TECHNOTES.WRI included with the OLE SDK
+// for details on implementing inplace activation.
+//
+//********************************************************************
+
+BOOL CSimpSvrObj::DoInPlaceActivate (LONG lVerb)
+{
+ BOOL retval = FALSE;
+ RECT posRect, clipRect;
+
+
+ TestDebugOut("In CSimpSvrObj::DoInPlaceActivate\r\n");
+
+ // if not currently in place active
+ if (!m_fInPlaceActive)
+ {
+ // get the inplace site
+ if (m_lpOleClientSite->QueryInterface(IID_IOleInPlaceSite,
+ (LPVOID FAR *)&m_lpIPSite) != NOERROR)
+ goto error;
+
+
+ // if the inplace site could not be obtained, or refuses to inplace
+ // activate then goto error.
+ if (m_lpIPSite == NULL || m_lpIPSite->CanInPlaceActivate() != NOERROR)
+ {
+ if (m_lpIPSite)
+ m_lpIPSite->Release();
+ m_lpIPSite = NULL;
+ goto error;
+ }
+
+ // tell the site that we are activating.
+ m_lpIPSite->OnInPlaceActivate();
+ m_fInPlaceActive = TRUE;
+ }
+
+ // if not currently inplace visibl
+ if (!m_fInPlaceVisible)
+ {
+ m_fInPlaceVisible = TRUE;
+
+ // get the window handle of the site
+ m_lpIPSite->GetWindow(&m_hWndParent);
+
+ // get window context from the container
+ m_lpIPSite->GetWindowContext ( &m_lpFrame,
+ &m_lpCntrDoc,
+ &posRect,
+ &clipRect,
+ &m_FrameInfo);
+
+ // show the hatch window
+ m_lpDoc->ShowHatchWnd();
+
+ // Set the parenting
+ SetParent (m_lpDoc->GethHatchWnd(), m_hWndParent);
+ SetParent (m_lpDoc->GethDocWnd(), m_lpDoc->GethHatchWnd());
+
+ // tell the client site to show the object
+ m_lpOleClientSite->ShowObject();
+
+ RECT resRect;
+
+ // figure out the "real" size of the object
+ IntersectRect(&resRect, &posRect, &clipRect);
+ CopyRect(&m_posRect, &posRect);
+
+ POINT pt;
+
+ // adjust our hatch window size
+ SetHatchWindowSize ( m_lpDoc->GethHatchWnd(),
+ &resRect,
+ &posRect,
+ &pt);
+
+ // calculate the actual object rect inside the hatchwnd.
+ OffsetRect (&resRect, pt.x, pt.y);
+
+ // move the object window
+ MoveWindow(m_lpDoc->GethDocWnd(),
+ resRect.left,
+ resRect.top,
+ resRect.right - resRect.left,
+ resRect.bottom - resRect.top,
+ FALSE);
+
+ // create the combined window
+ AssembleMenus();
+ }
+
+ // if not UIActive
+ if (!m_fUIActive)
+ {
+ m_fUIActive = TRUE;
+
+ // tell the inplace site that we are activating
+ m_lpIPSite->OnUIActivate();
+
+ // set the focus to our object window
+ SetFocus(m_lpDoc->GethDocWnd());
+
+ // set the active object on the frame
+ m_lpFrame->SetActiveObject(&m_OleInPlaceActiveObject, "Simple OLE 2.0 Server");
+
+ // set the active object on the Doc, if available.
+ if (m_lpCntrDoc)
+ m_lpCntrDoc->SetActiveObject(&m_OleInPlaceActiveObject, "Simple OLE 2.0 Server");
+
+ // add the frame level UI.
+ AddFrameLevelUI();
+ }
+
+ retval = TRUE;
+error:
+ return retval;
+}
+
+//**********************************************************************
+//
+// CSimpSvrObj::AssembleMenus
+//
+// Purpose:
+//
+// Creates the combined menus used during inplace activation.
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// CreateMenu Windows API
+// IOleInPlaceFrame::InsertMenus Container
+// InsertMenu Windows API
+// DestroyMenu Windows API
+// OleCreateMenuDescriptor OLE API
+//
+// Comments:
+//
+//
+//********************************************************************
+
+void CSimpSvrObj::AssembleMenus()
+{
+ TestDebugOut("In CSimpSvrObj::AssembleMenus\r\n");
+ OLEMENUGROUPWIDTHS menugroupwidths;
+
+ m_hmenuShared = NULL;
+
+ // Create the menu resource
+ m_hmenuShared = CreateMenu();
+
+ // have the contaner insert its menus
+ if (m_lpFrame->InsertMenus (m_hmenuShared, &menugroupwidths) == NOERROR)
+ {
+ int nFirstGroup = (int) menugroupwidths.width[0];
+
+ // insert the server menus
+ InsertMenu( m_hmenuShared, nFirstGroup, MF_BYPOSITION | MF_POPUP, m_lpDoc->GetApp()->GetColorMenu(), "&Color");
+ menugroupwidths.width[1] = 1;
+ menugroupwidths.width[3] = 0;
+ menugroupwidths.width[5] = 0;
+ }
+ else
+ {
+ // Destroy the menu resource
+ DestroyMenu(m_hmenuShared);
+ m_hmenuShared = NULL;
+ }
+
+ // tell OLE to create the menu descriptor
+ m_hOleMenu = OleCreateMenuDescriptor(m_hmenuShared, &menugroupwidths);
+}
+
+//**********************************************************************
+//
+// CSimpSvrObj::AddFrameLevelUI
+//
+// Purpose:
+//
+// Adds the Frame level user interface
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// IOleInPlaceFrame::SetMenu Container
+// IOleInPlaceFrame::SetBorderSpace Container
+// IOleInPlaceUIWindow::SetBorderSpace Container
+// CSimpSvrDoc::GethDocWnd DOC.H
+//
+// Comments:
+//
+//
+//********************************************************************
+
+void CSimpSvrObj::AddFrameLevelUI()
+{
+ TestDebugOut("In CSimpSvrObj::AddFrameLevelUI\r\n");
+
+ // add the combined menu
+ m_lpFrame->SetMenu(m_hmenuShared, m_hOleMenu, m_lpDoc->GethDocWnd());
+
+ // do hatched border
+ SetParent (m_lpDoc->GethHatchWnd(), m_hWndParent);
+ SetParent (m_lpDoc->GethDocWnd(), m_lpDoc->GethHatchWnd());
+
+ // set the border space. Normally we would negotiate for toolbar
+ // space at this point. Since this server doesn't have a toolbar,
+ // this isn't needed...
+ if (m_lpFrame)
+ m_lpFrame->SetBorderSpace(NULL);
+
+ if (m_lpCntrDoc)
+ m_lpCntrDoc->SetBorderSpace(NULL);
+}
+
+//**********************************************************************
+//
+// CSimpSvrObj::DoInPlaceHide
+//
+// Purpose:
+//
+// Hides the object while inplace actvie
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// SetParent Windows API
+// CSimpSvrDoc::GethDocWnd DOC.H
+// CSimpSvrDoc::GethAppWnd DOC.H
+// CSimpSvrDoc::GethHatchWnd DOC.H
+// CSimpSvrObj::DisassembleMenus OBJ.CPP
+// IOleInPlaceFrame::Release Container
+// IOleInPlaceUIWindow::Release Container
+//
+//
+// Comments:
+//
+// Be sure to read TECHNOTES.WRI included with the OLE SDK
+// for details on implementing inplace activation.
+//
+//********************************************************************
+
+void CSimpSvrObj::DoInPlaceHide()
+{
+ TestDebugOut("In CSimpSvrObj::DoInPlaceHide\r\n");
+
+ // if we aren't inplace visible, then this routine is a NOP,
+ if (!m_fInPlaceVisible)
+ return;
+
+ m_fInPlaceVisible = FALSE;
+
+ // change the parenting
+ SetParent (m_lpDoc->GethDocWnd(), m_lpDoc->GethAppWnd());
+ SetParent (m_lpDoc->GethHatchWnd(),m_lpDoc->GethDocWnd());
+
+ // rip down the combined menus
+ DisassembleMenus();
+
+ // release the inplace frame
+ m_lpFrame->Release();
+
+ m_lpFrame = NULL; // only holding one ref. to frame.
+
+ // release the UIWindow if it is there.
+ if (m_lpCntrDoc)
+ m_lpCntrDoc->Release();
+
+ m_lpCntrDoc = NULL;
+
+}
+
+//**********************************************************************
+//
+// CSimpSvrObj::DisassembleMenus
+//
+// Purpose:
+//
+// Disassembles the combined menus used in inplace activation
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// TestDebugOut Windows API
+// OleDestroyMenuDescriptor OLE API
+// RemoveMenu Windows API
+// IOleInPlaceFrame::RemoveMenus Container
+// DestroyMenu Windows API
+//
+// Comments:
+//
+// Be sure to read TECHNOTES.WRI included with the OLE SDK
+// for details on implementing inplace activation.
+//
+//********************************************************************
+
+void CSimpSvrObj::DisassembleMenus()
+{
+ // destroy the menu descriptor
+ OleDestroyMenuDescriptor(m_hOleMenu);
+
+ if (m_hmenuShared)
+ {
+ // remove the menus that we added
+ RemoveMenu( m_hmenuShared, 1, MF_BYPOSITION);
+
+ // have the container remove its menus
+ m_lpFrame->RemoveMenus(m_hmenuShared);
+
+ // Destroy the menu resource
+ DestroyMenu(m_hmenuShared);
+
+ m_hmenuShared = NULL;
+ }
+}
+
+//**********************************************************************
+//
+// CSimpSvrObj::SendOnDataChange
+//
+// Purpose:
+//
+// Uses the data advise holder to send a data change, then updates
+// the ROT to note the time of change.
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// IDataAdviseHolder::SendOnDataChange OLE API
+// GetRunningObjectTable OLE API
+// CoFileTimeNow OLE API
+// IRunningObjectTable::NoteChangeTime OLE API
+//
+// Comments:
+//
+//
+//********************************************************************
+
+void CSimpSvrObj::SendOnDataChange()
+{
+ if (m_lpDataAdviseHolder)
+ m_lpDataAdviseHolder->SendOnDataChange( (LPDATAOBJECT)&m_DataObject, 0, 0);
+
+ LPRUNNINGOBJECTTABLE lpRot;
+
+ GetRunningObjectTable(0, &lpRot);
+
+ if ( lpRot && m_dwRegister)
+ {
+ FILETIME ft;
+ CoFileTimeNow(&ft);
+
+ lpRot->NoteChangeTime(m_dwRegister, &ft);
+ lpRot->Release();
+ }
+}
+
+//**********************************************************************
+//
+// CSimpSvrObj::DeactivateUI
+//
+// Purpose:
+//
+// Breaks down the inplace ui
+//
+// Parameters:
+//
+// None
+//
+// Return Value:
+//
+// None
+//
+// Function Calls:
+// Function Location
+//
+// SetParent Windows API
+// IOleInPlaceUIWindow::SetActiveObject Container
+// IOleInPlaceFrame::SetActiveObject Container
+// IOleInPlaceSite::UIDeactivate Container
+//
+// Comments:
+//
+//
+//********************************************************************
+
+void CSimpSvrObj::DeactivateUI()
+{
+ // if not UI active, or no pointer to IOleInPlaceFrame, then
+ // return NOERROR
+ if (!(m_fUIActive || m_lpFrame))
+ return;
+ else
+ {
+ m_fUIActive = FALSE;
+
+ // remove hatching
+ SetParent (m_lpDoc->GethDocWnd(), m_lpDoc->GethAppWnd());
+ SetParent (m_lpDoc->GethHatchWnd(),m_lpDoc->GethDocWnd());
+
+ // if in an MDI container, call SetActiveObject on the DOC.
+ if (m_lpCntrDoc)
+ m_lpCntrDoc->SetActiveObject(NULL, NULL);
+
+ m_lpFrame->SetActiveObject(NULL, NULL);
+
+ // tell the container that our UI is going away.
+ if (m_lpIPSite)
+ m_lpIPSite->OnUIDeactivate(FALSE);
+ }
+}
diff --git a/private/oleutest/utests16/simpsvr/obj.h b/private/oleutest/utests16/simpsvr/obj.h
new file mode 100644
index 000000000..c8b4019ea
--- /dev/null
+++ b/private/oleutest/utests16/simpsvr/obj.h
@@ -0,0 +1,141 @@
+//**********************************************************************
+// File name: obj.h
+//
+// Definition of CSimpSvrObj
+//
+// Copyright (c) 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+
+#if !defined( _OBJ_H_)
+#define _OBJ_H_
+
+#include "ioipao.h"
+#include "ioipo.h"
+#include "ioo.h"
+#include "ips.h"
+#include "ido.h"
+#include "iec.h"
+
+class CSimpSvrDoc;
+interface COleObject;
+interface CPersistStorage;
+interface CDataObject;
+interface COleInPlaceActiveObject;
+interface COleInPlaceObject;
+interface CExternalConnection;
+
+class CSimpSvrObj : public IUnknown
+{
+private:
+ CSimpSvrDoc FAR * m_lpDoc; // Back pointer
+ int m_nCount; // reference count
+ BOOL m_fInPlaceActive; // Used during InPlace Negotiation
+ BOOL m_fInPlaceVisible; // " " " " " " " " "
+ BOOL m_fUIActive; // " " " " " " " " "
+ HMENU m_hmenuShared; // " " " " " " " " "
+ HOLEMENU m_hOleMenu; // " " " " " " " " "
+ RECT m_posRect; // " " " " " " " " "
+ OLEINPLACEFRAMEINFO m_FrameInfo;
+ BOOL m_fSaveWithSameAsLoad;
+ BOOL m_fNoScribbleMode;
+
+ DWORD m_dwRegister; // Registered in ROT
+
+ int m_red, m_green, m_blue; // current color
+ POINT m_size; // current size
+ int m_xOffset;
+ int m_yOffset;
+ float m_scale;
+
+ HWND m_hWndParent; // parent window handle
+
+ // interfaces used
+ LPSTORAGE m_lpStorage;
+ LPSTREAM m_lpColorStm, m_lpSizeStm;
+ LPOLECLIENTSITE m_lpOleClientSite; // IOleClientSite
+ LPOLEADVISEHOLDER m_lpOleAdviseHolder; // IOleAdviseHolder
+ LPDATAADVISEHOLDER m_lpDataAdviseHolder; // IDataAdviseHolder
+ LPOLEINPLACEFRAME m_lpFrame; // IOleInPlaceFrame
+ LPOLEINPLACEUIWINDOW m_lpCntrDoc; // IOleInPlaceUIWindow
+ LPOLEINPLACESITE m_lpIPSite; // IOleInPlaceSite
+
+ // interface implemented
+ COleObject m_OleObject; // IOleObject
+ CPersistStorage m_PersistStorage; // IPersistStorage
+ CDataObject m_DataObject; // IDataObject
+ COleInPlaceActiveObject m_OleInPlaceActiveObject; // IOleInPlaceActiveObject
+ COleInPlaceObject m_OleInPlaceObject; // IOleInPlaceObject
+ CExternalConnection m_ExternalConnection;
+
+public:
+ STDMETHODIMP QueryInterface (REFIID riid, LPVOID FAR* ppvObj);
+ STDMETHODIMP_(ULONG) AddRef ();
+ STDMETHODIMP_(ULONG) Release ();
+
+// construction/destruction
+ CSimpSvrObj(CSimpSvrDoc FAR * lpSimpSvrDoc);
+ ~CSimpSvrObj();
+
+// utility functions
+ void Draw(HDC hDC, BOOL fMetaDC = TRUE);
+ void PaintObj(HDC hDC);
+ void lButtonDown(WPARAM wParam,LPARAM lParam);
+ HANDLE GetMetaFilePict();
+ void SaveToStorage (LPSTORAGE lpStg, BOOL fSameAsLoad);
+ void LoadFromStorage ();
+
+// visual editing helper functions
+ BOOL DoInPlaceActivate (LONG lVerb);
+ void AssembleMenus();
+ void AddFrameLevelUI();
+ void DoInPlaceHide();
+ void DisassembleMenus();
+ void SendOnDataChange();
+ void DeactivateUI();
+
+// member variable access
+ inline BOOL IsInPlaceActive() { return m_fInPlaceActive; };
+ inline BOOL IsInPlaceVisible() { return m_fInPlaceVisible; };
+ inline BOOL IsUIActive() { return m_fUIActive; };
+ inline HWND GetParent() { return m_hWndParent; };
+ inline LPSTORAGE GetStorage() { return m_lpStorage; };
+ inline LPOLECLIENTSITE GetOleClientSite() { return m_lpOleClientSite; };
+ inline LPDATAADVISEHOLDER GetDataAdviseHolder() { return m_lpDataAdviseHolder; };
+ inline LPOLEADVISEHOLDER GetOleAdviseHolder() { return m_lpOleAdviseHolder; };
+ inline LPOLEINPLACEFRAME GetInPlaceFrame() { return m_lpFrame; };
+ inline LPOLEINPLACEUIWINDOW GetUIWindow() { return m_lpCntrDoc; };
+ inline LPOLEINPLACESITE GetInPlaceSite() { return m_lpIPSite; };
+ inline COleObject FAR * GetOleObject() { return &m_OleObject; };
+ inline CPersistStorage FAR * GetPersistStorage() { return &m_PersistStorage; };
+ inline CDataObject FAR * GetDataObject() { return &m_DataObject; };
+ inline COleInPlaceActiveObject FAR * GetOleInPlaceActiveObject() { return &m_OleInPlaceActiveObject; };
+ inline COleInPlaceObject FAR * GetOleInPlaceObject() { return &m_OleInPlaceObject; };
+ inline void ClearOleClientSite() { m_lpOleClientSite = NULL; };
+ inline void ClearDataAdviseHolder() { m_lpDataAdviseHolder = NULL; };
+ inline void ClearOleAdviseHolder() { m_lpOleAdviseHolder = NULL; };
+ inline LPRECT GetPosRect() { return &m_posRect; };
+ inline LPPOINT GetSize() { return &m_size; };
+ inline LPOLEINPLACEFRAMEINFO GetFrameInfo() {return &m_FrameInfo;};
+ inline DWORD GetRotRegister() { return m_dwRegister; };
+
+
+
+ // member manipulation
+ inline void SetColor (int nRed, int nGreen, int nBlue)
+ { m_red = nRed; m_green = nGreen; m_blue = nBlue; };
+
+ inline void RotateColor()
+ { m_red+=10; m_green+=10; m_blue+=10;};
+
+
+// all of the interface implementations should be friends of this
+// class
+friend interface COleObject;
+friend interface CPersistStorage;
+friend interface CDataObject;
+friend interface COleInPlaceActiveObject;
+friend interface COleInPlaceObject;
+friend interface CExternalConnection;
+
+};
+#endif
diff --git a/private/oleutest/utests16/simpsvr/pre.cpp b/private/oleutest/utests16/simpsvr/pre.cpp
new file mode 100644
index 000000000..9603f4089
--- /dev/null
+++ b/private/oleutest/utests16/simpsvr/pre.cpp
@@ -0,0 +1,9 @@
+//**********************************************************************
+// File name: pre.cpp
+//
+// Used for precompiled headers
+//
+// Copyright (c) 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+
+#include "pre.h"
diff --git a/private/oleutest/utests16/simpsvr/pre.h b/private/oleutest/utests16/simpsvr/pre.h
new file mode 100644
index 000000000..f52d44910
--- /dev/null
+++ b/private/oleutest/utests16/simpsvr/pre.h
@@ -0,0 +1,22 @@
+//**********************************************************************
+// File name: pre.h
+//
+// Used for precompiled headers
+//
+// Copyright (c) 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+
+#if !defined( _PRE_H_)
+#define _PRE_H_
+
+#include <windows.h>
+#include <ole2.h>
+#include <ole2ui.h>
+#include <assert.h>
+#include <string.h>
+#include "simpsvr.h"
+#include "resource.h"
+#include <ole2ver.h>
+extern "C" void TestDebugOut(LPSTR psz);
+
+#endif
diff --git a/private/oleutest/utests16/simpsvr/readme.txt b/private/oleutest/utests16/simpsvr/readme.txt
new file mode 100644
index 000000000..10fdbd35f
--- /dev/null
+++ b/private/oleutest/utests16/simpsvr/readme.txt
@@ -0,0 +1,7 @@
+Simpsvr
+--------
+This sample is the simplest OLE 2.0 object that can be written and
+still support the visual editing feature. The object that this server
+supports is a colored square with a black border.
+
+See the MAKEFILE for compilation instructions.
diff --git a/private/oleutest/utests16/simpsvr/resource.h b/private/oleutest/utests16/simpsvr/resource.h
new file mode 100644
index 000000000..be152d1ac
--- /dev/null
+++ b/private/oleutest/utests16/simpsvr/resource.h
@@ -0,0 +1,32 @@
+//{{NO_DEPENDENCIES}}
+// App Studio generated include file.
+// Used by SIMPSVR.RC
+//
+#define IDM_OPEN 102
+#define IDM_SAVE 103
+#define IDM_SAVEAS 104
+#define IDM_PRINT 105
+#define IDM_EXIT 106
+#define IDM_UNDO 107
+#define IDM_CUT 108
+#define IDM_COPY 109
+#define IDM_PASTE 110
+#define ID_EDIT_INSERTOBJECT 111
+#define IDM_INSERTOBJECT 111
+#define IDM_NEW 112
+#define IDM_RED 113
+#define IDM_GREEN 114
+#define IDM_BLUE 115
+#define IDM_ROTATE 116
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+
+#define _APS_NEXT_RESOURCE_VALUE 102
+#define _APS_NEXT_COMMAND_VALUE 117
+#define _APS_NEXT_CONTROL_VALUE 1000
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/private/oleutest/utests16/simpsvr/simpsvr.cpp b/private/oleutest/utests16/simpsvr/simpsvr.cpp
new file mode 100644
index 000000000..54066982b
--- /dev/null
+++ b/private/oleutest/utests16/simpsvr/simpsvr.cpp
@@ -0,0 +1,357 @@
+//**********************************************************************
+// File name: simpsvr.cpp
+//
+// Main source file for the simple OLE 2.0 server
+//
+// Functions:
+//
+// WinMain - Program entry point
+// MainWndProc - Processes messages for the frame window
+// About - Processes messages for the about dialog
+// DocWndProc - Processes messages for the doc window
+//
+// Copyright (c) 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+
+#include "pre.h"
+#include "obj.h"
+#include "app.h"
+#include "doc.h"
+#include "icf.h"
+
+// This line is needed for the debug utilities in OLE2UI
+extern "C" {
+ OLEDBGDATA_MAIN("SIMPSVR")
+}
+
+CSimpSvrApp FAR * lpCSimpSvrApp;
+CClassFactory FAR * lpClassFactory;
+BOOL fBeVerbose = FALSE;
+extern "C"
+void TestDebugOut(LPSTR psz)
+{
+ if (fBeVerbose)
+ {
+ OutputDebugString(psz);
+ }
+}
+
+//**********************************************************************
+//
+// WinMain
+//
+// Purpose:
+//
+// Program entry point
+//
+// Parameters:
+//
+// HANDLE hInstance - Instance handle for this instance
+//
+// HANDLE hPrevInstance - Instance handle for the last instance
+//
+// LPSTR lpCmdLine - Pointer to the command line
+//
+// int nCmdShow - Window State
+//
+// Return Value:
+//
+// msg.wParam
+//
+// Function Calls:
+// Function Location
+//
+// CSimpSvrApp::CSimpSvrApp APP.CPP
+// CSimpSvrApp::fInitApplication APP.CPP
+// CSimpSvrApp::fInitInstance APP.CPP
+// CSimpSvrApp::HandleAccelerators APP.CPP
+// CSimpSvrApp::~CSimpSvrApp APP.CPP
+// OleUIInitialize OLE2UI
+// OleUIUninitialize OLE2UI
+// GetMessage Windows API
+// TranslateMessage Windows API
+// DispatchMessage Windows API
+//
+// Comments:
+//
+//********************************************************************
+
+int PASCAL WinMain(HANDLE hInstance,HANDLE hPrevInstance,LPSTR lpCmdLine,int nCmdShow)
+
+{
+ MSG msg;
+ fBeVerbose = GetProfileInt("OLEUTEST","BeVerbose",0);
+
+ if(fBeVerbose == 0)
+ {
+ fBeVerbose = GetProfileInt("OLEUTEST","spsvr16",0);
+ }
+
+ // recommended size for OLE apps
+ SetMessageQueue(96);
+
+ lpCSimpSvrApp = new CSimpSvrApp;
+
+ lpCSimpSvrApp->AddRef(); // need the app ref. count at 1 to hold the
+ // app alive.
+
+ lpCSimpSvrApp->ParseCmdLine(lpCmdLine);
+
+ // app initialization
+ if (!hPrevInstance)
+ if (!lpCSimpSvrApp->fInitApplication(hInstance))
+ return (FALSE);
+
+ // instance initialization
+ if (!lpCSimpSvrApp->fInitInstance(hInstance, nCmdShow, lpClassFactory))
+ return (FALSE);
+
+ /* Initialization required for OLE 2 UI library. This call is
+ ** needed ONLY if we are using the static link version of the UI
+ ** library. If we are using the DLL version, we should NOT call
+ ** this function in our application.
+ */
+ if (!OleUIInitialize(hInstance, hPrevInstance))
+ {
+ OleDbgOut("Could not initialize OLEUI library\n");
+ return FALSE;
+ }
+
+ // message loop
+ while (GetMessage(&msg, NULL, NULL, NULL))
+ {
+ if (lpCSimpSvrApp->IsInPlaceActive())
+
+ // Only key messages need to be sent to OleTranslateAccelerator. Any other message
+ // would result in an extra FAR call to occur for that message processing...
+
+ if ( (msg.message >= WM_KEYFIRST) && (msg.message <= WM_KEYLAST) )
+
+ // OleTranslateAccelerator MUST be called, even though this application does
+ // not have an accelerator table. This has to be done in order for the
+ // mneumonics for the top level menu items to work properly.
+
+ if ( OleTranslateAccelerator ( lpCSimpSvrApp->GetDoc()->GetObj()->GetInPlaceFrame(),
+ lpCSimpSvrApp->GetDoc()->GetObj()->GetFrameInfo(),
+ &msg) == NOERROR)
+ continue;
+
+ TranslateMessage(&msg); /* Translates virtual key codes */
+ DispatchMessage(&msg); /* Dispatches message to window */
+ }
+
+ // De-initialization for UI libraries. Just like OleUIInitialize, this
+ // funciton is needed ONLY if we are using the static link version of the
+ // OLE UI library.
+ OleUIUninitialize();
+
+ return (msg.wParam); /* Returns the value from PostQuitMessage */
+}
+
+
+//**********************************************************************
+//
+// MainWndProc
+//
+// Purpose:
+//
+// Processes messages for the frame window
+//
+// Parameters:
+//
+// HWND hWnd - Window handle for frame window
+//
+// UINT message - Message value
+//
+// WPARAM wParam - Message info
+//
+// LPARAM lParam - Message info
+//
+// Return Value:
+//
+// long
+//
+// Function Calls:
+// Function Location
+//
+// CSimpSvrApp::lCommandHandler APP.CPP
+// CSimpSvrApp::DestroyDocs APP.CPP
+// CSimpSvrApp::lCreateDoc APP.CPP
+// CSimpSvrApp::lSizeHandler APP.CPP
+// CGameDoc::lAddVerbs DOC.CPP
+// PostQuitMessage Windows API
+// DefWindowProc Windows API
+//
+// Comments:
+//
+//********************************************************************
+
+long FAR PASCAL _export MainWndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)
+
+{
+
+ switch (message)
+ {
+ case WM_CLOSE:
+ TestDebugOut("*** In WM_CLOSE *** \r\n");
+
+ // if there is still a document
+ if (lpCSimpSvrApp->GetDoc())
+
+ // if there is still an object within a document
+ if (lpCSimpSvrApp->GetDoc()->GetObj()) // this case occurs if there is still
+ // an outstanding Ref count on the object
+ // when the app is trying to go away.
+ // typically this case will occur in
+ // the "open" editing mode.
+ // Close the document
+ lpCSimpSvrApp->GetDoc()->Close();
+
+ // hide the app window
+ lpCSimpSvrApp->HideAppWnd();
+
+ // if we were started by ole, unregister the class factory, otherwise
+ // remove the ref count on our dummy OLE object
+ if (lpCSimpSvrApp->IsStartedByOle())
+ CoRevokeClassObject(lpCSimpSvrApp->GetRegisterClass());
+ else
+ lpCSimpSvrApp->GetOleObject()->Release();
+
+ lpCSimpSvrApp->Release(); // This should close the app.
+
+ break;
+
+ case WM_COMMAND: // message: command from application menu
+ return lpCSimpSvrApp->lCommandHandler(hWnd, message, wParam, lParam);
+ break;
+
+ case WM_CREATE:
+ return lpCSimpSvrApp->lCreateDoc(hWnd, message, wParam, lParam);
+ break;
+
+ case WM_DESTROY: // message: window being destroyed
+ PostQuitMessage(0);
+ break;
+
+ case WM_SIZE:
+ return lpCSimpSvrApp->lSizeHandler(hWnd, message, wParam, lParam);
+
+ default: // Passes it on if unproccessed
+ return (DefWindowProc(hWnd, message, wParam, lParam));
+ }
+ return (NULL);
+}
+
+
+//**********************************************************************
+//
+// About
+//
+// Purpose:
+//
+// Processes dialog box messages
+//
+// Parameters:
+//
+// HWND hWnd - Window handle for dialog box
+//
+// UINT message - Message value
+//
+// WPARAM wParam - Message info
+//
+// LPARAM lParam - Message info
+//
+// Return Value:
+//
+// Function Calls:
+// Function Location
+//
+// EndDialog Windows API
+//
+// Comments:
+//
+//********************************************************************
+
+BOOL FAR PASCAL _export About(HWND hDlg,unsigned message,WORD wParam,LONG lParam)
+
+{
+ switch (message) {
+ case WM_INITDIALOG: /* message: initialize dialog box */
+ return (TRUE);
+
+ case WM_COMMAND: /* message: received a command */
+ if (wParam == IDOK /* "OK" box selected? */
+ || wParam == IDCANCEL) { /* System menu close command? */
+ EndDialog(hDlg, TRUE); /* Exits the dialog box */
+ return (TRUE);
+ }
+ break;
+ }
+ return (FALSE); /* Didn't process a message */
+}
+
+//**********************************************************************
+//
+// DocWndProc
+//
+// Purpose:
+//
+// Processes dialog box messages
+//
+// Parameters:
+//
+// HWND hWnd - Window handle for doc window
+//
+// UINT message - Message value
+//
+// WPARAM wParam - Message info
+//
+// LPARAM lParam - Message info
+//
+// Return Value:
+//
+// Function Calls:
+// Function Location
+//
+// CSimpSvrApp::PaintApp APP.CPP
+// BeginPaint Windows API
+// EndPaint Windows API
+// DefWindowProc Windows API
+// IOleObject::QueryInterface Object
+// IOleInPlaceObject::UIDeactivate Object
+// IOleObject::DoVerb Object
+// IOleInPlaceObject::Release Object
+//
+// Comments:
+//
+//********************************************************************
+
+long FAR PASCAL _export DocWndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)
+{
+ HDC hDC;
+ PAINTSTRUCT ps;
+
+ switch (message) {
+ case WM_COMMAND: // message: command from application menu
+ return lpCSimpSvrApp->lCommandHandler(hWnd, message, wParam, lParam);
+ break;
+
+ case WM_PAINT:
+ hDC = BeginPaint(hWnd, &ps);
+
+ // tell the app class to paint itself
+ if (lpCSimpSvrApp)
+ lpCSimpSvrApp->PaintApp (hDC);
+
+ EndPaint(hWnd, &ps);
+ break;
+
+ case WM_MENUSELECT:
+ lpCSimpSvrApp->SetStatusText();
+ break;
+
+ default: /* Passes it on if unproccessed */
+ return (DefWindowProc(hWnd, message, wParam, lParam));
+ }
+ return (NULL);
+}
diff --git a/private/oleutest/utests16/simpsvr/simpsvr.h b/private/oleutest/utests16/simpsvr/simpsvr.h
new file mode 100644
index 000000000..840ef8860
--- /dev/null
+++ b/private/oleutest/utests16/simpsvr/simpsvr.h
@@ -0,0 +1,16 @@
+//**********************************************************************
+// File name: simpsvr.h
+//
+// Copyright (c) 1993 Microsoft Corporation. All rights reserved.
+//**********************************************************************
+#define IDM_ABOUT 100
+#define IDM_INSERT 101
+#define IDM_VERB0 1000
+
+
+int PASCAL WinMain(HANDLE hInstance,HANDLE hPrevInstance,LPSTR lpCmdLine,int nCmdShow);
+BOOL InitApplication(HANDLE hInstance);
+BOOL InitInstance(HANDLE hInstance, int nCmdShow);
+long FAR PASCAL _export MainWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
+long FAR PASCAL _export DocWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
+BOOL FAR PASCAL _export About(HWND hDlg, unsigned message, WORD wParam, LONG lParam);
diff --git a/private/oleutest/utests16/simpsvr/simpsvr.ico b/private/oleutest/utests16/simpsvr/simpsvr.ico
new file mode 100644
index 000000000..f351bc754
--- /dev/null
+++ b/private/oleutest/utests16/simpsvr/simpsvr.ico
Binary files differ
diff --git a/private/oleutest/utests16/simpsvr/simpsvr.reg b/private/oleutest/utests16/simpsvr/simpsvr.reg
new file mode 100644
index 000000000..78768f1ee
--- /dev/null
+++ b/private/oleutest/utests16/simpsvr/simpsvr.reg
@@ -0,0 +1,21 @@
+REGEDIT
+HKEY_CLASSES_ROOT\SIMPSVR = Simple OLE 2.0 Server
+HKEY_CLASSES_ROOT\SIMPSVR\protocol\StdFileEditing\server = simpsvr.exe
+HKEY_CLASSES_ROOT\SIMPSVR\protocol\StdFileEditing\verb\0 = &Edit
+HKEY_CLASSES_ROOT\SIMPSVR\protocol\StdFileEditing\verb\1 = &Open
+HKEY_CLASSES_ROOT\SIMPSVR\Insertable
+HKEY_CLASSES_ROOT\SIMPSVR\CLSID = {BCF6D4A0-BE8C-1068-B6D4-00DD010C0509}
+HKEY_CLASSES_ROOT\CLSID\{BCF6D4A0-BE8C-1068-B6D4-00DD010C0509} = Simple OLE 2.0 Server
+HKEY_CLASSES_ROOT\CLSID\{BCF6D4A0-BE8C-1068-B6D4-00DD010C0509}\Insertable
+HKEY_CLASSES_ROOT\CLSID\{BCF6D4A0-BE8C-1068-B6D4-00DD010C0509}\MiscStatus = 0
+HKEY_CLASSES_ROOT\CLSID\{BCF6D4A0-BE8C-1068-B6D4-00DD010C0509}\DefaultIcon = simpsvr.exe,0
+HKEY_CLASSES_ROOT\CLSID\{BCF6D4A0-BE8C-1068-B6D4-00DD010C0509}\AuxUserType\2 = Simple Server
+HKEY_CLASSES_ROOT\CLSID\{BCF6D4A0-BE8C-1068-B6D4-00DD010C0509}\AuxUserType\3 = Simple OLE 2.0 Server
+HKEY_CLASSES_ROOT\CLSID\{BCF6D4A0-BE8C-1068-B6D4-00DD010C0509}\Verb\0 = &Play,0,2
+HKEY_CLASSES_ROOT\CLSID\{BCF6D4A0-BE8C-1068-B6D4-00DD010C0509}\Verb\1 = &Open,0,2
+HKEY_CLASSES_ROOT\CLSID\{BCF6D4A0-BE8C-1068-B6D4-00DD010C0509}\LocalServer = simpsvr.exe
+HKEY_CLASSES_ROOT\CLSID\{BCF6D4A0-BE8C-1068-B6D4-00DD010C0509}\InprocHandler = ole2.dll
+HKEY_CLASSES_ROOT\CLSID\{BCF6D4A0-BE8C-1068-B6D4-00DD010C0509}\ProgID = SIMPSVR
+HKEY_CLASSES_ROOT\CLSID\{BCF6D4A0-BE8C-1068-B6D4-00DD010C0509}\DataFormats\GetSet\0 = 3,1,32,1
+HKEY_CLASSES_ROOT\.svr = SIMPSVR
+
diff --git a/private/oleutest/utests16/simpsvr/spsvr16.def b/private/oleutest/utests16/simpsvr/spsvr16.def
new file mode 100644
index 000000000..cfff029d6
--- /dev/null
+++ b/private/oleutest/utests16/simpsvr/spsvr16.def
@@ -0,0 +1,22 @@
+; module-definition file for generic -- used by LINK.EXE
+
+NAME SPSVR16 ; application's module name
+
+DESCRIPTION 'Sample Microsoft Windows Application'
+
+EXETYPE WINDOWS ; required for all Windows applications
+
+STUB 'WINSTUB.EXE' ; Generates error message if application
+ ; is run without Windows
+
+;CODE can be moved in memory and discarded/reloaded
+CODE PRELOAD MOVEABLE DISCARDABLE
+
+;DATA must be MULTIPLE if program can be invoked more than once
+DATA PRELOAD MOVEABLE MULTIPLE
+
+
+HEAPSIZE 1024
+
+; All functions that will be called by any Windows routine
+; MUST be exported.
diff --git a/private/oleutest/utests16/simpsvr/spsvr16.rc b/private/oleutest/utests16/simpsvr/spsvr16.rc
new file mode 100644
index 000000000..190867d41
--- /dev/null
+++ b/private/oleutest/utests16/simpsvr/spsvr16.rc
@@ -0,0 +1,107 @@
+//Microsoft App Studio generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#define APSTUDIO_HIDDEN_SYMBOLS
+#include "windows.h"
+#undef APSTUDIO_HIDDEN_SYMBOLS
+#include "simpsvr.h"
+
+/////////////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+SIMPSVR ICON DISCARDABLE "SIMPSVR.ICO"
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// Menu
+//
+
+SIMPSVRMENU MENU DISCARDABLE
+BEGIN
+ POPUP "&File"
+ BEGIN
+ MENUITEM "E&xit", IDM_EXIT
+ END
+ POPUP "&Color"
+ BEGIN
+ MENUITEM "&Red", IDM_RED
+ MENUITEM "&Green", IDM_GREEN
+ MENUITEM "&Blue", IDM_BLUE
+ MENUITEM SEPARATOR
+ MENUITEM "&Rotate", IDM_ROTATE
+ END
+ POPUP "&Help"
+ BEGIN
+ MENUITEM "&About Simpsvr...", IDM_ABOUT
+ END
+END
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+ABOUTBOX DIALOG DISCARDABLE 22, 17, 144, 75
+STYLE DS_MODALFRAME | WS_CAPTION | WS_SYSMENU
+CAPTION "Simple OLE 2.0 Server"
+FONT 8, "System"
+BEGIN
+ CTEXT "Microsoft Windows",-1,0,5,144,8
+ CTEXT "Simple OLE 2.0 Server",-1,0,14,144,8
+ CTEXT "Version 1.0",-1,0,34,144,8
+ DEFPUSHBUTTON "OK",IDOK,53,59,32,14,WS_GROUP
+END
+
+#ifdef APSTUDIO_INVOKED
+//////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "#define APSTUDIO_HIDDEN_SYMBOLS\r\n"
+ "#include ""windows.h""\r\n"
+ "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n"
+ "#include ""simpsvr.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "#include ""..\\ole2ui\\ole2ui.rc""\r\n"
+ "\0"
+END
+
+/////////////////////////////////////////////////////////////////////////////////////
+#endif // APSTUDIO_INVOKED
+
+
+#ifndef APSTUDIO_INVOKED
+////////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+#include "..\ole2ui\ole2ui.rc"
+
+/////////////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/private/oleutest/uthread/at/makefile b/private/oleutest/uthread/at/makefile
new file mode 100644
index 000000000..1d3728d41
--- /dev/null
+++ b/private/oleutest/uthread/at/makefile
@@ -0,0 +1,10 @@
+############################################################################
+#
+# Copyright (C) 1992, Microsoft Corporation.
+#
+# All rights reserved.
+#
+############################################################################
+
+!include $(NTMAKEENV)\makefile.def
+
diff --git a/private/oleutest/uthread/at/makefile.inc b/private/oleutest/uthread/at/makefile.inc
new file mode 100644
index 000000000..fbbb4f738
--- /dev/null
+++ b/private/oleutest/uthread/at/makefile.inc
@@ -0,0 +1 @@
+obj\i386\oleat.def: oleat.src
diff --git a/private/oleutest/uthread/at/oleat.cpp b/private/oleutest/uthread/at/oleat.cpp
new file mode 100644
index 000000000..641a5bfa3
--- /dev/null
+++ b/private/oleutest/uthread/at/oleat.cpp
@@ -0,0 +1,26 @@
+//+-------------------------------------------------------------------
+//
+// File: oleat.cpp
+//
+// Contents: Unique parts of apt model DLL server
+//
+// Classes:
+//
+// Functions:
+//
+// History: 03-Nov-94 Ricksa
+//
+//--------------------------------------------------------------------
+#undef _UNICODE
+#undef UNICODE
+#include <windows.h>
+#include <ole2.h>
+#include <comclass.h>
+#include <uthread.h>
+
+CLSID clsidServer;
+
+void InitDll(void)
+{
+ clsidServer = clsidAptThreadedDll;
+}
diff --git a/private/oleutest/uthread/at/oleat.src b/private/oleutest/uthread/at/oleat.src
new file mode 100644
index 000000000..581d3cb26
--- /dev/null
+++ b/private/oleutest/uthread/at/oleat.src
@@ -0,0 +1,48 @@
+#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 oleat
+
+DESCRIPTION 'Microsoft (R) OLE 2.0 Proxy DLL 1.00'
+
+EXPORTS
+#if defined(i386)
+
+ _DllGetClassObject@12 @1
+ DllGetClassObject=_DllGetClassObject@12
+ _DllCanUnloadNow@0 @2
+ DllCanUnloadNow=_DllCanUnloadNow@0
+
+#else
+
+ DllGetClassObject @1
+ DllCanUnloadNow @2
+
+#endif // i386 - MIPS
+
+#endif // FLAT
diff --git a/private/oleutest/uthread/at/sources b/private/oleutest/uthread/at/sources
new file mode 100644
index 000000000..5df2cc9b3
--- /dev/null
+++ b/private/oleutest/uthread/at/sources
@@ -0,0 +1,96 @@
+!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:
+
+ David Plummer (davepl) 19-Mar-94
+
+ Modifed by via awk to include global project include file
+ and to wrap precompiled header line within a conditional
+ that can be set in this include file.
+
+ Donna Liu (DonnaLi) 19-Dec-1993
+
+!ENDIF
+
+MAJORCOMP = oleutest
+MINORCOMP = com
+
+# This links against "common". This Block assures that the build
+# of "common" finished before preceeding. This Block also serves
+# to protect the "bt" and "st" directories.
+
+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= oleat
+
+#
+# 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= DYNLINK
+
+DLLDEF= obj\*\oleat.def
+
+DLLENTRY= _DllMainCRTStartup
+
+DLLBASE=@$(BASEDIR)\PUBLIC\SDK\LIB\coffbase.txt,usermode
+
+#
+# The following includes a global include file defined at the
+# base of the project for all components
+#
+
+!include ..\..\daytona.inc
+
+INCLUDES= ..
+
+C_DEFINES= \
+ $(C_DEFINES)
+
+
+SOURCES= \
+ oleat.cpp
+
+LINKLIBS= \
+ ..\common\obj\*\common.lib \
+ $(BASEDIR)\public\sdk\lib\*\uuid.lib \
+ $(BASEDIR)\public\sdk\lib\*\ole32.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\*\crtdll.lib
+
+
+UMTYPE= windows
+UMAPPL=
+UMTEST=
diff --git a/private/oleutest/uthread/bt/makefile b/private/oleutest/uthread/bt/makefile
new file mode 100644
index 000000000..1d3728d41
--- /dev/null
+++ b/private/oleutest/uthread/bt/makefile
@@ -0,0 +1,10 @@
+############################################################################
+#
+# Copyright (C) 1992, Microsoft Corporation.
+#
+# All rights reserved.
+#
+############################################################################
+
+!include $(NTMAKEENV)\makefile.def
+
diff --git a/private/oleutest/uthread/bt/makefile.inc b/private/oleutest/uthread/bt/makefile.inc
new file mode 100644
index 000000000..663ac97be
--- /dev/null
+++ b/private/oleutest/uthread/bt/makefile.inc
@@ -0,0 +1 @@
+obj\i386\olebt.def: olebt.src
diff --git a/private/oleutest/uthread/bt/olebt.cpp b/private/oleutest/uthread/bt/olebt.cpp
new file mode 100644
index 000000000..12c3f5a99
--- /dev/null
+++ b/private/oleutest/uthread/bt/olebt.cpp
@@ -0,0 +1,474 @@
+//+-------------------------------------------------------------------
+//
+// File: olebt.cpp
+//
+// Contents: Test DLL class code that be used multithreaded.
+//
+// Classes:
+//
+// Functions:
+//
+// History: 03-Nov-94 Ricksa
+//
+//--------------------------------------------------------------------
+#undef _UNICODE
+#undef UNICODE
+#include <windows.h>
+#include <ole2.h>
+#include <uthread.h>
+
+
+// Global count of
+ULONG g_UseCount = 0;
+
+void PrintDebugMsg(char *pszMsg, DWORD dwData)
+{
+ char wszBuf[256];
+ wsprintf(wszBuf, "olebt.dll: %s %d\n", pszMsg, dwData);
+ OutputDebugString(wszBuf);
+}
+
+
+
+//+-------------------------------------------------------------------
+//
+// Class: CBasicBndCF
+//
+// Synopsis: Class Factory for CBasicBnd
+//
+// Methods: IUnknown - QueryInterface, AddRef, Release
+// IClassFactory - CreateInstance
+//
+// History: 03-Nov-94 Ricksa Created
+//
+//--------------------------------------------------------------------
+class FAR CBasicBndCF: public IClassFactory
+{
+public:
+
+ // Constructor/Destructor
+ CBasicBndCF(void);
+ ~CBasicBndCF();
+
+ // IUnknown
+ STDMETHODIMP QueryInterface(REFIID iid, void FAR * FAR * ppv);
+ STDMETHODIMP_(ULONG) AddRef(void);
+ STDMETHODIMP_(ULONG) Release(void);
+
+
+ // IClassFactory
+ STDMETHODIMP CreateInstance(
+ IUnknown FAR* pUnkOuter,
+ REFIID iidInterface,
+ void FAR* FAR* ppv);
+
+ STDMETHODIMP LockServer(BOOL fLock);
+
+private:
+
+ ULONG _cRefs;
+
+ IUnknown * _punkFm;
+};
+
+
+
+//+-------------------------------------------------------------------
+//
+// Class: CBasicBnd
+//
+// Synopsis: Test class CBasicBnd
+//
+// Methods:
+//
+// History: 03-Nov-94 Ricksa Created
+//
+//--------------------------------------------------------------------
+class FAR CBasicBnd: public IPersist
+{
+public:
+ // Constructor/Destructor
+ CBasicBnd(void);
+ ~CBasicBnd();
+
+ // IUnknown
+ STDMETHODIMP QueryInterface(REFIID iid, void FAR * FAR * ppv);
+ STDMETHODIMP_(ULONG) AddRef(void);
+ STDMETHODIMP_(ULONG) Release(void);
+
+ // IPersist - only thing we implement because it
+ // gives us a nice way to figure who we are talking to.
+ STDMETHODIMP GetClassID(LPCLSID lpClassID);
+
+private:
+
+ ULONG _cRefs;
+
+ IUnknown * _punkFm;
+};
+
+
+extern "C" BOOL WINAPI DllMain(
+ HANDLE,
+ DWORD,
+ LPVOID)
+{
+ return TRUE;
+}
+
+
+//+-------------------------------------------------------------------
+//
+// Function: DllGetClassObject
+//
+// Synopsis: Called by client (from within BindToObject et al)
+// interface requested should be IUnknown or IClassFactory -
+// Creates ClassFactory object and returns pointer to it
+//
+// Arguments: REFCLSID clsid - class id
+// REFIID iid - interface id
+// void FAR* FAR* ppv- pointer to class factory interface
+//
+// Returns: TRUE
+//
+// History: 03-Nov-94 Ricksa Created
+//
+//--------------------------------------------------------------------
+STDAPI DllGetClassObject(REFCLSID clsid, REFIID iid, void FAR* FAR* ppv)
+{
+ *ppv = NULL;
+
+ if (!IsEqualGUID(iid, IID_IUnknown)
+ && !IsEqualGUID(iid, IID_IClassFactory)
+ && !IsEqualGUID(iid, IID_IMarshal))
+ {
+ return E_NOINTERFACE;
+ }
+
+ if (IsEqualGUID(clsid, clsidBothThreadedDll))
+ {
+ IUnknown *punk = new CBasicBndCF();
+
+ HRESULT hr = punk->QueryInterface(iid, ppv);
+
+ punk->Release();
+
+ return hr;
+ }
+
+ return E_FAIL;
+}
+
+
+STDAPI DllCanUnloadNow(void)
+{
+ return (g_UseCount == 0)
+ ? S_OK
+ : S_FALSE;
+}
+
+
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CBasicBndCF::CBasicBndCF()
+//
+// Synopsis: The constructor for CBAsicBnd.
+//
+// Arguments: None
+//
+// History: 21-Nov-92 Ricksa Created
+//
+//--------------------------------------------------------------------
+CBasicBndCF::CBasicBndCF(void)
+ : _cRefs(1), _punkFm(NULL)
+{
+ PrintDebugMsg("Creating Class Factory", (DWORD) this);
+ g_UseCount++;
+}
+
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CBasicBnd::~CBasicBndCF()
+//
+// Synopsis: The destructor for CBasicCF.
+//
+// History: 03-Nov-94 Ricksa Created
+//
+//--------------------------------------------------------------------
+CBasicBndCF::~CBasicBndCF()
+{
+ PrintDebugMsg("Deleting Class Factory", (DWORD) this);
+ g_UseCount--;
+
+ if (_punkFm != NULL)
+ {
+ _punkFm->Release();
+ }
+
+ return;
+}
+
+
+//+-------------------------------------------------------------------
+//
+// Method: CBasicBndCF::QueryInterface
+//
+// Synopsis: Only IUnknown and IClassFactory supported
+//
+// History: 03-Nov-94 Ricksa Created
+//
+//--------------------------------------------------------------------
+STDMETHODIMP CBasicBndCF::QueryInterface(REFIID iid, void **ppv)
+{
+ HRESULT hr = E_NOINTERFACE;
+ *ppv = NULL;
+
+ if (IsEqualGUID(iid, IID_IUnknown) || IsEqualGUID(iid, IID_IClassFactory))
+ {
+ *ppv = this;
+ AddRef();
+ hr = S_OK;
+ }
+ else if (IsEqualGUID(iid, IID_IMarshal))
+ {
+ if (NULL == _punkFm)
+ {
+ hr = CoCreateFreeThreadedMarshaler(this, &_punkFm);
+ }
+
+ if (_punkFm != NULL)
+ {
+ return _punkFm->QueryInterface(iid, ppv);
+ }
+ }
+
+ return hr;
+}
+
+//+-------------------------------------------------------------------
+//
+// Method: CBasicBndCF::AddRef
+//
+// Synopsis: Increment reference count
+//
+// History: 03-Nov-94 Ricksa Created
+//
+//--------------------------------------------------------------------
+STDMETHODIMP_(ULONG) CBasicBndCF::AddRef(void)
+{
+ return ++_cRefs;
+}
+
+//+-------------------------------------------------------------------
+//
+// Method: CBasicBndCF::Release
+//
+// Synopsis: Decrement reference count
+//
+// History: 03-Nov-94 Ricksa Created
+//
+//--------------------------------------------------------------------
+STDMETHODIMP_(ULONG) CBasicBndCF::Release(void)
+{
+ ULONG cRefs = --_cRefs;
+
+ if (cRefs == 0)
+ {
+ delete this;
+ }
+
+ return cRefs;
+}
+
+
+
+//+-------------------------------------------------------------------
+//
+// Method: CBasicBndCF::CreateInstance
+//
+// Synopsis: This is called by Binding process to create the
+// actual class object
+//
+//--------------------------------------------------------------------
+STDMETHODIMP CBasicBndCF::CreateInstance(
+ IUnknown FAR* pUnkOuter,
+ REFIID iidInterface,
+ void FAR* FAR* ppv)
+{
+ HRESULT hresult = S_OK;
+
+ if (pUnkOuter != NULL)
+ {
+ return CLASS_E_NOAGGREGATION;
+ }
+
+ CBasicBnd *pbb = new FAR CBasicBnd();
+
+ if (pbb == NULL)
+ {
+ return E_OUTOFMEMORY;
+ }
+
+ hresult = pbb->QueryInterface(iidInterface, ppv);
+
+ pbb->Release();
+
+ return hresult;
+}
+
+//+-------------------------------------------------------------------
+//
+// Method: CBasicBndCF::LockServer
+//
+// Synopsis: Inc/Dec stay alive count
+//
+// History: 03-Nov-94 Ricksa Created
+//
+//--------------------------------------------------------------------
+
+STDMETHODIMP CBasicBndCF::LockServer(BOOL fLock)
+{
+ if (fLock)
+ {
+ g_UseCount++;
+ }
+ else
+ {
+ g_UseCount--;
+ }
+
+ return S_OK;
+}
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CBasicBnd::CBasicBnd()
+//
+// Synopsis: The constructor for CBAsicBnd. I
+//
+// Arguments: None
+//
+// History: 03-Nov-94 Ricksa Created
+//
+//--------------------------------------------------------------------
+
+CBasicBnd::CBasicBnd(void)
+ : _cRefs(1), _punkFm(NULL)
+{
+ PrintDebugMsg("Creating App Object", (DWORD) this);
+ g_UseCount++;
+}
+
+//+-------------------------------------------------------------------
+//
+// Member: CBasicBnd::~CBasicBndObj()
+//
+// Synopsis: The destructor for CBAsicBnd.
+//
+// History: 03-Nov-94 Ricksa Created
+//
+//--------------------------------------------------------------------
+
+CBasicBnd::~CBasicBnd(void)
+{
+ PrintDebugMsg("Deleting App Object", (DWORD) this);
+ g_UseCount--;
+ return;
+}
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CBasicBnd::QueryInterface
+//
+// Returns: S_OK
+//
+// History: 03-Nov-94 Ricksa Created
+//
+//--------------------------------------------------------------------
+STDMETHODIMP CBasicBnd::QueryInterface(REFIID iid, void **ppv)
+{
+ if (IsEqualGUID(iid, IID_IUnknown) || IsEqualGUID(iid, IID_IPersist))
+ {
+ *ppv = this;
+ AddRef();
+ return S_OK;
+ }
+ else if (IsEqualGUID(iid, IID_IMarshal))
+ {
+ HRESULT hr;
+
+ if (NULL == _punkFm)
+ {
+ hr = CoCreateFreeThreadedMarshaler(this, &_punkFm);
+ }
+
+ if (_punkFm != NULL)
+ {
+ hr = _punkFm->QueryInterface(iid, ppv);
+ }
+
+ return hr;
+ }
+ else
+ {
+ *ppv = NULL;
+ return E_NOINTERFACE;
+ }
+}
+
+//+-------------------------------------------------------------------
+//
+// Member: CBasicBnd::AddRef
+//
+// Synopsis: Standard stuff
+//
+// History: 03-Nov-94 Ricksa Created
+//
+//--------------------------------------------------------------------
+STDMETHODIMP_(ULONG) CBasicBnd::AddRef(void)
+{
+ return _cRefs++;
+}
+
+//+-------------------------------------------------------------------
+//
+// Member: CBasicBnd::Release
+//
+// Synopsis: Standard stuff
+//
+// History: 03-Nov-94 Ricksa Created
+//
+//--------------------------------------------------------------------
+STDMETHODIMP_(ULONG) CBasicBnd::Release(void)
+{
+ ULONG cRefs;
+
+ if ((cRefs = --_cRefs) == 0)
+ {
+ delete this;
+ }
+
+ return cRefs;
+}
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CBasicBnd::GetClassID
+//
+// Synopsis: Return the class id
+//
+// History: 03-Nov-94 Ricksa Created
+//
+//--------------------------------------------------------------------
+STDMETHODIMP CBasicBnd::GetClassID(LPCLSID classid)
+{
+ *classid = clsidBothThreadedDll;
+ return S_OK;
+}
diff --git a/private/oleutest/uthread/bt/olebt.src b/private/oleutest/uthread/bt/olebt.src
new file mode 100644
index 000000000..f36dd0748
--- /dev/null
+++ b/private/oleutest/uthread/bt/olebt.src
@@ -0,0 +1,48 @@
+#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 olebt
+
+DESCRIPTION 'Microsoft (R) OLE 2.0 Proxy DLL 1.00'
+
+EXPORTS
+#if defined(i386)
+
+ _DllGetClassObject@12 @1
+ DllGetClassObject=_DllGetClassObject@12
+ _DllCanUnloadNow@0 @2
+ DllCanUnloadNow=_DllCanUnloadNow@0
+
+#else
+
+ DllGetClassObject @1
+ DllCanUnloadNow @2
+
+#endif // i386 - MIPS
+
+#endif // FLAT
diff --git a/private/oleutest/uthread/bt/sources b/private/oleutest/uthread/bt/sources
new file mode 100644
index 000000000..76334023e
--- /dev/null
+++ b/private/oleutest/uthread/bt/sources
@@ -0,0 +1,89 @@
+!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:
+
+ David Plummer (davepl) 19-Mar-94
+
+ Modifed by via awk to include global project include file
+ and to wrap precompiled header line within a conditional
+ that can be set in this include file.
+
+ Donna Liu (DonnaLi) 19-Dec-1993
+
+!ENDIF
+
+MAJORCOMP = oleutest
+MINORCOMP = com
+
+#
+# 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= olebt
+
+#
+# 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= DYNLINK
+
+DLLDEF= obj\*\olebt.def
+
+DLLENTRY= _DllMainCRTStartup
+
+DLLBASE=@$(BASEDIR)\PUBLIC\SDK\LIB\coffbase.txt,usermode
+
+#
+# The following includes a global include file defined at the
+# base of the project for all components
+#
+
+!include ..\..\daytona.inc
+
+INCLUDES= ..
+
+C_DEFINES= \
+ $(C_DEFINES)
+
+
+SOURCES= \
+ olebt.cpp
+
+LINKLIBS= \
+ ..\common\obj\*\common.lib \
+ $(BASEDIR)\public\sdk\lib\*\uuid.lib \
+ $(BASEDIR)\public\sdk\lib\*\ole32.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\*\crtdll.lib
+
+
+UMTYPE= windows
+UMAPPL=
+UMTEST=
diff --git a/private/oleutest/uthread/comclass.h b/private/oleutest/uthread/comclass.h
new file mode 100644
index 000000000..b0c6855b5
--- /dev/null
+++ b/private/oleutest/uthread/comclass.h
@@ -0,0 +1,17 @@
+//+-------------------------------------------------------------------
+//
+// File: comclass.h
+//
+// Contents: Define class id for use by com class
+//
+// History: 03-Nov-94 Ricksa
+//
+//--------------------------------------------------------------------
+#ifndef _COMCLASS_H_
+#define _COMCLASS_H_
+
+extern CLSID clsidServer;
+
+void InitDll(void);
+
+#endif // _COMCLASS_H_
diff --git a/private/oleutest/uthread/common/classdef.cpp b/private/oleutest/uthread/common/classdef.cpp
new file mode 100644
index 000000000..b8a111576
--- /dev/null
+++ b/private/oleutest/uthread/common/classdef.cpp
@@ -0,0 +1,25 @@
+//+-------------------------------------------------------------------
+//
+// File: classdef.cpp
+//
+// Contents: Common constants for thread unit test
+//
+// History: 03-Nov-94 Ricksa
+//
+//--------------------------------------------------------------------
+#undef _UNICODE
+#undef UNICODE
+#include <windows.h>
+#include <uthread.h>
+
+const CLSID clsidSingleThreadedDll =
+ {0xe22e88c0, 0xf72a, 0x11cd, {0xa1,0xaa,0x00,0x00,0x69,0x01,0x29,0x3f}};
+const char *pszSingleThreadedDll = "olest.dll";
+
+const CLSID clsidAptThreadedDll =
+ {0xe82c0ae0, 0xf72a, 0x11cd, {0xa1,0xaa,0x00,0x00,0x69,0x01,0x29,0x3f}};
+const char *pszAptThreadedDll = "oleat.dll";
+
+const CLSID clsidBothThreadedDll =
+ {0xe97d4300, 0xf72a, 0x11cd, {0xa1,0xaa,0x00,0x00,0x69,0x01,0x29,0x3f}};
+const char *pszBothThreadedDll = "olebt.dll";
diff --git a/private/oleutest/uthread/common/comclass.cpp b/private/oleutest/uthread/common/comclass.cpp
new file mode 100644
index 000000000..682dcbb47
--- /dev/null
+++ b/private/oleutest/uthread/common/comclass.cpp
@@ -0,0 +1,436 @@
+//+-------------------------------------------------------------------
+//
+// File: comclass.cpp
+//
+// Contents: Test DLL class code that can be used for both apt
+// model and single threaded application
+//
+// Classes:
+//
+// Functions:
+//
+// History: 03-Nov-94 Ricksa
+//
+//--------------------------------------------------------------------
+#undef _UNICODE
+#undef UNICODE
+#include <windows.h>
+#include <ole2.h>
+#include <comclass.h>
+
+
+// Global count of
+ULONG g_UseCount = 0;
+
+
+
+
+//+-------------------------------------------------------------------
+//
+// Class: CBasicBndCF
+//
+// Synopsis: Class Factory for CBasicBnd
+//
+// Methods: IUnknown - QueryInterface, AddRef, Release
+// IClassFactory - CreateInstance
+//
+// History: 03-Nov-94 Ricksa Created
+//
+//--------------------------------------------------------------------
+class FAR CBasicBndCF: public IClassFactory
+{
+public:
+
+ // Constructor/Destructor
+ CBasicBndCF(REFCLSID rclsid);
+ ~CBasicBndCF();
+
+ // IUnknown
+ STDMETHODIMP QueryInterface(REFIID iid, void FAR * FAR * ppv);
+ STDMETHODIMP_(ULONG) AddRef(void);
+ STDMETHODIMP_(ULONG) Release(void);
+
+
+ // IClassFactory
+ STDMETHODIMP CreateInstance(
+ IUnknown FAR* pUnkOuter,
+ REFIID iidInterface,
+ void FAR* FAR* ppv);
+
+ STDMETHODIMP LockServer(BOOL fLock);
+
+private:
+
+ ULONG _cRefs;
+
+ REFCLSID _rclsid;
+
+ DWORD _dwThreadId;
+};
+
+
+
+//+-------------------------------------------------------------------
+//
+// Class: CBasicBnd
+//
+// Synopsis: Test class CBasicBnd
+//
+// Methods:
+//
+// History: 03-Nov-94 Ricksa Created
+//
+//--------------------------------------------------------------------
+class FAR CBasicBnd: public IPersist
+{
+public:
+ // Constructor/Destructor
+ CBasicBnd(REFCLSID rclsd, DWORD dwThreadId);
+ ~CBasicBnd();
+
+ // IUnknown
+ STDMETHODIMP QueryInterface(REFIID iid, void FAR * FAR * ppv);
+ STDMETHODIMP_(ULONG) AddRef(void);
+ STDMETHODIMP_(ULONG) Release(void);
+
+ // IPersist - only thing we implement because it
+ // gives us a nice way to figure who we are talking to.
+ STDMETHODIMP GetClassID(LPCLSID lpClassID);
+
+private:
+
+ ULONG _cRefs;
+
+ REFCLSID _rclsid;
+
+ DWORD _dwThreadId;
+};
+
+
+extern "C" BOOL WINAPI DllMain(
+ HANDLE,
+ DWORD,
+ LPVOID)
+{
+ static BOOL fFirst = TRUE;
+
+ if (fFirst)
+ {
+ InitDll();
+ fFirst = FALSE;
+ }
+
+ return TRUE;
+}
+
+
+//+-------------------------------------------------------------------
+//
+// Function: DllGetClassObject
+//
+// Synopsis: Called by client (from within BindToObject et al)
+// interface requested should be IUnknown or IClassFactory -
+// Creates ClassFactory object and returns pointer to it
+//
+// Arguments: REFCLSID clsid - class id
+// REFIID iid - interface id
+// void FAR* FAR* ppv- pointer to class factory interface
+//
+// Returns: TRUE
+//
+// History: 03-Nov-94 Ricksa Created
+//
+//--------------------------------------------------------------------
+STDAPI DllGetClassObject(REFCLSID clsid, REFIID iid, void FAR* FAR* ppv)
+{
+ if (!IsEqualGUID(iid, IID_IUnknown)
+ && !IsEqualGUID(iid, IID_IClassFactory))
+ {
+ return E_NOINTERFACE;
+ }
+
+ if (IsEqualGUID(clsid, clsidServer))
+ {
+ *ppv = new CBasicBndCF(clsidServer);
+
+ return (*ppv != NULL) ? S_OK : E_OUTOFMEMORY;
+ }
+
+ return E_FAIL;
+}
+
+
+STDAPI DllCanUnloadNow(void)
+{
+ return (g_UseCount == 0)
+ ? S_OK
+ : S_FALSE;
+}
+
+
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CBasicBndCF::CBasicBndCF()
+//
+// Synopsis: The constructor for CBAsicBnd.
+//
+// Arguments: None
+//
+// History: 21-Nov-92 SarahJ Created
+//
+//--------------------------------------------------------------------
+CBasicBndCF::CBasicBndCF(REFCLSID rclsid)
+ : _cRefs(1), _rclsid(rclsid), _dwThreadId(GetCurrentThreadId())
+{
+ g_UseCount++;
+}
+
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CBasicBnd::~CBasicBndCF()
+//
+// Synopsis: The destructor for CBasicCF.
+//
+// History: 21-Nov-92 SarahJ Created
+//
+//--------------------------------------------------------------------
+CBasicBndCF::~CBasicBndCF()
+{
+ g_UseCount--;
+ return;
+}
+
+
+//+-------------------------------------------------------------------
+//
+// Method: CBasicBndCF::QueryInterface
+//
+// Synopsis: Only IUnknown and IClassFactory supported
+//
+//--------------------------------------------------------------------
+STDMETHODIMP CBasicBndCF::QueryInterface(REFIID iid, void FAR * FAR * ppv)
+{
+ if (IsEqualGUID(iid, IID_IUnknown) || IsEqualGUID(iid, IID_IClassFactory))
+ {
+ *ppv = this;
+ AddRef();
+ return S_OK;
+ }
+ else
+ {
+ *ppv = NULL;
+ return E_NOINTERFACE;
+ }
+}
+
+STDMETHODIMP_(ULONG) CBasicBndCF::AddRef(void)
+{
+ return ++_cRefs;
+}
+
+STDMETHODIMP_(ULONG) CBasicBndCF::Release(void)
+{
+ ULONG cRefs = --_cRefs;
+
+ if (cRefs == 0)
+ {
+ delete this;
+ }
+
+ return cRefs;
+}
+
+
+
+//+-------------------------------------------------------------------
+//
+// Method: CBasicBndCF::CreateInstance
+//
+// Synopsis: This is called by Binding process to create the
+// actual class object
+//
+//--------------------------------------------------------------------
+STDMETHODIMP CBasicBndCF::CreateInstance(
+ IUnknown FAR* pUnkOuter,
+ REFIID iidInterface,
+ void FAR* FAR* ppv)
+{
+ if (GetCurrentThreadId() != _dwThreadId)
+ {
+ return E_UNEXPECTED;
+ }
+
+ HRESULT hresult = S_OK;
+
+ if (pUnkOuter != NULL)
+ {
+ return CLASS_E_NOAGGREGATION;
+ }
+
+ CBasicBnd *pbb = new FAR CBasicBnd(_rclsid, _dwThreadId);
+
+ if (pbb == NULL)
+ {
+ return E_OUTOFMEMORY;
+ }
+
+ hresult = pbb->QueryInterface(iidInterface, ppv);
+
+ pbb->Release();
+
+ return hresult;
+}
+
+//+-------------------------------------------------------------------
+//
+// Method: CBasicBndCF::LockServer
+//
+// Synopsis: Who knows what this is for?
+//
+//--------------------------------------------------------------------
+
+STDMETHODIMP CBasicBndCF::LockServer(BOOL fLock)
+{
+ if (GetCurrentThreadId() != _dwThreadId)
+ {
+ return E_UNEXPECTED;
+ }
+
+ if (fLock)
+ {
+ g_UseCount++;
+ }
+ else
+ {
+ g_UseCount--;
+ }
+
+ return S_OK;
+}
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CBasicBnd::CBasicBnd()
+//
+// Synopsis: The constructor for CBAsicBnd. I
+//
+// Arguments: None
+//
+// History: 21-Nov-92 SarahJ Created
+//
+//--------------------------------------------------------------------
+
+CBasicBnd::CBasicBnd(REFCLSID rclsid, DWORD dwThreadId)
+ : _cRefs(1), _rclsid(rclsid), _dwThreadId(dwThreadId)
+{
+ g_UseCount++;
+}
+
+//+-------------------------------------------------------------------
+//
+// Member: CBasicBnd::~CBasicBndObj()
+//
+// Synopsis: The destructor for CBAsicBnd.
+//
+// History: 21-Nov-92 SarahJ Created
+//
+//--------------------------------------------------------------------
+
+CBasicBnd::~CBasicBnd()
+{
+ g_UseCount--;
+ return;
+}
+
+
+//+-------------------------------------------------------------------
+//
+// Member: CBasicBnd::QueryInterface
+//
+// Returns: S_OK
+//
+// History: 21-Nov-92 SarahJ Created
+//
+//--------------------------------------------------------------------
+STDMETHODIMP CBasicBnd::QueryInterface(REFIID iid, void **ppv)
+{
+ if (GetCurrentThreadId() != _dwThreadId)
+ {
+ return E_UNEXPECTED;
+ }
+
+ if (IsEqualGUID(iid, IID_IUnknown) || IsEqualGUID(iid, IID_IPersist))
+ {
+ *ppv = this;
+ AddRef();
+ return S_OK;
+ }
+ else
+ {
+ *ppv = NULL;
+ return E_NOINTERFACE;
+ }
+}
+
+//+-------------------------------------------------------------------
+//
+// Member: CBasicBnd::AddRef
+//
+// Synopsis: Standard stuff
+//
+// History: 21-Nov-92 SarahJ Created
+//
+//--------------------------------------------------------------------
+STDMETHODIMP_(ULONG) CBasicBnd::AddRef(void)
+{
+ return _cRefs++;
+}
+
+//+-------------------------------------------------------------------
+//
+// Member: CBasicBnd::Release
+//
+// Synopsis: Standard stuff
+//
+// History: 21-Nov-92 SarahJ Created
+//
+//--------------------------------------------------------------------
+
+STDMETHODIMP_(ULONG) CBasicBnd::Release(void)
+{
+ ULONG cRefs;
+
+ if ((cRefs = --_cRefs) == 0)
+ {
+ delete this;
+ }
+
+ return cRefs;
+}
+
+
+//+-------------------------------------------------------------------
+//
+// Interface: IPersist
+//
+// Synopsis: IPersist interface methods
+// Need to return a valid class id here
+//
+// History: 21-Nov-92 SarahJ Created
+//
+
+STDMETHODIMP CBasicBnd::GetClassID(LPCLSID classid)
+{
+ if (GetCurrentThreadId() != _dwThreadId)
+ {
+ return E_UNEXPECTED;
+ }
+
+ *classid = _rclsid;
+ return S_OK;
+}
diff --git a/private/oleutest/uthread/common/makefile b/private/oleutest/uthread/common/makefile
new file mode 100644
index 000000000..1d3728d41
--- /dev/null
+++ b/private/oleutest/uthread/common/makefile
@@ -0,0 +1,10 @@
+############################################################################
+#
+# Copyright (C) 1992, Microsoft Corporation.
+#
+# All rights reserved.
+#
+############################################################################
+
+!include $(NTMAKEENV)\makefile.def
+
diff --git a/private/oleutest/uthread/common/sources b/private/oleutest/uthread/common/sources
new file mode 100644
index 000000000..d5b246d14
--- /dev/null
+++ b/private/oleutest/uthread/common/sources
@@ -0,0 +1,77 @@
+!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:
+
+ David Plummer (davepl) 19-Mar-94
+
+ Modifed by via awk to include global project include file
+ and to wrap precompiled header line within a conditional
+ that can be set in this include file.
+
+ Donna Liu (DonnaLi) 19-Dec-1993
+
+!ENDIF
+
+MAJORCOMP = cairole
+MINORCOMP = com
+
+#
+# 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= common
+
+#
+# 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= LIBRARY
+
+
+#
+# The following includes a global include file defined at the
+# base of the project for all components
+#
+
+!include ..\..\daytona.inc
+
+INCLUDES= ..
+
+C_DEFINES= \
+ $(C_DEFINES) \
+
+
+SOURCES= \
+ classdef.cpp \
+ comclass.cpp
+
+UMTYPE= windows
+UMAPPL=
+UMTEST=
+UMLIBS=
+
+!include .\sources.inc
diff --git a/private/oleutest/uthread/common/sources.inc b/private/oleutest/uthread/common/sources.inc
new file mode 100644
index 000000000..ef716da8c
--- /dev/null
+++ b/private/oleutest/uthread/common/sources.inc
@@ -0,0 +1,2 @@
+SYNCHRONIZE_BLOCK=1
+SYNCHRONIZE_DRAIN=1
diff --git a/private/oleutest/uthread/dirs b/private/oleutest/uthread/dirs
new file mode 100644
index 000000000..a838c8d42
--- /dev/null
+++ b/private/oleutest/uthread/dirs
@@ -0,0 +1,7 @@
+DIRS= \
+ common \
+ at \
+ bt \
+ st
+
+
diff --git a/private/oleutest/uthread/st/makefile b/private/oleutest/uthread/st/makefile
new file mode 100644
index 000000000..1d3728d41
--- /dev/null
+++ b/private/oleutest/uthread/st/makefile
@@ -0,0 +1,10 @@
+############################################################################
+#
+# Copyright (C) 1992, Microsoft Corporation.
+#
+# All rights reserved.
+#
+############################################################################
+
+!include $(NTMAKEENV)\makefile.def
+
diff --git a/private/oleutest/uthread/st/makefile.inc b/private/oleutest/uthread/st/makefile.inc
new file mode 100644
index 000000000..7b1804eae
--- /dev/null
+++ b/private/oleutest/uthread/st/makefile.inc
@@ -0,0 +1 @@
+obj\i386\olest.def: olest.src
diff --git a/private/oleutest/uthread/st/olest.cpp b/private/oleutest/uthread/st/olest.cpp
new file mode 100644
index 000000000..86918b7ce
--- /dev/null
+++ b/private/oleutest/uthread/st/olest.cpp
@@ -0,0 +1,26 @@
+//+-------------------------------------------------------------------
+//
+// File: olest.cpp
+//
+// Contents: Unique parts of apt model DLL server
+//
+// Classes:
+//
+// Functions:
+//
+// History: 03-Nov-94 Ricksa
+//
+//--------------------------------------------------------------------
+#undef _UNICODE
+#undef UNICODE
+#include <windows.h>
+#include <ole2.h>
+#include <comclass.h>
+#include <uthread.h>
+
+CLSID clsidServer;
+
+void InitDll(void)
+{
+ clsidServer = clsidSingleThreadedDll;
+}
diff --git a/private/oleutest/uthread/st/olest.src b/private/oleutest/uthread/st/olest.src
new file mode 100644
index 000000000..6c89a8805
--- /dev/null
+++ b/private/oleutest/uthread/st/olest.src
@@ -0,0 +1,47 @@
+#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 olest
+
+DESCRIPTION 'Microsoft (R) OLE 2.0 Proxy DLL 1.00'
+
+EXPORTS
+#if defined(i386)
+
+ _DllGetClassObject@12 @1
+ DllGetClassObject=_DllGetClassObject@12
+ _DllCanUnloadNow@0 @2
+ DllCanUnloadNow=_DllCanUnloadNow@0
+
+#else
+ DllGetClassObject @1
+ DllCanUnloadNow @2
+
+#endif // i386 - MIPS
+
+#endif // FLAT
diff --git a/private/oleutest/uthread/st/sources b/private/oleutest/uthread/st/sources
new file mode 100644
index 000000000..014257a06
--- /dev/null
+++ b/private/oleutest/uthread/st/sources
@@ -0,0 +1,89 @@
+!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:
+
+ David Plummer (davepl) 19-Mar-94
+
+ Modifed by via awk to include global project include file
+ and to wrap precompiled header line within a conditional
+ that can be set in this include file.
+
+ Donna Liu (DonnaLi) 19-Dec-1993
+
+!ENDIF
+
+MAJORCOMP = oleutest
+MINORCOMP = com
+
+#
+# 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= olest
+
+#
+# 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= DYNLINK
+
+DLLDEF= obj\*\olest.def
+
+DLLENTRY= _DllMainCRTStartup
+
+DLLBASE=@$(BASEDIR)\PUBLIC\SDK\LIB\coffbase.txt,usermode
+
+#
+# The following includes a global include file defined at the
+# base of the project for all components
+#
+
+!include ..\..\daytona.inc
+
+INCLUDES= ..
+
+C_DEFINES= \
+ $(C_DEFINES)
+
+
+SOURCES= \
+ olest.cpp
+
+LINKLIBS= \
+ ..\common\obj\*\common.lib \
+ $(BASEDIR)\public\sdk\lib\*\uuid.lib \
+ $(BASEDIR)\public\sdk\lib\*\ole32.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\*\crtdll.lib
+
+
+UMTYPE= windows
+UMAPPL=
+UMTEST=
diff --git a/private/oleutest/uthread/uthread.h b/private/oleutest/uthread/uthread.h
new file mode 100644
index 000000000..279fb0d94
--- /dev/null
+++ b/private/oleutest/uthread/uthread.h
@@ -0,0 +1,24 @@
+//+-------------------------------------------------------------------
+//
+// File: uthread.h
+//
+// Contents: Common constants for thread unit test
+//
+// History: 03-Nov-94 Ricksa
+//
+//--------------------------------------------------------------------
+#ifndef _UTHREAD_H_
+#define _UTHREAD_H_
+#undef UNICODE
+#undef _UNICODE
+
+extern const CLSID clsidSingleThreadedDll;
+extern const char *pszSingleThreadedDll;
+
+extern const CLSID clsidAptThreadedDll;
+extern const char *pszAptThreadedDll;
+
+extern const CLSID clsidBothThreadedDll;
+extern const char *pszBothThreadedDll;
+
+#endif // _UTHREAD_H_