// tmarsh.cxx : various tests related to marshalling... // #include #include #include #include "tmarshal.h" #include "tunk.h" #include #include #include #include // CStreamOnFile #include // 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; iQueryInterface(*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; iQueryInterface(*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; ipIID = 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; ipItf == 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; ipIID = 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; ipItf != 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; ipIID = iidMisc[i]; pMQIRes->pItf = NULL; } for (i=0; ipIID = iidSupported[i]; pMQIRes->pItf = NULL; } for (i=0; ipIID = 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; ipItf == 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; ipItf == 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; ipItf != 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; iQueryInterface(*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; iQueryInterface(*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; jRelease(); 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"); }