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.

980 lines
25 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1995 - 1995.
  5. //
  6. // File: util.cxx
  7. //
  8. // Contents: Misc helper functions
  9. //
  10. // History: 5-Apr-95 BruceFo Created
  11. //
  12. //----------------------------------------------------------------------------
  13. #include "headers.hxx"
  14. #pragma hdrstop
  15. #include "resource.h"
  16. #include "util.hxx"
  17. #include <safeboot.h> // SAFEBOOT_* flags
  18. //////////////////////////////////////////////////////////////////////////////
  19. #define NETMSG_DLL TEXT("netmsg.dll")
  20. //////////////////////////////////////////////////////////////////////////////
  21. //+-------------------------------------------------------------------------
  22. //
  23. // Function: MyFormatMessageText
  24. //
  25. // Synopsis: Given a resource IDs, load strings from given instance
  26. // and format the string into a buffer
  27. //
  28. // History: 11-Aug-93 WilliamW Created.
  29. //
  30. //--------------------------------------------------------------------------
  31. VOID
  32. MyFormatMessageText(
  33. IN HRESULT dwMsgId,
  34. IN PWSTR pszBuffer,
  35. IN DWORD dwBufferSize,
  36. IN va_list * parglist
  37. )
  38. {
  39. //
  40. // get message from system or app msg file.
  41. //
  42. DWORD dwReturn = FormatMessage(
  43. FORMAT_MESSAGE_FROM_HMODULE,
  44. g_hInstance,
  45. dwMsgId,
  46. LANG_USER_DEFAULT,
  47. pszBuffer,
  48. dwBufferSize,
  49. parglist);
  50. if (0 == dwReturn) // couldn't find message
  51. {
  52. appDebugOut((DEB_IERROR,
  53. "FormatMessage failed, 0x%08lx\n",
  54. GetLastError()));
  55. WCHAR szText[200];
  56. LoadString(g_hInstance, IDS_APP_MSG_NOT_FOUND, szText, ARRAYLEN(szText));
  57. wsprintf(pszBuffer,szText,dwMsgId);
  58. }
  59. }
  60. //+-------------------------------------------------------------------------
  61. //
  62. // Function: MyCommonDialog
  63. //
  64. // Synopsis: Common popup dialog routine - stole from diskadm directory
  65. //
  66. //--------------------------------------------------------------------------
  67. DWORD
  68. MyCommonDialog(
  69. IN HWND hwnd,
  70. IN HRESULT dwMsgCode,
  71. IN PWSTR pszCaption,
  72. IN DWORD dwFlags,
  73. IN va_list arglist
  74. )
  75. {
  76. WCHAR szMsgBuf[500];
  77. MyFormatMessageText(dwMsgCode, szMsgBuf, ARRAYLEN(szMsgBuf), &arglist);
  78. return MessageBox(hwnd, szMsgBuf, pszCaption, dwFlags);
  79. }
  80. //+-------------------------------------------------------------------------
  81. //
  82. // Function: MyConfirmationDialog
  83. //
  84. // Synopsis: This routine retreives a message from the app or system
  85. // message file and displays it in a message box.
  86. //
  87. // Note: Stole from diskadm directory
  88. //
  89. //--------------------------------------------------------------------------
  90. DWORD
  91. MyConfirmationDialog(
  92. IN HWND hwnd,
  93. IN HRESULT dwMsgCode,
  94. IN DWORD dwFlags,
  95. ...
  96. )
  97. {
  98. WCHAR szCaption[100];
  99. DWORD dwReturn;
  100. va_list arglist;
  101. va_start(arglist, dwFlags);
  102. LoadString(g_hInstance, IDS_MSGTITLE, szCaption, ARRAYLEN(szCaption));
  103. dwReturn = MyCommonDialog(hwnd, dwMsgCode, szCaption, dwFlags, arglist);
  104. va_end(arglist);
  105. return dwReturn;
  106. }
  107. //+-------------------------------------------------------------------------
  108. //
  109. // Function: MyErrorDialog
  110. //
  111. // Synopsis: This routine retreives a message from the app or system
  112. // message file and displays it in a message box.
  113. //
  114. // Note: Stole from diskadm directory
  115. //
  116. //--------------------------------------------------------------------------
  117. VOID
  118. MyErrorDialog(
  119. IN HWND hwnd,
  120. IN HRESULT dwErrorCode,
  121. ...
  122. )
  123. {
  124. WCHAR szCaption[100];
  125. va_list arglist;
  126. va_start(arglist, dwErrorCode);
  127. LoadString(g_hInstance, IDS_MSGTITLE, szCaption, ARRAYLEN(szCaption));
  128. MyCommonDialog(hwnd, dwErrorCode, szCaption, MB_ICONSTOP | MB_OK, arglist);
  129. va_end(arglist);
  130. }
  131. //+---------------------------------------------------------------------------
  132. //
  133. // Function: NewDup
  134. //
  135. // Synopsis: Duplicate a string using '::new'
  136. //
  137. // History: 28-Dec-94 BruceFo Created
  138. //
  139. //----------------------------------------------------------------------------
  140. PWSTR
  141. NewDup(
  142. IN const WCHAR* psz
  143. )
  144. {
  145. if (NULL == psz)
  146. {
  147. appDebugOut((DEB_IERROR,"Illegal string to duplicate: NULL\n"));
  148. return NULL;
  149. }
  150. PWSTR pszRet = new WCHAR[wcslen(psz) + 1];
  151. if (NULL == pszRet)
  152. {
  153. appDebugOut((DEB_ERROR,"OUT OF MEMORY\n"));
  154. return NULL;
  155. }
  156. wcscpy(pszRet, psz);
  157. return pszRet;
  158. }
  159. //+---------------------------------------------------------------------------
  160. //
  161. // Function: GetResourceString
  162. //
  163. // Synopsis: Load a resource string, are return a "new"ed copy
  164. //
  165. // Arguments: [dwId] -- a resource string ID
  166. //
  167. // Returns: new memory copy of a string
  168. //
  169. // History: 5-Apr-95 BruceFo Created
  170. //
  171. //----------------------------------------------------------------------------
  172. PWSTR
  173. GetResourceString(
  174. IN DWORD dwId
  175. )
  176. {
  177. WCHAR sz[50];
  178. if (0 == LoadString(g_hInstance, dwId, sz, ARRAYLEN(sz)))
  179. {
  180. return NULL;
  181. }
  182. else
  183. {
  184. return NewDup(sz);
  185. }
  186. }
  187. //+-------------------------------------------------------------------------
  188. //
  189. // Member: FindLastComponent, public
  190. //
  191. // Synopsis: Parse a string to find the last component.
  192. //
  193. // History: 21-Nov-94 BruceFo
  194. //
  195. //--------------------------------------------------------------------------
  196. PWSTR
  197. FindLastComponent(
  198. IN WCHAR* pszStr
  199. )
  200. {
  201. PWSTR pszTmp = wcsrchr(pszStr, L'\\');
  202. if (pszTmp != NULL)
  203. {
  204. return pszTmp + 1;
  205. }
  206. else
  207. {
  208. return pszStr;
  209. }
  210. }
  211. //+-------------------------------------------------------------------------
  212. //
  213. // Member: CopySecurityDescriptor, public
  214. //
  215. // Synopsis: Copy an NT security descriptor. The security descriptor must
  216. // be in self-relative (not absolute) form. Delete the result
  217. // using LocalFree().
  218. //
  219. // History: 19-Apr-95 BruceFo Created
  220. //
  221. //--------------------------------------------------------------------------
  222. PSECURITY_DESCRIPTOR
  223. CopySecurityDescriptor(
  224. IN PSECURITY_DESCRIPTOR pSecDesc
  225. )
  226. {
  227. appDebugOut((DEB_ITRACE, "CopySecurityDescriptor, pSecDesc = 0x%08lx\n", pSecDesc));
  228. if (NULL == pSecDesc)
  229. {
  230. return NULL;
  231. }
  232. appAssert(IsValidSecurityDescriptor(pSecDesc));
  233. LONG err;
  234. DWORD dwLen = GetSecurityDescriptorLength(pSecDesc);
  235. PSECURITY_DESCRIPTOR pSelfSecDesc = reinterpret_cast<PSECURITY_DESCRIPTOR>(
  236. ::LocalAlloc( LMEM_ZEROINIT,dwLen ) );
  237. if (NULL == pSelfSecDesc)
  238. {
  239. appDebugOut((DEB_ERROR, "new SECURITY_DESCRIPTOR (2) failed\n"));
  240. return NULL; // actually, should probably return an error
  241. }
  242. DWORD cbSelfSecDesc = dwLen;
  243. if (!MakeSelfRelativeSD(pSecDesc, pSelfSecDesc, &cbSelfSecDesc))
  244. {
  245. appDebugOut((DEB_TRACE, "MakeSelfRelativeSD failed, 0x%08lx\n", GetLastError()));
  246. // assume it failed because it was already self-relative
  247. CopyMemory(pSelfSecDesc, pSecDesc, dwLen);
  248. }
  249. appAssert(IsValidSecurityDescriptor(pSelfSecDesc));
  250. return pSelfSecDesc;
  251. }
  252. //+-------------------------------------------------------------------------
  253. //
  254. // Member: WarnDelShare, public
  255. //
  256. // Synopsis: Function to warn a user that a share will be deleted, and give
  257. // the user a chance to cancel.
  258. //
  259. // Arguments: [hwnd] - parent window handle for messages
  260. // [idMsg] - message ID to display (rmdir vs. move)
  261. // [pszShare] - share name
  262. // [pszPath] - path that share affects
  263. //
  264. // Returns: IDYES if share was deleted, IDNO if we don't want to delete,
  265. // but keep going, IDCANCEL to stop going.
  266. //
  267. // History: 19-Apr-95 BruceFo Created
  268. //
  269. //--------------------------------------------------------------------------
  270. UINT
  271. WarnDelShare(
  272. IN HWND hwnd,
  273. IN UINT idMsg,
  274. IN PWSTR pszShare,
  275. IN PWSTR pszPath
  276. )
  277. {
  278. DWORD id = MyConfirmationDialog(
  279. hwnd,
  280. idMsg,
  281. MB_YESNOCANCEL | MB_ICONEXCLAMATION,
  282. pszPath,
  283. pszShare);
  284. if (id != IDYES)
  285. {
  286. return id;
  287. }
  288. id = ConfirmStopShare(hwnd, MB_YESNOCANCEL, pszShare);
  289. if (id != IDYES)
  290. {
  291. return id;
  292. }
  293. UINT ret = NetShareDel(NULL, pszShare, 0);
  294. if (ret != NERR_Success)
  295. {
  296. DisplayError(hwnd, IERR_CANT_DEL_SHARE, ret, pszShare);
  297. return IDYES; // allow the stop anyway
  298. }
  299. return IDYES;
  300. }
  301. //+-------------------------------------------------------------------------
  302. //
  303. // Member: ConfirmStopShare, public
  304. //
  305. // Synopsis: Display the appropriate confirmations when stopping a share.
  306. //
  307. // Arguments: [hwnd] - parent window handle for messages
  308. // [uType] - either MB_YESNO or MB_YESNOCANCEL
  309. // [pszShare] - ptr to affected share name
  310. //
  311. // Returns: IDYES if share should be deleted, IDNO if we don't want to
  312. // delete, but keep going, IDCANCEL to stop going.
  313. //
  314. // History: 19-Apr-95 BruceFo Created
  315. //
  316. //--------------------------------------------------------------------------
  317. DWORD
  318. ConfirmStopShare(
  319. IN HWND hwnd,
  320. IN UINT uType,
  321. IN LPWSTR pszShare
  322. )
  323. {
  324. DWORD id = IDYES;
  325. DWORD cConns = 0;
  326. DWORD cOpens = 0;
  327. NET_API_STATUS err = ShareConnectionInfo(pszShare, &cConns, &cOpens);
  328. if (err != NERR_Success)
  329. {
  330. DisplayError(hwnd, IERR_CANT_DEL_SHARE, err, pszShare);
  331. // allow the stop anyway
  332. }
  333. else if (cConns != 0)
  334. {
  335. // If there are any open files, just give the more detailed
  336. // message about there being open files. Otherwise, just say how
  337. // many connections there are.
  338. if (cOpens != 0)
  339. {
  340. id = MyConfirmationDialog(
  341. hwnd,
  342. MSG_STOPSHAREOPENS,
  343. uType | MB_ICONEXCLAMATION,
  344. cOpens,
  345. cConns,
  346. pszShare);
  347. }
  348. else
  349. {
  350. id = MyConfirmationDialog(
  351. hwnd,
  352. MSG_STOPSHARECONNS,
  353. uType | MB_ICONEXCLAMATION,
  354. cConns,
  355. pszShare);
  356. }
  357. }
  358. // JonN 4/4/01 328512
  359. // Explorer Sharing Tab (NTSHRUI) should popup warning on deleting
  360. // SYSVOL,NETLOGON and C$, D$... shares
  361. //
  362. // No need to worry about IPC$, that won't turn up in NTSHRUI
  363. if (IDYES == id)
  364. {
  365. bool fSpecialShare = !lstrcmpi(pszShare,L"NETLOGON")
  366. || !lstrcmpi(pszShare,L"SYSVOL");
  367. if ( fSpecialShare
  368. || (lstrlen(pszShare) == 2 && L'$'== pszShare[1])
  369. )
  370. {
  371. id = MyConfirmationDialog(
  372. hwnd,
  373. (fSpecialShare) ? MSG_DELSPECIALSHARE
  374. : MSG_DELADMINSHARE,
  375. uType | MB_ICONEXCLAMATION,
  376. pszShare);
  377. }
  378. }
  379. return id;
  380. }
  381. //+-------------------------------------------------------------------------
  382. //
  383. // Member: ShareConnectionInfo, public
  384. //
  385. // Synopsis: Determine how many connections and file opens exist for a
  386. // share, for use by confirmation dialogs.
  387. //
  388. // Arguments: [pszShare] - ptr to affected share name
  389. // [pcConns] - *pcConns get the number of connections
  390. // [pcOpens] - *pcOpens get the number of file opens
  391. //
  392. // Returns: standard net api code, NERR_Success if everything ok.
  393. //
  394. // History: 19-Apr-95 BruceFo Stolen
  395. //
  396. //--------------------------------------------------------------------------
  397. NET_API_STATUS
  398. ShareConnectionInfo(
  399. IN LPWSTR pszShare,
  400. OUT LPDWORD pcConns,
  401. OUT LPDWORD pcOpens
  402. )
  403. {
  404. CONNECTION_INFO_1* pBuf;
  405. DWORD iEntry, iTotal;
  406. NET_API_STATUS err = NetConnectionEnum(
  407. NULL,
  408. pszShare,
  409. 1,
  410. (LPBYTE*)&pBuf,
  411. 0xffffffff, // no buffer limit; get them all!
  412. &iEntry,
  413. &iTotal,
  414. NULL);
  415. if ((err == NERR_Success) || (err == ERROR_MORE_DATA))
  416. {
  417. int iConnections = 0;
  418. for (DWORD i = 0; i < iEntry; i++)
  419. {
  420. iConnections += pBuf[i].coni1_num_opens;
  421. }
  422. *pcConns = iTotal;
  423. *pcOpens = iConnections;
  424. err = NERR_Success;
  425. }
  426. else
  427. {
  428. *pcConns = 0;
  429. *pcOpens = 0;
  430. }
  431. NetApiBufferFree(pBuf);
  432. appDebugOut((DEB_ITRACE,"Share '%ws' has %d connections and %d opens\n", pszShare, *pcConns, *pcOpens));
  433. return err;
  434. }
  435. //+-------------------------------------------------------------------------
  436. //
  437. // Function: DisplayError
  438. //
  439. // Synopsis: Display an error message
  440. //
  441. // History: 24-Apr-95 BruceFo Stolen
  442. //
  443. //--------------------------------------------------------------------------
  444. VOID
  445. DisplayError(
  446. IN HWND hwnd,
  447. IN HRESULT dwErrorCode, // message file number. not really an HRESULT
  448. IN NET_API_STATUS err,
  449. IN PWSTR pszShare
  450. )
  451. {
  452. if ( err < MIN_LANMAN_MESSAGE_ID
  453. || err > MAX_LANMAN_MESSAGE_ID
  454. )
  455. {
  456. // a Win32 error?
  457. WCHAR szMsg[500];
  458. DWORD dwReturn = FormatMessage(
  459. FORMAT_MESSAGE_FROM_SYSTEM,
  460. NULL,
  461. err,
  462. LANG_USER_DEFAULT,
  463. szMsg,
  464. ARRAYLEN(szMsg),
  465. NULL);
  466. if (0 == dwReturn) // couldn't find message
  467. {
  468. appDebugOut((DEB_IERROR,
  469. "FormatMessage (from system) failed, 0x%08lx\n",
  470. GetLastError()));
  471. MyErrorDialog(hwnd, IERR_UNKNOWN, err);
  472. }
  473. else
  474. {
  475. MyErrorDialog(hwnd, dwErrorCode, pszShare, szMsg);
  476. }
  477. }
  478. else
  479. {
  480. DisplayLanmanError(hwnd, dwErrorCode, err, pszShare);
  481. }
  482. }
  483. //+-------------------------------------------------------------------------
  484. //
  485. // Function: DisplayLanmanError
  486. //
  487. // Synopsis: Display an error message from a LanMan error.
  488. //
  489. // History: 24-Apr-95 BruceFo Stolen
  490. //
  491. //--------------------------------------------------------------------------
  492. VOID
  493. DisplayLanmanError(
  494. IN HWND hwnd,
  495. IN HRESULT dwErrorCode, // message file number. not really an HRESULT
  496. IN NET_API_STATUS err,
  497. IN PWSTR pszShare
  498. )
  499. {
  500. if ( err < MIN_LANMAN_MESSAGE_ID
  501. || err > MAX_LANMAN_MESSAGE_ID
  502. )
  503. {
  504. MyErrorDialog(hwnd, IERR_UNKNOWN, err);
  505. return;
  506. }
  507. WCHAR szCaption[100];
  508. LoadString(g_hInstance, IDS_MSGTITLE, szCaption, ARRAYLEN(szCaption));
  509. //
  510. // get LanMan message from system message file.
  511. //
  512. WCHAR szNetMsg[500];
  513. WCHAR szBuf[500];
  514. HINSTANCE hInstanceNetMsg = LoadLibrary(NETMSG_DLL);
  515. if (NULL == hInstanceNetMsg)
  516. {
  517. appDebugOut((DEB_IERROR,
  518. "LoadLibrary(netmsg.dll) failed, 0x%08lx\n",
  519. GetLastError()));
  520. LoadString(g_hInstance, IDS_NO_NET_MSG, szBuf, ARRAYLEN(szBuf));
  521. MessageBox(hwnd, szBuf, szCaption, MB_ICONSTOP | MB_OK);
  522. return;
  523. }
  524. DWORD dwReturn = FormatMessage(
  525. FORMAT_MESSAGE_FROM_HMODULE,
  526. hInstanceNetMsg,
  527. err,
  528. LANG_USER_DEFAULT,
  529. szNetMsg,
  530. ARRAYLEN(szNetMsg),
  531. NULL);
  532. if (0 == dwReturn) // couldn't find message
  533. {
  534. appDebugOut((DEB_IERROR,
  535. "FormatMessage failed, 0x%08lx\n",
  536. GetLastError()));
  537. LoadString(g_hInstance, IDS_NET_MSG_NOT_FOUND, szBuf, ARRAYLEN(szBuf));
  538. wsprintf(szNetMsg, szBuf, GetLastError());
  539. MessageBox(hwnd, szNetMsg, szCaption, MB_ICONSTOP | MB_OK);
  540. }
  541. else
  542. {
  543. MyErrorDialog(hwnd, dwErrorCode, pszShare, szNetMsg);
  544. }
  545. FreeLibrary(hInstanceNetMsg);
  546. }
  547. //+-------------------------------------------------------------------------
  548. //
  549. // Function: IsValidShareName
  550. //
  551. // Synopsis: Checks if the proposed share name is valid or not. If not,
  552. // it will return a message id for the reason why.
  553. //
  554. // Arguments: [pszShareName] - Proposed share name
  555. // [puId] - If name is invalid, this will contain the reason why.
  556. //
  557. // Returns: TRUE if name is valid, else FALSE.
  558. //
  559. // History: 3-May-95 BruceFo Stolen
  560. //
  561. //--------------------------------------------------------------------------
  562. BOOL
  563. IsValidShareName(
  564. IN PCWSTR pszShareName,
  565. OUT HRESULT* uId
  566. )
  567. {
  568. if (NetpNameValidate(NULL, (PWSTR)pszShareName, NAMETYPE_SHARE, 0L) != NERR_Success)
  569. {
  570. *uId = IERR_InvalidShareName;
  571. return FALSE;
  572. }
  573. return TRUE;
  574. }
  575. //+-------------------------------------------------------------------------
  576. //
  577. // Function: SetErrorFocus
  578. //
  579. // Synopsis: Set focus to an edit control and select its text.
  580. //
  581. // Arguments: [hwnd] - dialog window
  582. // [idCtrl] - edit control to set focus to (and select)
  583. //
  584. // Returns: nothing
  585. //
  586. // History: 3-May-95 BruceFo Stolen
  587. //
  588. //--------------------------------------------------------------------------
  589. VOID
  590. SetErrorFocus(
  591. IN HWND hwnd,
  592. IN UINT idCtrl
  593. )
  594. {
  595. HWND hCtrl = ::GetDlgItem(hwnd, idCtrl);
  596. ::SetFocus(hCtrl);
  597. ::SendMessage(hCtrl, EM_SETSEL, 0, -1);
  598. }
  599. //+-------------------------------------------------------------------------
  600. //
  601. // Function: ConfirmReplaceShare
  602. //
  603. // Synopsis: Display confirmations for replacing an existing share
  604. //
  605. // Arguments: [hwnd] - dialog window
  606. // [pszShareName] - name of share being replaced
  607. // [pszOldPath] - current path for the share
  608. // [pszNewPath] - directory the user's trying to share
  609. //
  610. // Returns: Returns IDYES or IDNO
  611. //
  612. // History: 4-May-95 BruceFo Stolen
  613. //
  614. //--------------------------------------------------------------------------
  615. DWORD
  616. ConfirmReplaceShare(
  617. IN HWND hwnd,
  618. IN PCWSTR pszShareName,
  619. IN PCWSTR pszOldPath,
  620. IN PCWSTR pszNewPath
  621. )
  622. {
  623. DWORD id = MyConfirmationDialog(
  624. hwnd,
  625. MSG_RESHARENAMECONFIRM,
  626. MB_YESNO | MB_ICONEXCLAMATION,
  627. pszOldPath,
  628. pszShareName,
  629. pszNewPath);
  630. if (id != IDYES)
  631. {
  632. return id;
  633. }
  634. return ConfirmStopShare(hwnd, MB_YESNO, (PWSTR)pszShareName);
  635. }
  636. //+---------------------------------------------------------------------------
  637. //
  638. // Function: IsWorkstationProduct
  639. //
  640. // Synopsis: Determines the NT product type (server or workstation),
  641. // and returns TRUE if it is workstation.
  642. //
  643. // Arguments: (none)
  644. //
  645. // Returns: TRUE if running on workstation products
  646. //
  647. // History: 11-Sep-95 BruceFo Created
  648. //
  649. //----------------------------------------------------------------------------
  650. BOOL
  651. IsWorkstationProduct(
  652. VOID
  653. )
  654. {
  655. //
  656. // Determine whether this is the workstation or server product by looking
  657. // at HKEY_LOCAL_MACHINE, System\CurrentControlSet\Control\ProductOptions.
  658. // The ProductType value therein is interpreted as follows:
  659. //
  660. // LanmanNt -- server product, running as domain controller
  661. // ServerNt -- server product, not a domain controller
  662. // WinNT -- workstation product
  663. //
  664. LONG ec;
  665. HKEY hkey;
  666. DWORD type;
  667. DWORD size;
  668. UCHAR buf[100];
  669. BOOL fIsWorkstation = TRUE;
  670. ec = RegOpenKeyEx(
  671. HKEY_LOCAL_MACHINE,
  672. TEXT("System\\CurrentControlSet\\Control\\ProductOptions"),
  673. 0,
  674. KEY_QUERY_VALUE,
  675. &hkey
  676. );
  677. if (ec == NO_ERROR)
  678. {
  679. size = sizeof(buf);
  680. ec = RegQueryValueEx(hkey,
  681. TEXT("ProductType"),
  682. NULL,
  683. &type,
  684. buf,
  685. &size);
  686. if ((ec == NO_ERROR) && (type == REG_SZ))
  687. {
  688. if (0 == lstrcmpi((LPTSTR)buf, TEXT("lanmannt")))
  689. {
  690. fIsWorkstation = FALSE;
  691. }
  692. if (0 == lstrcmpi((LPTSTR)buf, TEXT("servernt")))
  693. {
  694. fIsWorkstation = FALSE;
  695. }
  696. }
  697. RegCloseKey(hkey);
  698. }
  699. return fIsWorkstation;
  700. }
  701. //+---------------------------------------------------------------------------
  702. //
  703. // Function: TrimLeadingAndTrailingSpaces
  704. //
  705. // Synopsis: Trims the leading and trailing spaces from a null-terminated string.
  706. // Used primarily for share names.
  707. //
  708. // History: 18-Jul-97 JonN Created
  709. //
  710. //----------------------------------------------------------------------------
  711. VOID
  712. TrimLeadingAndTrailingSpaces(
  713. IN OUT PWSTR psz
  714. )
  715. {
  716. int cchStrlen = ::wcslen(psz);
  717. int cchLeadingSpaces = 0;
  718. int cchTrailingSpaces = 0;
  719. while (L' ' == psz[cchLeadingSpaces])
  720. cchLeadingSpaces++;
  721. if (cchLeadingSpaces < cchStrlen)
  722. {
  723. while (L' ' == psz[cchStrlen-(cchTrailingSpaces+1)])
  724. cchTrailingSpaces++;
  725. }
  726. if ((cchLeadingSpaces+cchTrailingSpaces) > 0)
  727. {
  728. cchStrlen -= (cchLeadingSpaces+cchTrailingSpaces);
  729. (void)memmove( psz,
  730. psz+cchLeadingSpaces,
  731. cchStrlen*sizeof(WCHAR) );
  732. psz[cchStrlen] = L'\0';
  733. }
  734. }
  735. //+---------------------------------------------------------------------------
  736. //
  737. // Function: IsSafeMode
  738. //
  739. // Synopsis: Checks the registry to see if the system is in safe mode.
  740. //
  741. // History: 06-Oct-00 JeffreyS Created
  742. //
  743. //----------------------------------------------------------------------------
  744. BOOL
  745. IsSafeMode(
  746. VOID
  747. )
  748. {
  749. BOOL fIsSafeMode = FALSE;
  750. LONG ec;
  751. HKEY hkey;
  752. ec = RegOpenKeyEx(
  753. HKEY_LOCAL_MACHINE,
  754. TEXT("SYSTEM\\CurrentControlSet\\Control\\SafeBoot\\Option"),
  755. 0,
  756. KEY_QUERY_VALUE,
  757. &hkey
  758. );
  759. if (ec == NO_ERROR)
  760. {
  761. DWORD dwValue;
  762. DWORD dwValueSize = sizeof(dwValue);
  763. ec = RegQueryValueEx(hkey,
  764. TEXT("OptionValue"),
  765. NULL,
  766. NULL,
  767. (LPBYTE)&dwValue,
  768. &dwValueSize);
  769. if (ec == NO_ERROR)
  770. {
  771. fIsSafeMode = (dwValue == SAFEBOOT_MINIMAL || dwValue == SAFEBOOT_NETWORK);
  772. }
  773. RegCloseKey(hkey);
  774. }
  775. return fIsSafeMode;
  776. }
  777. //+---------------------------------------------------------------------------
  778. //
  779. // Function: IsForcedGuestModeOn
  780. //
  781. // Synopsis: Checks the registry to see if the system is using the
  782. // Guest-only network access mode.
  783. //
  784. // History: 06-Oct-00 JeffreyS Created
  785. // 19-Apr-00 GPease Modified and changed name
  786. //
  787. //----------------------------------------------------------------------------
  788. BOOL
  789. IsForcedGuestModeOn(
  790. VOID
  791. )
  792. {
  793. BOOL fIsForcedGuestModeOn = FALSE;
  794. if (IsOS(OS_PERSONAL))
  795. {
  796. // Guest mode is always on for Personal
  797. fIsForcedGuestModeOn = TRUE;
  798. }
  799. else if (IsOS(OS_PROFESSIONAL) && !IsOS(OS_DOMAINMEMBER))
  800. {
  801. LONG ec;
  802. HKEY hkey;
  803. // Professional, not in a domain. Check the ForceGuest value.
  804. ec = RegOpenKeyEx(
  805. HKEY_LOCAL_MACHINE,
  806. TEXT("SYSTEM\\CurrentControlSet\\Control\\LSA"),
  807. 0,
  808. KEY_QUERY_VALUE,
  809. &hkey
  810. );
  811. if (ec == NO_ERROR)
  812. {
  813. DWORD dwValue;
  814. DWORD dwValueSize = sizeof(dwValue);
  815. ec = RegQueryValueEx(hkey,
  816. TEXT("ForceGuest"),
  817. NULL,
  818. NULL,
  819. (LPBYTE)&dwValue,
  820. &dwValueSize);
  821. if (ec == NO_ERROR && 1 == dwValue)
  822. {
  823. fIsForcedGuestModeOn = TRUE;
  824. }
  825. RegCloseKey(hkey);
  826. }
  827. }
  828. return fIsForcedGuestModeOn;
  829. }
  830. //+---------------------------------------------------------------------------
  831. //
  832. // Function: IsSimpleUI
  833. //
  834. // Synopsis: Checks whether to show the simple version of the UI.
  835. //
  836. // History: 06-Oct-00 JeffreyS Created
  837. // 19-Apr-00 GPease Removed CTRL key check
  838. //
  839. //----------------------------------------------------------------------------
  840. BOOL
  841. IsSimpleUI(
  842. VOID
  843. )
  844. {
  845. // Show old UI in safe mode and anytime network access involves
  846. // true user identity (server, pro with GuestMode off).
  847. // Show simple UI anytime network access is done using the Guest
  848. // account (personal, pro with GuestMode on) except in safe mode.
  849. return (!IsSafeMode() && IsForcedGuestModeOn());
  850. }