1183 lines
33 KiB
C++
1183 lines
33 KiB
C++
// stubexe.cpp A command line program which runs the appropriate version
|
|
// of MSInfo, based on the registry settings
|
|
//
|
|
// History: a-jsari 10/13/97
|
|
//
|
|
// Copyright (c) 1998-1999 Microsoft Corporation
|
|
|
|
#include <afx.h>
|
|
#include <afxwin.h>
|
|
#include <io.h>
|
|
#include <process.h>
|
|
#include <errno.h>
|
|
#include "StdAfx.h"
|
|
#include "Resource.h"
|
|
|
|
#include "StubExe.h"
|
|
|
|
#include "MSInfo.h"
|
|
#include "MSInfo_i.c"
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// These global variables hold arguments passed as command line parameters.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
CString strComputerParam(_T(""));
|
|
CString strCategoryParam(_T(""));
|
|
CString strNFOFileParam(_T(""));
|
|
CString strReportFileParam(_T(""));
|
|
|
|
#ifndef HRESULT
|
|
typedef long HRESULT;
|
|
#endif
|
|
|
|
// For Windows 95, the maximum length of a command line is 1024 characters.
|
|
// Not sure what it is for NT.
|
|
const int MAX_COMMAND_LINE = 1024;
|
|
|
|
LPCTSTR cszDefaultDirectory = _T("\\Microsoft Shared\\MSInfo\\");
|
|
|
|
LPCTSTR cszRegistryRoot = _T("Software\\Microsoft\\Shared Tools\\MSInfo");
|
|
LPCTSTR cszDirectoryKey = _T("Path");
|
|
|
|
LPCTSTR cszWindowsRoot = _T("Software\\Microsoft\\Windows\\CurrentVersion");
|
|
LPCTSTR cszCommonFilesKey = _T("CommonFilesDir");
|
|
|
|
CException *g_pException = NULL;
|
|
|
|
// Microsoft Management Console is the program that hosts MSInfo.
|
|
// This is a definition so that we can take its size.
|
|
#define cszProgram _T("mmc.exe")
|
|
|
|
/*
|
|
* ThrowErrorException -
|
|
*
|
|
* History: a-jsari 10/14/97 Initial version.
|
|
*/
|
|
inline void ThrowErrorException()
|
|
{
|
|
::g_pException = new CException;
|
|
if (::g_pException == NULL) ::AfxThrowMemoryException();
|
|
throw ::g_pException;
|
|
}
|
|
|
|
/*
|
|
* CMSInfo - A class to encapsulate using the DLL's COM interface.
|
|
*
|
|
* History: a-jsari 3/26/98 Initial version
|
|
*/
|
|
class CMSInfo {
|
|
public:
|
|
CMSInfo();
|
|
~CMSInfo();
|
|
|
|
HRESULT nfo(LPCTSTR lpszParams);
|
|
HRESULT report(LPCTSTR lpszParams);
|
|
HRESULT s(LPCTSTR lpszParams);
|
|
HRESULT SaveNFO();
|
|
HRESULT SaveReport();
|
|
|
|
private:
|
|
ISystemInfo *m_pISystemInfo;
|
|
HRESULT m_hr;
|
|
};
|
|
|
|
/*
|
|
* CSystemExecutable - The class that implements finding and running an
|
|
* executable.
|
|
*
|
|
* History: a-jsari 10/14/97 Initial version.
|
|
*/
|
|
class CSystemExecutable {
|
|
public:
|
|
CSystemExecutable(LPTSTR szProgram);
|
|
~CSystemExecutable() { DeleteStrings(); }
|
|
void Run();
|
|
void Find();
|
|
void ProcessCommandLine();
|
|
|
|
// Helper methods.
|
|
protected:
|
|
|
|
void DeleteStrings();
|
|
void FindFileOnSystem(CString &szFileName, CString &szDestination);
|
|
|
|
// Instance variables.
|
|
protected:
|
|
CString *m_pszPath;
|
|
CString *m_pszProgramName;
|
|
CString *m_pszCommandLine;
|
|
};
|
|
|
|
/*
|
|
* CMSInfoExecutable - MSInfo-specific functions.
|
|
*
|
|
* History: a-jsari 10/15/97 Initial version
|
|
*/
|
|
class CMSInfoExecutable : public CSystemExecutable {
|
|
public:
|
|
CMSInfoExecutable(LPTSTR szProgram);
|
|
~CMSInfoExecutable() {}
|
|
|
|
void ProcessCommandLine();
|
|
|
|
private:
|
|
void DisplayHelp();
|
|
void DeleteStrings();
|
|
void FindSavedConsole();
|
|
LPCTSTR GetMSIParameter(LPCTSTR szCommand, CString & strParam);
|
|
|
|
// Instance variables
|
|
private:
|
|
static const LPCTSTR cszSavedConsole;
|
|
CString *m_pszSavedConsole;
|
|
};
|
|
|
|
const LPCTSTR CMSInfoExecutable::cszSavedConsole = _T("MSInfo32.msc");
|
|
|
|
/*
|
|
* CMSInfo - Initialize COM and create our ISystemInfo object.
|
|
*
|
|
* History: a-jsari 3/26/98 Initial version.
|
|
*/
|
|
CMSInfo::CMSInfo()
|
|
:m_pISystemInfo(NULL)
|
|
{
|
|
HRESULT hr = CoInitialize(NULL);
|
|
if (FAILED(hr)) ::AfxThrowUserException();
|
|
|
|
m_hr = CoCreateInstance(CLSID_SystemInfo, NULL, CLSCTX_ALL, IID_ISystemInfo, (void **)&m_pISystemInfo);
|
|
}
|
|
|
|
LPCTSTR cszSeparators = _T(" \t,");
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Call the msinfo32.dll using COM to save an NFO file. Use the parameters
|
|
// parsed from the command line (categories, computer).
|
|
//-----------------------------------------------------------------------------
|
|
|
|
HRESULT CMSInfo::SaveNFO()
|
|
{
|
|
CString strFilename(strNFOFileParam);
|
|
CString strComputer(strComputerParam);
|
|
CString strCategory(strCategoryParam);
|
|
|
|
BSTR filename = strFilename.AllocSysString();
|
|
BSTR computer = strComputer.AllocSysString();
|
|
BSTR category = strCategory.AllocSysString();
|
|
|
|
if (m_pISystemInfo)
|
|
return m_pISystemInfo->MakeNFO(filename, computer, category);
|
|
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Call the msinfo32.dll using COM to save a report. Use the parameters
|
|
// parsed from the command line (categories, computer).
|
|
//-----------------------------------------------------------------------------
|
|
|
|
HRESULT CMSInfo::SaveReport()
|
|
{
|
|
CString strFilename(strReportFileParam);
|
|
CString strComputer(strComputerParam);
|
|
CString strCategory(strCategoryParam);
|
|
|
|
BSTR filename = strFilename.AllocSysString();
|
|
BSTR computer = strComputer.AllocSysString();
|
|
BSTR category = strCategory.AllocSysString();
|
|
|
|
if (m_pISystemInfo)
|
|
return m_pISystemInfo->MakeReport(filename, computer, category);
|
|
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
/*
|
|
* make_nfo - Process our parameters and call our ISystemInfo pointer's make_nfo function.
|
|
*
|
|
* History: a-jsari 3/26/98 Initial version.
|
|
*/
|
|
|
|
HRESULT CMSInfo::nfo(LPCTSTR lpszParams)
|
|
{
|
|
CString strBuffer = lpszParams;
|
|
CString strFilename;
|
|
LPCTSTR szComputer = NULL;
|
|
int iSpace;
|
|
|
|
strBuffer.TrimLeft();
|
|
iSpace = strBuffer.FindOneOf(cszSeparators);
|
|
do {
|
|
if (iSpace == -1) {
|
|
if (strBuffer.IsEmpty())
|
|
return E_INVALIDARG;
|
|
strFilename = strBuffer;
|
|
} else {
|
|
strFilename = strBuffer.Left(iSpace);
|
|
strBuffer = strBuffer.Mid(iSpace + 1);
|
|
strBuffer.TrimLeft();
|
|
if (strBuffer[0] == (TCHAR)',')
|
|
strBuffer = strBuffer.Mid(1);
|
|
strBuffer.TrimLeft();
|
|
iSpace = strBuffer.FindOneOf(cszSeparators);
|
|
if (iSpace != -1) {
|
|
strBuffer.Left(iSpace);
|
|
break;
|
|
}
|
|
szComputer = (LPCTSTR)strBuffer;
|
|
}
|
|
} while (FALSE);
|
|
if (m_pISystemInfo != NULL)
|
|
return m_pISystemInfo->make_nfo(const_cast<LPTSTR>((LPCTSTR)strFilename),
|
|
const_cast<LPTSTR>(szComputer));
|
|
return m_hr;
|
|
}
|
|
|
|
/*
|
|
* report - Process our parameters and call our ISystemInfo's make_report function.
|
|
*
|
|
* History: a-jsari 3/26/98 Initial version.
|
|
*/
|
|
HRESULT CMSInfo::report(LPCTSTR lpszParams)
|
|
{
|
|
CString strBuffer = lpszParams;
|
|
CString strFilename;
|
|
CString strComputer;
|
|
LPCTSTR szComputer = NULL;
|
|
LPCTSTR szCategory = NULL;
|
|
int iSpace;
|
|
|
|
strBuffer.TrimLeft();
|
|
iSpace = strBuffer.FindOneOf(cszSeparators);
|
|
do {
|
|
if (iSpace == -1) {
|
|
if (strBuffer.IsEmpty())
|
|
return E_INVALIDARG;
|
|
strFilename = strBuffer;
|
|
} else {
|
|
strFilename = strBuffer.Left(iSpace);
|
|
strBuffer = strBuffer.Mid(iSpace + 1);
|
|
strBuffer.TrimLeft();
|
|
if (strBuffer[0] == (TCHAR)',')
|
|
strBuffer = strBuffer.Mid(1);
|
|
strBuffer.TrimLeft();
|
|
iSpace = strBuffer.FindOneOf(cszSeparators);
|
|
if (iSpace == -1) {
|
|
strComputer = strBuffer;
|
|
szComputer = (LPCTSTR)strComputer;
|
|
break;
|
|
}
|
|
strComputer = strBuffer.Left(iSpace);
|
|
szComputer = (LPCTSTR)strComputer;
|
|
strBuffer = strBuffer.Mid(iSpace + 1);
|
|
strBuffer.TrimLeft();
|
|
if (strBuffer[0] == (TCHAR)',')
|
|
strBuffer = strBuffer.Mid(1);
|
|
strBuffer.TrimLeft();
|
|
iSpace = strBuffer.FindOneOf(cszSeparators);
|
|
if (iSpace != -1) {
|
|
strBuffer = strBuffer.Left(iSpace);
|
|
}
|
|
szCategory = (LPCTSTR)strBuffer;
|
|
}
|
|
} while (FALSE);
|
|
if (m_pISystemInfo != NULL)
|
|
return m_pISystemInfo->make_report(const_cast<LPTSTR>((LPCTSTR)strFilename),
|
|
const_cast<LPTSTR>(szComputer), const_cast<LPTSTR>(szCategory));
|
|
return m_hr;
|
|
}
|
|
|
|
/*
|
|
* s - Process our parameters and call our ISystemInfo's make_nfo function.
|
|
*
|
|
* History: a-jsari 3/26/98 Initial version.
|
|
*/
|
|
HRESULT CMSInfo::s(LPCTSTR lpszParams)
|
|
{
|
|
CString strBuffer = lpszParams;
|
|
int iSpace;
|
|
|
|
strBuffer.TrimLeft();
|
|
iSpace = strBuffer.FindOneOf(_T(" \t"));
|
|
if (iSpace != -1)
|
|
strBuffer = strBuffer.Left(iSpace);
|
|
if (!strBuffer.IsEmpty())
|
|
m_hr = E_INVALIDARG;
|
|
else {
|
|
if (m_pISystemInfo != NULL)
|
|
m_hr = m_pISystemInfo->make_nfo(const_cast<LPTSTR>((LPCTSTR)strBuffer), NULL);
|
|
}
|
|
return m_hr;
|
|
}
|
|
|
|
/*
|
|
* ~CMSInfo - Uninitialize COM and delete our ISystemInfo object.
|
|
*
|
|
* History: a-jsari 3/26/98 Initial version.
|
|
*/
|
|
CMSInfo::~CMSInfo()
|
|
{
|
|
if (SUCCEEDED(m_hr))
|
|
m_pISystemInfo->Release();
|
|
CoUninitialize();
|
|
}
|
|
|
|
/*
|
|
* CExecutable - Constructor which determines the type of the executable to
|
|
* be executed.
|
|
*
|
|
* History: a-jsari 10/14/97 Initial version.
|
|
*/
|
|
CSystemExecutable::CSystemExecutable(LPTSTR szProgram)
|
|
:m_pszProgramName(new CString), m_pszPath(new CString), m_pszCommandLine(new CString)
|
|
{
|
|
if (!(m_pszProgramName && m_pszPath && m_pszCommandLine)) AfxThrowMemoryException();
|
|
*m_pszProgramName = szProgram;
|
|
}
|
|
|
|
/*
|
|
* DeleteStrings - Delete all of the strings used by the object. Used to free
|
|
* our memory before calling exec.
|
|
*
|
|
* History: a-jsari 10/15/97 Initial version
|
|
*/
|
|
void CSystemExecutable::DeleteStrings()
|
|
{
|
|
delete m_pszPath;
|
|
m_pszPath = NULL;
|
|
delete m_pszProgramName;
|
|
m_pszProgramName = NULL;
|
|
delete m_pszCommandLine;
|
|
m_pszCommandLine = NULL;
|
|
}
|
|
|
|
/*
|
|
* FindFileOnSystem - We may eventually put code here to test multiple
|
|
* found copies and use the right one. But probably not.
|
|
*
|
|
* History: a-jsari 10/15/97 Stub version
|
|
*/
|
|
void CSystemExecutable::FindFileOnSystem(CString &szFileName,
|
|
CString &szDestination)
|
|
{
|
|
// Not reached.
|
|
CFileFind FileFinder;
|
|
BOOL bFindResult;
|
|
|
|
bFindResult = FileFinder.FindFile(szFileName);
|
|
if (!bFindResult) ThrowErrorException();
|
|
szDestination = FileFinder.GetFilePath();
|
|
#if 0
|
|
// Choose among all versions of the file?
|
|
while (bFindResult) {
|
|
FileFinder.FindNextFile();
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
* Find - Return a pointer to a string containing the full path
|
|
* to the MMC executable.
|
|
*
|
|
* History: a-jsari 10/13/97 Initial version
|
|
*/
|
|
void CSystemExecutable::Find()
|
|
{
|
|
UINT uReturnSize;
|
|
TCHAR szSystemDirectory[MAX_PATH + 1];
|
|
|
|
uReturnSize = GetSystemDirectory(szSystemDirectory, MAX_PATH);
|
|
if (uReturnSize == 0) ThrowErrorException();
|
|
if (uReturnSize > MAX_PATH) {
|
|
// Our buffer isn't big enough. This code will never get called.
|
|
AfxThrowResourceException();
|
|
}
|
|
*m_pszPath += szSystemDirectory;
|
|
*m_pszPath += _T("\\") + *m_pszProgramName;
|
|
if (_taccess(*m_pszPath, A_READ) < 0) {
|
|
// These may eventually want to be distinct exceptions.
|
|
if (errno == ENOENT) {
|
|
ThrowErrorException();
|
|
} else {
|
|
ASSERT(errno == EACCES);
|
|
ThrowErrorException();
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Run - Call exec with the parameters we so meticulously collected.
|
|
*
|
|
* History: a-jsari 10/15/97 Initial version.
|
|
*/
|
|
void CSystemExecutable::Run()
|
|
{
|
|
#if !defined(UNICODE)
|
|
TCHAR szPath[MAX_PATH + 1];
|
|
TCHAR szProgramName[MAX_PATH + 1];
|
|
TCHAR szCommandLine[MAX_COMMAND_LINE + 1];
|
|
|
|
_tcscpy(szPath, (LPCTSTR)*m_pszPath);
|
|
_tcscpy(szProgramName, (LPCTSTR)*m_pszProgramName);
|
|
_tcscpy(szCommandLine, (LPCTSTR)*m_pszCommandLine);
|
|
DeleteStrings();
|
|
::_execlp(szPath, szProgramName, szCommandLine, 0);
|
|
ThrowErrorException();
|
|
#else
|
|
char szPath[MAX_PATH + 1];
|
|
char szProgramName[MAX_PATH + 1];
|
|
char szCommandLine[MAX_COMMAND_LINE + 1];
|
|
|
|
wcstombs(szPath, (LPCTSTR) *m_pszPath, MAX_PATH);
|
|
wcstombs(szProgramName, (LPCTSTR) *m_pszProgramName, MAX_PATH);
|
|
wcstombs(szCommandLine, (LPCTSTR) *m_pszCommandLine, MAX_COMMAND_LINE);
|
|
|
|
DeleteStrings();
|
|
::_execlp(szPath, szProgramName, szCommandLine, 0);
|
|
ThrowErrorException();
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
* ProcessCommandLine - Pass all command line parameters to the called
|
|
* executable.
|
|
*
|
|
* History: a-jsari 10/14/97 Initial version
|
|
*/
|
|
void CSystemExecutable::ProcessCommandLine()
|
|
{
|
|
*m_pszCommandLine = GetCommandLine();
|
|
|
|
// Skip over the first element in the line, which is the path to
|
|
// the current executable. Preserve everything else.
|
|
const int FIND_NO_MATCH = -1;
|
|
int wIndex;
|
|
|
|
m_pszCommandLine->TrimLeft();
|
|
wIndex = m_pszCommandLine->FindOneOf(_T("\" \t\n"));
|
|
if ((*m_pszCommandLine)[wIndex] == '"') {
|
|
// This is the primary, if not guaranteed method.
|
|
*m_pszCommandLine = m_pszCommandLine->Right(m_pszCommandLine->GetLength() - (wIndex + 1));
|
|
wIndex = m_pszCommandLine->Find('"');
|
|
*m_pszCommandLine = m_pszCommandLine->Right(m_pszCommandLine->GetLength() - (wIndex + 1));
|
|
} else if (wIndex == FIND_NO_MATCH) {
|
|
*m_pszCommandLine = _T("");
|
|
} else {
|
|
*m_pszCommandLine = m_pszCommandLine->Right(m_pszCommandLine->GetLength() - (wIndex + 1));
|
|
}
|
|
}
|
|
|
|
/*
|
|
* CMSInfoExecutable - Just pass all parameters to the base constructor.
|
|
*
|
|
* History: a-jsari 10/15/97 Initial version
|
|
*/
|
|
CMSInfoExecutable::CMSInfoExecutable(LPTSTR szProgram)
|
|
:CSystemExecutable(szProgram), m_pszSavedConsole(new CString)
|
|
{
|
|
if (m_pszSavedConsole == NULL) AfxThrowMemoryException();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// This function is used to get a parameter from the command line. The first
|
|
// character may be one or more whitespace, or a ":" or a "=". After that, the
|
|
// string is read until a whitespace character is read outside of quotes.
|
|
//
|
|
// Return the pointer to the character location where we stopped reading.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
LPCTSTR CMSInfoExecutable::GetMSIParameter(LPCTSTR szCommand, CString & strParam)
|
|
{
|
|
strParam.Empty();
|
|
if (!szCommand)
|
|
return NULL;
|
|
|
|
// Advance past any leading whitespace, ':' or '='.
|
|
|
|
while (*szCommand && (*szCommand == _T(' ') || *szCommand == _T('\t') || *szCommand == _T(':') || *szCommand == _T('=')))
|
|
szCommand++;
|
|
|
|
if (*szCommand == _T('\0'))
|
|
return szCommand;
|
|
|
|
// Now read the parameter in until the end of the string or a non-quoted
|
|
// whitespace is found. Remove the quote marks.
|
|
|
|
BOOL fInQuote = FALSE;
|
|
while (*szCommand)
|
|
{
|
|
if (!fInQuote && (*szCommand == _T(' ') || *szCommand == _T('\t')))
|
|
break;
|
|
|
|
if (*szCommand == _T('"'))
|
|
{
|
|
fInQuote = !fInQuote;
|
|
szCommand++;
|
|
continue;
|
|
}
|
|
|
|
strParam += *szCommand++;
|
|
}
|
|
|
|
return szCommand;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// This function reads the command line, looking for parameters we know how to
|
|
// handle. Anything we don't know about, we assemble into a new command line
|
|
// to pass to MMC when we launch MSInfo (if we launch it).
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void CMSInfoExecutable::ProcessCommandLine()
|
|
{
|
|
CSystemExecutable::ProcessCommandLine();
|
|
FindSavedConsole();
|
|
|
|
CString strNewCommandLine;
|
|
int iLine = 0;
|
|
|
|
// Process the items on the command line. If we recognize the flag,
|
|
// save the value for use later. Otherwise add it to the command line
|
|
// we'll pass to the snapin.
|
|
|
|
while (m_pszCommandLine->GetLength() > 0)
|
|
{
|
|
// Remove the part of the command line we just processed.
|
|
|
|
*m_pszCommandLine = m_pszCommandLine->Mid(iLine);
|
|
iLine = m_pszCommandLine->FindOneOf(_T(" \t")) + 1;
|
|
|
|
if (iLine == 0)
|
|
iLine = m_pszCommandLine->GetLength();
|
|
|
|
// See if the first char is a command line switch.
|
|
|
|
TCHAR tcFirst = (*m_pszCommandLine)[0];
|
|
if (tcFirst == (TCHAR)'/' || tcFirst == (TCHAR)'-')
|
|
{
|
|
LPCTSTR pString = *m_pszCommandLine;
|
|
++pString;
|
|
|
|
// This is a command line switch - see if we recognize it.
|
|
|
|
if (::_tcsnicmp(pString, _T("?"), 1) == 0)
|
|
{
|
|
DisplayHelp();
|
|
exit(0);
|
|
}
|
|
else if (::_tcsnicmp(pString, _T("report"), 6) == 0)
|
|
{
|
|
LPCTSTR szEnd = GetMSIParameter(pString + 6, strReportFileParam);
|
|
szEnd++;
|
|
*m_pszCommandLine = szEnd;
|
|
iLine = 0;
|
|
continue;
|
|
}
|
|
else if (::_tcsnicmp(pString, _T("s"), 1) == 0)
|
|
{
|
|
LPCTSTR szEnd = GetMSIParameter(pString + 1, strNFOFileParam);
|
|
szEnd++;
|
|
*m_pszCommandLine = szEnd;
|
|
iLine = 0;
|
|
continue;
|
|
}
|
|
else if (::_tcsnicmp(pString, _T("nfo"), 3) == 0)
|
|
{
|
|
LPCTSTR szEnd = GetMSIParameter(pString + 3, strNFOFileParam);
|
|
szEnd++;
|
|
*m_pszCommandLine = szEnd;
|
|
iLine = 0;
|
|
continue;
|
|
}
|
|
else if (::_tcsnicmp(pString, _T("computer"), 8) == 0)
|
|
{
|
|
LPCTSTR szEnd = GetMSIParameter(pString + 8, strComputerParam);
|
|
szEnd++;
|
|
*m_pszCommandLine = szEnd;
|
|
iLine = 0;
|
|
continue;
|
|
}
|
|
else if (::_tcsnicmp(pString, _T("categories"), 10) == 0)
|
|
{
|
|
LPCTSTR szEnd = GetMSIParameter(pString + 10, strCategoryParam);
|
|
szEnd++;
|
|
*m_pszCommandLine = szEnd;
|
|
iLine = 0;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
// If we don't match one of our internal switches, pass it on.
|
|
|
|
strNewCommandLine += m_pszCommandLine->Left(iLine);
|
|
}
|
|
|
|
// Now, check the parameters we parsed from the command line to decide what
|
|
// to do. If we are to save an NFO or report, we should just exit after
|
|
// doing so.
|
|
|
|
if (!strNFOFileParam.IsEmpty() || !strReportFileParam.IsEmpty())
|
|
{
|
|
CMSInfo sysInfo;
|
|
|
|
if (!strNFOFileParam.IsEmpty())
|
|
sysInfo.SaveNFO();
|
|
else if (!strReportFileParam.IsEmpty())
|
|
sysInfo.SaveReport();
|
|
exit(0);
|
|
}
|
|
|
|
// Construct the command line for MMC.
|
|
|
|
*m_pszCommandLine = _T("/s \"") + *m_pszSavedConsole + _T("\" ") + strNewCommandLine;
|
|
|
|
if (!strComputerParam.IsEmpty())
|
|
*m_pszCommandLine += _T(" /computer \"") + strComputerParam + _T("\" ");
|
|
|
|
if (!strCategoryParam.IsEmpty())
|
|
*m_pszCommandLine += _T(" /msinfo_showcategories=\"") + strCategoryParam + _T("\" ");
|
|
|
|
delete m_pszSavedConsole;
|
|
m_pszSavedConsole = NULL;
|
|
}
|
|
|
|
/*
|
|
* FindSavedConsole - Finds SysInfo.msc using the registry, or the
|
|
* default directory.
|
|
*
|
|
* History: a-jsari 10/13/97 Initial version
|
|
*/
|
|
void CMSInfoExecutable::FindSavedConsole()
|
|
{
|
|
HKEY keyMSInfoRoot;
|
|
long lResult;
|
|
DWORD dwKeyLength = MAX_PATH;
|
|
DWORD dwType;
|
|
TCHAR szDirectory[MAX_PATH+1];
|
|
|
|
|
|
*m_pszSavedConsole = _T("");
|
|
do {
|
|
// Check the current directory.
|
|
if (::_taccess(cszSavedConsole, A_READ) == 0) {
|
|
*m_pszSavedConsole = cszSavedConsole;
|
|
return;
|
|
}
|
|
|
|
// Check the MSInfo Path key.
|
|
lResult = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE, cszRegistryRoot, 0, KEY_READ,
|
|
&keyMSInfoRoot);
|
|
if (lResult == ERROR_SUCCESS) {
|
|
lResult = ::RegQueryValueEx(keyMSInfoRoot, cszDirectoryKey, 0, &dwType,
|
|
reinterpret_cast<BYTE *>(szDirectory), &dwKeyLength);
|
|
if (lResult == ERROR_SUCCESS) {
|
|
LPTSTR pszPath = ::_tcsrchr(szDirectory, (TCHAR)'\\');
|
|
if (pszPath) *pszPath = 0;
|
|
*m_pszSavedConsole = szDirectory;
|
|
*m_pszSavedConsole += _T("\\");
|
|
*m_pszSavedConsole += cszSavedConsole;
|
|
if (::_taccess(*m_pszSavedConsole, A_READ) == 0)
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Use the hard-coded path %ProgramFilesRoot%\Common Files\MSInfo
|
|
lResult = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE, cszWindowsRoot, 0, KEY_READ, &keyMSInfoRoot);
|
|
ASSERT(lResult == ERROR_SUCCESS);
|
|
if (lResult != ERROR_SUCCESS) break;
|
|
dwKeyLength = sizeof( szDirectory);
|
|
lResult = ::RegQueryValueEx(keyMSInfoRoot, cszCommonFilesKey, 0, &dwType,
|
|
reinterpret_cast<BYTE *>(szDirectory), &dwKeyLength);
|
|
ASSERT(lResult == ERROR_SUCCESS);
|
|
if (lResult != ERROR_SUCCESS) break;
|
|
|
|
*m_pszSavedConsole = szDirectory;
|
|
*m_pszSavedConsole += cszDefaultDirectory;
|
|
*m_pszSavedConsole += cszSavedConsole;
|
|
|
|
if (::_taccess(*m_pszSavedConsole, A_READ) == 0)
|
|
return;
|
|
|
|
} while (0);
|
|
// AFX_MANAGE_STATE(::AfxGetStaticModuleState());
|
|
CString szNoMSCFile;
|
|
szNoMSCFile.LoadString(IDS_NOMSCFILE);
|
|
::AfxMessageBox(szNoMSCFile);
|
|
::ThrowErrorException();
|
|
}
|
|
|
|
/*
|
|
* DisplayHelp - Print the command line help for the executable.
|
|
*
|
|
* History: a-jsari 10/13/97 Initial version.
|
|
* a-adaml 03/15/99 Modified to display help in message box
|
|
*
|
|
*/
|
|
|
|
void CMSInfoExecutable::DisplayHelp()
|
|
{
|
|
CString strMsg, strTitle;
|
|
|
|
strTitle.LoadString(IDS_DESCRIPTION);
|
|
strMsg.LoadString(IDS_USAGE);
|
|
|
|
::MessageBox( NULL, strMsg, strTitle, MB_ICONINFORMATION | MB_OK);
|
|
}
|
|
|
|
/*
|
|
* InitInstance - The main entry point for the stub executable, the subclass InitInstance
|
|
* function
|
|
*
|
|
* History: a-jsari 10/13/97 Initial version
|
|
*/
|
|
BOOL CMSInfoApp::InitInstance()
|
|
{
|
|
#if FALSE // just run the helpctr version now
|
|
CString szResText;
|
|
CString szResTitle;
|
|
|
|
do {
|
|
try {
|
|
// FIX: Pre-load the memory resource in case memory problems develop.
|
|
|
|
CMSInfoExecutable exeMSInfo(cszProgram);
|
|
|
|
exeMSInfo.Find();
|
|
exeMSInfo.ProcessCommandLine();
|
|
exeMSInfo.Run();
|
|
// We never get past this on successful completion.
|
|
}
|
|
catch (CMemoryException e_Mem) {
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
VERIFY(szResText.LoadString(IDS_MEMORY));
|
|
VERIFY(szResTitle.LoadString(IDS_DESCRIPTION));
|
|
if (::MessageBox(NULL, szResText, szResTitle, MB_RETRYCANCEL | MB_ICONERROR) == IDCANCEL)
|
|
break;
|
|
continue;
|
|
}
|
|
catch (CException e_Generic) {
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
VERIFY(szResText.LoadString(IDS_UNEXPECTED));
|
|
::MessageBox(NULL, szResText, szResTitle, MB_OK | MB_ICONERROR);
|
|
delete ::g_pException;
|
|
break;
|
|
}
|
|
catch (...) {
|
|
ASSERT(FALSE);
|
|
break;
|
|
}
|
|
break;
|
|
} while (TRUE);
|
|
#endif
|
|
|
|
if (!RunMSInfoInHelpCtr())
|
|
{
|
|
CDialog help(IDD_MSICMDLINE);
|
|
help.DoModal();
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Required to use the new MSInfo DLL in HelpCtr.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
typedef class MSInfo MSInfo;
|
|
|
|
EXTERN_C const IID IID_IMSInfo;
|
|
|
|
struct IMSInfo : public IDispatch
|
|
{
|
|
public:
|
|
virtual /* [id][propput] */ HRESULT STDMETHODCALLTYPE put_AutoSize(
|
|
/* [in] */ VARIANT_BOOL vbool) = 0;
|
|
|
|
virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_AutoSize(
|
|
/* [retval][out] */ VARIANT_BOOL __RPC_FAR *pbool) = 0;
|
|
|
|
virtual /* [id][propput] */ HRESULT STDMETHODCALLTYPE put_BackColor(
|
|
/* [in] */ OLE_COLOR clr) = 0;
|
|
|
|
virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_BackColor(
|
|
/* [retval][out] */ OLE_COLOR __RPC_FAR *pclr) = 0;
|
|
|
|
virtual /* [id][propput] */ HRESULT STDMETHODCALLTYPE put_BackStyle(
|
|
/* [in] */ long style) = 0;
|
|
|
|
virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_BackStyle(
|
|
/* [retval][out] */ long __RPC_FAR *pstyle) = 0;
|
|
|
|
virtual /* [id][propput] */ HRESULT STDMETHODCALLTYPE put_BorderColor(
|
|
/* [in] */ OLE_COLOR clr) = 0;
|
|
|
|
virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_BorderColor(
|
|
/* [retval][out] */ OLE_COLOR __RPC_FAR *pclr) = 0;
|
|
|
|
virtual /* [id][propput] */ HRESULT STDMETHODCALLTYPE put_BorderStyle(
|
|
/* [in] */ long style) = 0;
|
|
|
|
virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_BorderStyle(
|
|
/* [retval][out] */ long __RPC_FAR *pstyle) = 0;
|
|
|
|
virtual /* [id][propput] */ HRESULT STDMETHODCALLTYPE put_BorderWidth(
|
|
/* [in] */ long width) = 0;
|
|
|
|
virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_BorderWidth(
|
|
/* [retval][out] */ long __RPC_FAR *width) = 0;
|
|
|
|
virtual /* [id][propputref] */ HRESULT STDMETHODCALLTYPE putref_Font(
|
|
/* [in] */ IFontDisp __RPC_FAR *pFont) = 0;
|
|
|
|
virtual /* [id][propput] */ HRESULT STDMETHODCALLTYPE put_Font(
|
|
/* [in] */ IFontDisp __RPC_FAR *pFont) = 0;
|
|
|
|
virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_Font(
|
|
/* [retval][out] */ IFontDisp __RPC_FAR *__RPC_FAR *ppFont) = 0;
|
|
|
|
virtual /* [id][propput] */ HRESULT STDMETHODCALLTYPE put_ForeColor(
|
|
/* [in] */ OLE_COLOR clr) = 0;
|
|
|
|
virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_ForeColor(
|
|
/* [retval][out] */ OLE_COLOR __RPC_FAR *pclr) = 0;
|
|
|
|
virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_Window(
|
|
/* [retval][out] */ long __RPC_FAR *phwnd) = 0;
|
|
|
|
virtual /* [id][propput] */ HRESULT STDMETHODCALLTYPE put_BorderVisible(
|
|
/* [in] */ VARIANT_BOOL vbool) = 0;
|
|
|
|
virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_BorderVisible(
|
|
/* [retval][out] */ VARIANT_BOOL __RPC_FAR *pbool) = 0;
|
|
|
|
virtual /* [id][propput] */ HRESULT STDMETHODCALLTYPE put_Appearance(
|
|
/* [in] */ short appearance) = 0;
|
|
|
|
virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_Appearance(
|
|
/* [retval][out] */ short __RPC_FAR *pappearance) = 0;
|
|
|
|
virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE SetHistoryStream(
|
|
IStream __RPC_FAR *pStream) = 0;
|
|
|
|
virtual /* [helpstring][id][propget] */ HRESULT STDMETHODCALLTYPE get_DCO_IUnknown(
|
|
/* [retval][out] */ IUnknown __RPC_FAR *__RPC_FAR *pVal) = 0;
|
|
|
|
virtual /* [helpstring][id][propput] */ HRESULT STDMETHODCALLTYPE put_DCO_IUnknown(
|
|
/* [in] */ IUnknown __RPC_FAR *newVal) = 0;
|
|
|
|
virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE SaveFile(
|
|
BSTR filename,
|
|
BSTR computer,
|
|
BSTR category) = 0;
|
|
|
|
};
|
|
|
|
#include "msinfo32_i.c"
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// This function encapsulates the functionality to run the new MSInfo in
|
|
// HelpCtr. If this function returns false, the help should be displayed.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void StringReplace(CString & str, LPCTSTR szLookFor, LPCTSTR szReplaceWith);
|
|
BOOL CMSInfoApp::RunMSInfoInHelpCtr()
|
|
{
|
|
//-------------------------------------------------------------------------
|
|
// Parse the command line parameters into one big string to pass to the
|
|
// ActiveX control. There are a few which would keep us from launching
|
|
// HelpCtr.
|
|
//-------------------------------------------------------------------------
|
|
|
|
CString strCommandLine(CWinApp::m_lpCmdLine);
|
|
|
|
CString strLastFlag;
|
|
CString strCategory;
|
|
CString strCategories;
|
|
CString strComputer;
|
|
CString strOpenFile;
|
|
CString strPrintFile;
|
|
CString strSilentNFO;
|
|
CString strSilentExport;
|
|
CString strTemp;
|
|
BOOL fShowPCH = FALSE;
|
|
BOOL fShowHelp = FALSE;
|
|
BOOL fShowCategories = FALSE;
|
|
|
|
while (!strCommandLine.IsEmpty())
|
|
{
|
|
// Remove the leading whitespace from the string.
|
|
|
|
strTemp = strCommandLine.SpanIncluding(_T(" \t=:"));
|
|
strCommandLine = strCommandLine.Right(strCommandLine.GetLength() - strTemp.GetLength());
|
|
|
|
// If the first character is a / or a -, then this is a flag.
|
|
|
|
if (strCommandLine[0] == _T('/') || strCommandLine[0] == _T('-'))
|
|
{
|
|
strCommandLine = strCommandLine.Right(strCommandLine.GetLength() - 1);
|
|
strLastFlag = strCommandLine.SpanExcluding(_T(" \t=:"));
|
|
strCommandLine = strCommandLine.Right(strCommandLine.GetLength() - strLastFlag.GetLength());
|
|
strLastFlag.MakeLower();
|
|
|
|
if (strLastFlag == CString(_T("pch")))
|
|
{
|
|
fShowPCH = TRUE;
|
|
strLastFlag.Empty();
|
|
}
|
|
else if (strLastFlag == CString(_T("?")) || strLastFlag == CString(_T("h")))
|
|
{
|
|
fShowHelp = TRUE;
|
|
strLastFlag.Empty();
|
|
}
|
|
else if (strLastFlag == CString(_T("showcategories")))
|
|
{
|
|
fShowCategories = TRUE;
|
|
strLastFlag.Empty();
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
// Otherwise, this is either a filename to open, or a parameter from the
|
|
// previous command line flag. This might have quotes around it.
|
|
|
|
if (strCommandLine[0] != _T('"'))
|
|
{
|
|
strTemp = strCommandLine.SpanExcluding(_T(" \t"));
|
|
strCommandLine = strCommandLine.Right(strCommandLine.GetLength() - strTemp.GetLength());
|
|
}
|
|
else
|
|
{
|
|
strCommandLine = strCommandLine.Right(strCommandLine.GetLength() - 1);
|
|
strTemp = strCommandLine.SpanExcluding(_T("\""));
|
|
strCommandLine = strCommandLine.Right(strCommandLine.GetLength() - strTemp.GetLength() - 1);
|
|
}
|
|
|
|
if (strLastFlag.IsEmpty() || strLastFlag == CString(_T("msinfo_file")))
|
|
strOpenFile = strTemp;
|
|
else if (strLastFlag == CString(_T("p")))
|
|
strPrintFile = strTemp;
|
|
else if (strLastFlag == CString(_T("category")))
|
|
strCategory = strTemp;
|
|
else if (strLastFlag == CString(_T("categories")))
|
|
strCategories = strTemp;
|
|
else if (strLastFlag == CString(_T("computer")))
|
|
strComputer = strTemp;
|
|
else if (strLastFlag == CString(_T("report")))
|
|
strSilentExport = strTemp;
|
|
else if (strLastFlag == CString(_T("nfo")) || strLastFlag == CString(_T("s")))
|
|
strSilentNFO = strTemp;
|
|
|
|
strLastFlag.Empty();
|
|
}
|
|
|
|
if (fShowHelp)
|
|
return FALSE;
|
|
|
|
TCHAR szCurrent[MAX_PATH];
|
|
GetCurrentDirectory(MAX_PATH, szCurrent);
|
|
CString strCurrent(szCurrent);
|
|
if (strCurrent.Right(1) != CString(_T("\\")))
|
|
strCurrent += CString(_T("\\"));
|
|
|
|
HRESULT hrInitialize = CoInitialize(NULL);
|
|
|
|
if (!strSilentNFO.IsEmpty() || !strSilentExport.IsEmpty())
|
|
{
|
|
IMSInfo * pMSInfo = NULL;
|
|
|
|
if (SUCCEEDED(CoCreateInstance(CLSID_MSInfo, NULL, CLSCTX_ALL, IID_IMSInfo, (void **)&pMSInfo)) && pMSInfo != NULL)
|
|
{
|
|
BSTR computer = strComputer.AllocSysString();
|
|
BSTR category = strCategories.AllocSysString();
|
|
|
|
if (!strSilentNFO.IsEmpty())
|
|
{
|
|
if (strSilentNFO.Find(_T('\\')) == -1)
|
|
strSilentNFO = strCurrent + strSilentNFO;
|
|
|
|
if (strSilentNFO.Right(4).CompareNoCase(CString(_T(".nfo"))) != 0)
|
|
strSilentNFO += CString(_T(".nfo"));
|
|
|
|
BSTR filename = strSilentNFO.AllocSysString();
|
|
pMSInfo->SaveFile(filename, computer, category);
|
|
SysFreeString(filename);
|
|
}
|
|
|
|
if (!strSilentExport.IsEmpty())
|
|
{
|
|
if (strSilentExport.Find(_T('\\')) == -1)
|
|
strSilentExport = strCurrent + strSilentExport;
|
|
|
|
BSTR filename = strSilentExport.AllocSysString();
|
|
pMSInfo->SaveFile(filename, computer, category);
|
|
SysFreeString(filename);
|
|
}
|
|
|
|
SysFreeString(computer);
|
|
SysFreeString(category);
|
|
pMSInfo->Release();
|
|
}
|
|
|
|
if (SUCCEEDED(hrInitialize))
|
|
CoUninitialize();
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
CString strURLParam;
|
|
|
|
if (fShowPCH)
|
|
strURLParam += _T("pch");
|
|
|
|
if (fShowCategories)
|
|
strURLParam += _T(",showcategories");
|
|
|
|
if (!strComputer.IsEmpty())
|
|
strURLParam += _T(",computer=") + strComputer;
|
|
|
|
if (!strCategory.IsEmpty())
|
|
strURLParam += _T(",category=") + strCategory;
|
|
|
|
if (!strCategories.IsEmpty())
|
|
strURLParam += _T(",categories=") + strCategories;
|
|
|
|
if (!strPrintFile.IsEmpty())
|
|
{
|
|
if (strPrintFile.Find(_T('\\')) == -1)
|
|
strPrintFile = strCurrent + strPrintFile;
|
|
|
|
strURLParam += _T(",print=") + strPrintFile;
|
|
}
|
|
|
|
if (!strOpenFile.IsEmpty())
|
|
{
|
|
if (strOpenFile.Find(_T('\\')) == -1)
|
|
strOpenFile = strCurrent + strOpenFile;
|
|
|
|
strURLParam += _T(",open=") + strOpenFile;
|
|
}
|
|
|
|
if (!strURLParam.IsEmpty())
|
|
{
|
|
strURLParam.TrimLeft(_T(","));
|
|
strURLParam = CString(_T("?")) + strURLParam;
|
|
}
|
|
|
|
CString strURLAddress(_T("hcp://system/sysinfo/msinfo.htm"));
|
|
CString strURL = strURLAddress + strURLParam;
|
|
|
|
//-------------------------------------------------------------------------
|
|
// Check to see if we can run MSInfo in HelpCtr. We need the HTM file
|
|
// to be present.
|
|
//-------------------------------------------------------------------------
|
|
|
|
BOOL fRunVersion6 = TRUE;
|
|
|
|
TCHAR szPath[MAX_PATH];
|
|
if (ExpandEnvironmentStrings(_T("%windir%\\pchealth\\helpctr\\system\\sysinfo\\msinfo.htm"), szPath, MAX_PATH))
|
|
{
|
|
WIN32_FIND_DATA finddata;
|
|
HANDLE h = FindFirstFile(szPath, &finddata);
|
|
|
|
if (INVALID_HANDLE_VALUE != h)
|
|
FindClose(h);
|
|
else
|
|
fRunVersion6 = FALSE;
|
|
}
|
|
|
|
// This would be used to check if the control is registered. Turns out we want to run anyway.
|
|
//
|
|
// IUnknown * pUnknown;
|
|
// if (fRunVersion6 && SUCCEEDED(CoCreateInstance(CLSID_MSInfo, NULL, CLSCTX_ALL, IID_IUnknown, (void **) &pUnknown)))
|
|
// pUnknown->Release();
|
|
// else
|
|
// fRunVersion6 = FALSE;
|
|
|
|
StringReplace(strURL, _T(" "), _T("%20"));
|
|
|
|
if (fRunVersion6)
|
|
{
|
|
// HelpCtr now supports running MSInfo in its own window. We need to
|
|
// execute the following:
|
|
//
|
|
// helpctr -mode hcp://system/sysinfo/msinfo.xml
|
|
//
|
|
// Additionally, we can pass parameters in the URL using the
|
|
// following flag:
|
|
//
|
|
// -url hcp://system/sysinfo/msinfo.htm?open=c:\savedfile.nfo
|
|
//
|
|
// First, find out of the XML file is present.
|
|
|
|
BOOL fXMLPresent = TRUE;
|
|
if (ExpandEnvironmentStrings(_T("%windir%\\pchealth\\helpctr\\system\\sysinfo\\msinfo.xml"), szPath, MAX_PATH))
|
|
{
|
|
WIN32_FIND_DATA finddata;
|
|
HANDLE h = FindFirstFile(szPath, &finddata);
|
|
|
|
if (INVALID_HANDLE_VALUE != h)
|
|
FindClose(h);
|
|
else
|
|
fXMLPresent = FALSE;
|
|
}
|
|
|
|
// If the XML file is present and we can get the path for helpctr.exe, we
|
|
// should launch it the new way.
|
|
|
|
TCHAR szHelpCtrPath[MAX_PATH];
|
|
if (fXMLPresent && ExpandEnvironmentStrings(_T("%windir%\\pchealth\\helpctr\\binaries\\helpctr.exe"), szHelpCtrPath, MAX_PATH))
|
|
{
|
|
CString strParams(_T("-mode hcp://system/sysinfo/msinfo.xml"));
|
|
if (!strURLParam.IsEmpty())
|
|
strParams += CString(_T(" -url ")) + strURL;
|
|
|
|
ShellExecute(NULL, NULL, szHelpCtrPath, strParams, NULL, SW_SHOWNORMAL);
|
|
}
|
|
else
|
|
ShellExecute(NULL, NULL, strURL, NULL, NULL, SW_SHOWNORMAL);
|
|
}
|
|
else
|
|
ShellExecute(NULL, NULL, _T("hcp://system"), NULL, NULL, SW_SHOWNORMAL);
|
|
|
|
if (SUCCEEDED(hrInitialize))
|
|
CoUninitialize();
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// This was used originally to replace some MFC functionality not in the ME
|
|
// build tree.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void StringReplace(CString & str, LPCTSTR szLookFor, LPCTSTR szReplaceWith)
|
|
{
|
|
CString strWorking(str);
|
|
CString strReturn;
|
|
CString strLookFor(szLookFor);
|
|
CString strReplaceWith(szReplaceWith);
|
|
|
|
int iLookFor = strLookFor.GetLength();
|
|
int iNext;
|
|
|
|
while (!strWorking.IsEmpty())
|
|
{
|
|
iNext = strWorking.Find(strLookFor);
|
|
if (iNext == -1)
|
|
{
|
|
strReturn += strWorking;
|
|
strWorking.Empty();
|
|
}
|
|
else
|
|
{
|
|
strReturn += strWorking.Left(iNext);
|
|
strReturn += strReplaceWith;
|
|
strWorking = strWorking.Right(strWorking.GetLength() - (iNext + iLookFor));
|
|
}
|
|
}
|
|
|
|
str = strReturn;
|
|
}
|