windows-nt/Source/XPSP1/NT/enduser/troubleshoot/msinfo/toolset.cpp
2020-09-26 16:20:57 +08:00

601 lines
16 KiB
C++

// Toolset.cpp - Classes to manage the tools menu.
//
// Copyright (c) 1998-1999 Microsoft Corporation
#include <process.h>
#include "StdAfx.h"
#include "Toolset.h"
#include "DataObj.h"
#include "CompData.h"
#include <atlbase.h>
#include "Resource.h"
#include "resrc1.h"
#include "msicab.h"
#ifdef _UNICODE
#define _tspawnl _wspawnl
#else
#define _tspawnl _spawnl
#endif
const unsigned KEY_SIZE = MAX_PATH;
const unsigned CToolset::MAXIMUM_TOOLS = 256;
LPCTSTR cszRoot = _T("Software\\Microsoft\\Shared Tools\\MSInfo");
LPCTSTR cszToolsetKey = _T("ToolSets");
LPCTSTR cszMSInfoRoot = _T("Software\\Microsoft\\Shared Tools\\MSInfo\\ToolSets");
LPCTSTR cszMSInfoCommandKey = _T("command");
LPCTSTR cszMSInfoParamKey = _T("param");
LPCTSTR cszMSInfoDescriptionKey = _T("description");
LPCTSTR cszSystemPolicyKey = _T("Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer");
LPCTSTR cszRunKey = _T("NoRun");
LPCTSTR cszDefaultToolsetKey = _T("MSInfo");
LPCTSTR cszExplorerSubPath = _T("\\explorer.exe");
LPCTSTR cszAppletExtension = _T(".cpl");
LPCTSTR cszSnapinExtension = _T(".msc");
/*
* CTool - Construct from the registry.
*
* History: a-jsari 11/11/97 Initial version.
*/
CTool::CTool(CRegKey * pKeyTool) : m_strName(_T("")), m_strPath(_T("")), m_strParam(_T("")), m_strDescription(_T("")), m_fValid(TRUE)
{
if (pKeyTool == NULL)
return;
TCHAR szBuffer[MAX_PATH];
DWORD dwSize;
dwSize = MAX_PATH;
if (pKeyTool->QueryValue(szBuffer, NULL, &dwSize) == ERROR_SUCCESS)
m_strName = szBuffer;
dwSize = MAX_PATH;
if (pKeyTool->QueryValue(szBuffer, cszMSInfoCommandKey, &dwSize) == ERROR_SUCCESS)
m_strPath = szBuffer;
dwSize = MAX_PATH;
if (pKeyTool->QueryValue(szBuffer, cszMSInfoParamKey, &dwSize) == ERROR_SUCCESS)
m_strParam = szBuffer;
dwSize = MAX_PATH;
if (pKeyTool->QueryValue(szBuffer, cszMSInfoDescriptionKey, &dwSize) == ERROR_SUCCESS)
m_strDescription = szBuffer;
m_fValid = PathExists();
}
/*
* operator= - Assignment operator, used to assign CTools to the CToolset array.
*
* History: a-jsari 11/11/97 Initial version
*/
const CTool &CTool::operator=(const CTool &toolCopy)
{
if (&toolCopy != this) {
m_strName = toolCopy.m_strName;
m_strPath = toolCopy.m_strPath;
m_strDescription = toolCopy.m_strDescription;
m_fValid = toolCopy.m_fValid;
}
return *this;
}
//-----------------------------------------------------------------------------
// PathExists - Return a flag specifying whether we can access the path
// to our executable, excluding any parameters.
//-----------------------------------------------------------------------------
BOOL CTool::PathExists() const
{
// First, we'll look for the command, to see if that file exists.
if (::_taccess((LPCTSTR)m_strPath, A_READ) != 0)
return FALSE;
// Also, the parameter value might contain a file (like a control
// panel or an MSC snap-in file) we should check for. We need to get
// a little bit kludgy here - if the param part ends with a CPL or
// MSC extension, then back up in the string, so we can check for
// the existence of that file.
if (m_strParam.Right(4).CompareNoCase(cszAppletExtension) == 0 || m_strParam.Right(4).CompareNoCase(cszSnapinExtension) == 0)
{
LPCTSTR szFile = ::_tcsrchr((LPCTSTR)m_strParam, (TCHAR)' ');
if (szFile)
szFile++; // advance past the space
else
szFile = (LPCTSTR)m_strParam;
if (szFile && ::_taccess(szFile, A_READ) != 0)
return FALSE;
}
return TRUE;
}
//-----------------------------------------------------------------------------
// RunTool - Spawn a process executing the current tool.
//-----------------------------------------------------------------------------
HRESULT CTool::RunTool()
{
AFX_MANAGE_STATE(::AfxGetStaticModuleState());
if (PolicyPermitRun() == FALSE)
{
CString strMessage;
strMessage.LoadString(IDS_POLICYFORBIDSRUN);
return S_OK;
}
LPCTSTR cszPath = GetPath();
LPCTSTR cszParam = GetParam();
if (msiLog.IsLogging())
msiLog.WriteLog(CMSInfoLog::TOOL, _T("TOOL \"%s\"\r\n"), m_strName);
intptr_t hProcess;
if (cszParam && *cszParam)
hProcess = ::_tspawnl(_P_NOWAIT, cszPath, cszPath, cszParam, NULL);
else
hProcess = ::_tspawnl(_P_NOWAIT, cszPath, cszPath, NULL);
if (hProcess < 0)
{
CString strMessage;
strMessage.Format(IDS_NOPATH, cszPath);
return E_UNEXPECTED;
}
return S_OK;
}
/*
* PolicyPermitRun - returns a BOOLEAN value which determines whether
*
* History: ericflo 11/21/97 Boilerplate version
* a-jsari 11/21/97 Initial edits
*/
BOOL CTool::PolicyPermitRun()
{
HKEY hKeyPolicy;
BOOL bReturn = TRUE;
DWORD dwSize, dwData, dwType;
// Explorer\\NoRun == 1
do {
if (RegOpenKeyEx (HKEY_CURRENT_USER, cszSystemPolicyKey, 0,
KEY_READ, &hKeyPolicy) == ERROR_SUCCESS) {
dwSize = sizeof(dwData);
if (RegQueryValueEx(hKeyPolicy, cszRunKey, NULL, &dwType,
(LPBYTE) &dwData, &dwSize) != ERROR_SUCCESS) break;
RegCloseKey (hKeyPolicy);
// I'm not sure which type this value is, so make an assumption.
switch (dwType) {
case REG_DWORD:
if (dwData == 1)
bReturn = FALSE;
break;
default:
// We are assuming the wrong value type.
ASSERT(FALSE);
break;
}
}
} while (FALSE);
return bReturn;
}
/*
* CCabTool - Construct the Cab explosion item.
*
* History: a-jsari 3/25/98 Initial version.
*/
CCabTool::CCabTool(CSystemInfoScope *pScope)
:m_pScope(pScope)
{
TCHAR szBuffer[MAX_PATH + 1];
UINT uSize = MAX_PATH;
AFX_MANAGE_STATE(::AfxGetStaticModuleState());
m_strName.LoadString(IDS_CAB_NAME);
m_strDescription.LoadString(IDS_CAB_DESCRIPTION);
VERIFY(GetWindowsDirectory(szBuffer, uSize));
m_strPath = szBuffer;
m_strPath += cszExplorerSubPath;
}
/*
* IsValid - Determine whether we have opened a CAB to explode.
*
* History: a-jsari 3/25/98 Initial version.
*/
BOOL CCabTool::IsValid() const
{
if (m_pScope == NULL || m_pScope->pSource() == NULL || m_pScope->pSource()->GetType() == CDataSource::GATHERER)
return FALSE;
if (!PathExists()) return FALSE;
return reinterpret_cast<CBufferDataSource *>(m_pScope->pSource())->HasCAB();
}
/*
* GetPath - Return the path to explorer with the CAB directory.
*
* History: a-jsari 3/25/98 Initial version.
*/
const CString &CCabTool::GetPath()
{
TCHAR szBuffer[MAX_PATH + 1];
UINT uSize = MAX_PATH;
VERIFY(GetWindowsDirectory(szBuffer, uSize));
m_strPath = (LPTSTR)szBuffer;
m_strPath += cszExplorerSubPath;
return m_strPath;
}
const CString &CCabTool::GetParam()
{
if (m_strParam.IsEmpty())
::GetCABExplodeDir(m_strParam, FALSE, CString(_T("")));
return m_strParam;
}
BOOL CToolset::s_fCabAdded = FALSE;
/*
* CToolset - Construct a toolset, reading the tools from the Registry key.
*
* History: a-jsari 11/6/97 Initial version
*/
CToolset::CToolset(CSystemInfoScope *pScope, CRegKey *pKeySet, CString *pstrName)
:m_pPopup(NULL)
{
CRegKey keySub;
if (pKeySet) {
long lResult;
do {
if (pstrName != NULL) {
// szName represents the name of a subkey to open.
lResult = keySub.Open(*pKeySet, *pstrName, KEY_READ);
ASSERT(lResult == ERROR_SUCCESS);
if (lResult != ERROR_SUCCESS) break;
}
DWORD dwSize;
TCHAR szBuffer[KEY_SIZE];
CRegKey keyTool;
FILETIME keyTime;
dwSize = sizeof(szBuffer);
keySub.QueryValue(szBuffer, NULL, &dwSize);
m_strName = szBuffer;
for (DWORD iTool = 0 ; ; ++iTool) {
//dwSize = sizeof(szBuffer);
dwSize = sizeof(szBuffer) / sizeof(TCHAR);
lResult = RegEnumKeyEx(keySub, iTool, szBuffer, &dwSize, NULL /* reserved */,
NULL /* class */, NULL /* class size */, &keyTime);
if (lResult == ERROR_NO_MORE_ITEMS) break;
// Hard limit of 256 tools per set.
if (iTool == MAXIMUM_TOOLS) break;
ASSERT(lResult == ERROR_SUCCESS);
if (lResult != ERROR_SUCCESS) break;
lResult = keyTool.Open(keySub, szBuffer, KEY_QUERY_VALUE);
if (lResult != ERROR_SUCCESS) break;
CTool *toolNew = new CTool(&keyTool);
m_Tools.SetAtGrow(iTool, toolNew);
}
if (!s_fCabAdded) {
CTool *pTool = new CCabTool(pScope);
s_fCabAdded = TRUE;
m_Tools.SetAtGrow(iTool, pTool);
}
} while (FALSE);
}
}
/*
* ~CToolset - Delete our objects.
*
* History: a-jsari 11/6/97 Initial version
*/
CToolset::~CToolset()
{
delete m_pPopup;
unsigned iTool = (unsigned)m_Tools.GetSize();
while (iTool--) {
delete m_Tools[iTool];
}
}
/*
* operator= - Set one toolset equal to another (for list insertion).
*
* History: a-jsari 11/6/97 Initial version
*/
const CToolset &CToolset::operator=(const CToolset &tCopy)
{
if (this != &tCopy) {
m_strName = tCopy.m_strName;
m_Tools.Copy(tCopy.m_Tools);
}
return *this;
}
/*
* AddToMenu - Add an item to the specified menu; set the CommandID to allow us to find
* the correct menu item.
*
* History: a-jsari 11/6/97 Initial version
*/
HRESULT CToolset::AddToMenu(unsigned long iSet, CMenu *pMenu)
{
m_pPopup = new CMenu;
if (m_pPopup == NULL) ::AfxThrowMemoryException();
m_pPopup->CreatePopupMenu();
UINT iTool = GetToolCount();
UINT iSetCount = 0;
while (iTool) {
// Decrement the tool after we have set the command, so that the command ID
// is equal to the set or'd with the Tool + 1.
UINT wCommand = iSet | (iTool--);
// Don't add a menu item for a
if (m_Tools[iTool]->IsValid()) {
++iSetCount;
VERIFY(m_pPopup->InsertMenu(0, MF_BYPOSITION | MF_STRING, wCommand, m_Tools[iTool]->GetName()));
} else {
; // Log an error message!
}
}
// Only add the sub-menu if there was at least one valid menu item.
if (iSetCount > 0)
pMenu->AppendMenu(MF_POPUP | MF_STRING, (UINT_PTR)m_pPopup->GetSafeHmenu(), m_strName);
return S_OK;
}
/*
* CToolList - Read the list of tools from the registry.
*
* History: a-jsari 11/6/97 Initial version.
*/
CToolList::CToolList(CSystemInfoScope *pScope)
:m_pMainPopup(NULL)
{
CRegKey crkToolRoot;
TCHAR szToolsetName[MAX_PATH];
CString szObject;
DWORD dwSize;
long lResult;
FILETIME keyTime;
lResult = crkToolRoot.Open(HKEY_LOCAL_MACHINE, cszMSInfoRoot, KEY_READ);
if (lResult != ERROR_SUCCESS) {
lResult = Register(TRUE);
if (lResult != ERROR_SUCCESS) return;
lResult = crkToolRoot.Open(HKEY_LOCAL_MACHINE, cszMSInfoRoot, KEY_READ);
ASSERT(lResult == ERROR_SUCCESS);
if (lResult != ERROR_SUCCESS) return;
}
for (DWORD iKey = 0 ; ; ++iKey) {
//dwSize = sizeof(szToolsetName);
dwSize = sizeof(szToolsetName) / sizeof(TCHAR);
lResult = RegEnumKeyEx(crkToolRoot, iKey, szToolsetName, &dwSize, NULL /* reserved */,
NULL /* class */, NULL /* class size */, &keyTime);
if (lResult == ERROR_NO_MORE_ITEMS) break;
szObject = szToolsetName;
CToolset *setNew = new CToolset(pScope, &crkToolRoot, &szObject);
Add(setNew);
}
}
/*
* ~CToolList - Delete our saved pop-up menu.
*
* History: a-jsari 11/6/97 Initial version
*/
CToolList::~CToolList()
{
delete m_pMainPopup;
unsigned iToolset = (unsigned)m_InternalList.GetSize();
while (iToolset--) {
delete m_InternalList[iToolset];
}
}
/*
* Add - Add an element to the end of the internal list.
*
* History: a-jsari 11/11/97 Initial version
*/
void CToolList::Add(CToolset *toolSet)
{
m_InternalList.Add(toolSet);
}
/*
* AddToMenu - Create our popup menu and add all of the sub-menus of each toolset
* to it.
*
* History: a-jsari 11/6/97 Initial version.
*/
HRESULT CToolList::AddToMenu(CMenu *pMenu)
{
// HRESULT hResult;
// CToolset eSet;
unsigned int ulMask; // To identify Toolset from the list for the CommandID.
unsigned cList;
m_pMainPopup = new CMenu;
if (m_pMainPopup == NULL) ::AfxThrowMemoryException();
m_pMainPopup->CreatePopupMenu();
cList = (unsigned)m_InternalList.GetSize();
for (ulMask = 0 ; ulMask < cList ; ++ulMask) {
// ulMask << 16 is or'd into the lCommand to represent the Toolset number.
HRESULT hResult = m_InternalList[ulMask]->AddToMenu(ulMask << 8, m_pMainPopup);
if (FAILED(hResult)) return hResult;
}
pMenu->AppendMenu(MF_POPUP | MF_STRING, (UINT_PTR) m_pMainPopup->GetSafeHmenu(), _T(""));
return S_OK;
}
//-----------------------------------------------------------------------------
// Register (or unregister) the tools which show up in the MSInfo tools menu.
// The tools are stored in a string resource, which we should process here
// to create the registry entries.
//
// Under the toolset registry entry, each tool will have a key. Values under
// the key will be:
//
// <default> Name of the tool, to appear in menu (may be localized).
// commnd Command line for tool.
// param Parameter for the tool.
//-----------------------------------------------------------------------------
long CToolList::Register(BOOL fRegister)
{
long lResult;
CRegKey crkToolsetRoot;
// If unregistering - recursively delete the ToolSets key under
// HKEY_LOCAL_MACHINE\Software\Microsoft\Shared Tools\MSInfo.
if (!fRegister)
{
lResult = crkToolsetRoot.Open(HKEY_LOCAL_MACHINE, cszRoot);
if (lResult != ERROR_SUCCESS)
return lResult;
return crkToolsetRoot.RecurseDeleteKey(cszToolsetKey);
}
AFX_MANAGE_STATE(::AfxGetStaticModuleState());
CRegKey crkNewToolset, crkTool;
CString strKeyValue;
// Create ToolSets key.
lResult = crkToolsetRoot.Create(HKEY_LOCAL_MACHINE, cszMSInfoRoot);
if (lResult != ERROR_SUCCESS)
return lResult;
// Delete anything which might already be under the MSInfo subkey.
lResult = crkToolsetRoot.Open(HKEY_LOCAL_MACHINE, cszMSInfoRoot);
if (lResult == ERROR_SUCCESS)
crkToolsetRoot.RecurseDeleteKey(cszDefaultToolsetKey);
lResult = crkNewToolset.Create(crkToolsetRoot, cszDefaultToolsetKey);
if (lResult != ERROR_SUCCESS)
return lResult;
VERIFY(strKeyValue.LoadString(IDS_MSINFOTOOLSET));
lResult = crkNewToolset.SetValue(strKeyValue);
if (lResult != ERROR_SUCCESS)
return lResult;
// Get the windows directory and system32 directory.
TCHAR szDirectory[MAX_PATH];
CString strSystemDirectory;
if (::GetSystemDirectory(szDirectory, MAX_PATH))
strSystemDirectory = szDirectory;
CString strWindowsDirectory;
if (::GetWindowsDirectory(szDirectory, MAX_PATH))
strWindowsDirectory = szDirectory;
// Load the string containing the tools to add to the registry.
CString strTools;
strTools.LoadString(IDS_DEFAULT_TOOLS);
CString strKeyName, strName, strCommand, strParam;
int iDelim;
while (!strTools.IsEmpty())
{
// First, get the different values we're going to add to the registry.
iDelim = strTools.Find((TCHAR) '|');
if (iDelim >= 0)
{
strKeyName = strTools.Left(iDelim);
strTools = strTools.Right(strTools.GetLength() - (iDelim + 1));
}
iDelim = strTools.Find((TCHAR) '|');
if (iDelim >= 0)
{
strName = strTools.Left(iDelim);
strTools = strTools.Right(strTools.GetLength() - (iDelim + 1));
}
iDelim = strTools.Find((TCHAR) '|');
if (iDelim >= 0)
{
strCommand = strTools.Left(iDelim);
strTools = strTools.Right(strTools.GetLength() - (iDelim + 1));
}
iDelim = strTools.Find((TCHAR) '|');
if (iDelim >= 0)
{
strParam = strTools.Left(iDelim);
strTools = strTools.Right(strTools.GetLength() - (iDelim + 1));
}
// Now we need to convert the sequences in the string which contain
// references to the windows directory, etc.
ReplaceString(strCommand, _T("%sys32%"), strSystemDirectory);
ReplaceString(strCommand, _T("%win%"), strWindowsDirectory);
ReplaceString(strParam, _T("%sys32%"), strSystemDirectory);
ReplaceString(strParam, _T("%win%"), strWindowsDirectory);
// Finally, create the registry entries.
lResult = crkTool.Create(crkNewToolset, strKeyName);
if (lResult != ERROR_SUCCESS)
continue;
crkTool.SetValue(strName);
crkTool.SetValue(strCommand, cszMSInfoCommandKey);
crkTool.SetValue(strParam, cszMSInfoParamKey);
}
return ERROR_SUCCESS;
}
//-----------------------------------------------------------------------------
// Look for instances of strFind in strString, and replace them with
// strReplace. There's a method to do this in CString in version 6.
//-----------------------------------------------------------------------------
void CToolList::ReplaceString(CString & strString, const CString & strFind, const CString & strReplace)
{
int iStart = strString.Find(strFind);
while (iStart != -1)
{
CString strTemp = strString.Left(iStart);
strTemp += strReplace;
strTemp += strString.Right(strString.GetLength() - iStart - strFind.GetLength());
strString = strTemp;
iStart = strString.Find(strFind);
}
}
/* operator[] - Index our internal list.
*
* History: a-jsari 11/11/97 Initial version. */
CToolset *CToolList::operator[](int iSet) const
{
return m_InternalList[iSet];
}