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.

1557 lines
40 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 "shares.h"
  17. #include "util.hxx"
  18. #include "shrpage.hxx"
  19. #include "dlgnew.hxx"
  20. #include "strsafe.h"
  21. #include "ccstock.h"
  22. //////////////////////////////////////////////////////////////////////////////
  23. DECLARE_INFOLEVEL(Sharing)
  24. #define NETMSG_DLL TEXT("netmsg.dll")
  25. #ifdef WIZARDS
  26. TCHAR g_szShareWizardCmd[] = TEXT("ShrPubW.exe"); // The Share Publishing Wizard
  27. TCHAR g_szShareWizardArg[] = TEXT("/folder "); // The Share Publishing Wizard
  28. TCHAR g_szSfm[] = TEXT("/sfm "); // Services For Macintosh
  29. TCHAR g_szFpnw[] = TEXT("/fpnw "); // File and Print Services for NetWare
  30. TCHAR g_szAll[] = TEXT("/all "); // all services
  31. #endif // WIZARDS
  32. //--------------------------------------------------------------------------
  33. // Globals used elsewhere
  34. UINT g_NonOLEDLLRefs = 0;
  35. HINSTANCE g_hInstance = NULL;
  36. UINT g_uiMaxUsers = 0; // max number of users based on product type
  37. WCHAR g_szAdminShare[] = L"ADMIN$";
  38. WCHAR g_szIpcShare[] = L"IPC$";
  39. UINT g_cfHIDA = 0;
  40. //////////////////////////////////////////////////////////////////////////////
  41. DWORD
  42. ConfirmStopShare(
  43. IN HWND hwnd,
  44. IN LPWSTR pszShare
  45. );
  46. NET_API_STATUS
  47. ShareConnectionInfo(
  48. IN LPWSTR pszShare,
  49. OUT LPDWORD pcConns,
  50. OUT LPDWORD pcOpens
  51. );
  52. //////////////////////////////////////////////////////////////////////////////
  53. //+-------------------------------------------------------------------------
  54. //
  55. // Function: MyFormatMessageText
  56. //
  57. // Synopsis: Given a resource IDs, load strings from given instance
  58. // and format the string into a buffer
  59. //
  60. // History: 11-Aug-93 WilliamW Created.
  61. //
  62. //--------------------------------------------------------------------------
  63. VOID
  64. MyFormatMessageText(
  65. IN HRESULT dwMsgId,
  66. IN PWSTR pszBuffer,
  67. IN DWORD dwBufferSize,
  68. IN va_list * parglist
  69. )
  70. {
  71. //
  72. // get message from system or app msg file.
  73. //
  74. DWORD dwReturn = FormatMessage(
  75. FORMAT_MESSAGE_FROM_HMODULE,
  76. g_hInstance,
  77. dwMsgId,
  78. LANG_USER_DEFAULT,
  79. pszBuffer,
  80. dwBufferSize,
  81. parglist);
  82. if (0 == dwReturn) // couldn't find message
  83. {
  84. appDebugOut((DEB_IERROR,
  85. "FormatMessage failed, 0x%08lx\n",
  86. GetLastError()));
  87. WCHAR szText[200];
  88. LoadString(g_hInstance, IDS_APP_MSG_NOT_FOUND, szText, ARRAYLEN(szText));
  89. StringCchPrintf(pszBuffer, dwBufferSize, szText, dwMsgId);
  90. }
  91. }
  92. //+-------------------------------------------------------------------------
  93. //
  94. // Function: MyFormatMessage
  95. //
  96. // Synopsis:
  97. //
  98. // Note:
  99. //
  100. //--------------------------------------------------------------------------
  101. VOID
  102. MyFormatMessage(
  103. IN HRESULT dwMsgId,
  104. IN PWSTR pszBuffer,
  105. IN DWORD dwBufferSize,
  106. ...
  107. )
  108. {
  109. va_list arglist;
  110. va_start(arglist, dwBufferSize);
  111. MyFormatMessageText(dwMsgId, pszBuffer, dwBufferSize, &arglist);
  112. va_end(arglist);
  113. }
  114. //+-------------------------------------------------------------------------
  115. //
  116. // Function: MyCommonDialog
  117. //
  118. // Synopsis: Common popup dialog routine - stole from diskadm directory
  119. //
  120. //--------------------------------------------------------------------------
  121. DWORD
  122. MyCommonDialog(
  123. IN HWND hwnd,
  124. IN HRESULT dwMsgCode,
  125. IN PWSTR pszCaption,
  126. IN DWORD dwFlags,
  127. IN va_list arglist
  128. )
  129. {
  130. WCHAR szMsgBuf[500];
  131. MyFormatMessageText(dwMsgCode, szMsgBuf, ARRAYLEN(szMsgBuf), &arglist);
  132. return MessageBox(hwnd, szMsgBuf, pszCaption, dwFlags);
  133. }
  134. //+-------------------------------------------------------------------------
  135. //
  136. // Function: MyConfirmationDialog
  137. //
  138. // Synopsis: This routine retreives a message from the app or system
  139. // message file and displays it in a message box.
  140. //
  141. // Note: Stole from diskadm directory
  142. //
  143. //--------------------------------------------------------------------------
  144. DWORD
  145. MyConfirmationDialog(
  146. IN HWND hwnd,
  147. IN HRESULT dwMsgCode,
  148. IN DWORD dwFlags,
  149. ...
  150. )
  151. {
  152. WCHAR szCaption[100];
  153. DWORD dwReturn;
  154. va_list arglist;
  155. va_start(arglist, dwFlags);
  156. LoadString(g_hInstance, IDS_MSGTITLE, szCaption, ARRAYLEN(szCaption));
  157. dwReturn = MyCommonDialog(hwnd, dwMsgCode, szCaption, dwFlags, arglist);
  158. va_end(arglist);
  159. return dwReturn;
  160. }
  161. //+-------------------------------------------------------------------------
  162. //
  163. // Function: MyErrorDialog
  164. //
  165. // Synopsis: This routine retreives a message from the app or system
  166. // message file and displays it in a message box.
  167. //
  168. // Note: Stole from diskadm directory
  169. //
  170. //--------------------------------------------------------------------------
  171. VOID
  172. MyErrorDialog(
  173. IN HWND hwnd,
  174. IN HRESULT dwErrorCode,
  175. ...
  176. )
  177. {
  178. WCHAR szCaption[100];
  179. va_list arglist;
  180. va_start(arglist, dwErrorCode);
  181. LoadString(g_hInstance, IDS_MSGTITLE, szCaption, ARRAYLEN(szCaption));
  182. MyCommonDialog(hwnd, dwErrorCode, szCaption, MB_ICONSTOP | MB_OK, arglist);
  183. va_end(arglist);
  184. }
  185. //+---------------------------------------------------------------------------
  186. //
  187. // Function: NewDup
  188. //
  189. // Synopsis: Duplicate a string using '::new'
  190. //
  191. // History: 28-Dec-94 BruceFo Created
  192. //
  193. //----------------------------------------------------------------------------
  194. PWSTR
  195. NewDup(
  196. IN const WCHAR* psz
  197. )
  198. {
  199. if (NULL == psz)
  200. {
  201. appDebugOut((DEB_IERROR,"Illegal string to duplicate: NULL\n"));
  202. return NULL;
  203. }
  204. int cchRet = wcslen(psz) + 1;
  205. PWSTR pszRet = new WCHAR[cchRet];
  206. if (NULL == pszRet)
  207. {
  208. appDebugOut((DEB_ERROR,"OUT OF MEMORY\n"));
  209. return NULL;
  210. }
  211. StringCchCopy(pszRet, cchRet, psz);
  212. return pszRet;
  213. }
  214. //+---------------------------------------------------------------------------
  215. //
  216. // Function: GetResourceString
  217. //
  218. // Synopsis: Load a resource string, are return a "new"ed copy
  219. //
  220. // Arguments: [dwId] -- a resource string ID
  221. //
  222. // Returns: new memory copy of a string
  223. //
  224. // History: 5-Apr-95 BruceFo Created
  225. //
  226. //----------------------------------------------------------------------------
  227. PWSTR
  228. GetResourceString(
  229. IN DWORD dwId
  230. )
  231. {
  232. WCHAR sz[50];
  233. if (0 == LoadString(g_hInstance, dwId, sz, ARRAYLEN(sz)))
  234. {
  235. return NULL;
  236. }
  237. else
  238. {
  239. return NewDup(sz);
  240. }
  241. }
  242. //+-------------------------------------------------------------------------
  243. //
  244. // Member: CopySecurityDescriptor, public
  245. //
  246. // Synopsis: Copy an NT security descriptor. The security descriptor must
  247. // be in self-relative (not absolute) form. Delete the result
  248. // using LocalFree().
  249. //
  250. // History: 19-Apr-95 BruceFo Created
  251. //
  252. //--------------------------------------------------------------------------
  253. PSECURITY_DESCRIPTOR
  254. CopySecurityDescriptor(
  255. IN PSECURITY_DESCRIPTOR pSecDesc
  256. )
  257. {
  258. appDebugOut((DEB_ITRACE, "CopySecurityDescriptor, pSecDesc = 0x%08lx\n", pSecDesc));
  259. if (NULL == pSecDesc)
  260. {
  261. return NULL;
  262. }
  263. appAssert(IsValidSecurityDescriptor(pSecDesc));
  264. DWORD dwLen = GetSecurityDescriptorLength(pSecDesc);
  265. PSECURITY_DESCRIPTOR pSelfSecDesc = reinterpret_cast<PSECURITY_DESCRIPTOR>(
  266. ::LocalAlloc(LMEM_ZEROINIT, dwLen) );
  267. if (NULL == pSelfSecDesc)
  268. {
  269. appDebugOut((DEB_ERROR, "new SECURITY_DESCRIPTOR (2) failed\n"));
  270. return NULL; // actually, should probably return an error
  271. }
  272. DWORD cbSelfSecDesc = dwLen;
  273. if (!MakeSelfRelativeSD(pSecDesc, pSelfSecDesc, &cbSelfSecDesc))
  274. {
  275. appDebugOut((DEB_TRACE, "MakeSelfRelativeSD failed, 0x%08lx\n", GetLastError()));
  276. // assume it failed because it was already self-relative
  277. CopyMemory(pSelfSecDesc, pSecDesc, dwLen);
  278. }
  279. appAssert(IsValidSecurityDescriptor(pSelfSecDesc));
  280. return pSelfSecDesc;
  281. }
  282. //+-------------------------------------------------------------------------
  283. //
  284. // Function: DisplayError
  285. //
  286. // Synopsis: Display an error message
  287. //
  288. // History: 24-Apr-95 BruceFo Stolen
  289. //
  290. //--------------------------------------------------------------------------
  291. VOID
  292. DisplayError(
  293. IN HWND hwnd,
  294. IN HRESULT dwErrorCode, // message file number. not really an HRESULT
  295. IN NET_API_STATUS err,
  296. IN PWSTR pszShare
  297. )
  298. {
  299. if ( err < MIN_LANMAN_MESSAGE_ID
  300. || err > MAX_LANMAN_MESSAGE_ID
  301. )
  302. {
  303. // a Win32 error?
  304. WCHAR szMsg[500];
  305. DWORD dwReturn = FormatMessage(
  306. FORMAT_MESSAGE_FROM_SYSTEM,
  307. NULL,
  308. err,
  309. LANG_USER_DEFAULT,
  310. szMsg,
  311. ARRAYLEN(szMsg),
  312. NULL);
  313. if (0 == dwReturn) // couldn't find message
  314. {
  315. appDebugOut((DEB_IERROR,
  316. "FormatMessage (from system) failed, 0x%08lx\n",
  317. GetLastError()));
  318. MyErrorDialog(hwnd, IERR_UNKNOWN, err);
  319. }
  320. else
  321. {
  322. MyErrorDialog(hwnd, dwErrorCode, pszShare, szMsg);
  323. }
  324. }
  325. else
  326. {
  327. DisplayLanmanError(hwnd, dwErrorCode, err, pszShare);
  328. }
  329. }
  330. //+-------------------------------------------------------------------------
  331. //
  332. // Function: DisplayLanmanError
  333. //
  334. // Synopsis: Display an error message from a LanMan error.
  335. //
  336. // History: 24-Apr-95 BruceFo Stolen
  337. //
  338. //--------------------------------------------------------------------------
  339. VOID
  340. DisplayLanmanError(
  341. IN HWND hwnd,
  342. IN HRESULT dwErrorCode, // message file number. not really an HRESULT
  343. IN NET_API_STATUS err,
  344. IN PWSTR pszShare
  345. )
  346. {
  347. if ( err < MIN_LANMAN_MESSAGE_ID
  348. || err > MAX_LANMAN_MESSAGE_ID
  349. )
  350. {
  351. MyErrorDialog(hwnd, IERR_UNKNOWN, err);
  352. return;
  353. }
  354. WCHAR szCaption[100];
  355. LoadString(g_hInstance, IDS_MSGTITLE, szCaption, ARRAYLEN(szCaption));
  356. //
  357. // get LanMan message from system message file.
  358. //
  359. WCHAR szNetMsg[500];
  360. WCHAR szBuf[500];
  361. HINSTANCE hInstanceNetMsg = LoadLibrary(NETMSG_DLL);
  362. if (NULL == hInstanceNetMsg)
  363. {
  364. appDebugOut((DEB_IERROR,
  365. "LoadLibrary(netmsg.dll) failed, 0x%08lx\n",
  366. GetLastError()));
  367. LoadString(g_hInstance, IDS_NO_NET_MSG, szBuf, ARRAYLEN(szBuf));
  368. MessageBox(hwnd, szBuf, szCaption, MB_ICONSTOP | MB_OK);
  369. return;
  370. }
  371. DWORD dwReturn = FormatMessage(
  372. FORMAT_MESSAGE_FROM_HMODULE,
  373. hInstanceNetMsg,
  374. err,
  375. LANG_USER_DEFAULT,
  376. szNetMsg,
  377. ARRAYLEN(szNetMsg),
  378. NULL);
  379. if (0 == dwReturn) // couldn't find message
  380. {
  381. appDebugOut((DEB_IERROR,
  382. "FormatMessage failed, 0x%08lx\n",
  383. GetLastError()));
  384. LoadString(g_hInstance, IDS_NET_MSG_NOT_FOUND, szBuf, ARRAYLEN(szBuf));
  385. StringCchPrintf(szNetMsg, ARRAYSIZE(szNetMsg), szBuf, GetLastError());
  386. MessageBox(hwnd, szNetMsg, szCaption, MB_ICONSTOP | MB_OK);
  387. }
  388. else
  389. {
  390. MyErrorDialog(hwnd, dwErrorCode, pszShare, szNetMsg);
  391. }
  392. FreeLibrary(hInstanceNetMsg);
  393. }
  394. //+-------------------------------------------------------------------------
  395. //
  396. // Function: IsValidShareName
  397. //
  398. // Synopsis: Checks if the proposed share name is valid or not. If not,
  399. // it will return a message id for the reason why.
  400. //
  401. // Arguments: [pszShareName] - Proposed share name
  402. // [puId] - If name is invalid, this will contain the reason why.
  403. //
  404. // Returns: TRUE if name is valid, else FALSE.
  405. //
  406. // History: 3-May-95 BruceFo Stolen
  407. //
  408. //--------------------------------------------------------------------------
  409. BOOL
  410. IsValidShareName(
  411. IN PCWSTR pszShareName,
  412. OUT HRESULT* uId
  413. )
  414. {
  415. if (NetpNameValidate(NULL, (PWSTR)pszShareName, NAMETYPE_SHARE, 0L) != NERR_Success)
  416. {
  417. *uId = IERR_InvalidShareName;
  418. return FALSE;
  419. }
  420. return TRUE;
  421. }
  422. //+-------------------------------------------------------------------------
  423. //
  424. // Function: SetErrorFocus
  425. //
  426. // Synopsis: Set focus to an edit control and select its text.
  427. //
  428. // Arguments: [hwnd] - dialog window
  429. // [idCtrl] - edit control to set focus to (and select)
  430. //
  431. // Returns: nothing
  432. //
  433. // History: 3-May-95 BruceFo Stolen
  434. //
  435. //--------------------------------------------------------------------------
  436. VOID
  437. SetErrorFocus(
  438. IN HWND hwnd,
  439. IN UINT idCtrl
  440. )
  441. {
  442. HWND hCtrl = ::GetDlgItem(hwnd, idCtrl);
  443. ::SetFocus(hCtrl);
  444. ::SendMessage(hCtrl, EM_SETSEL, 0, -1);
  445. }
  446. //+-------------------------------------------------------------------------
  447. //
  448. // Function: ConfirmReplaceShare
  449. //
  450. // Synopsis: Display confirmations for replacing an existing share
  451. //
  452. // Arguments: [hwnd] - dialog window
  453. // [pszShareName] - name of share being replaced
  454. // [pszOldPath] - current path for the share
  455. // [pszNewPath] - directory the user's trying to share
  456. //
  457. // Returns: Returns IDYES, IDNO, or IDCANCEL
  458. //
  459. // History: 4-May-95 BruceFo Stolen
  460. //
  461. //--------------------------------------------------------------------------
  462. DWORD
  463. ConfirmReplaceShare(
  464. IN HWND hwnd,
  465. IN PCWSTR pszShareName,
  466. IN PCWSTR pszOldPath,
  467. IN PCWSTR pszNewPath
  468. )
  469. {
  470. DWORD id = MyConfirmationDialog(
  471. hwnd,
  472. MSG_RESHARENAMECONFIRM,
  473. MB_YESNO | MB_ICONEXCLAMATION,
  474. pszOldPath,
  475. pszShareName,
  476. pszNewPath);
  477. if (id != IDYES)
  478. {
  479. return id;
  480. }
  481. return ConfirmStopShare(hwnd, (PWSTR)pszShareName);
  482. }
  483. //+-------------------------------------------------------------------------
  484. //
  485. // Member: ConfirmStopShare, public
  486. //
  487. // Synopsis: Display the appropriate confirmations when stopping a share.
  488. //
  489. // Arguments: [hwnd] - parent window handle for messages
  490. // [pszShare] - ptr to affected share name
  491. //
  492. // Returns: IDYES if share should be deleted, IDNO if we don't want to
  493. // delete, but keep going, IDCANCEL to stop going.
  494. //
  495. // History: 19-Apr-95 BruceFo Created
  496. //
  497. //--------------------------------------------------------------------------
  498. DWORD
  499. ConfirmStopShare(
  500. IN HWND hwnd,
  501. IN LPWSTR pszShare
  502. )
  503. {
  504. DWORD cConns, cOpens;
  505. NET_API_STATUS err = ShareConnectionInfo(pszShare, &cConns, &cOpens);
  506. if (err != NERR_Success)
  507. {
  508. DisplayError(hwnd, IERR_CANT_DEL_SHARE, err, pszShare);
  509. return IDYES; // allow the stop anyway
  510. }
  511. if (cConns != 0)
  512. {
  513. // If there are any open files, just give the more detailed
  514. // message about there being open files. Otherwise, just say how
  515. // many connections there are.
  516. if (cOpens != 0)
  517. {
  518. return MyConfirmationDialog(
  519. hwnd,
  520. MSG_STOPSHAREOPENS,
  521. MB_YESNOCANCEL | MB_ICONEXCLAMATION,
  522. cOpens,
  523. cConns,
  524. pszShare);
  525. }
  526. else
  527. {
  528. return MyConfirmationDialog(
  529. hwnd,
  530. MSG_STOPSHARECONNS,
  531. MB_YESNOCANCEL | MB_ICONEXCLAMATION,
  532. cConns,
  533. pszShare);
  534. }
  535. }
  536. return IDYES; /* OK to delete */
  537. }
  538. //+-------------------------------------------------------------------------
  539. //
  540. // Member: ShareConnectionInfo, public
  541. //
  542. // Synopsis: Determine how many connections and file opens exist for a
  543. // share, for use by confirmation dialogs.
  544. //
  545. // Arguments: [pszShare] - ptr to affected share name
  546. // [pcConns] - *pcConns get the number of connections
  547. // [pcOpens] - *pcOpens get the number of file opens
  548. //
  549. // Returns: standard net api code, NERR_Success if everything ok.
  550. //
  551. // History: 19-Apr-95 BruceFo Stolen
  552. //
  553. //--------------------------------------------------------------------------
  554. NET_API_STATUS
  555. ShareConnectionInfo(
  556. IN LPWSTR pszShare,
  557. OUT LPDWORD pcConns,
  558. OUT LPDWORD pcOpens
  559. )
  560. {
  561. CONNECTION_INFO_1* pBuf;
  562. DWORD iEntry, iTotal;
  563. NET_API_STATUS err = NetConnectionEnum(
  564. NULL,
  565. pszShare,
  566. 1,
  567. (LPBYTE*)&pBuf,
  568. 0xffffffff, // no buffer limit; get them all!
  569. &iEntry,
  570. &iTotal,
  571. NULL);
  572. if ((err == NERR_Success) || (err == ERROR_MORE_DATA))
  573. {
  574. int iConnections = 0;
  575. for (DWORD i = 0; i < iEntry; i++)
  576. {
  577. iConnections += pBuf[i].coni1_num_opens;
  578. }
  579. *pcConns = iTotal;
  580. *pcOpens = iConnections;
  581. err = NERR_Success;
  582. }
  583. else
  584. {
  585. *pcConns = 0;
  586. *pcOpens = 0;
  587. }
  588. NetApiBufferFree(pBuf);
  589. appDebugOut((DEB_ITRACE,"Share '%ws' has %d connections and %d opens\n", pszShare, *pcConns, *pcOpens));
  590. return err;
  591. }
  592. //+---------------------------------------------------------------------------
  593. //
  594. // Function: IsWorkstationProduct
  595. //
  596. // Synopsis: Determines the NT product type (server or workstation),
  597. // and returns TRUE if it is workstation.
  598. //
  599. // Arguments: (none)
  600. //
  601. // Returns: TRUE if running on workstation products
  602. //
  603. // History: 11-Sep-95 BruceFo Created
  604. //
  605. //----------------------------------------------------------------------------
  606. BOOL
  607. IsWorkstationProduct(
  608. VOID
  609. )
  610. {
  611. //
  612. // Determine whether this is the workstation or server product by looking
  613. // at HKEY_LOCAL_MACHINE, System\CurrentControlSet\Control\ProductOptions.
  614. // The ProductType value therein is interpreted as follows:
  615. //
  616. // LanmanNt -- server product, running as domain controller
  617. // ServerNt -- server product, not a domain controller
  618. // WinNT -- workstation product
  619. //
  620. LONG ec;
  621. HKEY hkey;
  622. DWORD type;
  623. DWORD size;
  624. UCHAR buf[100];
  625. BOOL fIsWorkstation = TRUE;
  626. ec = RegOpenKeyEx(
  627. HKEY_LOCAL_MACHINE,
  628. TEXT("System\\CurrentControlSet\\Control\\ProductOptions"),
  629. 0,
  630. KEY_QUERY_VALUE,
  631. &hkey
  632. );
  633. if (ec == NO_ERROR)
  634. {
  635. size = sizeof(buf);
  636. ec = RegQueryValueEx(hkey,
  637. TEXT("ProductType"),
  638. NULL,
  639. &type,
  640. buf,
  641. &size);
  642. if ((ec == NO_ERROR) && (type == REG_SZ))
  643. {
  644. if (0 == lstrcmpi((LPTSTR)buf, TEXT("lanmannt")))
  645. {
  646. fIsWorkstation = FALSE;
  647. }
  648. if (0 == lstrcmpi((LPTSTR)buf, TEXT("servernt")))
  649. {
  650. fIsWorkstation = FALSE;
  651. }
  652. }
  653. RegCloseKey(hkey);
  654. }
  655. return fIsWorkstation;
  656. }
  657. BOOL
  658. DriveLetterShare(
  659. PWSTR pszShareName
  660. )
  661. {
  662. if (NULL == pszShareName || lstrlen(pszShareName) != 2)
  663. {
  664. return FALSE;
  665. }
  666. // BUGBUG: what about non-English char sets?
  667. return ( ((pszShareName[0] >= TEXT('a')) && pszShareName[0] <= TEXT('z'))
  668. || ((pszShareName[0] >= TEXT('A')) && pszShareName[0] <= TEXT('Z'))
  669. )
  670. && (pszShareName[1] == TEXT('$'))
  671. ;
  672. }
  673. #if DBG == 1
  674. //+-------------------------------------------------------------------------
  675. //
  676. // Function: DumpNetEnum
  677. //
  678. // Synopsis: Dumps an array of SHARE_INFO_1 structures.
  679. //
  680. // History: 4-Apr-95 BruceFo Created
  681. //
  682. //--------------------------------------------------------------------------
  683. VOID
  684. DumpNetEnum(
  685. IN LPVOID pBufShares,
  686. IN ULONG entriesRead
  687. )
  688. {
  689. SHARE_INFO_1* pBase = (SHARE_INFO_1*) pBufShares;
  690. appDebugOut((DEB_TRACE,
  691. "DumpNetEnum: %d entries\n",
  692. entriesRead));
  693. for (ULONG i = 0; i < entriesRead; i++)
  694. {
  695. SHARE_INFO_1* p = &(pBase[i]);
  696. appDebugOut((DEB_TRACE | DEB_NOCOMPNAME,
  697. "\t Share name: %ws\n"
  698. "\t Type: %d (0x%08lx)\n"
  699. "\t Comment: %ws\n"
  700. "\n"
  701. ,
  702. p->shi1_netname,
  703. p->shi1_type, p->shi1_type,
  704. p->shi1_remark
  705. ));
  706. }
  707. }
  708. #endif // DBG == 1
  709. struct SHARE_PROPERTIES_DATA
  710. {
  711. IUnknown* punk;
  712. LPTSTR pszMachine;
  713. LPTSTR pszShareName;
  714. };
  715. DWORD CALLBACK
  716. SharePropertiesThreadProc(
  717. LPVOID lpThreadParameter
  718. )
  719. {
  720. SHARE_PROPERTIES_DATA* pData = (SHARE_PROPERTIES_DATA*)lpThreadParameter;
  721. if (NULL == pData)
  722. {
  723. appAssert(!"Unexpected properties thread data");
  724. return 0;
  725. }
  726. WCHAR szCaption[MAX_PATH];
  727. LoadString(g_hInstance, IDS_SHARE_PROPTITLE, szCaption, ARRAYLEN(szCaption));
  728. SHARE_PROPSHEETPAGE sprop;
  729. sprop.psp.dwSize = sizeof(sprop); // no extra data.
  730. sprop.psp.dwFlags = PSP_USEREFPARENT;
  731. sprop.psp.hInstance = g_hInstance;
  732. sprop.psp.pszTemplate = MAKEINTRESOURCE(IDD_SHARE_PROPERTIES);
  733. sprop.psp.hIcon = NULL;
  734. sprop.psp.pszTitle = NULL;
  735. sprop.psp.pfnDlgProc = CSharingPropertyPage::DlgProcPage;
  736. sprop.psp.lParam = 0;
  737. sprop.psp.pfnCallback = NULL;
  738. sprop.psp.pcRefParent = &g_NonOLEDLLRefs;
  739. sprop.pszMachine = pData->pszMachine;
  740. sprop.pszShareName = pData->pszShareName;
  741. PROPSHEETHEADER psh;
  742. psh.dwSize = sizeof(PROPSHEETHEADER);
  743. psh.dwFlags = PSH_PROPSHEETPAGE | PSH_USEICONID;
  744. psh.hwndParent = NULL;
  745. psh.hInstance = g_hInstance;
  746. psh.pszIcon = MAKEINTRESOURCE(IDI_SHARESFLD);
  747. psh.pszCaption = szCaption;
  748. psh.nPages = 1;
  749. psh.nStartPage = 0;
  750. psh.ppsp = (LPCPROPSHEETPAGE)&sprop;
  751. psh.pfnCallback= NULL;
  752. PropertySheet(&psh);
  753. pData->punk->Release();
  754. LocalFree(pData); // The strings are packed in the same allocation!
  755. return 0;
  756. }
  757. HRESULT
  758. ShareDoProperties(
  759. IN IUnknown* punk,
  760. IN LPTSTR pszMachine,
  761. IN LPTSTR pszShareName
  762. )
  763. {
  764. if (NULL == pszShareName)
  765. {
  766. return E_INVALIDARG;
  767. }
  768. DWORD cbMachine = 0;
  769. DWORD cbStrings = 0;
  770. if (NULL != pszMachine)
  771. {
  772. cbMachine = (lstrlen(pszMachine) + 1) * sizeof(TCHAR);
  773. cbStrings += cbMachine;
  774. }
  775. cbStrings += (lstrlen(pszShareName) + 1) * sizeof(TCHAR);
  776. HRESULT hr = S_OK;
  777. HANDLE hThread;
  778. DWORD idThread;
  779. SHARE_PROPERTIES_DATA* pData = (SHARE_PROPERTIES_DATA*)LocalAlloc(LPTR, sizeof(SHARE_PROPERTIES_DATA) + cbStrings);
  780. if (pData)
  781. {
  782. if (NULL != pszMachine)
  783. {
  784. pData->pszMachine = (LPWSTR)(((LPBYTE)pData) + sizeof(SHARE_PROPERTIES_DATA));
  785. StringCbCopy(pData->pszMachine, cbMachine, pszMachine);
  786. }
  787. else
  788. {
  789. pData->pszMachine = NULL;
  790. }
  791. pData->pszShareName = (LPWSTR)(((LPBYTE)pData) + sizeof(SHARE_PROPERTIES_DATA) + cbMachine);
  792. StringCbCopy(pData->pszShareName, cbStrings - cbMachine, pszShareName);
  793. pData->punk = punk;
  794. pData->punk->AddRef();
  795. hThread = CreateThread(NULL, 0, SharePropertiesThreadProc, pData, 0, &idThread);
  796. if (hThread)
  797. {
  798. CloseHandle(hThread);
  799. return S_OK;
  800. }
  801. else
  802. {
  803. pData->punk->Release();
  804. LocalFree(pData);
  805. return HRESULT_FROM_WIN32(GetLastError());
  806. }
  807. }
  808. else
  809. {
  810. hr = E_OUTOFMEMORY;
  811. }
  812. return hr;
  813. }
  814. HRESULT
  815. ShareDoDelete(
  816. IN HWND hwndOwner,
  817. IN PWSTR pszMachine,
  818. IN PWSTR pszShareName
  819. )
  820. {
  821. // Remove the share. We need to know the path that was
  822. // shared to be able to update the explorer. So, get
  823. // that.
  824. SHARE_INFO_1* pInfo1 = NULL;
  825. SHARE_INFO_2* pInfo2 = NULL;
  826. DWORD ret;
  827. HRESULT hr = S_OK;
  828. ret = NetShareGetInfo(pszMachine, pszShareName, 2, (LPBYTE*)&pInfo2);
  829. if (NERR_Success != ret)
  830. {
  831. // make sure it's null
  832. pInfo2 = NULL;
  833. }
  834. // Warn and confirm if it's a special share, either ADMIN$, IPC$,
  835. // or <drive>$
  836. if (NULL == pInfo2)
  837. {
  838. // Permissions problem? Try getting SHARE_INFO_1.
  839. ret = NetShareGetInfo(pszMachine, pszShareName, 1, (LPBYTE*)&pInfo1);
  840. if (NERR_Success != ret)
  841. {
  842. // make sure it's null
  843. pInfo1 = NULL;
  844. }
  845. }
  846. else
  847. {
  848. pInfo1 = (SHARE_INFO_1*)pInfo2; // I just need the type
  849. }
  850. if (NULL != pInfo1)
  851. {
  852. DWORD id = IDYES;
  853. if (pInfo1->shi1_type & STYPE_SPECIAL)
  854. {
  855. id = MyConfirmationDialog(
  856. hwndOwner,
  857. MSG_DELETESPECIAL,
  858. MB_YESNO | MB_ICONEXCLAMATION,
  859. pszShareName);
  860. }
  861. if (pInfo1 != (SHARE_INFO_1*)pInfo2)
  862. {
  863. NetApiBufferFree(pInfo1);
  864. }
  865. if (id != IDYES)
  866. {
  867. hr = S_OK;
  868. goto nodelete;
  869. }
  870. }
  871. // Actually delete the share
  872. ret = NetShareDel(pszMachine, pszShareName, 0);
  873. if (NERR_Success == ret)
  874. {
  875. if (NULL != pInfo2)
  876. {
  877. SHChangeNotify(SHCNE_NETUNSHARE, SHCNF_PATH, pInfo2->shi2_path, 0);
  878. }
  879. }
  880. else
  881. {
  882. // BUGBUG: error message to user
  883. hr = HRESULT_FROM_WIN32(GetLastError());
  884. }
  885. nodelete:
  886. if (NULL != pInfo2)
  887. {
  888. NetApiBufferFree(pInfo2);
  889. }
  890. return hr;
  891. }
  892. struct SHARE_NEW_DATA
  893. {
  894. IUnknown* punk;
  895. LPTSTR pszMachine;
  896. };
  897. DWORD CALLBACK
  898. ShareNewThreadProc(
  899. LPVOID lpThreadParameter
  900. )
  901. {
  902. SHARE_NEW_DATA* pData = (SHARE_NEW_DATA*)lpThreadParameter;
  903. if (NULL == pData)
  904. {
  905. appAssert(!"Unexpected properties thread data");
  906. return 0;
  907. }
  908. CDlgNewShare dlg(NULL, pData->pszMachine);
  909. if (dlg.DoModal())
  910. {
  911. }
  912. pData->punk->Release();
  913. LocalFree(pData); // The strings are packed in the same allocation!
  914. return 0;
  915. }
  916. HRESULT
  917. ShareDoNew(
  918. IN IUnknown* punk,
  919. IN PWSTR pszMachine
  920. )
  921. {
  922. DWORD cbStrings = 0;
  923. if (NULL != pszMachine)
  924. {
  925. cbStrings += (lstrlen(pszMachine) + 1) * sizeof(TCHAR);
  926. }
  927. HRESULT hr = S_OK;
  928. HANDLE hThread;
  929. DWORD idThread;
  930. SHARE_NEW_DATA* pData = (SHARE_NEW_DATA*)LocalAlloc(LPTR, sizeof(SHARE_NEW_DATA) + cbStrings);
  931. if (pData)
  932. {
  933. if (NULL != pszMachine)
  934. {
  935. pData->pszMachine = (LPWSTR)(((LPBYTE)pData) + sizeof(SHARE_NEW_DATA));
  936. StringCbCopy(pData->pszMachine, cbStrings, pszMachine);
  937. }
  938. else
  939. {
  940. pData->pszMachine = NULL;
  941. }
  942. pData->punk = punk;
  943. pData->punk->AddRef();
  944. hThread = CreateThread(NULL, 0, ShareNewThreadProc, pData, 0, &idThread);
  945. if (hThread)
  946. {
  947. CloseHandle(hThread);
  948. return S_OK;
  949. }
  950. else
  951. {
  952. pData->punk->Release();
  953. LocalFree(pData);
  954. return HRESULT_FROM_WIN32(GetLastError());
  955. }
  956. }
  957. else
  958. {
  959. hr = E_OUTOFMEMORY;
  960. }
  961. return hr;
  962. }
  963. #ifdef WIZARDS
  964. HRESULT
  965. ShareDoSpecial(
  966. IN HWND hwndOwner,
  967. IN PWSTR pszMachine,
  968. IN BYTE bType
  969. )
  970. {
  971. // Construct the command line to pass to the Share Wizard
  972. TCHAR szCommandLine[MAX_PATH];
  973. StringCchCopy(szCommandLine, ARRAYSIZE(szCommandLine), g_szShareWizardArg);
  974. switch (bType)
  975. {
  976. case SHID_SHARE_NW:
  977. StringCchCat(szCommandLine, ARRAYSIZE(szCommandLine), g_szFpnw);
  978. break;
  979. case SHID_SHARE_MAC:
  980. StringCchCat(szCommandLine, ARRAYSIZE(szCommandLine), g_szSfm);
  981. break;
  982. case SHID_SHARE_ALL:
  983. StringCchCat(szCommandLine, ARRAYSIZE(szCommandLine), g_szAll);
  984. break;
  985. case SHID_SHARE_NEW:
  986. // nothing special
  987. break;
  988. default: appAssert(!"Unknown object type");
  989. }
  990. if (NULL != pszMachine)
  991. {
  992. StringCchCat(szCommandLine, ARRAYSIZE(szCommandLine), pszMachine);
  993. }
  994. appDebugOut((DEB_TRACE, "Invoking wizard with this command line: %ws\n", szCommandLine));
  995. // Looks like CreateProcess writes to this buffer!
  996. STARTUPINFO si = { 0 };
  997. si.cb = sizeof(si);
  998. PROCESS_INFORMATION pi = { 0 };
  999. BOOL b = CreateProcess(
  1000. g_szShareWizardCmd,
  1001. szCommandLine,
  1002. NULL, // pointer to process security attributes
  1003. NULL, // pointer to thread security attributes
  1004. FALSE, // handle inheritance flag
  1005. 0, // creation flags
  1006. NULL, // pointer to new environment block
  1007. NULL, // pointer to current directory name
  1008. &si, // pointer to STARTUPINFO
  1009. &pi); // pointer to PROCESS_INFORMATION
  1010. if (b)
  1011. {
  1012. CloseHandle(pi.hProcess);
  1013. CloseHandle(pi.hThread);
  1014. }
  1015. else
  1016. {
  1017. appDebugOut((DEB_ERROR,
  1018. "CreateProcess failed, 0x%08lx\n",
  1019. GetLastError()));
  1020. MyErrorDialog(hwndOwner, MSG_NOWIZARD);
  1021. }
  1022. return S_OK;
  1023. }
  1024. #endif // WIZARDS
  1025. VOID FSSetStatusText(HWND hwndOwner, LPTSTR* ppszText, int iStart, int iEnd)
  1026. {
  1027. HWND hwndStatus = NULL;
  1028. IShellBrowser* psb = FileCabinet_GetIShellBrowser(hwndOwner);
  1029. if (psb)
  1030. {
  1031. psb->GetControlWindow(FCW_STATUS, &hwndStatus);
  1032. if (hwndStatus)
  1033. {
  1034. for (; iStart <= iEnd; iStart++)
  1035. {
  1036. LPTSTR lpsz;
  1037. if (ppszText)
  1038. {
  1039. lpsz = *ppszText;
  1040. ppszText++;
  1041. }
  1042. else
  1043. {
  1044. lpsz = (LPTSTR)TEXT("");
  1045. }
  1046. #ifdef WINDOWS_ME
  1047. SendMessage(hwndStatus, SB_SETTEXT, SB_RTLREADING | (WPARAM)iStart, (LPARAM)lpsz);
  1048. #else
  1049. SendMessage(hwndStatus, SB_SETTEXT, (WPARAM)iStart, (LPARAM)lpsz);
  1050. #endif
  1051. }
  1052. }
  1053. }
  1054. }
  1055. BOOL
  1056. IsLevelOk(
  1057. IN PWSTR pszMachine,
  1058. IN DWORD level
  1059. )
  1060. {
  1061. LPBYTE pBuf = NULL;
  1062. DWORD entriesread, totalentries;
  1063. NET_API_STATUS ret;
  1064. // we want to get the minimum amount of data, because all we care about
  1065. // is whether it succeeds the access check
  1066. DWORD prefmaxlen = 300;
  1067. for (;; prefmaxlen *= 2)
  1068. {
  1069. ret = NetShareEnum(
  1070. pszMachine,
  1071. level,
  1072. &pBuf,
  1073. prefmaxlen,
  1074. &entriesread,
  1075. &totalentries,
  1076. NULL);
  1077. if (NERR_BufTooSmall != ret)
  1078. {
  1079. NetApiBufferFree(pBuf);
  1080. break;
  1081. }
  1082. }
  1083. if (ERROR_ACCESS_DENIED == ret)
  1084. {
  1085. return FALSE;
  1086. }
  1087. else if (NERR_Success == ret || ERROR_MORE_DATA == ret)
  1088. {
  1089. return TRUE;
  1090. }
  1091. else
  1092. {
  1093. // some other error
  1094. return FALSE;
  1095. }
  1096. }
  1097. VOID
  1098. SetDialogIconBig(
  1099. IN HWND hwnd,
  1100. WORD idIcon
  1101. )
  1102. {
  1103. HICON hiconLarge = (HICON)LoadImage(
  1104. g_hInstance,
  1105. MAKEINTRESOURCE(idIcon),
  1106. IMAGE_ICON,
  1107. GetSystemMetrics(SM_CXICON),
  1108. GetSystemMetrics(SM_CYICON),
  1109. LR_DEFAULTCOLOR);
  1110. if (NULL == hiconLarge)
  1111. {
  1112. appDebugOut((DEB_ERROR,
  1113. "LoadImage for large image failed, 0x%08lx\n",
  1114. GetLastError()));
  1115. }
  1116. else
  1117. {
  1118. SendMessage(hwnd, WM_SETICON, ICON_BIG, (LPARAM)hiconLarge);
  1119. }
  1120. }
  1121. VOID
  1122. SetDialogIconSmall(
  1123. IN HWND hwnd,
  1124. WORD idIcon
  1125. )
  1126. {
  1127. HICON hiconSmall = (HICON)LoadImage(
  1128. g_hInstance,
  1129. MAKEINTRESOURCE(idIcon),
  1130. IMAGE_ICON,
  1131. GetSystemMetrics(SM_CXSMICON),
  1132. GetSystemMetrics(SM_CYSMICON),
  1133. LR_DEFAULTCOLOR);
  1134. if (NULL == hiconSmall)
  1135. {
  1136. appDebugOut((DEB_ERROR,
  1137. "LoadImage for small image failed, 0x%08lx\n",
  1138. GetLastError()));
  1139. }
  1140. else
  1141. {
  1142. SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)hiconSmall);
  1143. }
  1144. }
  1145. //////////////////////////////////////////////////////////////////////////////
  1146. HRESULT
  1147. STRRETLoadString(
  1148. UINT ids,
  1149. STRRET* pstr
  1150. )
  1151. {
  1152. #ifdef UNICODE
  1153. TCHAR szTemp[MAX_PATH];
  1154. szTemp[0] = TEXT('\0');
  1155. LoadString(g_hInstance, ids, szTemp, ARRAYLEN(szTemp));
  1156. int cchOleStr = lstrlen(szTemp)+1;
  1157. pstr->pOleStr = (LPOLESTR)SHAlloc(cchOleStr * sizeof(TCHAR));
  1158. if (NULL != pstr->pOleStr)
  1159. {
  1160. pstr->uType = STRRET_OLESTR;
  1161. StringCchCopy(pstr->pOleStr, cchOleStr, szTemp);
  1162. }
  1163. else
  1164. {
  1165. pstr->uType = STRRET_CSTR;
  1166. pstr->cStr[0] = '\0';
  1167. return E_OUTOFMEMORY;
  1168. }
  1169. #else
  1170. pstr->uType = STRRET_CSTR;
  1171. LoadString(g_hInstance, ids, pstr->cStr, ARRAYLEN(pstr->cStr));
  1172. #endif
  1173. return S_OK;
  1174. }
  1175. HRESULT
  1176. STRRETCopy(
  1177. LPTSTR pszString,
  1178. STRRET* pstr
  1179. )
  1180. {
  1181. #ifdef UNICODE
  1182. int cchOleStr = lstrlen(pszString)+1;
  1183. pstr->pOleStr = (LPOLESTR)SHAlloc(cchOleStr * sizeof(TCHAR));
  1184. if (NULL != pstr->pOleStr)
  1185. {
  1186. pstr->uType = STRRET_OLESTR;
  1187. StringCchCopy(pstr->pOleStr, cchOleStr, pszString);
  1188. }
  1189. else
  1190. {
  1191. pstr->uType = STRRET_CSTR;
  1192. pstr->cStr[0] = '\0';
  1193. return E_OUTOFMEMORY;
  1194. }
  1195. #else
  1196. pstr->uType = STRRET_CSTR;
  1197. int cch = lstrlen(pszString) + 1;
  1198. cch = min(cch, ARRAYLEN(pstr->cStr));
  1199. StringCchCopy(pstr->cStr, cch, pszString);
  1200. pszString[cch - 1] = '\0';
  1201. #endif
  1202. return S_OK;
  1203. }
  1204. VOID
  1205. FillSpecialID(
  1206. LPIDSHARE pids,
  1207. BYTE bFlags, // SHID_SHARE_*
  1208. UINT idsName
  1209. )
  1210. {
  1211. WCHAR szBuf[MAX_PATH];
  1212. szBuf[0] = L'\0';
  1213. LoadString(g_hInstance, idsName, szBuf, ARRAYLEN(szBuf));
  1214. LPWSTR pszName = szBuf;
  1215. USHORT nameLength = (USHORT)lstrlen(pszName);
  1216. USHORT nameOffset = 0;
  1217. pids->bFlags = bFlags;
  1218. pids->bReserved = 0;
  1219. pids->maxUses = 0xffffffff; // bogus
  1220. // we don't store nameOffset
  1221. pids->oComment = 0xffff; // bogus
  1222. pids->oPath = 0xffff; // bogus
  1223. StringCchCopy(&pids->cBuf[nameOffset], ARRAYSIZE(pids->cBuf) - nameOffset, pszName);
  1224. pids->cb = offsetof(IDSHARE, cBuf)
  1225. + (nameLength + 1) * sizeof(WCHAR);
  1226. //
  1227. // null terminate pidl
  1228. //
  1229. *(USHORT *)((LPBYTE)pids + pids->cb) = 0;
  1230. }
  1231. VOID
  1232. FillID1(
  1233. LPIDSHARE pids,
  1234. LPSHARE_INFO_1 pInfo
  1235. )
  1236. {
  1237. LPWSTR pszName = pInfo->shi1_netname;
  1238. LPWSTR pszComment = pInfo->shi1_remark;
  1239. USHORT nameLength, commentLength;
  1240. USHORT nameOffset, commentOffset;
  1241. nameLength = (USHORT)lstrlen(pszName);
  1242. commentLength = (USHORT)lstrlen(pszComment);
  1243. nameOffset = 0;
  1244. commentOffset = nameOffset + nameLength + 1;
  1245. pids->bFlags = SHID_SHARE_1;
  1246. pids->bReserved = 0;
  1247. pids->type = pInfo->shi1_type;
  1248. pids->maxUses = 0xffffffff; // bogus
  1249. // we don't store nameOffset
  1250. pids->oComment = commentOffset;
  1251. pids->oPath = 0xffff; // bogus
  1252. StringCchCopy(&pids->cBuf[nameOffset], ARRAYSIZE(pids->cBuf) - nameOffset, pszName);
  1253. StringCchCopy(&pids->cBuf[commentOffset], ARRAYSIZE(pids->cBuf) - commentOffset, pszComment);
  1254. pids->cb = offsetof(IDSHARE, cBuf)
  1255. + (nameLength + 1 + commentLength + 1) * sizeof(WCHAR);
  1256. //
  1257. // null terminate pidl
  1258. //
  1259. *(USHORT *)((LPBYTE)pids + pids->cb) = 0;
  1260. }
  1261. VOID
  1262. FillID2(
  1263. LPIDSHARE pids,
  1264. LPSHARE_INFO_2 pInfo
  1265. )
  1266. {
  1267. LPWSTR pszName = pInfo->shi2_netname;
  1268. LPWSTR pszComment = pInfo->shi2_remark;
  1269. LPWSTR pszPath = pInfo->shi2_path;
  1270. USHORT nameLength, commentLength, pathLength;
  1271. USHORT nameOffset, commentOffset, pathOffset;
  1272. nameLength = (USHORT)lstrlen(pszName);
  1273. commentLength = (USHORT)lstrlen(pszComment);
  1274. pathLength = (USHORT)lstrlen(pszPath);
  1275. nameOffset = 0;
  1276. commentOffset = nameOffset + nameLength + 1;
  1277. pathOffset = commentOffset + commentLength + 1;
  1278. pids->bFlags = SHID_SHARE_2;
  1279. pids->bReserved = 0;
  1280. pids->type = pInfo->shi2_type;
  1281. pids->maxUses = pInfo->shi2_max_uses;
  1282. // we don't store nameOffset
  1283. pids->oComment = commentOffset;
  1284. pids->oPath = pathOffset;
  1285. StringCchCopy(&pids->cBuf[nameOffset], ARRAYSIZE(pids->cBuf) - nameOffset, pszName);
  1286. StringCchCopy(&pids->cBuf[commentOffset], ARRAYSIZE(pids->cBuf) - commentOffset, pszComment);
  1287. StringCchCopy(&pids->cBuf[pathOffset], ARRAYSIZE(pids->cBuf) - pathOffset, pszPath);
  1288. pids->cb = offsetof(IDSHARE, cBuf)
  1289. + (nameLength + 1 + commentLength + 1 + pathLength + 1) * sizeof(WCHAR);
  1290. //
  1291. // null terminate pidl
  1292. //
  1293. *(USHORT *)((LPBYTE)pids + pids->cb) = 0;
  1294. }
  1295. VOID
  1296. StrNCopy(
  1297. OUT LPWSTR pszTarget,
  1298. IN LPCWSTR pszSource,
  1299. IN DWORD cchTarget
  1300. )
  1301. {
  1302. DWORD cch = lstrlen(pszSource) + 1;
  1303. cch = min(cch, cchTarget);
  1304. StringCchCopy(pszTarget, cch, pszSource);
  1305. pszTarget[cch - 1] = TEXT('\0');
  1306. }
  1307. //+---------------------------------------------------------------------------
  1308. //
  1309. // Function: TrimLeadingAndTrailingSpaces
  1310. //
  1311. // Synopsis: Trims the leading and trailing spaces from a null-terminated string.
  1312. // Used primarily for share names.
  1313. //
  1314. // History: 18-Jul-97 JonN Created
  1315. //
  1316. //----------------------------------------------------------------------------
  1317. VOID
  1318. TrimLeadingAndTrailingSpaces(
  1319. IN OUT PWSTR psz
  1320. )
  1321. {
  1322. int cchStrlen = ::wcslen(psz);
  1323. int cchLeadingSpaces = 0;
  1324. int cchTrailingSpaces = 0;
  1325. while (L' ' == psz[cchLeadingSpaces])
  1326. cchLeadingSpaces++;
  1327. if (cchLeadingSpaces < cchStrlen)
  1328. {
  1329. while (L' ' == psz[cchStrlen-(cchTrailingSpaces+1)])
  1330. cchTrailingSpaces++;
  1331. }
  1332. if ((cchLeadingSpaces+cchTrailingSpaces) > 0)
  1333. {
  1334. cchStrlen -= (cchLeadingSpaces+cchTrailingSpaces);
  1335. (void)memmove( psz,
  1336. psz+cchLeadingSpaces,
  1337. cchStrlen*sizeof(WCHAR) );
  1338. psz[cchStrlen] = L'\0';
  1339. }
  1340. }