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.

868 lines
25 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1997-1999.
  5. //
  6. // File: N C M I S C . C P P
  7. //
  8. // Contents: Miscellaneous common code.
  9. //
  10. // Notes: Pollute this under penalty of death.
  11. //
  12. // Author: shaunco 10 Oct 1997
  13. //
  14. //----------------------------------------------------------------------------
  15. #include <pch.h>
  16. #pragma hdrstop
  17. #include "ncdebug.h"
  18. #include "ncmisc.h"
  19. #include "ncreg.h"
  20. #include "ncsvc.h"
  21. #include "nceh.h"
  22. #include <eh.h>
  23. //+---------------------------------------------------------------------------
  24. //
  25. // Function: FInSystemSetup
  26. //
  27. // Purpose: Determines whether the machine is in GUI mode setup or not.
  28. //
  29. // Arguments:
  30. // (none)
  31. //
  32. // Returns: TRUE if in GUI mode (system) setup, FALSE if not.
  33. //
  34. // Author: danielwe 13 Jun 1997
  35. //
  36. // Notes: The state is cached (since it can't change without a reboot)
  37. // so call as often as you like. No need to keep you're own
  38. // cached copy.
  39. //
  40. BOOL
  41. FInSystemSetup ()
  42. {
  43. enum SETUP_STATE
  44. {
  45. SS_UNKNOWN = 0, // state unknown
  46. SS_NOTINSETUP, // not in setup mode
  47. SS_SYSTEMSETUP // in GUI mode setup
  48. };
  49. static SETUP_STATE s_CachedSetupState = SS_UNKNOWN;
  50. if (SS_UNKNOWN == s_CachedSetupState)
  51. {
  52. s_CachedSetupState = SS_NOTINSETUP;
  53. // Open the setup key
  54. //
  55. HRESULT hr;
  56. HKEY hkeySetup;
  57. hr = HrRegOpenKeyEx(HKEY_LOCAL_MACHINE, L"System\\Setup",
  58. KEY_READ, &hkeySetup);
  59. if (S_OK == hr)
  60. {
  61. // get the value of the setup in progress
  62. //
  63. DWORD dwSysSetup;
  64. hr = HrRegQueryDword(hkeySetup, L"SystemSetupInProgress",
  65. &dwSysSetup);
  66. if ((S_OK == hr) && dwSysSetup)
  67. {
  68. s_CachedSetupState = SS_SYSTEMSETUP;
  69. }
  70. RegCloseKey(hkeySetup);
  71. }
  72. }
  73. Assert (SS_UNKNOWN != s_CachedSetupState);
  74. return (SS_SYSTEMSETUP == s_CachedSetupState);
  75. }
  76. //+---------------------------------------------------------------------------
  77. //
  78. // Function: GetProductFlavor
  79. //
  80. // Purpose: Returns the flavor of NT currenty running on the machine.
  81. //
  82. // Arguments:
  83. // pvReserved [in] Reserved. Must be NULL.
  84. // ppf [out] Returned flavor.
  85. //
  86. // Returns: nothing
  87. //
  88. // Author: shaunco 24 Mar 1997
  89. //
  90. // Notes:
  91. //
  92. NOTHROW
  93. VOID
  94. GetProductFlavor (
  95. const void* pvReserved,
  96. PRODUCT_FLAVOR* ppf)
  97. {
  98. NT_PRODUCT_TYPE Type;
  99. Assert(!pvReserved);
  100. Assert(ppf);
  101. // Assume workstation product
  102. //
  103. *ppf = PF_WORKSTATION;
  104. // Even if RtlGetProductType fails, its documented to return
  105. // NtProductWinNt.
  106. //
  107. RtlGetNtProductType (&Type);
  108. if (NtProductWinNt != Type)
  109. {
  110. *ppf = PF_SERVER;
  111. }
  112. }
  113. //+---------------------------------------------------------------------------
  114. //
  115. // Function: HrIsNetworkingInstalled
  116. //
  117. // Purpose: Returns whether networking is installed.
  118. //
  119. // Arguments:
  120. // (none)
  121. //
  122. // Returns: S_OK if networking is installed, S_FALSE if not, Win32 error
  123. // otherwise.
  124. //
  125. // Author: danielwe 25 Jun 1997
  126. //
  127. // Notes: To determine if networking is installed, the ProviderOrder
  128. // value of System\CurrentControlSet\Control\NetworkProvider\Order
  129. // registry key is queried. If any data is present, networking
  130. // is installed.
  131. //
  132. HRESULT
  133. HrIsNetworkingInstalled ()
  134. {
  135. HRESULT hr = S_OK;
  136. HKEY hkeyProvider;
  137. DWORD cbSize = 0;
  138. DWORD dwType;
  139. extern const WCHAR c_szRegKeyCtlNPOrder[];
  140. extern const WCHAR c_szProviderOrder[];
  141. // open the provider key
  142. hr = HrRegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szRegKeyCtlNPOrder,
  143. KEY_READ, &hkeyProvider);
  144. if (S_OK == hr)
  145. {
  146. // get the count in bytes of the provider order value
  147. hr = HrRegQueryValueEx(hkeyProvider, c_szProviderOrder,
  148. &dwType, (LPBYTE)NULL, &cbSize);
  149. if (S_OK == hr)
  150. {
  151. if (cbSize > 2)
  152. {
  153. // if the value was present and it contained information
  154. // then we have networking of some sorts
  155. //
  156. hr = S_OK;
  157. }
  158. else
  159. {
  160. hr = S_FALSE;
  161. }
  162. }
  163. else if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
  164. {
  165. hr = S_FALSE;
  166. }
  167. RegCloseKey(hkeyProvider);
  168. }
  169. TraceError("HrIsNetworkingInstalled", (hr == S_FALSE) ? S_OK : hr);
  170. return hr;
  171. }
  172. #ifdef REMOTEBOOT
  173. //+---------------------------------------------------------------------------
  174. //
  175. // Function: HrIsRemoteBootMachine
  176. //
  177. // Purpose: Returns whether this is a remote boot client.
  178. //
  179. // Arguments:
  180. // (none)
  181. //
  182. // Returns: S_OK if it is remote boot, S_FALSE if not.
  183. //
  184. // Author: adamba 27 Mar 1998
  185. //
  186. // Notes: Calls GetSystemInfoEx to determine whether this is a
  187. // remote boot client.
  188. //
  189. HRESULT HrIsRemoteBootMachine()
  190. {
  191. BOOL fIsRemoteBoot;
  192. BOOL ok;
  193. DWORD size = sizeof(fIsRemoteBoot);
  194. ok = GetSystemInfoEx(SystemInfoRemoteBoot, &fIsRemoteBoot, &size);
  195. Assert(ok);
  196. if (fIsRemoteBoot) {
  197. return S_OK;
  198. } else {
  199. return S_FALSE;
  200. }
  201. }
  202. #endif // defined(REMOTEBOOT)
  203. //+---------------------------------------------------------------------------
  204. //
  205. // Function: HrRegisterOrUnregisterComObject
  206. //
  207. // Purpose: Handles registration or unregistration of one or more COM
  208. // objects contained in a DLL that supports the
  209. // DllRegisterServer or DllUnregisterServer entry points.
  210. //
  211. // Arguments:
  212. // pszDllPath [in] Path to DLL that contains COM object(s) to (un)register.
  213. // rf [in] Function to perform
  214. //
  215. // Returns: S_OK if successful, Win32 or OLE HRESULT if failure.
  216. //
  217. // Author: danielwe 6 May 1997
  218. //
  219. // Notes:
  220. //
  221. HRESULT
  222. HrRegisterOrUnregisterComObject (
  223. PCWSTR pszDllPath,
  224. REGISTER_FUNCTION rf)
  225. {
  226. BOOL fCoUninitialize = TRUE;
  227. HRESULT hr = CoInitializeEx( NULL,
  228. COINIT_DISABLE_OLE1DDE | COINIT_MULTITHREADED );
  229. if (RPC_E_CHANGED_MODE == hr)
  230. {
  231. hr = S_OK;
  232. fCoUninitialize = FALSE;
  233. }
  234. if (SUCCEEDED(hr))
  235. {
  236. // ANSI only
  237. const CHAR c_szaRegisterFunction[] = "DllRegisterServer";
  238. const CHAR c_szaUnregisterFunction[] = "DllUnregisterServer";
  239. typedef HRESULT (CALLBACK *HCRET)(void);
  240. HCRET pfnRegister;
  241. HMODULE hModule;
  242. // Get a pointer the the registration function in the Dll
  243. hr = HrLoadLibAndGetProc (pszDllPath,
  244. ((RF_REGISTER == rf) ?
  245. c_szaRegisterFunction : c_szaUnregisterFunction),
  246. &hModule,
  247. reinterpret_cast<FARPROC*>(&pfnRegister));
  248. if (S_OK == hr)
  249. {
  250. // Call the registration function
  251. hr = (*pfnRegister)();
  252. // RAID #160109 (danielwe) 21 Apr 1998: Handle this error and
  253. // ignore it.
  254. if (RPC_E_CHANGED_MODE == hr)
  255. {
  256. hr = S_OK;
  257. }
  258. TraceError ("HrRegisterOrUnregisterComObject - "
  259. "Dll(Un)RegisterServer failed!", hr);
  260. FreeLibrary (hModule);
  261. }
  262. // Balances call to CoInitialize() above. Not harmful if CoInitialize()
  263. // was called more than once before this.
  264. if (fCoUninitialize)
  265. {
  266. CoUninitialize();
  267. }
  268. }
  269. TraceError ("HrRegisterOrUnregisterComObject", hr);
  270. return hr;
  271. }
  272. //
  273. // Special case handling for Netbios stopping
  274. //
  275. #include <nb30p.h> // Netbios IOCTLs and netbios name #define
  276. //+---------------------------------------------------------------------------
  277. //
  278. // Func: ScStopNetbios
  279. //
  280. // Desc: This function checks if the driver being unloaded is NETBIOS.SYS.
  281. // If so it performs some special case processing for Netbios.
  282. //
  283. // Args: none
  284. //
  285. // Return: STATUS_SUCCESS if successful, or an error status
  286. //
  287. // History: 28-Apr-98 SumitC got from VRaman
  288. //
  289. //----------------------------------------------------------------------------
  290. DWORD
  291. ScStopNetbios()
  292. {
  293. OBJECT_ATTRIBUTES ObjAttr;
  294. UNICODE_STRING NbDeviceName;
  295. IO_STATUS_BLOCK IoStatus, StopStatus;
  296. NTSTATUS ntStatus = STATUS_SUCCESS;
  297. HANDLE NbHandle = NULL;
  298. do
  299. {
  300. //
  301. // Driver being stopped is netbios
  302. //
  303. //
  304. // 1. Open a handle to the \\Device\Netbios
  305. //
  306. RtlInitUnicodeString(&NbDeviceName, NB_DEVICE_NAME);
  307. InitializeObjectAttributes(
  308. &ObjAttr, // obj attr to initialize
  309. &NbDeviceName, // string to use
  310. OBJ_CASE_INSENSITIVE, // Attributes
  311. NULL, // Root directory
  312. NULL); // Security Descriptor
  313. ntStatus = NtCreateFile(
  314. &NbHandle, // ptr to handle
  315. GENERIC_READ|GENERIC_WRITE, // desired access
  316. &ObjAttr, // name & attributes
  317. &IoStatus, // I/O status block.
  318. NULL, // alloc size.
  319. FILE_ATTRIBUTE_NORMAL,
  320. FILE_SHARE_DELETE // share...
  321. | FILE_SHARE_READ
  322. | FILE_SHARE_WRITE, // ...access
  323. FILE_OPEN_IF, // create disposition
  324. 0, // ...options
  325. NULL, // EA buffer
  326. 0L // Ea buffer len
  327. );
  328. if (!NT_SUCCESS(ntStatus))
  329. {
  330. TraceTag(ttidError, "Failed to open file handle to Netbios device (%08lx)",
  331. ntStatus);
  332. break;
  333. }
  334. //
  335. // 2. Send a stop IOCTL to it.
  336. //
  337. ntStatus = NtDeviceIoControlFile(
  338. NbHandle, // Handle to device
  339. NULL, // Event to be signalled
  340. NULL, // No post routine
  341. NULL, // no context for post
  342. &StopStatus, // return status block
  343. IOCTL_NB_STOP, // IOCTL
  344. NULL, // No input parameters
  345. 0,
  346. NULL, // No output paramters
  347. 0
  348. );
  349. if (!NT_SUCCESS(ntStatus))
  350. {
  351. TraceTag(ttidSvcCtl, "Failed to send STOP IOCTL to netbios (%08lx).",
  352. "probably means Netbios isn't running... anyway, we can't stop it",
  353. ntStatus);
  354. break;
  355. }
  356. } while (FALSE);
  357. //
  358. // 4. Close the handle just opened to the driver
  359. //
  360. if (NULL != NbHandle)
  361. {
  362. NtClose( NbHandle );
  363. }
  364. TraceError("ScStopNetbios", HRESULT_FROM_WIN32(ntStatus));
  365. return ntStatus;
  366. }
  367. // ----------------------------------------------------------------------
  368. //
  369. // Function: HrEnableAndStartSpooler
  370. //
  371. // Purpose: Start spooler, enable if necessary
  372. //
  373. // Arguments: None
  374. //
  375. // Returns: S_OK on success, otherwise an error code
  376. //
  377. // Author: kumarp 19-May-98
  378. //
  379. // Notes:
  380. //
  381. HRESULT HrEnableAndStartSpooler ()
  382. {
  383. static const WCHAR c_szSpooler[] = L"Spooler";
  384. TraceTag(ttidNetcfgBase, "entering ---> HrEnableAndStartSpooler" );
  385. // Try to start the spooler. Need to explicitly open the service
  386. // control manager with all access first, so that in case we need to
  387. // change the start type, we have the proper permission.
  388. //
  389. CServiceManager scm;
  390. HRESULT hr = scm.HrOpen (NO_LOCK, SC_MANAGER_ALL_ACCESS);
  391. if (S_OK == hr)
  392. {
  393. hr = scm.HrStartServiceAndWait (c_szSpooler);
  394. if (HRESULT_FROM_WIN32(ERROR_SERVICE_DISABLED) == hr)
  395. {
  396. TraceTag(ttidNetcfgBase, "HrEnableAndStartSpooler: spooler is "
  397. "disabled trying to enable it..." );
  398. // Have to lock the service controller before changing the
  399. // configuration of a service. Do so and unlock before trying to
  400. // start the service.
  401. //
  402. hr = scm.HrLock ();
  403. if (S_OK == hr)
  404. {
  405. CService svc;
  406. hr = scm.HrOpenService (&svc, c_szSpooler,
  407. NO_LOCK,
  408. SC_MANAGER_ALL_ACCESS,
  409. STANDARD_RIGHTS_REQUIRED
  410. | SERVICE_CHANGE_CONFIG);
  411. if (S_OK == hr)
  412. {
  413. hr = svc.HrSetStartType (SERVICE_DEMAND_START);
  414. }
  415. scm.Unlock ();
  416. }
  417. if (S_OK == hr)
  418. {
  419. TraceTag(ttidNetcfgBase, "HrEnableAndStartSpooler: succeeded "
  420. "in enabling spooer. Now starting..." );
  421. hr = scm.HrStartServiceAndWait(c_szSpooler);
  422. }
  423. }
  424. }
  425. TraceError("HrEnableAndStartSpooler", hr);
  426. return hr;
  427. }
  428. //+---------------------------------------------------------------------------
  429. //
  430. // Function: HrCreateDirectoryTree
  431. //
  432. // Purpose: Creates (or ensures existence of) all directories on the path
  433. // specified in szPath.
  434. //
  435. // Arguments:
  436. // pszPath [in] Full path of one or more directories to create
  437. // (i.e. c:\this\is\a\directory\path)
  438. // psa [in] Security attributes
  439. //
  440. // Returns: S_OK if success, Win32 error code otherwise
  441. //
  442. // Author: shaunco (copied from RASUI by danielwe) 26 Jun 1998
  443. //
  444. // Notes:
  445. //
  446. HRESULT HrCreateDirectoryTree(PWSTR pszPath, LPSECURITY_ATTRIBUTES psa)
  447. {
  448. HRESULT hr = S_OK;
  449. if (pszPath)
  450. {
  451. DWORD dwErr = ERROR_SUCCESS;
  452. // Loop through the path.
  453. //
  454. PWSTR pch;
  455. for (pch = pszPath; *pch; pch++)
  456. {
  457. // Stop at each backslash and make sure the path
  458. // is created to that point. Do this by changing the
  459. // backslash to a null-terminator, calling CreateDirecotry,
  460. // and changing it back.
  461. //
  462. if (L'\\' == *pch)
  463. {
  464. BOOL fOk;
  465. *pch = 0;
  466. fOk = CreateDirectory(pszPath, psa);
  467. *pch = L'\\';
  468. // Any errors other than path alredy exists and we should
  469. // bail out. We also get access denied when trying to
  470. // create a root drive (i.e. c:) so check for this too.
  471. //
  472. if (!fOk)
  473. {
  474. dwErr = GetLastError();
  475. if (ERROR_ALREADY_EXISTS == dwErr)
  476. {
  477. dwErr = ERROR_SUCCESS;
  478. }
  479. else if ((ERROR_ACCESS_DENIED == dwErr) &&
  480. (pch - 1 > pszPath) && (L':' == *(pch - 1)))
  481. {
  482. dwErr = ERROR_SUCCESS;
  483. }
  484. else
  485. {
  486. break;
  487. }
  488. }
  489. }
  490. }
  491. if (ERROR_ALREADY_EXISTS == dwErr)
  492. {
  493. dwErr = ERROR_SUCCESS;
  494. }
  495. if (dwErr != ERROR_SUCCESS)
  496. {
  497. hr = HRESULT_FROM_WIN32(dwErr);
  498. }
  499. }
  500. TraceError("HrCreateDirectoryTree", hr);
  501. return hr;
  502. }
  503. //+---------------------------------------------------------------------------
  504. //
  505. // Function: HrDeleteFileSpecification
  506. //
  507. // Purpose: Delete the files specified with pszFileSpec from the
  508. // directory given by pszDirectoryPath.
  509. //
  510. // Arguments:
  511. // pszFileSpec [in] File specificaion to delete. e.g. *.mdb
  512. // pszDirectoryPath [in] Directory path to delete from
  513. //
  514. // Returns: S_OK or an error code.
  515. //
  516. // Author: shaunco 4 Jun 1998
  517. //
  518. // Notes:
  519. //
  520. HRESULT
  521. HrDeleteFileSpecification (
  522. PCWSTR pszFileSpec,
  523. PCWSTR pszDirectoryPath)
  524. {
  525. Assert (pszFileSpec && *pszFileSpec);
  526. Assert (pszDirectoryPath && *pszDirectoryPath);
  527. HRESULT hr = S_OK;
  528. INT cchSpec = lstrlenW (pszFileSpec);
  529. INT cchDir = lstrlenW (pszDirectoryPath);
  530. // Make sure the length of the directory and filespec combined is less
  531. // than MAX_PATH before continuing. The '+1' is for the backslash
  532. // that we may add.
  533. //
  534. if (cchDir + 1 + cchSpec > MAX_PATH)
  535. {
  536. hr = HRESULT_FROM_WIN32 (ERROR_BAD_PATHNAME);
  537. }
  538. else
  539. {
  540. WCHAR szPath[MAX_PATH];
  541. // Form the path by copying the directory and making sure it
  542. // is terminated with a backslash if needed.
  543. //
  544. lstrcpyW (szPath, pszDirectoryPath);
  545. if (cchDir &&
  546. (L':' != pszDirectoryPath[cchDir - 1]) &&
  547. (L'\\' != pszDirectoryPath[cchDir - 1]))
  548. {
  549. lstrcatW (szPath, L"\\");
  550. cchDir++;
  551. }
  552. // Append the filespec to the directory and look for the first
  553. // file.
  554. lstrcatW (szPath, pszFileSpec);
  555. TraceTag (ttidNetcfgBase, "Looking to delete %S (cchDir=%u)",
  556. szPath, cchDir);
  557. WIN32_FIND_DATA FindData;
  558. HANDLE hFind = FindFirstFile (szPath, &FindData);
  559. if (INVALID_HANDLE_VALUE != hFind)
  560. {
  561. PCWSTR pszFileName;
  562. INT cchFileName;
  563. do
  564. {
  565. // Skip files with these attributes.
  566. //
  567. if (FindData.dwFileAttributes & (FILE_ATTRIBUTE_DIRECTORY |
  568. FILE_ATTRIBUTE_HIDDEN |
  569. FILE_ATTRIBUTE_READONLY |
  570. FILE_ATTRIBUTE_SYSTEM))
  571. {
  572. continue;
  573. }
  574. // Use the shortname where possible to give us a chance
  575. // of using a path within MAX_PATH first.
  576. //
  577. pszFileName = FindData.cAlternateFileName;
  578. cchFileName = lstrlenW (pszFileName);
  579. if (!cchFileName)
  580. {
  581. pszFileName = FindData.cFileName;
  582. cchFileName = lstrlenW (pszFileName);
  583. }
  584. // If the length of the directory and filename don't exceed
  585. // MAX_PATH, form the full pathname and delete it.
  586. //
  587. if (cchDir + cchFileName < MAX_PATH)
  588. {
  589. lstrcpyW (&szPath[cchDir], pszFileName);
  590. TraceTag (ttidNetcfgBase, "Deleting %S", szPath);
  591. if (!DeleteFile (szPath))
  592. {
  593. hr = HrFromLastWin32Error ();
  594. TraceError ("DeleteFile failed. Ignoring.", hr);
  595. }
  596. }
  597. }
  598. while (FindNextFile (hFind, &FindData));
  599. // FindNextFile should set last error to ERROR_NO_MORE_FILES
  600. // on a succesful termination.
  601. //
  602. hr = HrFromLastWin32Error ();
  603. if (HRESULT_FROM_WIN32(ERROR_NO_MORE_FILES) == hr)
  604. {
  605. hr = S_OK;
  606. }
  607. FindClose (hFind);
  608. }
  609. else
  610. {
  611. // If FindFirstFile didn't find anything, that's okay.
  612. //
  613. hr = HrFromLastWin32Error ();
  614. if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)
  615. {
  616. hr = S_OK;
  617. }
  618. }
  619. }
  620. TraceError ("HrDeleteFileSpecification", hr);
  621. return hr;
  622. }
  623. // ----------------------------------------------------------------------
  624. //
  625. // Function: HrDeleteDirectory
  626. //
  627. // Purpose: Recursively delete a directory and its all sub-dirs.
  628. //
  629. // Arguments:
  630. // pszDir [in] full path to a dir
  631. // fContinueOnError [in] whether to continue deleting others when we
  632. // error when deleting one
  633. //
  634. // Returns: S_OK on success, otherwise an error code
  635. //
  636. // Author: kumarp 19-December-97
  637. // danielwe 15-December-98 (moved to common and revised)
  638. //
  639. // Notes:
  640. //
  641. HRESULT HrDeleteDirectory(IN PCWSTR pszDir,
  642. IN BOOL fContinueOnError)
  643. {
  644. HRESULT hr = S_OK;
  645. WCHAR szPrefix[MAX_PATH];
  646. WCHAR szFileSpec[MAX_PATH];
  647. WCHAR szAllFiles[MAX_PATH];
  648. HANDLE hFileContext;
  649. WIN32_FIND_DATA fd;
  650. TraceTag(ttidNetcfgBase, "Deleting directory %S", pszDir);
  651. lstrcpyW(szPrefix, pszDir);
  652. lstrcatW(szPrefix, L"\\");
  653. lstrcpyW(szAllFiles, pszDir);
  654. lstrcatW(szAllFiles, L"\\");
  655. lstrcatW(szAllFiles, L"*");
  656. hFileContext = FindFirstFile(szAllFiles, &fd);
  657. if (hFileContext != INVALID_HANDLE_VALUE)
  658. {
  659. do
  660. {
  661. lstrcpyW(szFileSpec, szPrefix);
  662. lstrcatW(szFileSpec, fd.cFileName);
  663. if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  664. {
  665. if (!(!lstrcmpiW(fd.cFileName, L".") ||
  666. !lstrcmpiW(fd.cFileName, L"..")))
  667. {
  668. hr = HrDeleteDirectory(szFileSpec, fContinueOnError);
  669. if (FAILED(hr) && fContinueOnError)
  670. {
  671. hr = S_OK;
  672. }
  673. }
  674. }
  675. else
  676. {
  677. TraceTag(ttidNetcfgBase, "Deleting file %S", szFileSpec);
  678. if (DeleteFile(szFileSpec))
  679. {
  680. hr = S_OK;
  681. }
  682. else
  683. {
  684. TraceTag(ttidNetcfgBase, "Error deleting file %S",
  685. szFileSpec);
  686. TraceError("HrDeleteDirectory", hr);
  687. hr = fContinueOnError ? S_OK : HrFromLastWin32Error();
  688. }
  689. }
  690. if ((S_OK == hr) && FindNextFile(hFileContext, &fd))
  691. {
  692. hr = S_OK;
  693. }
  694. else
  695. {
  696. hr = HrFromLastWin32Error();
  697. }
  698. }
  699. while (S_OK == hr);
  700. if (hr == HRESULT_FROM_WIN32(ERROR_NO_MORE_FILES))
  701. {
  702. hr = S_OK;
  703. }
  704. FindClose(hFileContext);
  705. if (S_OK == hr)
  706. {
  707. if (RemoveDirectory(pszDir))
  708. {
  709. hr = S_OK;
  710. }
  711. else
  712. {
  713. TraceTag(ttidNetcfgBase, "Error deleting directory %S", pszDir);
  714. TraceLastWin32Error("HrDeleteDirectory");
  715. hr = fContinueOnError ? S_OK : HrFromLastWin32Error();
  716. }
  717. }
  718. }
  719. else
  720. {
  721. hr = HrFromLastWin32Error();
  722. }
  723. TraceError("HrDeleteDirectory", hr);
  724. return hr;
  725. }
  726. //+---------------------------------------------------------------------------
  727. //
  728. // Function: LowerCaseComputerName
  729. //
  730. // Purpose: Utility function to lowercase a name obtained either from
  731. // the user via an UPPERCASE edit control, or via GetComputerName.
  732. //
  733. // Arguments:
  734. // szName [in,out] Computername, which is modified in-place
  735. //
  736. // Returns: VOID
  737. //
  738. // Author: SumitC 29 Sep 1999
  739. //
  740. // Notes: The conversion only fails if CharLowerBuffW fails. Per the user
  741. // guys, CharLowerBuff never actually returns any indication of
  742. // failure, so we can't tell anyway. I've been assured that the
  743. // conversion is VERY unlikely to fail.
  744. //
  745. VOID
  746. LowerCaseComputerName(
  747. IN OUT PWSTR szName)
  748. {
  749. // try the conversion
  750. Assert(szName);
  751. DWORD dwLen = wcslen(szName);
  752. DWORD dwConverted = CharLowerBuff(szName, dwLen);
  753. Assert(dwConverted == dwLen);
  754. }
  755. void __cdecl nc_trans_func( unsigned int uSECode, EXCEPTION_POINTERS* pExp )
  756. {
  757. throw SE_Exception( uSECode );
  758. }
  759. void EnableCPPExceptionHandling()
  760. {
  761. _set_se_translator(nc_trans_func);
  762. }
  763. void DisableCPPExceptionHandling()
  764. {
  765. _set_se_translator(NULL);
  766. }