Leaked source code of windows server 2003
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.

722 lines
22 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // File: NCCMAK.CPP
  4. //
  5. // Module: NetOC.DLL
  6. //
  7. // Synopsis: Implements the dll entry points required to integrate into
  8. // NetOC.DLL the installation of the following components.
  9. //
  10. // NETCMAK
  11. //
  12. // Copyright (C) Microsoft Corporation. All rights reserved.
  13. //
  14. // Author: a-anasj 9 Mar 1998
  15. // quintinb 18 Sep 1998 -- rewrote
  16. //
  17. //+---------------------------------------------------------------------------
  18. #include "pch.h"
  19. #pragma hdrstop
  20. #include <atlbase.h>
  21. extern CComModule _Module;
  22. #include <atlcom.h>
  23. #include "ncatl.h"
  24. #include "resource.h"
  25. #include "nccm.h"
  26. //
  27. // Define Globals
  28. //
  29. WCHAR g_szCmakPath[MAX_PATH+1];
  30. //
  31. // Define Strings Chars
  32. //
  33. static const WCHAR c_szCmakRegPath[] = L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\CMAK.EXE";
  34. static const WCHAR c_szPathValue[] = L"Path";
  35. static const WCHAR c_szProfiles32Fmt[] = L"%s\\Profiles-32";
  36. static const WCHAR c_szCm32Fmt[] = L"%s\\cm32";
  37. static const WCHAR c_szProfilesFmt[] = L"%s\\Profiles";
  38. static const WCHAR c_szSupportFmt[] = L"%s\\Support";
  39. static const WCHAR c_szCmHelpFmt[] = L"%s\\Support\\CmHelp";
  40. static const WCHAR c_szCmakGroup[] = L"Connection Manager Administration Kit";
  41. const DWORD c_dwCmakDirID = 123174; // just must be larger than DIRID_USER = 0x8000;
  42. //+---------------------------------------------------------------------------
  43. //
  44. // Function: HrOcCmakPreQueueFiles
  45. //
  46. // Purpose: Called by optional components installer code before any files
  47. // are copied to handle any additional installation processing
  48. // for the Connection Manager Administration Kit.
  49. //
  50. // Arguments:
  51. // pnocd [in] Pointer to NETOC data.
  52. //
  53. // Returns: S_OK if successfull, Win32 error otherwise.
  54. //
  55. // Author: quintinb 18 Sep 1998
  56. //
  57. // Notes:
  58. //
  59. HRESULT HrOcCmakPreQueueFiles(PNETOCDATA pnocd)
  60. {
  61. HRESULT hr = S_OK;
  62. if ((IT_INSTALL == pnocd->eit) || (IT_UPGRADE == pnocd->eit) || (IT_REMOVE == pnocd->eit))
  63. {
  64. // Figure out if CMAK is already installed
  65. // if so, save where it is located
  66. HKEY hKey;
  67. ZeroMemory(g_szCmakPath, sizeof(g_szCmakPath));
  68. hr = HrRegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szCmakRegPath, KEY_READ, &hKey);
  69. if (SUCCEEDED(hr))
  70. {
  71. DWORD dwSize = sizeof(g_szCmakPath);
  72. if (ERROR_SUCCESS != RegQueryValueExW(hKey, c_szPathValue, NULL, NULL,
  73. (LPBYTE)g_szCmakPath, &dwSize))
  74. {
  75. hr = HRESULT_FROM_WIN32(GetLastError());
  76. }
  77. RegCloseKey(hKey);
  78. }
  79. else if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)
  80. {
  81. // This is a fresh install of CMAK, don't return an error
  82. //
  83. hr = SHGetSpecialFolderPath(NULL, g_szCmakPath, CSIDL_PROGRAM_FILES, FALSE);
  84. if (SUCCEEDED(hr))
  85. {
  86. lstrcatW(g_szCmakPath, L"\\Cmak");
  87. }
  88. }
  89. if (SUCCEEDED(hr))
  90. {
  91. // Next Create the CMAK Dir ID
  92. //
  93. hr = HrEnsureInfFileIsOpen(pnocd->pszComponentId, *pnocd);
  94. if (SUCCEEDED(hr))
  95. {
  96. if(!SetupSetDirectoryId(pnocd->hinfFile, c_dwCmakDirID, g_szCmakPath))
  97. {
  98. hr = HRESULT_FROM_WIN32(GetLastError());
  99. }
  100. }
  101. }
  102. }
  103. TraceError("HrOcCmakPreQueueFiles", hr);
  104. return hr;
  105. }
  106. //+---------------------------------------------------------------------------
  107. //
  108. // Function: HrOcCmakPostInstall
  109. //
  110. // Purpose: Called by optional components installer code to handle
  111. // additional installation requirements for Connection Manager Administration Kit.
  112. //
  113. // Arguments:
  114. // pnocd [in] Pointer to NETOC data.
  115. //
  116. // Returns: S_OK if successfull, Win32 error otherwise.
  117. //
  118. // Author: a-anasj 9 Mar 1998
  119. //
  120. // Notes:
  121. //
  122. HRESULT HrOcCmakPostInstall(PNETOCDATA pnocd)
  123. {
  124. HRESULT hr = S_OK;
  125. WCHAR szTempDest[MAX_PATH+1];
  126. if ((IT_INSTALL == pnocd->eit) || (IT_UPGRADE == pnocd->eit))
  127. {
  128. //
  129. // Then we need to migrate profiles and potentially delete old directories
  130. //
  131. if (L'\0' != g_szCmakPath[0])
  132. {
  133. wsprintfW(szTempDest, c_szProfilesFmt, g_szCmakPath);
  134. //
  135. // Rename Profiles-32 to Profiles
  136. //
  137. BOOL bFail = !RenameProfiles32(g_szCmakPath, szTempDest);
  138. hr = bFail ? E_UNEXPECTED: S_OK;
  139. //
  140. // Migrate 1.0 Profiles
  141. //
  142. bFail = !migrateProfiles(g_szCmakPath, szTempDest);
  143. hr = bFail ? E_UNEXPECTED: S_OK;
  144. //
  145. // Delete the old directories (cm32 and its sub-dirs)
  146. //
  147. DeleteOldCmakSubDirs(g_szCmakPath);
  148. DeleteOldNtopLinks();
  149. DeleteIeakCmakLinks();
  150. }
  151. }
  152. else if (IT_REMOVE == pnocd->eit)
  153. {
  154. //
  155. // We use the g_szCmakPath string to hold where CMAK was installed.
  156. // To Properly delete the CMAK directory, we must delete the following
  157. // directories CMAK\Support\CMHelp, CMAK\Support, CMAK\Profiles, and CMAK.
  158. // We should only delete these directories if they are empty of both files
  159. // and sub-dirs.
  160. //
  161. wsprintfW(szTempDest, c_szCmHelpFmt, g_szCmakPath);
  162. if (!RemoveDirectory(szTempDest))
  163. {
  164. TraceError("HrOcCmakPostInstall -- Removing CMHelp Dir",
  165. HRESULT_FROM_WIN32(GetLastError()));
  166. }
  167. wsprintfW(szTempDest, c_szSupportFmt, g_szCmakPath);
  168. if (!RemoveDirectory(szTempDest))
  169. {
  170. TraceError("HrOcCmakPostInstall -- Removing Support Dir",
  171. HRESULT_FROM_WIN32(GetLastError()));
  172. }
  173. wsprintfW(szTempDest, c_szProfilesFmt, g_szCmakPath);
  174. if (!RemoveDirectory(szTempDest))
  175. {
  176. TraceError("HrOcCmakPostInstall -- Removing Profiles Dir",
  177. HRESULT_FROM_WIN32(GetLastError()));
  178. }
  179. if (!RemoveDirectory(g_szCmakPath))
  180. {
  181. TraceError("HrOcCmakPostInstall -- Removing CMAK Dir",
  182. HRESULT_FROM_WIN32(GetLastError()));
  183. }
  184. }
  185. TraceError("HrOcCmakPostInstall", hr);
  186. return hr;
  187. }
  188. //+---------------------------------------------------------------------------
  189. //
  190. // Function: migrateProfiles
  191. //
  192. // Purpose: This is the function that migrates the profiles. It takes the current
  193. // CMAK dir as its first input and the new CMAK dir as its second input..
  194. //
  195. // Arguments: PCWSTR pszSource - root of source CMAK dir
  196. // PCWSTR pszDestination - root of destination CMAK dir
  197. //
  198. // Returns: BOOL - Returns TRUE if it was able to migrate the profiles.
  199. //
  200. // Author: a-anasj 9 Mar 1998
  201. //
  202. // Notes:
  203. // History: quintinb Created 12/9/97
  204. //
  205. BOOL migrateProfiles(PCWSTR pszSource, PCWSTR pszDestination)
  206. {
  207. WCHAR szSourceProfileSearchString[MAX_PATH+1];
  208. WCHAR szFile[MAX_PATH+1];
  209. HANDLE hFileSearch;
  210. WIN32_FIND_DATA wfdFindData;
  211. BOOL bReturn = TRUE;
  212. SHFILEOPSTRUCT fOpStruct;
  213. //
  214. // Initialize the searchstring and the destination dir
  215. //
  216. wsprintfW(szSourceProfileSearchString, L"%s\\*.*", pszSource);
  217. //
  218. // Create the destination directory
  219. //
  220. CreateDirectory(pszDestination, NULL); //lint !e534 this might fail if it already exists
  221. hFileSearch = FindFirstFile(szSourceProfileSearchString, &wfdFindData);
  222. while (INVALID_HANDLE_VALUE != hFileSearch)
  223. {
  224. if((wfdFindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
  225. (0 != _wcsicmp(wfdFindData.cFileName, L"cm32")) && // 1.1/1.2 Legacy
  226. (0 != _wcsicmp(wfdFindData.cFileName, L"cm16")) && // 1.1/1.2 Legacy
  227. (0 != _wcsicmp(wfdFindData.cFileName, L"Docs")) &&
  228. (0 != _wcsicmp(wfdFindData.cFileName, L"Profiles-32")) && // 1.1/1.2 Legacy
  229. (0 != _wcsicmp(wfdFindData.cFileName, L"Profiles-16")) && // 1.1/1.2 Legacy
  230. (0 != _wcsicmp(wfdFindData.cFileName, L"Support")) &&
  231. (0 != _wcsicmp(wfdFindData.cFileName, L"Profiles")) &&
  232. (0 != _wcsicmp(wfdFindData.cFileName, L".")) &&
  233. (0 != _wcsicmp(wfdFindData.cFileName, L"..")))
  234. {
  235. //
  236. // Then I have a profile directory
  237. //
  238. ZeroMemory(&fOpStruct, sizeof(fOpStruct));
  239. ZeroMemory(szFile, sizeof(szFile));
  240. wsprintfW(szFile, L"%s\\%s", pszSource, wfdFindData.cFileName);
  241. fOpStruct.hwnd = NULL;
  242. fOpStruct.wFunc = FO_MOVE;
  243. fOpStruct.pTo = pszDestination;
  244. fOpStruct.pFrom = szFile;
  245. fOpStruct.fFlags = FOF_SILENT | FOF_NOCONFIRMATION | FOF_NOCONFIRMMKDIR;
  246. bReturn &= (0== SHFileOperation(&fOpStruct)); //lint !e514, intended use of boolean, quintinb
  247. }
  248. //
  249. // Check to see if we have any more Files
  250. //
  251. if (!FindNextFile(hFileSearch, &wfdFindData))
  252. {
  253. if (ERROR_NO_MORE_FILES != GetLastError())
  254. {
  255. //
  256. // We had some unexpected error, report unsuccessful completion
  257. //
  258. bReturn = FALSE;
  259. }
  260. //
  261. // Exit the loop
  262. //
  263. break;
  264. }
  265. }
  266. if (INVALID_HANDLE_VALUE != hFileSearch)
  267. {
  268. FindClose(hFileSearch);
  269. }
  270. return bReturn;
  271. }
  272. //+---------------------------------------------------------------------------
  273. //
  274. // Function: RenameProfiles32
  275. //
  276. // Purpose: Takes the inputted CMAK path, appends Profiles-32 to it, and then
  277. // renames the resulting dir to the path inputted as pszProfilesDir.
  278. // Note this dir must exist for it to be renamed.
  279. //
  280. // Arguments: PCWSTR pszCMAKpath - current cmak path
  281. // PCWSTR pszProfilesDir - new profiles directory path
  282. //
  283. // Returns: BOOL - Returns TRUE if succeeded
  284. //
  285. // Author: quintinb 13 Aug 1998
  286. //
  287. // Notes:
  288. BOOL RenameProfiles32(PCWSTR pszCMAKpath, PCWSTR pszProfilesDir)
  289. {
  290. SHFILEOPSTRUCT fOpStruct;
  291. WCHAR szTemp[MAX_PATH+1];
  292. ZeroMemory(&fOpStruct, sizeof(fOpStruct));
  293. ZeroMemory(szTemp, sizeof(szTemp));
  294. wsprintfW(szTemp, c_szProfiles32Fmt, pszCMAKpath);
  295. if (SetFileAttributes(szTemp, FILE_ATTRIBUTE_NORMAL))
  296. {
  297. fOpStruct.hwnd = NULL;
  298. fOpStruct.wFunc = FO_MOVE;
  299. fOpStruct.pTo = pszProfilesDir;
  300. fOpStruct.pFrom = szTemp;
  301. fOpStruct.fFlags = FOF_SILENT | FOF_NOCONFIRMATION | FOF_NOCONFIRMMKDIR;
  302. return (0== SHFileOperation(&fOpStruct)); //lint !e514, intended use of boolean, quintinb
  303. }
  304. else
  305. {
  306. return TRUE;
  307. }
  308. }
  309. //+---------------------------------------------------------------------------
  310. //
  311. // Function: DeleteOldCmakSubDirs
  312. //
  313. // Purpose: Deletes the old Cmak sub directories. Uses FindFirstFile becuase
  314. // we don't want to delete any customized doc files that the user may
  315. // have customized. Thus anything in the CMHelp directory except the
  316. // original help files is deleted.
  317. //
  318. // Arguments: PCWSTR pszCMAKpath - current cmak path
  319. //
  320. // Returns: Nothing
  321. //
  322. // Author: quintinb 6 Nov 1998
  323. //
  324. // Notes:
  325. void DeleteOldCmakSubDirs(PCWSTR pszCmakPath)
  326. {
  327. WCHAR szCm32path[MAX_PATH+1];
  328. WCHAR szCm32SearchString[MAX_PATH+1];
  329. WCHAR szTemp[MAX_PATH+1];
  330. HANDLE hCm32FileSearch;
  331. WIN32_FIND_DATA wfdCm32;
  332. //
  333. // Delete the old IEAK Docs Dir
  334. //
  335. wsprintfW(szTemp, L"%s\\%s", pszCmakPath, SzLoadIds(IDS_OC_OLD_IEAK_DOCDIR));
  336. RemoveDirectory(szTemp);
  337. wsprintfW(szCm32path, c_szCm32Fmt, pszCmakPath);
  338. //
  339. // First look in the Cm32 directory itself. Delete all files found, continue down
  340. // into subdirs.
  341. //
  342. wsprintfW(szCm32SearchString, L"%s\\*.*", szCm32path);
  343. hCm32FileSearch = FindFirstFile(szCm32SearchString, &wfdCm32);
  344. while (INVALID_HANDLE_VALUE != hCm32FileSearch)
  345. {
  346. if (wfdCm32.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  347. {
  348. if ((0 != lstrcmpiW(wfdCm32.cFileName, L".")) &&
  349. (0 != lstrcmpiW(wfdCm32.cFileName, L"..")))
  350. {
  351. //
  352. // Then we want to delete all the files in this lang sub dir and we
  353. // we want to delete the four help files from the CM help dir. If all the
  354. // files are deleted from a dir then we should remove the directory.
  355. //
  356. WCHAR szLangDirSearchString[MAX_PATH+1];
  357. HANDLE hLangDirFileSearch;
  358. WIN32_FIND_DATA wfdLangDir;
  359. wsprintfW(szLangDirSearchString, L"%s\\%s\\*.*", szCm32path,
  360. wfdCm32.cFileName);
  361. hLangDirFileSearch = FindFirstFile(szLangDirSearchString, &wfdLangDir);
  362. while (INVALID_HANDLE_VALUE != hLangDirFileSearch)
  363. {
  364. if (wfdLangDir.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  365. {
  366. if ((0 != lstrcmpiW(wfdLangDir.cFileName, L".")) &&
  367. (0 != lstrcmpiW(wfdLangDir.cFileName, L"..")))
  368. {
  369. //
  370. // We only want to delete help files from our help source dirs
  371. //
  372. if (0 == _wcsnicmp(wfdLangDir.cFileName, L"CM", 2))
  373. {
  374. //
  375. // Delete the four help files only.
  376. //
  377. wsprintfW(szTemp, L"%s\\%s\\%s\\cmctx32.rtf", szCm32path,
  378. wfdCm32.cFileName, wfdLangDir.cFileName);
  379. DeleteFile(szTemp);
  380. wsprintfW(szTemp, L"%s\\%s\\%s\\cmmgr32.h", szCm32path,
  381. wfdCm32.cFileName, wfdLangDir.cFileName);
  382. DeleteFile(szTemp);
  383. wsprintfW(szTemp, L"%s\\%s\\%s\\cmmgr32.hpj", szCm32path,
  384. wfdCm32.cFileName, wfdLangDir.cFileName);
  385. DeleteFile(szTemp);
  386. wsprintfW(szTemp, L"%s\\%s\\%s\\cmtrb32.rtf", szCm32path,
  387. wfdCm32.cFileName, wfdLangDir.cFileName);
  388. DeleteFile(szTemp);
  389. //
  390. // Now try to remove the directory
  391. //
  392. wsprintfW(szTemp, L"%s\\%s\\%s", szCm32path,
  393. wfdCm32.cFileName, wfdLangDir.cFileName);
  394. RemoveDirectory(szTemp);
  395. }
  396. }
  397. }
  398. else
  399. {
  400. wsprintfW(szTemp, L"%s\\%s\\%s", szCm32path, wfdCm32.cFileName,
  401. wfdLangDir.cFileName);
  402. DeleteFile(szTemp);
  403. }
  404. //
  405. // Check to see if we have any more Files
  406. //
  407. if (!FindNextFile(hLangDirFileSearch, &wfdLangDir))
  408. {
  409. //
  410. // Exit the loop
  411. //
  412. break;
  413. }
  414. }
  415. if (INVALID_HANDLE_VALUE != hLangDirFileSearch)
  416. {
  417. FindClose(hLangDirFileSearch);
  418. //
  419. // Now try to remove the lang dir directory
  420. //
  421. wsprintfW(szTemp, L"%s\\%s", szCm32path, wfdCm32.cFileName);
  422. RemoveDirectory(szTemp);
  423. }
  424. }
  425. }
  426. else
  427. {
  428. wsprintfW(szTemp, L"%s\\%s", szCm32path, wfdCm32.cFileName);
  429. DeleteFile(szTemp);
  430. }
  431. //
  432. // Check to see if we have any more Files
  433. //
  434. if (!FindNextFile(hCm32FileSearch, &wfdCm32))
  435. {
  436. if (INVALID_HANDLE_VALUE != hCm32FileSearch)
  437. {
  438. FindClose(hCm32FileSearch);
  439. }
  440. //
  441. // Now try to remove the cm32 directory
  442. //
  443. RemoveDirectory(szCm32path);
  444. //
  445. // Exit the loop
  446. //
  447. break;
  448. }
  449. }
  450. }
  451. //+---------------------------------------------------------------------------
  452. //
  453. // Function: DeleteProgramGroupWithLinks
  454. //
  455. // Purpose: Utility function to delete a given program group and its links.
  456. // Thus if you pass in the full path to a program group to delete,
  457. // the function does a findfirstfile to find and delete any links.
  458. // The function ignores sub-dirs.
  459. //
  460. //
  461. // Arguments: PCWSTR pszGroupPath - Full path to the program group to delete.
  462. //
  463. // Returns: Nothing
  464. //
  465. // Author: quintinb 6 Nov 1998
  466. //
  467. // Notes:
  468. void DeleteProgramGroupWithLinks(PCWSTR pszGroupPath)
  469. {
  470. HANDLE hLinkSearch;
  471. WIN32_FIND_DATA wfdLinks;
  472. WCHAR szLinkSearchString[MAX_PATH+1];
  473. WCHAR szTemp[MAX_PATH+1];
  474. wsprintfW(szLinkSearchString, L"%s\\*.*", pszGroupPath);
  475. hLinkSearch = FindFirstFile(szLinkSearchString, &wfdLinks);
  476. while (INVALID_HANDLE_VALUE != hLinkSearch)
  477. {
  478. if (!(wfdLinks.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
  479. {
  480. wsprintfW(szTemp, L"%s\\%s", pszGroupPath, wfdLinks.cFileName);
  481. DeleteFile(szTemp);
  482. }
  483. //
  484. // Check to see if we have any more Files
  485. //
  486. if (!FindNextFile(hLinkSearch, &wfdLinks))
  487. {
  488. FindClose(hLinkSearch);
  489. //
  490. // Now try to remove the directory
  491. //
  492. RemoveDirectory(pszGroupPath);
  493. //
  494. // Exit the loop
  495. //
  496. break;
  497. }
  498. }
  499. }
  500. //+---------------------------------------------------------------------------
  501. //
  502. // Function: DeleteOldNtopLinks
  503. //
  504. // Purpose: Deletes the old links from the NT 4.0 Option Pack
  505. //
  506. //
  507. // Arguments: None
  508. //
  509. // Returns: Nothing
  510. //
  511. // Author: quintinb 6 Nov 1998
  512. //
  513. // Notes:
  514. void DeleteOldNtopLinks()
  515. {
  516. HRESULT hr;
  517. //
  518. // First Delete the old NTOP4 Path
  519. //
  520. WCHAR szGroup[MAX_PATH+1];
  521. WCHAR szTemp[MAX_PATH+1];
  522. //
  523. // Get the CSIDL_COMMON_PROGRAMS value
  524. //
  525. hr = SHGetSpecialFolderPath(NULL, szTemp, CSIDL_COMMON_PROGRAMS, FALSE);
  526. if (SUCCEEDED(hr))
  527. {
  528. wsprintfW(szGroup, L"%s\\%s\\%s", szTemp,
  529. (PWSTR)SzLoadIds(IDS_OC_NTOP4_GROUPNAME),
  530. (PWSTR)SzLoadIds(IDS_OC_ICS_GROUPNAME));
  531. DeleteProgramGroupWithLinks(szGroup);
  532. }
  533. }
  534. //+---------------------------------------------------------------------------
  535. //
  536. // Function: DeleteIeakCmakLinks
  537. //
  538. // Purpose: Deletes the old links from the IEAK4 CMAK
  539. //
  540. //
  541. // Arguments: None
  542. //
  543. // Returns: Nothing
  544. //
  545. // Author: quintinb 6 Nov 1998
  546. //
  547. // Notes:
  548. void DeleteIeakCmakLinks()
  549. {
  550. WCHAR szUserDirRoot[MAX_PATH+1];
  551. WCHAR szGroup[MAX_PATH+1];
  552. WCHAR szTemp[MAX_PATH+1];
  553. WCHAR szEnd[MAX_PATH+1];
  554. //
  555. // Next Delete the old IEAK CMAK links
  556. //
  557. //
  558. // Get the Desktop directory and then remove the desktop part. This will give us the
  559. // root of the user directories.
  560. //
  561. HRESULT hr = SHGetSpecialFolderPath(NULL, szUserDirRoot, CSIDL_DESKTOPDIRECTORY, FALSE);
  562. if (SUCCEEDED(hr))
  563. {
  564. //
  565. // Remove \\Desktop
  566. //
  567. WCHAR* pszTemp = wcsrchr(szUserDirRoot, L'\\');
  568. if (NULL == pszTemp)
  569. {
  570. return;
  571. }
  572. else
  573. {
  574. *pszTemp = L'\0';
  575. }
  576. HRESULT hr = SHGetSpecialFolderPath(NULL, szTemp, CSIDL_PROGRAMS, FALSE);
  577. if (SUCCEEDED(hr))
  578. {
  579. if (0 == _wcsnicmp(szUserDirRoot, szTemp, wcslen(szUserDirRoot)))
  580. {
  581. lstrcpyW(szEnd, &(szTemp[wcslen(szUserDirRoot)]));
  582. }
  583. }
  584. //
  585. // Remove \\<User Name>>
  586. //
  587. pszTemp = wcsrchr(szUserDirRoot, L'\\');
  588. if (NULL == pszTemp)
  589. {
  590. return;
  591. }
  592. else
  593. {
  594. *pszTemp = L'\0';
  595. }
  596. //
  597. // Now start searching for user dirs to delete the CMAK group from
  598. //
  599. WCHAR szUserDirSearchString[MAX_PATH+1];
  600. HANDLE hUserDirSearch;
  601. WIN32_FIND_DATA wfdUserDirs;
  602. wsprintfW(szUserDirSearchString, L"%s\\*.*", szUserDirRoot);
  603. hUserDirSearch = FindFirstFile(szUserDirSearchString, &wfdUserDirs);
  604. while (INVALID_HANDLE_VALUE != hUserDirSearch)
  605. {
  606. if ((wfdUserDirs.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
  607. (0 != _wcsicmp(wfdUserDirs.cFileName, L".")) &&
  608. (0 != _wcsicmp(wfdUserDirs.cFileName, L"..")))
  609. {
  610. wsprintfW(szGroup, L"%s\\%s%s\\%s", szUserDirRoot, wfdUserDirs.cFileName,
  611. szEnd, c_szCmakGroup);
  612. DeleteProgramGroupWithLinks(szGroup);
  613. }
  614. if (!FindNextFile(hUserDirSearch, &wfdUserDirs))
  615. {
  616. FindClose(hUserDirSearch);
  617. //
  618. // Exit the loop
  619. //
  620. break;
  621. }
  622. }
  623. }
  624. }