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.

2515 lines
68 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. mpransi.cxx
  5. Abstract:
  6. Contains Ansi Entry points for the MPR api.
  7. Author:
  8. Dan Lafferty (danl) 20-Dec-1991
  9. Environment:
  10. User Mode -Win32
  11. Notes:
  12. I may want to add a buffer size parameter to ConvertToAnsi
  13. Revision History:
  14. 08-Aug-1996 anirudhs
  15. Major revision (simplification): Converted all remaining APIs to
  16. the smaller, faster interpreted scheme. Added ANSI_API_ macros.
  17. Eliminated helper functions used by the old scheme. These changes
  18. shrink this file by about 1400 lines.
  19. 16-Feb-1996 anirudhs
  20. Added InputParmsToUnicode, OutputBufferToAnsi and helper functions.
  21. These form a smaller, faster, interpreted scheme for writing the
  22. Ansi APIs. This scheme is smaller chiefly because it eliminates
  23. a very large amount of code duplication present in the previous
  24. scheme. This also makes the Ansi APIs less bug-prone. It is
  25. faster chiefly because intermediate storage is allocated with a
  26. single heap allocation per API, rather than several. Also, the
  27. number of passes to scan and copy data is minimized.
  28. 06-Oct-1995 anirudhs
  29. MprMakeUnicodeNetRes and related functions: Removed duplicated
  30. code for the string fields of the net resource; added code to
  31. iterate over the string fields instead. Fixed access violation
  32. and memory leaks.
  33. 24-Aug-1992 danl
  34. For WNetGetConnection & WNetGetUser, we allocate a buffer twice
  35. the size of the user buffer. The data is placed in this buffer.
  36. Then we check to see if the data will fit in the user buffer
  37. after it is translated to Ansi. The presence of DBSC characters
  38. may make it not fit. In which case, we return the required number
  39. of bytes. This number assumes worse-case where all characters are
  40. DBCS characters.
  41. 20-Dec-1991 danl
  42. created
  43. --*/
  44. //
  45. // INCLUDES
  46. //
  47. #include "precomp.hxx"
  48. #include <string.h> // strlen
  49. #include <tstring.h> // STRLEN
  50. //
  51. // CONSTANTS
  52. //
  53. #define MAX_STRINGS_PER_API 6
  54. //
  55. // The following masks are used to indicate which fields in the NetResource
  56. // structure are used by an API.
  57. // The values must match the NRWField and NRAField arrays.
  58. //
  59. #define NETRESFIELD_LOCALNAME 0x00000001
  60. #define NETRESFIELD_REMOTENAME 0x00000002
  61. #define NETRESFIELD_COMMENT 0x00000004
  62. #define NETRESFIELD_PROVIDER 0x00000008
  63. #define NUMBER_OF_NETRESFIELD 4
  64. //
  65. // Combinations of the NETRESFIELD_ constants, for passing to InputParmsToUnicode.
  66. //
  67. #define NETRES_LRP "\xB" // local name, remote name, provider
  68. #define NETRES_RP "\xA" // remote name, provider
  69. //
  70. // Alignment macros
  71. // These macros assume that sizeof(WCHAR) and sizeof(DWORD) are powers of 2
  72. //
  73. #define ROUND_UP_TO_WCHAR(x) (((DWORD)(x) + sizeof(WCHAR) - 1) & ~(sizeof(WCHAR) - 1))
  74. #define ROUND_UP_TO_DWORD(x) (((DWORD)(x) + sizeof(DWORD) - 1) & ~(sizeof(DWORD) - 1))
  75. #define IS_WCHAR_ALIGNED(x) (((ULONG_PTR)(x) & (sizeof(WCHAR) - 1)) == 0)
  76. #define IS_DWORD_ALIGNED(x) (((ULONG_PTR)(x) & (sizeof(DWORD) - 1)) == 0)
  77. //
  78. // Nearly every API ends this way
  79. //
  80. #define SET_AND_RETURN(status) \
  81. if (status != NO_ERROR) \
  82. { \
  83. SetLastError(status); \
  84. } \
  85. \
  86. return status;
  87. //
  88. // This is the general pattern of an Ansi wrapper for an API with no
  89. // output Ansi parameters. There are some exceptions.
  90. //
  91. #define ANSI_API_WITHOUT_ANSI_OUTPUT(NUMBER_OF_PARMS, \
  92. ANSI_PARM_ASSIGNMENT, \
  93. INSTRUCTION_STRING, \
  94. UNICODE_CALL) \
  95. \
  96. DWORD status; \
  97. LPBYTE tempBuffer = NULL; \
  98. ANSI_PARM AParm[NUMBER_OF_PARMS]; \
  99. UNICODE_PARM UParm[NUMBER_OF_PARMS]; \
  100. \
  101. ANSI_PARM_ASSIGNMENT \
  102. \
  103. status = InputParmsToUnicode(INSTRUCTION_STRING, AParm, UParm, &tempBuffer); \
  104. \
  105. if (status == WN_SUCCESS) \
  106. { \
  107. status = UNICODE_CALL \
  108. } \
  109. \
  110. LocalFree(tempBuffer); \
  111. \
  112. SET_AND_RETURN(status)
  113. //
  114. // This is the general pattern of an Ansi wrapper for an API that
  115. // has output Ansi parameters. There are some exceptions.
  116. //
  117. #define ANSI_API_WITH_ANSI_OUTPUT(NUMBER_OF_PARMS, \
  118. ANSI_PARM_ASSIGNMENT, \
  119. INSTRUCTION_STRING, \
  120. UNICODE_CALL, \
  121. OUTPUT_CALL) \
  122. \
  123. DWORD status; \
  124. LPBYTE tempBuffer = NULL; \
  125. ANSI_PARM AParm[NUMBER_OF_PARMS]; \
  126. UNICODE_PARM UParm[NUMBER_OF_PARMS]; \
  127. \
  128. ANSI_PARM_ASSIGNMENT \
  129. \
  130. status = InputParmsToUnicode(INSTRUCTION_STRING, AParm, UParm, &tempBuffer); \
  131. \
  132. if (status == WN_SUCCESS) \
  133. { \
  134. status = UNICODE_CALL \
  135. \
  136. if (status == WN_SUCCESS) \
  137. { \
  138. status = OUTPUT_CALL \
  139. } \
  140. } \
  141. \
  142. LocalFree(tempBuffer); \
  143. \
  144. SET_AND_RETURN(status)
  145. //
  146. // STRUCTURES
  147. //
  148. // These unions are defined so that parameters of various types can be passed
  149. // to the generic routine InputParmsToUnicode.
  150. // CODEWORK: By using these unions, we have lost type safety, and this could
  151. // cause some bugs to go undetected. To get back type safety, ANSI_PARM and
  152. // UNICODE_PARM could be made into "smart union" classes, with overloaded
  153. // assignment and cast operators that, in the checked build, remember the
  154. // type of the data that they are assigned, and assert if they are used as
  155. // any other type of data.
  156. // This would also make the code neater by allowing initializers like
  157. // ANSI_PARM AParm[] = { lpName, lpUserName, lpnLength };
  158. typedef union
  159. {
  160. DWORD dword;
  161. LPCSTR lpcstr;
  162. LPNETRESOURCEA lpNetResA;
  163. LPVOID lpvoid;
  164. LPDWORD lpdword;
  165. } ANSI_PARM;
  166. typedef union
  167. {
  168. DWORD dword;
  169. LPBYTE lpbyte;
  170. LPWSTR lpwstr;
  171. LPNETRESOURCEW lpNetResW;
  172. } UNICODE_PARM;
  173. class ANSI_OUT_BUFFER
  174. {
  175. private:
  176. const LPBYTE _Start; // Pointer to start of buffer
  177. const DWORD _Size; // Total number of bytes in buffer
  178. DWORD _Used; // Number of bytes used (may exceed Size)
  179. public:
  180. ANSI_OUT_BUFFER(LPBYTE Start, DWORD Size) :
  181. _Start(Start),
  182. _Size (Size),
  183. _Used (0)
  184. { }
  185. BYTE * Next() const
  186. { return _Start + _Used; }
  187. BOOL Overflow() const
  188. { return (_Used > _Size); }
  189. DWORD FreeSpace() const
  190. { return (Overflow() ? 0 : _Size - _Used); }
  191. BOOL HasRoomFor(DWORD Request) const
  192. { return (_Used + Request <= _Size); }
  193. void AddUsed(DWORD Request)
  194. { _Used += Request; }
  195. DWORD GetUsage() const
  196. { return _Used; }
  197. };
  198. //
  199. // STATIC DATA
  200. //
  201. //
  202. // These arrays of members are used to iterate through the string fields
  203. // of a net resource.
  204. // The order must match the NETRESFIELD_ definitions.
  205. //
  206. LPWSTR NETRESOURCEW::* const NRWField[NUMBER_OF_NETRESFIELD] =
  207. {
  208. &NETRESOURCEW::lpLocalName,
  209. &NETRESOURCEW::lpRemoteName,
  210. &NETRESOURCEW::lpComment,
  211. &NETRESOURCEW::lpProvider
  212. };
  213. LPSTR NETRESOURCEA::* const NRAField[NUMBER_OF_NETRESFIELD] =
  214. {
  215. &NETRESOURCEA::lpLocalName,
  216. &NETRESOURCEA::lpRemoteName,
  217. &NETRESOURCEA::lpComment,
  218. &NETRESOURCEA::lpProvider
  219. };
  220. //
  221. // Local Functions
  222. //
  223. DWORD
  224. InputParmsToUnicode(
  225. IN LPCSTR Instructions,
  226. IN const ANSI_PARM InputParms[],
  227. OUT UNICODE_PARM OutputParms[],
  228. OUT LPBYTE * ppBuffer
  229. );
  230. DWORD
  231. StringParmToUnicodePass1(
  232. IN LPCSTR StringParm,
  233. OUT PANSI_STRING AnsiString,
  234. OUT PUNICODE_STRING UnicodeString,
  235. IN OUT PULONG BufferOffset
  236. );
  237. DWORD
  238. StringParmToUnicodePass2(
  239. IN OUT PANSI_STRING AnsiString,
  240. OUT PUNICODE_STRING UnicodeString,
  241. IN const BYTE * BufferStart,
  242. OUT LPWSTR * Result
  243. );
  244. DWORD
  245. OutputBufferToAnsi(
  246. IN char BufferFormat,
  247. IN LPBYTE SourceBuffer,
  248. OUT LPVOID AnsiBuffer,
  249. IN OUT LPDWORD pcbBufferSize
  250. );
  251. DWORD
  252. OutputStringToAnsi(
  253. IN LPCWSTR UnicodeIn,
  254. IN OUT ANSI_OUT_BUFFER * Buf
  255. );
  256. DWORD
  257. OutputStringToAnsiInPlace(
  258. IN LPWSTR UnicodeIn
  259. );
  260. DWORD
  261. OutputNetResourceToAnsi(
  262. IN NETRESOURCEW * lpNetResW,
  263. IN OUT ANSI_OUT_BUFFER * Buf
  264. );
  265. DWORD
  266. InputParmsToUnicode(
  267. IN LPCSTR Instructions,
  268. IN const ANSI_PARM InputParms[],
  269. OUT UNICODE_PARM OutputParms[],
  270. OUT LPBYTE * ppBuffer
  271. )
  272. /*++
  273. Routine Description:
  274. This function converts the caller's input parameters to Unicode.
  275. If necessary, it allocates one temporary buffer in which it stores
  276. the intermediate Unicode parameters. This minimizes the cost of
  277. calls to LocalAlloc.
  278. Arguments:
  279. Instructions - A string of characters, roughly one for each member
  280. of the InputParms array, describing the action to be taken on each
  281. InputParms member. Recognized values for the characters are:
  282. 'S' (String) - InputParms member is an LPSTR to be converted to
  283. Unicode. Store a pointer to the Unicode string in the
  284. corresponding OutputParms member.
  285. 'N' (NetResource) - InputParms member is a LPNETRESOURCEA to be
  286. converted to a NETRESOURCEW. The next character in Instructions
  287. is a bitmask of the NETRESFIELD_ constants, indicating which
  288. fields of the NETRESOURCEA to convert. Store a pointer to the
  289. NETRESOURCEW in the corresponding OutputParms member.
  290. 'B' (Buffer) - InputParms member (say InputParms[i]) is a pointer to
  291. an output buffer. InputParms[i+1] is a pointer to a DWORD
  292. indicating the buffer size in bytes. Probe the buffer for write.
  293. Allocate an area of double the size (i.e. of size
  294. (*InputParms[i+1])*sizeof(WCHAR)) in the intermediate buffer.
  295. Store a pointer to this area of the buffer in OutputParms[i].
  296. Store the size of this area in OutputParms[i+1].
  297. If InputParms[i] is NULL, store NULL in OutputParms[i], and
  298. ignore InputParms[i+1]. (In other words, the buffer pointer
  299. is optional; the size pointer is required if the buffer pointer
  300. is present and ignored if the buffer pointer is absent.)
  301. 'Bs' (Buffer beginning with structure) - Same as 'B', but the first
  302. N bytes of the output buffer, where N is stored in InputParms[i+2],
  303. are supposed to hold a fixed-size structure, not strings.
  304. When calculating the size of the intermediate area, double the
  305. size of the rest of the buffer, but not the size of the structure.
  306. CODEWORK: Also verify that the buffer is DWORD-aligned?
  307. InputParms - An array of parameters to the Ansi API, described by the
  308. Instructions parameter.
  309. OutputParms - An array of the same size as InputParms, to hold the
  310. converted Unicode parameters.
  311. ppBuffer - A pointer to the intermediate buffer allocated by this
  312. function will be stored here. It must be freed by a single call
  313. to LocalFree, regardless of the return value from this function.
  314. Return Value:
  315. WN_SUCCESS
  316. WN_OUT_OF_MEMORY
  317. WN_BAD_POINTER
  318. History:
  319. 16-Feb-1996 anirudhs Created.
  320. Notes:
  321. The function works by making two passes through the Instructions string.
  322. In the first pass the string lengths are determined and saved, and the
  323. required size of the temporary buffer is calculated. In the second
  324. pass the parameters are actually converted to Unicode.
  325. --*/
  326. {
  327. ANSI_STRING AnsiStrings [MAX_STRINGS_PER_API] = {0};
  328. UNICODE_STRING UnicodeStrings[MAX_STRINGS_PER_API] = {0};
  329. ULONG Bytes = 0; // Size of buffer to allocate
  330. DWORD status = WN_SUCCESS;
  331. //
  332. // The caller must have initialized the buffer pointer to NULL, so
  333. // he can free the buffer even if this function fails.
  334. //
  335. ASSERT(*ppBuffer == NULL);
  336. __try
  337. {
  338. //
  339. // For two passes through Instructions
  340. //
  341. #define FIRST_PASS (iPass == 0)
  342. for (ULONG iPass = 0; iPass <= 1; iPass++)
  343. {
  344. ULONG iString = 0; // Index into AnsiStrings and UnicodeStrings
  345. //
  346. // For each character in Instructions
  347. //
  348. const CHAR * pInstruction; // Pointer into Instructions
  349. ULONG iParm; // Index into InputParms and OutputParms
  350. for (pInstruction = Instructions, iParm = 0;
  351. *pInstruction;
  352. pInstruction++, iParm++)
  353. {
  354. MPR_LOG(ANSI, "Processing instruction '%hc'\n", *pInstruction);
  355. switch (*pInstruction)
  356. {
  357. case 'B':
  358. //
  359. // The next 2 InputParms are a buffer pointer and size.
  360. // Note that this code could cause an exception.
  361. //
  362. if (InputParms[iParm].lpvoid == NULL)
  363. {
  364. // A NULL pointer stays NULL; the size pointer is ignored
  365. OutputParms[iParm].lpbyte = NULL;
  366. }
  367. else if (FIRST_PASS)
  368. {
  369. // Probe the original buffer
  370. if (IS_BAD_BYTE_BUFFER(InputParms[iParm].lpvoid,
  371. InputParms[iParm+1].lpdword))
  372. {
  373. status = WN_BAD_POINTER;
  374. __leave;
  375. }
  376. // Reserve the intermediate buffer area
  377. Bytes = ROUND_UP_TO_DWORD(Bytes);
  378. OutputParms[iParm].dword = Bytes;
  379. OutputParms[iParm+1].dword =
  380. (*InputParms[iParm+1].lpdword) * sizeof(WCHAR);
  381. // Check for an optional 's' in Instructions
  382. if (*(pInstruction+1) == 's')
  383. {
  384. // CODEWORK: Check for DWORD alignment on RISC?
  385. // if (!IS_DWORD_ALIGNED(InputParms[iParm].lpvoid))
  386. // { status = WN_BAD_POINTER; __leave; }
  387. // InputParms[iParm+2].dword holds the size of the
  388. // fixed-length structure that will go at the start
  389. // of the buffer. We don't want to multiply its
  390. // size by sizeof(WCHAR).
  391. if (OutputParms[iParm+1].dword/sizeof(WCHAR) <
  392. InputParms[iParm+2].dword)
  393. {
  394. OutputParms[iParm+1].dword /= sizeof(WCHAR);
  395. }
  396. else
  397. {
  398. OutputParms[iParm+1].dword -=
  399. InputParms[iParm+2].dword*(sizeof(WCHAR)-1);
  400. }
  401. }
  402. Bytes += OutputParms[iParm+1].dword;
  403. }
  404. else // Non-NULL pointer, second pass
  405. {
  406. // Convert the offset to a pointer
  407. OutputParms[iParm].lpbyte =
  408. *ppBuffer + OutputParms[iParm].dword;
  409. ASSERT(IS_DWORD_ALIGNED(OutputParms[iParm].lpbyte));
  410. }
  411. iParm++; // iParm+1 was for the buffer size
  412. if (*(pInstruction+1) == 's')
  413. {
  414. pInstruction++;
  415. iParm++; // iParm+2 was for the fixed structure size
  416. }
  417. break;
  418. case 'S':
  419. //
  420. // InputParm is a string to be converted.
  421. // A NULL string stays NULL.
  422. //
  423. if (FIRST_PASS)
  424. {
  425. ASSERT(iString < MAX_STRINGS_PER_API);
  426. Bytes = ROUND_UP_TO_WCHAR(Bytes);
  427. status = StringParmToUnicodePass1(
  428. InputParms[iParm].lpcstr,
  429. &AnsiStrings[iString],
  430. &UnicodeStrings[iString],
  431. &Bytes);
  432. }
  433. else
  434. {
  435. status = StringParmToUnicodePass2(
  436. &AnsiStrings[iString],
  437. &UnicodeStrings[iString],
  438. *ppBuffer,
  439. &OutputParms[iParm].lpwstr);
  440. }
  441. if (status != WN_SUCCESS)
  442. {
  443. __leave;
  444. }
  445. iString++;
  446. break;
  447. case 'N':
  448. //
  449. // InputParm is a NETRESOURCEA to be converted, and the
  450. // next character in Instructions tells which of its string
  451. // fields are to be converted.
  452. // NULL strings remain NULL; ignored fields are copied
  453. // unchanged.
  454. //
  455. pInstruction++;
  456. if (InputParms[iParm].lpNetResA == NULL)
  457. {
  458. // A null netresource stays null
  459. OutputParms[iParm].lpNetResW = NULL;
  460. break;
  461. }
  462. {
  463. // First deal with the fixed-size part of the structure.
  464. const NETRESOURCEA *pNetResA =
  465. InputParms[iParm].lpNetResA;
  466. NETRESOURCEW *pNetResW;
  467. if (FIRST_PASS)
  468. {
  469. // Reserve space for the NETRESOURCEW
  470. Bytes = ROUND_UP_TO_DWORD(Bytes);
  471. OutputParms[iParm].dword = Bytes;
  472. Bytes += sizeof(NETRESOURCEW);
  473. ASSERT(IS_WCHAR_ALIGNED(Bytes));
  474. }
  475. else
  476. {
  477. // Copy fixed-size fields and NULL pointers
  478. pNetResW = (NETRESOURCEW *)
  479. (*ppBuffer + OutputParms[iParm].dword);
  480. ASSERT(IS_DWORD_ALIGNED(pNetResW));
  481. RtlCopyMemory(pNetResW, pNetResA, sizeof(NETRESOURCEA));
  482. OutputParms[iParm].lpNetResW = pNetResW;
  483. }
  484. // Next add each non-null string specified in the
  485. // field mask.
  486. CHAR FieldMask = *pInstruction;
  487. ASSERT(FieldMask != 0);
  488. for (ULONG iField = 0;
  489. iField < NUMBER_OF_NETRESFIELD;
  490. iField++)
  491. {
  492. if ((FieldMask >> iField) & 1)
  493. {
  494. if (FIRST_PASS)
  495. {
  496. ASSERT(iString < MAX_STRINGS_PER_API);
  497. status = StringParmToUnicodePass1(
  498. pNetResA->*NRAField[iField],
  499. &AnsiStrings[iString],
  500. &UnicodeStrings[iString],
  501. &Bytes);
  502. }
  503. else
  504. {
  505. status = StringParmToUnicodePass2(
  506. &AnsiStrings[iString],
  507. &UnicodeStrings[iString],
  508. *ppBuffer,
  509. &(pNetResW->*NRWField[iField]));
  510. }
  511. if (status != WN_SUCCESS)
  512. {
  513. __leave;
  514. }
  515. iString++;
  516. }
  517. }
  518. }
  519. break;
  520. default:
  521. ASSERT(0);
  522. }
  523. }
  524. if (FIRST_PASS)
  525. {
  526. //
  527. // Actually allocate the space for the Unicode parameters
  528. //
  529. *ppBuffer = (LPBYTE) LocalAlloc(0, Bytes);
  530. if (*ppBuffer == NULL)
  531. {
  532. status = GetLastError();
  533. MPR_LOG2(ERROR,
  534. "InputParmsToUnicode: LocalAlloc for %lu bytes failed, %lu\n",
  535. Bytes, status);
  536. __leave;
  537. }
  538. }
  539. }
  540. }
  541. __except(EXCEPTION_EXECUTE_HANDLER)
  542. {
  543. #if DBG == 1
  544. status = GetExceptionCode();
  545. if (status != EXCEPTION_ACCESS_VIOLATION)
  546. {
  547. MPR_LOG(ERROR,"InputParmsToUnicode: Unexpected Exception %#lx\n",status);
  548. }
  549. #endif
  550. status = WN_BAD_POINTER;
  551. }
  552. return status;
  553. }
  554. DWORD
  555. StringParmToUnicodePass1 (
  556. IN LPCSTR StringParm,
  557. OUT PANSI_STRING AnsiString,
  558. OUT PUNICODE_STRING UnicodeString,
  559. IN OUT PULONG BufferOffset
  560. )
  561. /*++
  562. Routine Description:
  563. Helper function for InputParmsToUnicode.
  564. --*/
  565. {
  566. RtlInitAnsiString( AnsiString, StringParm );
  567. if (StringParm == NULL)
  568. {
  569. return WN_SUCCESS;
  570. }
  571. // Save the offset to the memory for this Unicode string, to be converted
  572. // to a pointer after the memory is allocated
  573. ULONG UnicodeLength = RtlAnsiStringToUnicodeSize( AnsiString );
  574. if (UnicodeLength > MAXUSHORT)
  575. {
  576. MPR_LOG(ERROR,
  577. "Unicode size of Ansi string parm is %lu, exceeds MAXUSHORT\n",
  578. UnicodeLength);
  579. return WN_BAD_VALUE;
  580. }
  581. UnicodeString->Buffer = (LPWSTR) UlongToPtr(*BufferOffset);
  582. UnicodeString->MaximumLength = (USHORT) UnicodeLength;
  583. *BufferOffset = ROUND_UP_TO_DWORD(*BufferOffset + UnicodeLength);
  584. return WN_SUCCESS;
  585. }
  586. DWORD
  587. StringParmToUnicodePass2 (
  588. IN OUT PANSI_STRING AnsiString,
  589. OUT PUNICODE_STRING UnicodeString,
  590. IN const BYTE * BufferStart,
  591. OUT LPWSTR * Result
  592. )
  593. /*++
  594. Routine Description:
  595. Helper function for InputParmsToUnicode.
  596. --*/
  597. {
  598. if (AnsiString->Buffer == NULL)
  599. {
  600. *Result = NULL;
  601. // NOTE: the UnicodeString is not initialized in this case
  602. return WN_SUCCESS;
  603. }
  604. // Convert the previously stored buffer offset into a pointer
  605. UnicodeString->Buffer = (LPWSTR)
  606. (BufferStart + (ULONG_PTR) UnicodeString->Buffer);
  607. ASSERT(IS_WCHAR_ALIGNED(UnicodeString->Buffer));
  608. // Convert the string to Unicode
  609. NTSTATUS ntstatus =
  610. RtlAnsiStringToUnicodeString(UnicodeString, AnsiString, FALSE);
  611. if (!NT_SUCCESS(ntstatus))
  612. {
  613. MPR_LOG(ERROR, "RtlAnsiStringToUnicodeString failed %#lx\n", ntstatus);
  614. return RtlNtStatusToDosError(ntstatus);
  615. }
  616. *Result = UnicodeString->Buffer;
  617. return WN_SUCCESS;
  618. }
  619. DWORD
  620. OutputBufferToAnsi(
  621. IN char BufferFormat,
  622. IN LPBYTE SourceBuffer,
  623. OUT LPVOID AnsiBuffer,
  624. IN OUT LPDWORD pcbBufferSize
  625. )
  626. /*++
  627. Routine Description:
  628. This function converts the data in the result buffer that was returned
  629. from a Unicode API into Ansi and stores it in the Ansi caller's result
  630. buffer. If the caller's buffer isn't large enough it saves the required
  631. size in *pcbBufferSize and returns WN_MORE_DATA.
  632. Nearly all the WNet APIs that have output buffers have only a single
  633. field in the output buffer, so this API takes only a single character,
  634. rather than a string, for the buffer format. APIs with more complicated
  635. output buffers should handle the complexity themselves, by directly
  636. calling the functions that this function calls.
  637. Arguments:
  638. BufferFormat - A character indicating the format of the SourceBuffer
  639. field. Recognized values are:
  640. 'S' - SourceBuffer contains a Unicode string. Convert it to Ansi
  641. and store the Ansi version in AnsiBuffer.
  642. 'N' - SourceBuffer contains a NETRESOURCEW with its associated
  643. strings. Convert it to Ansi and store the Ansi version in
  644. AnsiBuffer.
  645. SourceBuffer - The output buffer returned from a Unicode API.
  646. This must not be NULL.
  647. AnsiBuffer - The output buffer that the caller of the Ansi API supplied.
  648. This must not be NULL.
  649. pcbBufferSize - On entry, the size of AnsiBuffer in bytes. If the
  650. function returns WN_MORE_DATA, the required size is stored here;
  651. otherwise this is unmodified.
  652. This must not be NULL (must be a writeable DWORD pointer).
  653. Return Value:
  654. WN_SUCCESS - successful.
  655. WN_MORE_DATA - The buffer specified by AnsiBuffer and pcbBufferSize was
  656. not large enough to hold the converted data from SourceBuffer. In
  657. this case the required buffer size (in bytes) is written to
  658. *pcbBufferSize. The contents of AnsiBuffer are undefined (it will
  659. be partially filled).
  660. History:
  661. 16-Feb-1996 anirudhs Created.
  662. Notes:
  663. --*/
  664. {
  665. // Doesn't handle optional parameters for now
  666. ASSERT(SourceBuffer != NULL &&
  667. AnsiBuffer != NULL &&
  668. pcbBufferSize != NULL);
  669. ANSI_OUT_BUFFER Buf((LPBYTE) AnsiBuffer, *pcbBufferSize);
  670. DWORD status;
  671. switch (BufferFormat)
  672. {
  673. case 'S':
  674. status = OutputStringToAnsi((LPCWSTR) SourceBuffer, &Buf);
  675. break;
  676. case 'N':
  677. status = OutputNetResourceToAnsi((NETRESOURCEW *) SourceBuffer, &Buf);
  678. break;
  679. default:
  680. ASSERT(0);
  681. return ERROR_INVALID_LEVEL;
  682. }
  683. //
  684. // Map the results to the conventions followed by the WNet APIs
  685. //
  686. if (status == WN_SUCCESS)
  687. {
  688. if (Buf.Overflow())
  689. {
  690. *pcbBufferSize = Buf.GetUsage();
  691. status = WN_MORE_DATA;
  692. }
  693. }
  694. else
  695. {
  696. ASSERT(status != WN_MORE_DATA);
  697. }
  698. return status;
  699. }
  700. DWORD
  701. OutputStringToAnsi(
  702. IN LPCWSTR UnicodeIn,
  703. IN OUT ANSI_OUT_BUFFER * Buf
  704. )
  705. /*++
  706. Routine Description:
  707. This function converts a Unicode string to Ansi and calculates the number
  708. of bytes required to store it. If the caller passes a buffer that has
  709. enough remaining free space, it stores the Ansi data in the buffer.
  710. Otherwise it just increments the buffer's space usage by the number of
  711. bytes required.
  712. Arguments:
  713. UnicodeIn - A Unicode string to be converted to Ansi.
  714. This must not be NULL.
  715. Buf - A structure whose elements are interpreted as follows:
  716. _Start - Start address of a buffer to contain the Ansi data.
  717. This buffer must be writeable, or an exception will occur.
  718. _Size - The total size of the buffer for the Ansi data.
  719. _Used - On entry, the number of bytes in the buffer that have
  720. already been used. The function will begin writing data at
  721. _Start + _Used and will never write past the total size
  722. specified by _Size. If there is not enough room left
  723. in the buffer it will be partially filled or unmodified.
  724. On a successful return, _Used is incremented by the number
  725. of bytes that would be required to store the converted Ansi
  726. data, whether or not it was actually stored in the buffer.
  727. (This is done because the WNet APIs need to return the
  728. required buffer size if the caller's buffer was too small.)
  729. The use of this structure simplifies the writing of routines that
  730. use this function and need to convert multiple fields of Unicode
  731. data. Callers that need to convert only a single field can use
  732. OutputBufferToAnsi.
  733. Return Value:
  734. WN_SUCCESS - successful. The Ansi data was written to the buffer if
  735. Buf->_Used <= Buf->_Size. Otherwise, Buf->_Used was incremented
  736. without completely writing the data.
  737. Note that WN_MORE_DATA is never returned.
  738. History:
  739. 16-Feb-1996 anirudhs Created.
  740. Notes:
  741. --*/
  742. {
  743. NTSTATUS ntStatus;
  744. UNICODE_STRING unicodeString;
  745. ANSI_STRING ansiString;
  746. ASSERT(UnicodeIn != NULL); // Doesn't handle optional parameters for now
  747. //
  748. // Initialize the string structures
  749. //
  750. RtlInitUnicodeString(&unicodeString, UnicodeIn);
  751. ansiString.Buffer = (PCHAR) Buf->Next();
  752. ansiString.MaximumLength = (Buf->FreeSpace() > MAXUSHORT ?
  753. MAXUSHORT :
  754. (USHORT) Buf->FreeSpace()
  755. );
  756. //
  757. // Call the conversion function
  758. //
  759. ntStatus = RtlUnicodeStringToAnsiString (
  760. &ansiString, // Destination
  761. &unicodeString, // Source
  762. (BOOLEAN)FALSE); // Don't allocate the destination
  763. if (NT_SUCCESS(ntStatus))
  764. {
  765. // Add on the buffer space we used
  766. Buf->AddUsed(ansiString.Length + 1);
  767. ASSERT(! Buf->Overflow());
  768. return WN_SUCCESS;
  769. }
  770. else if (ntStatus == STATUS_BUFFER_OVERFLOW)
  771. {
  772. // We couldn't fit the string in the buffer, but still figure out
  773. // how much buffer space we would have used if we could
  774. Buf->AddUsed(RtlUnicodeStringToAnsiSize(&unicodeString));
  775. ASSERT(Buf->Overflow());
  776. return WN_SUCCESS;
  777. }
  778. else
  779. {
  780. MPR_LOG(ERROR, "RtlUnicodeStringToAnsiString failed %#lx\n", ntStatus);
  781. DWORD status = RtlNtStatusToDosError(ntStatus);
  782. ASSERT(status != WN_MORE_DATA);
  783. return status;
  784. }
  785. }
  786. DWORD
  787. OutputNetResourceToAnsi(
  788. IN NETRESOURCEW * lpNetResW,
  789. IN OUT ANSI_OUT_BUFFER * Buf
  790. )
  791. /*++
  792. Routine Description:
  793. This function converts a NETRESOURCEW and its associated Unicode strings
  794. to Ansi and returns the number of bytes required to store them. If the
  795. caller passes a buffer that has enough remaining free space, it stores
  796. the Ansi data in the buffer.
  797. Arguments:
  798. lpNetResW - A Unicode net resource to be converted to Ansi.
  799. This must not be NULL.
  800. Buf - same as OutputStringToAnsi.
  801. Return Value:
  802. Same as OutputStringToAnsi.
  803. History:
  804. 16-Feb-1996 anirudhs Created.
  805. Notes:
  806. --*/
  807. {
  808. //
  809. // Copy the fixed-size part of the structure, including NULL pointers,
  810. // and/or add on the buffer space it would take
  811. //
  812. LPNETRESOURCEA lpNetResA = (LPNETRESOURCEA) Buf->Next();
  813. if (Buf->HasRoomFor(sizeof(NETRESOURCEA)))
  814. {
  815. RtlCopyMemory(lpNetResA, lpNetResW, sizeof(NETRESOURCEA));
  816. }
  817. Buf->AddUsed(sizeof(NETRESOURCEA));
  818. //
  819. // Copy each non-NULL string field,
  820. // and/or add on the buffer space it would take
  821. //
  822. for (DWORD iField = 0;
  823. iField < NUMBER_OF_NETRESFIELD;
  824. iField++)
  825. {
  826. if (lpNetResW->*NRWField[iField] != NULL)
  827. {
  828. // Save a pointer to the Ansi string we are about to create
  829. // in the Ansi net resource
  830. lpNetResA->*NRAField[iField] = (LPSTR) Buf->Next();
  831. // Convert the string
  832. DWORD status = OutputStringToAnsi(lpNetResW->*NRWField[iField], Buf);
  833. if (status != WN_SUCCESS)
  834. {
  835. ASSERT(status != WN_MORE_DATA);
  836. return status;
  837. }
  838. }
  839. }
  840. return WN_SUCCESS;
  841. }
  842. DWORD
  843. OutputStringToAnsiInPlace(
  844. IN LPWSTR UnicodeIn
  845. )
  846. /*++
  847. Routine Description:
  848. This function converts a Unicode string to Ansi in place.
  849. This is the same as OutputStringToAnsi, optimized for in-place conversions.
  850. Arguments:
  851. UnicodeIn - A Unicode string to be converted to Ansi.
  852. This may be NULL, in which case the function does nothing.
  853. Return Value:
  854. WN_SUCCESS - successful.
  855. Note that WN_MORE_DATA is never returned.
  856. History:
  857. 08-Aug-1996 anirudhs Created.
  858. Notes:
  859. --*/
  860. {
  861. NTSTATUS ntStatus;
  862. UNICODE_STRING unicodeString;
  863. ANSI_STRING ansiString;
  864. if (UnicodeIn == NULL)
  865. {
  866. return WN_SUCCESS;
  867. }
  868. //
  869. // Initialize the string structures
  870. //
  871. RtlInitUnicodeString(&unicodeString, UnicodeIn);
  872. ansiString.Buffer = (PCHAR) UnicodeIn;
  873. ansiString.MaximumLength = unicodeString.MaximumLength;
  874. //
  875. // Call the conversion function
  876. //
  877. ntStatus = RtlUnicodeStringToAnsiString (
  878. &ansiString, // Destination
  879. &unicodeString, // Source
  880. (BOOLEAN)FALSE); // Don't allocate the destination
  881. ASSERT(ntStatus != STATUS_BUFFER_OVERFLOW);
  882. if (NT_SUCCESS(ntStatus))
  883. {
  884. return WN_SUCCESS;
  885. }
  886. else
  887. {
  888. MPR_LOG(ERROR, "RtlUnicodeStringToAnsiString failed %#lx\n", ntStatus);
  889. DWORD status = RtlNtStatusToDosError(ntStatus);
  890. ASSERT(status != WN_MORE_DATA);
  891. return status;
  892. }
  893. }
  894. //////////////////////////////////////////////////////////////////////////
  895. //////////////////////////////////////////////////////////////////////////
  896. DWORD APIENTRY
  897. WNetGetNetworkInformationA(
  898. IN LPCSTR lpProvider,
  899. IN OUT LPNETINFOSTRUCT lpNetInfoStruct
  900. )
  901. /*++
  902. Routine Description:
  903. Arguments:
  904. Return Value:
  905. --*/
  906. {
  907. ANSI_API_WITHOUT_ANSI_OUTPUT(
  908. 1,
  909. AParm[0].lpcstr = lpProvider; ,
  910. "S",
  911. WNetGetNetworkInformationW(UParm[0].lpwstr, lpNetInfoStruct);
  912. )
  913. }
  914. DWORD APIENTRY
  915. WNetGetProviderNameA(
  916. IN DWORD dwNetType,
  917. OUT LPSTR lpProviderName,
  918. IN OUT LPDWORD lpBufferSize
  919. )
  920. /*++
  921. Routine Description:
  922. Arguments:
  923. Return Value:
  924. --*/
  925. {
  926. ANSI_API_WITH_ANSI_OUTPUT(
  927. 2,
  928. AParm[0].lpvoid = lpProviderName;
  929. AParm[1].lpdword = lpBufferSize; ,
  930. "B",
  931. WNetGetProviderNameW(dwNetType, UParm[0].lpwstr, lpBufferSize); ,
  932. OutputBufferToAnsi('S', UParm[0].lpbyte, lpProviderName, lpBufferSize);
  933. )
  934. }
  935. DWORD
  936. WNetGetProviderTypeA(
  937. IN LPCSTR lpProvider,
  938. OUT LPDWORD lpdwNetType
  939. )
  940. /*++
  941. Routine Description:
  942. Arguments:
  943. Return Value:
  944. --*/
  945. {
  946. ANSI_API_WITHOUT_ANSI_OUTPUT(
  947. 1,
  948. AParm[0].lpcstr = lpProvider; ,
  949. "S",
  950. WNetGetProviderTypeW(UParm[0].lpwstr, lpdwNetType);
  951. )
  952. }
  953. DWORD APIENTRY
  954. WNetAddConnectionA (
  955. IN LPCSTR lpRemoteName,
  956. IN LPCSTR lpPassword,
  957. IN LPCSTR lpLocalName
  958. )
  959. /*++
  960. Routine Description:
  961. Arguments:
  962. Return Value:
  963. --*/
  964. {
  965. DWORD status;
  966. LPBYTE tempBuffer = NULL;
  967. ANSI_PARM AParm[3];
  968. UNICODE_PARM UParm[3];
  969. AParm[0].lpcstr = lpRemoteName;
  970. AParm[1].lpcstr = lpPassword;
  971. AParm[2].lpcstr = lpLocalName;
  972. UParm[1].lpwstr = NULL;
  973. status = InputParmsToUnicode("SSS", AParm, UParm, &tempBuffer);
  974. if (status == WN_SUCCESS)
  975. {
  976. status = WNetAddConnectionW(
  977. UParm[0].lpwstr,
  978. UParm[1].lpwstr,
  979. UParm[2].lpwstr
  980. );
  981. }
  982. MprClearString(UParm[1].lpwstr);
  983. LocalFree(tempBuffer);
  984. SET_AND_RETURN(status)
  985. }
  986. DWORD APIENTRY
  987. WNetAddConnection2A (
  988. IN LPNETRESOURCEA lpNetResource,
  989. IN LPCSTR lpPassword,
  990. IN LPCSTR lpUserName,
  991. IN DWORD dwFlags
  992. )
  993. /*++
  994. Routine Description:
  995. Arguments:
  996. Return Value:
  997. --*/
  998. {
  999. return (WNetUseConnectionA(
  1000. NULL,
  1001. lpNetResource,
  1002. lpPassword,
  1003. lpUserName,
  1004. dwFlags,
  1005. NULL,
  1006. NULL,
  1007. NULL
  1008. ));
  1009. }
  1010. DWORD APIENTRY
  1011. WNetAddConnection3A (
  1012. IN HWND hwndOwner,
  1013. IN LPNETRESOURCEA lpNetResource,
  1014. IN LPCSTR lpPassword,
  1015. IN LPCSTR lpUserName,
  1016. IN DWORD dwFlags
  1017. )
  1018. /*++
  1019. Routine Description:
  1020. Arguments:
  1021. Return Value:
  1022. --*/
  1023. {
  1024. return (WNetUseConnectionA(
  1025. hwndOwner,
  1026. lpNetResource,
  1027. lpPassword,
  1028. lpUserName,
  1029. dwFlags,
  1030. NULL,
  1031. NULL,
  1032. NULL
  1033. ));
  1034. }
  1035. DWORD APIENTRY
  1036. WNetUseConnectionA(
  1037. IN HWND hwndOwner,
  1038. IN LPNETRESOURCEA lpNetResource,
  1039. IN LPCSTR lpPassword,
  1040. IN LPCSTR lpUserID,
  1041. IN DWORD dwFlags,
  1042. OUT LPSTR lpAccessName OPTIONAL,
  1043. IN OUT LPDWORD lpBufferSize OPTIONAL, // Optional only if lpAccessName absent
  1044. OUT LPDWORD lpResult
  1045. )
  1046. /*++
  1047. Routine Description:
  1048. Arguments:
  1049. Return Value:
  1050. --*/
  1051. {
  1052. DWORD status;
  1053. LPBYTE tempBuffer = NULL;
  1054. ANSI_PARM AParm[5];
  1055. UNICODE_PARM UParm[5];
  1056. AParm[0].lpNetResA = lpNetResource;
  1057. AParm[1].lpcstr = lpPassword;
  1058. AParm[2].lpcstr = lpUserID;
  1059. AParm[3].lpvoid = lpAccessName;
  1060. AParm[4].lpdword = lpBufferSize;
  1061. UParm[1].lpwstr = NULL;
  1062. status = InputParmsToUnicode("N" NETRES_LRP "SSB", AParm, UParm, &tempBuffer);
  1063. if (status == WN_SUCCESS)
  1064. {
  1065. status = WNetUseConnectionW(
  1066. hwndOwner,
  1067. UParm[0].lpNetResW,
  1068. UParm[1].lpwstr,
  1069. UParm[2].lpwstr,
  1070. dwFlags,
  1071. UParm[3].lpwstr,
  1072. lpBufferSize,
  1073. lpResult
  1074. );
  1075. if (status == WN_SUCCESS)
  1076. {
  1077. if (ARGUMENT_PRESENT(lpAccessName))
  1078. {
  1079. //
  1080. // Note: At this point, we know that lpBufferSize is writeable.
  1081. //
  1082. status = OutputBufferToAnsi(
  1083. 'S', UParm[3].lpbyte, lpAccessName, lpBufferSize);
  1084. }
  1085. }
  1086. }
  1087. MprClearString(UParm[1].lpwstr);
  1088. LocalFree(tempBuffer);
  1089. SET_AND_RETURN(status)
  1090. }
  1091. DWORD APIENTRY
  1092. WNetCancelConnection2A (
  1093. IN LPCSTR lpName,
  1094. IN DWORD dwFlags,
  1095. IN BOOL fForce
  1096. )
  1097. /*++
  1098. Routine Description:
  1099. Arguments:
  1100. Return Value:
  1101. --*/
  1102. {
  1103. ANSI_API_WITHOUT_ANSI_OUTPUT(
  1104. 1,
  1105. AParm[0].lpcstr = lpName; ,
  1106. "S",
  1107. WNetCancelConnection2W(UParm[0].lpwstr, dwFlags, fForce);
  1108. )
  1109. }
  1110. DWORD APIENTRY
  1111. WNetCancelConnectionA (
  1112. IN LPCSTR lpName,
  1113. IN BOOL fForce
  1114. )
  1115. /*++
  1116. Routine Description:
  1117. This routine is provided for Win 3.1 compatibility.
  1118. Arguments:
  1119. Return Value:
  1120. --*/
  1121. {
  1122. return WNetCancelConnection2A( lpName, CONNECT_UPDATE_PROFILE, fForce ) ;
  1123. }
  1124. DWORD APIENTRY
  1125. WNetGetConnectionA (
  1126. IN LPCSTR lpLocalName,
  1127. OUT LPSTR lpRemoteName,
  1128. IN OUT LPDWORD lpnLength
  1129. )
  1130. /*++
  1131. Routine Description:
  1132. This function returns the RemoteName that is associated with a
  1133. LocalName (or drive letter).
  1134. Arguments:
  1135. lpLocalName - This is a pointer to the string that contains the LocalName.
  1136. lpRemoteName - This is a pointer to the buffer that will contain the
  1137. RemoteName string upon exit.
  1138. lpnLength - This is a pointer to the size (in characters) of the buffer
  1139. that is to be filled in with the RemoteName string. It is assumed
  1140. upon entry, that characters are all single byte characters.
  1141. If the buffer is too small and WN_MORE_DATA is returned, the data
  1142. at this location contains buffer size information - in number of
  1143. characters (bytes). This information indicates how large the buffer
  1144. should be (in bytes) to obtain the remote name. It is assumed that
  1145. all Unicode characteres translate into DBCS characters.
  1146. Return Value:
  1147. --*/
  1148. {
  1149. DWORD status;
  1150. LPBYTE tempBuffer = NULL;
  1151. ANSI_PARM AParm[3];
  1152. UNICODE_PARM UParm[3];
  1153. AParm[0].lpcstr = lpLocalName;
  1154. AParm[1].lpvoid = lpRemoteName;
  1155. AParm[2].lpdword = lpnLength;
  1156. status = InputParmsToUnicode("SB", AParm, UParm, &tempBuffer);
  1157. if (status == WN_SUCCESS)
  1158. {
  1159. status = WNetGetConnectionW(UParm[0].lpwstr, UParm[1].lpwstr, lpnLength);
  1160. if (status == WN_SUCCESS || status == WN_CONNECTION_CLOSED)
  1161. {
  1162. DWORD tempStatus =
  1163. OutputBufferToAnsi('S', UParm[1].lpbyte, lpRemoteName, lpnLength);
  1164. if (tempStatus != WN_SUCCESS)
  1165. {
  1166. status = tempStatus;
  1167. }
  1168. }
  1169. }
  1170. LocalFree(tempBuffer);
  1171. SET_AND_RETURN(status)
  1172. }
  1173. DWORD APIENTRY
  1174. WNetGetConnection2A (
  1175. IN LPSTR lpLocalName,
  1176. OUT LPVOID lpBuffer,
  1177. IN OUT LPDWORD lpnLength
  1178. )
  1179. /*++
  1180. Routine Description:
  1181. This function returns the RemoteName that is associated with a
  1182. LocalName (or drive letter) and the provider name that made the
  1183. connection.
  1184. Arguments:
  1185. lpLocalName - This is a pointer to the string that contains the LocalName.
  1186. lpBuffer - This is a pointer to the buffer that will contain the
  1187. WNET_CONNECTIONINFO structure upon exit.
  1188. lpnLength - This is a pointer to the size (in characters) of the buffer
  1189. that is to be filled in with the RemoteName string. It is assumed
  1190. upon entry, that characters are all single byte characters.
  1191. If the buffer is too small and WN_MORE_DATA is returned, the data
  1192. at this location contains buffer size information - in number of
  1193. characters (bytes). This information indicates how large the buffer
  1194. should be (in bytes) to obtain the remote name. It is assumed that
  1195. all Unicode characters translate into DBCS characters.
  1196. Return Value:
  1197. --*/
  1198. {
  1199. DWORD status;
  1200. LPBYTE tempBuffer = NULL;
  1201. ANSI_PARM AParm[4];
  1202. UNICODE_PARM UParm[4];
  1203. AParm[0].lpcstr = lpLocalName;
  1204. AParm[1].lpvoid = lpBuffer;
  1205. AParm[2].lpdword = lpnLength;
  1206. AParm[3].dword = sizeof(WNET_CONNECTIONINFO);
  1207. status = InputParmsToUnicode("SBs", AParm, UParm, &tempBuffer);
  1208. if (status == WN_SUCCESS)
  1209. {
  1210. status = WNetGetConnection2W(
  1211. UParm[0].lpwstr,
  1212. UParm[1].lpbyte,
  1213. &UParm[2].dword
  1214. );
  1215. if (status == WN_SUCCESS || status == WN_CONNECTION_CLOSED)
  1216. {
  1217. ANSI_OUT_BUFFER Buf((LPBYTE) lpBuffer, *lpnLength);
  1218. //
  1219. // Copy the fixed-size part of the structure, including NULL pointers,
  1220. // and/or add on the buffer space it would take
  1221. //
  1222. WNET_CONNECTIONINFOW * pconninfow = (WNET_CONNECTIONINFOW *) UParm[1].lpbyte;
  1223. WNET_CONNECTIONINFOA * pconninfoa = (WNET_CONNECTIONINFOA *) Buf.Next();
  1224. ASSERT(Buf.HasRoomFor(sizeof(WNET_CONNECTIONINFOA)));
  1225. RtlCopyMemory(pconninfoa, pconninfow, sizeof(WNET_CONNECTIONINFOA));
  1226. Buf.AddUsed(sizeof(WNET_CONNECTIONINFOA));
  1227. //
  1228. // Copy each non-NULL string field,
  1229. // and/or add on the buffer space it would take
  1230. //
  1231. DWORD tempStatus = WN_SUCCESS;
  1232. if (pconninfow->lpRemoteName != NULL)
  1233. {
  1234. pconninfoa->lpRemoteName = (LPSTR) Buf.Next();
  1235. tempStatus = OutputStringToAnsi(pconninfow->lpRemoteName, &Buf);
  1236. }
  1237. if (tempStatus == WN_SUCCESS &&
  1238. pconninfow->lpProvider != NULL)
  1239. {
  1240. pconninfoa->lpProvider = (LPSTR) Buf.Next();
  1241. tempStatus = OutputStringToAnsi(pconninfow->lpProvider, &Buf);
  1242. }
  1243. //
  1244. // Map the results to WNet API conventions
  1245. //
  1246. if (tempStatus != WN_SUCCESS)
  1247. {
  1248. status = tempStatus;
  1249. }
  1250. else if (Buf.Overflow())
  1251. {
  1252. *lpnLength = Buf.GetUsage();
  1253. status = WN_MORE_DATA;
  1254. }
  1255. }
  1256. else if (status == WN_MORE_DATA)
  1257. {
  1258. //
  1259. // Adjust the required buffer size for ansi/DBCS.
  1260. //
  1261. // We don't know how many characters will be required so we have to
  1262. // assume the worst case (all characters are DBCS characters).
  1263. //
  1264. *lpnLength = UParm[2].dword;
  1265. }
  1266. }
  1267. LocalFree(tempBuffer);
  1268. SET_AND_RETURN(status)
  1269. }
  1270. DWORD APIENTRY
  1271. WNetGetConnection3A(
  1272. IN LPCSTR lpLocalName,
  1273. IN LPCSTR lpProviderName OPTIONAL,
  1274. IN DWORD dwLevel,
  1275. OUT LPVOID lpBuffer,
  1276. IN OUT LPDWORD lpBufferSize // in bytes
  1277. )
  1278. /*++
  1279. Routine Description:
  1280. Arguments:
  1281. Return Value:
  1282. --*/
  1283. {
  1284. // For the only supported level, the output buffer is a DWORD, so no
  1285. // conversion of the output buffer is necessary
  1286. ANSI_API_WITHOUT_ANSI_OUTPUT(
  1287. 2,
  1288. AParm[0].lpcstr = lpLocalName;
  1289. AParm[1].lpcstr = lpProviderName; ,
  1290. "SS",
  1291. WNetGetConnection3W(
  1292. UParm[0].lpwstr,
  1293. UParm[1].lpwstr,
  1294. dwLevel,
  1295. lpBuffer,
  1296. lpBufferSize
  1297. );
  1298. )
  1299. }
  1300. DWORD
  1301. WNetGetUniversalNameA (
  1302. IN LPCSTR lpLocalPath,
  1303. IN DWORD dwInfoLevel,
  1304. OUT LPVOID lpBuffer,
  1305. IN OUT LPDWORD lpBufferSize
  1306. )
  1307. /*++
  1308. Routine Description:
  1309. Arguments:
  1310. Return Value:
  1311. --*/
  1312. {
  1313. DWORD status;
  1314. LPBYTE tempBuffer = NULL;
  1315. ANSI_PARM AParm[4];
  1316. UNICODE_PARM UParm[4];
  1317. DWORD dwStructSize =
  1318. (dwInfoLevel == UNIVERSAL_NAME_INFO_LEVEL) ? sizeof(UNIVERSAL_NAME_INFO) :
  1319. (dwInfoLevel == REMOTE_NAME_INFO_LEVEL) ? sizeof(REMOTE_NAME_INFO) :
  1320. 0;
  1321. AParm[0].lpcstr = lpLocalPath;
  1322. AParm[1].lpvoid = lpBuffer;
  1323. AParm[2].lpdword = lpBufferSize;
  1324. AParm[3].dword = dwStructSize;
  1325. status = InputParmsToUnicode("SBs", AParm, UParm, &tempBuffer);
  1326. if (status == WN_SUCCESS)
  1327. {
  1328. status = WNetGetUniversalNameW(
  1329. UParm[0].lpwstr,
  1330. dwInfoLevel,
  1331. UParm[1].lpbyte,
  1332. &UParm[2].dword
  1333. );
  1334. if (status == WN_SUCCESS || status == WN_CONNECTION_CLOSED)
  1335. {
  1336. DWORD tempStatus = WN_SUCCESS;
  1337. ANSI_OUT_BUFFER Buf((LPBYTE) lpBuffer, *lpBufferSize);
  1338. //
  1339. // Copy the fixed-size part of the structure, including NULL pointers,
  1340. // and/or add on the buffer space it would take
  1341. //
  1342. ASSERT(Buf.HasRoomFor(dwStructSize));
  1343. RtlCopyMemory(Buf.Next(), UParm[1].lpbyte, dwStructSize);
  1344. if (dwInfoLevel == REMOTE_NAME_INFO_LEVEL)
  1345. {
  1346. // -----------------------------------
  1347. // REMOTE_NAME_INFO_LEVEL
  1348. // -----------------------------------
  1349. LPREMOTE_NAME_INFOW pRemoteNameInfoW =
  1350. (LPREMOTE_NAME_INFOW) UParm[1].lpbyte;
  1351. LPREMOTE_NAME_INFOA pRemoteNameInfoA =
  1352. (LPREMOTE_NAME_INFOA) Buf.Next();
  1353. Buf.AddUsed(dwStructSize);
  1354. //
  1355. // Convert the returned Unicode string and string size back to
  1356. // ansi.
  1357. //
  1358. if (pRemoteNameInfoW->lpUniversalName != NULL)
  1359. {
  1360. pRemoteNameInfoA->lpUniversalName = (LPSTR) Buf.Next();
  1361. tempStatus = OutputStringToAnsi(pRemoteNameInfoW->lpUniversalName, &Buf);
  1362. }
  1363. if (tempStatus == WN_SUCCESS && pRemoteNameInfoW->lpConnectionName != NULL)
  1364. {
  1365. pRemoteNameInfoA->lpConnectionName = (LPSTR) Buf.Next();
  1366. tempStatus = OutputStringToAnsi(pRemoteNameInfoW->lpConnectionName, &Buf);
  1367. }
  1368. if (tempStatus == WN_SUCCESS && pRemoteNameInfoW->lpRemainingPath != NULL)
  1369. {
  1370. pRemoteNameInfoA->lpRemainingPath = (LPSTR) Buf.Next();
  1371. tempStatus = OutputStringToAnsi(pRemoteNameInfoW->lpRemainingPath, &Buf);
  1372. }
  1373. }
  1374. else
  1375. {
  1376. // -----------------------------------
  1377. // Must be UNIVERSAL_NAME_INFO_LEVEL
  1378. // -----------------------------------
  1379. ASSERT(dwInfoLevel == UNIVERSAL_NAME_INFO_LEVEL);
  1380. LPUNIVERSAL_NAME_INFOW pUniNameInfoW =
  1381. (LPUNIVERSAL_NAME_INFOW) UParm[1].lpbyte;
  1382. LPUNIVERSAL_NAME_INFOA pUniNameInfoA =
  1383. (LPUNIVERSAL_NAME_INFOA) Buf.Next();
  1384. Buf.AddUsed(dwStructSize);
  1385. //
  1386. // Convert the returned Unicode string and string size back to
  1387. // ansi.
  1388. //
  1389. if (pUniNameInfoW->lpUniversalName != NULL)
  1390. {
  1391. pUniNameInfoA->lpUniversalName = (LPSTR) Buf.Next();
  1392. tempStatus = OutputStringToAnsi(pUniNameInfoW->lpUniversalName, &Buf);
  1393. }
  1394. }
  1395. //
  1396. // Map the results to WNet API conventions
  1397. //
  1398. if (tempStatus != WN_SUCCESS)
  1399. {
  1400. status = tempStatus;
  1401. }
  1402. else if (Buf.Overflow())
  1403. {
  1404. *lpBufferSize = Buf.GetUsage();
  1405. status = WN_MORE_DATA;
  1406. }
  1407. }
  1408. else if (status == WN_MORE_DATA)
  1409. {
  1410. //
  1411. // Adjust the required buffer size for ansi/DBCS.
  1412. //
  1413. // We don't know how many characters will be required so we have to
  1414. // assume the worst case (all characters are DBCS characters).
  1415. //
  1416. *lpBufferSize = UParm[2].dword;
  1417. }
  1418. }
  1419. LocalFree(tempBuffer);
  1420. SET_AND_RETURN(status)
  1421. }
  1422. DWORD APIENTRY
  1423. WNetSetConnectionA(
  1424. IN LPCSTR lpName,
  1425. IN DWORD dwProperties,
  1426. IN OUT LPVOID pvValues
  1427. )
  1428. /*++
  1429. Routine Description:
  1430. Arguments:
  1431. Return Value:
  1432. --*/
  1433. {
  1434. //
  1435. // pvValues points to various types of structures depending on the value
  1436. // of dwProperties.
  1437. // Currently there is only one valid value for dwProperties, and its
  1438. // corresponding pvValues points to a DWORD, so we don't need to worry
  1439. // about converting pvValues to Unicode.
  1440. //
  1441. ANSI_API_WITHOUT_ANSI_OUTPUT(
  1442. 1,
  1443. AParm[0].lpcstr = lpName; ,
  1444. "S",
  1445. WNetSetConnectionW(UParm[0].lpwstr, dwProperties, pvValues);
  1446. )
  1447. }
  1448. DWORD APIENTRY
  1449. MultinetGetConnectionPerformanceA(
  1450. IN LPNETRESOURCEA lpNetResource,
  1451. OUT LPNETCONNECTINFOSTRUCT lpNetConnectInfoStruct
  1452. )
  1453. /*++
  1454. Routine Description:
  1455. Arguments:
  1456. Return Value:
  1457. --*/
  1458. {
  1459. ANSI_API_WITHOUT_ANSI_OUTPUT(
  1460. 1,
  1461. AParm[0].lpNetResA = lpNetResource; ,
  1462. "N" NETRES_LRP,
  1463. MultinetGetConnectionPerformanceW(
  1464. UParm[0].lpNetResW,
  1465. lpNetConnectInfoStruct);
  1466. )
  1467. }
  1468. DWORD APIENTRY
  1469. WNetOpenEnumA (
  1470. IN DWORD dwScope,
  1471. IN DWORD dwType,
  1472. IN DWORD dwUsage,
  1473. IN LPNETRESOURCEA lpNetResource,
  1474. OUT LPHANDLE lphEnum
  1475. )
  1476. /*++
  1477. Routine Description:
  1478. Arguments:
  1479. Return Value:
  1480. --*/
  1481. {
  1482. ANSI_API_WITHOUT_ANSI_OUTPUT(
  1483. 1,
  1484. AParm[0].lpNetResA = lpNetResource; ,
  1485. "N" NETRES_RP,
  1486. WNetOpenEnumW(dwScope, dwType, dwUsage, UParm[0].lpNetResW, lphEnum);
  1487. )
  1488. }
  1489. DWORD APIENTRY
  1490. WNetEnumResourceA (
  1491. IN HANDLE hEnum,
  1492. IN OUT LPDWORD lpcCount,
  1493. OUT LPVOID lpBuffer,
  1494. IN OUT LPDWORD lpBufferSize
  1495. )
  1496. /*++
  1497. Routine Description:
  1498. This function calls the unicode version of WNetEnumResource and
  1499. then converts the strings that are returned into ansi strings.
  1500. Since the user provided buffer is used to contain the unicode strings,
  1501. that buffer should be allocated with the size of unicode strings
  1502. in mind.
  1503. Arguments:
  1504. Return Value:
  1505. --*/
  1506. {
  1507. DWORD status = WNetEnumResourceW(
  1508. hEnum,
  1509. lpcCount,
  1510. lpBuffer,
  1511. lpBufferSize);
  1512. if (status == WN_SUCCESS)
  1513. {
  1514. //
  1515. // The output buffer contains an array of NETRESOURCEWs, plus strings.
  1516. // Convert the Unicode strings pointed to by these NETRESOURCEWs
  1517. // to Ansi strings, in place.
  1518. //
  1519. LPNETRESOURCEW lpNetResW = (LPNETRESOURCEW) lpBuffer;
  1520. for (DWORD i=0; i<*lpcCount; i++, lpNetResW++)
  1521. {
  1522. for (UINT iField = 0;
  1523. iField < NUMBER_OF_NETRESFIELD;
  1524. iField++)
  1525. {
  1526. if (lpNetResW->*NRWField[iField] != NULL)
  1527. {
  1528. status = OutputStringToAnsiInPlace(
  1529. lpNetResW->*NRWField[iField]);
  1530. if (status != WN_SUCCESS)
  1531. {
  1532. MPR_LOG0(ERROR,"WNetEnumResourceA: Couldn't convert all structs\n");
  1533. status = WN_SUCCESS;
  1534. *lpcCount = i;
  1535. break; // breaks out of both loops
  1536. }
  1537. }
  1538. }
  1539. }
  1540. }
  1541. SET_AND_RETURN(status)
  1542. }
  1543. DWORD APIENTRY
  1544. WNetGetResourceInformationA(
  1545. IN LPNETRESOURCEA lpNetResource,
  1546. OUT LPVOID lpBuffer,
  1547. IN OUT LPDWORD lpBufferSize,
  1548. OUT LPSTR * lplpSystem
  1549. )
  1550. {
  1551. DWORD status;
  1552. LPBYTE tempBuffer = NULL;
  1553. ANSI_PARM AParm[4];
  1554. UNICODE_PARM UParm[4];
  1555. AParm[0].lpNetResA = lpNetResource;
  1556. AParm[1].lpvoid = lpBuffer;
  1557. AParm[2].lpdword = lpBufferSize;
  1558. AParm[3].dword = sizeof(NETRESOURCE);
  1559. status = InputParmsToUnicode("N" NETRES_RP "Bs", AParm, UParm, &tempBuffer);
  1560. if (status == WN_SUCCESS)
  1561. {
  1562. status = WNetGetResourceInformationW(
  1563. UParm[0].lpNetResW,
  1564. UParm[1].lpbyte,
  1565. &UParm[2].dword,
  1566. (LPWSTR *) lplpSystem
  1567. );
  1568. if (status == WN_SUCCESS)
  1569. {
  1570. ANSI_OUT_BUFFER Buf((LPBYTE) lpBuffer, *lpBufferSize);
  1571. //
  1572. // Convert the Unicode netresource returned to Ansi
  1573. //
  1574. status = OutputNetResourceToAnsi(UParm[1].lpNetResW, &Buf);
  1575. if (status == WN_SUCCESS)
  1576. {
  1577. //
  1578. // Convert the Unicode string (*lplpSystem) returned to Ansi
  1579. //
  1580. LPWSTR lpSystemW = * (LPWSTR *) lplpSystem;
  1581. if (lpSystemW != NULL)
  1582. {
  1583. *lplpSystem = (LPSTR) Buf.Next();
  1584. status = OutputStringToAnsi(lpSystemW, &Buf);
  1585. }
  1586. }
  1587. //
  1588. // Map the results to WNet API conventions
  1589. //
  1590. if (status == WN_SUCCESS && Buf.Overflow())
  1591. {
  1592. *lpBufferSize = Buf.GetUsage();
  1593. status = WN_MORE_DATA;
  1594. }
  1595. }
  1596. else if (status == WN_MORE_DATA)
  1597. {
  1598. //
  1599. // Adjust the required buffer size for ansi/DBCS.
  1600. //
  1601. // We don't know how many characters will be required so we have to
  1602. // assume the worst case (all characters are DBCS characters).
  1603. //
  1604. *lpBufferSize = UParm[2].dword;
  1605. }
  1606. }
  1607. LocalFree(tempBuffer);
  1608. SET_AND_RETURN(status)
  1609. }
  1610. DWORD APIENTRY
  1611. WNetGetResourceParentA(
  1612. IN LPNETRESOURCEA lpNetResource,
  1613. OUT LPVOID lpBuffer,
  1614. IN OUT LPDWORD lpBufferSize
  1615. )
  1616. {
  1617. DWORD status;
  1618. LPBYTE tempBuffer = NULL;
  1619. ANSI_PARM AParm[4];
  1620. UNICODE_PARM UParm[4];
  1621. AParm[0].lpNetResA = lpNetResource;
  1622. AParm[1].lpvoid = lpBuffer;
  1623. AParm[2].lpdword = lpBufferSize;
  1624. AParm[3].dword = sizeof(NETRESOURCE);
  1625. status = InputParmsToUnicode("N" NETRES_RP "Bs", AParm, UParm, &tempBuffer);
  1626. if (status == WN_SUCCESS)
  1627. {
  1628. status = WNetGetResourceParentW(
  1629. UParm[0].lpNetResW,
  1630. UParm[1].lpbyte,
  1631. &UParm[2].dword
  1632. );
  1633. if (status == WN_SUCCESS)
  1634. {
  1635. //
  1636. // Convert the Unicode netresource returned to Ansi
  1637. //
  1638. status = OutputBufferToAnsi('N', UParm[1].lpbyte, lpBuffer, lpBufferSize);
  1639. }
  1640. else if (status == WN_MORE_DATA)
  1641. {
  1642. //
  1643. // Adjust the required buffer size for ansi/DBCS.
  1644. //
  1645. // We don't know how many characters will be required so we have to
  1646. // assume the worst case (all characters are DBCS characters).
  1647. //
  1648. *lpBufferSize = UParm[2].dword;
  1649. }
  1650. }
  1651. LocalFree(tempBuffer);
  1652. SET_AND_RETURN(status)
  1653. }
  1654. DWORD APIENTRY
  1655. WNetGetUserA (
  1656. IN LPCSTR lpName,
  1657. OUT LPSTR lpUserName,
  1658. IN OUT LPDWORD lpnLength
  1659. )
  1660. /*++
  1661. Routine Description:
  1662. This function retreives the current default user name or the username
  1663. used to establish a network connection.
  1664. Arguments:
  1665. lpName - Points to a null-terminated string that specifies either the
  1666. name or the local device to return the user name for, or a network
  1667. name that the user has made a connection to. If the pointer is
  1668. NULL, the name of the current user is returned.
  1669. lpUserName - Points to a buffer to receive the null-terminated
  1670. user name.
  1671. lpnLength - Specifies the size (in characters) of the buffer pointed
  1672. to by the lpUserName parameter. If the call fails because the
  1673. buffer is not big enough, this location is used to return the
  1674. required buffer size.
  1675. Return Value:
  1676. --*/
  1677. {
  1678. ANSI_API_WITH_ANSI_OUTPUT(
  1679. 3,
  1680. AParm[0].lpcstr = lpName;
  1681. AParm[1].lpvoid = lpUserName;
  1682. AParm[2].lpdword = lpnLength; ,
  1683. "SB",
  1684. WNetGetUserW(UParm[0].lpwstr, UParm[1].lpwstr, lpnLength); ,
  1685. OutputBufferToAnsi('S', UParm[1].lpbyte, lpUserName, lpnLength);
  1686. )
  1687. }
  1688. DWORD
  1689. RestoreConnectionA0 (
  1690. IN HWND hwnd,
  1691. IN LPSTR lpDevice
  1692. )
  1693. /*++
  1694. Routine Description:
  1695. Arguments:
  1696. Return Value:
  1697. --*/
  1698. {
  1699. ANSI_API_WITHOUT_ANSI_OUTPUT(
  1700. 1,
  1701. AParm[0].lpcstr = lpDevice; ,
  1702. "S",
  1703. WNetRestoreConnectionW(hwnd, UParm[0].lpwstr);
  1704. )
  1705. }
  1706. DWORD
  1707. RestoreConnection2A0 (
  1708. IN HWND hwnd,
  1709. IN LPSTR lpDevice,
  1710. IN DWORD dwFlags,
  1711. OUT BOOL* pfReconnectFailed
  1712. )
  1713. /*++
  1714. Routine Description:
  1715. Arguments:
  1716. Return Value:
  1717. --*/
  1718. {
  1719. ANSI_API_WITHOUT_ANSI_OUTPUT(
  1720. 1,
  1721. AParm[0].lpcstr = lpDevice; ,
  1722. "S",
  1723. WNetRestoreConnection2W(hwnd, UParm[0].lpwstr, dwFlags, pfReconnectFailed);
  1724. )
  1725. }
  1726. DWORD
  1727. WNetGetDirectoryTypeA (
  1728. IN LPSTR lpName,
  1729. OUT LPINT lpType,
  1730. IN BOOL bFlushCache
  1731. )
  1732. /*++
  1733. Routine Description:
  1734. Arguments:
  1735. Return Value:
  1736. --*/
  1737. {
  1738. ANSI_API_WITHOUT_ANSI_OUTPUT(
  1739. 1,
  1740. AParm[0].lpcstr = lpName; ,
  1741. "S",
  1742. WNetGetDirectoryTypeW(UParm[0].lpwstr, lpType, bFlushCache);
  1743. )
  1744. }
  1745. DWORD
  1746. WNetDirectoryNotifyA (
  1747. IN HWND hwnd,
  1748. IN LPSTR lpDir,
  1749. IN DWORD dwOper
  1750. )
  1751. /*++
  1752. Routine Description:
  1753. Arguments:
  1754. Return Value:
  1755. --*/
  1756. {
  1757. ANSI_API_WITHOUT_ANSI_OUTPUT(
  1758. 1,
  1759. AParm[0].lpcstr = lpDir; ,
  1760. "S",
  1761. WNetDirectoryNotifyW(hwnd, UParm[0].lpwstr, dwOper);
  1762. )
  1763. }
  1764. DWORD APIENTRY
  1765. WNetGetLastErrorA (
  1766. OUT LPDWORD lpError,
  1767. OUT LPSTR lpErrorBuf,
  1768. IN DWORD nErrorBufSize,
  1769. OUT LPSTR lpNameBuf,
  1770. IN DWORD nNameBufSize
  1771. )
  1772. /*++
  1773. Routine Description:
  1774. Arguments:
  1775. Return Value:
  1776. --*/
  1777. {
  1778. DWORD status;
  1779. //
  1780. // We re-use the Ansi buffers for the Unicode API.
  1781. // There are no input Ansi parameters to convert to Unicode.
  1782. //
  1783. // Call the Unicode version of the function.
  1784. // Note: The sizes for the buffers that are passed in assume that
  1785. // the returned unicode strings will return DBCS characters.
  1786. //
  1787. status = WNetGetLastErrorW(
  1788. lpError,
  1789. (LPWSTR) lpErrorBuf,
  1790. nErrorBufSize / sizeof(WCHAR),
  1791. (LPWSTR) lpNameBuf,
  1792. nNameBufSize / sizeof(WCHAR)
  1793. );
  1794. //
  1795. // Convert the returned strings to Ansi, in place.
  1796. // There should be no buffer overflow.
  1797. //
  1798. if (status == WN_SUCCESS)
  1799. {
  1800. status = OutputStringToAnsiInPlace((LPWSTR) lpErrorBuf);
  1801. if (status == WN_SUCCESS)
  1802. {
  1803. status = OutputStringToAnsiInPlace((LPWSTR) lpNameBuf);
  1804. }
  1805. }
  1806. SET_AND_RETURN(status)
  1807. }
  1808. VOID
  1809. WNetSetLastErrorA(
  1810. IN DWORD err,
  1811. IN LPSTR lpError,
  1812. IN LPSTR lpProviders
  1813. )
  1814. /*++
  1815. Routine Description:
  1816. Arguments:
  1817. Return Value:
  1818. --*/
  1819. {
  1820. DWORD status;
  1821. LPBYTE tempBuffer = NULL;
  1822. ANSI_PARM AParm[2];
  1823. UNICODE_PARM UParm[2];
  1824. AParm[0].lpcstr = lpError;
  1825. AParm[1].lpcstr = lpProviders;
  1826. status = InputParmsToUnicode("SS", AParm, UParm, &tempBuffer);
  1827. if (status != WN_SUCCESS)
  1828. {
  1829. UParm[0].lpwstr = NULL;
  1830. UParm[1].lpwstr = NULL;
  1831. }
  1832. WNetSetLastErrorW(err, UParm[0].lpwstr, UParm[1].lpwstr);
  1833. LocalFree(tempBuffer);
  1834. return;
  1835. }
  1836. DWORD APIENTRY
  1837. MultinetGetErrorTextA(
  1838. OUT LPSTR lpErrorTextBuf OPTIONAL,
  1839. IN OUT LPDWORD lpnErrorBufSize OPTIONAL,
  1840. OUT LPSTR lpProviderNameBuf OPTIONAL,
  1841. IN OUT LPDWORD lpnNameBufSize OPTIONAL
  1842. )
  1843. /*++
  1844. Routine Description:
  1845. Arguments:
  1846. Return Value:
  1847. --*/
  1848. {
  1849. // CODEWORK: This could be simplified by re-using the Unicode buffers,
  1850. // like WNetGetLastErrorA.
  1851. DWORD status;
  1852. LPBYTE tempBuffer = NULL;
  1853. ANSI_PARM AParm[4];
  1854. UNICODE_PARM UParm[4];
  1855. AParm[0].lpvoid = lpErrorTextBuf;
  1856. AParm[1].lpdword = lpnErrorBufSize;
  1857. AParm[2].lpvoid = lpProviderNameBuf;
  1858. AParm[3].lpdword = lpnNameBufSize;
  1859. status = InputParmsToUnicode("BB", AParm, UParm, &tempBuffer);
  1860. if (status == WN_SUCCESS)
  1861. {
  1862. // Remember the sizes before calling the function
  1863. DWORD nErrorBufSize;
  1864. DWORD nNameBufSize;
  1865. if (ARGUMENT_PRESENT(lpErrorTextBuf))
  1866. {
  1867. nErrorBufSize = *lpnErrorBufSize;
  1868. }
  1869. if (ARGUMENT_PRESENT(lpProviderNameBuf))
  1870. {
  1871. nNameBufSize = *lpnNameBufSize;
  1872. }
  1873. status = MultinetGetErrorTextW(
  1874. UParm[0].lpwstr,
  1875. lpnErrorBufSize,
  1876. UParm[2].lpwstr,
  1877. lpnNameBufSize
  1878. );
  1879. if (status == WN_SUCCESS || status == WN_MORE_DATA)
  1880. {
  1881. if (ARGUMENT_PRESENT(lpErrorTextBuf) &&
  1882. nErrorBufSize == *lpnErrorBufSize)
  1883. {
  1884. // The Unicode API must have written the error text buffer
  1885. DWORD status2 = OutputBufferToAnsi(
  1886. 'S',
  1887. UParm[0].lpbyte,
  1888. lpErrorTextBuf,
  1889. lpnErrorBufSize);
  1890. if (status2 != WN_SUCCESS)
  1891. {
  1892. status = status2;
  1893. }
  1894. }
  1895. }
  1896. if (status == WN_SUCCESS || status == WN_MORE_DATA)
  1897. {
  1898. if (ARGUMENT_PRESENT(lpProviderNameBuf) &&
  1899. nNameBufSize == *lpnNameBufSize)
  1900. {
  1901. // The Unicode API must have written the provider name buffer
  1902. DWORD status2 = OutputBufferToAnsi(
  1903. 'S',
  1904. UParm[2].lpbyte,
  1905. lpProviderNameBuf,
  1906. lpnNameBufSize);
  1907. if (status2 != WN_SUCCESS)
  1908. {
  1909. status = status2;
  1910. }
  1911. }
  1912. }
  1913. }
  1914. LocalFree(tempBuffer);
  1915. SET_AND_RETURN(status)
  1916. }
  1917. DWORD
  1918. WNetPropertyDialogA (
  1919. HWND hwndParent,
  1920. DWORD iButton,
  1921. DWORD nPropSel,
  1922. LPSTR lpszName,
  1923. DWORD nType
  1924. )
  1925. /*++
  1926. Routine Description:
  1927. Arguments:
  1928. Return Value:
  1929. --*/
  1930. {
  1931. ANSI_API_WITHOUT_ANSI_OUTPUT(
  1932. 1,
  1933. AParm[0].lpcstr = lpszName; ,
  1934. "S",
  1935. WNetPropertyDialogW(hwndParent, iButton, nPropSel, UParm[0].lpwstr, nType);
  1936. )
  1937. }
  1938. DWORD
  1939. WNetGetPropertyTextA (
  1940. IN DWORD iButton,
  1941. IN DWORD nPropSel,
  1942. IN LPSTR lpszName,
  1943. OUT LPSTR lpszButtonName,
  1944. IN DWORD nButtonNameLen,
  1945. IN DWORD nType
  1946. )
  1947. /*++
  1948. Routine Description:
  1949. Arguments:
  1950. Return Value:
  1951. --*/
  1952. {
  1953. ANSI_API_WITH_ANSI_OUTPUT(
  1954. 3,
  1955. AParm[0].lpcstr = lpszName;
  1956. AParm[1].lpvoid = lpszButtonName;
  1957. AParm[2].lpdword = &nButtonNameLen; ,
  1958. "SB",
  1959. WNetGetPropertyTextW(iButton, nPropSel, UParm[0].lpwstr,
  1960. UParm[1].lpwstr, nButtonNameLen, nType); ,
  1961. OutputBufferToAnsi('S', UParm[1].lpbyte, lpszButtonName, &nButtonNameLen);
  1962. )
  1963. }
  1964. DWORD APIENTRY
  1965. WNetFormatNetworkNameA(
  1966. IN LPCSTR lpProvider,
  1967. IN LPCSTR lpRemoteName,
  1968. OUT LPSTR lpFormattedName,
  1969. IN OUT LPDWORD lpnLength, // In characters!
  1970. IN DWORD dwFlags,
  1971. IN DWORD dwAveCharPerLine
  1972. )
  1973. /*++
  1974. Routine Description:
  1975. Arguments:
  1976. Return Value:
  1977. --*/
  1978. {
  1979. ANSI_API_WITH_ANSI_OUTPUT(
  1980. 4,
  1981. AParm[0].lpcstr = lpProvider;
  1982. AParm[1].lpcstr = lpRemoteName;
  1983. AParm[2].lpvoid = lpFormattedName;
  1984. AParm[3].lpdword = lpnLength; ,
  1985. "SSB",
  1986. WNetFormatNetworkNameW(
  1987. UParm[0].lpwstr,
  1988. UParm[1].lpwstr,
  1989. UParm[2].lpwstr,
  1990. lpnLength,
  1991. dwFlags,
  1992. dwAveCharPerLine
  1993. ); ,
  1994. OutputBufferToAnsi('S', UParm[2].lpbyte, lpFormattedName, lpnLength);
  1995. )
  1996. }