ComModule.h 39 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343
  1. #ifndef __ComModule_h__
  2. #define __ComModule_h__
  3. #pragma once
  4. /////////////////////////////////////////////////////////////////////////////
  5. // ComModule.h : Declaration and implementation of the TCComModule class.
  6. //
  7. #include <TCLib.h>
  8. #include <..\TCLib\AutoHandle.h>
  9. #include "UserAcct.h"
  10. /////////////////////////////////////////////////////////////////////////////
  11. //
  12. template <class T>
  13. class ATL_NO_VTABLE TCComModule : public CComModule
  14. {
  15. // Types
  16. protected:
  17. typedef TCComModule<T> TCComModuleBase;
  18. typedef HRESULT (T::*XOptionProc)(int, TCHAR*[], int*);
  19. struct XCmdLineOption
  20. {
  21. LPCSTR m_pszOption;
  22. LPCSTR m_pszOptionDesc;
  23. XOptionProc m_pfn;
  24. int m_cMinParams;
  25. int m_cMaxParams;
  26. bool m_bContinue;
  27. bool m_bReportSuccess;
  28. bool m_bAllowForWin9x;
  29. bool m_bAllowForWinNT;
  30. };
  31. typedef const XCmdLineOption* PXCmdLineOption;
  32. // Construction / Destruction
  33. public:
  34. TCComModule();
  35. ~TCComModule();
  36. void Init(_ATL_OBJMAP_ENTRY* p, HINSTANCE h, const GUID* plibid = NULL);
  37. // Attributes
  38. public:
  39. static UINT GetShutdownEventName(LPTSTR pszEventName, UINT cch,
  40. bool bGlobalObject = true);
  41. void SetMessageHwnd(HWND hwnd);
  42. HWND GetMessageHwnd() const;
  43. // Operations
  44. public:
  45. HRESULT ParseCommandLine(LPCTSTR pszCmdLine = NULL);
  46. HRESULT ParseCommandLine(int argc, TCHAR* argv[]);
  47. HRESULT OnRegServer (int argc, TCHAR* argv[], int* pnArgs);
  48. HRESULT OnUnregServer(int argc, TCHAR* argv[], int* pnArgs);
  49. HRESULT OnNoExit (int argc, TCHAR* argv[], int* pnArgs);
  50. HRESULT OnExit (int argc, TCHAR* argv[], int* pnArgs);
  51. HRESULT OnHelp (int argc, TCHAR* argv[], int* pnArgs);
  52. HRESULT ReportError(HRESULT hr, LPCTSTR pszDesc);
  53. void ReportSuccess(LPCTSTR pszDesc);
  54. int Echo(LPCTSTR pszFmt, ...);
  55. int Echo(UINT idFmt, ...);
  56. int EchoV(LPCTSTR pszFmt, va_list argptr);
  57. void EchoFlush();
  58. void ClearOutputText();
  59. HRESULT Syntax();
  60. HRESULT RegisterClassObjects(DWORD dwFlags = REGCLS_MULTIPLEUSE,
  61. DWORD dwClsContext = CLSCTX_LOCAL_SERVER);
  62. HRESULT RevokeClassObjects();
  63. HRESULT StartMonitor();
  64. LONG Unlock();
  65. HRESULT OpenAppIDRegKey(CRegKey& key, REGSAM samDesired = KEY_ALL_ACCESS);
  66. // Overrides
  67. public:
  68. HRESULT InitializeSecurity();
  69. HRESULT RegisterSecurity();
  70. HRESULT GetAccessSecurity(PSECURITY_DESCRIPTOR* psd, DWORD* pcb);
  71. HRESULT GetLaunchSecurity(PSECURITY_DESCRIPTOR* psd, DWORD* pcb);
  72. HRESULT GetAuthenticationLevel(DWORD* pdwAuthnLevel);
  73. void DisplaySyntax();
  74. void OutputText(LPCTSTR pszText);
  75. bool UseMessageBox() {return true;}
  76. LPCTSTR GetRegInfo(UINT& idResource, bool& bRegTypeLib);
  77. UINT GetCmdLineOptionMap(const XCmdLineOption** ppMap);
  78. DWORD GetIdleShutdownTimeout() {return 5000;}
  79. DWORD GetThreadPauseTimeout () {return 1000;}
  80. _ATL_REGMAP_ENTRY* GetRegMapEntries() {return NULL;}
  81. // Implementation
  82. public:
  83. static void parse_cmdline(_TSCHAR* cmdstart, _TSCHAR** argv,
  84. _TSCHAR* args, int* numargs, int* numchars);
  85. static HANDLE CreateShutdownEvent();
  86. static BOOL WINAPI ConsoleCtrlHandler(DWORD dwCtrlType);
  87. static DWORD WINAPI MonitorThunk(void* pv);
  88. void MonitorProc();
  89. PXCmdLineOption GetCurrentCmdLineOption() const;
  90. // Data Members
  91. protected:
  92. UINT m_cchOutputText, m_cchOutputTextMax;
  93. TCCoTaskPtr<TCHAR*> m_spszOutputText;
  94. DWORD m_dwThreadID;
  95. HANDLE m_hEventShutdown;
  96. TCPtr<PXCmdLineOption> m_spfnCmdLineOption;
  97. HWND m_hwndMessage;
  98. bool m_bActivity : 1;
  99. bool m_bPermanent : 1;
  100. };
  101. /////////////////////////////////////////////////////////////////////////////
  102. // Construction / Destruction
  103. template <class T>
  104. TCComModule<T>::TCComModule() :
  105. m_cchOutputText(0),
  106. m_cchOutputTextMax(0),
  107. m_dwThreadID(0),
  108. m_hEventShutdown(NULL),
  109. m_hwndMessage(NULL),
  110. m_bActivity(false),
  111. m_bPermanent(false)
  112. {
  113. }
  114. template <class T>
  115. TCComModule<T>::~TCComModule()
  116. {
  117. EchoFlush();
  118. }
  119. template <class T>
  120. void TCComModule<T>::Init(_ATL_OBJMAP_ENTRY* p, HINSTANCE h, const GUID* plibid)
  121. {
  122. // Perform default processing
  123. CComModule::Init(p, h);
  124. // Get the current thread id
  125. m_dwThreadID = GetCurrentThreadId();
  126. // Trim the initial working set
  127. #ifndef _WINDLL
  128. if (IsWinNT())
  129. SetProcessWorkingSetSize(GetCurrentProcess(), -1, -1);
  130. #endif // !_WINDLL
  131. }
  132. /////////////////////////////////////////////////////////////////////////////
  133. // Attributes
  134. template <class T>
  135. UINT TCComModule<T>::GetShutdownEventName(LPTSTR pszEventName, UINT cch,
  136. bool bGlobalObject)
  137. {
  138. #ifdef _WINDLL
  139. assert(!"defined(_WINDLL)");
  140. return E_UNEXPECTED;
  141. #endif // _WINDLL
  142. // Get the base file name of the module and make it lowercase
  143. TCHAR szFileName[_MAX_PATH], szBaseName[_MAX_FNAME];
  144. GetModuleFileName(NULL, szFileName, sizeofArray(szFileName));
  145. _tsplitpath(szFileName, NULL, NULL, szBaseName, NULL);
  146. _tcsupr(szBaseName);
  147. // Create the event name
  148. _tcscpy(szFileName, bGlobalObject ? TEXT("Global\\") : TEXT(""));
  149. _tcscat(szFileName, szBaseName);
  150. _tcscat(szFileName, TEXT("_TCComModule"));
  151. // Copy the name to the [out] parameter
  152. if (cch && pszEventName)
  153. lstrcpyn(pszEventName, szFileName, cch);
  154. // Return the length of the event name
  155. return _tcslen(szFileName);
  156. }
  157. template <class T>
  158. inline void TCComModule<T>::SetMessageHwnd(HWND hwnd)
  159. {
  160. m_hwndMessage = hwnd;
  161. }
  162. template <class T>
  163. inline HWND TCComModule<T>::GetMessageHwnd() const
  164. {
  165. return m_hwndMessage;
  166. }
  167. /////////////////////////////////////////////////////////////////////////////
  168. // Operations
  169. template <class T>
  170. HRESULT TCComModule<T>::ParseCommandLine(LPCTSTR pszCmdLine)
  171. {
  172. ///////////////////////////////////////////////////////////////////////////
  173. // This was blatantly ripped off from stdargv.c in the VC6 CRT library and
  174. // modified for use here.
  175. //
  176. // Define some local constants
  177. const TCHAR ZT = TCHAR('\0');
  178. const TCHAR SP = TCHAR(' ');
  179. const TCHAR DQ = TCHAR('\"');
  180. // Ensure that we have a command line
  181. if (!pszCmdLine || ZT == *pszCmdLine)
  182. {
  183. #ifdef _WINDLL
  184. assert(pszCmdLine && ZT != *pszCmdLine);
  185. return E_UNEXPECTED;
  186. #else // _WINDLL
  187. pszCmdLine = GetCommandLine();
  188. #endif // _WINDLL
  189. }
  190. // Make a local copy of the command line
  191. int cb = (lstrlen(pszCmdLine) + 1) * sizeof(TCHAR);
  192. LPTSTR szCmdLine = (LPTSTR)_alloca(cb);
  193. lstrcpy(szCmdLine, pszCmdLine);
  194. // First find out how much space is needed to store args
  195. int numargs, numchars;
  196. parse_cmdline((_TSCHAR*)szCmdLine, NULL, NULL, &numargs, &numchars);
  197. // Allocate space for argv[] vector and strings
  198. cb = numargs * sizeof(LPTSTR) + numchars * sizeof(TCHAR);
  199. _TSCHAR* p = (_TSCHAR*)_alloca(cb);
  200. if (!p)
  201. return E_OUTOFMEMORY;
  202. // Store args and argv ptrs in just allocated block
  203. parse_cmdline((_TSCHAR*)szCmdLine,
  204. (_TSCHAR**)p, p + numargs * sizeof(_TSCHAR*), &numargs, &numchars);
  205. // Delegate to the other method
  206. int argc = numargs - 1;
  207. TCHAR** argv = (TCHAR**)p;
  208. return ParseCommandLine(argc, argv);
  209. }
  210. template <class T>
  211. HRESULT TCComModule<T>::ParseCommandLine(int argc, TCHAR* argv[])
  212. {
  213. assert(argc);
  214. assert(argv);
  215. // Decrement to account for the module name
  216. --argc;
  217. ++argv;
  218. // Return if no arguments were specified
  219. if (argc < 1)
  220. return S_OK;
  221. // Get a pointer to the most-derived class
  222. T* pT = static_cast<T*>(this);
  223. // Continue while we have arguments
  224. bool bProcessed = false;
  225. bool bContinue = true;
  226. while (argc > 0 && bContinue)
  227. {
  228. // Option must begin with an option character
  229. if (TEXT('-') != *argv[0] && TEXT('/') != *argv[0])
  230. return Syntax();
  231. // Get the option name
  232. LPCTSTR pszOption = argv[0] + 1;
  233. // Advance argc and argv past the option name
  234. --argc;
  235. ++argv;
  236. // Loop thru map of options and determine which was specified
  237. HRESULT hr;
  238. int nEaten;
  239. const XCmdLineOption* pEntries = NULL;
  240. UINT cEntries = pT->GetCmdLineOptionMap(&pEntries);
  241. for (UINT i = 0; i < cEntries; ++i)
  242. {
  243. if (0 == lstrcmpi(pszOption, pEntries[i].m_pszOption))
  244. {
  245. // Ignore if option not valid for current platform
  246. if (!pEntries[i].m_bAllowForWin9x && IsWin9x())
  247. continue;
  248. if (!pEntries[i].m_bAllowForWinNT && IsWinNT())
  249. continue;
  250. // Validate the specified number of option parameters
  251. if (pEntries[i].m_cMinParams >= 0)
  252. {
  253. if (argc < pEntries[i].m_cMinParams)
  254. {
  255. Echo(TEXT("Not enough parameters specified for \"%s\" option.\n"),
  256. pEntries[i].m_pszOption);
  257. return Syntax();
  258. }
  259. if (pEntries[i].m_cMaxParams >= 0 && argc > pEntries[i].m_cMaxParams)
  260. {
  261. Echo(TEXT("Too many parameters specified for \"%s\" option.\n"),
  262. pEntries[i].m_pszOption);
  263. return Syntax();
  264. }
  265. }
  266. // Process the option
  267. if (pEntries[i].m_pfn)
  268. {
  269. // Call the option handler function
  270. nEaten = 0;
  271. m_spfnCmdLineOption = pEntries + i;
  272. hr = (pT->*pEntries[i].m_pfn)(argc, argv, &nEaten);
  273. m_spfnCmdLineOption = NULL;
  274. // Report failure or success
  275. if (FAILED(hr))
  276. return ReportError(hr, pEntries[i].m_pszOptionDesc);
  277. if (pEntries[i].m_bReportSuccess && S_FALSE != hr)
  278. ReportSuccess(pEntries[i].m_pszOptionDesc);
  279. // Keep track that we successfully processed an option
  280. bProcessed = true;
  281. // Advance argc and argv past the parsed options
  282. argc -= nEaten;
  283. argv += nEaten;
  284. }
  285. bContinue = pEntries[i].m_bContinue;
  286. break;
  287. }
  288. }
  289. // Display the "invalid option" message
  290. if (i >= cEntries)
  291. {
  292. Echo(TEXT("\"%s\" is an invalid option.\n"), pszOption);
  293. return Syntax();
  294. }
  295. }
  296. // Return code based on bContinue flag
  297. return bContinue ? S_OK : S_FALSE;
  298. }
  299. template <class T>
  300. HRESULT TCComModule<T>::OnRegServer(int argc, TCHAR* argv[], int* pnArgs)
  301. {
  302. // Eat all the parameters
  303. *pnArgs = argc;
  304. // Prepare to manipulate the specified user account
  305. bool bInteractiveUser = false;
  306. TCUserAccount acct;
  307. if (IsWinNT())
  308. {
  309. bInteractiveUser = 0 == _tcsicmp(argv[0], TEXT("Interactive User"));
  310. if (!bInteractiveUser)
  311. RETURN_FAILED(acct.Init(argv[0]))
  312. else if (argc > 1)
  313. {
  314. Echo("Password not allowed for \"Interactive User\".\n");
  315. Syntax();
  316. return S_FALSE;
  317. }
  318. }
  319. // Get a pointer to the most-derived class
  320. T* pT = static_cast<T*>(this);
  321. // Get registration info from the most-derived class
  322. UINT idr = 0;
  323. bool bRegTypeLib = false;
  324. LPCTSTR pszAppID = pT->GetRegInfo(idr, bRegTypeLib);
  325. // Get registrar map entries from the most-derived class
  326. _ATL_REGMAP_ENTRY* pRegMap = pT->GetRegMapEntries();
  327. // Register our AppID
  328. if (idr)
  329. RETURN_FAILED(_Module.UpdateRegistryFromResource(idr, true, pRegMap));
  330. // Register our components
  331. #ifndef _WINDLL
  332. RETURN_FAILED(_Module.RegisterServer(bRegTypeLib));
  333. #else // !_WINDLL
  334. RETURN_FAILED(DllRegisterServer());
  335. #endif // !_WINDLL
  336. // Register security options
  337. RETURN_FAILED(pT->RegisterSecurity());
  338. // Ensure that the specified user has the "Logon as a batch job" right
  339. if (IsWinNT())
  340. {
  341. if (bInteractiveUser)
  342. {
  343. // Set the Interactive User as the "RunAs" value for the AppID
  344. RETURN_FAILED(acct.SetRunAsInteractiveUser(pszAppID));
  345. }
  346. else
  347. {
  348. // Ensure that the specified user has the "Logon as a batch job" right
  349. HRESULT hr = acct.HasRight(SE_BATCH_LOGON_NAME);
  350. if (S_OK != hr)
  351. {
  352. RETURN_FAILED(acct.SetRight(SE_BATCH_LOGON_NAME));
  353. Echo(TEXT("The account %ls\\%ls has been granted the Logon As A Batch Job right."),
  354. acct.GetDomainNameW(), acct.GetUserNameW());
  355. EchoFlush();
  356. }
  357. // Set the specified user account as the "RunAs" value for the AppID
  358. LPCTSTR pszPassword = (2 == argc) ? argv[1] : TEXT("");
  359. RETURN_FAILED(acct.SetRunAsUser(pszAppID, pszPassword));
  360. }
  361. }
  362. // Indicate success
  363. return S_OK;
  364. }
  365. template <class T>
  366. HRESULT TCComModule<T>::OnUnregServer(int argc, TCHAR* argv[], int* pnArgs)
  367. {
  368. #ifndef _WINDLL
  369. // Get a pointer to the most-derived class
  370. T* pT = static_cast<T*>(this);
  371. // Get registration info from the most-derived class
  372. UINT idr = 0;
  373. bool bRegTypeLib;
  374. pT->GetRegInfo(idr, bRegTypeLib);
  375. // Unregister the AppID
  376. if (idr)
  377. _Module.UpdateRegistryFromResource(idr, FALSE);
  378. // Unregister the components
  379. _Module.UnregisterServer(TRUE);
  380. // Indicate success
  381. return S_OK;
  382. #else // !_WINDLL
  383. // Just use the exported function
  384. return DllUnregisterServer();
  385. #endif // !_WINDLL
  386. }
  387. template <class T>
  388. HRESULT TCComModule<T>::OnNoExit(int argc, TCHAR* argv[], int* pnArgs)
  389. {
  390. m_bPermanent = true;
  391. return S_OK;
  392. }
  393. template <class T>
  394. HRESULT TCComModule<T>::OnExit(int argc, TCHAR* argv[], int* pnArgs)
  395. {
  396. // Open the shutdown event
  397. TCHandle hevt(CreateShutdownEvent());
  398. if (hevt.IsNull())
  399. return HRESULT_FROM_WIN32(GetLastError());
  400. if (GetLastError() != ERROR_ALREADY_EXISTS)
  401. {
  402. Echo("No server is currently running.");
  403. return S_FALSE;
  404. }
  405. // Signal the shutdown event
  406. SetEvent(hevt);
  407. // Display status
  408. Echo("Server has been signaled to exit.");
  409. EchoFlush();
  410. // Indicate success
  411. return S_OK;
  412. }
  413. template <class T>
  414. HRESULT TCComModule<T>::OnHelp(int argc, TCHAR* argv[], int* pnArgs)
  415. {
  416. Syntax();
  417. return S_OK;
  418. }
  419. template <class T>
  420. HRESULT TCComModule<T>::Syntax()
  421. {
  422. // Call on the most-derived class to display its syntax
  423. static_cast<T*>(this)->DisplaySyntax();
  424. return S_FALSE;
  425. }
  426. template <class T>
  427. HRESULT TCComModule<T>::ReportError(HRESULT hr, LPCTSTR pszDesc)
  428. {
  429. // Declare an array of modules in which to find the system message
  430. TCHAR* szModules[] = {TEXT("NetMsg.dll"), NULL};
  431. // Loop through each module in the array
  432. LPTSTR pszBuffer = NULL;
  433. DWORD dwLangID = MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT);
  434. DWORD dwFormatFlags = FORMAT_MESSAGE_ALLOCATE_BUFFER |
  435. FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM;
  436. for (int i = 0; i < sizeofArray(szModules); ++i)
  437. {
  438. // Attempt to load the library for messages
  439. TCHinstance shInst = (szModules[i] && *szModules[i]) ?
  440. LoadLibraryEx(szModules[i], NULL, LOAD_LIBRARY_AS_DATAFILE) : NULL;
  441. // Determine the format flags
  442. DWORD dwFlags = dwFormatFlags |
  443. (shInst.IsNull() ? 0 : FORMAT_MESSAGE_FROM_HMODULE);
  444. // Allow the system to format the message
  445. DWORD cch = FormatMessage(dwFlags, shInst.GetHandle(), hr, dwLangID,
  446. (LPTSTR)&pszBuffer, 0, NULL);
  447. if (cch)
  448. break;
  449. }
  450. // Echo the base message first
  451. static_cast<T*>(this)->Echo(TEXT("%s failed with return code 0x%08X.\n"),
  452. pszDesc, hr);
  453. if (pszBuffer)
  454. {
  455. static_cast<T*>(this)->Echo(TEXT(" %s\n"), pszBuffer);
  456. LocalFree(pszBuffer);
  457. }
  458. // Return the specified result
  459. return hr;
  460. }
  461. template <class T>
  462. void TCComModule<T>::ReportSuccess(LPCTSTR pszDesc)
  463. {
  464. if (pszDesc && TEXT('\0') != *pszDesc)
  465. static_cast<T*>(this)->Echo(TEXT("%s succeeded.\n"), pszDesc);
  466. }
  467. template <class T>
  468. inline int TCComModule<T>::Echo(LPCTSTR pszFmt, ...)
  469. {
  470. va_list argptr;
  471. va_start(argptr, pszFmt);
  472. int cch = static_cast<T*>(this)->EchoV(pszFmt, argptr);
  473. va_end(argptr);
  474. return cch;
  475. }
  476. template <class T>
  477. inline int TCComModule<T>::Echo(UINT idFmt, ...)
  478. {
  479. // Load the specified string resource
  480. TCHAR szFmt[_MAX_PATH * 4];
  481. LoadString(GetResourceInstance(), idFmt, szFmt, sizeofArray(szFmt));
  482. // Get a pointer to the variable argument list and delegate
  483. va_list argptr;
  484. va_start(argptr, idFmt);
  485. int cch = static_cast<T*>(this)->EchoV(szFmt, argptr);
  486. va_end(argptr);
  487. return cch;
  488. }
  489. template <class T>
  490. int TCComModule<T>::EchoV(LPCTSTR pszFmt, va_list argptr)
  491. {
  492. // Format the text
  493. TCHAR szText[_MAX_PATH * 6];
  494. int cch = _vsntprintf(szText, sizeofArray(szText), pszFmt, argptr);
  495. if (-1 == cch)
  496. return cch;
  497. // Ensure that the buffer is big enough to concatenate the string
  498. int cchTotal = cch + 1;
  499. int cchRemain = m_cchOutputTextMax - m_cchOutputText;
  500. if (cchRemain < cchTotal || m_spszOutputText.IsNull())
  501. {
  502. // Allocate or reallocate enough memory to concetenate the string
  503. int cchNeeded = cchTotal - cchRemain;
  504. int cBlocksNeeded = 1 + (cchNeeded / _MAX_PATH);
  505. cchNeeded = cBlocksNeeded * _MAX_PATH;
  506. m_cchOutputTextMax += cchNeeded;
  507. int cbAlloc = m_cchOutputTextMax * sizeof(TCHAR);
  508. LPTSTR pszOld = m_spszOutputText.Detach();
  509. m_spszOutputText = (LPTSTR)CoTaskMemRealloc(pszOld, cbAlloc);
  510. if (m_spszOutputText.IsNull())
  511. {
  512. m_spszOutputText = pszOld;
  513. m_cchOutputTextMax -= cchNeeded;
  514. assert(!"CoTaskMemRealloc returned NULL");
  515. return -1;
  516. }
  517. if (!m_cchOutputText)
  518. *m_spszOutputText = TEXT('\0');
  519. }
  520. // Concatenate the string to the buffer
  521. _tcscat(m_spszOutputText, szText);
  522. m_cchOutputText += cchTotal;
  523. // Return the number of characters formatted (excluding terminating NULL)
  524. return cch;
  525. }
  526. template <class T>
  527. inline void TCComModule<T>::EchoFlush()
  528. {
  529. if (!m_spszOutputText.IsNull())
  530. {
  531. static_cast<T*>(this)->OutputText(m_spszOutputText);
  532. static_cast<T*>(this)->ClearOutputText();
  533. }
  534. }
  535. template <class T>
  536. void TCComModule<T>::ClearOutputText()
  537. {
  538. // Release the text pointer
  539. m_spszOutputText = NULL;
  540. m_spszOutputText = NULL;
  541. m_cchOutputText = m_cchOutputTextMax = 0;
  542. }
  543. template <class T>
  544. HRESULT TCComModule<T>::RegisterClassObjects(DWORD dwFlags, DWORD dwClsContext)
  545. {
  546. #ifdef _WINDLL
  547. assert(!"defined(_WINDLL)");
  548. return E_UNEXPECTED;
  549. #endif // _WINDLL
  550. // Start the monitor thread
  551. _Module.StartMonitor();
  552. // Register our class (factory) objects
  553. #if (_WIN32_WINNT >= 0x0400 || defined(_WIN32_DCOM)) & defined(_ATL_FREE_THREADED)
  554. RETURN_FAILED(CComModule::RegisterClassObjects(dwClsContext,
  555. dwFlags | REGCLS_SUSPENDED));
  556. RETURN_FAILED(CoResumeClassObjects());
  557. #else
  558. RETURN_FAILED(CComModule::RegisterClassObjects(dwFlags, dwClsContext));
  559. #endif
  560. return S_OK;
  561. }
  562. template <class T>
  563. HRESULT TCComModule<T>::RevokeClassObjects()
  564. {
  565. #ifdef _WINDLL
  566. assert(!"defined(_WINDLL)");
  567. return E_UNEXPECTED;
  568. #endif // _WINDLL
  569. // Perform default processing
  570. HRESULT hr = CComModule::RevokeClassObjects();
  571. // Wait for any threads to finish
  572. Sleep(static_cast<T*>(this)->GetThreadPauseTimeout());
  573. // Indicate success
  574. return S_OK;
  575. }
  576. template <class T>
  577. HRESULT TCComModule<T>::StartMonitor()
  578. {
  579. #ifdef _WINDLL
  580. assert(!"defined(_WINDLL)");
  581. return E_UNEXPECTED;
  582. #endif // _WINDLL
  583. // Create the shutdown event
  584. m_hEventShutdown = CreateShutdownEvent();
  585. if (!m_hEventShutdown)
  586. return HRESULT_FROM_WIN32(GetLastError());
  587. // Create the monitor thread
  588. DWORD dwThreadID;
  589. HANDLE hth = CreateThread(NULL, 0, MonitorThunk, static_cast<T*>(this),
  590. 0, &dwThreadID);
  591. return hth ? S_OK : HRESULT_FROM_WIN32(GetLastError());
  592. }
  593. template <class T>
  594. LONG TCComModule<T>::Unlock()
  595. {
  596. // Perform default processing
  597. LONG l = CComModule::Unlock();
  598. // _TRACE2("TCComModule<%hs>::Unlock(): l = %d\n", TCTypeName(T), l);
  599. #ifndef _WINDLL
  600. // Shutdown the app on last unlock
  601. if (!m_bPermanent && 0 == l)
  602. {
  603. m_bActivity = true;
  604. SetEvent(m_hEventShutdown); // tell monitor that we transitioned to zero
  605. }
  606. #endif // !_WINDLL
  607. // Return the result of the default processing
  608. return l;
  609. }
  610. template <class T>
  611. HRESULT TCComModule<T>::OpenAppIDRegKey(CRegKey& key, REGSAM samDesired)
  612. {
  613. // Get the AppID string (may be a CLSID or ProgID)
  614. USES_CONVERSION;
  615. UINT idResource;
  616. bool bRegTypeLib;
  617. WCHAR szAppID[_MAX_PATH];
  618. wcscpy(szAppID, T2CW(_Module.GetRegInfo(idResource, bRegTypeLib)));
  619. // Resolve and open the registry key of the AppID string
  620. HKEY hkey = NULL;
  621. RETURN_FAILED(TCUserAccount::ResolveAppID(szAppID, &hkey, samDesired));
  622. key.Close();
  623. key.Attach(hkey);
  624. return S_OK;
  625. }
  626. /////////////////////////////////////////////////////////////////////////////
  627. // Overrides
  628. template <class T>
  629. HRESULT TCComModule<T>::InitializeSecurity()
  630. {
  631. // Default is to use the AppID registry settings
  632. return S_OK;
  633. }
  634. template <class T>
  635. HRESULT TCComModule<T>::RegisterSecurity()
  636. {
  637. // Get a pointer to the most-derived class
  638. T* pT = static_cast<T*>(this);
  639. // Get the AppID string (may be a CLSID or ProgID)
  640. USES_CONVERSION;
  641. UINT idResource;
  642. bool bRegTypeLib;
  643. WCHAR szAppID[_MAX_PATH];
  644. wcscpy(szAppID, T2CW(pT->GetRegInfo(idResource, bRegTypeLib)));
  645. // Resolve and open the registry key of the AppID string
  646. HKEY hkey = NULL;
  647. RETURN_FAILED(TCUserAccount::ResolveAppID(szAppID, &hkey));
  648. CRegKey key;
  649. key.Attach(hkey);
  650. // Allow the most-derived class to specify access permissions
  651. HRESULT hr;
  652. TCArrayPtr<BYTE*> spSD;
  653. DWORD cbSD;
  654. RETURN_FAILED(hr = pT->GetAccessSecurity((PSECURITY_DESCRIPTOR*)&spSD, &cbSD));
  655. if (!spSD.IsNull() && (S_FALSE != hr))
  656. {
  657. // Write the self-relative security descriptor to the registry value
  658. LONG lr = RegSetValueEx(key, TEXT("AccessPermission"), 0, REG_BINARY,
  659. spSD, cbSD);
  660. if (ERROR_SUCCESS != lr)
  661. return HRESULT_FROM_WIN32(lr);
  662. }
  663. // Allow the most-derived class to specify launch permissions
  664. RETURN_FAILED(hr = pT->GetLaunchSecurity((PSECURITY_DESCRIPTOR*)&spSD, &cbSD));
  665. if (!spSD.IsNull() && (S_FALSE != hr))
  666. {
  667. // Write the self-relative security descriptor to the registry value
  668. LONG lr = RegSetValueEx(key, TEXT("LaunchPermission"), 0, REG_BINARY,
  669. spSD, cbSD);
  670. if (ERROR_SUCCESS != lr)
  671. return HRESULT_FROM_WIN32(lr);
  672. }
  673. // Allow the most-derived class to specify authentication level
  674. DWORD dwAuthnLevel = 0;
  675. RETURN_FAILED(hr = pT->GetAuthenticationLevel(&dwAuthnLevel));
  676. if (RPC_C_AUTHN_LEVEL_NONE <= dwAuthnLevel &&
  677. dwAuthnLevel <= RPC_C_AUTHN_LEVEL_PKT_PRIVACY && (S_FALSE != hr))
  678. {
  679. // Write the authentication level
  680. LONG lr = key.SetValue(dwAuthnLevel, TEXT("AuthenticationLevel"));
  681. if (ERROR_SUCCESS != lr)
  682. return HRESULT_FROM_WIN32(lr);
  683. }
  684. // Indicate success
  685. return S_OK;
  686. }
  687. template <class T>
  688. HRESULT TCComModule<T>::GetAccessSecurity(PSECURITY_DESCRIPTOR* psd,
  689. DWORD* pcb)
  690. {
  691. // Initialize the [out] parameter
  692. if (pcb)
  693. *pcb = 0;
  694. // Returning S_FALSE will avoid writing the AccessPermission value
  695. if (IsWin9x())
  696. return S_FALSE;
  697. // Create a security descriptor, owned by the thread owner
  698. CSecurityDescriptor sd;
  699. sd.InitializeFromThreadToken();
  700. // Define a table of Authority/SubAuthorities to be added to the DACL
  701. static struct
  702. {
  703. SID_IDENTIFIER_AUTHORITY m_auth;
  704. DWORD m_authSub1, m_authSub2;
  705. } auths[] =
  706. {
  707. {SECURITY_NT_AUTHORITY , SECURITY_LOCAL_SYSTEM_RID },
  708. {SECURITY_NT_AUTHORITY , SECURITY_INTERACTIVE_RID },
  709. {SECURITY_NT_AUTHORITY , SECURITY_BUILTIN_DOMAIN_RID,
  710. DOMAIN_ALIAS_RID_ADMINS },
  711. {SECURITY_WORLD_SID_AUTHORITY, SECURITY_WORLD_RID },
  712. };
  713. // Compute the number of bytes taken by an ACE, in addtion to the SID
  714. const DWORD cbACE = sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD);
  715. // Compute the number of bytes needed for the DACL, in addition to the ACEs
  716. DWORD cbACL = sizeof(ACL);
  717. // Create a SID for each Authority/SubAuthorities in the table
  718. TCSid psids[sizeofArray(auths)];
  719. for (UINT i = 0; i < sizeofArray(auths); ++i)
  720. {
  721. // Create a SID for the next Authority/SubAuthorities in the table
  722. SID_IDENTIFIER_AUTHORITY auth = auths[i].m_auth;
  723. if (!AllocateAndInitializeSid(&auth, auths[i].m_authSub2 ? 2 : 1,
  724. auths[i].m_authSub1, auths[i].m_authSub2, 0, 0, 0, 0, 0, 0, &psids[i]))
  725. return HRESULT_FROM_WIN32(GetLastError());
  726. // Add the size of an ACE for this SID to the DACL size
  727. cbACL += cbACE + GetLengthSid(psids[i]);
  728. }
  729. // Free the current DACL and allocate a new one
  730. if (sd.m_pDACL)
  731. free(sd.m_pDACL);
  732. sd.m_pDACL = (ACL*)malloc(cbACL);
  733. // Initialize the DACL
  734. if (!InitializeAcl(sd.m_pDACL, cbACL, ACL_REVISION))
  735. return HRESULT_FROM_WIN32(GetLastError());
  736. // Add the SIDs to the security descriptor
  737. for (i = 0; i < sizeofArray(psids); ++i)
  738. if (!AddAccessAllowedAce(sd.m_pDACL, ACL_REVISION,
  739. COM_RIGHTS_EXECUTE, psids[i]))
  740. return HRESULT_FROM_WIN32(GetLastError());
  741. // Set the new DACL of the security descriptor
  742. if (!SetSecurityDescriptorDacl(sd.m_pSD, true, sd.m_pDACL, false))
  743. return HRESULT_FROM_WIN32(GetLastError());
  744. // Get the size of the security descriptor, represented self-relatively
  745. DWORD cbSD = 0;
  746. MakeSelfRelativeSD(sd, NULL, &cbSD);
  747. // Allocate a self-relative security descriptor (delete'd by the caller)
  748. PSECURITY_DESCRIPTOR psdTemp = new BYTE[cbSD];
  749. if (!psdTemp)
  750. return E_OUTOFMEMORY;
  751. ZeroMemory(psdTemp, cbSD);
  752. if (MakeSelfRelativeSD(sd, psdTemp, &cbSD))
  753. {
  754. *psd = psdTemp;
  755. if (pcb)
  756. *pcb = cbSD;
  757. return S_OK;
  758. }
  759. // Free the allocated self-relative security descriptor
  760. DWORD dwLastError = GetLastError();
  761. delete psdTemp;
  762. return HRESULT_FROM_WIN32(dwLastError);
  763. }
  764. template <class T>
  765. HRESULT TCComModule<T>::GetLaunchSecurity(PSECURITY_DESCRIPTOR* psd,
  766. DWORD* pcb)
  767. {
  768. // Initialize the [out] parameter
  769. if (pcb)
  770. *pcb = 0;
  771. // Returning S_FALSE will avoid writing the LaunchPermission value
  772. if (IsWin9x())
  773. return S_FALSE;
  774. // Use the access permissions of this class (not the most-derived class)
  775. return GetAccessSecurity(psd, pcb);
  776. }
  777. template <class T>
  778. HRESULT TCComModule<T>::GetAuthenticationLevel(DWORD* pdwAuthnLevel)
  779. {
  780. // Returning S_FALSE will avoid writing the AuthenticationLevel value
  781. return S_FALSE;
  782. }
  783. template <class T>
  784. UINT TCComModule<T>::GetCmdLineOptionMap(const XCmdLineOption** ppMap)
  785. {
  786. if (ppMap)
  787. *ppMap = NULL;
  788. return 0;
  789. }
  790. template <class T>
  791. void TCComModule<T>::OutputText(LPCTSTR pszText)
  792. {
  793. // Define some local constants
  794. const TCHAR ZT = TEXT('\0');
  795. const TCHAR CR = TEXT('\r');
  796. const TCHAR LF = TEXT('\n');
  797. // Do nothing if the specified string is empty
  798. if (!pszText || ZT == *pszText)
  799. return;
  800. // Output the text as-is to the debug monitor
  801. OutputDebugString(pszText);
  802. OutputDebugString(TEXT("\n"));
  803. // Write the text to StdOut, expanding LF's into CRLF's
  804. HANDLE hStdOut = ::GetStdHandle(STD_OUTPUT_HANDLE);
  805. DWORD cbWritten = sizeof(TCHAR);
  806. for (LPCTSTR psz = pszText, pszPrev = NULL; ZT != *psz; pszPrev = psz++)
  807. {
  808. if (LF == *psz && (!pszPrev || CR != *pszPrev))
  809. ::WriteFile(hStdOut, &CR, sizeof(TCHAR), &cbWritten, NULL);
  810. ::WriteFile(hStdOut, psz, sizeof(TCHAR), &cbWritten, NULL);
  811. if (sizeof(TCHAR) != cbWritten)
  812. {
  813. // Get the module name
  814. TCHAR szModule[_MAX_PATH], szFname[_MAX_FNAME], szExt[_MAX_EXT];
  815. ::GetModuleFileName(GetModuleInstance(), szModule,
  816. sizeofArray(szModule));
  817. _tsplitpath(szModule, NULL, NULL, szFname, szExt);
  818. _tmakepath(szModule, NULL, NULL, szFname, szExt);
  819. // Use MessageBox to output the specified text
  820. T* pT = static_cast<T*>(this);
  821. if (pT->UseMessageBox())
  822. {
  823. ::MessageBox(GetMessageHwnd(), pszText, szModule,
  824. MB_OK | MB_ICONINFORMATION);
  825. }
  826. return;
  827. }
  828. }
  829. // Write out a trailing CRLF for good measure
  830. ::WriteFile(hStdOut, &CR, sizeof(TCHAR), &cbWritten, NULL);
  831. ::WriteFile(hStdOut, &LF, sizeof(TCHAR), &cbWritten, NULL);
  832. // ::CloseHandle(hStdOut);
  833. }
  834. /////////////////////////////////////////////////////////////////////////////
  835. // Implementation
  836. /////////////////////////////////////////////////////////////////////////////
  837. // Description: Parses the command line and sets up the argv[] array.
  838. //
  839. // Remarks: On entry, cmdstart should point to the command line, argv should
  840. // point to memory for the argv array, args points to memory to place the
  841. // text of the arguments. If these are NULL, then no storing (only coujting)
  842. // is done.
  843. //
  844. // On exit, *numargs has the number of arguments (plus one for a final NULL
  845. // argument), and *numchars has the number of bytes used in the buffer
  846. // pointed to by args.
  847. //
  848. // Parameters:
  849. // cmdstart - pointer to command line of the form <progname><sp><args><nul>
  850. // argv - where to build argv array; NULL means don't build array
  851. // args - where to place argument text; NULL means don't store text
  852. //
  853. // Note: This was blatantly ripped off from stdargv.c in the VC6 CRT library
  854. // and modified for use here. I didn't reformat it or change variable names
  855. // so as to not introduce any new bugs.
  856. //
  857. template <class T>
  858. void TCComModule<T>::parse_cmdline(_TSCHAR* cmdstart, _TSCHAR** argv,
  859. _TSCHAR* args, int* numargs, int* numchars)
  860. {
  861. // Define some local constants
  862. const _TSCHAR NULCHAR = _T('\0');
  863. const _TSCHAR SPACECHAR = _T(' ');
  864. const _TSCHAR TABCHAR = _T('\t');
  865. const _TSCHAR DQUOTECHAR = _T('\"');
  866. const _TSCHAR SLASHCHAR = _T('\\');
  867. _TSCHAR *p;
  868. _TUCHAR c;
  869. int inquote; /* 1 = inside quotes */
  870. int copychar; /* 1 = copy char to *args */
  871. unsigned numslash; /* num of backslashes seen */
  872. *numchars = 0;
  873. *numargs = 1; /* the program name at least */
  874. /* first scan the program name, copy it, and count the bytes */
  875. p = cmdstart;
  876. if (argv)
  877. *argv++ = args;
  878. /* A quoted program name is handled here. The handling is much
  879. simpler than for other arguments. Basically, whatever lies
  880. between the leading double-quote and next one, or a terminal null
  881. character is simply accepted. Fancier handling is not required
  882. because the program name must be a legal NTFS/HPFS file name.
  883. Note that the double-quote characters are not copied, nor do they
  884. contribute to numchars. */
  885. if ( *p == DQUOTECHAR ) {
  886. /* scan from just past the first double-quote through the next
  887. double-quote, or up to a null, whichever comes first */
  888. while ( (*(++p) != DQUOTECHAR) && (*p != NULCHAR) ) {
  889. #ifdef _MBCS
  890. if (_ismbblead(*p)) {
  891. ++*numchars;
  892. if ( args )
  893. *args++ = *p++;
  894. }
  895. #endif /* _MBCS */
  896. ++*numchars;
  897. if ( args )
  898. *args++ = *p;
  899. }
  900. /* append the terminating null */
  901. ++*numchars;
  902. if ( args )
  903. *args++ = NULCHAR;
  904. /* if we stopped on a double-quote (usual case), skip over it */
  905. if ( *p == DQUOTECHAR )
  906. p++;
  907. }
  908. else {
  909. /* Not a quoted program name */
  910. do {
  911. ++*numchars;
  912. if (args)
  913. *args++ = *p;
  914. c = (_TUCHAR) *p++;
  915. #ifdef _MBCS
  916. if (_ismbblead(c)) {
  917. ++*numchars;
  918. if (args)
  919. *args++ = *p; /* copy 2nd byte too */
  920. p++; /* skip over trail byte */
  921. }
  922. #endif /* _MBCS */
  923. } while ( c != SPACECHAR && c != NULCHAR && c != TABCHAR );
  924. if ( c == NULCHAR ) {
  925. p--;
  926. } else {
  927. if (args)
  928. *(args-1) = NULCHAR;
  929. }
  930. }
  931. inquote = 0;
  932. /* loop on each argument */
  933. for(;;) {
  934. if ( *p ) {
  935. while (*p == SPACECHAR || *p == TABCHAR)
  936. ++p;
  937. }
  938. if (*p == NULCHAR)
  939. break; /* end of args */
  940. /* scan an argument */
  941. if (argv)
  942. *argv++ = args; /* store ptr to arg */
  943. ++*numargs;
  944. /* loop through scanning one argument */
  945. for (;;) {
  946. copychar = 1;
  947. /* Rules: 2N backslashes + " ==> N backslashes and begin/end quote
  948. 2N+1 backslashes + " ==> N backslashes + literal "
  949. N backslashes ==> N backslashes */
  950. numslash = 0;
  951. while (*p == SLASHCHAR) {
  952. /* count number of backslashes for use below */
  953. ++p;
  954. ++numslash;
  955. }
  956. if (*p == DQUOTECHAR) {
  957. /* if 2N backslashes before, start/end quote, otherwise
  958. copy literally */
  959. if (numslash % 2 == 0) {
  960. if (inquote) {
  961. if (p[1] == DQUOTECHAR)
  962. p++; /* Double quote inside quoted string */
  963. else /* skip first quote char and copy second */
  964. copychar = 0;
  965. } else
  966. copychar = 0; /* don't copy quote */
  967. inquote = !inquote;
  968. }
  969. numslash /= 2; /* divide numslash by two */
  970. }
  971. /* copy slashes */
  972. while (numslash--) {
  973. if (args)
  974. *args++ = SLASHCHAR;
  975. ++*numchars;
  976. }
  977. /* if at end of arg, break loop */
  978. if (*p == NULCHAR || (!inquote && (*p == SPACECHAR || *p == TABCHAR)))
  979. break;
  980. /* copy character into argument */
  981. #ifdef _MBCS
  982. if (copychar) {
  983. if (args) {
  984. if (_ismbblead(*p)) {
  985. *args++ = *p++;
  986. ++*numchars;
  987. }
  988. *args++ = *p;
  989. } else {
  990. if (_ismbblead(*p)) {
  991. ++p;
  992. ++*numchars;
  993. }
  994. }
  995. ++*numchars;
  996. }
  997. ++p;
  998. #else /* _MBCS */
  999. if (copychar) {
  1000. if (args)
  1001. *args++ = *p;
  1002. ++*numchars;
  1003. }
  1004. ++p;
  1005. #endif /* _MBCS */
  1006. }
  1007. /* null-terminate the argument */
  1008. if (args)
  1009. *args++ = NULCHAR; /* terminate string */
  1010. ++*numchars;
  1011. }
  1012. /* We put one last argument in -- a null ptr */
  1013. if (argv)
  1014. *argv++ = NULL;
  1015. ++*numargs;
  1016. }
  1017. template <class T>
  1018. HANDLE TCComModule<T>::CreateShutdownEvent()
  1019. {
  1020. #ifdef _WINDLL
  1021. assert(!"defined(_WINDLL)");
  1022. return E_UNEXPECTED;
  1023. #endif // _WINDLL
  1024. // Set security under WinNT
  1025. SECURITY_ATTRIBUTES* psa = NULL;
  1026. if (IsWinNT())
  1027. {
  1028. // Create a NULL dacl to give "everyone" access
  1029. SECURITY_DESCRIPTOR sd;
  1030. SECURITY_ATTRIBUTES sa = {sizeof(sa), &sd, false};
  1031. InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
  1032. SetSecurityDescriptorDacl(&sd, true, NULL, FALSE);
  1033. psa = &sa;
  1034. }
  1035. // Get the name of the shutdown event
  1036. TCHAR szEventName[_MAX_PATH];
  1037. GetShutdownEventName(szEventName, sizeofArray(szEventName));
  1038. // Create the shutdown event
  1039. HANDLE hevt = CreateEvent(psa, false, false, szEventName);
  1040. if (!hevt)
  1041. {
  1042. GetShutdownEventName(szEventName, sizeofArray(szEventName), false);
  1043. hevt = CreateEvent(psa, false, false, szEventName);
  1044. }
  1045. return hevt;
  1046. }
  1047. template <class T>
  1048. BOOL WINAPI TCComModule<T>::ConsoleCtrlHandler(DWORD)
  1049. {
  1050. TCHandle hevt(CreateShutdownEvent());
  1051. SetEvent(hevt);
  1052. _Module.Echo(TEXT("The server has been signaled to exit."));
  1053. _Module.EchoFlush();
  1054. return TRUE;
  1055. }
  1056. template <class T>
  1057. DWORD WINAPI TCComModule<T>::MonitorThunk(void* pv)
  1058. {
  1059. // Delegate to the non-static method
  1060. T* pT = reinterpret_cast<T*>(pv);
  1061. pT->MonitorProc();
  1062. return 0;
  1063. }
  1064. template <class T>
  1065. void TCComModule<T>::MonitorProc()
  1066. {
  1067. DWORD dwTimeOut = static_cast<T*>(this)->GetIdleShutdownTimeout();
  1068. while (true)
  1069. {
  1070. WaitForSingleObject(m_hEventShutdown, INFINITE);
  1071. DWORD dwWait=0;
  1072. do
  1073. {
  1074. m_bActivity = false;
  1075. dwWait = WaitForSingleObject(m_hEventShutdown, dwTimeOut);
  1076. } while (dwWait == WAIT_OBJECT_0);
  1077. // timed out
  1078. if (!m_bActivity && m_nLockCnt == 0) // if no activity let's really bail
  1079. {
  1080. #if (_WIN32_WINNT >= 0x0400 || defined(_WIN32_DCOM)) & defined(_ATL_FREE_THREADED)
  1081. CoSuspendClassObjects();
  1082. if (!m_bActivity && m_nLockCnt == 0)
  1083. #endif
  1084. break;
  1085. }
  1086. }
  1087. CloseHandle(m_hEventShutdown);
  1088. PostThreadMessage(m_dwThreadID, WM_QUIT, 0, 0);
  1089. }
  1090. template <class T>
  1091. inline TCComModule<T>::PXCmdLineOption TCComModule<T>::GetCurrentCmdLineOption() const
  1092. {
  1093. return m_spfnCmdLineOption;
  1094. }
  1095. /////////////////////////////////////////////////////////////////////////////
  1096. // Command Line Option Map Macros
  1097. #define BEGIN_CMDLINE_OPTION_MAP() \
  1098. static UINT GetCmdLineOptionMap(const XCmdLineOption** ppMap) \
  1099. { \
  1100. static XCmdLineOption map[] = \
  1101. {
  1102. #define CMDLINE_OPTION_ENTRY_EX(sz, szDesc, fn, cMin, cMax, cont, reportSuccess, win9x, winNT) \
  1103. {TEXT(sz), TEXT(szDesc), fn, cMin, cMax, cont, reportSuccess, win9x, winNT},
  1104. #define CMDLINE_OPTION_ENTRY(sz, szDesc, fn, cont, reportSuccess) \
  1105. CMDLINE_OPTION_ENTRY_EX(sz, szDesc, fn, -1, 0, cont, reportSuccess, \
  1106. true, true)
  1107. #define CMDLINE_OPTION_Automation() \
  1108. CMDLINE_OPTION_ENTRY("Automation", NULL, NULL, true, false) \
  1109. CMDLINE_OPTION_ENTRY("Embedding", NULL, NULL, true, false)
  1110. #define CMDLINE_OPTION_RegServer9x() \
  1111. CMDLINE_OPTION_ENTRY_EX("RegServer", "Server Registration", \
  1112. OnRegServer, 0, 0, false, true, true, false)
  1113. #define CMDLINE_OPTION_RegServerNT() \
  1114. CMDLINE_OPTION_ENTRY_EX("RegServer", "Server Registration", \
  1115. OnRegServer, 1, 2, false, true, false, true)
  1116. #define CMDLINE_OPTION_UnregServer() \
  1117. CMDLINE_OPTION_ENTRY_EX("UnregServer", "Server Unregistration", \
  1118. OnUnregServer, 0, 0, false, true, true, true)
  1119. #define CMDLINE_OPTION_NoExit() \
  1120. CMDLINE_OPTION_ENTRY_EX("NoExit", NULL, OnNoExit, 0, 0, true, false, \
  1121. true, false)
  1122. #define CMDLINE_OPTION_Exit() \
  1123. CMDLINE_OPTION_ENTRY_EX("Exit", NULL, OnExit, 0, 0, false, false, \
  1124. true, true)
  1125. #define CMDLINE_OPTION_Help() \
  1126. CMDLINE_OPTION_ENTRY_EX("?", NULL, OnHelp, 0, 0, false, false, \
  1127. true, true) \
  1128. CMDLINE_OPTION_ENTRY_EX("Help", NULL, OnHelp, 0, 0, false, false, \
  1129. true, true)
  1130. #define END_CMDLINE_OPTION_MAP() \
  1131. {NULL, NULL, NULL, false, false} \
  1132. }; \
  1133. if (ppMap) \
  1134. *ppMap = map; \
  1135. return sizeofArray(map) - 1; \
  1136. };
  1137. /////////////////////////////////////////////////////////////////////////////
  1138. #endif // !__ComModule_h__