Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

302 lines
8.7 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1998.
  5. //
  6. // File: apmutils.cpp
  7. //
  8. // Contents: Private utility functions for use during APM driver upgrade
  9. //
  10. // Notes:
  11. //
  12. // Author: t-sdey 10 July 98
  13. //
  14. //----------------------------------------------------------------------------
  15. #include <winnt32.h>
  16. //+---------------------------------------------------------------------------
  17. //
  18. // Function: RemoveSubString
  19. //
  20. // Purpose: Remove (the first occurrence of) a specified substring
  21. // from a string
  22. //
  23. // Arguments: szString [in] Complete string
  24. // szSubString [in] Substring to find and remove
  25. // pszRemoved [out] New string is placed here
  26. //
  27. // Returns: TRUE if a string was subtracted
  28. // FALSE if szString is NULL, if szSubString is NULL, or
  29. // if szSubString is not in szString. When FALSE is returned,
  30. // pszRemoved will be NULL.
  31. //
  32. // Author: t-sdey 10 July 98
  33. //
  34. // Notes: Assumes szString and szSubString are null-terminated.
  35. // Pass in NULL for pszRemoved because it will be overwritten.
  36. //
  37. BOOL RemoveSubString(IN TCHAR* szString,
  38. IN TCHAR* szSubString,
  39. OUT TCHAR** pszRemoved)
  40. {
  41. *pszRemoved = NULL;
  42. if ((!szString) || (!szSubString))
  43. return FALSE;
  44. // Get the string lengths
  45. int lenString = lstrlen(szString);
  46. int lenSubString = lstrlen(szSubString);
  47. int lenNew = lenString - lenSubString;
  48. // Search the string to find our substring and construct a new
  49. // one with the substring removed
  50. TCHAR* szNew = NULL;
  51. TCHAR* szStart = _tcsstr(szString, szSubString);
  52. if (szStart) {
  53. // Allocate space for the new string
  54. szNew = new TCHAR[lenNew + 1];
  55. if (!szNew) {
  56. // Out of memory!
  57. return FALSE;
  58. }
  59. // Construct the new string
  60. TCHAR* szCur = NULL;
  61. int i = 0;
  62. for (szCur = szString;
  63. (szCur != szStart) && (i < lenNew) && (szCur[0] != '\0');
  64. szCur++) {
  65. szNew[i] = szCur[0];
  66. i++;
  67. }
  68. for (szCur = szCur + lenSubString;
  69. (szCur[0] != '\0') && (i < lenNew);
  70. szCur++) {
  71. szNew[i] = szCur[0];
  72. i++;
  73. }
  74. szNew[i] = '\0';
  75. *pszRemoved = szNew;
  76. } else {
  77. return FALSE;
  78. }
  79. return TRUE;
  80. }
  81. //+---------------------------------------------------------------------------
  82. //
  83. // Function: DeleteRegKeyAndSubkeys
  84. //
  85. // Purpose: (Recursively) Remove a registry key and all of its subkeys
  86. //
  87. // Arguments: hKey [in] Handle to an open registry key
  88. // lpszSubKey [in] Name of a subkey to be deleted along with all
  89. // of its subkeys
  90. //
  91. // Returns: ERROR_SUCCESS if entire subtree was successfully deleted.
  92. // ERROR_ACCESS_DENIED if given subkey could not be deleted.
  93. //
  94. // Author: t-sdey 15 July 98
  95. //
  96. // Notes: Snitched from regedit.
  97. // This specifically does not attempt to deal rationally with the
  98. // case where the caller may not have access to some of the subkeys
  99. // of the key to be deleted. In this case, all the subkeys which
  100. // the caller can delete will be deleted, but the api will still
  101. // return ERROR_ACCESS_DENIED.
  102. //
  103. LONG DeleteRegKeyAndSubkeys(IN HKEY hKey,
  104. IN LPTSTR lpszSubKey)
  105. {
  106. DWORD i;
  107. HKEY Key;
  108. LONG Status;
  109. DWORD ClassLength=0;
  110. DWORD SubKeys;
  111. DWORD MaxSubKey;
  112. DWORD MaxClass;
  113. DWORD Values;
  114. DWORD MaxValueName;
  115. DWORD MaxValueData;
  116. DWORD SecurityLength;
  117. FILETIME LastWriteTime;
  118. LPTSTR NameBuffer;
  119. //
  120. // First open the given key so we can enumerate its subkeys
  121. //
  122. Status = RegOpenKeyEx(hKey,
  123. lpszSubKey,
  124. 0,
  125. KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE,
  126. &Key);
  127. if (Status != ERROR_SUCCESS) {
  128. //
  129. // possibly we have delete access, but not enumerate/query.
  130. // So go ahead and try the delete call, but don't worry about
  131. // any subkeys. If we have any, the delete will fail anyway.
  132. //
  133. return(RegDeleteKey(hKey,lpszSubKey));
  134. }
  135. //
  136. // Use RegQueryInfoKey to determine how big to allocate the buffer
  137. // for the subkey names.
  138. //
  139. Status = RegQueryInfoKey(Key,
  140. NULL,
  141. &ClassLength,
  142. 0,
  143. &SubKeys,
  144. &MaxSubKey,
  145. &MaxClass,
  146. &Values,
  147. &MaxValueName,
  148. &MaxValueData,
  149. &SecurityLength,
  150. &LastWriteTime);
  151. if ((Status != ERROR_SUCCESS) &&
  152. (Status != ERROR_MORE_DATA) &&
  153. (Status != ERROR_INSUFFICIENT_BUFFER)) {
  154. RegCloseKey(Key);
  155. return(Status);
  156. }
  157. NameBuffer = (LPTSTR) LocalAlloc(LPTR, (MaxSubKey + 1)*sizeof(TCHAR));
  158. if (NameBuffer == NULL) {
  159. RegCloseKey(Key);
  160. return(ERROR_NOT_ENOUGH_MEMORY);
  161. }
  162. //
  163. // Enumerate subkeys and apply ourselves to each one.
  164. //
  165. i=0;
  166. do {
  167. Status = RegEnumKey(Key,
  168. i,
  169. NameBuffer,
  170. MaxSubKey+1);
  171. if (Status == ERROR_SUCCESS) {
  172. Status = DeleteRegKeyAndSubkeys(Key, NameBuffer);
  173. }
  174. if (Status != ERROR_SUCCESS) {
  175. //
  176. // Failed to delete the key at the specified index. Increment
  177. // the index and keep going. We could probably bail out here,
  178. // since the api is going to fail, but we might as well keep
  179. // going and delete everything we can.
  180. //
  181. ++i;
  182. }
  183. } while ( (Status != ERROR_NO_MORE_ITEMS) &&
  184. (i < SubKeys) );
  185. LocalFree((HLOCAL) NameBuffer);
  186. RegCloseKey(Key);
  187. return(RegDeleteKey(hKey,lpszSubKey));
  188. }
  189. //+---------------------------------------------------------------------------
  190. //
  191. // Function: CallUninstallFunction
  192. //
  193. // Purpose: Call the uninstall function found in the registry for a
  194. // software product.
  195. //
  196. // Arguments: szRegKey [in] Location of uninstall key in the registry
  197. // (ex: HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Softex APM Drivers)
  198. // szSilentFlag [in] String which will be appended to the
  199. // command to force quiet uninstall
  200. //
  201. // Returns: S_OK if call to uninstall function was successful
  202. // S_FALSE if call was unsuccessful or function could not be found
  203. //
  204. // Author: t-sdey 29 July 98
  205. //
  206. // Notes: Send in szSilentFlag=NULL for no flag
  207. //
  208. HRESULT CallUninstallFunction(IN LPTSTR szRegKey,
  209. IN LPTSTR szSilentFlag)
  210. {
  211. HKEY hkey = NULL;
  212. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  213. szRegKey,
  214. 0,
  215. KEY_ALL_ACCESS,
  216. &hkey) == ERROR_SUCCESS) {
  217. // Found uninstall utility
  218. // Get the uninstall command from the registry
  219. long lMax = (65535 / sizeof(TCHAR)) + 1;
  220. if (szSilentFlag != NULL)
  221. lMax += lstrlen(szSilentFlag);
  222. DWORD dwValType = REG_SZ;
  223. TCHAR* pszVal = new TCHAR[lMax];
  224. DWORD dwValSz = lMax;
  225. if (!pszVal) {
  226. // Out of memory
  227. if (hkey)
  228. RegCloseKey(hkey);
  229. return S_FALSE;
  230. }
  231. if (RegQueryValueEx(hkey,
  232. TEXT("UninstallString"),
  233. NULL,
  234. &dwValType,
  235. (LPBYTE) pszVal,
  236. &dwValSz) != ERROR_SUCCESS) {
  237. // Some error occurred
  238. if (hkey)
  239. RegCloseKey(hkey);
  240. return S_FALSE;
  241. }
  242. // Append " -a" to the string to make it uninstall quietly
  243. if (szSilentFlag != NULL)
  244. _tcscat(pszVal, szSilentFlag);
  245. // Now run the uninstall command
  246. STARTUPINFO si = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
  247. si.cb = sizeof(si);
  248. PROCESS_INFORMATION pi;
  249. if (CreateProcess(NULL, pszVal, NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS,
  250. NULL, NULL, &si, &pi) == FALSE) {
  251. // An error occurred
  252. if (pszVal)
  253. delete[] pszVal;
  254. if (hkey)
  255. RegCloseKey(hkey);
  256. return S_FALSE;
  257. } else {
  258. // The process was started successfully. Wait for it to finish.
  259. // This is necessary because we loop in DetectAndDisable to make
  260. // sure the drivers really were removed.
  261. WaitForSingleObject(pi.hProcess, INFINITE);
  262. CloseHandle(pi.hProcess);
  263. CloseHandle(pi.hThread);
  264. }
  265. if (pszVal)
  266. delete[] pszVal;
  267. } else {
  268. // Could not find uninstall command
  269. if (hkey)
  270. RegCloseKey(hkey);
  271. return S_FALSE;
  272. }
  273. if (hkey)
  274. RegCloseKey(hkey);
  275. return S_OK;
  276. }