Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

557 lines
15 KiB

  1. // This file was originally stubexe.cpp (written by a-jsari), and was copied
  2. // to create stubmsd.cpp to generate an identical stub program for winmsd.
  3. //
  4. // Copyright (c) 1998-1999 Microsoft Corporation
  5. #include <afx.h>
  6. #include <afxwin.h>
  7. #include <io.h>
  8. #include <process.h>
  9. #include <errno.h>
  10. #include <iostream.h>
  11. #include "StdAfx.h"
  12. #include "Resource.h"
  13. #include "stubmsd.h"
  14. #ifndef HRESULT
  15. typedef long HRESULT;
  16. #endif
  17. // For Windows 95, the maximum length of a command line is 1024 characters.
  18. // Not sure what it is for NT.
  19. const int MAX_COMMAND_LINE = 1024;
  20. LPCTSTR cszDefaultDirectory = _T("\\Microsoft Shared\\MSInfo\\");
  21. LPCTSTR cszRegistryRoot = _T("Software\\Microsoft\\Shared Tools\\MSInfo");
  22. LPCTSTR cszDirectoryKey = _T("Path");
  23. LPCTSTR cszWindowsRoot = _T("Software\\Microsoft\\Windows\\CurrentVersion");
  24. LPCTSTR cszCommonFilesKey = _T("CommonFilesDir");
  25. CException *g_pException = NULL;
  26. // Microsoft Management Console is the program that hosts MSInfo.
  27. // This is a definition so that we can take its size.
  28. #define cszProgram _T("mmc.exe")
  29. /*
  30. * ThrowErrorException -
  31. *
  32. * History: a-jsari 10/14/97 Initial version.
  33. */
  34. inline void ThrowErrorException()
  35. {
  36. ::g_pException = new CException;
  37. if (::g_pException == NULL) ::AfxThrowMemoryException();
  38. throw ::g_pException;
  39. }
  40. /*
  41. * CSystemExecutable - The class that implements finding and running an
  42. * executable.
  43. *
  44. * History: a-jsari 10/14/97 Initial version.
  45. */
  46. class CSystemExecutable {
  47. public:
  48. CSystemExecutable(LPTSTR szProgram);
  49. ~CSystemExecutable() { DeleteStrings(); }
  50. void Run();
  51. void Find();
  52. void ProcessCommandLine();
  53. // Helper methods.
  54. protected:
  55. void DeleteStrings();
  56. void FindFileOnSystem(CString &szFileName, CString &szDestination);
  57. // Instance variables.
  58. protected:
  59. CString *m_pszPath;
  60. CString *m_pszProgramName;
  61. CString *m_pszCommandLine;
  62. };
  63. /*
  64. * CMSInfoExecutable - MSInfo-specific functions.
  65. *
  66. * History: a-jsari 10/15/97 Initial version
  67. */
  68. class CMSInfoExecutable : public CSystemExecutable {
  69. public:
  70. CMSInfoExecutable(LPTSTR szProgram);
  71. ~CMSInfoExecutable() {}
  72. BOOL ProcessCommandLine();
  73. private:
  74. void DisplayHelp();
  75. void DeleteStrings();
  76. void FindSavedConsole();
  77. void FindMSInfoEXE();
  78. // Instance variables
  79. private:
  80. static const LPCTSTR cszSavedConsole;
  81. static const LPCTSTR cszMSInfo32;
  82. CString *m_pszSavedConsole;
  83. };
  84. const LPCTSTR CMSInfoExecutable::cszSavedConsole = _T("MSInfo32.msc");
  85. const LPCTSTR CMSInfoExecutable::cszMSInfo32 = _T("msinfo32.exe");
  86. /*
  87. * CExecutable - Constructor which determines the type of the executable to
  88. * be executed.
  89. *
  90. * History: a-jsari 10/14/97 Initial version.
  91. */
  92. CSystemExecutable::CSystemExecutable(LPTSTR szProgram)
  93. :m_pszProgramName(new CString), m_pszPath(new CString), m_pszCommandLine(new CString)
  94. {
  95. if (!(m_pszProgramName && m_pszPath && m_pszCommandLine)) AfxThrowMemoryException();
  96. *m_pszProgramName = szProgram;
  97. }
  98. /*
  99. * DeleteStrings - Delete all of the strings used by the object. Used to free
  100. * our memory before calling exec.
  101. *
  102. * History: a-jsari 10/15/97 Initial version
  103. */
  104. void CSystemExecutable::DeleteStrings()
  105. {
  106. delete m_pszPath;
  107. m_pszPath = NULL;
  108. delete m_pszProgramName;
  109. m_pszProgramName = NULL;
  110. delete m_pszCommandLine;
  111. m_pszCommandLine = NULL;
  112. }
  113. /*
  114. * FindFileOnSystem - We may eventually put code here to test multiple
  115. * found copies and use the right one. But probably not.
  116. *
  117. * History: a-jsari 10/15/97 Stub version
  118. */
  119. void CSystemExecutable::FindFileOnSystem(CString &szFileName,
  120. CString &szDestination)
  121. {
  122. // Not reached.
  123. CFileFind FileFinder;
  124. BOOL bFindResult;
  125. bFindResult = FileFinder.FindFile(szFileName);
  126. if (!bFindResult) ThrowErrorException();
  127. szDestination = FileFinder.GetFilePath();
  128. #if 0
  129. // Choose among all versions of the file?
  130. while (bFindResult) {
  131. FileFinder.FindNextFile();
  132. }
  133. #endif
  134. }
  135. /*
  136. * Find - Return a pointer to a string containing the full path
  137. * to the MMC executable.
  138. *
  139. * History: a-jsari 10/13/97 Initial version
  140. */
  141. void CSystemExecutable::Find()
  142. {
  143. // We no longer call mmc, we instead call msinfo32.exe so that
  144. // winmsd appears to support all the same command line options
  145. // whatever they may be.
  146. #ifdef BUILD_MMC_COMMAND_LINE
  147. UINT uReturnSize;
  148. TCHAR szSystemDirectory[MAX_PATH + 1];
  149. uReturnSize = GetSystemDirectory(szSystemDirectory, MAX_PATH);
  150. if (uReturnSize == 0) ThrowErrorException();
  151. if (uReturnSize > MAX_PATH) {
  152. // Our buffer isn't big enough. This code will never get called.
  153. AfxThrowResourceException();
  154. }
  155. *m_pszPath += szSystemDirectory;
  156. *m_pszPath += _T("\\") + *m_pszProgramName;
  157. if (_taccess(*m_pszPath, A_READ) < 0) {
  158. // These may eventually want to be distinct exceptions.
  159. if (errno == ENOENT) {
  160. ThrowErrorException();
  161. } else {
  162. ASSERT(errno == EACCES);
  163. ThrowErrorException();
  164. }
  165. }
  166. #endif
  167. }
  168. /*
  169. * Run - Call exec with the parameters we so meticulously collected.
  170. *
  171. * History: a-jsari 10/15/97 Initial version.
  172. */
  173. void CSystemExecutable::Run()
  174. {
  175. #if !defined(UNICODE)
  176. TCHAR szPath[MAX_PATH + 1];
  177. TCHAR szProgramName[MAX_PATH + 1];
  178. TCHAR szCommandLine[MAX_COMMAND_LINE + 1];
  179. _tcscpy(szPath, (LPCTSTR)*m_pszPath);
  180. _tcscpy(szProgramName, (LPCTSTR)*m_pszProgramName);
  181. _tcscpy(szCommandLine, (LPCTSTR)*m_pszCommandLine);
  182. DeleteStrings();
  183. ::_execlp(szPath, szProgramName, szCommandLine, 0);
  184. ThrowErrorException();
  185. #else
  186. char szPath[MAX_PATH + 1];
  187. char szProgramName[MAX_PATH + 1];
  188. char szCommandLine[MAX_COMMAND_LINE + 1];
  189. wcstombs(szPath, (LPCTSTR) *m_pszPath, MAX_PATH);
  190. wcstombs(szProgramName, (LPCTSTR) *m_pszProgramName, MAX_PATH);
  191. wcstombs(szCommandLine, (LPCTSTR) *m_pszCommandLine, MAX_COMMAND_LINE);
  192. DeleteStrings();
  193. ::_execlp(szPath, szProgramName, szCommandLine, 0);
  194. ThrowErrorException();
  195. #endif
  196. }
  197. /*
  198. * ProcessCommandLine - Pass all command line parameters to the called
  199. * executable.
  200. *
  201. * History: a-jsari 10/14/97 Initial version
  202. */
  203. void CSystemExecutable::ProcessCommandLine()
  204. {
  205. *m_pszCommandLine = GetCommandLine();
  206. // Skip over the first element in the line, which is the path to
  207. // the current executable. Preserve everything else.
  208. const int FIND_NO_MATCH = -1;
  209. int wIndex;
  210. m_pszCommandLine->TrimLeft();
  211. wIndex = m_pszCommandLine->FindOneOf(_T("\" \t\n"));
  212. if ((*m_pszCommandLine)[wIndex] == '"') {
  213. // This is the primary, if not guaranteed method.
  214. *m_pszCommandLine = m_pszCommandLine->Right(m_pszCommandLine->GetLength() - (wIndex + 1));
  215. wIndex = m_pszCommandLine->Find('"');
  216. *m_pszCommandLine = m_pszCommandLine->Right(m_pszCommandLine->GetLength() - (wIndex + 1));
  217. } else if (wIndex == FIND_NO_MATCH) {
  218. *m_pszCommandLine = _T("");
  219. } else {
  220. *m_pszCommandLine = m_pszCommandLine->Right(m_pszCommandLine->GetLength() - (wIndex + 1));
  221. }
  222. }
  223. /*
  224. * CMSInfoExecutable - Just pass all parameters to the base constructor.
  225. *
  226. * History: a-jsari 10/15/97 Initial version
  227. */
  228. CMSInfoExecutable::CMSInfoExecutable(LPTSTR szProgram)
  229. :CSystemExecutable(szProgram), m_pszSavedConsole(new CString)
  230. {
  231. if (m_pszSavedConsole == NULL) AfxThrowMemoryException();
  232. }
  233. /*
  234. * ProcessCommandLine - Process the command line parameters we can handle; pass on
  235. * the ones we can't, adding the saved console file.
  236. *
  237. * History: a-jsari 10/15/97 Initial version
  238. */
  239. BOOL CMSInfoExecutable::ProcessCommandLine()
  240. {
  241. // If the user specifies the "/?" switch on the winmsd.exe command line,
  242. // we need to inform the user that msinfo32.exe is the preferred way to
  243. // view the information now.
  244. CString strCommandLine = GetCommandLine();
  245. if (strCommandLine.Find(_T("/?")) != -1 && IDNO == ::AfxMessageBox(IDS_MSDNOTE, MB_YESNO))
  246. return FALSE;
  247. // builds m_pszCommandLine
  248. CSystemExecutable::ProcessCommandLine();
  249. // We no longer call mmc, we instead call msinfo32.exe so that
  250. // winmsd appears to support all the same command line options
  251. // whatever they may be.
  252. #ifdef BUILD_MMC_COMMAND_LINE
  253. FindSavedConsole();
  254. CString szNewCommandLine;
  255. int iLine = 0;
  256. while (m_pszCommandLine->GetLength() > 0) {
  257. *m_pszCommandLine = m_pszCommandLine->Mid(iLine);
  258. iLine = m_pszCommandLine->FindOneOf(_T(" \t")) + 1;
  259. if (iLine == 0)
  260. iLine = m_pszCommandLine->GetLength();
  261. TCHAR tcFirst = *m_pszCommandLine[0];
  262. // It's a command line switch.
  263. if (tcFirst == (TCHAR)'/' || tcFirst == (TCHAR)'-') {
  264. LPCTSTR pString = *m_pszCommandLine;
  265. ++pString;
  266. if (::_tcsicmp(pString, _T("?")) == 0) {
  267. DisplayHelp();
  268. continue;
  269. } else if (::_tcsicmp(pString, _T("report")) == 0) {
  270. ASSERT(FALSE);
  271. continue;
  272. } else if (::_tcsicmp(pString, _T("s")) == 0) {
  273. ASSERT(FALSE);
  274. continue;
  275. } else if (::_tcsicmp(pString, _T("nfo")) == 0) {
  276. ASSERT(FALSE);
  277. continue;
  278. }
  279. }
  280. // If we don't match one of our internal switches, pass it on.
  281. szNewCommandLine += m_pszCommandLine->Left(iLine);
  282. }
  283. *m_pszCommandLine = _T("/s \"") + *m_pszSavedConsole + _T("\" ") + szNewCommandLine;
  284. delete m_pszSavedConsole;
  285. m_pszSavedConsole = NULL;
  286. #else
  287. FindMSInfoEXE();
  288. #endif
  289. return TRUE;
  290. }
  291. //-----------------------------------------------------------------------------
  292. // Locate the msinfo32.exe file. We'll look in the following places:
  293. //
  294. // 1. In the current directory.
  295. // 2. In the directory in the registry under:
  296. // HKLM\Software\Microsoft\Shared Tools\MSInfo\Path
  297. // 3a. In the directory %CommonFilesDir%\Microsoft Shared\MSInfo, where
  298. // %CommonFilesDir% is found in
  299. // HKLM\Software\Microsoft\Windows\CurrentVersion\CommonFilesDir.
  300. // 3b. Use the %CommonFilesDir% value with a subpath loaded from a
  301. // string resource.
  302. // 4. Last ditch is to look in a directory stored as a string resource
  303. // for this file.
  304. //-----------------------------------------------------------------------------
  305. void CMSInfoExecutable::FindMSInfoEXE()
  306. {
  307. m_pszPath->Empty();
  308. // First, check the current directory.
  309. if (::_taccess(_T("msinfo32.exe"), A_READ) == 0)
  310. {
  311. *m_pszPath = _T("msinfo32.exe");
  312. return;
  313. }
  314. // Second, use the path key in the MSInfo registry key.
  315. HKEY hkey;
  316. if (ERROR_SUCCESS == ::RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("Software\\Microsoft\\Shared Tools\\MSInfo"), 0, KEY_READ, &hkey))
  317. {
  318. DWORD dwType;
  319. TCHAR szDirectory[MAX_PATH + 1];
  320. DWORD dwKeyLength = MAX_PATH * sizeof(TCHAR);
  321. if (ERROR_SUCCESS == ::RegQueryValueEx(hkey, _T("path"), 0, &dwType, (BYTE *) szDirectory, &dwKeyLength))
  322. if (::_taccess(szDirectory, A_READ) == 0)
  323. {
  324. *m_pszPath = szDirectory;
  325. RegCloseKey(hkey);
  326. return;
  327. }
  328. RegCloseKey(hkey);
  329. }
  330. // Third, look for it in the %CommonFilesDir% directory. Look both in the hardcoded
  331. // subdirectory, and in a subdirectory loaded from a string resource.
  332. if (ERROR_SUCCESS == ::RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("Software\\Microsoft\\Windows\\CurrentVersion"), 0, KEY_READ, &hkey))
  333. {
  334. DWORD dwKeyLength = MAX_PATH;
  335. DWORD dwType;
  336. TCHAR szDirectory[MAX_PATH + 1];
  337. if (ERROR_SUCCESS == ::RegQueryValueEx(hkey, _T("CommonFilesDir"), 0, &dwType, (BYTE *) szDirectory, &dwKeyLength))
  338. {
  339. CString strTestPath(szDirectory);
  340. strTestPath += _T("\\Microsoft Shared\\MSInfo\\msinfo32.exe");
  341. if (::_taccess(strTestPath, A_READ) == 0)
  342. {
  343. *m_pszPath = strTestPath;
  344. RegCloseKey(hkey);
  345. return;
  346. }
  347. if (strTestPath.LoadString(IDS_COMMONFILES_SUBPATH))
  348. {
  349. strTestPath = CString(szDirectory) + strTestPath;
  350. if (::_taccess(strTestPath, A_READ) == 0)
  351. {
  352. *m_pszPath = strTestPath;
  353. RegCloseKey(hkey);
  354. return;
  355. }
  356. }
  357. }
  358. RegCloseKey(hkey);
  359. }
  360. // Finally, look for it using the string resource.
  361. CString strTestPath;
  362. if (strTestPath.LoadString(IDS_MSINFO_PATH))
  363. {
  364. TCHAR szExpandedPath[MAX_PATH];
  365. if (::ExpandEnvironmentStrings(strTestPath, szExpandedPath, MAX_PATH))
  366. if (::_taccess(szExpandedPath, A_READ) == 0)
  367. {
  368. *m_pszPath = szExpandedPath;
  369. return;
  370. }
  371. }
  372. CString szNoMSCFile;
  373. szNoMSCFile.LoadString(IDS_NOMSCFILE);
  374. ::AfxMessageBox(szNoMSCFile);
  375. ::ThrowErrorException();
  376. }
  377. /*
  378. * FindSavedConsole - Finds SysInfo.msc using the registry, or the
  379. * default directory.
  380. *
  381. * History: a-jsari 10/13/97 Initial version
  382. */
  383. void CMSInfoExecutable::FindSavedConsole()
  384. {
  385. HKEY keyMSInfoRoot;
  386. long lResult;
  387. DWORD dwKeyLength = MAX_PATH;
  388. DWORD dwType;
  389. TCHAR szDirectory[MAX_PATH + 1];
  390. *m_pszSavedConsole = _T("");
  391. do {
  392. // Check the current directory.
  393. if (::_taccess(cszSavedConsole, A_READ) == 0) {
  394. *m_pszSavedConsole = cszSavedConsole;
  395. return;
  396. }
  397. // Check the MSInfo Path key.
  398. lResult = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE, cszRegistryRoot, 0, KEY_READ,
  399. &keyMSInfoRoot);
  400. if (lResult == ERROR_SUCCESS) {
  401. lResult = ::RegQueryValueEx(keyMSInfoRoot, cszDirectoryKey, 0, &dwType,
  402. reinterpret_cast<BYTE *>(szDirectory), &dwKeyLength);
  403. if (lResult == ERROR_SUCCESS) {
  404. LPTSTR pszPath = ::_tcsrchr(szDirectory, (TCHAR)'\\');
  405. if (pszPath) *pszPath = 0;
  406. *m_pszSavedConsole = szDirectory;
  407. *m_pszSavedConsole += _T("\\");
  408. *m_pszSavedConsole += cszSavedConsole;
  409. if (::_taccess(*m_pszSavedConsole, A_READ) == 0)
  410. return;
  411. }
  412. }
  413. // Use the hard-coded path %CommonFilesDir%\MSInfo
  414. lResult = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE, cszWindowsRoot, 0, KEY_READ, &keyMSInfoRoot);
  415. ASSERT(lResult == ERROR_SUCCESS);
  416. if (lResult != ERROR_SUCCESS) break;
  417. dwKeyLength = sizeof( szDirectory);
  418. lResult = ::RegQueryValueEx(keyMSInfoRoot, cszCommonFilesKey, 0, &dwType,
  419. reinterpret_cast<BYTE *>(szDirectory), &dwKeyLength);
  420. ASSERT(lResult == ERROR_SUCCESS);
  421. if (lResult != ERROR_SUCCESS) break;
  422. *m_pszSavedConsole = szDirectory;
  423. *m_pszSavedConsole += cszDefaultDirectory;
  424. *m_pszSavedConsole += cszSavedConsole;
  425. if (::_taccess(*m_pszSavedConsole, A_READ) == 0)
  426. return;
  427. } while (0);
  428. // AFX_MANAGE_STATE(::AfxGetStaticModuleState());
  429. CString szNoMSCFile;
  430. szNoMSCFile.LoadString(IDS_NOMSCFILE);
  431. ::AfxMessageBox(szNoMSCFile);
  432. ::ThrowErrorException();
  433. }
  434. void CMSInfoExecutable::DisplayHelp()
  435. {
  436. cerr << _T("/? - display this help") << endl;
  437. cerr << _T("/report <filename, computername, categoryname, ...>") << endl;
  438. cerr << _T("/s <filename> - outputs the nfo file to the specified file") << endl;
  439. cerr << _T("/nfo <filesname>, <computername> - connect to the specified computer and create the named file") << endl;
  440. }
  441. /*
  442. * main - The main entry point for the stub executable.
  443. *
  444. * History: a-jsari 10/13/97 Initial version
  445. */
  446. BOOL CMSInfoApp::InitInstance()
  447. {
  448. CString szResText;
  449. CString szResTitle;
  450. // Shouldn't need this.
  451. do {
  452. try {
  453. // FIX: Pre-load the memory resource in case memory problems develop.
  454. CMSInfoExecutable exeMSInfo(cszProgram);
  455. exeMSInfo.Find();
  456. if (exeMSInfo.ProcessCommandLine())
  457. exeMSInfo.Run();
  458. // We never get past this on successful completion.
  459. }
  460. catch (CMemoryException e_Mem) {
  461. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  462. VERIFY(szResText.LoadString(IDS_MEMORY));
  463. VERIFY(szResTitle.LoadString(IDS_DESCRIPTION));
  464. if (::MessageBox(NULL, szResText, szResTitle, MB_RETRYCANCEL | MB_ICONERROR) == IDCANCEL)
  465. break;
  466. continue;
  467. }
  468. catch (CException e_Generic) {
  469. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  470. VERIFY(szResText.LoadString(IDS_UNEXPECTED));
  471. ::MessageBox(NULL, szResText, szResTitle, MB_OK | MB_ICONERROR);
  472. delete ::g_pException;
  473. break;
  474. }
  475. catch (...) {
  476. ASSERT(FALSE);
  477. break;
  478. }
  479. break;
  480. } while (TRUE);
  481. return FALSE;
  482. }