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

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;
}