//============================================================================= // The CMSInfoTool class encapsulates a tool (which can appear on the Tools // menu or as part of a context sensitive menu). //============================================================================= #include "stdafx.h" #include "msinfotool.h" #include "wmiabstraction.h" // Trick the resource.h include file into defining the _APS_NEXT_COMMAND_VALUE // symbol. We can use this to add menu items dynamically. #ifndef APSTUDIO_INVOKED #define APSTUDIO_INVOKED 1 #include "resource.h" #undef APSTUDIO_INVOKED #else #include "resource.h" #endif // An array of tools to be included (in addition to the registry tools). MSITOOLINFO aInitialToolset[] = { { IDS_CABCONTENTSNAME, 0, NULL, NULL, _T("explorer"), NULL, _T("%2") }, { IDS_DRWATSONNAME, 0, _T("%windir%\\system32\\drwtsn32.exe"), NULL, NULL, NULL, NULL }, { IDS_DXDIAGNAME, 0, _T("%windir%\\system32\\dxdiag.exe"), NULL, NULL, NULL, NULL }, { IDS_SIGVERIFNAME, 0, _T("%windir%\\system32\\sigverif.exe"), NULL, NULL, NULL, NULL }, { IDS_SYSTEMRESTNAME, 0, _T("%windir%\\system32\\restore\\rstrui.exe"), NULL, NULL, NULL, NULL }, { IDS_NETDIAGNAME, 0, _T("hcp://system/netdiag/dglogs.htm"), NULL, NULL, NULL, NULL }, { 0, 0, NULL, NULL, NULL, NULL, NULL } }; //----------------------------------------------------------------------------- // Check to see if the specified file (with path information) exists on // the machine. //----------------------------------------------------------------------------- BOOL FileExists(const CString & strFile) { WIN32_FIND_DATA finddata; HANDLE h = FindFirstFile(strFile, &finddata); if (INVALID_HANDLE_VALUE != h) { FindClose(h); return TRUE; } return FALSE; } //----------------------------------------------------------------------------- // Delete the map of tools. //----------------------------------------------------------------------------- void RemoveToolset(CMapWordToPtr & map) { WORD wCommand; CMSInfoTool * pTool; for (POSITION pos = map.GetStartPosition(); pos != NULL; ) { map.GetNextAssoc(pos, wCommand, (void * &) pTool); ASSERT(pTool); if (pTool) delete pTool; } map.RemoveAll(); } //----------------------------------------------------------------------------- // Load the map of tools from the specified registry location. This will be // called in the case when there is no CAB file open. // // If an HKEY is passed in, it should be open, and it will be closed when // the function is complete. //----------------------------------------------------------------------------- void LoadGlobalToolset(CMapWordToPtr & map, HKEY hkeyTools) { RemoveToolset(map); // This should automatically put us out of the range of any menu IDs // stored in the resources. CMSInfoTool * pTool; DWORD dwID = _APS_NEXT_COMMAND_VALUE; DWORD dwIndex = 0; // Load the tools out of the array built into the code. for (MSITOOLINFO * pInitialTool = aInitialToolset; pInitialTool->m_szCommand || pInitialTool->m_szCABCommand; pInitialTool++) { pTool = new CMSInfoTool; if (pTool) { if (pTool->LoadGlobalFromMSITOOLINFO(dwID, pInitialTool, FALSE)) { map.SetAt((WORD) dwID, (void *) pTool); dwID++; } else delete pTool; } } // Make sure we have an open handle for the tools section of the registry. HKEY hkeyBase = hkeyTools; if (hkeyBase == NULL) if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\Microsoft\\Shared Tools\\MSInfo\\Toolsets\\MSInfo"), 0, KEY_READ, &hkeyBase) != ERROR_SUCCESS) return; // Enumerate the subkeys of the tools key. HKEY hkeySub; DWORD dwChild = MAX_PATH; TCHAR szChild[MAX_PATH]; while (RegEnumKeyEx(hkeyBase, dwIndex++, szChild, &dwChild, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) { if (RegOpenKeyEx(hkeyBase, szChild, 0, KEY_READ, &hkeySub) == ERROR_SUCCESS) { pTool = new CMSInfoTool; if (pTool) { if (pTool->LoadGlobalFromRegistry(hkeySub, dwID, FALSE, map)) { map.SetAt((WORD) dwID, (void *) pTool); dwID++; } else delete pTool; } RegCloseKey(hkeySub); } dwChild = MAX_PATH; } RegCloseKey(hkeyBase); } //----------------------------------------------------------------------------- // Load the map of tools from the specified registry location. This will be // called in the case when there IS a CAB file open. // // If an HKEY is passed in, it should be open, and it will be closed when // the function is complete. //----------------------------------------------------------------------------- void LoadGlobalToolsetWithOpenCAB(CMapWordToPtr & map, LPCTSTR szCABDir, HKEY hkeyTools) { // This should automatically put us out of the range of any menu IDs // stored in the resources. RemoveToolset(map); CMSInfoTool * pTool; DWORD dwID = _APS_NEXT_COMMAND_VALUE; DWORD dwIndex = 0; // Load the tools out of the array built into the code. for (MSITOOLINFO * pInitialTool = aInitialToolset; pInitialTool->m_szCommand || pInitialTool->m_szCABCommand; pInitialTool++) { pTool = new CMSInfoTool; if (pTool) { if (pTool->LoadGlobalFromMSITOOLINFO(dwID, pInitialTool, TRUE)) { pTool->Replace(_T("%2"), szCABDir); map.SetAt((WORD) dwID, (void *) pTool); dwID++; } else delete pTool; } } // Make sure we have an open handle for the tools section of the registry. HKEY hkeyBase = hkeyTools; if (hkeyBase == NULL) if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\Microsoft\\Shared Tools\\MSInfo\\Tools"), 0, KEY_READ, &hkeyBase) != ERROR_SUCCESS) return; // Enumerate the subkeys of the tools key. HKEY hkeySub; DWORD dwChild = MAX_PATH; TCHAR szChild[MAX_PATH]; while (RegEnumKeyEx(hkeyBase, dwIndex++, szChild, &dwChild, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) { if (RegOpenKeyEx(hkeyBase, szChild, 0, KEY_READ, &hkeySub) == ERROR_SUCCESS) { pTool = new CMSInfoTool; if (pTool) { if (pTool->LoadGlobalFromRegistry(hkeySub, dwID, TRUE, map)) { pTool->Replace(_T("%2"), szCABDir); map.SetAt((WORD) dwID, (void *) pTool); dwID++; // If this tool is for CAB contents, and there is a cabextensions // string, then we want to look in the contents of the CAB for all // of the files with that extension. For each file we find, we should // insert a submenu item with the file name. CString strExtensions = pTool->GetCABExtensions(); if (!strExtensions.IsEmpty()) { CString strExtension = strExtensions; // TBD - allow for more than one CString strSearch(szCABDir); if (strSearch.Right(1) != CString(_T("\\"))) strSearch += _T("\\"); strSearch += CString(_T("*.")) + strExtension; WIN32_FIND_DATA finddata; HANDLE hFindFile = FindFirstFile(strSearch, &finddata); if (INVALID_HANDLE_VALUE != hFindFile) { do { CMSInfoTool * pSubTool = pTool->CloneTool(dwID, finddata.cFileName); if (pSubTool) { pSubTool->Replace(_T("%1"), finddata.cFileName); map.SetAt((WORD) dwID, (void *) pSubTool); dwID++; } } while (FindNextFile(hFindFile, &finddata)); FindClose(hFindFile); } } } else delete pTool; } RegCloseKey(hkeySub); } dwChild = MAX_PATH; } RegCloseKey(hkeyBase); } //----------------------------------------------------------------------------- // Check to see if the specified tool exists on this machine. //----------------------------------------------------------------------------- BOOL ToolExists(const CString & strTool, const CString & strParameters) { CString strWorking(strTool); // If the tool is MMC, we really want to look for the existence of // the parameter (the MSC file). CString strCheck(strTool); strCheck.MakeLower(); if (strCheck.Find(_T("\\mmc.exe")) != -1) strWorking = strParameters; // If the tool is actually a HSC page (it starts with "hcp:") then we need // to change it into a file path (converting forward slashes to backslashes) // and prepend the helpctr path. if (strCheck.Find(_T("hcp:")) == 0) { TCHAR szHelpCtrPath[MAX_PATH]; if (0 != ::ExpandEnvironmentStrings(_T("%windir%\\pchealth\\helpctr"), szHelpCtrPath, MAX_PATH)) { CString strHelpCtrPath(szHelpCtrPath); strWorking.Replace(_T("hcp://"), _T("\\")); strWorking.Replace(_T("/"), _T("\\")); strWorking = strHelpCtrPath + strWorking; } } if (strWorking.Find(_T("\\")) != -1) return (FileExists(strWorking)); // The command for the tool doesn't have path information in it. That // means we'll need to check all the directories in the path to see // if it exists. const DWORD dwBufferSize = MAX_PATH * 10; // TBD - figure out the actual max LPTSTR szPath = new TCHAR[dwBufferSize]; BOOL fFound = TRUE; // better to show the tool incorrectly if there's an error CString strCandidate; if (szPath && dwBufferSize > ExpandEnvironmentStrings(_T("%path%"), szPath, dwBufferSize)) { CString strPath(szPath); fFound = FALSE; while (!strPath.IsEmpty()) { strCandidate = strPath.SpanExcluding(_T(";")); if (strPath.GetLength() != strCandidate.GetLength()) strPath = strPath.Right(strPath.GetLength() - strCandidate.GetLength() - 1); else strPath.Empty(); if (strCandidate.Right(1) != CString(_T("\\"))) strCandidate += _T("\\"); strCandidate += strWorking; if (FileExists(strCandidate)) { fFound = TRUE; break; } } } if (szPath) delete [] szPath; return fFound; } //============================================================================= // CMSInfoTool Methods //============================================================================= //----------------------------------------------------------------------------- // Load this tool from the specified registry key. //----------------------------------------------------------------------------- BOOL CMSInfoTool::LoadGlobalFromRegistry(HKEY hkeyTool, DWORD dwID, BOOL fCABOpen, CMapWordToPtr & map) { TCHAR szBuffer[MAX_PATH]; DWORD dwType, dwSize; // Read in the values from the specified registry key. LPCTSTR aszValueNames[] = { _T(""), _T("command"), _T("description"), _T("parameters"), _T("cabcommand"), _T("cabextensions"), _T("cabparameters"), NULL }; CString * apstrValues[] = { &m_strName, &m_strCommand, &m_strDescription, &m_strParameters, &m_strCABCommand, &m_strCABExtension, &m_strCABParameters, NULL }; for (int i = 0; aszValueNames[i] && apstrValues[i]; i++) { dwSize = sizeof(TCHAR) * MAX_PATH; if (ERROR_SUCCESS == RegQueryValueEx(hkeyTool, aszValueNames[i], NULL, &dwType, (LPBYTE) szBuffer, &dwSize)) *(apstrValues[i]) = szBuffer; else { if (_tcscmp(aszValueNames[i], _T("parameters")) == 0) if (ERROR_SUCCESS == RegQueryValueEx(hkeyTool, _T("param"), NULL, &dwType, (LPBYTE) szBuffer, &dwSize)) *(apstrValues[i]) = szBuffer; } } m_dwID = dwID; if (m_strName.IsEmpty()) return FALSE; // Look for the name of this tool in the map (don't want to add it twice). CMSInfoTool * pTool; WORD wCommand; for (POSITION pos = map.GetStartPosition(); pos != NULL; ) { map.GetNextAssoc(pos, wCommand, (void * &) pTool); if (pTool && m_strName.CompareNoCase(pTool->m_strName) == 0) return FALSE; } // Special hack - don't include help center in the list of tools. CString strCommand(m_strCommand); strCommand.MakeLower(); if (strCommand.Find(_T("helpctr.exe")) != -1) return FALSE; // Another special hack - need explorer.exe, not just explorer. if (m_strCABCommand.CompareNoCase(_T("explorer")) == 0) m_strCABCommand = _T("explorer.exe"); // If a CAB has been opened, and there is a specific command for that // case, AND the command exists, then set the flag so we use that // command. // // Otherwise, check to see if the default command exists. m_fCABOpen = FALSE; if (fCABOpen && !m_strCABCommand.IsEmpty() && ToolExists(m_strCABCommand, m_strCABParameters)) m_fCABOpen = TRUE; else if (m_strCommand.IsEmpty() || !ToolExists(m_strCommand, m_strParameters)) return FALSE; return TRUE; } //----------------------------------------------------------------------------- // Load this tool from the specified registry key. //----------------------------------------------------------------------------- BOOL CMSInfoTool::LoadGlobalFromMSITOOLINFO(DWORD dwID, MSITOOLINFO * pTool, BOOL fCABOpen) { ASSERT(pTool); if (pTool == NULL) return FALSE; if (pTool->m_uiNameID != 0) m_strName.LoadString(pTool->m_uiNameID); else m_strName = pTool->m_szCommand; if (pTool->m_uiDescriptionID != 0) m_strDescription.LoadString(pTool->m_uiDescriptionID); else m_strDescription = pTool->m_szCommand; m_strCommand = pTool->m_szCommand; m_strParameters = pTool->m_szParams; m_strCABCommand = pTool->m_szCABCommand; m_strCABExtension = pTool->m_szCABExtension; m_strCABParameters = pTool->m_szCABParams; CString strCommand(m_strCommand); strCommand.MakeLower(); if (strCommand.Find(_T("%windir%")) != -1) { TCHAR szBuffer[MAX_PATH]; if (::ExpandEnvironmentStrings(m_strCommand, szBuffer, MAX_PATH)) m_strCommand = szBuffer; } m_dwID = dwID; if (m_strName.IsEmpty()) return FALSE; // Special hack - don't include help center in the list of tools. strCommand = m_strCommand; strCommand.MakeLower(); if (strCommand.Find(_T("helpctr.exe")) != -1) return FALSE; // Another special hack - need explorer.exe, not just explorer. if (m_strCABCommand.CompareNoCase(_T("explorer")) == 0) m_strCABCommand = _T("explorer.exe"); // If a CAB has been opened, and there is a specific command for that // case, AND the command exists, then set the flag so we use that // command. // // Otherwise, check to see if the default command exists. m_fCABOpen = FALSE; if (fCABOpen && !m_strCABCommand.IsEmpty() && ToolExists(m_strCABCommand, m_strCABParameters)) m_fCABOpen = TRUE; else if (m_strCommand.IsEmpty() || !ToolExists(m_strCommand, m_strParameters)) return FALSE; return TRUE; } //----------------------------------------------------------------------------- // Execute should actually launch this tool. //----------------------------------------------------------------------------- void CMSInfoTool::Execute() { if (m_fCABOpen) ShellExecute(NULL, NULL, m_strCABCommand, m_strCABParameters, NULL, SW_SHOWNORMAL); else ShellExecute(NULL, NULL, m_strCommand, m_strParameters, NULL, SW_SHOWNORMAL); } //----------------------------------------------------------------------------- // Replace is used to convert fields in the command and parameters to actual // values which make sense (i.e. "%2" is replaced with the CAB directory). //----------------------------------------------------------------------------- void CMSInfoTool::Replace(LPCTSTR szReplace, LPCTSTR szWith) { if (m_fCABOpen) { StringReplace(m_strCABCommand, szReplace, szWith); StringReplace(m_strCABParameters, szReplace, szWith); } } //----------------------------------------------------------------------------- // Make a copy of this tool, with the new ID. //----------------------------------------------------------------------------- CMSInfoTool * CMSInfoTool::CloneTool(DWORD dwID, LPCTSTR szName) { CMSInfoTool * pNewTool = new CMSInfoTool; if (pNewTool) { this->m_fHasSubitems = TRUE; pNewTool->m_dwID = dwID; pNewTool->m_dwParentID = this->GetID(); pNewTool->m_fCABOpen = this->m_fCABOpen; pNewTool->m_strName = szName; pNewTool->m_strCommand = this->m_strCommand; pNewTool->m_strDescription = this->m_strDescription; pNewTool->m_strParameters = this->m_strParameters; pNewTool->m_strCABCommand = this->m_strCABCommand; pNewTool->m_strCABExtension = this->m_strCABExtension; pNewTool->m_strCABParameters = this->m_strCABParameters; } return (pNewTool); } //----------------------------------------------------------------------------- // Create the tool explicitly (note - this has very limited use at this point). //----------------------------------------------------------------------------- void CMSInfoTool::Create(DWORD dwID, BOOL fCABOnly, LPCTSTR szName, LPCTSTR szCommand, LPCTSTR szDesc, LPCTSTR szParam, LPCTSTR szCABCommand, LPCTSTR szCABExt, LPCTSTR szCABParam) { m_dwID = dwID; m_fCABOpen = fCABOnly; m_strName = szName; m_strCommand = szCommand; m_strDescription = szDesc; m_strParameters = szParam; m_strCABCommand = szCABCommand; m_strCABExtension = szCABExt; m_strCABParameters = szCABParam; }