diff options
Diffstat (limited to 'private/oleutest/balls/client/dllhost/tdllhost.cxx')
-rw-r--r-- | private/oleutest/balls/client/dllhost/tdllhost.cxx | 600 |
1 files changed, 600 insertions, 0 deletions
diff --git a/private/oleutest/balls/client/dllhost/tdllhost.cxx b/private/oleutest/balls/client/dllhost/tdllhost.cxx new file mode 100644 index 000000000..97d91e6f1 --- /dev/null +++ b/private/oleutest/balls/client/dllhost/tdllhost.cxx @@ -0,0 +1,600 @@ +//+------------------------------------------------------------------ +// +// File: tdllhost.cxx +// +// Contents: test for dll hosting +// +//-------------------------------------------------------------------- +#include <tstmain.hxx> +#include "tdllhost.h" + + +// BUGBUG: these should be in a public place somewhere. +DEFINE_OLEGUID(CLSID_Balls, 0x0000013a, 1, 8); +DEFINE_OLEGUID(CLSID_Cubes, 0x0000013b, 1, 8); +DEFINE_OLEGUID(CLSID_LoopSrv, 0x0000013c, 1, 8); + +DEFINE_OLEGUID(CLSID_QI, 0x00000140, 0, 8); +const GUID CLSID_QI = + {0x00000140,0x0000,0x0008,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}}; + +const GUID CLSID_QIHANDLER1 = + {0x00000141,0x0000,0x0008,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}}; + + +const TCHAR *pszRegValThreadModel = TEXT("ThreadingModel"); +const TCHAR *pszSingleModel = TEXT("Single"); +const TCHAR *pszApartmentModel = TEXT("Apartment"); +const TCHAR *pszMultiThreadedModel = TEXT("Free"); +const TCHAR *pszBothModel = TEXT("Both"); + +BOOL gfApt; + +// ---------------------------------------------------------------------- +// +// Structures and Function Prototypes +// +// ---------------------------------------------------------------------- +typedef struct tagLoadDLLParams +{ + DWORD dwCallingTID; // tid of calling thread + DWORD dwCoInitFlag; // flag to initialize OLE with + DWORD dwItfFlag; // flag if the resulting object should be a proxy + BOOL RetVal; // return value + HANDLE hEvent; // thread completion event +} SLoadDLLParam; + +typedef enum tagITFFLAGS +{ + ITF_REAL = 1, // expect ptr to real object + ITF_PROXY = 2 // expect ptr to proxy object +} ITFFLAGS; + + +// worker subroutines +BOOL SpinThread(DWORD dwInitFlag, DWORD dwItfFlag); +DWORD _stdcall LoadDLLOnThread(void *param); +BOOL LoadClassObject(DWORD dwItfFlag); +BOOL SetRegForDll(REFCLSID rclsid, const TCHAR *pszThreadModel); + + +// test routines - return value of TRUE return means the test passed +BOOL TestLoadSingleThreaded(void); +BOOL TestLoadApartmentThreaded(void); +BOOL TestLoadMultiThreaded(void); +BOOL TestLoadBothThreaded(void); + + +// ---------------------------------------------------------------------- +// +// TestDllHost - main test driver. read the ini file to determine +// which tests to run. +// +// ---------------------------------------------------------------------- +BOOL TestDllHost(void) +{ + BOOL RetVal = TRUE; + + gfApt = (gInitFlag == COINIT_APARTMENTTHREADED) ? TRUE : FALSE; + + // the driver did a CoInitialize, we dont want one so do CoUninit. + CoUninitialize(); + + if (GetProfileInt(TEXT("DllHost Test"),TEXT("LoadSingleThreaded"),1)) + RetVal &= TestLoadSingleThreaded(); + + if (GetProfileInt(TEXT("DllHost Test"),TEXT("LoadApartmentThreaded"),1)) + RetVal &= TestLoadApartmentThreaded(); + + if (GetProfileInt(TEXT("DllHost Test"),TEXT("LoadMultiThreaded"),1)) + RetVal &= TestLoadMultiThreaded(); + + if (GetProfileInt(TEXT("DllHost Test"),TEXT("LoadBothThreaded"),1)) + RetVal &= TestLoadBothThreaded(); + + // re-initialize so we dont get a complaint from OLE in debug builds + // about an unbalanced call to Uninitialize. + CoInitializeEx(NULL, gInitFlag); + + return RetVal; +} + + + +// ---------------------------------------------------------------------- +// +// TestLoadSingleThreaded +// +// Tests loading a single-threaded DLL +// +// ---------------------------------------------------------------------- +BOOL TestLoadSingleThreaded(void) +{ + BOOL RetVal = TRUE, RetVal2 = TRUE; + HRESULT hRes = S_OK; + + OUTPUT ("\n\nStarting TestLoadSingleThreaded\n"); + + // First, mark the DLL appropriately in the registry. + RetVal2 = SetRegForDll(CLSID_QI, pszSingleModel); + TEST_FAILED(!RetVal2, "SetRegForDLL Failed\n"); + + + hRes = CoInitializeEx(NULL, gInitFlag); + TEST_FAILED(FAILED(hRes), "CoInitializeEx Failed\n"); + +// ---------------------------------------------------------------------- + OUTPUT ("\n Load Single-Threaded DLL on Main Thread\n"); + + RetVal2 = LoadClassObject((gfApt) ? ITF_REAL : ITF_PROXY); + TEST_FAILED(!RetVal2, "SingleThreadedDLL on Main Thread Failed\n"); + + OUTPUT (" Done Load Single-Threaded DLL on Main Thread\n"); + + OUTPUT ("\n Load Single-Threaded DLL on Main Thread\n"); + + RetVal2 = LoadClassObject((gfApt) ? ITF_REAL : ITF_PROXY); + TEST_FAILED(!RetVal2, "SingleThreadedDLL on Main Thread Failed\n"); + + OUTPUT (" Done Load Single-Threaded DLL on Main Thread\n"); + +// ---------------------------------------------------------------------- + OUTPUT ("\n Load Single-Threaded DLL on Different Apartment Thread\n"); + + hRes = SpinThread(COINIT_APARTMENTTHREADED, ITF_PROXY); + TEST_FAILED(!RetVal2, "SingleThreadedDLL on Apartment Thread Failed\n"); + + OUTPUT (" Done Load Single-Threaded DLL on Different Apartment Thread\n"); + + OUTPUT ("\n Second Load Single-Threaded DLL on Different Apartment Thread\n"); + + hRes = SpinThread(COINIT_APARTMENTTHREADED, ITF_PROXY); + TEST_FAILED(!RetVal2, "Single-ThreadedDLL on Apartment Thread Failed\n"); + + OUTPUT (" Second Done Load Single-Threaded DLL on Different Apartment Thread\n"); + + +// ---------------------------------------------------------------------- + OUTPUT ("\n Load Single-Thread DLL on Multi-Threaded Apartment Thread\n"); + + hRes = SpinThread(COINIT_MULTITHREADED, ITF_PROXY); + TEST_FAILED(!RetVal2, "SingleThreadedDLL on Multi Thread Failed\n"); + + OUTPUT (" Done Load Single-Thread DLL on Multi-Threaded Apartment Thread\n"); + + OUTPUT ("\n Load Single-Thread DLL on Multi-Threaded Apartment Thread\n"); + + hRes = SpinThread(COINIT_MULTITHREADED, ITF_PROXY); + TEST_FAILED(!RetVal2, "SingleThreadedDLL on Multi Thread Failed\n"); + + OUTPUT (" Done Load Single-Thread DLL on Multi-Threaded Apartment Thread\n"); + +// ---------------------------------------------------------------------- + OUTPUT (" - Test Complete. Doing Cleanup\n"); + + CoUninitialize(); + + BOOL fResult = TestResult(RetVal, "TestLoadSingleThreaded"); + Sleep(2000); + return fResult; +} + + +// ---------------------------------------------------------------------- +// +// TestLoadApartmentThreaded +// +// Tests loading an apartment-threaded DLL +// +// ---------------------------------------------------------------------- +BOOL TestLoadApartmentThreaded(void) +{ + BOOL RetVal = TRUE, RetVal2 = FALSE; + HRESULT hRes = S_OK; + + OUTPUT ("\n\nStarting TestLoadApartmentThreaded\n"); + + // First, mark the DLL appropriately in the registry. + RetVal2 = SetRegForDll(CLSID_QI, pszApartmentModel); + TEST_FAILED(!RetVal2, "SetRegForDLL Failed\n"); + + hRes = CoInitializeEx(NULL, gInitFlag); + TEST_FAILED(FAILED(hRes), "CoInitializeEx Failed\n"); + +// ---------------------------------------------------------------------- + OUTPUT ("\n Load Apartment-Threaded DLL on Main Thread\n"); + + RetVal2 = LoadClassObject((gfApt) ? ITF_REAL : ITF_PROXY); + TEST_FAILED(!RetVal2, "Apartment-ThreadedDLL on Main Thread Failed\n"); + + OUTPUT (" Done Load Apartment-Threaded DLL on Main Thread\n"); + + OUTPUT ("\n Load Apartment-Threaded DLL on Main Thread\n"); + + RetVal2 = LoadClassObject((gfApt) ? ITF_REAL : ITF_PROXY); + TEST_FAILED(!RetVal2, "Apartment-ThreadedDLL on Main Thread Failed\n"); + + OUTPUT (" Done Load Apartment-Threaded DLL on Main Thread\n"); + +// ---------------------------------------------------------------------- + OUTPUT ("\n Load Apartment-Threaded DLL on Different Apartment Thread\n"); + + hRes = SpinThread(COINIT_APARTMENTTHREADED, ITF_REAL); + TEST_FAILED(!RetVal2, "Apartment-ThreadedDLL on Apartment Thread Failed\n"); + + OUTPUT (" Done Load Apartment-Threaded DLL on Different Apartment Thread\n"); + + OUTPUT ("\n Second Load Apartment-Threaded DLL on Different Apartment Thread\n"); + + hRes = SpinThread(COINIT_APARTMENTTHREADED, ITF_REAL); + TEST_FAILED(!RetVal2, "Apartment-ThreadedDLL on Apartment Thread Failed\n"); + + OUTPUT (" Second Done Load Apartment-Threaded DLL on Different Apartment Thread\n"); + +// ---------------------------------------------------------------------- + OUTPUT ("\n Load Apartment-Thread DLL on Multi-Threaded Apartment Thread\n"); + + hRes = SpinThread(COINIT_MULTITHREADED, ITF_PROXY); + TEST_FAILED(!RetVal2, "Apartment-ThreadedDLL on Multi Thread Failed\n"); + + OUTPUT (" Done Load Apartment-Thread DLL on Multi-Threaded Apartment Thread\n"); + + OUTPUT ("\n Load Apartment-Thread DLL on Multi-Threaded Apartment Thread\n"); + + hRes = SpinThread(COINIT_MULTITHREADED, ITF_PROXY); + TEST_FAILED(!RetVal2, "Apartment-ThreadedDLL on Multi Thread Failed\n"); + + OUTPUT (" Done Load Apartment-Thread DLL on Multi-Threaded Apartment Thread\n"); + +// ---------------------------------------------------------------------- + OUTPUT (" - Test Complete. Doing Cleanup\n"); + + CoUninitialize(); + + BOOL fResult = TestResult(RetVal, "TestLoadApartmentThreaded"); + Sleep(2000); + return fResult; +} + + +// ---------------------------------------------------------------------- +// +// TestLoadMultiThreaded +// +// Tests loading a multi-threaded DLL +// +// ---------------------------------------------------------------------- +BOOL TestLoadMultiThreaded(void) +{ + BOOL RetVal = TRUE, RetVal2 = FALSE;; + HRESULT hRes = S_OK; + + OUTPUT ("\n\nStarting TestLoadMultiThreaded\n"); + + // First, mark the DLL appropriately in the registry. + RetVal2 = SetRegForDll(CLSID_QI, pszMultiThreadedModel); + TEST_FAILED(!RetVal2, "SetRegForDLL Failed\n"); + + hRes = CoInitializeEx(NULL, gInitFlag); + TEST_FAILED(FAILED(hRes), "CoInitializeEx Failed\n"); + +// ---------------------------------------------------------------------- + OUTPUT ("\n Load Free-Threaded DLL on Main Thread\n"); + + RetVal2 = LoadClassObject((gfApt) ? ITF_PROXY : ITF_REAL); + TEST_FAILED(!RetVal2, "Free-ThreadedDLL on Main Thread Failed\n"); + + OUTPUT (" Done Load Free-Threaded DLL on Main Thread\n"); + + OUTPUT ("\n Load Free-Threaded DLL on Main Thread\n"); + + RetVal2 = LoadClassObject((gfApt) ? ITF_PROXY : ITF_REAL); + TEST_FAILED(!RetVal2, "Free-ThreadedDLL on Main Thread Failed\n"); + + OUTPUT (" Done Load Free-Threaded DLL on Main Thread\n"); + +// ---------------------------------------------------------------------- + OUTPUT ("\n Load Free-Threaded DLL on Different Apartment Thread\n"); + + hRes = SpinThread(COINIT_APARTMENTTHREADED, ITF_PROXY); + TEST_FAILED(!RetVal2, "Free-ThreadedDLL on Apartment Thread Failed\n"); + + OUTPUT (" Done Load Free-Threaded DLL on Different Apartment Thread\n"); + + OUTPUT ("\n Second Load Free-Threaded DLL on Different Apartment Thread\n"); + + hRes = SpinThread(COINIT_APARTMENTTHREADED, ITF_PROXY); + TEST_FAILED(!RetVal2, "Free-ThreadedDLL on Apartment Thread Failed\n"); + + OUTPUT (" Second Done Load Apartment-Threaded DLL on Different Apartment Thread\n"); + +// ---------------------------------------------------------------------- + OUTPUT ("\n Load Apartment-Thread DLL on Multi-Threaded Apartment Thread\n"); + + hRes = SpinThread(COINIT_MULTITHREADED, ITF_REAL); + TEST_FAILED(!RetVal2, "Free-ThreadedDLL on Multi Thread Failed\n"); + + OUTPUT (" Done Load Free-Thread DLL on Multi-Threaded Apartment Thread\n"); + + OUTPUT ("\n Load Apartment-Thread DLL on Multi-Threaded Apartment Thread\n"); + + hRes = SpinThread(COINIT_MULTITHREADED, ITF_REAL); + TEST_FAILED(!RetVal2, "Free-ThreadedDLL on Multi Thread Failed\n"); + + OUTPUT (" Done Load Free-Thread DLL on Multi-Threaded Apartment Thread\n"); + +// ---------------------------------------------------------------------- + OUTPUT (" - Test Complete. Doing Cleanup\n"); + + CoUninitialize(); + + BOOL fResult = TestResult(RetVal, "TestLoadMultiThreaded"); + Sleep(2000); + return fResult; +} + + +// ---------------------------------------------------------------------- +// +// TestLoadBothThreaded +// +// Tests loading a both-threaded DLL +// +// ---------------------------------------------------------------------- +BOOL TestLoadBothThreaded(void) +{ + BOOL RetVal = TRUE, RetVal2 = FALSE;; + HRESULT hRes = S_OK; + + OUTPUT ("\n\nStarting TestLoadBothThreaded\n"); + + // First, mark the DLL appropriately in the registry. + RetVal2 = SetRegForDll(CLSID_QI, pszBothModel); + TEST_FAILED(!RetVal2, "SetRegForDLL Failed\n"); + + hRes = CoInitializeEx(NULL, gInitFlag); + TEST_FAILED(FAILED(hRes), "CoInitializeEx Failed\n"); + +// ---------------------------------------------------------------------- + OUTPUT ("\n Load Both-Threaded DLL on Main Thread\n"); + + RetVal2 = LoadClassObject(ITF_REAL); + TEST_FAILED(!RetVal2, "Both-ThreadedDLL on Main Thread Failed\n"); + + OUTPUT (" Done Load Both-Threaded DLL on Main Thread\n"); + +// ---------------------------------------------------------------------- + OUTPUT ("\n Load Both-Threaded DLL on Different Apartment Thread\n"); + + hRes = SpinThread(COINIT_APARTMENTTHREADED, ITF_REAL); + TEST_FAILED(!RetVal2, "Free-ThreadedDLL on Apartment Thread Failed\n"); + + OUTPUT (" Done Load Free-Threaded DLL on Different Apartment Thread\n"); + + OUTPUT ("\n Second Load Free-Threaded DLL on Different Apartment Thread\n"); + + hRes = SpinThread(COINIT_APARTMENTTHREADED, ITF_REAL); + TEST_FAILED(!RetVal2, "Free-ThreadedDLL on Apartment Thread Failed\n"); + + OUTPUT (" Second Done Load Free-Threaded DLL on Different Apartment Thread\n"); + +// ---------------------------------------------------------------------- + OUTPUT ("\n Load Apartment-Thread DLL on Multi-Threaded Apartment Thread\n"); + + hRes = SpinThread(COINIT_MULTITHREADED, ITF_REAL); + TEST_FAILED(!RetVal2, "Free-ThreadedDLL on Multi Thread Failed\n"); + + OUTPUT (" Done Load Free-Thread DLL on Multi-Threaded Apartment Thread\n"); + + OUTPUT ("\n Load Apartment-Thread DLL on Multi-Threaded Apartment Thread\n"); + + hRes = SpinThread(COINIT_MULTITHREADED, ITF_REAL); + TEST_FAILED(!RetVal2, "Free-ThreadedDLL on Multi Thread Failed\n"); + + OUTPUT (" Done Load Free-Thread DLL on Multi-Threaded Apartment Thread\n"); + +// ---------------------------------------------------------------------- + OUTPUT (" - Test Complete. Doing Cleanup\n"); + + CoUninitialize(); + + BOOL fResult = TestResult(RetVal, "TestLoadBothThreaded"); + Sleep(2000); + return fResult; +} + + +// ---------------------------------------------------------------------- +// +// Function: SpinThread +// +// Synopsis: Creates a thread to do some work for us. Waits for it to +// complete. Returns the results. +// +// ---------------------------------------------------------------------- +BOOL SpinThread(DWORD dwInitFlag, DWORD dwItfFlag) +{ + BOOL RetVal = FALSE; + + // set up paramters to pass to the thread + + SLoadDLLParam LoadParam; + LoadParam.dwCallingTID = GetCurrentThreadId(); + LoadParam.dwCoInitFlag = dwInitFlag; + LoadParam.dwItfFlag = dwItfFlag; + LoadParam.RetVal = FALSE; + LoadParam.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + + // create the thread + + DWORD dwThrdId = 0; + HANDLE hThrd = CreateThread(NULL, 0, + LoadDLLOnThread, + &LoadParam, 0, &dwThrdId); + if (hThrd) + { + // enter a message loop and wait for the other thread to run + // We stay here until the thread posts a QUIT message. + + MSG msg; + while (GetMessage(&msg, NULL, 0, 0)) + { + DispatchMessage(&msg); + } + + // close the thread handle + CloseHandle(hThrd); + } + else + { + HRESULT hRes = GetLastError(); + TEST_FAILED(hRes, "CreateThread failed\n") + LoadParam.RetVal = RetVal; + } + + // wait for the other thread to complete + WaitForSingleObject(LoadParam.hEvent, 0xffffffff); + CloseHandle(LoadParam.hEvent); + + return LoadParam.RetVal; +} + +// ---------------------------------------------------------------------- +// +// Function: LoadDLLOnThread +// +// Synopsis: Initializes COM, loads the class object and creates an +// instance, releases them, Posts a message to wake up the +// calling thread, Uninitializes COM, then exits. +// +// ---------------------------------------------------------------------- +DWORD _stdcall LoadDLLOnThread(void *param) +{ + BOOL RetVal = TRUE; + HRESULT hRes = S_OK; + SLoadDLLParam *pLoadParam = (SLoadDLLParam *)param; + + OUTPUT (" - LoadDLLOnThread Entered\n"); + hRes = CoInitializeEx(NULL, pLoadParam->dwCoInitFlag); + TEST_FAILED(FAILED(hRes), "CoInitialize failed\n") + + if (SUCCEEDED(hRes)) + { + // attempt to load the class object on this thread. + pLoadParam->RetVal = LoadClassObject(pLoadParam->dwItfFlag); + CoUninitialize(); + } + + // post a message to the server thread to exit now that we are done. + PostThreadMessage(pLoadParam->dwCallingTID, WM_QUIT, 0, 0); + SetEvent(pLoadParam->hEvent); + + OUTPUT (" - LoadDLLOnThread Exit\n"); + return RetVal; +} + +// ---------------------------------------------------------------------- +// +// Function: LoadClassObject +// +// Synopsis: Loads the class object, creates an instance, releases +// them, returns the results. +// +// ---------------------------------------------------------------------- +BOOL LoadClassObject(DWORD dwItfFlag) +{ + BOOL RetVal = TRUE; + IClassFactory *pICF = NULL; + IUnknown *pIPM = NULL; + + // try to load the dll class object + HRESULT hRes = CoGetClassObject(CLSID_QI, CLSCTX_INPROC_SERVER, NULL, + IID_IClassFactory, (void **)&pICF); + + TEST_FAILED(FAILED(hRes), "CoGetClassObject failed\n"); + + if (SUCCEEDED(hRes)) + { + hRes = pICF->QueryInterface(IID_IProxyManager, (void **)&pIPM); + + if (SUCCEEDED(hRes)) + { + pIPM->Release(); + TEST_FAILED(dwItfFlag != ITF_PROXY, "Got Proxy when expected Real\n"); + } + else + { + TEST_FAILED(dwItfFlag != ITF_REAL, "Got Real when expected Proxy\n"); + } + + // CODEWORK: create an instance, then release them + + // release the class object. + OUTPUT (" - CoGetClassObject succeeded\n"); + + ULONG ulRefCnt = pICF->Release(); + TEST_FAILED(ulRefCnt != 0, "pICF RefCnt not zero\n"); + pICF = NULL; + OUTPUT (" - Released ClassObject\n"); + } + + return RetVal; +} + + + +//+------------------------------------------------------------------- +// +// Function: SetRegForDll, private +// +// Synopsis: Set registry entry for a DLL +// +// Arguments: [rclsid] - clsid for reg entry +// [pszThreadModel] - threading model can be NULL. +// +// Returns: TRUE - Registry entry set successfully. +// FALSE - Registry entry set successfully. +// +// History: 01-Nov-94 Ricksa Created +// +//-------------------------------------------------------------------- +BOOL SetRegForDll(REFCLSID rclsid, const TCHAR *pszThreadModel) +{ + BOOL fResult = FALSE; + HKEY hKeyClass = NULL; + HKEY hKeyDll = NULL; + TCHAR aszWkBuf[MAX_PATH]; // String buffer used for various purposes + + // Build clsid registry key + wsprintf(aszWkBuf, + TEXT("CLSID\\{%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}"), + rclsid.Data1, rclsid.Data2, rclsid.Data3, + rclsid.Data4[0], rclsid.Data4[1], + rclsid.Data4[2], rclsid.Data4[3], + rclsid.Data4[4], rclsid.Data4[5], + rclsid.Data4[6], rclsid.Data4[7]); + + // Create the key for the class + if (RegCreateKey(HKEY_CLASSES_ROOT, aszWkBuf, &hKeyClass) == ERROR_SUCCESS) + { + // Create the key for the DLL + if (RegCreateKey(hKeyClass, TEXT("InprocServer32"), &hKeyDll) == ERROR_SUCCESS) + { + // Set the value for the Threading Model + if (RegSetValueEx(hKeyDll, pszRegValThreadModel, 0, + REG_SZ, + (const unsigned char*) pszThreadModel, + (wcslen(pszThreadModel) + 1) * sizeof(WCHAR)) + == ERROR_SUCCESS) + { + fResult = TRUE; + } + + RegCloseKey(hKeyDll); + } + + RegCloseKey(hKeyClass); + } + + return fResult; +} |