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