543 lines
16 KiB
C++
543 lines
16 KiB
C++
//=============================================================================
|
|
// 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;
|
|
}
|