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.

2754 lines
79 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. enum.cxx
  5. Abstract:
  6. Contains the entry points for the WinNet Enum API supported by the
  7. Multi-Provider Router. The following functions are in this file:
  8. WNetOpenEnumW
  9. WNetEnumResourceW
  10. WNetCloseEnum
  11. MprOpenEnumConnect
  12. MprOpenEnumNetwork
  13. MprEnumConnect
  14. MprEnumNetwork
  15. MprProviderEnum
  16. MprCopyResource
  17. MprCopyProviderEnum
  18. MprProviderOpen
  19. MprOpenRemember
  20. MprEnumRemembered
  21. MprMultiStrBuffSize
  22. Author:
  23. Dan Lafferty (danl) 14-Oct-1991
  24. Environment:
  25. User Mode -Win32
  26. Notes:
  27. Revision History:
  28. 14-Oct-1991 danl
  29. created
  30. 21-Sep-1992 KeithMo
  31. Handle odd-sized buffers.
  32. 02-Nov-1992 danl
  33. Fail with NO_NETWORK if there are no providers.
  34. 02-Mar-1995 anirudhs
  35. Add support for RESOURCE_CONTEXT.
  36. 17-Jul-1995 anirudhs
  37. Add recognition (but not true support) of RESOURCE_RECENT.
  38. Clean up code for detecting top-level enum.
  39. 03-Aug-1995 anirudhs
  40. WNetEnumResourceW: Allow a *lpcCount of 0.
  41. 15-Sep-1995 anirudhs
  42. MprEnumRemembered: Fail after all resources have been enumerated.
  43. 24-Sep-1995 anirudhs
  44. Add support for customization of the RESOURCE_CONTEXT enumeration
  45. based on policy settings.
  46. 11-Apr-1996 anirudhs
  47. Use CRoutedOperation in one case of WNetOpenEnumW.
  48. 16-Mar-1999 jschwart
  49. Add support for RESOURCE_SHAREABLE
  50. 05-May-1999 jschwart
  51. Make provider addition/removal dynamic
  52. --*/
  53. //
  54. // INCLUDES
  55. //
  56. #include "precomp.hxx"
  57. #include <memory.h> // memcpy
  58. #include <lmcons.h> // needed for netlib.h
  59. #include <tstring.h> // STRLEN
  60. #include <regstr.h> // Registry keys and value names
  61. //
  62. // EXTERNALS
  63. //
  64. extern DWORD GlobalNumActiveProviders;
  65. extern HMODULE hDLL;
  66. //
  67. // DATA STRUCTURES
  68. //
  69. //
  70. // "Manually" align headers and put pointers first in ENUM
  71. // structures to avoid Win64 alignment faults. Keep Key as
  72. // the first field in the header so MPR knows where to check
  73. // to see what type of enum it is.
  74. //
  75. typedef struct _CONNECT_HEADER
  76. {
  77. DWORD Key;
  78. DWORD ReturnRoot;
  79. DWORD dwNumProviders;
  80. DWORD dwNumActiveProviders;
  81. }
  82. CONNECT_HEADER, *LPCONNECT_HEADER;
  83. typedef struct _CONNECT_ENUM
  84. {
  85. HANDLE ProviderEnumHandle;
  86. HINSTANCE hProviderDll; // Refcount the provider DLL
  87. PF_NPEnumResource pfEnumResource;
  88. PF_NPCloseEnum pfCloseEnum;
  89. DWORD State;
  90. }
  91. CONNECT_ENUM, *LPCONNECT_ENUM;
  92. typedef struct _NETWORK_HEADER
  93. {
  94. DWORD Key;
  95. DWORD dwNumProviders;
  96. DWORD dwNumActiveProviders;
  97. DWORD dwPad;
  98. }
  99. NETWORK_HEADER, *LPNETWORK_HEADER;
  100. typedef struct _NETWORK_ENUM
  101. {
  102. HINSTANCE hProviderDll;
  103. LPNETRESOURCE lpnr;
  104. DWORD State;
  105. }
  106. NETWORK_ENUM, *LPNETWORK_ENUM;
  107. typedef struct _ENUM_HANDLE
  108. {
  109. DWORD Key;
  110. DWORD dwPad;
  111. HANDLE EnumHandle;
  112. HINSTANCE hProviderDll;
  113. PF_NPEnumResource pfEnumResource;
  114. PF_NPCloseEnum pfCloseEnum;
  115. }
  116. ENUM_HANDLE, *LPENUM_HANDLE;
  117. typedef struct _REMEMBER_HANDLE
  118. {
  119. DWORD Key;
  120. DWORD dwPad;
  121. HKEY ConnectKey;
  122. DWORD KeyIndex;
  123. DWORD ConnectionType;
  124. }
  125. REMEMBER_HANDLE, *LPREMEMBER_HANDLE;
  126. //
  127. // CONSTANTS
  128. //
  129. #define DONE 1
  130. #define MORE_ENTRIES 2
  131. #define NOT_OPENED 3
  132. #define CONNECT_TABLE_KEY 0x6e6e4f63 // "cOnn"
  133. #define STATE_TABLE_KEY 0x74417473 // "stAt"
  134. #define PROVIDER_ENUM_KEY 0x764f7270 // "prOv"
  135. #define REMEMBER_KEY 0x626D4572 // "rEmb"
  136. #define REGSTR_PATH_NETWORK_POLICIES \
  137. REGSTR_PATH_POLICIES L"\\" REGSTR_KEY_NETWORK
  138. //
  139. // Macros for rounding a value up/down to a WCHAR boundary.
  140. // Note: These macros assume that sizeof(WCHAR) is a power of 2.
  141. //
  142. #define ROUND_DOWN(x) ((x) & ~(sizeof(WCHAR) - 1))
  143. #define ROUND_UP(x) (((x) + sizeof(WCHAR) - 1) & ~(sizeof(WCHAR) - 1))
  144. //
  145. // LOCAL FUNCTION PROTOTYPES
  146. //
  147. DWORD
  148. MprCopyProviderEnum(
  149. IN LPNETRESOURCEW ProviderBuffer,
  150. IN OUT LPDWORD EntryCount,
  151. IN OUT LPBYTE *TempBufPtr,
  152. IN OUT LPDWORD BytesLeft
  153. );
  154. DWORD
  155. MprCopyResource(
  156. IN OUT LPBYTE *BufPtr,
  157. IN const NETRESOURCEW *Resource,
  158. IN OUT LPDWORD BytesLeft
  159. );
  160. DWORD
  161. MprEnumNetwork(
  162. IN OUT LPNETWORK_HEADER StateTable,
  163. IN OUT LPDWORD NumEntries,
  164. IN OUT LPVOID lpBuffer,
  165. IN OUT LPDWORD lpBufferSize
  166. );
  167. DWORD
  168. MprEnumConnect(
  169. IN OUT LPCONNECT_HEADER ConnectEnumHeader,
  170. IN OUT LPDWORD NumEntries,
  171. IN OUT LPVOID lpBuffer,
  172. IN OUT LPDWORD lpBufferSize
  173. );
  174. DWORD
  175. MprOpenEnumNetwork(
  176. OUT LPHANDLE lphEnum
  177. );
  178. DWORD
  179. MprOpenEnumConnect(
  180. IN DWORD dwScope,
  181. IN DWORD dwType,
  182. IN DWORD dwUsage,
  183. IN LPNETRESOURCE lpNetResource,
  184. OUT LPHANDLE lphEnum
  185. );
  186. DWORD
  187. MprProviderEnum(
  188. IN LPENUM_HANDLE EnumHandlePtr,
  189. IN OUT LPDWORD lpcCount,
  190. IN LPVOID lpBuffer,
  191. IN OUT LPDWORD lpBufferSize
  192. );
  193. DWORD
  194. MprOpenRemember(
  195. IN DWORD dwType,
  196. OUT LPHANDLE lphRemember
  197. );
  198. DWORD
  199. MprEnumRemembered(
  200. IN OUT LPREMEMBER_HANDLE RememberInfo,
  201. IN OUT LPDWORD NumEntries,
  202. IN OUT LPBYTE lpBuffer,
  203. IN OUT LPDWORD lpBufferSize
  204. );
  205. DWORD
  206. MprMultiStrBuffSize(
  207. IN LPTSTR lpString1,
  208. IN LPTSTR lpString2,
  209. IN LPTSTR lpString3,
  210. IN LPTSTR lpString4,
  211. IN LPTSTR lpString5
  212. ) ;
  213. class CProviderOpenEnum : public CRoutedOperation
  214. {
  215. public:
  216. CProviderOpenEnum(
  217. DWORD dwScope,
  218. DWORD dwType,
  219. DWORD dwUsage,
  220. LPNETRESOURCEW lpNetResource,
  221. LPHANDLE lphEnum
  222. ) :
  223. CRoutedOperation(DBGPARM("ProviderOpenEnum")
  224. PROVIDERFUNC(OpenEnum)),
  225. _dwScope (dwScope ),
  226. _dwType (dwType ),
  227. _dwUsage (dwUsage ),
  228. _lpNetResource(lpNetResource),
  229. _lphEnum (lphEnum )
  230. { }
  231. protected:
  232. DWORD GetResult(); // overrides CRoutedOperation implementation
  233. private:
  234. DWORD _dwScope;
  235. DWORD _dwType;
  236. DWORD _dwUsage;
  237. LPNETRESOURCEW _lpNetResource;
  238. LPHANDLE _lphEnum;
  239. HANDLE _ProviderEnumHandle; // Enum handle returned by provider
  240. DECLARE_CROUTED
  241. };
  242. DWORD
  243. WNetOpenEnumW (
  244. IN DWORD dwScope,
  245. IN DWORD dwType,
  246. IN DWORD dwUsage,
  247. IN LPNETRESOURCEW lpNetResource,
  248. OUT LPHANDLE lphEnum
  249. )
  250. /*++
  251. Routine Description:
  252. This API is used to open an enumeration of network resources or existing
  253. connections. It must be called to obtain a valid handle for enumeration.
  254. NOTE:
  255. For GlobalNet Enum, the caller must get a new handle for each level that
  256. is desired. For the other scopes, the caller gets a single handle and
  257. with that can enumerate all resources.
  258. Arguments:
  259. dwScope - Determines the scope of the enumeration. This can be one of:
  260. RESOURCE_CONNECTED - All Currently connected resources.
  261. RESOURCE_GLOBALNET - All resources on the network.
  262. RESOURCE_REMEMBERED - All persistent connections.
  263. RESOURCE_RECENT - Same as RESOURCE_REMEMBERED (supported for Win95
  264. semi-compatibility)
  265. RESOURCE_CONTEXT - The resources associated with the user's current
  266. and default network context (as defined by the providers).
  267. RESOURCE_SHAREABLE - All shareable resources on the given server
  268. dwType - Used to specify the type of resources on interest. This is a
  269. bitmask which may be any combination of:
  270. RESOURCETYPE_DISK - All disk resources
  271. RESOURCETYPE_PRINT - All print resources
  272. If this is 0. all types of resources are returned. If a provider does
  273. not have the capability to distinguish between print and disk
  274. resources at a level, it may return all resources.
  275. dwUsage - Used to specify the usage of resources of interest. This is a
  276. bitmask which may be any combination of:
  277. RESOURCEUSAGE_CONNECTABLE - all connectable resources.
  278. RESOURCEUSAGE_CONTAINER - all container resources.
  279. The bitmask may be 0 to match all.
  280. lpNetResource - This specifies the container to perform the enumeration.
  281. If it is NULL, the logical root of the network is assumed, and the
  282. router is responsible for obtaining the information for return.
  283. lphEnum - If the Open was successful, this will contain a handle that
  284. can be used for future calls to WNetEnumResource.
  285. Return Value:
  286. WN_SUCCESS - Indicates the operation was successful.
  287. WN_NOT_CONTAINER - Indicates that lpNetResource does not point to a
  288. container.
  289. WN_BAD_VALUE - Invalid dwScope or dwType, or bad combination of parameters
  290. is specified.
  291. WN_NO_NETWORK - network is not present.
  292. --*/
  293. {
  294. DWORD status = WN_SUCCESS;
  295. //
  296. // dwScope MUST be set to either GLOBALNET or CONNECTED or REMEMBERED
  297. // or RECENT or CONTEXT or SHAREABLE.
  298. // This is verified in the switch statement below.
  299. //
  300. //
  301. // dwType is a bit mask that can have any combination of the DISK
  302. // or PRINT bits set. Or it can be the value 0.
  303. //
  304. if (dwType & ~(RESOURCETYPE_DISK | RESOURCETYPE_PRINT)) {
  305. status = WN_BAD_VALUE;
  306. goto CleanExit;
  307. }
  308. //
  309. // dwUsage is a bit mask that can have any combination of the CONNECTABLE
  310. // or CONTAINER bits set. Or it can be the value 0. This field is
  311. // ignored if dwScope is not RESOURCE_GLOBALNET.
  312. //
  313. if (dwScope == RESOURCE_GLOBALNET) {
  314. if (dwUsage & ~(RESOURCEUSAGE_ALL)) {
  315. status = WN_BAD_VALUE;
  316. goto CleanExit;
  317. }
  318. }
  319. //
  320. // Make sure the user passed in a valid OUT parameter
  321. //
  322. __try
  323. {
  324. PROBE_FOR_WRITE((LPDWORD)lphEnum);
  325. }
  326. __except(EXCEPTION_EXECUTE_HANDLER)
  327. {
  328. status = WN_BAD_POINTER;
  329. }
  330. if (status != WN_SUCCESS)
  331. {
  332. goto CleanExit;
  333. }
  334. //
  335. // Check to see if it is a top-level enum request.
  336. //
  337. if (lpNetResource == NULL
  338. ||
  339. (IS_EMPTY_STRING(lpNetResource->lpProvider) &&
  340. IS_EMPTY_STRING(lpNetResource->lpRemoteName))
  341. ||
  342. dwScope == RESOURCE_SHAREABLE)
  343. {
  344. //
  345. // lpNetResource is NULL or represents no resource or this is
  346. // a request for shareable resources.
  347. // This is a top-level enum request, therefore, the MPR must provide
  348. // the information.
  349. //
  350. switch(dwScope) {
  351. case RESOURCE_CONNECTED:
  352. case RESOURCE_CONTEXT:
  353. case RESOURCE_SHAREABLE:
  354. {
  355. MprCheckProviders();
  356. CProviderSharedLock PLock;
  357. INIT_IF_NECESSARY(NETWORK_LEVEL,status);
  358. if (MprNetIsAvailable()) {
  359. status = MprOpenEnumConnect(dwScope,
  360. dwType,
  361. dwUsage,
  362. lpNetResource,
  363. lphEnum);
  364. }
  365. else
  366. status = WN_NO_NETWORK ;
  367. break;
  368. }
  369. case RESOURCE_GLOBALNET:
  370. {
  371. MprCheckProviders();
  372. CProviderSharedLock PLock;
  373. INIT_IF_NECESSARY(NETWORK_LEVEL,status);
  374. if (MprNetIsAvailable()) {
  375. status = MprOpenEnumNetwork(lphEnum);
  376. }
  377. else
  378. status = WN_NO_NETWORK ;
  379. break;
  380. }
  381. case RESOURCE_REMEMBERED:
  382. case RESOURCE_RECENT:
  383. MPR_LOG(TRACE,"OpenEnum RESOURCE_REMEMBERED\n",0);
  384. status = MprOpenRemember(dwType, lphEnum);
  385. break;
  386. default:
  387. status = WN_BAD_VALUE;
  388. break;
  389. }
  390. }
  391. else {
  392. //
  393. // Request is for one of the providers. It should be for a
  394. // GLOBALNET enumeration. It is not allowed to request any
  395. // other type of enumeration with a pointer to a resource
  396. // buffer.
  397. //
  398. if (dwScope != RESOURCE_GLOBALNET) {
  399. status = WN_BAD_VALUE;
  400. goto CleanExit;
  401. }
  402. CProviderOpenEnum ProviderOpenEnum(
  403. dwScope,
  404. dwType,
  405. dwUsage,
  406. lpNetResource,
  407. lphEnum);
  408. status = ProviderOpenEnum.Perform(TRUE);
  409. }
  410. CleanExit:
  411. if (status != WN_SUCCESS) {
  412. SetLastError(status);
  413. }
  414. return(status);
  415. }
  416. DWORD
  417. WNetEnumResourceW (
  418. IN HANDLE hEnum,
  419. IN OUT LPDWORD lpcCount,
  420. OUT LPVOID lpBuffer,
  421. IN OUT LPDWORD lpBufferSize
  422. )
  423. /*++
  424. Routine Description:
  425. This function is used to obtain an array of NETRESOURCE structures each
  426. of which describes a network resource.
  427. Arguments:
  428. hEnum - This is a handle that was obtained from an WNetOpenEnum call.
  429. lpcCount - Specifies the number of entries requested. -1 indicates
  430. as many entries as possible are requested. If the operation is
  431. successful, this location will receive the number of entries
  432. actually read.
  433. lpBuffer - A pointer to the buffer to receive the enumeration result,
  434. which are returned as an array of NETRESOURCE entries. The buffer
  435. is valid until the next call using hEnum.
  436. lpBufferSize - This specifies the size of the buffer passed to the function
  437. call. It will contain the required buffer size if WN_MORE_DATA is
  438. returned.
  439. Return Value:
  440. WN_SUCCESS - Indicates that the call is successful, and that the caller
  441. should continue to call WNetEnumResource to continue the enumeration.
  442. WN_NO_MORE_ENTRIES - Indicates that the enumeration completed successfully.
  443. The following return codes indicate an error occured and GetLastError
  444. may be used to obtain another copy of the error code:
  445. WN_MORE_DATA - Indicates that the buffer is too small for even one
  446. entry.
  447. WN_BAD_HANDLE - hEnum is not a valid handle.
  448. WN_NO_NETWORK - The Network is not present. This condition is checked
  449. for before hEnum is tested for validity.
  450. History:
  451. 12-Feb-1992 Johnl Removed requirement that buffersize must be at
  452. least as large as NETRESOURCEW (bug 5790)
  453. --*/
  454. {
  455. DWORD status = WN_SUCCESS;
  456. //
  457. // Screen the parameters as best we can.
  458. //
  459. //
  460. // Probe the handle
  461. //
  462. __try {
  463. *(volatile DWORD *)hEnum;
  464. }
  465. __except(EXCEPTION_EXECUTE_HANDLER) {
  466. status = GetExceptionCode();
  467. if (status != EXCEPTION_ACCESS_VIOLATION) {
  468. MPR_LOG(ERROR,"WNetEnumResource:Unexpected Exception 0x%lx\n",status);
  469. }
  470. status = WN_BAD_HANDLE;
  471. }
  472. __try {
  473. PROBE_FOR_WRITE(lpcCount);
  474. if (IS_BAD_BYTE_BUFFER(lpBuffer, lpBufferSize)) {
  475. status = WN_BAD_POINTER;
  476. }
  477. }
  478. __except (EXCEPTION_EXECUTE_HANDLER) {
  479. status = GetExceptionCode();
  480. if (status != EXCEPTION_ACCESS_VIOLATION) {
  481. MPR_LOG(ERROR,"WNetEnumResource:Unexpected Exception 0x%lx\n",status);
  482. }
  483. status = WN_BAD_POINTER;
  484. }
  485. if (status != WN_SUCCESS) {
  486. goto CleanExit;
  487. }
  488. switch(*(LPDWORD)hEnum){
  489. case CONNECT_TABLE_KEY:
  490. //
  491. // Call on Providers to enumerate connections.
  492. //
  493. status = MprEnumConnect(
  494. (LPCONNECT_HEADER)hEnum, // key is part of structure
  495. lpcCount,
  496. lpBuffer,
  497. lpBufferSize);
  498. break;
  499. case STATE_TABLE_KEY:
  500. //
  501. // Enumerate the top level NetResource structure maintained by
  502. // the router.
  503. //
  504. status = MprEnumNetwork(
  505. (LPNETWORK_HEADER)hEnum,
  506. lpcCount,
  507. lpBuffer,
  508. lpBufferSize);
  509. break;
  510. case PROVIDER_ENUM_KEY:
  511. //
  512. // Call on providers to enumerate resources on the network.
  513. //
  514. status = MprProviderEnum(
  515. (LPENUM_HANDLE)hEnum, // key is part of structure
  516. lpcCount,
  517. lpBuffer,
  518. lpBufferSize);
  519. break;
  520. case REMEMBER_KEY:
  521. //
  522. // Enumerate the connections in the current user section of the
  523. // registry.
  524. //
  525. status = MprEnumRemembered(
  526. (LPREMEMBER_HANDLE)hEnum,
  527. lpcCount,
  528. (LPBYTE)lpBuffer,
  529. lpBufferSize);
  530. break;
  531. default:
  532. status = WN_BAD_HANDLE;
  533. }
  534. CleanExit:
  535. if(status != WN_SUCCESS) {
  536. SetLastError(status);
  537. }
  538. return(status);
  539. }
  540. DWORD
  541. WNetCloseEnum (
  542. IN HANDLE hEnum
  543. )
  544. /*++
  545. Routine Description:
  546. Closes an enumeration handle that is owned by the router.
  547. In cases where the router is acting as a proxy for a single provider,
  548. an attempt is made to return any error information from this provider
  549. back to the user. This makes the router as transparent as possible.
  550. Arguments:
  551. hEnum - This must be a handle obtained from a call to WNetOpenEnum.
  552. Return Value:
  553. WN_SUCCESS - The operation was successful.
  554. WN_NO_NETWORK - The Network is not present. This condition is checked
  555. before hEnum is tested for validity.
  556. WN_BAD_HANDLE - hEnum is not a valid handle.
  557. --*/
  558. {
  559. DWORD status = WN_SUCCESS;
  560. DWORD i;
  561. //
  562. // Probe the handle
  563. //
  564. __try {
  565. *(volatile DWORD *)hEnum;
  566. }
  567. __except(EXCEPTION_EXECUTE_HANDLER) {
  568. status = GetExceptionCode();
  569. if (status != EXCEPTION_ACCESS_VIOLATION) {
  570. MPR_LOG(ERROR,"WNetCloseEnum:Unexpected Exception 0x%lx\n",status);
  571. }
  572. status = WN_BAD_HANDLE;
  573. }
  574. if (status != WN_SUCCESS) {
  575. SetLastError(WN_BAD_HANDLE);
  576. return(status);
  577. }
  578. //
  579. // Use hEnum as a pointer and check the DWORD value at its location.
  580. // If it contains a CONNECT_TABLE_KEY, we must close all handles to
  581. // the providers before freeing the memory for the table.
  582. // If it is a STATE_TABLE_KEY, we just free the memory.
  583. //
  584. switch(*(LPDWORD)hEnum){
  585. case CONNECT_TABLE_KEY:
  586. {
  587. LPCONNECT_HEADER connectEnumHeader;
  588. LPCONNECT_ENUM connectEnumTable;
  589. connectEnumHeader = (LPCONNECT_HEADER)hEnum;
  590. connectEnumTable = (LPCONNECT_ENUM)(connectEnumHeader + 1);
  591. //
  592. // Close all the open provider handles
  593. //
  594. MPR_LOG(TRACE,"Closing Connection Enum Handles from Providers\n",0);
  595. for(i = 0; i < connectEnumHeader->dwNumProviders; i++) {
  596. if((connectEnumTable[i].State != NOT_OPENED) &&
  597. (connectEnumTable[i].pfCloseEnum != NULL))
  598. {
  599. status = connectEnumTable[i].pfCloseEnum(
  600. connectEnumTable[i].ProviderEnumHandle);
  601. if(status != WN_SUCCESS) {
  602. //
  603. // Because we are closing many handles at once, the failure
  604. // is noted for debug purposes only.
  605. //
  606. MPR_LOG(ERROR,"WNetCloseEnum:(connect-provider #%d) failed\n",i);
  607. MPR_LOG(ERROR,"WNetCloseEnum: error code = %d\n",status);
  608. //
  609. // Error information is returned if there is only one
  610. // provider.
  611. //
  612. if (connectEnumHeader->dwNumProviders != 1) {
  613. status = WN_SUCCESS;
  614. }
  615. }
  616. //
  617. // If this fires, the logic in MprOpenEnumConnect is wrong
  618. //
  619. ASSERT(connectEnumTable[i].hProviderDll != NULL);
  620. FreeLibrary(connectEnumTable[i].hProviderDll);
  621. }
  622. else
  623. {
  624. //
  625. // If this fires, the logic in MprOpenEnumConnect is wrong
  626. // and we're not releasing a refcounted provider DLL
  627. //
  628. ASSERT(connectEnumTable[i].hProviderDll == NULL);
  629. }
  630. }
  631. //
  632. // Free the Table Memory
  633. //
  634. if (LocalFree(hEnum)) {
  635. MPR_LOG(ERROR,"WNetCloseEnum:LocalFree(connect) failed %d\n",
  636. GetLastError());
  637. }
  638. if (status != WN_SUCCESS)
  639. {
  640. SetLastError(status);
  641. }
  642. return(status);
  643. }
  644. case STATE_TABLE_KEY:
  645. {
  646. LPNETWORK_HEADER StateTableHeader;
  647. LPNETWORK_ENUM StateTable;
  648. //
  649. // Free the State Table Memory.
  650. //
  651. MPR_LOG(TRACE,"Free State Table for Network Enum\n",0);
  652. StateTableHeader = (LPNETWORK_HEADER)hEnum;
  653. StateTable = (LPNETWORK_ENUM)(StateTableHeader + 1);
  654. for (i = 0; i < StateTableHeader->dwNumProviders; i++)
  655. {
  656. if (StateTable[i].hProviderDll != NULL)
  657. {
  658. FreeLibrary(StateTable[i].hProviderDll);
  659. LocalFree(StateTable[i].lpnr);
  660. }
  661. else
  662. {
  663. //
  664. // If this fires, MprOpenEnumNetwork is causing a mem leak
  665. //
  666. ASSERT(StateTable[i].lpnr == NULL);
  667. }
  668. }
  669. if (LocalFree(hEnum)) {
  670. MPR_LOG(ERROR,"WNetCloseEnum:LocalFree(network) failed %d\n",
  671. GetLastError());
  672. }
  673. return(WN_SUCCESS);
  674. }
  675. case PROVIDER_ENUM_KEY:
  676. {
  677. LPENUM_HANDLE enumHandle;
  678. //
  679. // Close the providers enumeration handle, and free the
  680. // ENUM_HANDLE structure.
  681. //
  682. MPR_LOG(TRACE,"Closing Provider Enum Handle\n",0);
  683. enumHandle = (LPENUM_HANDLE)hEnum;
  684. ASSERT(enumHandle->pfCloseEnum != NULL);
  685. status = (enumHandle->pfCloseEnum)(enumHandle->EnumHandle);
  686. ASSERT(enumHandle->hProviderDll != NULL);
  687. FreeLibrary(enumHandle->hProviderDll);
  688. if (LocalFree(enumHandle) != 0) {
  689. MPR_LOG(ERROR,"WNetCloseEnum:LocalFree(provider) failed %d\n",
  690. GetLastError());
  691. }
  692. //
  693. // Check the status returned from the Provider's CloseEnum
  694. //
  695. if(status != WN_SUCCESS) {
  696. MPR_LOG(ERROR,"WNetCloseEnum:(provider) failed %d\n",status);
  697. SetLastError(status);
  698. }
  699. return(status);
  700. }
  701. case REMEMBER_KEY:
  702. {
  703. LPREMEMBER_HANDLE rememberHandle;
  704. rememberHandle = (LPREMEMBER_HANDLE)hEnum;
  705. //
  706. // Close the RegistryKey Handle associated with this handle.
  707. //
  708. if (rememberHandle->ConnectKey != NULL) {
  709. RegCloseKey(rememberHandle->ConnectKey);
  710. }
  711. //
  712. // Free up the memory for the handle.
  713. //
  714. if (LocalFree(rememberHandle) != 0) {
  715. MPR_LOG(ERROR,"WNetCloseEnum:LocalFree(remember) failed %d\n",
  716. GetLastError());
  717. }
  718. return(WN_SUCCESS);
  719. }
  720. default:
  721. SetLastError(WN_BAD_HANDLE);
  722. return(WN_BAD_HANDLE);
  723. }
  724. }
  725. DWORD
  726. MprOpenEnumConnect(
  727. IN DWORD dwScope,
  728. IN DWORD dwType,
  729. IN DWORD dwUsage,
  730. IN LPNETRESOURCE lpNetResource,
  731. OUT LPHANDLE lphEnum
  732. )
  733. /*++
  734. Routine Description:
  735. This function handles the opening of connection enumerations and context
  736. enumerations. It does this by sending an OpenEnum to all Providers, and
  737. storing the returned handles in a table. The handle that is returned is
  738. a pointer to this table.
  739. The first DWORD in the table is a key that will help to identify a
  740. correct table. The second DWORD is a Boolean value that tells whether
  741. a NETRESOURCE structure representing the root of the network needs to be
  742. returned in the enumeration.
  743. Arguments:
  744. dwScope - RESOURCE_CONNECTED, RESOURCE_CONTEXT, or RESOURCE_SHAREABLE
  745. dwType -
  746. dwUsage -
  747. lpNetResource -
  748. lphEnum - This is a pointer to a location where the handle for
  749. the connection enumeration is to be stored.
  750. Return Value:
  751. WN_SUCCESS - The operation was successful.
  752. WN_OUT_OF_MEMORY - The memory allocation for the handle was unsuccessful.
  753. --*/
  754. {
  755. DWORD i;
  756. DWORD status;
  757. LPCONNECT_HEADER connectEnumHeader;
  758. LPCONNECT_ENUM connectEnumTable;
  759. LPPROVIDER provider;
  760. BOOL fcnSupported = FALSE; // Is fcn supported by a provider?
  761. BOOL atLeastOne=FALSE;
  762. BOOL bDynamicEntries = TRUE; // Whether to show dynamic entries
  763. // in the net neighborhood
  764. HKEY hkPolicies = NULL;
  765. ASSERT(dwScope == RESOURCE_CONNECTED
  766. ||
  767. dwScope == RESOURCE_CONTEXT
  768. ||
  769. dwScope == RESOURCE_SHAREABLE);
  770. ASSERT_INITIALIZED(NETWORK);
  771. //
  772. // If there are no providers, return NO_NETWORK
  773. //
  774. if (GlobalNumActiveProviders == 0) {
  775. return(WN_NO_NETWORK);
  776. }
  777. //
  778. // Allocate the handle table with enough room for a header.
  779. //
  780. connectEnumHeader = (LPCONNECT_HEADER) LocalAlloc(
  781. LPTR,
  782. sizeof(CONNECT_HEADER) +
  783. sizeof(CONNECT_ENUM) * GlobalNumProviders
  784. );
  785. if (connectEnumHeader == NULL) {
  786. MPR_LOG(ERROR,"MprOpenEnumConnect:LocalAlloc Failed %d\n",GetLastError());
  787. return(WN_OUT_OF_MEMORY);
  788. }
  789. //
  790. // Initialize the key used in the connect table.
  791. //
  792. connectEnumHeader->Key = CONNECT_TABLE_KEY;
  793. connectEnumHeader->ReturnRoot = FALSE;
  794. connectEnumHeader->dwNumProviders = GlobalNumProviders;
  795. connectEnumHeader->dwNumActiveProviders = GlobalNumActiveProviders;
  796. connectEnumTable = (LPCONNECT_ENUM)(connectEnumHeader + 1);
  797. //
  798. // Check the policy on whether dynamic entries are to be shown in the
  799. // network neighborhood. By default, they are shown.
  800. //
  801. if (dwScope == RESOURCE_CONTEXT)
  802. {
  803. if (MprOpenKey(
  804. HKEY_CURRENT_USER,
  805. REGSTR_PATH_NETWORK_POLICIES,
  806. &hkPolicies,
  807. KEY_READ))
  808. {
  809. bDynamicEntries = ! (MprGetKeyNumberValue(
  810. hkPolicies,
  811. REGSTR_VAL_NOWORKGROUPCONTENTS,
  812. FALSE));
  813. }
  814. else
  815. {
  816. hkPolicies = NULL;
  817. }
  818. }
  819. //
  820. // Initialize all state flags for providers to the NOT_OPENED state, so
  821. // we won't try to enumerate or close their handles unless we actually
  822. // got handles from them.
  823. // Initialize handles for the network providers by calling them with
  824. // OpenEnum.
  825. //
  826. for(i=0; i<GlobalNumProviders; i++) {
  827. connectEnumTable[i].State = NOT_OPENED;
  828. provider = GlobalProviderInfo + i;
  829. if ((provider->InitClass & NETWORK_TYPE) &&
  830. (provider->OpenEnum != NULL)) {
  831. if (dwScope == RESOURCE_CONTEXT)
  832. {
  833. DWORD dwCaps = provider->GetCaps(WNNC_ENUMERATION);
  834. if (dwCaps & WNNC_ENUM_GLOBAL)
  835. {
  836. // A browsing network is present, so show root,
  837. // even if network is down, and even if ENUM_CONTEXT
  838. // isn't supported.
  839. connectEnumHeader->ReturnRoot = TRUE;
  840. }
  841. if ((dwCaps & WNNC_ENUM_CONTEXT) == 0)
  842. {
  843. // This provider can't show hood entries, so skip it.
  844. continue;
  845. }
  846. }
  847. else if (dwScope == RESOURCE_SHAREABLE)
  848. {
  849. DWORD dwCaps = provider->GetCaps(WNNC_ENUMERATION);
  850. if ((dwCaps & WNNC_ENUM_SHAREABLE) == 0)
  851. {
  852. // This provider can't show shareable resources, so skip it.
  853. continue;
  854. }
  855. }
  856. fcnSupported = TRUE;
  857. if (bDynamicEntries)
  858. {
  859. //
  860. // Refcount the provider
  861. //
  862. connectEnumTable[i].hProviderDll = LoadLibraryEx(provider->DllName,
  863. NULL,
  864. LOAD_WITH_ALTERED_SEARCH_PATH);
  865. if (connectEnumTable[i].hProviderDll == NULL)
  866. {
  867. status = GetLastError();
  868. //
  869. // This can happen under extreme low memory conditions. The
  870. // loader can sometimes return ERROR_MOD_NOT_FOUND in this case.
  871. //
  872. MPR_LOG2(ERROR,
  873. "MprOpenEnumConnect: LoadLibraryEx on %ws FAILED %d\n",
  874. provider->DllName,
  875. status);
  876. ASSERT(status == ERROR_NOT_ENOUGH_MEMORY || status == ERROR_MOD_NOT_FOUND);
  877. continue;
  878. }
  879. connectEnumTable[i].pfEnumResource = provider->EnumResource;
  880. connectEnumTable[i].pfCloseEnum = provider->CloseEnum;
  881. status = provider->OpenEnum(
  882. dwScope, // Scope
  883. dwType, // Type
  884. dwUsage, // Usage
  885. (dwScope == RESOURCE_SHAREABLE ? lpNetResource : NULL), // NetResource
  886. &(connectEnumTable[i].ProviderEnumHandle)); // hEnum
  887. if (status != WN_SUCCESS) {
  888. MPR_LOG(ERROR,"MprOpenEnumConnect:OpenEnum Failed %d\n",status);
  889. MPR_LOG(ERROR,
  890. "That was for the %ws Provider\n",
  891. provider->Resource.lpProvider);
  892. FreeLibrary(connectEnumTable[i].hProviderDll);
  893. connectEnumTable[i].hProviderDll = NULL;
  894. connectEnumTable[i].pfEnumResource = NULL;
  895. connectEnumTable[i].pfCloseEnum = NULL;
  896. }
  897. else {
  898. //
  899. // At least one provider has returned a handle.
  900. //
  901. atLeastOne = TRUE;
  902. //
  903. // Set the state to MORE_ENTRIES, so we later enumerate from the
  904. // handle and/or close it.
  905. //
  906. connectEnumTable[i].State = MORE_ENTRIES;
  907. MPR_LOG(TRACE,"MprOpenEnumConnect: OpenEnum Handle = 0x%lx\n",
  908. connectEnumTable[i].ProviderEnumHandle);
  909. }
  910. }
  911. else
  912. {
  913. // Succeed the WNetOpenEnum but leave this provider as NOT_OPENED
  914. atLeastOne = TRUE;
  915. }
  916. }
  917. }
  918. if (connectEnumHeader->ReturnRoot)
  919. {
  920. // Able to show the root object. Check the policy on whether
  921. // to show it.
  922. connectEnumHeader->ReturnRoot = ! (MprGetKeyNumberValue(
  923. hkPolicies,
  924. REGSTR_VAL_NOENTIRENETWORK,
  925. FALSE));
  926. fcnSupported = TRUE;
  927. atLeastOne = TRUE;
  928. }
  929. if (hkPolicies)
  930. {
  931. RegCloseKey(hkPolicies);
  932. }
  933. if (fcnSupported == FALSE) {
  934. //
  935. // No providers in the list support the API function. Therefore,
  936. // we assume that no networks are installed.
  937. // Note that in this case, atLeastOne will always be FALSE.
  938. //
  939. status = WN_NOT_SUPPORTED;
  940. }
  941. //
  942. // return the handle (pointer to connectEnumTable);
  943. //
  944. *lphEnum = connectEnumHeader;
  945. if (atLeastOne == FALSE) {
  946. //
  947. // If none of the providers returned a handle, then return the
  948. // status from the last provider.
  949. //
  950. *lphEnum = NULL;
  951. LocalFree( connectEnumHeader);
  952. return(status);
  953. }
  954. return(WN_SUCCESS);
  955. }
  956. DWORD
  957. MprOpenEnumNetwork(
  958. OUT LPHANDLE lphEnum
  959. )
  960. /*++
  961. Routine Description:
  962. This function handles the opening of net resource enumerations.
  963. It does this by allocating a table of Provider State Flags and returning
  964. a handle to that table. The state flags (or for each provider) will
  965. be set to MORE_ENTRIES. Later, when enumerations take place, the state
  966. for each provider is changed to DONE after the buffer is successfully
  967. loaded with the the NETRESOURCE info for that provider.
  968. Arguments:
  969. lphEnum - This is a pointer to a location where the handle for
  970. the network resource enumeration is to be stored.
  971. Return Value:
  972. WN_SUCCESS - The operation was successful.
  973. WN_OUT_OF_MEMORY - The memory allocation for the handle was unsuccessful.
  974. --*/
  975. {
  976. LPNETWORK_ENUM stateTable;
  977. LPNETWORK_HEADER stateTableHeader;
  978. DWORD i;
  979. ASSERT_INITIALIZED(NETWORK);
  980. //
  981. // If there are no providers, return NO_NETWORK
  982. //
  983. if (GlobalNumActiveProviders == 0) {
  984. return(WN_NO_NETWORK);
  985. }
  986. //
  987. // Allocate the state table.
  988. //
  989. stateTableHeader = (LPNETWORK_HEADER) LocalAlloc(
  990. LPTR,
  991. sizeof(NETWORK_HEADER) +
  992. sizeof(NETWORK_ENUM) * GlobalNumProviders
  993. );
  994. if (stateTableHeader == NULL) {
  995. MPR_LOG(ERROR,"MprOpenEnumNetwork:LocalAlloc Failed %d\n",GetLastError());
  996. return(WN_OUT_OF_MEMORY);
  997. }
  998. stateTableHeader->Key = STATE_TABLE_KEY;
  999. stateTableHeader->dwNumProviders = GlobalNumProviders;
  1000. stateTableHeader->dwNumActiveProviders = GlobalNumActiveProviders;
  1001. stateTable = (LPNETWORK_ENUM)(stateTableHeader + 1);
  1002. //
  1003. // Initialize state flags for all network providers to the MORE_ENTRIES state.
  1004. //
  1005. for(i = 0; i < GlobalNumProviders; i++) {
  1006. if (GlobalProviderInfo[i].InitClass & NETWORK_TYPE)
  1007. {
  1008. if (GlobalProviderInfo[i].Handle != NULL)
  1009. {
  1010. stateTable[i].hProviderDll = LoadLibraryEx(GlobalProviderInfo[i].DllName,
  1011. NULL,
  1012. LOAD_WITH_ALTERED_SEARCH_PATH);
  1013. if (stateTable[i].hProviderDll == NULL)
  1014. {
  1015. DWORD status = GetLastError();
  1016. //
  1017. // This can happen under extreme low memory conditions. The
  1018. // loader can sometimes return ERROR_MOD_NOT_FOUND in this case.
  1019. //
  1020. MPR_LOG1(ERROR,
  1021. "MprOpenEnumNetwork: LoadLibraryEx on %ws FAILED\n",
  1022. GlobalProviderInfo[i].DllName);
  1023. ASSERT(status == ERROR_NOT_ENOUGH_MEMORY || status == ERROR_MOD_NOT_FOUND);
  1024. }
  1025. else
  1026. {
  1027. LPBYTE lpTempBuffer;
  1028. DWORD dwSize = 0;
  1029. DWORD dwStatus;
  1030. //
  1031. // Figure out how much space we'll need for the NETRESOURCE.
  1032. // It needs to be copied since the provider (and its resource)
  1033. // may go away between now and the WNetEnumResource call.
  1034. //
  1035. dwStatus = MprCopyResource(NULL,
  1036. &GlobalProviderInfo[i].Resource,
  1037. &dwSize);
  1038. ASSERT(dwStatus == WN_MORE_DATA);
  1039. stateTable[i].lpnr = (LPNETRESOURCE)LocalAlloc(LPTR, dwSize);
  1040. if (stateTable[i].lpnr == NULL)
  1041. {
  1042. MPR_LOG0(ERROR, "MprOpenEnumNetwork: LocalAlloc FAILED\n");
  1043. //
  1044. // Rather than fail silently in this case, bail out
  1045. //
  1046. for (UINT j = 0; j <= i; j++)
  1047. {
  1048. if (stateTable[j].hProviderDll)
  1049. {
  1050. FreeLibrary(stateTable[j].hProviderDll);
  1051. stateTable[j].hProviderDll = NULL;
  1052. stateTable[j].State = MORE_ENTRIES;
  1053. }
  1054. LocalFree(stateTable[j].lpnr);
  1055. }
  1056. LocalFree(stateTableHeader);
  1057. return(WN_OUT_OF_MEMORY);
  1058. }
  1059. else
  1060. {
  1061. lpTempBuffer = (LPBYTE)stateTable[i].lpnr;
  1062. dwStatus = MprCopyResource(&lpTempBuffer,
  1063. &GlobalProviderInfo[i].Resource,
  1064. &dwSize);
  1065. ASSERT(dwStatus == WN_SUCCESS);
  1066. }
  1067. }
  1068. }
  1069. stateTable[i].State = MORE_ENTRIES;
  1070. }
  1071. else {
  1072. stateTable[i].State = DONE;
  1073. }
  1074. }
  1075. //
  1076. // return the handle (pointer to stateTable);
  1077. //
  1078. *lphEnum = stateTableHeader;
  1079. return(WN_SUCCESS);
  1080. }
  1081. DWORD
  1082. MprEnumConnect(
  1083. IN OUT LPCONNECT_HEADER ConnectEnumHeader,
  1084. IN OUT LPDWORD NumEntries,
  1085. IN OUT LPVOID lpBuffer,
  1086. IN OUT LPDWORD lpBufferSize
  1087. )
  1088. /*++
  1089. Routine Description:
  1090. This function looks in the ConnectEnumTable for the next provider that
  1091. has MORE_ENTRIES. It begins requesting Enum Data from that provider -
  1092. each time copying data that is returned from the provider enum into the
  1093. users enum buffer (lpBuffer). This continues until we finish, or
  1094. we reach the requested number of elements, or the user buffer is full.
  1095. Each time we enumerate a provider to completion, that provider is
  1096. marked as DONE.
  1097. Note, for a context enumeration, the first NETRESOURCE returned in the
  1098. enumeration is a constant NETRESOURCE representing the root of the
  1099. network. This is done to make it easy for the shell to display a
  1100. "Rest of Network" object in a "Network Neighborhood" view.
  1101. Arguments:
  1102. ConnectEnumHeader - This is a pointer to a CONNECT_HEADER structure
  1103. followed by an array of CONNECT_ENUM structures. The ReturnRoot
  1104. member of the header tells whether the root object needs to be
  1105. returned at the start of the enumeration. On exit, if the root
  1106. object has been returned, the ReturnRoot member is set to FALSE.
  1107. NumEntries - On entry this points to the maximum number of entries
  1108. that the user desires to receive. On exit it points to the
  1109. number of entries that were placed in the users buffer.
  1110. lpBuffer - This is a pointer to the users buffer in which the
  1111. enumeration data is to be placed.
  1112. lpBufferSize - This is the size (in bytes) of the users buffer. It will
  1113. be set to the size of the required buffer size of WN_MORE_DATA is
  1114. returned.
  1115. Return Value:
  1116. WN_SUCCESS - This indicates that the call is returning some entries.
  1117. However, the enumeration is not complete due to one of the following:
  1118. 1) There was not enough buffer space.
  1119. 2) The requested number of entries was reached.
  1120. 3) There is no more data to enumerate - the next call will
  1121. return WN_NO_MORE_ENTRIES.
  1122. WN_MORE_DATA - This indicates that the buffer was not large enough
  1123. to receive one enumeration entry.
  1124. WN_NO_MORE_ENTRIES - This indicates that there are no more entries
  1125. to enumerate. No data is returned with this return code.
  1126. WN_NO_NETWORK - If there are no providers loaded.
  1127. Note:
  1128. --*/
  1129. {
  1130. DWORD i; // provider index
  1131. DWORD status=WN_NO_MORE_ENTRIES;
  1132. DWORD entriesRead=0; // number of entries read into the buffer.
  1133. LPBYTE tempBufPtr; // pointer to top of remaining free buffer space.
  1134. LPNETRESOURCEW providerBuffer; // buffer for data returned from provider
  1135. DWORD bytesLeft; // Numer of bytes left in the buffer
  1136. DWORD entryCount; // number of entries read from provider
  1137. LPCONNECT_ENUM ConnectEnumTable = (LPCONNECT_ENUM) (ConnectEnumHeader + 1);
  1138. // Start of array
  1139. //
  1140. // If there are no providers, return NO_NETWORK
  1141. //
  1142. if (ConnectEnumHeader->dwNumActiveProviders == 0) {
  1143. return(WN_NO_NETWORK);
  1144. }
  1145. bytesLeft = ROUND_DOWN(*lpBufferSize);
  1146. tempBufPtr = (LPBYTE) lpBuffer;
  1147. //
  1148. // Check to see if there are any flags in state table that indicate
  1149. // MORE_ENTRIES. If not, we want to return WN_NO_MORE_ENTRIES.
  1150. //
  1151. for(i = 0; i < ConnectEnumHeader->dwNumProviders; i++) {
  1152. if(ConnectEnumTable[i].State == MORE_ENTRIES) {
  1153. break;
  1154. }
  1155. }
  1156. if ( (i == ConnectEnumHeader->dwNumProviders) && (! ConnectEnumHeader->ReturnRoot) ) {
  1157. *NumEntries = 0;
  1158. return(WN_NO_MORE_ENTRIES);
  1159. }
  1160. //
  1161. // If no entries are requested, we have nothing to do
  1162. //
  1163. if (*NumEntries == 0) {
  1164. return WN_SUCCESS;
  1165. }
  1166. //
  1167. // Allocate a buffer for the provider to return data in.
  1168. // The buffer size must equal the number of bytes left in the
  1169. // user buffer.
  1170. // (We can't have the provider write data directly to the caller's
  1171. // buffer because NPEnumResource is not required to place strings
  1172. // at the end of the buffer -- only at the end of the array of
  1173. // NETRESOURCEs.)
  1174. //
  1175. providerBuffer = (LPNETRESOURCEW) LocalAlloc(LPTR, bytesLeft);
  1176. if (providerBuffer == NULL) {
  1177. MPR_LOG(ERROR,"MprEnumConnect:LocalAlloc Failed %d\n",
  1178. GetLastError());
  1179. *NumEntries = 0;
  1180. return(WN_OUT_OF_MEMORY);
  1181. }
  1182. //
  1183. // Copy the root-of-network resource if required.
  1184. //
  1185. if (ConnectEnumHeader->ReturnRoot)
  1186. {
  1187. NETRESOURCEW RootResource = {
  1188. RESOURCE_GLOBALNET, // dwScope
  1189. RESOURCETYPE_ANY, // dwType
  1190. RESOURCEDISPLAYTYPE_ROOT, // dwDisplayType
  1191. RESOURCEUSAGE_CONTAINER, // dwUsage
  1192. NULL, // lpLocalName
  1193. NULL, // lpRemoteName
  1194. g_wszEntireNetwork, // lpComment
  1195. NULL // lpProvider
  1196. };
  1197. status = MprCopyResource(&tempBufPtr, &RootResource, &bytesLeft);
  1198. if (status == WN_SUCCESS)
  1199. {
  1200. entriesRead = 1;
  1201. ConnectEnumHeader->ReturnRoot = FALSE;
  1202. }
  1203. else
  1204. {
  1205. if (status == WN_MORE_DATA)
  1206. {
  1207. //
  1208. // Not even enough room for one NETRESOURCE
  1209. //
  1210. *lpBufferSize = bytesLeft;
  1211. }
  1212. goto CleanExit;
  1213. }
  1214. }
  1215. //
  1216. // Loop until we have copied from all Providers or until the
  1217. // the maximum number of entries has been reached.
  1218. //
  1219. for ( ; i < ConnectEnumHeader->dwNumProviders && entriesRead < *NumEntries; i++)
  1220. {
  1221. if (ConnectEnumTable[i].State != MORE_ENTRIES)
  1222. {
  1223. //
  1224. // Skip providers that don't have more entries
  1225. //
  1226. continue;
  1227. }
  1228. if (ConnectEnumTable[i].hProviderDll == NULL) {
  1229. //
  1230. // If the provider has not been initialized because it is
  1231. // not "ACTIVE", then skip it.
  1232. //
  1233. ConnectEnumTable[i].State = DONE;
  1234. status = WN_SUCCESS;
  1235. continue;
  1236. }
  1237. //
  1238. // Adjust the entry count for any entries that have been read
  1239. // so far.
  1240. //
  1241. entryCount = *NumEntries - entriesRead;
  1242. //
  1243. // Call the provider to get the enumerated data
  1244. //
  1245. status = ConnectEnumTable[i].pfEnumResource(
  1246. ConnectEnumTable[i].ProviderEnumHandle,
  1247. &entryCount,
  1248. providerBuffer,
  1249. &bytesLeft ); // (note, the provider updates
  1250. // bytesLeft only if it returns
  1251. // WN_MORE_DATA)
  1252. switch (status)
  1253. {
  1254. case WN_SUCCESS:
  1255. MPR_LOG(TRACE,"EnumResourceHandle = 0x%lx\n",
  1256. ConnectEnumTable[i].ProviderEnumHandle);
  1257. status = MprCopyProviderEnum(
  1258. providerBuffer,
  1259. &entryCount,
  1260. &tempBufPtr,
  1261. &bytesLeft);
  1262. entriesRead += entryCount;
  1263. if (status != WN_SUCCESS) {
  1264. //
  1265. // An internal error occured - for some reason the
  1266. // buffer space left in the user buffer was smaller
  1267. // than the buffer space that the provider filled in.
  1268. // The best we can do in this case is return what data
  1269. // we have. WARNING: the data that didn't make it
  1270. // will become lost since the provider thinks it
  1271. // enumerated successfully, but we couldn't do anything
  1272. // with it.
  1273. //
  1274. MPR_LOG(ERROR,
  1275. "MprEnumConnect:MprCopyProviderEnum Internal Error %d\n",
  1276. status);
  1277. if(entriesRead > 0) {
  1278. status = WN_SUCCESS;
  1279. }
  1280. goto CleanExit;
  1281. }
  1282. //
  1283. // We successfully placed all the received data from
  1284. // that provider into the user buffer. In this case,
  1285. // if we haven't reached the requested number of entries,
  1286. // we want to loop around and ask the same provider
  1287. // to enumerate more. This time the provider should
  1288. // indicate why it quit last time - either there are
  1289. // no more entries, or we ran out of buffer space.
  1290. //
  1291. break;
  1292. case WN_NO_MORE_ENTRIES:
  1293. //
  1294. // This Provider has completed its enumeration, mark it
  1295. // as done and increment to the next provider. We don't
  1296. // want to return NO_MORE_ENTRIES status. That should
  1297. // only be returned by the check at beginning or end
  1298. // of this function.
  1299. //
  1300. ConnectEnumTable[i].State = DONE;
  1301. status = WN_SUCCESS;
  1302. break;
  1303. case WN_MORE_DATA:
  1304. //
  1305. // This provider has more data, but there is not enough
  1306. // room left in the user buffer to place any more data
  1307. // from this provider. We don't want to go on to the
  1308. // next provider until we're finished with this one. So
  1309. // if we have any entries at all to return, we send back
  1310. // a SUCCESS status. Otherwise, the WN_MORE_DATA status
  1311. // is appropriate.
  1312. //
  1313. if(entriesRead > 0) {
  1314. status = WN_SUCCESS;
  1315. }
  1316. else
  1317. {
  1318. //
  1319. // If 0 entries were read, then the provider should
  1320. // have set bytesLeft with the required buffer size
  1321. //
  1322. *lpBufferSize = ROUND_UP(bytesLeft);
  1323. }
  1324. goto CleanExit;
  1325. break;
  1326. default:
  1327. //
  1328. // We received an unexpected error from the Provider Enum
  1329. // call.
  1330. //
  1331. MPR_LOG(ERROR,"MprEnumConnect:ProviderEnum Error %d\n",status);
  1332. if(entriesRead > 0) {
  1333. //
  1334. // If we have received data so far, ignore this error
  1335. // and move on to the next provider. This provider will
  1336. // be left in the MORE_ENTRIES state, so that on some other
  1337. // pass - when all other providers are done, this error
  1338. // will be returned.
  1339. //
  1340. status = WN_SUCCESS;
  1341. }
  1342. else{
  1343. //
  1344. // No entries have been read so far. We can return
  1345. // immediately with the error.
  1346. //
  1347. goto CleanExit;
  1348. }
  1349. } // end switch (status)
  1350. } // end for (each provider)
  1351. //
  1352. // If we looped through all providers and they are all DONE.
  1353. // If there were no connections, then return proper error code.
  1354. //
  1355. if ((entriesRead == 0) && (status == WN_SUCCESS)) {
  1356. status = WN_NO_MORE_ENTRIES;
  1357. }
  1358. CleanExit:
  1359. //
  1360. // Update the number of entries to be returned to user.
  1361. //
  1362. *NumEntries = entriesRead;
  1363. LocalFree(providerBuffer);
  1364. return(status);
  1365. }
  1366. DWORD
  1367. MprEnumNetwork(
  1368. IN OUT LPNETWORK_HEADER StateTableHeader,
  1369. IN OUT LPDWORD NumEntries,
  1370. IN OUT LPVOID lpBuffer,
  1371. IN OUT LPDWORD lpBufferSize
  1372. )
  1373. /*++
  1374. Routine Description:
  1375. This function Looks in the state table for the next provider that has
  1376. MORE_ENTRIES. It begins by copying the NETRESOURCE info for that one.
  1377. This continues until we finish, or we reach the requested number of
  1378. elements, or the buffer is full. Each time we copy a complete structure,
  1379. we mark that provider as DONE.
  1380. Arguments:
  1381. StateTable - This is a pointer to the state table that is managed by
  1382. the handle used in this request. The state table is a table of
  1383. flags used to indicate the enumeration state for a given
  1384. provider. These flags are in the same order as the provider
  1385. information in the GlobalProviderInfo Array. The state can be
  1386. either DONE or MORE_ENTRIES.
  1387. NumEntries - On entry this points to the maximum number of entries
  1388. that the user desires to receive. On exit it points to the
  1389. number of entries that were placed in the users buffer.
  1390. lpBuffer - This is a pointer to the users buffer in which the
  1391. enumeration data is to be placed.
  1392. lpBufferSize - This is the size (in bytes) of the users buffer.
  1393. Return Value:
  1394. WN_SUCCESS - This indicates that the call is returning some entries.
  1395. However, the enumeration is not complete due to one of the following:
  1396. 1) There was not enough buffer space.
  1397. 2) The requested number of entries was reached.
  1398. 3) There is no more data to enumerate - the next call will
  1399. return WN_NO_MORE_ENTRIES.
  1400. WN_MORE_DATA - This indicates that the buffer was not large enough
  1401. to receive one enumeration entry.
  1402. WN_NO_MORE_ENTRIES - This indicates that there are no more entries
  1403. to enumerate. No data is returned with this return code.
  1404. Note:
  1405. CAUTION: "DONE" entries may appear anywhere in the statetable.
  1406. You cannot always rely on the fact that all of the entries
  1407. after a MORE_ENTRIES entry are also in the MORE_ENTRIES state.
  1408. This is because a provider that would not pass back a handle
  1409. at open time will be marked as DONE so that it gets skipped
  1410. at Enum Time.
  1411. --*/
  1412. {
  1413. DWORD i;
  1414. DWORD status;
  1415. DWORD entriesRead=0; // number of entries read into the buffer.
  1416. LPBYTE tempBufPtr; // pointer to top of remaining free buffer space.
  1417. DWORD bytesLeft; // num bytes left in free buffer space
  1418. LPNETWORK_ENUM StateTable = (LPNETWORK_ENUM)(StateTableHeader + 1);
  1419. //
  1420. // If there are no providers, return NO_NETWORK
  1421. //
  1422. if (StateTableHeader->dwNumActiveProviders == 0) {
  1423. return(WN_NO_NETWORK);
  1424. }
  1425. bytesLeft = ROUND_DOWN(*lpBufferSize);
  1426. tempBufPtr = (LPBYTE) lpBuffer;
  1427. //
  1428. // Check to see if there are any flags in state table that indicate
  1429. // MORE_ENTRIES. If not, we want to return WN_NO_MORE_ENTRIES.
  1430. //
  1431. for(i = 0; i < StateTableHeader->dwNumProviders; i++) {
  1432. if(StateTable[i].State == MORE_ENTRIES) {
  1433. break;
  1434. }
  1435. }
  1436. if ( i >= StateTableHeader->dwNumProviders ) {
  1437. *NumEntries = 0;
  1438. return(WN_NO_MORE_ENTRIES);
  1439. }
  1440. //
  1441. // Loop until we have copied from all Providers or until the
  1442. // the maximum number of entries has been reached.
  1443. //
  1444. for(; (i < StateTableHeader->dwNumProviders) && (entriesRead < *NumEntries); i++)
  1445. {
  1446. if (StateTable[i].State == MORE_ENTRIES) {
  1447. if (StateTable[i].hProviderDll == NULL)
  1448. {
  1449. //
  1450. // If the provider is not ACTIVE, skip it.
  1451. //
  1452. StateTable[i].State = DONE;
  1453. }
  1454. else
  1455. {
  1456. status = MprCopyResource(
  1457. &tempBufPtr,
  1458. StateTable[i].lpnr,
  1459. &bytesLeft);
  1460. if (status == WN_SUCCESS)
  1461. {
  1462. StateTable[i].State = DONE;
  1463. entriesRead++;
  1464. }
  1465. else
  1466. {
  1467. //
  1468. // The buffer must be full - so exit.
  1469. // If no entries are being returned, we will indicate
  1470. // that the buffer was not large enough for even one entry.
  1471. //
  1472. *NumEntries = entriesRead;
  1473. if (entriesRead > 0) {
  1474. return(WN_SUCCESS);
  1475. }
  1476. else {
  1477. *lpBufferSize = ROUND_UP(bytesLeft);
  1478. return(WN_MORE_DATA);
  1479. }
  1480. }
  1481. }
  1482. } // EndIf (state == MORE_ENTRIES)
  1483. } // EndFor (each provider)
  1484. //
  1485. // Update the number of entries to be returned to user
  1486. //
  1487. *NumEntries = entriesRead;
  1488. return(WN_SUCCESS);
  1489. }
  1490. DWORD
  1491. MprProviderEnum(
  1492. IN LPENUM_HANDLE EnumHandlePtr,
  1493. IN OUT LPDWORD lpcCount,
  1494. IN LPVOID lpBuffer,
  1495. IN OUT LPDWORD lpBufferSize
  1496. )
  1497. /*++
  1498. Routine Description:
  1499. This function calls the provider (identified by the EnumHandlePtr)
  1500. with a WNetEnumResource request. Aside from the EnumHandlePtr, all the
  1501. rest of the parameters are simply passed thru to the provider.
  1502. Arguments:
  1503. EnumHandlePtr - This is a pointer to an ENUM_HANDLE structure which
  1504. contains a pointer to the provider structure and the handle for
  1505. that provider's enumeration.
  1506. lpcCount - A pointer to a value that on entry contains the requested
  1507. number of elements to enumerate. On exit this contains the
  1508. actual number of elements enumerated.
  1509. lpBuffer - A pointer to the users buffer that the enumeration data
  1510. is to be placed into.
  1511. lpBufferSize - The number of bytes of free space in the user's buffer.
  1512. Return Value:
  1513. This function can return any return code that WNetEnumResource()
  1514. can return.
  1515. --*/
  1516. {
  1517. DWORD status;
  1518. ASSERT(EnumHandlePtr->pfEnumResource != NULL);
  1519. //
  1520. // Call the provider listed in the ENUM_HANDLE structure and ask it
  1521. // to enumerate.
  1522. //
  1523. status = EnumHandlePtr->pfEnumResource(
  1524. EnumHandlePtr->EnumHandle,
  1525. lpcCount,
  1526. lpBuffer,
  1527. lpBufferSize);
  1528. if (status == WN_SUCCESS) {
  1529. MPR_LOG(TRACE,"EnumResourceHandle = 0x%lx\n",
  1530. EnumHandlePtr->EnumHandle);
  1531. }
  1532. return(status);
  1533. }
  1534. DWORD
  1535. MprCopyResource(
  1536. IN OUT LPBYTE *BufPtr,
  1537. IN const NETRESOURCEW *Resource,
  1538. IN OUT LPDWORD BytesLeft
  1539. )
  1540. /*++
  1541. Routine Description:
  1542. This function copies a single NETRESOURCE structure into a buffer.
  1543. The structure gets copied to the top of the buffer, and the strings
  1544. that the structure references are copied to the bottom of the
  1545. buffer. So any remaining free buffer space is left in the middle.
  1546. Upon successful return from this function, BufPtr will point to
  1547. the top of this remaining free space, and BytesLeft will be updated
  1548. to indicate how many bytes of free space are remaining.
  1549. If there is not enough room in the buffer to copy the Resource and its
  1550. strings, an error is returned, and BufPtr is not changed.
  1551. Arguments:
  1552. BufPtr - This is a pointer to a location that upon entry, contains a
  1553. pointer to the buffer that the copied data is to be placed into.
  1554. Upon exit, this pointer location points to the next free location
  1555. in the buffer.
  1556. Resource - This points to the Resource Structure that is to be copied
  1557. into the buffer.
  1558. BytesLeft - This points to a location to where a count of the remaining
  1559. free bytes in the buffer is stored. This is updated on exit to
  1560. indicate the adjusted number of free bytes left in the buffer.
  1561. If the buffer is not large enough, and WN_MORE_DATA is returned, then
  1562. the size of the buffer required to fit all the data is returned in
  1563. this field.
  1564. Return Value:
  1565. WN_SUCCESS - The operation was successful
  1566. WN_MORE_DATA - The buffer was not large enough to contain the
  1567. Resource structure an its accompanying strings.
  1568. Note:
  1569. History:
  1570. 02-Apr-1992 JohnL
  1571. Changed error return code to WN_MORE_DATA, added code to set the
  1572. required buffer size if WN_MORE_DATA is returned.
  1573. --*/
  1574. {
  1575. LPTSTR startOfFreeBuf;
  1576. LPTSTR endOfFreeBuf;
  1577. LPNETRESOURCEW newResource;
  1578. //
  1579. // The buffer must be at least large enough to hold a resource structure.
  1580. //
  1581. if (*BytesLeft < sizeof(NETRESOURCEW)) {
  1582. *BytesLeft = MprMultiStrBuffSize( Resource->lpRemoteName,
  1583. Resource->lpLocalName,
  1584. Resource->lpComment,
  1585. Resource->lpProvider,
  1586. NULL ) + sizeof(NETRESOURCEW) ;
  1587. return(WN_MORE_DATA);
  1588. }
  1589. //
  1590. // Copy the Resource structure into the beginning of the buffer.
  1591. //
  1592. newResource = (LPNETRESOURCEW) *BufPtr;
  1593. memcpy(newResource, Resource, sizeof(NETRESOURCEW));
  1594. startOfFreeBuf = (LPTSTR)((PCHAR)newResource + sizeof(NETRESOURCEW));
  1595. endOfFreeBuf = (LPTSTR)((LPBYTE)newResource + *BytesLeft);
  1596. //
  1597. // If a REMOTE_NAME string is to be copied, copy that and update the
  1598. // pointer in the structure.
  1599. //
  1600. if (Resource->lpRemoteName != NULL) {
  1601. //
  1602. // If we must copy the remote name,
  1603. //
  1604. if (!NetpCopyStringToBuffer(
  1605. Resource->lpRemoteName, // pointer to string
  1606. STRLEN(Resource->lpRemoteName), // num chars in string
  1607. startOfFreeBuf, // start of open space
  1608. &endOfFreeBuf, // end of open space
  1609. &newResource->lpRemoteName)) { // where string pointer goes
  1610. *BytesLeft = MprMultiStrBuffSize( Resource->lpRemoteName,
  1611. Resource->lpLocalName,
  1612. Resource->lpComment,
  1613. Resource->lpProvider,
  1614. NULL ) ;
  1615. goto ErrorMoreData ;
  1616. }
  1617. }
  1618. else{
  1619. newResource->lpRemoteName = NULL;
  1620. }
  1621. //
  1622. // If a LOCAL_NAME string is to be copied, copy that and update the
  1623. // pointer in the structure.
  1624. //
  1625. if( ((Resource->dwScope == RESOURCE_CONNECTED) ||
  1626. (Resource->dwScope == RESOURCE_REMEMBERED))
  1627. &&
  1628. (Resource->lpLocalName != NULL) ) {
  1629. //
  1630. // If we must copy the local name,
  1631. //
  1632. if (!NetpCopyStringToBuffer(
  1633. Resource->lpLocalName, // pointer to string
  1634. STRLEN(Resource->lpLocalName), // num chars in string
  1635. startOfFreeBuf, // start of open space
  1636. &endOfFreeBuf, // end of open space
  1637. &newResource->lpLocalName)) // where string pointer goes
  1638. {
  1639. goto ErrorMoreData ;
  1640. }
  1641. }
  1642. else{
  1643. newResource->lpLocalName = NULL;
  1644. }
  1645. //
  1646. // If a COMMENT string is to be copied, copy that and update the
  1647. // pointer in the structure.
  1648. //
  1649. if (Resource->lpComment != NULL) {
  1650. //
  1651. // If we must copy the comment string,
  1652. //
  1653. if (!NetpCopyStringToBuffer(
  1654. Resource->lpComment, // pointer to string
  1655. STRLEN(Resource->lpComment), // num chars in string
  1656. startOfFreeBuf, // start of open space
  1657. &endOfFreeBuf, // end of open space
  1658. &newResource->lpComment)) // where string pointer goes
  1659. {
  1660. goto ErrorMoreData ;
  1661. }
  1662. }
  1663. else{
  1664. newResource->lpComment = NULL;
  1665. }
  1666. //
  1667. // If a PROVIDER string is to be copied, copy that and update the
  1668. // pointer in the structure.
  1669. //
  1670. if (Resource->lpProvider != NULL) {
  1671. //
  1672. // If we must copy the provider name,
  1673. //
  1674. if (!NetpCopyStringToBuffer(
  1675. Resource->lpProvider, // pointer to string
  1676. STRLEN(Resource->lpProvider), // num chars in string
  1677. startOfFreeBuf, // start of open space
  1678. &endOfFreeBuf, // end of open space
  1679. &newResource->lpProvider)) // where string pointer goes
  1680. {
  1681. goto ErrorMoreData ;
  1682. }
  1683. }
  1684. else{
  1685. newResource->lpProvider = NULL;
  1686. }
  1687. //
  1688. // Update the returned information
  1689. //
  1690. *BufPtr = (LPBYTE)startOfFreeBuf;
  1691. *BytesLeft = (DWORD) ((LPBYTE) endOfFreeBuf - (LPBYTE) startOfFreeBuf);
  1692. return (WN_SUCCESS);
  1693. //
  1694. // This is reached when we couldn't fill the buffer because the given
  1695. // buffer size is too small. We therefore need to set the required
  1696. // buffer size before returning.
  1697. ErrorMoreData:
  1698. *BytesLeft = MprMultiStrBuffSize( Resource->lpRemoteName,
  1699. Resource->lpLocalName,
  1700. Resource->lpComment,
  1701. Resource->lpProvider,
  1702. NULL ) + sizeof(NETRESOURCEW) ;
  1703. return (WN_MORE_DATA);
  1704. }
  1705. DWORD
  1706. MprCopyProviderEnum(
  1707. IN LPNETRESOURCEW ProviderBuffer,
  1708. IN OUT LPDWORD EntryCount,
  1709. IN OUT LPBYTE *TempBufPtr,
  1710. IN OUT LPDWORD BytesLeft
  1711. )
  1712. /*++
  1713. Routine Description:
  1714. This function moves the enumerated NETRESOURCE structures that are
  1715. returned from a provider to a buffer that can be returned to the user.
  1716. The buffer that is returned to the user may contain enum data from
  1717. several providers. Because, we don't know how strings are packed in
  1718. the buffer that is returned from the provider, we must simply walk
  1719. through each structure and copy the information into the user buffer
  1720. in a format that we do know about. Then the amount of free space
  1721. left in the user buffer can be determined so that enum data from
  1722. another provider can be added to it.
  1723. Arguments:
  1724. ProviderBuffer - This is a pointer to the top of an array of NETRESOURCE
  1725. structures that is returned from one of the providers.
  1726. EntryCount - This points to the number of elements in the array that
  1727. was returned from the provider. On exit, this points to the number
  1728. of elements that was successfully copied. This should always be
  1729. the same as the number of elements passed in.
  1730. TempBufPtr - This is a pointer to the top of the free space in the user
  1731. buffer.
  1732. BytesLeft - Upon entry, this contains the number of free space bytes
  1733. in the user buffer. Upon exit, this contains the updated number
  1734. of free space bytes in the user buffer.
  1735. Return Value:
  1736. WN_SUCCESS - The operation was successful
  1737. WN_OUT_OF_MEMORY - The buffer was not large enough to contain all of
  1738. data the provider returned. This should never happen.
  1739. Note:
  1740. --*/
  1741. {
  1742. DWORD i;
  1743. DWORD status;
  1744. DWORD entriesRead=0;
  1745. //
  1746. // Loop for each element in the array of NetResource Structures.
  1747. //
  1748. for(i=0; i<*EntryCount; i++,ProviderBuffer++) {
  1749. status = MprCopyResource(
  1750. TempBufPtr,
  1751. ProviderBuffer,
  1752. BytesLeft);
  1753. if (status != WN_SUCCESS) {
  1754. MPR_LOG(ERROR,"MprCopyProviderEnum: Buffer Size Mismatch\n",0);
  1755. //
  1756. // The buffer must be full - this should never happen since
  1757. // the amount of data placed in the ProviderBuffer is limited
  1758. // by the number of bytes left in the user buffer.
  1759. //
  1760. ASSERT(0);
  1761. *EntryCount = entriesRead;
  1762. return(status);
  1763. }
  1764. entriesRead++;
  1765. }
  1766. *EntryCount = entriesRead;
  1767. return(WN_SUCCESS);
  1768. }
  1769. //===================================================================
  1770. // CProviderOpenEnum - open an enumeration by a provider
  1771. //===================================================================
  1772. DWORD
  1773. CProviderOpenEnum::ValidateRoutedParameters(
  1774. LPCWSTR * ppProviderName,
  1775. LPCWSTR * ppRemoteName,
  1776. LPCWSTR * ppLocalName
  1777. )
  1778. {
  1779. //
  1780. // Let the base class validate any specified provider name.
  1781. // Note: This must be done before setting _lpNetResource to NULL!
  1782. //
  1783. *ppProviderName = _lpNetResource->lpProvider;
  1784. //
  1785. // Check to see if a top level enumeration for the provider is requested.
  1786. // (This is different from a top level MPR enumeration.)
  1787. // A top level enum is signified by a net resource with either a special
  1788. // bit set in the dwUsage field, or a provider name but no remote name.
  1789. //
  1790. if ((_lpNetResource->dwUsage & RESOURCEUSAGE_RESERVED) ||
  1791. IS_EMPTY_STRING(_lpNetResource->lpRemoteName))
  1792. {
  1793. //
  1794. // Top level enum. Don't pass the net resource to the provider.
  1795. //
  1796. ASSERT(! IS_EMPTY_STRING(_lpNetResource->lpProvider));
  1797. _lpNetResource = NULL;
  1798. }
  1799. else
  1800. {
  1801. //
  1802. // Use the remote name as a hint to pick the provider order.
  1803. //
  1804. *ppRemoteName = _lpNetResource->lpRemoteName;
  1805. }
  1806. *ppLocalName = NULL;
  1807. return WN_SUCCESS;
  1808. }
  1809. DWORD
  1810. CProviderOpenEnum::TestProvider(
  1811. const PROVIDER * pProvider
  1812. )
  1813. {
  1814. ASSERT(MPR_IS_INITIALIZED(NETWORK));
  1815. if ((pProvider->GetCaps(WNNC_ENUMERATION) & WNNC_ENUM_GLOBAL) == 0)
  1816. {
  1817. return WN_NOT_SUPPORTED;
  1818. }
  1819. return ( pProvider->OpenEnum(
  1820. _dwScope,
  1821. _dwType,
  1822. _dwUsage,
  1823. _lpNetResource,
  1824. &_ProviderEnumHandle) );
  1825. }
  1826. DWORD
  1827. CProviderOpenEnum::GetResult()
  1828. {
  1829. //
  1830. // Let the base class try the providers until one responds
  1831. // CRoutedOperation::GetResult calls INIT_IF_NECESSARY
  1832. //
  1833. DWORD status = CRoutedOperation::GetResult();
  1834. if (status != WN_SUCCESS)
  1835. {
  1836. return status;
  1837. }
  1838. MPR_LOG(TRACE,"CProviderOpenEnum: OpenEnum Handle = 0x%lx\n",
  1839. _ProviderEnumHandle);
  1840. //
  1841. // Allocate memory to store the handle.
  1842. //
  1843. LPENUM_HANDLE enumHandleStruct =
  1844. (ENUM_HANDLE *) LocalAlloc(LPTR, sizeof(ENUM_HANDLE));
  1845. if (enumHandleStruct == NULL)
  1846. {
  1847. //
  1848. // If we can't allocate memory to store the handle
  1849. // away, then we must close it, and change the status
  1850. // to indicate a memory failure.
  1851. //
  1852. MPR_LOG(ERROR,"CProviderOpenEnum: LocalAlloc failed %d\n",
  1853. GetLastError());
  1854. LastProvider()->CloseEnum(_ProviderEnumHandle);
  1855. status = WN_OUT_OF_MEMORY;
  1856. }
  1857. else
  1858. {
  1859. //
  1860. // Store the handle in the ENUM_HANDLE structure and
  1861. // return the pointer to that structure as a handle
  1862. // for the user.
  1863. //
  1864. enumHandleStruct->Key = PROVIDER_ENUM_KEY;
  1865. //
  1866. // Refcount the provider
  1867. //
  1868. enumHandleStruct->hProviderDll = LoadLibraryEx(LastProvider()->DllName,
  1869. NULL,
  1870. LOAD_WITH_ALTERED_SEARCH_PATH);
  1871. if (enumHandleStruct->hProviderDll == NULL)
  1872. {
  1873. status = GetLastError();
  1874. //
  1875. // This can happen under extreme low memory conditions. The
  1876. // loader can sometimes return ERROR_MOD_NOT_FOUND in this case.
  1877. //
  1878. MPR_LOG2(ERROR,
  1879. "MprOpenEnumConnect: LoadLibraryEx on %ws FAILED %d\n",
  1880. LastProvider()->DllName,
  1881. status);
  1882. ASSERT(status == ERROR_NOT_ENOUGH_MEMORY || status == ERROR_MOD_NOT_FOUND);
  1883. LastProvider()->CloseEnum(_ProviderEnumHandle);
  1884. LocalFree(enumHandleStruct);
  1885. }
  1886. else
  1887. {
  1888. enumHandleStruct->pfEnumResource = LastProvider()->EnumResource;
  1889. enumHandleStruct->pfCloseEnum = LastProvider()->CloseEnum;
  1890. enumHandleStruct->EnumHandle = _ProviderEnumHandle;
  1891. *_lphEnum = enumHandleStruct;
  1892. }
  1893. }
  1894. return status;
  1895. }
  1896. DWORD
  1897. MprOpenRemember(
  1898. IN DWORD dwType,
  1899. OUT LPHANDLE lphRemember
  1900. )
  1901. /*++
  1902. Routine Description:
  1903. Arguments:
  1904. Return Value:
  1905. Note:
  1906. --*/
  1907. {
  1908. LPREMEMBER_HANDLE rememberInfo;
  1909. rememberInfo = (REMEMBER_HANDLE *) LocalAlloc(LPTR, sizeof(REMEMBER_HANDLE));
  1910. if (rememberInfo == NULL) {
  1911. MPR_LOG(ERROR,"MprOpenRemember:LocalAlloc Failed %d\n",GetLastError());
  1912. return(WN_OUT_OF_MEMORY);
  1913. }
  1914. rememberInfo->Key = REMEMBER_KEY;
  1915. rememberInfo->KeyIndex = 0;
  1916. rememberInfo->ConnectionType = dwType;
  1917. //
  1918. // Open the key to the connection information in the current user
  1919. // section of the registry.
  1920. //
  1921. // NOTE: If this fails, we must assume that there is no connection
  1922. // information stored. This is not an error condition.
  1923. // In this case, we store a NULL for the handle so that we know
  1924. // the situation. Each time EnumResource is called, we can try
  1925. // to open the key again.
  1926. //
  1927. if (!MprOpenKey(
  1928. HKEY_CURRENT_USER,
  1929. CONNECTION_KEY_NAME,
  1930. &(rememberInfo->ConnectKey),
  1931. DA_READ)) {
  1932. MPR_LOG(ERROR,"MprOpenRemember: MprOpenKey Failed\n",0);
  1933. rememberInfo->ConnectKey = NULL;
  1934. }
  1935. *lphRemember = (HANDLE)rememberInfo;
  1936. return(WN_SUCCESS);
  1937. }
  1938. DWORD
  1939. MprEnumRemembered(
  1940. IN OUT LPREMEMBER_HANDLE RememberInfo,
  1941. IN OUT LPDWORD NumEntries,
  1942. IN OUT LPBYTE lpBuffer,
  1943. IN OUT LPDWORD lpBufferSize
  1944. )
  1945. /*++
  1946. Routine Description:
  1947. Arguments:
  1948. RememberInfo - This is a pointer to REMEMBER_HANDLE data structure
  1949. that contains the context information for this enumeration handle.
  1950. NumEntries - On entry this points to the maximum number of entries
  1951. that the user desires to receive. On exit it points to the
  1952. number of entries that were placed in the users buffer.
  1953. lpBuffer - This is a pointer to the users buffer in which the
  1954. enumeration data is to be placed.
  1955. lpBufferSize - This is the size (in bytes) of the users buffer.
  1956. Return Value:
  1957. WN_SUCCESS - The call was successful, and some entries were returned.
  1958. However, there are still more entries to be enumerated.
  1959. WN_NO_MORE_ENTRIES - This function has no data to return because
  1960. there was no further connection information in the registry.
  1961. WN_CONNOT_OPEN_PROFILE - This function could open a key to the
  1962. connection information, but could not get any information about
  1963. that key.
  1964. WN_MORE_DATA - The caller's buffer was too small for even one entry.
  1965. Note:
  1966. History:
  1967. Changed to return "status" instead of WN_SUCCESS
  1968. --*/
  1969. {
  1970. DWORD status = WN_SUCCESS ;
  1971. LPTSTR userName;
  1972. NETRESOURCEW netResource;
  1973. LPBYTE tempBufPtr;
  1974. DWORD bytesLeft;
  1975. DWORD entriesRead = 0;
  1976. DWORD numSubKeys;
  1977. DWORD maxSubKeyLen;
  1978. DWORD maxValueLen;
  1979. if ((RememberInfo->ConnectKey == NULL) && (RememberInfo->KeyIndex == 0)) {
  1980. //
  1981. // If we failed to open the key at Open-time, attempt to open it
  1982. // now. This registry key is closed when the CloseEnum function is
  1983. // called.
  1984. //
  1985. if (!MprOpenKey(
  1986. HKEY_CURRENT_USER,
  1987. CONNECTION_KEY_NAME,
  1988. &(RememberInfo->ConnectKey),
  1989. DA_READ)) {
  1990. //
  1991. // We couldn't open the key. So we must assume that it doesn't
  1992. // exist because there if no connection information stored.
  1993. //
  1994. MPR_LOG(ERROR,"MprEnumRemembered: MprOpenKey Failed\n",0);
  1995. RememberInfo->ConnectKey = NULL;
  1996. return(WN_NO_MORE_ENTRIES);
  1997. }
  1998. }
  1999. //
  2000. // Find out the size of the largest key name.
  2001. //
  2002. if(!MprGetKeyInfo(
  2003. RememberInfo->ConnectKey,
  2004. NULL,
  2005. &numSubKeys,
  2006. &maxSubKeyLen,
  2007. NULL,
  2008. &maxValueLen)) {
  2009. MPR_LOG(ERROR,"MprEnumRemembered: MprGetKeyInfo Failed\n",0);
  2010. return(WN_CANNOT_OPEN_PROFILE);
  2011. }
  2012. //
  2013. // If we've already enumerated all the subkeys, there are no more entries.
  2014. //
  2015. if (RememberInfo->KeyIndex >= numSubKeys) {
  2016. return(WN_NO_MORE_ENTRIES);
  2017. }
  2018. tempBufPtr = lpBuffer;
  2019. bytesLeft = ROUND_DOWN(*lpBufferSize);
  2020. tempBufPtr = lpBuffer;
  2021. netResource.lpComment = NULL;
  2022. netResource.dwScope = RESOURCE_REMEMBERED;
  2023. netResource.dwUsage = 0;
  2024. netResource.dwDisplayType = RESOURCEDISPLAYTYPE_SHARE;
  2025. //
  2026. // MprReadConnectionInfo may access the providers
  2027. //
  2028. MprCheckProviders();
  2029. CProviderSharedLock PLock;
  2030. while(
  2031. (RememberInfo->KeyIndex < numSubKeys) &&
  2032. (entriesRead < *NumEntries) &&
  2033. (bytesLeft > sizeof(NETRESOURCE))
  2034. )
  2035. {
  2036. //
  2037. // Get the connection info from the key and stuff it into
  2038. // a NETRESOURCE structure.
  2039. //
  2040. BOOL fMatch = FALSE;
  2041. DWORD ProviderFlags; // ignored
  2042. DWORD DeferFlags; // ignored
  2043. if(!MprReadConnectionInfo(
  2044. RememberInfo->ConnectKey,
  2045. NULL,
  2046. RememberInfo->KeyIndex,
  2047. &ProviderFlags,
  2048. &DeferFlags,
  2049. &userName,
  2050. &netResource,
  2051. NULL,
  2052. maxSubKeyLen)) {
  2053. //
  2054. // NOTE: The ReadConnectionInfo call could return FALSE
  2055. // if it failed in a memory allocation.
  2056. //
  2057. if (entriesRead == 0) {
  2058. status = WN_NO_MORE_ENTRIES;
  2059. }
  2060. else {
  2061. status = WN_SUCCESS;
  2062. }
  2063. break;
  2064. }
  2065. else
  2066. {
  2067. if ((netResource.dwType == RememberInfo->ConnectionType) ||
  2068. (RememberInfo->ConnectionType == RESOURCETYPE_ANY)) {
  2069. fMatch = TRUE;
  2070. }
  2071. }
  2072. //
  2073. // Copy the new netResource information into the user's
  2074. // buffer. Each time this function is called, the tempBufPtr
  2075. // gets updated to point to the next free space in the user's
  2076. // buffer.
  2077. //
  2078. if ( fMatch )
  2079. {
  2080. status = MprCopyResource(
  2081. &tempBufPtr,
  2082. &netResource,
  2083. &bytesLeft);
  2084. if (status != WN_SUCCESS) {
  2085. if (entriesRead == 0) {
  2086. *lpBufferSize = ROUND_UP(bytesLeft);
  2087. status = WN_MORE_DATA;
  2088. }
  2089. else {
  2090. status = WN_SUCCESS;
  2091. }
  2092. break;
  2093. }
  2094. entriesRead++;
  2095. }
  2096. //
  2097. // Free the allocated memory resources.
  2098. //
  2099. LocalFree(netResource.lpLocalName);
  2100. LocalFree(netResource.lpRemoteName);
  2101. LocalFree(netResource.lpProvider);
  2102. if (userName != NULL) {
  2103. LocalFree(userName);
  2104. }
  2105. (RememberInfo->KeyIndex)++;
  2106. }
  2107. *NumEntries = entriesRead;
  2108. return(status);
  2109. }
  2110. DWORD
  2111. MprMultiStrBuffSize(
  2112. IN LPTSTR lpString1,
  2113. IN LPTSTR lpString2,
  2114. IN LPTSTR lpString3,
  2115. IN LPTSTR lpString4,
  2116. IN LPTSTR lpString5
  2117. )
  2118. /*++
  2119. Routine Description:
  2120. This function is a worker function that simply determines the total
  2121. storage requirements needed by the passed set of strings. Any of the
  2122. strings maybe NULL in which case the string will be ignored.
  2123. The NULL terminator is added into the total memory requirements.
  2124. Arguments:
  2125. lpString1 -> 5 - Pointers to valid strings or NULL.
  2126. Return Value:
  2127. The count of bytes required to store the passed strings.
  2128. Note:
  2129. --*/
  2130. {
  2131. DWORD cbRequired = 0 ;
  2132. if ( lpString1 != NULL )
  2133. {
  2134. cbRequired += (STRLEN( lpString1 ) + 1) * sizeof(TCHAR) ;
  2135. }
  2136. if ( lpString2 != NULL )
  2137. {
  2138. cbRequired += (STRLEN( lpString2 ) + 1) * sizeof(TCHAR) ;
  2139. }
  2140. if ( lpString3 != NULL )
  2141. {
  2142. cbRequired += (STRLEN( lpString3 ) + 1) * sizeof(TCHAR) ;
  2143. }
  2144. if ( lpString4 != NULL )
  2145. {
  2146. cbRequired += (STRLEN( lpString4 ) + 1) * sizeof(TCHAR) ;
  2147. }
  2148. if ( lpString5 != NULL )
  2149. {
  2150. cbRequired += (STRLEN( lpString5 ) + 1) * sizeof(TCHAR) ;
  2151. }
  2152. return cbRequired ;
  2153. }
  2154. BOOL
  2155. MprNetIsAvailable(
  2156. VOID)
  2157. /*++
  2158. Routine Description:
  2159. This function checks if the net is available by calling the GetCaps
  2160. of each provider to make sure it is started.
  2161. Arguments:
  2162. none
  2163. Return Value:
  2164. TRUE is yes, FALSE otherwise
  2165. Note:
  2166. --*/
  2167. {
  2168. DWORD status = WN_SUCCESS;
  2169. LPDWORD index;
  2170. DWORD indexArray[DEFAULT_MAX_PROVIDERS];
  2171. DWORD numProviders, i;
  2172. LPPROVIDER provider;
  2173. DWORD dwResult ;
  2174. //
  2175. // Find the list of providers to call for this request.
  2176. // If there are no active providers, MprFindCallOrder returns
  2177. // WN_NO_NETWORK.
  2178. //
  2179. index = indexArray;
  2180. status = MprFindCallOrder(
  2181. NULL,
  2182. &index,
  2183. &numProviders,
  2184. NETWORK_TYPE);
  2185. if (status != WN_SUCCESS)
  2186. return(FALSE);
  2187. //
  2188. // Loop through the list of providers, making sure at least one
  2189. // is started
  2190. //
  2191. ASSERT(MPR_IS_INITIALIZED(NETWORK));
  2192. for (i=0; i<numProviders; i++)
  2193. {
  2194. //
  2195. // Call the appropriate providers API entry point
  2196. //
  2197. provider = GlobalProviderInfo + index[i];
  2198. if (provider->GetCaps != NULL)
  2199. {
  2200. dwResult = provider->GetCaps( WNNC_START );
  2201. if (dwResult != 0)
  2202. {
  2203. if (index != indexArray)
  2204. LocalFree(index);
  2205. return (TRUE) ;
  2206. }
  2207. }
  2208. }
  2209. //
  2210. // If memory was allocated by MprFindCallOrder, free it.
  2211. //
  2212. if (index != indexArray)
  2213. LocalFree(index);
  2214. return(FALSE);
  2215. }