601 lines
16 KiB
C++
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];
|
|
}
|