//************************************************************* // File name: delprof.c // // Description: Utility to delete user profiles // // // Microsoft Confidential // Copyright (c) Microsoft Corporation 1996 // All rights reserved // //************************************************************* #include #include #include #include #include #include "delprof.h" #include "userenv.h" #define ARRAYSIZE(a) (sizeof(a)/sizeof(a[0])) #define VALID_COMPUTER_NAME_LENGTH MAX_COMPUTERNAME_LENGTH + 3 // including \\ with Null terminator // // Globals // BOOL bQuiet; BOOL bIgnoreErrors; BOOL bPromptBeforeDelete; BOOL bLocalComputer = FALSE; TCHAR szComputerName[MAX_PATH]; TCHAR szSystemRoot[2*MAX_PATH]; TCHAR szSystemDrive[2*MAX_PATH]; LONG lDays; HINSTANCE hInst; LPDELETEITEM lpDeleteList; LONG lCurrentDateInDays; //************************************************************* // // Usage() // // Purpose: prints the usage info // // Parameters: void // // Return: void // // Comments: // // History: Date Author Comment // 5/18/96 ericflo Created // //************************************************************* void Usage (void) { TCHAR szTemp[200]; LoadString (hInst, IDS_USAGE1, szTemp, ARRAYSIZE(szTemp)); _tprintf(szTemp); LoadString (hInst, IDS_USAGE2, szTemp, ARRAYSIZE(szTemp)); _tprintf(szTemp); LoadString (hInst, IDS_USAGE3, szTemp, ARRAYSIZE(szTemp)); _tprintf(szTemp); LoadString (hInst, IDS_USAGE4, szTemp, ARRAYSIZE(szTemp)); _tprintf(szTemp); LoadString (hInst, IDS_USAGE5, szTemp, ARRAYSIZE(szTemp)); _tprintf(szTemp); LoadString (hInst, IDS_USAGE6, szTemp, ARRAYSIZE(szTemp)); _tprintf(szTemp); LoadString (hInst, IDS_USAGE7, szTemp, ARRAYSIZE(szTemp)); _tprintf(szTemp); LoadString (hInst, IDS_USAGE8, szTemp, ARRAYSIZE(szTemp)); _tprintf(szTemp); LoadString (hInst, IDS_USAGE9, szTemp, ARRAYSIZE(szTemp)); _tprintf(szTemp); } //************************************************************* // // InitializeGlobals() // // Purpose: Initializes the global variables // // Parameters: void // // Return: void // // Comments: // // History: Date Author Comment // 5/18/96 ericflo Created // //************************************************************* void InitializeGlobals (void) { OSVERSIONINFO ver; SYSTEMTIME systime; // // Initialize global variables // bQuiet = FALSE; bIgnoreErrors = FALSE; bPromptBeforeDelete = FALSE; szComputerName[0] = TEXT('\0'); lDays = 0; lpDeleteList = NULL; setlocale(LC_ALL,""); hInst = GetModuleHandle(TEXT("delprof.exe")); GetLocalTime (&systime); lCurrentDateInDays = gdate_dmytoday(systime.wYear, systime.wMonth, systime.wDay); } //************************************************************* // // CheckGlobals() // // Purpose: Checks the global variables // // Parameters: void // // Return: DWORD - ERROR_SUCCESS for success // win32 error code for failure // // Comments: // // History: Date Author Comment // 5/18/96 ericflo Created // //************************************************************* DWORD CheckGlobals (void) { DWORD dwSize; HRESULT hr; DWORD dwErr = ERROR_SUCCESS; TCHAR szTemp[MAX_PATH]; // // If szComputerName is still NULL, fill in the computer name // we're running on. // if (szComputerName[0] == TEXT('\0')) { szComputerName[0] = TEXT('\\'); szComputerName[1] = TEXT('\\'); dwSize = ARRAYSIZE(szComputerName) - 2; if (!GetComputerName(szComputerName + 2, &dwSize)) { return GetLastError(); } bLocalComputer = TRUE; } else { // // Make sure that the computer name starts with \\ // if (szComputerName[0] != TEXT('\\')) { szTemp[0] = TEXT('\\'); szTemp[1] = TEXT('\\'); hr = StringCchCopy(szTemp + 2, ARRAYSIZE(szTemp) - 2, szComputerName); if (FAILED(hr)) return HRESULT_CODE(hr); hr = StringCchCopy(szComputerName, ARRAYSIZE(szComputerName), szTemp); if (FAILED(hr)) return HRESULT_CODE(hr); } } // // If the user has requested to run in Quiet mode, // then we turn off the prompt on every delete option. // if (bQuiet) { bPromptBeforeDelete = FALSE; } return ERROR_SUCCESS; } //************************************************************* // // ParseCommandLine() // // Purpose: Parses the command line // // Parameters: lpCommandLine - Command line // // Return: TRUE if successful // FALSE if an error occurs // // Comments: // // History: Date Author Comment // 5/18/96 ericflo Created // //************************************************************* BOOL ParseCommandLine (LPTSTR lpCommandLine) { LPTSTR lpTemp; DWORD cchTemp; TCHAR szDays[32]; // // Check for NULL command line // if (!lpCommandLine || !*lpCommandLine) return TRUE; // // Find the executable name // while (*lpCommandLine && (_tcsncmp(lpCommandLine, TEXT("delprof"), 7) != 0)) { lpCommandLine++; } if (!*lpCommandLine) { return TRUE; } // // Find the first argument // while (*lpCommandLine && ((*lpCommandLine != TEXT(' ')) && (*lpCommandLine != TEXT('/')) && (*lpCommandLine != TEXT('-')))) { lpCommandLine++; } // // Skip white space // while (*lpCommandLine && (*lpCommandLine == TEXT(' '))) { lpCommandLine++; } if (!*lpCommandLine) { return TRUE; } // // We should be at the first argument now. // if ((*lpCommandLine != TEXT('/')) && (*lpCommandLine != TEXT('-'))) { Usage(); return FALSE; } while (1) { // // Increment the pointer and branch to the correct argument. // lpCommandLine++; switch (*lpCommandLine) { case TEXT('?'): Usage(); ExitProcess(0); break; case TEXT('Q'): case TEXT('q'): bQuiet = TRUE; lpCommandLine++; break; case TEXT('I'): case TEXT('i'): bIgnoreErrors = TRUE; lpCommandLine++; break; case TEXT('P'): case TEXT('p'): bPromptBeforeDelete = TRUE; lpCommandLine++; break; case TEXT('C'): case TEXT('c'): // // Find the colon // lpCommandLine++; if (*lpCommandLine != TEXT(':')) { Usage(); return FALSE; } // // Find the first character // lpCommandLine++; if (!*lpCommandLine) { Usage(); return FALSE; } // // Copy the computer name // cchTemp = 0; lpTemp = szComputerName; while (*lpCommandLine && (cchTemp < ARRAYSIZE(szComputerName) - 1) && ((*lpCommandLine != TEXT(' ')) && (*lpCommandLine != TEXT('/')))){ *lpTemp++ = *lpCommandLine++; cchTemp++; } if (cchTemp > VALID_COMPUTER_NAME_LENGTH) { Usage(); return FALSE; } *lpTemp = TEXT('\0'); break; case TEXT('D'): case TEXT('d'): // // Find the colon // lpCommandLine++; if (*lpCommandLine != TEXT(':')) { Usage(); return FALSE; } // // Find the first character // lpCommandLine++; if (!*lpCommandLine) { Usage(); return FALSE; } // // Copy the number of days (in characters) // lpTemp = szDays; cchTemp = 0; while (*lpCommandLine && (cchTemp < ARRAYSIZE(szDays) - 1) && ((*lpCommandLine != TEXT(' ')) && (*lpCommandLine != TEXT('/')) && (*lpCommandLine != TEXT('-')))) { *lpTemp++ = *lpCommandLine++; cchTemp++; } *lpTemp = TEXT('\0'); // // Convert the days into a number // lDays = _ttol(szDays); break; default: Usage(); return FALSE; } // // Skip white space // while (*lpCommandLine && (*lpCommandLine == TEXT(' '))) { lpCommandLine++; } if (!*lpCommandLine) { return TRUE; } // // We should be at the next argument now. // if ((*lpCommandLine != TEXT('/')) && (*lpCommandLine != TEXT('-'))) { Usage(); return FALSE; } } return TRUE; } //************************************************************* // // Confirm() // // Purpose: Confirm the user really wants to delete the profiles // // Parameters: void // // Return: TRUE if we should continue // FALSE if not // // Comments: // // History: Date Author Comment // 5/18/96 ericflo Created // //************************************************************* BOOL Confirm () { TCHAR szTemp[200]; TCHAR tChar, tTemp; // // If we are prompting for every profile, then don't // give the general prompt. // if (bPromptBeforeDelete) { return TRUE; } // // If the user is requesting a specific day count, // give a more appropriate confirmation message. // if (lDays > 0) { LoadString (hInst, IDS_CONFIRMDAYS, szTemp, ARRAYSIZE(szTemp)); _tprintf (szTemp, szComputerName, lDays); } else { LoadString (hInst, IDS_CONFIRM, szTemp, ARRAYSIZE(szTemp)); _tprintf (szTemp, szComputerName); } tChar = _gettchar(); tTemp = tChar; while (tTemp != TEXT('\n')) { tTemp = _gettchar(); } if ((tChar == TEXT('Y')) || (tChar == TEXT('y'))) { return TRUE; } // // If the user didn't press Y/y, then we bail. // LoadString (hInst, IDS_NO, szTemp, ARRAYSIZE(szTemp)); _tprintf (szTemp); return FALSE; } //************************************************************* // // PrintLastError() // // Purpose: Displays the last error string to the user // // Parameters: lError - error code // // Return: void // // Comments: // // History: Date Author Comment // 5/18/96 ericflo Created // //************************************************************* void PrintLastError(LONG lError) { TCHAR szMessage[MAX_PATH]; FormatMessage( FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM, NULL, lError, MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), szMessage, ARRAYSIZE(szMessage), NULL); _tprintf (szMessage); } //************************************************************* // // AddNode() // // Purpose: Adds a new node to the link list // // Parameters: szSubKey - SubKey // szProfilePath - Profile Path (or NULL) // bDir - Directory or file // // Return: TRUE if successful // FALSE if an error occurs // // Comments: szProfilePath can be NULL. In this case, we // are just removing the bogus registry entry. // // History: Date Author Comment // 5/18/96 ericflo Created // //************************************************************* BOOL AddNode (LPTSTR szSubKey, LPTSTR szProfilePath, BOOL bDir) { LPDELETEITEM lpItem, lpTemp; UINT uAlloc = 0; DWORD cchSubKeyWithNull = 0, cchProfilePathWithNull = 0; HRESULT hr; // // Create a new node // cchSubKeyWithNull = lstrlen(szSubKey) + 1; uAlloc = sizeof(DELETEITEM) + cchSubKeyWithNull * sizeof(TCHAR); if (szProfilePath) { cchProfilePathWithNull = lstrlen(szProfilePath) + 1; uAlloc += cchProfilePathWithNull * sizeof(TCHAR); } lpItem = LocalAlloc (LPTR, uAlloc); if (!lpItem) { return FALSE; } lpItem->lpSubKey = (LPTSTR)((LPBYTE)lpItem + sizeof(DELETEITEM)); hr = StringCchCopy(lpItem->lpSubKey, cchSubKeyWithNull, szSubKey); if (FAILED(hr)) { LocalFree(lpItem); return FALSE; } if (szProfilePath) { lpItem->lpProfilePath = lpItem->lpSubKey + lstrlen(szSubKey) + 1; hr = StringCchCopy(lpItem->lpProfilePath, cchProfilePathWithNull, szProfilePath); if (FAILED(hr)) { LocalFree(lpItem); return FALSE; } } else { lpItem->lpProfilePath = NULL; } lpItem->bDir = bDir; // // Add this node to the global lpItemList // if (lpDeleteList) { lpTemp = lpDeleteList; while (lpTemp->pNext) { lpTemp = lpTemp->pNext; } lpTemp->pNext = lpItem; } else { lpDeleteList = lpItem; } return TRUE; } //************************************************************* // // GetProfileDateInDays() // // Purpose: Gets the profile date in days. // // Parameters: szProfilePath - Profile path // bDir - Directory or file // // Return: age in days. // // Comments: // // History: Date Author Comment // 5/18/96 ericflo Created // //************************************************************* LONG GetProfileDateInDays(LPTSTR szProfilePath, BOOL bDir) { TCHAR szTemp[MAX_PATH]; HANDLE hFile; WIN32_FIND_DATA fd; LONG days; SYSTEMTIME systime; FILETIME ft; HRESULT hr; if (bDir) { // // Tack on ntuser.* to find the registry hive. // hr = StringCchCopy(szTemp, ARRAYSIZE(szTemp), szProfilePath); if (FAILED(hr)) return lCurrentDateInDays; hr = StringCchCat(szTemp, ARRAYSIZE(szTemp), TEXT("\\ntuser.*")); if (FAILED(hr)) return lCurrentDateInDays; hFile = FindFirstFile (szTemp, &fd); } else { // // szProfilePath points to a file. // hFile = FindFirstFile (szProfilePath, &fd); } if (hFile != INVALID_HANDLE_VALUE) { FindClose (hFile); FileTimeToLocalFileTime (&fd.ftLastWriteTime, &ft); FileTimeToSystemTime (&ft, &systime); days = gdate_dmytoday(systime.wYear, systime.wMonth, systime.wDay); } else { days = lCurrentDateInDays; } return days; } //************************************************************* // // CheckProfile() // // Purpose: Checks if the given profile should be deleted. // If so, it is added to the list. // // Parameters: hKeyLM - Local Machine key // hKeyUsers - HKEY_USERS key // lpSid - Sid string (key name) // // Return: TRUE if successful // FALSE if not // // Comments: // // History: Date Author Comment // 5/18/96 ericflo Created // //************************************************************* BOOL CheckProfile (HKEY hKeyLM, HKEY hKeyUsers, LPTSTR lpSid) { LONG lResult; HKEY hkey = NULL; TCHAR szSubKey[MAX_PATH]; DWORD dwSize, dwType; TCHAR szTemp[MAX_PATH]; TCHAR szProfilePath[MAX_PATH]; TCHAR szError[200]; DWORD dwAttribs; BOOL bDir; LONG lProfileDateInDays; HRESULT hr; // // Check if the profile is in use // lResult = RegOpenKeyEx (hKeyUsers, lpSid, 0, KEY_READ, &hkey); if (lResult == ERROR_SUCCESS) { RegCloseKey (hkey); return TRUE; } // // Open the profile information // hr = StringCchPrintf(szSubKey, ARRAYSIZE(szSubKey), TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList\\%s"), lpSid); if (FAILED(hr)) { PrintLastError(HRESULT_CODE(hr)); return FALSE; } lResult = RegOpenKeyEx (hKeyLM, szSubKey, 0, KEY_READ, &hkey); if (lResult != ERROR_SUCCESS) { LoadString (hInst, IDS_FAILEDOPENPROFILE, szError, ARRAYSIZE(szError)); _tprintf(szError, lpSid); PrintLastError(lResult); return FALSE; } // // Query for the ProfileImagePath // dwSize = MAX_PATH * sizeof(TCHAR); lResult = RegQueryValueEx (hkey, TEXT("ProfileImagePath"), NULL, &dwType, (LPBYTE)szTemp, &dwSize); RegCloseKey(hkey); hkey = NULL; if (lResult != ERROR_SUCCESS) { LoadString (hInst, IDS_FAILEDPATHQUERY, szError, ARRAYSIZE(szError)); _tprintf(szError, lpSid); PrintLastError(lResult); return FALSE; } // // Expand the path. // if (_tcsnicmp(TEXT("%SystemRoot%"), szTemp, 12) == 0) { hr = StringCchPrintf(szProfilePath, ARRAYSIZE(szProfilePath), TEXT("%s\\%s"), szSystemRoot, szTemp+13); if (FAILED(hr)) { PrintLastError(HRESULT_CODE(hr)); return FALSE; } } else if (_tcsnicmp(TEXT("%SystemDrive%"), szTemp, 13) == 0) { hr = StringCchPrintf(szProfilePath, ARRAYSIZE(szProfilePath), TEXT("%s\\%s"), szSystemDrive, szTemp+14); if (FAILED(hr)) { PrintLastError(HRESULT_CODE(hr)); return FALSE; } } else if (NULL == _tcschr(szTemp, TEXT('%')) && !bLocalComputer) { if (TEXT(':') == szTemp[1]) szTemp[1] = TEXT('$'); hr = StringCchPrintf(szProfilePath, ARRAYSIZE(szProfilePath), TEXT("%s\\%s"), szComputerName, szTemp); if (FAILED(hr)) { PrintLastError(HRESULT_CODE(hr)); return FALSE; } } else { LoadString (hInst, IDS_SKIPPROFILE, szError, ARRAYSIZE(szError)); _tprintf(szError, szTemp); return TRUE; } // // Is this a directory or a file? // dwAttribs = GetFileAttributes (szProfilePath); if (dwAttribs == -1) { AddNode (szSubKey, NULL, FALSE); return TRUE; } bDir = (dwAttribs & FILE_ATTRIBUTE_DIRECTORY) ? TRUE : FALSE; // // Check Time/Date stamp. If the profile date is older // than the amount specified, add it to the delete list. // lProfileDateInDays = GetProfileDateInDays(szProfilePath, bDir); if (lCurrentDateInDays >= lProfileDateInDays) { if ((lCurrentDateInDays - lProfileDateInDays) >= lDays) { AddNode (szSubKey, szProfilePath, bDir); } } return TRUE; } //************************************************************* // // DelProfiles() // // Purpose: Deletes the user profiles // // Parameters: void // // Return: TRUE if successful // FALSE if an error occurs // // Comments: // // History: Date Author Comment // 5/18/96 ericflo Created // //************************************************************* BOOL DelProfiles(void) { HKEY hKeyLM = NULL, hKeyUsers = NULL, hKeyProfiles = NULL; HKEY hKeyCurrentVersion = NULL; LONG lResult; BOOL bResult = FALSE, bTemp; TCHAR szError[200]; DWORD dwIndex = 0, dwNameSize; DWORD dwBufferSize; TCHAR szName[MAX_PATH]; TCHAR szTemp[MAX_PATH]; TCHAR tChar, tTemp; FILETIME ft; LPDELETEITEM lpTemp; LPTSTR pSid, lpEnd; DWORD lProfileKeyLen; HRESULT hr; lProfileKeyLen = lstrlen(TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList"))+1; // // Open the registry // lResult = RegConnectRegistry(szComputerName, HKEY_LOCAL_MACHINE, &hKeyLM); if (lResult != ERROR_SUCCESS) { PrintLastError(lResult); goto Exit; } lResult = RegConnectRegistry(szComputerName, HKEY_USERS, &hKeyUsers); if (lResult != ERROR_SUCCESS) { PrintLastError(lResult); goto Exit; } // // Get the value of %SystemRoot% and %SystemDrive% relative to the computer // lResult = RegOpenKeyEx(hKeyLM, TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion"), 0, KEY_READ, &hKeyCurrentVersion); if (lResult != ERROR_SUCCESS) { PrintLastError(lResult); goto Exit; } dwBufferSize = sizeof(szTemp); lResult = RegQueryValueEx(hKeyCurrentVersion, TEXT("SystemRoot"), NULL, NULL, (BYTE *) szTemp, &dwBufferSize); if (lResult != ERROR_SUCCESS) { PrintLastError(lResult); goto Exit; } if (!bLocalComputer) { szTemp[1] = TEXT('$'); hr = StringCchCopy(szSystemRoot, ARRAYSIZE(szSystemRoot), szComputerName); if (FAILED(hr)) { PrintLastError(HRESULT_CODE(hr)); goto Exit; } hr = StringCchCat(szSystemRoot, ARRAYSIZE(szSystemRoot), TEXT("\\")); if (FAILED(hr)) { PrintLastError(HRESULT_CODE(hr)); goto Exit; } hr = StringCchCat(szSystemRoot, ARRAYSIZE(szSystemRoot), szTemp); if (FAILED(hr)) { PrintLastError(HRESULT_CODE(hr)); goto Exit; } hr = StringCchCopy(szSystemDrive, ARRAYSIZE(szSystemDrive), szComputerName); if (FAILED(hr)) { PrintLastError(HRESULT_CODE(hr)); goto Exit; } hr = StringCchCat(szSystemDrive, ARRAYSIZE(szSystemDrive), TEXT("\\")); if (FAILED(hr)) { PrintLastError(HRESULT_CODE(hr)); goto Exit; } hr = StringCchCatN(szSystemDrive, ARRAYSIZE(szSystemDrive), szTemp, 2); if (FAILED(hr)) { PrintLastError(HRESULT_CODE(hr)); goto Exit; } } else { szSystemDrive[0] = TEXT('\0'); hr = StringCchCatN(szSystemDrive, ARRAYSIZE(szSystemDrive), szTemp, 2); if (FAILED(hr)) { PrintLastError(HRESULT_CODE(hr)); goto Exit; } hr = StringCchCopy(szSystemRoot, ARRAYSIZE(szSystemRoot), szTemp); if (FAILED(hr)) { PrintLastError(HRESULT_CODE(hr)); goto Exit; } } // // Open the ProfileList key // lResult = RegOpenKeyEx (hKeyLM, TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList"), 0, KEY_ALL_ACCESS, &hKeyProfiles); if (lResult != ERROR_SUCCESS) { LoadString (hInst, IDS_FAILEDPROFILELIST, szError, ARRAYSIZE(szError)); _tprintf(szError); PrintLastError(lResult); goto Exit; } // // Enumerate the profiles // dwNameSize = ARRAYSIZE(szName); lResult = RegEnumKeyEx(hKeyProfiles, dwIndex, szName, &dwNameSize, NULL, NULL, NULL, &ft); while (lResult == ERROR_SUCCESS) { // // Hand the profile info off to CheckProfile // to determine if the profile should be deleted or not. // if (!CheckProfile (hKeyLM, hKeyUsers, szName)) { if (!bIgnoreErrors) { goto Exit; } } // // Reset for the next loop // dwIndex++; dwNameSize = ARRAYSIZE(szName); lResult = RegEnumKeyEx(hKeyProfiles, dwIndex, szName, &dwNameSize, NULL, NULL, NULL, &ft); } // // Check for errors // if (lResult != ERROR_NO_MORE_ITEMS) { LoadString (hInst, IDS_FAILEDENUM, szError, ARRAYSIZE(szError)); _tprintf(szError); PrintLastError(lResult); goto Exit; } // // Remove profiles // lpTemp = lpDeleteList; while (lpTemp) { if (lpTemp->lpProfilePath) { // // Prompt before deleting the profile (if approp). // if (bPromptBeforeDelete) { while (1) { LoadString (hInst, IDS_DELETEPROMPT, szError, ARRAYSIZE(szError)); _tprintf (szError, lpTemp->lpProfilePath); tChar = _gettchar(); tTemp = tChar; while (tTemp != TEXT('\n')) { tTemp = _gettchar(); } if ((tChar == TEXT('N')) || (tChar == TEXT('n'))) { goto LoopAgain; } if ((tChar == TEXT('A')) || (tChar == TEXT('a'))) { bPromptBeforeDelete = FALSE; break; } if ((tChar == TEXT('Y')) || (tChar == TEXT('y'))) { break; } } } // // Delete the profile // LoadString (hInst, IDS_DELETING, szError, ARRAYSIZE(szError)); _tprintf (szError, lpTemp->lpProfilePath); pSid = lpTemp->lpSubKey+lProfileKeyLen; bTemp = DeleteProfile(pSid, lpTemp->lpProfilePath, ((bLocalComputer)? NULL:szComputerName)); if (bTemp) { LoadString (hInst, IDS_SUCCESS, szError, ARRAYSIZE(szError)); _tprintf (szError, lpTemp->lpProfilePath); } else { LoadString (hInst, IDS_FAILED, szError, ARRAYSIZE(szError)); _tprintf (szError, lpTemp->lpProfilePath); PrintLastError(GetLastError()); } } else { // // If there isn't a profile path, then we are just // cleaning up the bogus registry entry. // bTemp = TRUE; // // Clean up the registry. // RegDeleteKey (hKeyLM, lpTemp->lpSubKey); } // // Did the clean up fail? // if (!bTemp) { if (!bIgnoreErrors) { goto Exit; } } LoopAgain: lpTemp = lpTemp->pNext; } // // Success // bResult = TRUE; Exit: if (hKeyCurrentVersion) RegCloseKey(hKeyCurrentVersion); if (hKeyProfiles) RegCloseKey(hKeyProfiles); if (hKeyLM) RegCloseKey(hKeyLM); if (hKeyUsers) RegCloseKey(hKeyUsers); if (lpDeleteList) { do { lpTemp = lpDeleteList->pNext; LocalFree (lpDeleteList); lpDeleteList = lpTemp; } while (lpDeleteList); } return bResult; } //************************************************************* // // main() // // Purpose: main entry point // // Parameters: argc - number of arguments // argv - arguments // // Return: 0 if successful // 1 if an error occurs // // Comments: // // History: Date Author Comment // 5/18/96 ericflo Created // //************************************************************* int __cdecl main( int argc, char *argv[]) { DWORD dwErr; // // Initialize the globals // InitializeGlobals(); // // Parse the command line // if (!ParseCommandLine(GetCommandLine())) { return 1; } // // Check the globals variables // dwErr = CheckGlobals(); if (ERROR_SUCCESS != dwErr) { PrintLastError(dwErr); return 1; } // // Confirmation // if (!bQuiet) { if (!Confirm()) { return 1; } } // // Remove the profiles // if (!DelProfiles()) { return 1; } return 0; }