diff options
Diffstat (limited to 'private/oleutest/balls/client')
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_ |