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.

1182 lines
33 KiB

  1. // stubexe.cpp A command line program which runs the appropriate version
  2. // of MSInfo, based on the registry settings
  3. //
  4. // History: a-jsari 10/13/97
  5. //
  6. // Copyright (c) 1998-1999 Microsoft Corporation
  7. #include <afx.h>
  8. #include <afxwin.h>
  9. #include <io.h>
  10. #include <process.h>
  11. #include <errno.h>
  12. #include "StdAfx.h"
  13. #include "Resource.h"
  14. #include "StubExe.h"
  15. #include "MSInfo.h"
  16. #include "MSInfo_i.c"
  17. //-----------------------------------------------------------------------------
  18. // These global variables hold arguments passed as command line parameters.
  19. //-----------------------------------------------------------------------------
  20. CString strComputerParam(_T(""));
  21. CString strCategoryParam(_T(""));
  22. CString strNFOFileParam(_T(""));
  23. CString strReportFileParam(_T(""));
  24. #ifndef HRESULT
  25. typedef long HRESULT;
  26. #endif
  27. // For Windows 95, the maximum length of a command line is 1024 characters.
  28. // Not sure what it is for NT.
  29. const int MAX_COMMAND_LINE = 1024;
  30. LPCTSTR cszDefaultDirectory = _T("\\Microsoft Shared\\MSInfo\\");
  31. LPCTSTR cszRegistryRoot = _T("Software\\Microsoft\\Shared Tools\\MSInfo");
  32. LPCTSTR cszDirectoryKey = _T("Path");
  33. LPCTSTR cszWindowsRoot = _T("Software\\Microsoft\\Windows\\CurrentVersion");
  34. LPCTSTR cszCommonFilesKey = _T("CommonFilesDir");
  35. CException *g_pException = NULL;
  36. // Microsoft Management Console is the program that hosts MSInfo.
  37. // This is a definition so that we can take its size.
  38. #define cszProgram _T("mmc.exe")
  39. /*
  40. * ThrowErrorException -
  41. *
  42. * History: a-jsari 10/14/97 Initial version.
  43. */
  44. inline void ThrowErrorException()
  45. {
  46. ::g_pException = new CException;
  47. if (::g_pException == NULL) ::AfxThrowMemoryException();
  48. throw ::g_pException;
  49. }
  50. /*
  51. * CMSInfo - A class to encapsulate using the DLL's COM interface.
  52. *
  53. * History: a-jsari 3/26/98 Initial version
  54. */
  55. class CMSInfo {
  56. public:
  57. CMSInfo();
  58. ~CMSInfo();
  59. HRESULT nfo(LPCTSTR lpszParams);
  60. HRESULT report(LPCTSTR lpszParams);
  61. HRESULT s(LPCTSTR lpszParams);
  62. HRESULT SaveNFO();
  63. HRESULT SaveReport();
  64. private:
  65. ISystemInfo *m_pISystemInfo;
  66. HRESULT m_hr;
  67. };
  68. /*
  69. * CSystemExecutable - The class that implements finding and running an
  70. * executable.
  71. *
  72. * History: a-jsari 10/14/97 Initial version.
  73. */
  74. class CSystemExecutable {
  75. public:
  76. CSystemExecutable(LPTSTR szProgram);
  77. ~CSystemExecutable() { DeleteStrings(); }
  78. void Run();
  79. void Find();
  80. void ProcessCommandLine();
  81. // Helper methods.
  82. protected:
  83. void DeleteStrings();
  84. void FindFileOnSystem(CString &szFileName, CString &szDestination);
  85. // Instance variables.
  86. protected:
  87. CString *m_pszPath;
  88. CString *m_pszProgramName;
  89. CString *m_pszCommandLine;
  90. };
  91. /*
  92. * CMSInfoExecutable - MSInfo-specific functions.
  93. *
  94. * History: a-jsari 10/15/97 Initial version
  95. */
  96. class CMSInfoExecutable : public CSystemExecutable {
  97. public:
  98. CMSInfoExecutable(LPTSTR szProgram);
  99. ~CMSInfoExecutable() {}
  100. void ProcessCommandLine();
  101. private:
  102. void DisplayHelp();
  103. void DeleteStrings();
  104. void FindSavedConsole();
  105. LPCTSTR GetMSIParameter(LPCTSTR szCommand, CString & strParam);
  106. // Instance variables
  107. private:
  108. static const LPCTSTR cszSavedConsole;
  109. CString *m_pszSavedConsole;
  110. };
  111. const LPCTSTR CMSInfoExecutable::cszSavedConsole = _T("MSInfo32.msc");
  112. /*
  113. * CMSInfo - Initialize COM and create our ISystemInfo object.
  114. *
  115. * History: a-jsari 3/26/98 Initial version.
  116. */
  117. CMSInfo::CMSInfo()
  118. :m_pISystemInfo(NULL)
  119. {
  120. HRESULT hr = CoInitialize(NULL);
  121. if (FAILED(hr)) ::AfxThrowUserException();
  122. m_hr = CoCreateInstance(CLSID_SystemInfo, NULL, CLSCTX_ALL, IID_ISystemInfo, (void **)&m_pISystemInfo);
  123. }
  124. LPCTSTR cszSeparators = _T(" \t,");
  125. //-----------------------------------------------------------------------------
  126. // Call the msinfo32.dll using COM to save an NFO file. Use the parameters
  127. // parsed from the command line (categories, computer).
  128. //-----------------------------------------------------------------------------
  129. HRESULT CMSInfo::SaveNFO()
  130. {
  131. CString strFilename(strNFOFileParam);
  132. CString strComputer(strComputerParam);
  133. CString strCategory(strCategoryParam);
  134. BSTR filename = strFilename.AllocSysString();
  135. BSTR computer = strComputer.AllocSysString();
  136. BSTR category = strCategory.AllocSysString();
  137. if (m_pISystemInfo)
  138. return m_pISystemInfo->MakeNFO(filename, computer, category);
  139. return E_NOTIMPL;
  140. }
  141. //-----------------------------------------------------------------------------
  142. // Call the msinfo32.dll using COM to save a report. Use the parameters
  143. // parsed from the command line (categories, computer).
  144. //-----------------------------------------------------------------------------
  145. HRESULT CMSInfo::SaveReport()
  146. {
  147. CString strFilename(strReportFileParam);
  148. CString strComputer(strComputerParam);
  149. CString strCategory(strCategoryParam);
  150. BSTR filename = strFilename.AllocSysString();
  151. BSTR computer = strComputer.AllocSysString();
  152. BSTR category = strCategory.AllocSysString();
  153. if (m_pISystemInfo)
  154. return m_pISystemInfo->MakeReport(filename, computer, category);
  155. return E_NOTIMPL;
  156. }
  157. /*
  158. * make_nfo - Process our parameters and call our ISystemInfo pointer's make_nfo function.
  159. *
  160. * History: a-jsari 3/26/98 Initial version.
  161. */
  162. HRESULT CMSInfo::nfo(LPCTSTR lpszParams)
  163. {
  164. CString strBuffer = lpszParams;
  165. CString strFilename;
  166. LPCTSTR szComputer = NULL;
  167. int iSpace;
  168. strBuffer.TrimLeft();
  169. iSpace = strBuffer.FindOneOf(cszSeparators);
  170. do {
  171. if (iSpace == -1) {
  172. if (strBuffer.IsEmpty())
  173. return E_INVALIDARG;
  174. strFilename = strBuffer;
  175. } else {
  176. strFilename = strBuffer.Left(iSpace);
  177. strBuffer = strBuffer.Mid(iSpace + 1);
  178. strBuffer.TrimLeft();
  179. if (strBuffer[0] == (TCHAR)',')
  180. strBuffer = strBuffer.Mid(1);
  181. strBuffer.TrimLeft();
  182. iSpace = strBuffer.FindOneOf(cszSeparators);
  183. if (iSpace != -1) {
  184. strBuffer.Left(iSpace);
  185. break;
  186. }
  187. szComputer = (LPCTSTR)strBuffer;
  188. }
  189. } while (FALSE);
  190. if (m_pISystemInfo != NULL)
  191. return m_pISystemInfo->make_nfo(const_cast<LPTSTR>((LPCTSTR)strFilename),
  192. const_cast<LPTSTR>(szComputer));
  193. return m_hr;
  194. }
  195. /*
  196. * report - Process our parameters and call our ISystemInfo's make_report function.
  197. *
  198. * History: a-jsari 3/26/98 Initial version.
  199. */
  200. HRESULT CMSInfo::report(LPCTSTR lpszParams)
  201. {
  202. CString strBuffer = lpszParams;
  203. CString strFilename;
  204. CString strComputer;
  205. LPCTSTR szComputer = NULL;
  206. LPCTSTR szCategory = NULL;
  207. int iSpace;
  208. strBuffer.TrimLeft();
  209. iSpace = strBuffer.FindOneOf(cszSeparators);
  210. do {
  211. if (iSpace == -1) {
  212. if (strBuffer.IsEmpty())
  213. return E_INVALIDARG;
  214. strFilename = strBuffer;
  215. } else {
  216. strFilename = strBuffer.Left(iSpace);
  217. strBuffer = strBuffer.Mid(iSpace + 1);
  218. strBuffer.TrimLeft();
  219. if (strBuffer[0] == (TCHAR)',')
  220. strBuffer = strBuffer.Mid(1);
  221. strBuffer.TrimLeft();
  222. iSpace = strBuffer.FindOneOf(cszSeparators);
  223. if (iSpace == -1) {
  224. strComputer = strBuffer;
  225. szComputer = (LPCTSTR)strComputer;
  226. break;
  227. }
  228. strComputer = strBuffer.Left(iSpace);
  229. szComputer = (LPCTSTR)strComputer;
  230. strBuffer = strBuffer.Mid(iSpace + 1);
  231. strBuffer.TrimLeft();
  232. if (strBuffer[0] == (TCHAR)',')
  233. strBuffer = strBuffer.Mid(1);
  234. strBuffer.TrimLeft();
  235. iSpace = strBuffer.FindOneOf(cszSeparators);
  236. if (iSpace != -1) {
  237. strBuffer = strBuffer.Left(iSpace);
  238. }
  239. szCategory = (LPCTSTR)strBuffer;
  240. }
  241. } while (FALSE);
  242. if (m_pISystemInfo != NULL)
  243. return m_pISystemInfo->make_report(const_cast<LPTSTR>((LPCTSTR)strFilename),
  244. const_cast<LPTSTR>(szComputer), const_cast<LPTSTR>(szCategory));
  245. return m_hr;
  246. }
  247. /*
  248. * s - Process our parameters and call our ISystemInfo's make_nfo function.
  249. *
  250. * History: a-jsari 3/26/98 Initial version.
  251. */
  252. HRESULT CMSInfo::s(LPCTSTR lpszParams)
  253. {
  254. CString strBuffer = lpszParams;
  255. int iSpace;
  256. strBuffer.TrimLeft();
  257. iSpace = strBuffer.FindOneOf(_T(" \t"));
  258. if (iSpace != -1)
  259. strBuffer = strBuffer.Left(iSpace);
  260. if (!strBuffer.IsEmpty())
  261. m_hr = E_INVALIDARG;
  262. else {
  263. if (m_pISystemInfo != NULL)
  264. m_hr = m_pISystemInfo->make_nfo(const_cast<LPTSTR>((LPCTSTR)strBuffer), NULL);
  265. }
  266. return m_hr;
  267. }
  268. /*
  269. * ~CMSInfo - Uninitialize COM and delete our ISystemInfo object.
  270. *
  271. * History: a-jsari 3/26/98 Initial version.
  272. */
  273. CMSInfo::~CMSInfo()
  274. {
  275. if (SUCCEEDED(m_hr))
  276. m_pISystemInfo->Release();
  277. CoUninitialize();
  278. }
  279. /*
  280. * CExecutable - Constructor which determines the type of the executable to
  281. * be executed.
  282. *
  283. * History: a-jsari 10/14/97 Initial version.
  284. */
  285. CSystemExecutable::CSystemExecutable(LPTSTR szProgram)
  286. :m_pszProgramName(new CString), m_pszPath(new CString), m_pszCommandLine(new CString)
  287. {
  288. if (!(m_pszProgramName && m_pszPath && m_pszCommandLine)) AfxThrowMemoryException();
  289. *m_pszProgramName = szProgram;
  290. }
  291. /*
  292. * DeleteStrings - Delete all of the strings used by the object. Used to free
  293. * our memory before calling exec.
  294. *
  295. * History: a-jsari 10/15/97 Initial version
  296. */
  297. void CSystemExecutable::DeleteStrings()
  298. {
  299. delete m_pszPath;
  300. m_pszPath = NULL;
  301. delete m_pszProgramName;
  302. m_pszProgramName = NULL;
  303. delete m_pszCommandLine;
  304. m_pszCommandLine = NULL;
  305. }
  306. /*
  307. * FindFileOnSystem - We may eventually put code here to test multiple
  308. * found copies and use the right one. But probably not.
  309. *
  310. * History: a-jsari 10/15/97 Stub version
  311. */
  312. void CSystemExecutable::FindFileOnSystem(CString &szFileName,
  313. CString &szDestination)
  314. {
  315. // Not reached.
  316. CFileFind FileFinder;
  317. BOOL bFindResult;
  318. bFindResult = FileFinder.FindFile(szFileName);
  319. if (!bFindResult) ThrowErrorException();
  320. szDestination = FileFinder.GetFilePath();
  321. #if 0
  322. // Choose among all versions of the file?
  323. while (bFindResult) {
  324. FileFinder.FindNextFile();
  325. }
  326. #endif
  327. }
  328. /*
  329. * Find - Return a pointer to a string containing the full path
  330. * to the MMC executable.
  331. *
  332. * History: a-jsari 10/13/97 Initial version
  333. */
  334. void CSystemExecutable::Find()
  335. {
  336. UINT uReturnSize;
  337. TCHAR szSystemDirectory[MAX_PATH + 1];
  338. uReturnSize = GetSystemDirectory(szSystemDirectory, MAX_PATH);
  339. if (uReturnSize == 0) ThrowErrorException();
  340. if (uReturnSize > MAX_PATH) {
  341. // Our buffer isn't big enough. This code will never get called.
  342. AfxThrowResourceException();
  343. }
  344. *m_pszPath += szSystemDirectory;
  345. *m_pszPath += _T("\\") + *m_pszProgramName;
  346. if (_taccess(*m_pszPath, A_READ) < 0) {
  347. // These may eventually want to be distinct exceptions.
  348. if (errno == ENOENT) {
  349. ThrowErrorException();
  350. } else {
  351. ASSERT(errno == EACCES);
  352. ThrowErrorException();
  353. }
  354. }
  355. }
  356. /*
  357. * Run - Call exec with the parameters we so meticulously collected.
  358. *
  359. * History: a-jsari 10/15/97 Initial version.
  360. */
  361. void CSystemExecutable::Run()
  362. {
  363. #if !defined(UNICODE)
  364. TCHAR szPath[MAX_PATH + 1];
  365. TCHAR szProgramName[MAX_PATH + 1];
  366. TCHAR szCommandLine[MAX_COMMAND_LINE + 1];
  367. _tcscpy(szPath, (LPCTSTR)*m_pszPath);
  368. _tcscpy(szProgramName, (LPCTSTR)*m_pszProgramName);
  369. _tcscpy(szCommandLine, (LPCTSTR)*m_pszCommandLine);
  370. DeleteStrings();
  371. ::_execlp(szPath, szProgramName, szCommandLine, 0);
  372. ThrowErrorException();
  373. #else
  374. char szPath[MAX_PATH + 1];
  375. char szProgramName[MAX_PATH + 1];
  376. char szCommandLine[MAX_COMMAND_LINE + 1];
  377. wcstombs(szPath, (LPCTSTR) *m_pszPath, MAX_PATH);
  378. wcstombs(szProgramName, (LPCTSTR) *m_pszProgramName, MAX_PATH);
  379. wcstombs(szCommandLine, (LPCTSTR) *m_pszCommandLine, MAX_COMMAND_LINE);
  380. DeleteStrings();
  381. ::_execlp(szPath, szProgramName, szCommandLine, 0);
  382. ThrowErrorException();
  383. #endif
  384. }
  385. /*
  386. * ProcessCommandLine - Pass all command line parameters to the called
  387. * executable.
  388. *
  389. * History: a-jsari 10/14/97 Initial version
  390. */
  391. void CSystemExecutable::ProcessCommandLine()
  392. {
  393. *m_pszCommandLine = GetCommandLine();
  394. // Skip over the first element in the line, which is the path to
  395. // the current executable. Preserve everything else.
  396. const int FIND_NO_MATCH = -1;
  397. int wIndex;
  398. m_pszCommandLine->TrimLeft();
  399. wIndex = m_pszCommandLine->FindOneOf(_T("\" \t\n"));
  400. if ((*m_pszCommandLine)[wIndex] == '"') {
  401. // This is the primary, if not guaranteed method.
  402. *m_pszCommandLine = m_pszCommandLine->Right(m_pszCommandLine->GetLength() - (wIndex + 1));
  403. wIndex = m_pszCommandLine->Find('"');
  404. *m_pszCommandLine = m_pszCommandLine->Right(m_pszCommandLine->GetLength() - (wIndex + 1));
  405. } else if (wIndex == FIND_NO_MATCH) {
  406. *m_pszCommandLine = _T("");
  407. } else {
  408. *m_pszCommandLine = m_pszCommandLine->Right(m_pszCommandLine->GetLength() - (wIndex + 1));
  409. }
  410. }
  411. /*
  412. * CMSInfoExecutable - Just pass all parameters to the base constructor.
  413. *
  414. * History: a-jsari 10/15/97 Initial version
  415. */
  416. CMSInfoExecutable::CMSInfoExecutable(LPTSTR szProgram)
  417. :CSystemExecutable(szProgram), m_pszSavedConsole(new CString)
  418. {
  419. if (m_pszSavedConsole == NULL) AfxThrowMemoryException();
  420. }
  421. //-----------------------------------------------------------------------------
  422. // This function is used to get a parameter from the command line. The first
  423. // character may be one or more whitespace, or a ":" or a "=". After that, the
  424. // string is read until a whitespace character is read outside of quotes.
  425. //
  426. // Return the pointer to the character location where we stopped reading.
  427. //-----------------------------------------------------------------------------
  428. LPCTSTR CMSInfoExecutable::GetMSIParameter(LPCTSTR szCommand, CString & strParam)
  429. {
  430. strParam.Empty();
  431. if (!szCommand)
  432. return NULL;
  433. // Advance past any leading whitespace, ':' or '='.
  434. while (*szCommand && (*szCommand == _T(' ') || *szCommand == _T('\t') || *szCommand == _T(':') || *szCommand == _T('=')))
  435. szCommand++;
  436. if (*szCommand == _T('\0'))
  437. return szCommand;
  438. // Now read the parameter in until the end of the string or a non-quoted
  439. // whitespace is found. Remove the quote marks.
  440. BOOL fInQuote = FALSE;
  441. while (*szCommand)
  442. {
  443. if (!fInQuote && (*szCommand == _T(' ') || *szCommand == _T('\t')))
  444. break;
  445. if (*szCommand == _T('"'))
  446. {
  447. fInQuote = !fInQuote;
  448. szCommand++;
  449. continue;
  450. }
  451. strParam += *szCommand++;
  452. }
  453. return szCommand;
  454. }
  455. //-----------------------------------------------------------------------------
  456. // This function reads the command line, looking for parameters we know how to
  457. // handle. Anything we don't know about, we assemble into a new command line
  458. // to pass to MMC when we launch MSInfo (if we launch it).
  459. //-----------------------------------------------------------------------------
  460. void CMSInfoExecutable::ProcessCommandLine()
  461. {
  462. CSystemExecutable::ProcessCommandLine();
  463. FindSavedConsole();
  464. CString strNewCommandLine;
  465. int iLine = 0;
  466. // Process the items on the command line. If we recognize the flag,
  467. // save the value for use later. Otherwise add it to the command line
  468. // we'll pass to the snapin.
  469. while (m_pszCommandLine->GetLength() > 0)
  470. {
  471. // Remove the part of the command line we just processed.
  472. *m_pszCommandLine = m_pszCommandLine->Mid(iLine);
  473. iLine = m_pszCommandLine->FindOneOf(_T(" \t")) + 1;
  474. if (iLine == 0)
  475. iLine = m_pszCommandLine->GetLength();
  476. // See if the first char is a command line switch.
  477. TCHAR tcFirst = (*m_pszCommandLine)[0];
  478. if (tcFirst == (TCHAR)'/' || tcFirst == (TCHAR)'-')
  479. {
  480. LPCTSTR pString = *m_pszCommandLine;
  481. ++pString;
  482. // This is a command line switch - see if we recognize it.
  483. if (::_tcsnicmp(pString, _T("?"), 1) == 0)
  484. {
  485. DisplayHelp();
  486. exit(0);
  487. }
  488. else if (::_tcsnicmp(pString, _T("report"), 6) == 0)
  489. {
  490. LPCTSTR szEnd = GetMSIParameter(pString + 6, strReportFileParam);
  491. szEnd++;
  492. *m_pszCommandLine = szEnd;
  493. iLine = 0;
  494. continue;
  495. }
  496. else if (::_tcsnicmp(pString, _T("s"), 1) == 0)
  497. {
  498. LPCTSTR szEnd = GetMSIParameter(pString + 1, strNFOFileParam);
  499. szEnd++;
  500. *m_pszCommandLine = szEnd;
  501. iLine = 0;
  502. continue;
  503. }
  504. else if (::_tcsnicmp(pString, _T("nfo"), 3) == 0)
  505. {
  506. LPCTSTR szEnd = GetMSIParameter(pString + 3, strNFOFileParam);
  507. szEnd++;
  508. *m_pszCommandLine = szEnd;
  509. iLine = 0;
  510. continue;
  511. }
  512. else if (::_tcsnicmp(pString, _T("computer"), 8) == 0)
  513. {
  514. LPCTSTR szEnd = GetMSIParameter(pString + 8, strComputerParam);
  515. szEnd++;
  516. *m_pszCommandLine = szEnd;
  517. iLine = 0;
  518. continue;
  519. }
  520. else if (::_tcsnicmp(pString, _T("categories"), 10) == 0)
  521. {
  522. LPCTSTR szEnd = GetMSIParameter(pString + 10, strCategoryParam);
  523. szEnd++;
  524. *m_pszCommandLine = szEnd;
  525. iLine = 0;
  526. continue;
  527. }
  528. }
  529. // If we don't match one of our internal switches, pass it on.
  530. strNewCommandLine += m_pszCommandLine->Left(iLine);
  531. }
  532. // Now, check the parameters we parsed from the command line to decide what
  533. // to do. If we are to save an NFO or report, we should just exit after
  534. // doing so.
  535. if (!strNFOFileParam.IsEmpty() || !strReportFileParam.IsEmpty())
  536. {
  537. CMSInfo sysInfo;
  538. if (!strNFOFileParam.IsEmpty())
  539. sysInfo.SaveNFO();
  540. else if (!strReportFileParam.IsEmpty())
  541. sysInfo.SaveReport();
  542. exit(0);
  543. }
  544. // Construct the command line for MMC.
  545. *m_pszCommandLine = _T("/s \"") + *m_pszSavedConsole + _T("\" ") + strNewCommandLine;
  546. if (!strComputerParam.IsEmpty())
  547. *m_pszCommandLine += _T(" /computer \"") + strComputerParam + _T("\" ");
  548. if (!strCategoryParam.IsEmpty())
  549. *m_pszCommandLine += _T(" /msinfo_showcategories=\"") + strCategoryParam + _T("\" ");
  550. delete m_pszSavedConsole;
  551. m_pszSavedConsole = NULL;
  552. }
  553. /*
  554. * FindSavedConsole - Finds SysInfo.msc using the registry, or the
  555. * default directory.
  556. *
  557. * History: a-jsari 10/13/97 Initial version
  558. */
  559. void CMSInfoExecutable::FindSavedConsole()
  560. {
  561. HKEY keyMSInfoRoot;
  562. long lResult;
  563. DWORD dwKeyLength = MAX_PATH;
  564. DWORD dwType;
  565. TCHAR szDirectory[MAX_PATH+1];
  566. *m_pszSavedConsole = _T("");
  567. do {
  568. // Check the current directory.
  569. if (::_taccess(cszSavedConsole, A_READ) == 0) {
  570. *m_pszSavedConsole = cszSavedConsole;
  571. return;
  572. }
  573. // Check the MSInfo Path key.
  574. lResult = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE, cszRegistryRoot, 0, KEY_READ,
  575. &keyMSInfoRoot);
  576. if (lResult == ERROR_SUCCESS) {
  577. lResult = ::RegQueryValueEx(keyMSInfoRoot, cszDirectoryKey, 0, &dwType,
  578. reinterpret_cast<BYTE *>(szDirectory), &dwKeyLength);
  579. if (lResult == ERROR_SUCCESS) {
  580. LPTSTR pszPath = ::_tcsrchr(szDirectory, (TCHAR)'\\');
  581. if (pszPath) *pszPath = 0;
  582. *m_pszSavedConsole = szDirectory;
  583. *m_pszSavedConsole += _T("\\");
  584. *m_pszSavedConsole += cszSavedConsole;
  585. if (::_taccess(*m_pszSavedConsole, A_READ) == 0)
  586. return;
  587. }
  588. }
  589. // Use the hard-coded path %ProgramFilesRoot%\Common Files\MSInfo
  590. lResult = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE, cszWindowsRoot, 0, KEY_READ, &keyMSInfoRoot);
  591. ASSERT(lResult == ERROR_SUCCESS);
  592. if (lResult != ERROR_SUCCESS) break;
  593. dwKeyLength = sizeof( szDirectory);
  594. lResult = ::RegQueryValueEx(keyMSInfoRoot, cszCommonFilesKey, 0, &dwType,
  595. reinterpret_cast<BYTE *>(szDirectory), &dwKeyLength);
  596. ASSERT(lResult == ERROR_SUCCESS);
  597. if (lResult != ERROR_SUCCESS) break;
  598. *m_pszSavedConsole = szDirectory;
  599. *m_pszSavedConsole += cszDefaultDirectory;
  600. *m_pszSavedConsole += cszSavedConsole;
  601. if (::_taccess(*m_pszSavedConsole, A_READ) == 0)
  602. return;
  603. } while (0);
  604. // AFX_MANAGE_STATE(::AfxGetStaticModuleState());
  605. CString szNoMSCFile;
  606. szNoMSCFile.LoadString(IDS_NOMSCFILE);
  607. ::AfxMessageBox(szNoMSCFile);
  608. ::ThrowErrorException();
  609. }
  610. /*
  611. * DisplayHelp - Print the command line help for the executable.
  612. *
  613. * History: a-jsari 10/13/97 Initial version.
  614. * a-adaml 03/15/99 Modified to display help in message box
  615. *
  616. */
  617. void CMSInfoExecutable::DisplayHelp()
  618. {
  619. CString strMsg, strTitle;
  620. strTitle.LoadString(IDS_DESCRIPTION);
  621. strMsg.LoadString(IDS_USAGE);
  622. ::MessageBox( NULL, strMsg, strTitle, MB_ICONINFORMATION | MB_OK);
  623. }
  624. /*
  625. * InitInstance - The main entry point for the stub executable, the subclass InitInstance
  626. * function
  627. *
  628. * History: a-jsari 10/13/97 Initial version
  629. */
  630. BOOL CMSInfoApp::InitInstance()
  631. {
  632. #if FALSE // just run the helpctr version now
  633. CString szResText;
  634. CString szResTitle;
  635. do {
  636. try {
  637. // FIX: Pre-load the memory resource in case memory problems develop.
  638. CMSInfoExecutable exeMSInfo(cszProgram);
  639. exeMSInfo.Find();
  640. exeMSInfo.ProcessCommandLine();
  641. exeMSInfo.Run();
  642. // We never get past this on successful completion.
  643. }
  644. catch (CMemoryException e_Mem) {
  645. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  646. VERIFY(szResText.LoadString(IDS_MEMORY));
  647. VERIFY(szResTitle.LoadString(IDS_DESCRIPTION));
  648. if (::MessageBox(NULL, szResText, szResTitle, MB_RETRYCANCEL | MB_ICONERROR) == IDCANCEL)
  649. break;
  650. continue;
  651. }
  652. catch (CException e_Generic) {
  653. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  654. VERIFY(szResText.LoadString(IDS_UNEXPECTED));
  655. ::MessageBox(NULL, szResText, szResTitle, MB_OK | MB_ICONERROR);
  656. delete ::g_pException;
  657. break;
  658. }
  659. catch (...) {
  660. ASSERT(FALSE);
  661. break;
  662. }
  663. break;
  664. } while (TRUE);
  665. #endif
  666. if (!RunMSInfoInHelpCtr())
  667. {
  668. CDialog help(IDD_MSICMDLINE);
  669. help.DoModal();
  670. }
  671. return FALSE;
  672. }
  673. //-----------------------------------------------------------------------------
  674. // Required to use the new MSInfo DLL in HelpCtr.
  675. //-----------------------------------------------------------------------------
  676. typedef class MSInfo MSInfo;
  677. EXTERN_C const IID IID_IMSInfo;
  678. struct IMSInfo : public IDispatch
  679. {
  680. public:
  681. virtual /* [id][propput] */ HRESULT STDMETHODCALLTYPE put_AutoSize(
  682. /* [in] */ VARIANT_BOOL vbool) = 0;
  683. virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_AutoSize(
  684. /* [retval][out] */ VARIANT_BOOL __RPC_FAR *pbool) = 0;
  685. virtual /* [id][propput] */ HRESULT STDMETHODCALLTYPE put_BackColor(
  686. /* [in] */ OLE_COLOR clr) = 0;
  687. virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_BackColor(
  688. /* [retval][out] */ OLE_COLOR __RPC_FAR *pclr) = 0;
  689. virtual /* [id][propput] */ HRESULT STDMETHODCALLTYPE put_BackStyle(
  690. /* [in] */ long style) = 0;
  691. virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_BackStyle(
  692. /* [retval][out] */ long __RPC_FAR *pstyle) = 0;
  693. virtual /* [id][propput] */ HRESULT STDMETHODCALLTYPE put_BorderColor(
  694. /* [in] */ OLE_COLOR clr) = 0;
  695. virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_BorderColor(
  696. /* [retval][out] */ OLE_COLOR __RPC_FAR *pclr) = 0;
  697. virtual /* [id][propput] */ HRESULT STDMETHODCALLTYPE put_BorderStyle(
  698. /* [in] */ long style) = 0;
  699. virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_BorderStyle(
  700. /* [retval][out] */ long __RPC_FAR *pstyle) = 0;
  701. virtual /* [id][propput] */ HRESULT STDMETHODCALLTYPE put_BorderWidth(
  702. /* [in] */ long width) = 0;
  703. virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_BorderWidth(
  704. /* [retval][out] */ long __RPC_FAR *width) = 0;
  705. virtual /* [id][propputref] */ HRESULT STDMETHODCALLTYPE putref_Font(
  706. /* [in] */ IFontDisp __RPC_FAR *pFont) = 0;
  707. virtual /* [id][propput] */ HRESULT STDMETHODCALLTYPE put_Font(
  708. /* [in] */ IFontDisp __RPC_FAR *pFont) = 0;
  709. virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_Font(
  710. /* [retval][out] */ IFontDisp __RPC_FAR *__RPC_FAR *ppFont) = 0;
  711. virtual /* [id][propput] */ HRESULT STDMETHODCALLTYPE put_ForeColor(
  712. /* [in] */ OLE_COLOR clr) = 0;
  713. virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_ForeColor(
  714. /* [retval][out] */ OLE_COLOR __RPC_FAR *pclr) = 0;
  715. virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_Window(
  716. /* [retval][out] */ long __RPC_FAR *phwnd) = 0;
  717. virtual /* [id][propput] */ HRESULT STDMETHODCALLTYPE put_BorderVisible(
  718. /* [in] */ VARIANT_BOOL vbool) = 0;
  719. virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_BorderVisible(
  720. /* [retval][out] */ VARIANT_BOOL __RPC_FAR *pbool) = 0;
  721. virtual /* [id][propput] */ HRESULT STDMETHODCALLTYPE put_Appearance(
  722. /* [in] */ short appearance) = 0;
  723. virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_Appearance(
  724. /* [retval][out] */ short __RPC_FAR *pappearance) = 0;
  725. virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE SetHistoryStream(
  726. IStream __RPC_FAR *pStream) = 0;
  727. virtual /* [helpstring][id][propget] */ HRESULT STDMETHODCALLTYPE get_DCO_IUnknown(
  728. /* [retval][out] */ IUnknown __RPC_FAR *__RPC_FAR *pVal) = 0;
  729. virtual /* [helpstring][id][propput] */ HRESULT STDMETHODCALLTYPE put_DCO_IUnknown(
  730. /* [in] */ IUnknown __RPC_FAR *newVal) = 0;
  731. virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE SaveFile(
  732. BSTR filename,
  733. BSTR computer,
  734. BSTR category) = 0;
  735. };
  736. #include "msinfo32_i.c"
  737. //-----------------------------------------------------------------------------
  738. // This function encapsulates the functionality to run the new MSInfo in
  739. // HelpCtr. If this function returns false, the help should be displayed.
  740. //-----------------------------------------------------------------------------
  741. void StringReplace(CString & str, LPCTSTR szLookFor, LPCTSTR szReplaceWith);
  742. BOOL CMSInfoApp::RunMSInfoInHelpCtr()
  743. {
  744. //-------------------------------------------------------------------------
  745. // Parse the command line parameters into one big string to pass to the
  746. // ActiveX control. There are a few which would keep us from launching
  747. // HelpCtr.
  748. //-------------------------------------------------------------------------
  749. CString strCommandLine(CWinApp::m_lpCmdLine);
  750. CString strLastFlag;
  751. CString strCategory;
  752. CString strCategories;
  753. CString strComputer;
  754. CString strOpenFile;
  755. CString strPrintFile;
  756. CString strSilentNFO;
  757. CString strSilentExport;
  758. CString strTemp;
  759. BOOL fShowPCH = FALSE;
  760. BOOL fShowHelp = FALSE;
  761. BOOL fShowCategories = FALSE;
  762. while (!strCommandLine.IsEmpty())
  763. {
  764. // Remove the leading whitespace from the string.
  765. strTemp = strCommandLine.SpanIncluding(_T(" \t=:"));
  766. strCommandLine = strCommandLine.Right(strCommandLine.GetLength() - strTemp.GetLength());
  767. // If the first character is a / or a -, then this is a flag.
  768. if (strCommandLine[0] == _T('/') || strCommandLine[0] == _T('-'))
  769. {
  770. strCommandLine = strCommandLine.Right(strCommandLine.GetLength() - 1);
  771. strLastFlag = strCommandLine.SpanExcluding(_T(" \t=:"));
  772. strCommandLine = strCommandLine.Right(strCommandLine.GetLength() - strLastFlag.GetLength());
  773. strLastFlag.MakeLower();
  774. if (strLastFlag == CString(_T("pch")))
  775. {
  776. fShowPCH = TRUE;
  777. strLastFlag.Empty();
  778. }
  779. else if (strLastFlag == CString(_T("?")) || strLastFlag == CString(_T("h")))
  780. {
  781. fShowHelp = TRUE;
  782. strLastFlag.Empty();
  783. }
  784. else if (strLastFlag == CString(_T("showcategories")))
  785. {
  786. fShowCategories = TRUE;
  787. strLastFlag.Empty();
  788. }
  789. continue;
  790. }
  791. // Otherwise, this is either a filename to open, or a parameter from the
  792. // previous command line flag. This might have quotes around it.
  793. if (strCommandLine[0] != _T('"'))
  794. {
  795. strTemp = strCommandLine.SpanExcluding(_T(" \t"));
  796. strCommandLine = strCommandLine.Right(strCommandLine.GetLength() - strTemp.GetLength());
  797. }
  798. else
  799. {
  800. strCommandLine = strCommandLine.Right(strCommandLine.GetLength() - 1);
  801. strTemp = strCommandLine.SpanExcluding(_T("\""));
  802. strCommandLine = strCommandLine.Right(strCommandLine.GetLength() - strTemp.GetLength() - 1);
  803. }
  804. if (strLastFlag.IsEmpty() || strLastFlag == CString(_T("msinfo_file")))
  805. strOpenFile = strTemp;
  806. else if (strLastFlag == CString(_T("p")))
  807. strPrintFile = strTemp;
  808. else if (strLastFlag == CString(_T("category")))
  809. strCategory = strTemp;
  810. else if (strLastFlag == CString(_T("categories")))
  811. strCategories = strTemp;
  812. else if (strLastFlag == CString(_T("computer")))
  813. strComputer = strTemp;
  814. else if (strLastFlag == CString(_T("report")))
  815. strSilentExport = strTemp;
  816. else if (strLastFlag == CString(_T("nfo")) || strLastFlag == CString(_T("s")))
  817. strSilentNFO = strTemp;
  818. strLastFlag.Empty();
  819. }
  820. if (fShowHelp)
  821. return FALSE;
  822. TCHAR szCurrent[MAX_PATH];
  823. GetCurrentDirectory(MAX_PATH, szCurrent);
  824. CString strCurrent(szCurrent);
  825. if (strCurrent.Right(1) != CString(_T("\\")))
  826. strCurrent += CString(_T("\\"));
  827. HRESULT hrInitialize = CoInitialize(NULL);
  828. if (!strSilentNFO.IsEmpty() || !strSilentExport.IsEmpty())
  829. {
  830. IMSInfo * pMSInfo = NULL;
  831. if (SUCCEEDED(CoCreateInstance(CLSID_MSInfo, NULL, CLSCTX_ALL, IID_IMSInfo, (void **)&pMSInfo)) && pMSInfo != NULL)
  832. {
  833. BSTR computer = strComputer.AllocSysString();
  834. BSTR category = strCategories.AllocSysString();
  835. if (!strSilentNFO.IsEmpty())
  836. {
  837. if (strSilentNFO.Find(_T('\\')) == -1)
  838. strSilentNFO = strCurrent + strSilentNFO;
  839. if (strSilentNFO.Right(4).CompareNoCase(CString(_T(".nfo"))) != 0)
  840. strSilentNFO += CString(_T(".nfo"));
  841. BSTR filename = strSilentNFO.AllocSysString();
  842. pMSInfo->SaveFile(filename, computer, category);
  843. SysFreeString(filename);
  844. }
  845. if (!strSilentExport.IsEmpty())
  846. {
  847. if (strSilentExport.Find(_T('\\')) == -1)
  848. strSilentExport = strCurrent + strSilentExport;
  849. BSTR filename = strSilentExport.AllocSysString();
  850. pMSInfo->SaveFile(filename, computer, category);
  851. SysFreeString(filename);
  852. }
  853. SysFreeString(computer);
  854. SysFreeString(category);
  855. pMSInfo->Release();
  856. }
  857. if (SUCCEEDED(hrInitialize))
  858. CoUninitialize();
  859. return TRUE;
  860. }
  861. CString strURLParam;
  862. if (fShowPCH)
  863. strURLParam += _T("pch");
  864. if (fShowCategories)
  865. strURLParam += _T(",showcategories");
  866. if (!strComputer.IsEmpty())
  867. strURLParam += _T(",computer=") + strComputer;
  868. if (!strCategory.IsEmpty())
  869. strURLParam += _T(",category=") + strCategory;
  870. if (!strCategories.IsEmpty())
  871. strURLParam += _T(",categories=") + strCategories;
  872. if (!strPrintFile.IsEmpty())
  873. {
  874. if (strPrintFile.Find(_T('\\')) == -1)
  875. strPrintFile = strCurrent + strPrintFile;
  876. strURLParam += _T(",print=") + strPrintFile;
  877. }
  878. if (!strOpenFile.IsEmpty())
  879. {
  880. if (strOpenFile.Find(_T('\\')) == -1)
  881. strOpenFile = strCurrent + strOpenFile;
  882. strURLParam += _T(",open=") + strOpenFile;
  883. }
  884. if (!strURLParam.IsEmpty())
  885. {
  886. strURLParam.TrimLeft(_T(","));
  887. strURLParam = CString(_T("?")) + strURLParam;
  888. }
  889. CString strURLAddress(_T("hcp://system/sysinfo/msinfo.htm"));
  890. CString strURL = strURLAddress + strURLParam;
  891. //-------------------------------------------------------------------------
  892. // Check to see if we can run MSInfo in HelpCtr. We need the HTM file
  893. // to be present.
  894. //-------------------------------------------------------------------------
  895. BOOL fRunVersion6 = TRUE;
  896. TCHAR szPath[MAX_PATH];
  897. if (ExpandEnvironmentStrings(_T("%windir%\\pchealth\\helpctr\\system\\sysinfo\\msinfo.htm"), szPath, MAX_PATH))
  898. {
  899. WIN32_FIND_DATA finddata;
  900. HANDLE h = FindFirstFile(szPath, &finddata);
  901. if (INVALID_HANDLE_VALUE != h)
  902. FindClose(h);
  903. else
  904. fRunVersion6 = FALSE;
  905. }
  906. // This would be used to check if the control is registered. Turns out we want to run anyway.
  907. //
  908. // IUnknown * pUnknown;
  909. // if (fRunVersion6 && SUCCEEDED(CoCreateInstance(CLSID_MSInfo, NULL, CLSCTX_ALL, IID_IUnknown, (void **) &pUnknown)))
  910. // pUnknown->Release();
  911. // else
  912. // fRunVersion6 = FALSE;
  913. StringReplace(strURL, _T(" "), _T("%20"));
  914. if (fRunVersion6)
  915. {
  916. // HelpCtr now supports running MSInfo in its own window. We need to
  917. // execute the following:
  918. //
  919. // helpctr -mode hcp://system/sysinfo/msinfo.xml
  920. //
  921. // Additionally, we can pass parameters in the URL using the
  922. // following flag:
  923. //
  924. // -url hcp://system/sysinfo/msinfo.htm?open=c:\savedfile.nfo
  925. //
  926. // First, find out of the XML file is present.
  927. BOOL fXMLPresent = TRUE;
  928. if (ExpandEnvironmentStrings(_T("%windir%\\pchealth\\helpctr\\system\\sysinfo\\msinfo.xml"), szPath, MAX_PATH))
  929. {
  930. WIN32_FIND_DATA finddata;
  931. HANDLE h = FindFirstFile(szPath, &finddata);
  932. if (INVALID_HANDLE_VALUE != h)
  933. FindClose(h);
  934. else
  935. fXMLPresent = FALSE;
  936. }
  937. // If the XML file is present and we can get the path for helpctr.exe, we
  938. // should launch it the new way.
  939. TCHAR szHelpCtrPath[MAX_PATH];
  940. if (fXMLPresent && ExpandEnvironmentStrings(_T("%windir%\\pchealth\\helpctr\\binaries\\helpctr.exe"), szHelpCtrPath, MAX_PATH))
  941. {
  942. CString strParams(_T("-mode hcp://system/sysinfo/msinfo.xml"));
  943. if (!strURLParam.IsEmpty())
  944. strParams += CString(_T(" -url ")) + strURL;
  945. ShellExecute(NULL, NULL, szHelpCtrPath, strParams, NULL, SW_SHOWNORMAL);
  946. }
  947. else
  948. ShellExecute(NULL, NULL, strURL, NULL, NULL, SW_SHOWNORMAL);
  949. }
  950. else
  951. ShellExecute(NULL, NULL, _T("hcp://system"), NULL, NULL, SW_SHOWNORMAL);
  952. if (SUCCEEDED(hrInitialize))
  953. CoUninitialize();
  954. return TRUE;
  955. }
  956. //-----------------------------------------------------------------------------
  957. // This was used originally to replace some MFC functionality not in the ME
  958. // build tree.
  959. //-----------------------------------------------------------------------------
  960. void StringReplace(CString & str, LPCTSTR szLookFor, LPCTSTR szReplaceWith)
  961. {
  962. CString strWorking(str);
  963. CString strReturn;
  964. CString strLookFor(szLookFor);
  965. CString strReplaceWith(szReplaceWith);
  966. int iLookFor = strLookFor.GetLength();
  967. int iNext;
  968. while (!strWorking.IsEmpty())
  969. {
  970. iNext = strWorking.Find(strLookFor);
  971. if (iNext == -1)
  972. {
  973. strReturn += strWorking;
  974. strWorking.Empty();
  975. }
  976. else
  977. {
  978. strReturn += strWorking.Left(iNext);
  979. strReturn += strReplaceWith;
  980. strWorking = strWorking.Right(strWorking.GetLength() - (iNext + iLookFor));
  981. }
  982. }
  983. str = strReturn;
  984. }