// This file was originally stubexe.cpp (written by a-jsari), and was copied // to create stubmsd.cpp to generate an identical stub program for winmsd. // // Copyright (c) 1998-1999 Microsoft Corporation #include #include #include #include #include #include #include "StdAfx.h" #include "Resource.h" #include "stubmsd.h" #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; } /* * 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() {} BOOL ProcessCommandLine(); private: void DeleteStrings(); void FindMSInfoEXE(); // Instance variables private: static const LPCTSTR cszMSInfo32; }; const LPCTSTR CMSInfoExecutable::cszMSInfo32 = _T("msinfo32.exe"); /* * 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() { // We no longer call mmc, we instead call msinfo32.exe so that // winmsd appears to support all the same command line options // whatever they may be. #ifdef BUILD_MMC_COMMAND_LINE 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(); } } #endif } /* * 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]; _tcsncpy(szPath, (LPCTSTR)*m_pszPath, sizeof(szPath)/sizeof(TCHAR)); _tcsncpy(szProgramName, (LPCTSTR)*m_pszProgramName, sizeof(szProgramName)/sizeof(TCHAR)); _tcsncpy(szCommandLine, (LPCTSTR)*m_pszCommandLine, sizeof(szCommandLine)/sizeof(TCHAR)); 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) { } /* * ProcessCommandLine - Process the command line parameters we can handle; pass on * the ones we can't, adding the saved console file. * * History: a-jsari 10/15/97 Initial version */ BOOL CMSInfoExecutable::ProcessCommandLine() { // If the user specifies the "/?" switch on the winmsd.exe command line, // we need to inform the user that msinfo32.exe is the preferred way to // view the information now. CString strCommandLine = GetCommandLine(); if (strCommandLine.Find(_T("/?")) != -1 && IDNO == ::AfxMessageBox(IDS_MSDNOTE, MB_YESNO)) return FALSE; // builds m_pszCommandLine CSystemExecutable::ProcessCommandLine(); FindMSInfoEXE(); return TRUE; } //----------------------------------------------------------------------------- // Locate the msinfo32.exe file. We'll look in the following places: // // 1. In the current directory. // 2. In the directory in the registry under: // HKLM\Software\Microsoft\Shared Tools\MSInfo\Path // 3a. In the directory %CommonFilesDir%\Microsoft Shared\MSInfo, where // %CommonFilesDir% is found in // HKLM\Software\Microsoft\Windows\CurrentVersion\CommonFilesDir. // 3b. Use the %CommonFilesDir% value with a subpath loaded from a // string resource. // 4. Last ditch is to look in a directory stored as a string resource // for this file. //----------------------------------------------------------------------------- void CMSInfoExecutable::FindMSInfoEXE() { m_pszPath->Empty(); // First, check the current directory. if (::_taccess(_T("msinfo32.exe"), A_READ) == 0) { *m_pszPath = _T("msinfo32.exe"); return; } // Second, use the path key in the MSInfo registry key. HKEY hkey; if (ERROR_SUCCESS == ::RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("Software\\Microsoft\\Shared Tools\\MSInfo"), 0, KEY_READ, &hkey)) { DWORD dwType; TCHAR szDirectory[MAX_PATH + 1]; DWORD dwKeyLength = MAX_PATH * sizeof(TCHAR); if (ERROR_SUCCESS == ::RegQueryValueEx(hkey, _T("path"), 0, &dwType, (BYTE *) szDirectory, &dwKeyLength)) if (::_taccess(szDirectory, A_READ) == 0) { *m_pszPath = szDirectory; RegCloseKey(hkey); return; } RegCloseKey(hkey); } // Third, look for it in the %CommonFilesDir% directory. Look both in the hardcoded // subdirectory, and in a subdirectory loaded from a string resource. if (ERROR_SUCCESS == ::RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("Software\\Microsoft\\Windows\\CurrentVersion"), 0, KEY_READ, &hkey)) { DWORD dwKeyLength = MAX_PATH * sizeof(TCHAR); DWORD dwType; TCHAR szDirectory[MAX_PATH + 1]; if (ERROR_SUCCESS == ::RegQueryValueEx(hkey, _T("CommonFilesDir"), 0, &dwType, (BYTE *) szDirectory, &dwKeyLength)) { CString strTestPath(szDirectory); strTestPath += _T("\\Microsoft Shared\\MSInfo\\msinfo32.exe"); if (::_taccess(strTestPath, A_READ) == 0) { *m_pszPath = strTestPath; RegCloseKey(hkey); return; } if (strTestPath.LoadString(IDS_COMMONFILES_SUBPATH)) { strTestPath = CString(szDirectory) + strTestPath; if (::_taccess(strTestPath, A_READ) == 0) { *m_pszPath = strTestPath; RegCloseKey(hkey); return; } } } RegCloseKey(hkey); } // Finally, look for it using the string resource. CString strTestPath; if (strTestPath.LoadString(IDS_MSINFO_PATH)) { TCHAR szExpandedPath[MAX_PATH]; if (::ExpandEnvironmentStrings(strTestPath, szExpandedPath, MAX_PATH)) if (::_taccess(szExpandedPath, A_READ) == 0) { *m_pszPath = szExpandedPath; return; } } CString szNoMSCFile; szNoMSCFile.LoadString(IDS_NOMSCFILE); ::AfxMessageBox(szNoMSCFile); ::ThrowErrorException(); } /* * main - The main entry point for the stub executable. * * History: a-jsari 10/13/97 Initial version */ BOOL CMSInfoApp::InitInstance() { CString szResText; CString szResTitle; // Shouldn't need this. do { try { // FIX: Pre-load the memory resource in case memory problems develop. CMSInfoExecutable exeMSInfo(cszProgram); exeMSInfo.Find(); if (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); return FALSE; }