//+------------------------------------------------------------------- // // File: srvmain.cxx // // Contents: This file contins the EXE entry points // // History: 28-Feb-96 Rickhi Created // //--------------------------------------------------------------------- #include #include extern "C" const GUID CLSID_QI; extern "C" const GUID CLSID_Balls; extern "C" const GUID CLSID_Loop; extern "C" const GUID CLSID_Cubes; int WINAPI RegisterSameThread( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow, DWORD dwThreadModel); int WINAPI RegisterDifferentThreads( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow, DWORD dwThreadModel); void RunServerThread(STHREADINFO *pThrdInfo); DWORD _stdcall ServerThread(void *param); void WakeupAllThreads(); TCHAR *pszWindow[] = { TEXT("QI Server"), TEXT("Balls Server"), TEXT("Cubes Server"), TEXT("Loops Server")}; STHREADINFO *gpThrdInfo = NULL; ULONG gcThrds = 0; BOOL gfWokenUpAllThreads = FALSE; //+------------------------------------------------------------------- // // Function: MakeClassInfo // // Synopsis: fills in a SCLASSINFO structure // // History: 28-Feb-96 Rickhi Created // //-------------------------------------------------------------------- HRESULT MakeClassInfo(REFCLSID rclsid, SCLASSINFO *pClsInfo) { pClsInfo->clsid = rclsid; pClsInfo->pCF = (IClassFactory *) new CMixedClassFactory(rclsid); pClsInfo->dwCtx = CLSCTX_LOCAL_SERVER; pClsInfo->dwClsReg = REGCLS_MULTIPLEUSE | REGCLS_SUSPENDED; pClsInfo->dwReg = 0; return (pClsInfo->pCF != NULL) ? S_OK : E_OUTOFMEMORY; } //+------------------------------------------------------------------- // // Function: WinMain // // Synopsis: Entry point. Creates the classinfo and enters the main // server loop. // // History: 28-Feb-96 Rickhi Created // //-------------------------------------------------------------------- int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { if (lpCmdLine == NULL) { // ShowHelp(); return -1; } if (!(strncmp(lpCmdLine, "ApartmentSameThread", 19))) { return RegisterSameThread(hInstance, hPrevInstance, lpCmdLine, nCmdShow, SRVF_THREADMODEL_APARTMENT); } else if (!(strncmp(lpCmdLine, "FreeSameThread", 14))) { return RegisterSameThread(hInstance, hPrevInstance, lpCmdLine, nCmdShow, SRVF_THREADMODEL_MULTI); } else if (!(strncmp(lpCmdLine, "ApartmentDifferentThread", 24))) { return RegisterDifferentThreads(hInstance, hPrevInstance, lpCmdLine, nCmdShow, SRVF_THREADMODEL_APARTMENT); } else if (!(strncmp(lpCmdLine, "FreeDifferentThread", 24))) { return RegisterDifferentThreads(hInstance, hPrevInstance, lpCmdLine, nCmdShow, SRVF_THREADMODEL_MULTI); } return -1; } //+------------------------------------------------------------------- // // Function: RegisterSameThread // // Synopsis: Entry point. Creates the classinfo and enters the main // server loop. // // History: 28-Feb-96 Rickhi Created // //-------------------------------------------------------------------- int WINAPI RegisterSameThread( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow, DWORD dwThreadModel) { SCLASSINFO ClsInfo[4]; STHREADINFO ThrdInfo; HRESULT hr[4]; hr[0] = MakeClassInfo(CLSID_QI, &ClsInfo[0]); hr[1] = MakeClassInfo(CLSID_Balls, &ClsInfo[1]); hr[2] = MakeClassInfo(CLSID_Cubes, &ClsInfo[2]); hr[3] = MakeClassInfo(CLSID_Loop, &ClsInfo[3]); ThrdInfo.hEventRun = CreateEvent(NULL, FALSE, FALSE, NULL); ThrdInfo.hEventDone = CreateEvent(NULL, FALSE, FALSE, NULL); ThrdInfo.hInstance = hInstance; ThrdInfo.pszWindow = pszWindow[0]; ThrdInfo.dwFlags = dwThreadModel; ThrdInfo.cClasses = 4; ThrdInfo.pClsInfo = &ClsInfo[0]; // this thread is the one that should call resume. ThrdInfo.dwFlags |= SRVF_REGISTER_RESUME; ThrdInfo.dwTid = GetCurrentThreadId(); // stuff the thrd pointers and count into globals so we can // wake the threads up whenever 1 single thread exits. gpThrdInfo = &ThrdInfo; gcThrds = 1; hr[0] = SrvMain2(&ThrdInfo); return hr[0]; } //+------------------------------------------------------------------- // // Function: RegisterDifferentThreads // // Synopsis: Entry point. Creates the classinfo and enters the main // server loop. // // History: 28-Feb-96 Rickhi Created // //-------------------------------------------------------------------- int WINAPI RegisterDifferentThreads( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow, DWORD dwThreadModel) { SCLASSINFO ClsInfo[4]; STHREADINFO ThrdInfo[4]; HRESULT hr[4]; hr[0] = MakeClassInfo(CLSID_QI, &ClsInfo[0]); hr[1] = MakeClassInfo(CLSID_Balls, &ClsInfo[1]); hr[2] = MakeClassInfo(CLSID_Cubes, &ClsInfo[2]); hr[3] = MakeClassInfo(CLSID_Loop, &ClsInfo[3]); for (int i=0; i<4; i++) { if (SUCCEEDED(hr[i])) { ThrdInfo[i].hEventRun = CreateEvent(NULL, FALSE, FALSE, NULL); ThrdInfo[i].hEventDone = CreateEvent(NULL, FALSE, FALSE, NULL); ThrdInfo[i].hInstance = hInstance; ThrdInfo[i].pszWindow = pszWindow[i]; ThrdInfo[i].dwFlags = dwThreadModel; ThrdInfo[i].cClasses = 1; ThrdInfo[i].pClsInfo = &ClsInfo[i]; if (i > 0) { // run the thread and wait for it signal it's ready RunServerThread(&ThrdInfo[i]); WaitForSingleObject(ThrdInfo[i].hEventRun, 0xffffffff); CloseHandle(ThrdInfo[i].hEventRun); } } } // this thread is the one that should call resume. ThrdInfo[0].dwFlags |= SRVF_REGISTER_RESUME; ThrdInfo[0].dwTid = GetCurrentThreadId(); // stuff the thrd pointers and count into globals so we can // wake the threads up whenever 1 single thread exits. gpThrdInfo = &ThrdInfo[0]; gcThrds = 4; hr[0] = SrvMain2(&ThrdInfo[0]); WakeupAllThreads(); for (i=0; i<4; i++) { if (SUCCEEDED(hr[i])) { // wait for other thread to complete before exiting. WaitForSingleObject(ThrdInfo[i].hEventDone, 0xffffffff); CloseHandle(ThrdInfo[i].hEventDone); } } return hr[0]; } //+------------------------------------------------------------------- // // Function: WakeupAllThreads // // Synopsis: Wakes up all the other threads in the process when // one thread decides to exit. // // History: 28-Feb-96 Rickhi Created // //-------------------------------------------------------------------- void WakeupAllThreads() { if (gfWokenUpAllThreads) return; gfWokenUpAllThreads = TRUE; STHREADINFO *pThrdInfo = gpThrdInfo; for (ULONG i=0; idwTid, WM_QUIT, 0, 0); } } //+------------------------------------------------------------------- // // Function: ServerThread // // Synopsis: Thread Entry point. Registers a class and waits for calls // on it. // // History: 28-Feb-96 Rickhi Created // //-------------------------------------------------------------------- DWORD _stdcall ServerThread(void *param) { STHREADINFO *pThrdInfo = (STHREADINFO *)param; HRESULT hr = SrvMain2(pThrdInfo); // wake up the other threads. WakeupAllThreads(); return hr; } //+------------------------------------------------------------------- // // Function: RunServerThread // // Synopsis: Spins up a thread to act as a class server. // // History: 28-Feb-96 Rickhi Created // //-------------------------------------------------------------------- void RunServerThread(STHREADINFO *pThrdInfo) { HANDLE hThrd = CreateThread(NULL, 0, ServerThread, pThrdInfo, 0, &(pThrdInfo->dwTid)); if (hThrd) { CloseHandle(hThrd); } return; }