windows-nt/Source/XPSP1/NT/base/ntsetup/winnt32/apmupgrd/apmutils.cpp
2020-09-26 16:20:57 +08:00

303 lines
8.7 KiB
C++

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1998.
//
// File: apmutils.cpp
//
// Contents: Private utility functions for use during APM driver upgrade
//
// Notes:
//
// Author: t-sdey 10 July 98
//
//----------------------------------------------------------------------------
#include <winnt32.h>
//+---------------------------------------------------------------------------
//
// Function: RemoveSubString
//
// Purpose: Remove (the first occurrence of) a specified substring
// from a string
//
// Arguments: szString [in] Complete string
// szSubString [in] Substring to find and remove
// pszRemoved [out] New string is placed here
//
// Returns: TRUE if a string was subtracted
// FALSE if szString is NULL, if szSubString is NULL, or
// if szSubString is not in szString. When FALSE is returned,
// pszRemoved will be NULL.
//
// Author: t-sdey 10 July 98
//
// Notes: Assumes szString and szSubString are null-terminated.
// Pass in NULL for pszRemoved because it will be overwritten.
//
BOOL RemoveSubString(IN TCHAR* szString,
IN TCHAR* szSubString,
OUT TCHAR** pszRemoved)
{
*pszRemoved = NULL;
if ((!szString) || (!szSubString))
return FALSE;
// Get the string lengths
int lenString = lstrlen(szString);
int lenSubString = lstrlen(szSubString);
int lenNew = lenString - lenSubString;
// Search the string to find our substring and construct a new
// one with the substring removed
TCHAR* szNew = NULL;
TCHAR* szStart = _tcsstr(szString, szSubString);
if (szStart) {
// Allocate space for the new string
szNew = new TCHAR[lenNew + 1];
if (!szNew) {
// Out of memory!
return FALSE;
}
// Construct the new string
TCHAR* szCur = NULL;
int i = 0;
for (szCur = szString;
(szCur != szStart) && (i < lenNew) && (szCur[0] != '\0');
szCur++) {
szNew[i] = szCur[0];
i++;
}
for (szCur = szCur + lenSubString;
(szCur[0] != '\0') && (i < lenNew);
szCur++) {
szNew[i] = szCur[0];
i++;
}
szNew[i] = '\0';
*pszRemoved = szNew;
} else {
return FALSE;
}
return TRUE;
}
//+---------------------------------------------------------------------------
//
// Function: DeleteRegKeyAndSubkeys
//
// Purpose: (Recursively) Remove a registry key and all of its subkeys
//
// Arguments: hKey [in] Handle to an open registry key
// lpszSubKey [in] Name of a subkey to be deleted along with all
// of its subkeys
//
// Returns: ERROR_SUCCESS if entire subtree was successfully deleted.
// ERROR_ACCESS_DENIED if given subkey could not be deleted.
//
// Author: t-sdey 15 July 98
//
// Notes: Snitched from regedit.
// This specifically does not attempt to deal rationally with the
// case where the caller may not have access to some of the subkeys
// of the key to be deleted. In this case, all the subkeys which
// the caller can delete will be deleted, but the api will still
// return ERROR_ACCESS_DENIED.
//
LONG DeleteRegKeyAndSubkeys(IN HKEY hKey,
IN LPTSTR lpszSubKey)
{
DWORD i;
HKEY Key;
LONG Status;
DWORD ClassLength=0;
DWORD SubKeys;
DWORD MaxSubKey;
DWORD MaxClass;
DWORD Values;
DWORD MaxValueName;
DWORD MaxValueData;
DWORD SecurityLength;
FILETIME LastWriteTime;
LPTSTR NameBuffer;
//
// First open the given key so we can enumerate its subkeys
//
Status = RegOpenKeyEx(hKey,
lpszSubKey,
0,
KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE,
&Key);
if (Status != ERROR_SUCCESS) {
//
// possibly we have delete access, but not enumerate/query.
// So go ahead and try the delete call, but don't worry about
// any subkeys. If we have any, the delete will fail anyway.
//
return(RegDeleteKey(hKey,lpszSubKey));
}
//
// Use RegQueryInfoKey to determine how big to allocate the buffer
// for the subkey names.
//
Status = RegQueryInfoKey(Key,
NULL,
&ClassLength,
0,
&SubKeys,
&MaxSubKey,
&MaxClass,
&Values,
&MaxValueName,
&MaxValueData,
&SecurityLength,
&LastWriteTime);
if ((Status != ERROR_SUCCESS) &&
(Status != ERROR_MORE_DATA) &&
(Status != ERROR_INSUFFICIENT_BUFFER)) {
RegCloseKey(Key);
return(Status);
}
NameBuffer = (LPTSTR) LocalAlloc(LPTR, (MaxSubKey + 1)*sizeof(TCHAR));
if (NameBuffer == NULL) {
RegCloseKey(Key);
return(ERROR_NOT_ENOUGH_MEMORY);
}
//
// Enumerate subkeys and apply ourselves to each one.
//
i=0;
do {
Status = RegEnumKey(Key,
i,
NameBuffer,
MaxSubKey+1);
if (Status == ERROR_SUCCESS) {
Status = DeleteRegKeyAndSubkeys(Key, NameBuffer);
}
if (Status != ERROR_SUCCESS) {
//
// Failed to delete the key at the specified index. Increment
// the index and keep going. We could probably bail out here,
// since the api is going to fail, but we might as well keep
// going and delete everything we can.
//
++i;
}
} while ( (Status != ERROR_NO_MORE_ITEMS) &&
(i < SubKeys) );
LocalFree((HLOCAL) NameBuffer);
RegCloseKey(Key);
return(RegDeleteKey(hKey,lpszSubKey));
}
//+---------------------------------------------------------------------------
//
// Function: CallUninstallFunction
//
// Purpose: Call the uninstall function found in the registry for a
// software product.
//
// Arguments: szRegKey [in] Location of uninstall key in the registry
// (ex: HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Softex APM Drivers)
// szSilentFlag [in] String which will be appended to the
// command to force quiet uninstall
//
// Returns: S_OK if call to uninstall function was successful
// S_FALSE if call was unsuccessful or function could not be found
//
// Author: t-sdey 29 July 98
//
// Notes: Send in szSilentFlag=NULL for no flag
//
HRESULT CallUninstallFunction(IN LPTSTR szRegKey,
IN LPTSTR szSilentFlag)
{
HKEY hkey = NULL;
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
szRegKey,
0,
KEY_ALL_ACCESS,
&hkey) == ERROR_SUCCESS) {
// Found uninstall utility
// Get the uninstall command from the registry
long lMax = (65535 / sizeof(TCHAR)) + 1;
if (szSilentFlag != NULL)
lMax += lstrlen(szSilentFlag);
DWORD dwValType = REG_SZ;
TCHAR* pszVal = new TCHAR[lMax];
DWORD dwValSz = lMax;
if (!pszVal) {
// Out of memory
if (hkey)
RegCloseKey(hkey);
return S_FALSE;
}
if (RegQueryValueEx(hkey,
TEXT("UninstallString"),
NULL,
&dwValType,
(LPBYTE) pszVal,
&dwValSz) != ERROR_SUCCESS) {
// Some error occurred
if (hkey)
RegCloseKey(hkey);
return S_FALSE;
}
// Append " -a" to the string to make it uninstall quietly
if (szSilentFlag != NULL)
_tcscat(pszVal, szSilentFlag);
// Now run the uninstall command
STARTUPINFO si = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
si.cb = sizeof(si);
PROCESS_INFORMATION pi;
if (CreateProcess(NULL, pszVal, NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS,
NULL, NULL, &si, &pi) == FALSE) {
// An error occurred
if (pszVal)
delete[] pszVal;
if (hkey)
RegCloseKey(hkey);
return S_FALSE;
} else {
// The process was started successfully. Wait for it to finish.
// This is necessary because we loop in DetectAndDisable to make
// sure the drivers really were removed.
WaitForSingleObject(pi.hProcess, INFINITE);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
if (pszVal)
delete[] pszVal;
} else {
// Could not find uninstall command
if (hkey)
RegCloseKey(hkey);
return S_FALSE;
}
if (hkey)
RegCloseKey(hkey);
return S_OK;
}