summaryrefslogtreecommitdiffstats
path: root/private/oleutest/balls/client
diff options
context:
space:
mode:
Diffstat (limited to 'private/oleutest/balls/client')
-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
40 files changed, 10397 insertions, 0 deletions
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_