303 lines
8.7 KiB
C++
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;
|
||
|
}
|