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.

542 lines
16 KiB

  1. //=============================================================================
  2. // The CMSInfoTool class encapsulates a tool (which can appear on the Tools
  3. // menu or as part of a context sensitive menu).
  4. //=============================================================================
  5. #include "stdafx.h"
  6. #include "msinfotool.h"
  7. #include "wmiabstraction.h"
  8. // Trick the resource.h include file into defining the _APS_NEXT_COMMAND_VALUE
  9. // symbol. We can use this to add menu items dynamically.
  10. #ifndef APSTUDIO_INVOKED
  11. #define APSTUDIO_INVOKED 1
  12. #include "resource.h"
  13. #undef APSTUDIO_INVOKED
  14. #else
  15. #include "resource.h"
  16. #endif
  17. // An array of tools to be included (in addition to the registry tools).
  18. MSITOOLINFO aInitialToolset[] =
  19. {
  20. { IDS_CABCONTENTSNAME, 0, NULL, NULL, _T("explorer"), NULL, _T("%2") },
  21. { IDS_DRWATSONNAME, 0, _T("%windir%\\system32\\drwtsn32.exe"), NULL, NULL, NULL, NULL },
  22. { IDS_DXDIAGNAME, 0, _T("%windir%\\system32\\dxdiag.exe"), NULL, NULL, NULL, NULL },
  23. { IDS_SIGVERIFNAME, 0, _T("%windir%\\system32\\sigverif.exe"), NULL, NULL, NULL, NULL },
  24. { IDS_SYSTEMRESTNAME, 0, _T("%windir%\\system32\\restore\\rstrui.exe"), NULL, NULL, NULL, NULL },
  25. { IDS_NETDIAGNAME, 0, _T("hcp://system/netdiag/dglogs.htm"), NULL, NULL, NULL, NULL },
  26. { 0, 0, NULL, NULL, NULL, NULL, NULL }
  27. };
  28. //-----------------------------------------------------------------------------
  29. // Check to see if the specified file (with path information) exists on
  30. // the machine.
  31. //-----------------------------------------------------------------------------
  32. BOOL FileExists(const CString & strFile)
  33. {
  34. WIN32_FIND_DATA finddata;
  35. HANDLE h = FindFirstFile(strFile, &finddata);
  36. if (INVALID_HANDLE_VALUE != h)
  37. {
  38. FindClose(h);
  39. return TRUE;
  40. }
  41. return FALSE;
  42. }
  43. //-----------------------------------------------------------------------------
  44. // Delete the map of tools.
  45. //-----------------------------------------------------------------------------
  46. void RemoveToolset(CMapWordToPtr & map)
  47. {
  48. WORD wCommand;
  49. CMSInfoTool * pTool;
  50. for (POSITION pos = map.GetStartPosition(); pos != NULL; )
  51. {
  52. map.GetNextAssoc(pos, wCommand, (void * &) pTool);
  53. ASSERT(pTool);
  54. if (pTool)
  55. delete pTool;
  56. }
  57. map.RemoveAll();
  58. }
  59. //-----------------------------------------------------------------------------
  60. // Load the map of tools from the specified registry location. This will be
  61. // called in the case when there is no CAB file open.
  62. //
  63. // If an HKEY is passed in, it should be open, and it will be closed when
  64. // the function is complete.
  65. //-----------------------------------------------------------------------------
  66. void LoadGlobalToolset(CMapWordToPtr & map, HKEY hkeyTools)
  67. {
  68. RemoveToolset(map);
  69. // This should automatically put us out of the range of any menu IDs
  70. // stored in the resources.
  71. CMSInfoTool * pTool;
  72. DWORD dwID = _APS_NEXT_COMMAND_VALUE;
  73. DWORD dwIndex = 0;
  74. // Load the tools out of the array built into the code.
  75. for (MSITOOLINFO * pInitialTool = aInitialToolset; pInitialTool->m_szCommand || pInitialTool->m_szCABCommand; pInitialTool++)
  76. {
  77. pTool = new CMSInfoTool;
  78. if (pTool)
  79. {
  80. if (pTool->LoadGlobalFromMSITOOLINFO(dwID, pInitialTool, FALSE))
  81. {
  82. map.SetAt((WORD) dwID, (void *) pTool);
  83. dwID++;
  84. }
  85. else
  86. delete pTool;
  87. }
  88. }
  89. // Make sure we have an open handle for the tools section of the registry.
  90. HKEY hkeyBase = hkeyTools;
  91. if (hkeyBase == NULL)
  92. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\Microsoft\\Shared Tools\\MSInfo\\Toolsets\\MSInfo"), 0, KEY_READ, &hkeyBase) != ERROR_SUCCESS)
  93. return;
  94. // Enumerate the subkeys of the tools key.
  95. HKEY hkeySub;
  96. DWORD dwChild = MAX_PATH;
  97. TCHAR szChild[MAX_PATH];
  98. while (RegEnumKeyEx(hkeyBase, dwIndex++, szChild, &dwChild, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
  99. {
  100. if (RegOpenKeyEx(hkeyBase, szChild, 0, KEY_READ, &hkeySub) == ERROR_SUCCESS)
  101. {
  102. pTool = new CMSInfoTool;
  103. if (pTool)
  104. {
  105. if (pTool->LoadGlobalFromRegistry(hkeySub, dwID, FALSE, map))
  106. {
  107. map.SetAt((WORD) dwID, (void *) pTool);
  108. dwID++;
  109. }
  110. else
  111. delete pTool;
  112. }
  113. RegCloseKey(hkeySub);
  114. }
  115. dwChild = MAX_PATH;
  116. }
  117. RegCloseKey(hkeyBase);
  118. }
  119. //-----------------------------------------------------------------------------
  120. // Load the map of tools from the specified registry location. This will be
  121. // called in the case when there IS a CAB file open.
  122. //
  123. // If an HKEY is passed in, it should be open, and it will be closed when
  124. // the function is complete.
  125. //-----------------------------------------------------------------------------
  126. void LoadGlobalToolsetWithOpenCAB(CMapWordToPtr & map, LPCTSTR szCABDir, HKEY hkeyTools)
  127. {
  128. // This should automatically put us out of the range of any menu IDs
  129. // stored in the resources.
  130. RemoveToolset(map);
  131. CMSInfoTool * pTool;
  132. DWORD dwID = _APS_NEXT_COMMAND_VALUE;
  133. DWORD dwIndex = 0;
  134. // Load the tools out of the array built into the code.
  135. for (MSITOOLINFO * pInitialTool = aInitialToolset; pInitialTool->m_szCommand || pInitialTool->m_szCABCommand; pInitialTool++)
  136. {
  137. pTool = new CMSInfoTool;
  138. if (pTool)
  139. {
  140. if (pTool->LoadGlobalFromMSITOOLINFO(dwID, pInitialTool, TRUE))
  141. {
  142. pTool->Replace(_T("%2"), szCABDir);
  143. map.SetAt((WORD) dwID, (void *) pTool);
  144. dwID++;
  145. }
  146. else
  147. delete pTool;
  148. }
  149. }
  150. // Make sure we have an open handle for the tools section of the registry.
  151. HKEY hkeyBase = hkeyTools;
  152. if (hkeyBase == NULL)
  153. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\Microsoft\\Shared Tools\\MSInfo\\Tools"), 0, KEY_READ, &hkeyBase) != ERROR_SUCCESS)
  154. return;
  155. // Enumerate the subkeys of the tools key.
  156. HKEY hkeySub;
  157. DWORD dwChild = MAX_PATH;
  158. TCHAR szChild[MAX_PATH];
  159. while (RegEnumKeyEx(hkeyBase, dwIndex++, szChild, &dwChild, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
  160. {
  161. if (RegOpenKeyEx(hkeyBase, szChild, 0, KEY_READ, &hkeySub) == ERROR_SUCCESS)
  162. {
  163. pTool = new CMSInfoTool;
  164. if (pTool)
  165. {
  166. if (pTool->LoadGlobalFromRegistry(hkeySub, dwID, TRUE, map))
  167. {
  168. pTool->Replace(_T("%2"), szCABDir);
  169. map.SetAt((WORD) dwID, (void *) pTool);
  170. dwID++;
  171. // If this tool is for CAB contents, and there is a cabextensions
  172. // string, then we want to look in the contents of the CAB for all
  173. // of the files with that extension. For each file we find, we should
  174. // insert a submenu item with the file name.
  175. CString strExtensions = pTool->GetCABExtensions();
  176. if (!strExtensions.IsEmpty())
  177. {
  178. CString strExtension = strExtensions; // TBD - allow for more than one
  179. CString strSearch(szCABDir);
  180. if (strSearch.Right(1) != CString(_T("\\")))
  181. strSearch += _T("\\");
  182. strSearch += CString(_T("*.")) + strExtension;
  183. WIN32_FIND_DATA finddata;
  184. HANDLE hFindFile = FindFirstFile(strSearch, &finddata);
  185. if (INVALID_HANDLE_VALUE != hFindFile)
  186. {
  187. do
  188. {
  189. CMSInfoTool * pSubTool = pTool->CloneTool(dwID, finddata.cFileName);
  190. if (pSubTool)
  191. {
  192. pSubTool->Replace(_T("%1"), finddata.cFileName);
  193. map.SetAt((WORD) dwID, (void *) pSubTool);
  194. dwID++;
  195. }
  196. } while (FindNextFile(hFindFile, &finddata));
  197. FindClose(hFindFile);
  198. }
  199. }
  200. }
  201. else
  202. delete pTool;
  203. }
  204. RegCloseKey(hkeySub);
  205. }
  206. dwChild = MAX_PATH;
  207. }
  208. RegCloseKey(hkeyBase);
  209. }
  210. //-----------------------------------------------------------------------------
  211. // Check to see if the specified tool exists on this machine.
  212. //-----------------------------------------------------------------------------
  213. BOOL ToolExists(const CString & strTool, const CString & strParameters)
  214. {
  215. CString strWorking(strTool);
  216. // If the tool is MMC, we really want to look for the existence of
  217. // the parameter (the MSC file).
  218. CString strCheck(strTool);
  219. strCheck.MakeLower();
  220. if (strCheck.Find(_T("\\mmc.exe")) != -1)
  221. strWorking = strParameters;
  222. // If the tool is actually a HSC page (it starts with "hcp:") then we need
  223. // to change it into a file path (converting forward slashes to backslashes)
  224. // and prepend the helpctr path.
  225. if (strCheck.Find(_T("hcp:")) == 0)
  226. {
  227. TCHAR szHelpCtrPath[MAX_PATH];
  228. if (0 != ::ExpandEnvironmentStrings(_T("%windir%\\pchealth\\helpctr"), szHelpCtrPath, MAX_PATH))
  229. {
  230. CString strHelpCtrPath(szHelpCtrPath);
  231. strWorking.Replace(_T("hcp://"), _T("\\"));
  232. strWorking.Replace(_T("/"), _T("\\"));
  233. strWorking = strHelpCtrPath + strWorking;
  234. }
  235. }
  236. if (strWorking.Find(_T("\\")) != -1)
  237. return (FileExists(strWorking));
  238. // The command for the tool doesn't have path information in it. That
  239. // means we'll need to check all the directories in the path to see
  240. // if it exists.
  241. const DWORD dwBufferSize = MAX_PATH * 10; // TBD - figure out the actual max
  242. LPTSTR szPath = new TCHAR[dwBufferSize];
  243. BOOL fFound = TRUE; // better to show the tool incorrectly if there's an error
  244. CString strCandidate;
  245. if (szPath && dwBufferSize > ExpandEnvironmentStrings(_T("%path%"), szPath, dwBufferSize))
  246. {
  247. CString strPath(szPath);
  248. fFound = FALSE;
  249. while (!strPath.IsEmpty())
  250. {
  251. strCandidate = strPath.SpanExcluding(_T(";"));
  252. if (strPath.GetLength() != strCandidate.GetLength())
  253. strPath = strPath.Right(strPath.GetLength() - strCandidate.GetLength() - 1);
  254. else
  255. strPath.Empty();
  256. if (strCandidate.Right(1) != CString(_T("\\")))
  257. strCandidate += _T("\\");
  258. strCandidate += strWorking;
  259. if (FileExists(strCandidate))
  260. {
  261. fFound = TRUE;
  262. break;
  263. }
  264. }
  265. }
  266. if (szPath)
  267. delete [] szPath;
  268. return fFound;
  269. }
  270. //=============================================================================
  271. // CMSInfoTool Methods
  272. //=============================================================================
  273. //-----------------------------------------------------------------------------
  274. // Load this tool from the specified registry key.
  275. //-----------------------------------------------------------------------------
  276. BOOL CMSInfoTool::LoadGlobalFromRegistry(HKEY hkeyTool, DWORD dwID, BOOL fCABOpen, CMapWordToPtr & map)
  277. {
  278. TCHAR szBuffer[MAX_PATH];
  279. DWORD dwType, dwSize;
  280. // Read in the values from the specified registry key.
  281. LPCTSTR aszValueNames[] = { _T(""), _T("command"), _T("description"), _T("parameters"), _T("cabcommand"), _T("cabextensions"), _T("cabparameters"), NULL };
  282. CString * apstrValues[] = { &m_strName, &m_strCommand, &m_strDescription, &m_strParameters, &m_strCABCommand, &m_strCABExtension, &m_strCABParameters, NULL };
  283. for (int i = 0; aszValueNames[i] && apstrValues[i]; i++)
  284. {
  285. dwSize = sizeof(TCHAR) * MAX_PATH;
  286. if (ERROR_SUCCESS == RegQueryValueEx(hkeyTool, aszValueNames[i], NULL, &dwType, (LPBYTE) szBuffer, &dwSize))
  287. *(apstrValues[i]) = szBuffer;
  288. else
  289. {
  290. if (_tcscmp(aszValueNames[i], _T("parameters")) == 0)
  291. if (ERROR_SUCCESS == RegQueryValueEx(hkeyTool, _T("param"), NULL, &dwType, (LPBYTE) szBuffer, &dwSize))
  292. *(apstrValues[i]) = szBuffer;
  293. }
  294. }
  295. m_dwID = dwID;
  296. if (m_strName.IsEmpty())
  297. return FALSE;
  298. // Look for the name of this tool in the map (don't want to add it twice).
  299. CMSInfoTool * pTool;
  300. WORD wCommand;
  301. for (POSITION pos = map.GetStartPosition(); pos != NULL; )
  302. {
  303. map.GetNextAssoc(pos, wCommand, (void * &) pTool);
  304. if (pTool && m_strName.CompareNoCase(pTool->m_strName) == 0)
  305. return FALSE;
  306. }
  307. // Special hack - don't include help center in the list of tools.
  308. CString strCommand(m_strCommand);
  309. strCommand.MakeLower();
  310. if (strCommand.Find(_T("helpctr.exe")) != -1)
  311. return FALSE;
  312. // Another special hack - need explorer.exe, not just explorer.
  313. if (m_strCABCommand.CompareNoCase(_T("explorer")) == 0)
  314. m_strCABCommand = _T("explorer.exe");
  315. // If a CAB has been opened, and there is a specific command for that
  316. // case, AND the command exists, then set the flag so we use that
  317. // command.
  318. //
  319. // Otherwise, check to see if the default command exists.
  320. m_fCABOpen = FALSE;
  321. if (fCABOpen && !m_strCABCommand.IsEmpty() && ToolExists(m_strCABCommand, m_strCABParameters))
  322. m_fCABOpen = TRUE;
  323. else if (m_strCommand.IsEmpty() || !ToolExists(m_strCommand, m_strParameters))
  324. return FALSE;
  325. return TRUE;
  326. }
  327. //-----------------------------------------------------------------------------
  328. // Load this tool from the specified registry key.
  329. //-----------------------------------------------------------------------------
  330. BOOL CMSInfoTool::LoadGlobalFromMSITOOLINFO(DWORD dwID, MSITOOLINFO * pTool, BOOL fCABOpen)
  331. {
  332. ASSERT(pTool);
  333. if (pTool == NULL)
  334. return FALSE;
  335. if (pTool->m_uiNameID != 0)
  336. m_strName.LoadString(pTool->m_uiNameID);
  337. else
  338. m_strName = pTool->m_szCommand;
  339. if (pTool->m_uiDescriptionID != 0)
  340. m_strDescription.LoadString(pTool->m_uiDescriptionID);
  341. else
  342. m_strDescription = pTool->m_szCommand;
  343. m_strCommand = pTool->m_szCommand;
  344. m_strParameters = pTool->m_szParams;
  345. m_strCABCommand = pTool->m_szCABCommand;
  346. m_strCABExtension = pTool->m_szCABExtension;
  347. m_strCABParameters = pTool->m_szCABParams;
  348. CString strCommand(m_strCommand);
  349. strCommand.MakeLower();
  350. if (strCommand.Find(_T("%windir%")) != -1)
  351. {
  352. TCHAR szBuffer[MAX_PATH];
  353. if (::ExpandEnvironmentStrings(m_strCommand, szBuffer, MAX_PATH))
  354. m_strCommand = szBuffer;
  355. }
  356. m_dwID = dwID;
  357. if (m_strName.IsEmpty())
  358. return FALSE;
  359. // Special hack - don't include help center in the list of tools.
  360. strCommand = m_strCommand;
  361. strCommand.MakeLower();
  362. if (strCommand.Find(_T("helpctr.exe")) != -1)
  363. return FALSE;
  364. // Another special hack - need explorer.exe, not just explorer.
  365. if (m_strCABCommand.CompareNoCase(_T("explorer")) == 0)
  366. m_strCABCommand = _T("explorer.exe");
  367. // If a CAB has been opened, and there is a specific command for that
  368. // case, AND the command exists, then set the flag so we use that
  369. // command.
  370. //
  371. // Otherwise, check to see if the default command exists.
  372. m_fCABOpen = FALSE;
  373. if (fCABOpen && !m_strCABCommand.IsEmpty() && ToolExists(m_strCABCommand, m_strCABParameters))
  374. m_fCABOpen = TRUE;
  375. else if (m_strCommand.IsEmpty() || !ToolExists(m_strCommand, m_strParameters))
  376. return FALSE;
  377. return TRUE;
  378. }
  379. //-----------------------------------------------------------------------------
  380. // Execute should actually launch this tool.
  381. //-----------------------------------------------------------------------------
  382. void CMSInfoTool::Execute()
  383. {
  384. if (m_fCABOpen)
  385. ShellExecute(NULL, NULL, m_strCABCommand, m_strCABParameters, NULL, SW_SHOWNORMAL);
  386. else
  387. ShellExecute(NULL, NULL, m_strCommand, m_strParameters, NULL, SW_SHOWNORMAL);
  388. }
  389. //-----------------------------------------------------------------------------
  390. // Replace is used to convert fields in the command and parameters to actual
  391. // values which make sense (i.e. "%2" is replaced with the CAB directory).
  392. //-----------------------------------------------------------------------------
  393. void CMSInfoTool::Replace(LPCTSTR szReplace, LPCTSTR szWith)
  394. {
  395. if (m_fCABOpen)
  396. {
  397. StringReplace(m_strCABCommand, szReplace, szWith);
  398. StringReplace(m_strCABParameters, szReplace, szWith);
  399. }
  400. }
  401. //-----------------------------------------------------------------------------
  402. // Make a copy of this tool, with the new ID.
  403. //-----------------------------------------------------------------------------
  404. CMSInfoTool * CMSInfoTool::CloneTool(DWORD dwID, LPCTSTR szName)
  405. {
  406. CMSInfoTool * pNewTool = new CMSInfoTool;
  407. if (pNewTool)
  408. {
  409. this->m_fHasSubitems = TRUE;
  410. pNewTool->m_dwID = dwID;
  411. pNewTool->m_dwParentID = this->GetID();
  412. pNewTool->m_fCABOpen = this->m_fCABOpen;
  413. pNewTool->m_strName = szName;
  414. pNewTool->m_strCommand = this->m_strCommand;
  415. pNewTool->m_strDescription = this->m_strDescription;
  416. pNewTool->m_strParameters = this->m_strParameters;
  417. pNewTool->m_strCABCommand = this->m_strCABCommand;
  418. pNewTool->m_strCABExtension = this->m_strCABExtension;
  419. pNewTool->m_strCABParameters = this->m_strCABParameters;
  420. }
  421. return (pNewTool);
  422. }
  423. //-----------------------------------------------------------------------------
  424. // Create the tool explicitly (note - this has very limited use at this point).
  425. //-----------------------------------------------------------------------------
  426. void CMSInfoTool::Create(DWORD dwID, BOOL fCABOnly, LPCTSTR szName, LPCTSTR szCommand, LPCTSTR szDesc, LPCTSTR szParam, LPCTSTR szCABCommand, LPCTSTR szCABExt, LPCTSTR szCABParam)
  427. {
  428. m_dwID = dwID;
  429. m_fCABOpen = fCABOnly;
  430. m_strName = szName;
  431. m_strCommand = szCommand;
  432. m_strDescription = szDesc;
  433. m_strParameters = szParam;
  434. m_strCABCommand = szCABCommand;
  435. m_strCABExtension = szCABExt;
  436. m_strCABParameters = szCABParam;
  437. }