/*++ Copyright (C) 1996-2001 Microsoft Corporation Module Name: EXEMAIN.CPP Abstract: EXE/COM Helpers History: --*/ #include "precomp.h" #include #include "commain.cpp" #include DWORD g_dwMainThreadId = 0xFFFFFFFF; class CExeClassFactory : public IClassFactory, IExternalConnection { long m_lRef; IClassFactory* m_pFactory; CUnkInternal* m_pInternalUnk; public: CExeClassFactory( CUnkInternal* pInternalUnk ) : m_pInternalUnk( pInternalUnk ), m_lRef(0), m_pFactory(0) { m_pInternalUnk->InternalAddRef(); m_pInternalUnk->InternalQueryInterface( IID_IClassFactory, (void**)&m_pFactory ); } ~CExeClassFactory() { m_pInternalUnk->InternalRelease(); } STDMETHOD(QueryInterface)( REFIID riid, void** ppv ) { HRESULT hr; if ( riid == IID_IUnknown || riid == IID_IClassFactory ) { *ppv = this; AddRef(); hr = S_OK; } else if ( riid == IID_IExternalConnection ) { *ppv = (IExternalConnection*)this; AddRef(); hr = S_OK; } else { *ppv = NULL; hr = E_NOINTERFACE; } return hr; } STDMETHOD_(ULONG, AddRef)() { return InterlockedIncrement( &m_lRef ); } STDMETHOD_(ULONG, Release)() { long lRef = InterlockedDecrement( &m_lRef ); if ( lRef == 0 ) { delete this; } return lRef; } STDMETHOD(CreateInstance)(IUnknown* pOuter, REFIID riid, void** ppv) { return m_pFactory->CreateInstance( pOuter, riid, ppv ); } STDMETHOD(LockServer)(BOOL fLock) { return m_pFactory->LockServer( fLock ); } STDMETHOD_(DWORD,AddConnection)( DWORD exconn, DWORD dwreserved ) { m_pFactory->LockServer( TRUE ); return 1; } STDMETHOD_(DWORD,ReleaseConnection)( DWORD exconn, DWORD dwreserved, BOOL fLastReleaseCloses ) { m_pFactory->LockServer( FALSE ); return 1; } }; class CExeLifeControl : public CLifeControl { protected: long m_lNumObjects; BOOL m_bUnloading; CMyCritSec m_cs; protected: virtual void Quit() { PostThreadMessage(g_dwMainThreadId, WM_QUIT, 0, 0); } public: CExeLifeControl() : m_lNumObjects(0), m_bUnloading(FALSE){} virtual BOOL ObjectCreated(IUnknown* pv) { CMyInCritSec ics(&m_cs); if(m_bUnloading) return FALSE; m_lNumObjects++; return TRUE; } virtual void ObjectDestroyed(IUnknown* pv) { EnterCriticalSection(&m_cs); long l = --m_lNumObjects; if(l == 0) { m_bUnloading = TRUE; LeaveCriticalSection(&m_cs); Quit(); } else { LeaveCriticalSection(&m_cs); } } virtual void AddRef(IUnknown* pv){} virtual void Release(IUnknown* pv){} }; BOOL ContainsSubstring( LPCTSTR szStr, LPCTSTR szSubStr ) { BOOL bContains; #ifdef UNICODE bContains = wcsstr(szStr,szSubStr) != NULL; #else bContains = strstr(szStr,szSubStr) != NULL; #endif return bContains; } void MessageLoop() { MSG msg; while(GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } } struct ServiceInfo { BOOL m_bUsed; LPTSTR m_szServiceName; LPTSTR m_szDisplayName; BOOL m_bAuto; HANDLE m_hEvent; SERVICE_STATUS_HANDLE m_hStatus; ServiceInfo() : m_bUsed(FALSE){} } g_ServiceInfo; void SetServiceInfo(LPTSTR szServiceName, LPTSTR szDisplayName, BOOL bAuto) { g_ServiceInfo.m_bUsed = TRUE; g_ServiceInfo.m_szServiceName = szServiceName; g_ServiceInfo.m_szDisplayName = szDisplayName; g_ServiceInfo.m_bAuto = bAuto; } void WINAPI ServiceHandler(DWORD dwControl) { SERVICE_STATUS Status; Status.dwServiceType = SERVICE_WIN32_OWN_PROCESS; Status.dwCurrentState = SERVICE_RUNNING; Status.dwControlsAccepted = SERVICE_ACCEPT_STOP; Status.dwWin32ExitCode = NO_ERROR; Status.dwCheckPoint = 0; Status.dwWaitHint = 0; if(!SetServiceStatus(g_ServiceInfo.m_hStatus, &Status)) { long lRes = GetLastError(); return; } switch(dwControl) { case SERVICE_CONTROL_STOP: Status.dwCurrentState = SERVICE_STOPPED; SetServiceStatus(g_ServiceInfo.m_hStatus, &Status); SetEvent(g_ServiceInfo.m_hEvent); ExitProcess(0); return; case SERVICE_CONTROL_PAUSE: case SERVICE_CONTROL_CONTINUE: case SERVICE_CONTROL_INTERROGATE: case SERVICE_CONTROL_SHUTDOWN: return; }; } void WINAPI ServiceMain(DWORD dwArgc, LPTSTR* lpszArgv) { g_ServiceInfo.m_hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); g_ServiceInfo.m_hStatus = RegisterServiceCtrlHandler( g_ServiceInfo.m_szServiceName, (LPHANDLER_FUNCTION)&ServiceHandler); if(g_ServiceInfo.m_hStatus == NULL) { long lRes = GetLastError(); return; } SERVICE_STATUS Status; Status.dwServiceType = SERVICE_WIN32_OWN_PROCESS; Status.dwCurrentState = SERVICE_START_PENDING; Status.dwControlsAccepted = SERVICE_ACCEPT_STOP; Status.dwWin32ExitCode = NO_ERROR; Status.dwCheckPoint = 0; Status.dwWaitHint = 10000; if(!SetServiceStatus(g_ServiceInfo.m_hStatus, &Status)) { long lRes = GetLastError(); return; } Status.dwCurrentState = SERVICE_RUNNING; if(!SetServiceStatus(g_ServiceInfo.m_hStatus, &Status)) { long lRes = GetLastError(); return; } MessageLoop(); } BOOL StartService() { SERVICE_TABLE_ENTRY aEntries[2]; aEntries[0].lpServiceName = g_ServiceInfo.m_szServiceName; aEntries[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)&ServiceMain; aEntries[1].lpServiceName = NULL; aEntries[1].lpServiceProc = NULL; if(!StartServiceCtrlDispatcher(aEntries)) { long lRes = GetLastError(); return FALSE; } return TRUE; } BOOL InstallService() { SC_HANDLE hManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); TCHAR szFilename[1024]; GetModuleFileName(NULL, szFilename, 1023); SC_HANDLE hService = CreateService(hManager, g_ServiceInfo.m_szServiceName, g_ServiceInfo.m_szDisplayName, SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, g_ServiceInfo.m_bAuto?SERVICE_AUTO_START : SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, szFilename, NULL, NULL, NULL, NULL, //Local System NULL // no password ); if(hService == NULL) { long lRes = GetLastError(); return FALSE; } /* // Create AppId key // ================ GUID AppId = *g_aClassInfos[0].m_pClsid; char szAppId[128]; WCHAR wszAppId[128]; char szAppIdKey[128]; StringFromGUID2(*pInfo->m_pClsid, wszAppId, 128); wcstombs(szAppId, wszAppId, 128); strcpy(szAppIdKey, "SOFTWARE\\Classes\\AppId\\"); strcat(szAppIdKey, szAppId); HKEY hKey1; RegCreateKey(HKEY_LOCAL_MACHINE, szAppIdKey, &hKey1); RegSetValueEx(hKey1, "LocalService", 0, REG_SZ, g_ServiceInfo.m_szServiceName, strlen(g_ServiceInfo.m_szServiceName)+1); */ return TRUE; } BOOL DeinstallService() { SC_HANDLE hManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); SC_HANDLE hService = OpenService(hManager, g_ServiceInfo.m_szServiceName, SERVICE_ALL_ACCESS); if(hService == NULL) { long lRes = GetLastError(); return FALSE; } if(!DeleteService(hService)) { long lRes = GetLastError(); return FALSE; } return TRUE; } CExeLifeControl g_LifeControl; CLifeControl* g_pLifeControl = &g_LifeControl; void CALLBACK MyTimerProc(HWND hWnd, UINT uMsg, UINT idEvent, DWORD dwTime) { PostQuitMessage(0); } void __cdecl main() { LPTSTR szOrigCommandLine = GetCommandLine(); size_t cchLen = lstrlen(szOrigCommandLine)+1; LPTSTR szCommandLine = new TCHAR[cchLen]; if (!szCommandLine) return; StringCchCopy( szCommandLine,cchLen,szOrigCommandLine ); TCHAR * pc = szCommandLine; while(*pc) *(pc++) = (TCHAR)wbem_towupper(*pc); GlobalInitialize(); if ( ContainsSubstring(szCommandLine, TEXT("-REGSERVER")) || ContainsSubstring(szCommandLine, TEXT("/REGSERVER")) ) { GlobalRegister(); for(LIST_ENTRY * pEntry = g_ClassInfoHead.Flink; pEntry != &g_ClassInfoHead; pEntry = pEntry->Flink) { CClassInfo* pInfo = CONTAINING_RECORD(pEntry,CClassInfo,m_Entry); HRESULT hres = RegisterServer(pInfo, TRUE); if(FAILED(hres)) return; } if(g_ServiceInfo.m_bUsed) { InstallService(); } } else if ( ContainsSubstring( szCommandLine, TEXT("-UNREGSERVER")) || ContainsSubstring( szCommandLine, TEXT("/UNREGSERVER"))) { GlobalUnregister(); for(LIST_ENTRY * pEntry = g_ClassInfoHead.Flink; pEntry != &g_ClassInfoHead; pEntry = pEntry->Flink) { CClassInfo* pInfo = CONTAINING_RECORD(pEntry,CClassInfo,m_Entry); HRESULT hres = UnregisterServer(pInfo, TRUE); if(FAILED(hres)) return; } if(g_ServiceInfo.m_bUsed) { DeinstallService(); } } else if( !ContainsSubstring(szCommandLine, TEXT("EMBEDDING")) && !g_ServiceInfo.m_bUsed ) { printf("Cannot run standalone\n"); } else { int i; if(FAILED(GlobalInitializeCom())) return; for(LIST_ENTRY * pEntry = g_ClassInfoHead.Flink; pEntry != &g_ClassInfoHead; pEntry = pEntry->Flink) { CClassInfo* pInfo = CONTAINING_RECORD(pEntry,CClassInfo,m_Entry); IClassFactory* pFactory = new CExeClassFactory( pInfo->m_pFactory); if ( pFactory == NULL ) return; HRESULT hres = CoRegisterClassObject( *pInfo->m_pClsid, pFactory, CLSCTX_SERVER, REGCLS_MULTIPLEUSE, &pInfo->m_dwCookie); if(FAILED(hres)) return; } if(g_ServiceInfo.m_bUsed) { StartService(); } else { g_dwMainThreadId = GetCurrentThreadId(); MessageLoop(); } for(LIST_ENTRY * pEntry = g_ClassInfoHead.Flink; pEntry != &g_ClassInfoHead; pEntry = pEntry->Flink) { CClassInfo* pInfo = CONTAINING_RECORD(pEntry,CClassInfo,m_Entry); HRESULT hres = CoRevokeClassObject(pInfo->m_dwCookie); if(FAILED(hres)) return; } SetTimer(NULL, 0, 1000, (TIMERPROC)MyTimerProc); MessageLoop(); GlobalUninitialize(); } } int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR lpCmdLine, int nCmdShow) { main(); return 0; }