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.

600 lines
16 KiB

  1. // Toolset.cpp - Classes to manage the tools menu.
  2. //
  3. // Copyright (c) 1998-1999 Microsoft Corporation
  4. #include <process.h>
  5. #include "StdAfx.h"
  6. #include "Toolset.h"
  7. #include "DataObj.h"
  8. #include "CompData.h"
  9. #include <atlbase.h>
  10. #include "Resource.h"
  11. #include "resrc1.h"
  12. #include "msicab.h"
  13. #ifdef _UNICODE
  14. #define _tspawnl _wspawnl
  15. #else
  16. #define _tspawnl _spawnl
  17. #endif
  18. const unsigned KEY_SIZE = MAX_PATH;
  19. const unsigned CToolset::MAXIMUM_TOOLS = 256;
  20. LPCTSTR cszRoot = _T("Software\\Microsoft\\Shared Tools\\MSInfo");
  21. LPCTSTR cszToolsetKey = _T("ToolSets");
  22. LPCTSTR cszMSInfoRoot = _T("Software\\Microsoft\\Shared Tools\\MSInfo\\ToolSets");
  23. LPCTSTR cszMSInfoCommandKey = _T("command");
  24. LPCTSTR cszMSInfoParamKey = _T("param");
  25. LPCTSTR cszMSInfoDescriptionKey = _T("description");
  26. LPCTSTR cszSystemPolicyKey = _T("Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer");
  27. LPCTSTR cszRunKey = _T("NoRun");
  28. LPCTSTR cszDefaultToolsetKey = _T("MSInfo");
  29. LPCTSTR cszExplorerSubPath = _T("\\explorer.exe");
  30. LPCTSTR cszAppletExtension = _T(".cpl");
  31. LPCTSTR cszSnapinExtension = _T(".msc");
  32. /*
  33. * CTool - Construct from the registry.
  34. *
  35. * History: a-jsari 11/11/97 Initial version.
  36. */
  37. CTool::CTool(CRegKey * pKeyTool) : m_strName(_T("")), m_strPath(_T("")), m_strParam(_T("")), m_strDescription(_T("")), m_fValid(TRUE)
  38. {
  39. if (pKeyTool == NULL)
  40. return;
  41. TCHAR szBuffer[MAX_PATH];
  42. DWORD dwSize;
  43. dwSize = MAX_PATH;
  44. if (pKeyTool->QueryValue(szBuffer, NULL, &dwSize) == ERROR_SUCCESS)
  45. m_strName = szBuffer;
  46. dwSize = MAX_PATH;
  47. if (pKeyTool->QueryValue(szBuffer, cszMSInfoCommandKey, &dwSize) == ERROR_SUCCESS)
  48. m_strPath = szBuffer;
  49. dwSize = MAX_PATH;
  50. if (pKeyTool->QueryValue(szBuffer, cszMSInfoParamKey, &dwSize) == ERROR_SUCCESS)
  51. m_strParam = szBuffer;
  52. dwSize = MAX_PATH;
  53. if (pKeyTool->QueryValue(szBuffer, cszMSInfoDescriptionKey, &dwSize) == ERROR_SUCCESS)
  54. m_strDescription = szBuffer;
  55. m_fValid = PathExists();
  56. }
  57. /*
  58. * operator= - Assignment operator, used to assign CTools to the CToolset array.
  59. *
  60. * History: a-jsari 11/11/97 Initial version
  61. */
  62. const CTool &CTool::operator=(const CTool &toolCopy)
  63. {
  64. if (&toolCopy != this) {
  65. m_strName = toolCopy.m_strName;
  66. m_strPath = toolCopy.m_strPath;
  67. m_strDescription = toolCopy.m_strDescription;
  68. m_fValid = toolCopy.m_fValid;
  69. }
  70. return *this;
  71. }
  72. //-----------------------------------------------------------------------------
  73. // PathExists - Return a flag specifying whether we can access the path
  74. // to our executable, excluding any parameters.
  75. //-----------------------------------------------------------------------------
  76. BOOL CTool::PathExists() const
  77. {
  78. // First, we'll look for the command, to see if that file exists.
  79. if (::_taccess((LPCTSTR)m_strPath, A_READ) != 0)
  80. return FALSE;
  81. // Also, the parameter value might contain a file (like a control
  82. // panel or an MSC snap-in file) we should check for. We need to get
  83. // a little bit kludgy here - if the param part ends with a CPL or
  84. // MSC extension, then back up in the string, so we can check for
  85. // the existence of that file.
  86. if (m_strParam.Right(4).CompareNoCase(cszAppletExtension) == 0 || m_strParam.Right(4).CompareNoCase(cszSnapinExtension) == 0)
  87. {
  88. LPCTSTR szFile = ::_tcsrchr((LPCTSTR)m_strParam, (TCHAR)' ');
  89. if (szFile)
  90. szFile++; // advance past the space
  91. else
  92. szFile = (LPCTSTR)m_strParam;
  93. if (szFile && ::_taccess(szFile, A_READ) != 0)
  94. return FALSE;
  95. }
  96. return TRUE;
  97. }
  98. //-----------------------------------------------------------------------------
  99. // RunTool - Spawn a process executing the current tool.
  100. //-----------------------------------------------------------------------------
  101. HRESULT CTool::RunTool()
  102. {
  103. AFX_MANAGE_STATE(::AfxGetStaticModuleState());
  104. if (PolicyPermitRun() == FALSE)
  105. {
  106. CString strMessage;
  107. strMessage.LoadString(IDS_POLICYFORBIDSRUN);
  108. return S_OK;
  109. }
  110. LPCTSTR cszPath = GetPath();
  111. LPCTSTR cszParam = GetParam();
  112. if (msiLog.IsLogging())
  113. msiLog.WriteLog(CMSInfoLog::TOOL, _T("TOOL \"%s\"\r\n"), m_strName);
  114. intptr_t hProcess;
  115. if (cszParam && *cszParam)
  116. hProcess = ::_tspawnl(_P_NOWAIT, cszPath, cszPath, cszParam, NULL);
  117. else
  118. hProcess = ::_tspawnl(_P_NOWAIT, cszPath, cszPath, NULL);
  119. if (hProcess < 0)
  120. {
  121. CString strMessage;
  122. strMessage.Format(IDS_NOPATH, cszPath);
  123. return E_UNEXPECTED;
  124. }
  125. return S_OK;
  126. }
  127. /*
  128. * PolicyPermitRun - returns a BOOLEAN value which determines whether
  129. *
  130. * History: ericflo 11/21/97 Boilerplate version
  131. * a-jsari 11/21/97 Initial edits
  132. */
  133. BOOL CTool::PolicyPermitRun()
  134. {
  135. HKEY hKeyPolicy;
  136. BOOL bReturn = TRUE;
  137. DWORD dwSize, dwData, dwType;
  138. // Explorer\\NoRun == 1
  139. do {
  140. if (RegOpenKeyEx (HKEY_CURRENT_USER, cszSystemPolicyKey, 0,
  141. KEY_READ, &hKeyPolicy) == ERROR_SUCCESS) {
  142. dwSize = sizeof(dwData);
  143. if (RegQueryValueEx(hKeyPolicy, cszRunKey, NULL, &dwType,
  144. (LPBYTE) &dwData, &dwSize) != ERROR_SUCCESS) break;
  145. RegCloseKey (hKeyPolicy);
  146. // I'm not sure which type this value is, so make an assumption.
  147. switch (dwType) {
  148. case REG_DWORD:
  149. if (dwData == 1)
  150. bReturn = FALSE;
  151. break;
  152. default:
  153. // We are assuming the wrong value type.
  154. ASSERT(FALSE);
  155. break;
  156. }
  157. }
  158. } while (FALSE);
  159. return bReturn;
  160. }
  161. /*
  162. * CCabTool - Construct the Cab explosion item.
  163. *
  164. * History: a-jsari 3/25/98 Initial version.
  165. */
  166. CCabTool::CCabTool(CSystemInfoScope *pScope)
  167. :m_pScope(pScope)
  168. {
  169. TCHAR szBuffer[MAX_PATH + 1];
  170. UINT uSize = MAX_PATH;
  171. AFX_MANAGE_STATE(::AfxGetStaticModuleState());
  172. m_strName.LoadString(IDS_CAB_NAME);
  173. m_strDescription.LoadString(IDS_CAB_DESCRIPTION);
  174. VERIFY(GetWindowsDirectory(szBuffer, uSize));
  175. m_strPath = szBuffer;
  176. m_strPath += cszExplorerSubPath;
  177. }
  178. /*
  179. * IsValid - Determine whether we have opened a CAB to explode.
  180. *
  181. * History: a-jsari 3/25/98 Initial version.
  182. */
  183. BOOL CCabTool::IsValid() const
  184. {
  185. if (m_pScope == NULL || m_pScope->pSource() == NULL || m_pScope->pSource()->GetType() == CDataSource::GATHERER)
  186. return FALSE;
  187. if (!PathExists()) return FALSE;
  188. return reinterpret_cast<CBufferDataSource *>(m_pScope->pSource())->HasCAB();
  189. }
  190. /*
  191. * GetPath - Return the path to explorer with the CAB directory.
  192. *
  193. * History: a-jsari 3/25/98 Initial version.
  194. */
  195. const CString &CCabTool::GetPath()
  196. {
  197. TCHAR szBuffer[MAX_PATH + 1];
  198. UINT uSize = MAX_PATH;
  199. VERIFY(GetWindowsDirectory(szBuffer, uSize));
  200. m_strPath = (LPTSTR)szBuffer;
  201. m_strPath += cszExplorerSubPath;
  202. return m_strPath;
  203. }
  204. const CString &CCabTool::GetParam()
  205. {
  206. if (m_strParam.IsEmpty())
  207. ::GetCABExplodeDir(m_strParam, FALSE, CString(_T("")));
  208. return m_strParam;
  209. }
  210. BOOL CToolset::s_fCabAdded = FALSE;
  211. /*
  212. * CToolset - Construct a toolset, reading the tools from the Registry key.
  213. *
  214. * History: a-jsari 11/6/97 Initial version
  215. */
  216. CToolset::CToolset(CSystemInfoScope *pScope, CRegKey *pKeySet, CString *pstrName)
  217. :m_pPopup(NULL)
  218. {
  219. CRegKey keySub;
  220. if (pKeySet) {
  221. long lResult;
  222. do {
  223. if (pstrName != NULL) {
  224. // szName represents the name of a subkey to open.
  225. lResult = keySub.Open(*pKeySet, *pstrName, KEY_READ);
  226. ASSERT(lResult == ERROR_SUCCESS);
  227. if (lResult != ERROR_SUCCESS) break;
  228. }
  229. DWORD dwSize;
  230. TCHAR szBuffer[KEY_SIZE];
  231. CRegKey keyTool;
  232. FILETIME keyTime;
  233. dwSize = sizeof(szBuffer);
  234. keySub.QueryValue(szBuffer, NULL, &dwSize);
  235. m_strName = szBuffer;
  236. for (DWORD iTool = 0 ; ; ++iTool) {
  237. //dwSize = sizeof(szBuffer);
  238. dwSize = sizeof(szBuffer) / sizeof(TCHAR);
  239. lResult = RegEnumKeyEx(keySub, iTool, szBuffer, &dwSize, NULL /* reserved */,
  240. NULL /* class */, NULL /* class size */, &keyTime);
  241. if (lResult == ERROR_NO_MORE_ITEMS) break;
  242. // Hard limit of 256 tools per set.
  243. if (iTool == MAXIMUM_TOOLS) break;
  244. ASSERT(lResult == ERROR_SUCCESS);
  245. if (lResult != ERROR_SUCCESS) break;
  246. lResult = keyTool.Open(keySub, szBuffer, KEY_QUERY_VALUE);
  247. if (lResult != ERROR_SUCCESS) break;
  248. CTool *toolNew = new CTool(&keyTool);
  249. m_Tools.SetAtGrow(iTool, toolNew);
  250. }
  251. if (!s_fCabAdded) {
  252. CTool *pTool = new CCabTool(pScope);
  253. s_fCabAdded = TRUE;
  254. m_Tools.SetAtGrow(iTool, pTool);
  255. }
  256. } while (FALSE);
  257. }
  258. }
  259. /*
  260. * ~CToolset - Delete our objects.
  261. *
  262. * History: a-jsari 11/6/97 Initial version
  263. */
  264. CToolset::~CToolset()
  265. {
  266. delete m_pPopup;
  267. unsigned iTool = (unsigned)m_Tools.GetSize();
  268. while (iTool--) {
  269. delete m_Tools[iTool];
  270. }
  271. }
  272. /*
  273. * operator= - Set one toolset equal to another (for list insertion).
  274. *
  275. * History: a-jsari 11/6/97 Initial version
  276. */
  277. const CToolset &CToolset::operator=(const CToolset &tCopy)
  278. {
  279. if (this != &tCopy) {
  280. m_strName = tCopy.m_strName;
  281. m_Tools.Copy(tCopy.m_Tools);
  282. }
  283. return *this;
  284. }
  285. /*
  286. * AddToMenu - Add an item to the specified menu; set the CommandID to allow us to find
  287. * the correct menu item.
  288. *
  289. * History: a-jsari 11/6/97 Initial version
  290. */
  291. HRESULT CToolset::AddToMenu(unsigned long iSet, CMenu *pMenu)
  292. {
  293. m_pPopup = new CMenu;
  294. if (m_pPopup == NULL) ::AfxThrowMemoryException();
  295. m_pPopup->CreatePopupMenu();
  296. UINT iTool = GetToolCount();
  297. UINT iSetCount = 0;
  298. while (iTool) {
  299. // Decrement the tool after we have set the command, so that the command ID
  300. // is equal to the set or'd with the Tool + 1.
  301. UINT wCommand = iSet | (iTool--);
  302. // Don't add a menu item for a
  303. if (m_Tools[iTool]->IsValid()) {
  304. ++iSetCount;
  305. VERIFY(m_pPopup->InsertMenu(0, MF_BYPOSITION | MF_STRING, wCommand, m_Tools[iTool]->GetName()));
  306. } else {
  307. ; // Log an error message!
  308. }
  309. }
  310. // Only add the sub-menu if there was at least one valid menu item.
  311. if (iSetCount > 0)
  312. pMenu->AppendMenu(MF_POPUP | MF_STRING, (UINT_PTR)m_pPopup->GetSafeHmenu(), m_strName);
  313. return S_OK;
  314. }
  315. /*
  316. * CToolList - Read the list of tools from the registry.
  317. *
  318. * History: a-jsari 11/6/97 Initial version.
  319. */
  320. CToolList::CToolList(CSystemInfoScope *pScope)
  321. :m_pMainPopup(NULL)
  322. {
  323. CRegKey crkToolRoot;
  324. TCHAR szToolsetName[MAX_PATH];
  325. CString szObject;
  326. DWORD dwSize;
  327. long lResult;
  328. FILETIME keyTime;
  329. lResult = crkToolRoot.Open(HKEY_LOCAL_MACHINE, cszMSInfoRoot, KEY_READ);
  330. if (lResult != ERROR_SUCCESS) {
  331. lResult = Register(TRUE);
  332. if (lResult != ERROR_SUCCESS) return;
  333. lResult = crkToolRoot.Open(HKEY_LOCAL_MACHINE, cszMSInfoRoot, KEY_READ);
  334. ASSERT(lResult == ERROR_SUCCESS);
  335. if (lResult != ERROR_SUCCESS) return;
  336. }
  337. for (DWORD iKey = 0 ; ; ++iKey) {
  338. //dwSize = sizeof(szToolsetName);
  339. dwSize = sizeof(szToolsetName) / sizeof(TCHAR);
  340. lResult = RegEnumKeyEx(crkToolRoot, iKey, szToolsetName, &dwSize, NULL /* reserved */,
  341. NULL /* class */, NULL /* class size */, &keyTime);
  342. if (lResult == ERROR_NO_MORE_ITEMS) break;
  343. szObject = szToolsetName;
  344. CToolset *setNew = new CToolset(pScope, &crkToolRoot, &szObject);
  345. Add(setNew);
  346. }
  347. }
  348. /*
  349. * ~CToolList - Delete our saved pop-up menu.
  350. *
  351. * History: a-jsari 11/6/97 Initial version
  352. */
  353. CToolList::~CToolList()
  354. {
  355. delete m_pMainPopup;
  356. unsigned iToolset = (unsigned)m_InternalList.GetSize();
  357. while (iToolset--) {
  358. delete m_InternalList[iToolset];
  359. }
  360. }
  361. /*
  362. * Add - Add an element to the end of the internal list.
  363. *
  364. * History: a-jsari 11/11/97 Initial version
  365. */
  366. void CToolList::Add(CToolset *toolSet)
  367. {
  368. m_InternalList.Add(toolSet);
  369. }
  370. /*
  371. * AddToMenu - Create our popup menu and add all of the sub-menus of each toolset
  372. * to it.
  373. *
  374. * History: a-jsari 11/6/97 Initial version.
  375. */
  376. HRESULT CToolList::AddToMenu(CMenu *pMenu)
  377. {
  378. // HRESULT hResult;
  379. // CToolset eSet;
  380. unsigned int ulMask; // To identify Toolset from the list for the CommandID.
  381. unsigned cList;
  382. m_pMainPopup = new CMenu;
  383. if (m_pMainPopup == NULL) ::AfxThrowMemoryException();
  384. m_pMainPopup->CreatePopupMenu();
  385. cList = (unsigned)m_InternalList.GetSize();
  386. for (ulMask = 0 ; ulMask < cList ; ++ulMask) {
  387. // ulMask << 16 is or'd into the lCommand to represent the Toolset number.
  388. HRESULT hResult = m_InternalList[ulMask]->AddToMenu(ulMask << 8, m_pMainPopup);
  389. if (FAILED(hResult)) return hResult;
  390. }
  391. pMenu->AppendMenu(MF_POPUP | MF_STRING, (UINT_PTR) m_pMainPopup->GetSafeHmenu(), _T(""));
  392. return S_OK;
  393. }
  394. //-----------------------------------------------------------------------------
  395. // Register (or unregister) the tools which show up in the MSInfo tools menu.
  396. // The tools are stored in a string resource, which we should process here
  397. // to create the registry entries.
  398. //
  399. // Under the toolset registry entry, each tool will have a key. Values under
  400. // the key will be:
  401. //
  402. // <default> Name of the tool, to appear in menu (may be localized).
  403. // commnd Command line for tool.
  404. // param Parameter for the tool.
  405. //-----------------------------------------------------------------------------
  406. long CToolList::Register(BOOL fRegister)
  407. {
  408. long lResult;
  409. CRegKey crkToolsetRoot;
  410. // If unregistering - recursively delete the ToolSets key under
  411. // HKEY_LOCAL_MACHINE\Software\Microsoft\Shared Tools\MSInfo.
  412. if (!fRegister)
  413. {
  414. lResult = crkToolsetRoot.Open(HKEY_LOCAL_MACHINE, cszRoot);
  415. if (lResult != ERROR_SUCCESS)
  416. return lResult;
  417. return crkToolsetRoot.RecurseDeleteKey(cszToolsetKey);
  418. }
  419. AFX_MANAGE_STATE(::AfxGetStaticModuleState());
  420. CRegKey crkNewToolset, crkTool;
  421. CString strKeyValue;
  422. // Create ToolSets key.
  423. lResult = crkToolsetRoot.Create(HKEY_LOCAL_MACHINE, cszMSInfoRoot);
  424. if (lResult != ERROR_SUCCESS)
  425. return lResult;
  426. // Delete anything which might already be under the MSInfo subkey.
  427. lResult = crkToolsetRoot.Open(HKEY_LOCAL_MACHINE, cszMSInfoRoot);
  428. if (lResult == ERROR_SUCCESS)
  429. crkToolsetRoot.RecurseDeleteKey(cszDefaultToolsetKey);
  430. lResult = crkNewToolset.Create(crkToolsetRoot, cszDefaultToolsetKey);
  431. if (lResult != ERROR_SUCCESS)
  432. return lResult;
  433. VERIFY(strKeyValue.LoadString(IDS_MSINFOTOOLSET));
  434. lResult = crkNewToolset.SetValue(strKeyValue);
  435. if (lResult != ERROR_SUCCESS)
  436. return lResult;
  437. // Get the windows directory and system32 directory.
  438. TCHAR szDirectory[MAX_PATH];
  439. CString strSystemDirectory;
  440. if (::GetSystemDirectory(szDirectory, MAX_PATH))
  441. strSystemDirectory = szDirectory;
  442. CString strWindowsDirectory;
  443. if (::GetWindowsDirectory(szDirectory, MAX_PATH))
  444. strWindowsDirectory = szDirectory;
  445. // Load the string containing the tools to add to the registry.
  446. CString strTools;
  447. strTools.LoadString(IDS_DEFAULT_TOOLS);
  448. CString strKeyName, strName, strCommand, strParam;
  449. int iDelim;
  450. while (!strTools.IsEmpty())
  451. {
  452. // First, get the different values we're going to add to the registry.
  453. iDelim = strTools.Find((TCHAR) '|');
  454. if (iDelim >= 0)
  455. {
  456. strKeyName = strTools.Left(iDelim);
  457. strTools = strTools.Right(strTools.GetLength() - (iDelim + 1));
  458. }
  459. iDelim = strTools.Find((TCHAR) '|');
  460. if (iDelim >= 0)
  461. {
  462. strName = strTools.Left(iDelim);
  463. strTools = strTools.Right(strTools.GetLength() - (iDelim + 1));
  464. }
  465. iDelim = strTools.Find((TCHAR) '|');
  466. if (iDelim >= 0)
  467. {
  468. strCommand = strTools.Left(iDelim);
  469. strTools = strTools.Right(strTools.GetLength() - (iDelim + 1));
  470. }
  471. iDelim = strTools.Find((TCHAR) '|');
  472. if (iDelim >= 0)
  473. {
  474. strParam = strTools.Left(iDelim);
  475. strTools = strTools.Right(strTools.GetLength() - (iDelim + 1));
  476. }
  477. // Now we need to convert the sequences in the string which contain
  478. // references to the windows directory, etc.
  479. ReplaceString(strCommand, _T("%sys32%"), strSystemDirectory);
  480. ReplaceString(strCommand, _T("%win%"), strWindowsDirectory);
  481. ReplaceString(strParam, _T("%sys32%"), strSystemDirectory);
  482. ReplaceString(strParam, _T("%win%"), strWindowsDirectory);
  483. // Finally, create the registry entries.
  484. lResult = crkTool.Create(crkNewToolset, strKeyName);
  485. if (lResult != ERROR_SUCCESS)
  486. continue;
  487. crkTool.SetValue(strName);
  488. crkTool.SetValue(strCommand, cszMSInfoCommandKey);
  489. crkTool.SetValue(strParam, cszMSInfoParamKey);
  490. }
  491. return ERROR_SUCCESS;
  492. }
  493. //-----------------------------------------------------------------------------
  494. // Look for instances of strFind in strString, and replace them with
  495. // strReplace. There's a method to do this in CString in version 6.
  496. //-----------------------------------------------------------------------------
  497. void CToolList::ReplaceString(CString & strString, const CString & strFind, const CString & strReplace)
  498. {
  499. int iStart = strString.Find(strFind);
  500. while (iStart != -1)
  501. {
  502. CString strTemp = strString.Left(iStart);
  503. strTemp += strReplace;
  504. strTemp += strString.Right(strString.GetLength() - iStart - strFind.GetLength());
  505. strString = strTemp;
  506. iStart = strString.Find(strFind);
  507. }
  508. }
  509. /* operator[] - Index our internal list.
  510. *
  511. * History: a-jsari 11/11/97 Initial version. */
  512. CToolset *CToolList::operator[](int iSet) const
  513. {
  514. return m_InternalList[iSet];
  515. }