2516 lines
68 KiB
C++
2516 lines
68 KiB
C++
/*++
|
||
|
||
Copyright (c) 1991 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
mpransi.cxx
|
||
|
||
Abstract:
|
||
|
||
Contains Ansi Entry points for the MPR api.
|
||
|
||
Author:
|
||
|
||
Dan Lafferty (danl) 20-Dec-1991
|
||
|
||
Environment:
|
||
|
||
User Mode -Win32
|
||
|
||
Notes:
|
||
|
||
I may want to add a buffer size parameter to ConvertToAnsi
|
||
|
||
Revision History:
|
||
|
||
08-Aug-1996 anirudhs
|
||
Major revision (simplification): Converted all remaining APIs to
|
||
the smaller, faster interpreted scheme. Added ANSI_API_ macros.
|
||
Eliminated helper functions used by the old scheme. These changes
|
||
shrink this file by about 1400 lines.
|
||
16-Feb-1996 anirudhs
|
||
Added InputParmsToUnicode, OutputBufferToAnsi and helper functions.
|
||
These form a smaller, faster, interpreted scheme for writing the
|
||
Ansi APIs. This scheme is smaller chiefly because it eliminates
|
||
a very large amount of code duplication present in the previous
|
||
scheme. This also makes the Ansi APIs less bug-prone. It is
|
||
faster chiefly because intermediate storage is allocated with a
|
||
single heap allocation per API, rather than several. Also, the
|
||
number of passes to scan and copy data is minimized.
|
||
06-Oct-1995 anirudhs
|
||
MprMakeUnicodeNetRes and related functions: Removed duplicated
|
||
code for the string fields of the net resource; added code to
|
||
iterate over the string fields instead. Fixed access violation
|
||
and memory leaks.
|
||
24-Aug-1992 danl
|
||
For WNetGetConnection & WNetGetUser, we allocate a buffer twice
|
||
the size of the user buffer. The data is placed in this buffer.
|
||
Then we check to see if the data will fit in the user buffer
|
||
after it is translated to Ansi. The presence of DBSC characters
|
||
may make it not fit. In which case, we return the required number
|
||
of bytes. This number assumes worse-case where all characters are
|
||
DBCS characters.
|
||
20-Dec-1991 danl
|
||
created
|
||
|
||
--*/
|
||
|
||
//
|
||
// INCLUDES
|
||
//
|
||
|
||
#include "precomp.hxx"
|
||
#include <string.h> // strlen
|
||
#include <tstring.h> // STRLEN
|
||
|
||
|
||
//
|
||
// CONSTANTS
|
||
//
|
||
|
||
#define MAX_STRINGS_PER_API 6
|
||
|
||
//
|
||
// The following masks are used to indicate which fields in the NetResource
|
||
// structure are used by an API.
|
||
// The values must match the NRWField and NRAField arrays.
|
||
//
|
||
#define NETRESFIELD_LOCALNAME 0x00000001
|
||
#define NETRESFIELD_REMOTENAME 0x00000002
|
||
#define NETRESFIELD_COMMENT 0x00000004
|
||
#define NETRESFIELD_PROVIDER 0x00000008
|
||
|
||
#define NUMBER_OF_NETRESFIELD 4
|
||
|
||
//
|
||
// Combinations of the NETRESFIELD_ constants, for passing to InputParmsToUnicode.
|
||
//
|
||
#define NETRES_LRP "\xB" // local name, remote name, provider
|
||
#define NETRES_RP "\xA" // remote name, provider
|
||
|
||
//
|
||
// Alignment macros
|
||
// These macros assume that sizeof(WCHAR) and sizeof(DWORD) are powers of 2
|
||
//
|
||
#define ROUND_UP_TO_WCHAR(x) (((DWORD)(x) + sizeof(WCHAR) - 1) & ~(sizeof(WCHAR) - 1))
|
||
#define ROUND_UP_TO_DWORD(x) (((DWORD)(x) + sizeof(DWORD) - 1) & ~(sizeof(DWORD) - 1))
|
||
#define IS_WCHAR_ALIGNED(x) (((ULONG_PTR)(x) & (sizeof(WCHAR) - 1)) == 0)
|
||
#define IS_DWORD_ALIGNED(x) (((ULONG_PTR)(x) & (sizeof(DWORD) - 1)) == 0)
|
||
|
||
//
|
||
// Nearly every API ends this way
|
||
//
|
||
#define SET_AND_RETURN(status) \
|
||
if (status != NO_ERROR) \
|
||
{ \
|
||
SetLastError(status); \
|
||
} \
|
||
\
|
||
return status;
|
||
|
||
//
|
||
// This is the general pattern of an Ansi wrapper for an API with no
|
||
// output Ansi parameters. There are some exceptions.
|
||
//
|
||
#define ANSI_API_WITHOUT_ANSI_OUTPUT(NUMBER_OF_PARMS, \
|
||
ANSI_PARM_ASSIGNMENT, \
|
||
INSTRUCTION_STRING, \
|
||
UNICODE_CALL) \
|
||
\
|
||
DWORD status; \
|
||
LPBYTE tempBuffer = NULL; \
|
||
ANSI_PARM AParm[NUMBER_OF_PARMS]; \
|
||
UNICODE_PARM UParm[NUMBER_OF_PARMS]; \
|
||
\
|
||
ANSI_PARM_ASSIGNMENT \
|
||
\
|
||
status = InputParmsToUnicode(INSTRUCTION_STRING, AParm, UParm, &tempBuffer); \
|
||
\
|
||
if (status == WN_SUCCESS) \
|
||
{ \
|
||
status = UNICODE_CALL \
|
||
} \
|
||
\
|
||
LocalFree(tempBuffer); \
|
||
\
|
||
SET_AND_RETURN(status)
|
||
|
||
|
||
|
||
//
|
||
// This is the general pattern of an Ansi wrapper for an API that
|
||
// has output Ansi parameters. There are some exceptions.
|
||
//
|
||
#define ANSI_API_WITH_ANSI_OUTPUT(NUMBER_OF_PARMS, \
|
||
ANSI_PARM_ASSIGNMENT, \
|
||
INSTRUCTION_STRING, \
|
||
UNICODE_CALL, \
|
||
OUTPUT_CALL) \
|
||
\
|
||
DWORD status; \
|
||
LPBYTE tempBuffer = NULL; \
|
||
ANSI_PARM AParm[NUMBER_OF_PARMS]; \
|
||
UNICODE_PARM UParm[NUMBER_OF_PARMS]; \
|
||
\
|
||
ANSI_PARM_ASSIGNMENT \
|
||
\
|
||
status = InputParmsToUnicode(INSTRUCTION_STRING, AParm, UParm, &tempBuffer); \
|
||
\
|
||
if (status == WN_SUCCESS) \
|
||
{ \
|
||
status = UNICODE_CALL \
|
||
\
|
||
if (status == WN_SUCCESS) \
|
||
{ \
|
||
status = OUTPUT_CALL \
|
||
} \
|
||
} \
|
||
\
|
||
LocalFree(tempBuffer); \
|
||
\
|
||
SET_AND_RETURN(status)
|
||
|
||
|
||
|
||
//
|
||
// STRUCTURES
|
||
//
|
||
|
||
// These unions are defined so that parameters of various types can be passed
|
||
// to the generic routine InputParmsToUnicode.
|
||
// CODEWORK: By using these unions, we have lost type safety, and this could
|
||
// cause some bugs to go undetected. To get back type safety, ANSI_PARM and
|
||
// UNICODE_PARM could be made into "smart union" classes, with overloaded
|
||
// assignment and cast operators that, in the checked build, remember the
|
||
// type of the data that they are assigned, and assert if they are used as
|
||
// any other type of data.
|
||
// This would also make the code neater by allowing initializers like
|
||
// ANSI_PARM AParm[] = { lpName, lpUserName, lpnLength };
|
||
|
||
typedef union
|
||
{
|
||
DWORD dword;
|
||
LPCSTR lpcstr;
|
||
LPNETRESOURCEA lpNetResA;
|
||
LPVOID lpvoid;
|
||
LPDWORD lpdword;
|
||
} ANSI_PARM;
|
||
|
||
typedef union
|
||
{
|
||
DWORD dword;
|
||
LPBYTE lpbyte;
|
||
LPWSTR lpwstr;
|
||
LPNETRESOURCEW lpNetResW;
|
||
} UNICODE_PARM;
|
||
|
||
|
||
class ANSI_OUT_BUFFER
|
||
{
|
||
private:
|
||
const LPBYTE _Start; // Pointer to start of buffer
|
||
const DWORD _Size; // Total number of bytes in buffer
|
||
DWORD _Used; // Number of bytes used (may exceed Size)
|
||
|
||
public:
|
||
|
||
ANSI_OUT_BUFFER(LPBYTE Start, DWORD Size) :
|
||
_Start(Start),
|
||
_Size (Size),
|
||
_Used (0)
|
||
{ }
|
||
|
||
BYTE * Next() const
|
||
{ return _Start + _Used; }
|
||
|
||
BOOL Overflow() const
|
||
{ return (_Used > _Size); }
|
||
|
||
DWORD FreeSpace() const
|
||
{ return (Overflow() ? 0 : _Size - _Used); }
|
||
|
||
BOOL HasRoomFor(DWORD Request) const
|
||
{ return (_Used + Request <= _Size); }
|
||
|
||
void AddUsed(DWORD Request)
|
||
{ _Used += Request; }
|
||
|
||
DWORD GetUsage() const
|
||
{ return _Used; }
|
||
};
|
||
|
||
//
|
||
// STATIC DATA
|
||
//
|
||
|
||
//
|
||
// These arrays of members are used to iterate through the string fields
|
||
// of a net resource.
|
||
// The order must match the NETRESFIELD_ definitions.
|
||
//
|
||
|
||
LPWSTR NETRESOURCEW::* const NRWField[NUMBER_OF_NETRESFIELD] =
|
||
{
|
||
&NETRESOURCEW::lpLocalName,
|
||
&NETRESOURCEW::lpRemoteName,
|
||
&NETRESOURCEW::lpComment,
|
||
&NETRESOURCEW::lpProvider
|
||
};
|
||
|
||
LPSTR NETRESOURCEA::* const NRAField[NUMBER_OF_NETRESFIELD] =
|
||
{
|
||
&NETRESOURCEA::lpLocalName,
|
||
&NETRESOURCEA::lpRemoteName,
|
||
&NETRESOURCEA::lpComment,
|
||
&NETRESOURCEA::lpProvider
|
||
};
|
||
|
||
|
||
//
|
||
// Local Functions
|
||
//
|
||
|
||
DWORD
|
||
InputParmsToUnicode(
|
||
IN LPCSTR Instructions,
|
||
IN const ANSI_PARM InputParms[],
|
||
OUT UNICODE_PARM OutputParms[],
|
||
OUT LPBYTE * ppBuffer
|
||
);
|
||
|
||
DWORD
|
||
StringParmToUnicodePass1(
|
||
IN LPCSTR StringParm,
|
||
OUT PANSI_STRING AnsiString,
|
||
OUT PUNICODE_STRING UnicodeString,
|
||
IN OUT PULONG BufferOffset
|
||
);
|
||
|
||
DWORD
|
||
StringParmToUnicodePass2(
|
||
IN OUT PANSI_STRING AnsiString,
|
||
OUT PUNICODE_STRING UnicodeString,
|
||
IN const BYTE * BufferStart,
|
||
OUT LPWSTR * Result
|
||
);
|
||
|
||
DWORD
|
||
OutputBufferToAnsi(
|
||
IN char BufferFormat,
|
||
IN LPBYTE SourceBuffer,
|
||
OUT LPVOID AnsiBuffer,
|
||
IN OUT LPDWORD pcbBufferSize
|
||
);
|
||
|
||
DWORD
|
||
OutputStringToAnsi(
|
||
IN LPCWSTR UnicodeIn,
|
||
IN OUT ANSI_OUT_BUFFER * Buf
|
||
);
|
||
|
||
DWORD
|
||
OutputStringToAnsiInPlace(
|
||
IN LPWSTR UnicodeIn
|
||
);
|
||
|
||
DWORD
|
||
OutputNetResourceToAnsi(
|
||
IN NETRESOURCEW * lpNetResW,
|
||
IN OUT ANSI_OUT_BUFFER * Buf
|
||
);
|
||
|
||
|
||
|
||
DWORD
|
||
InputParmsToUnicode(
|
||
IN LPCSTR Instructions,
|
||
IN const ANSI_PARM InputParms[],
|
||
OUT UNICODE_PARM OutputParms[],
|
||
OUT LPBYTE * ppBuffer
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function converts the caller's input parameters to Unicode.
|
||
If necessary, it allocates one temporary buffer in which it stores
|
||
the intermediate Unicode parameters. This minimizes the cost of
|
||
calls to LocalAlloc.
|
||
|
||
Arguments:
|
||
|
||
Instructions - A string of characters, roughly one for each member
|
||
of the InputParms array, describing the action to be taken on each
|
||
InputParms member. Recognized values for the characters are:
|
||
|
||
'S' (String) - InputParms member is an LPSTR to be converted to
|
||
Unicode. Store a pointer to the Unicode string in the
|
||
corresponding OutputParms member.
|
||
|
||
'N' (NetResource) - InputParms member is a LPNETRESOURCEA to be
|
||
converted to a NETRESOURCEW. The next character in Instructions
|
||
is a bitmask of the NETRESFIELD_ constants, indicating which
|
||
fields of the NETRESOURCEA to convert. Store a pointer to the
|
||
NETRESOURCEW in the corresponding OutputParms member.
|
||
|
||
'B' (Buffer) - InputParms member (say InputParms[i]) is a pointer to
|
||
an output buffer. InputParms[i+1] is a pointer to a DWORD
|
||
indicating the buffer size in bytes. Probe the buffer for write.
|
||
Allocate an area of double the size (i.e. of size
|
||
(*InputParms[i+1])*sizeof(WCHAR)) in the intermediate buffer.
|
||
Store a pointer to this area of the buffer in OutputParms[i].
|
||
Store the size of this area in OutputParms[i+1].
|
||
|
||
If InputParms[i] is NULL, store NULL in OutputParms[i], and
|
||
ignore InputParms[i+1]. (In other words, the buffer pointer
|
||
is optional; the size pointer is required if the buffer pointer
|
||
is present and ignored if the buffer pointer is absent.)
|
||
|
||
'Bs' (Buffer beginning with structure) - Same as 'B', but the first
|
||
N bytes of the output buffer, where N is stored in InputParms[i+2],
|
||
are supposed to hold a fixed-size structure, not strings.
|
||
When calculating the size of the intermediate area, double the
|
||
size of the rest of the buffer, but not the size of the structure.
|
||
CODEWORK: Also verify that the buffer is DWORD-aligned?
|
||
|
||
InputParms - An array of parameters to the Ansi API, described by the
|
||
Instructions parameter.
|
||
|
||
OutputParms - An array of the same size as InputParms, to hold the
|
||
converted Unicode parameters.
|
||
|
||
ppBuffer - A pointer to the intermediate buffer allocated by this
|
||
function will be stored here. It must be freed by a single call
|
||
to LocalFree, regardless of the return value from this function.
|
||
|
||
Return Value:
|
||
|
||
WN_SUCCESS
|
||
|
||
WN_OUT_OF_MEMORY
|
||
|
||
WN_BAD_POINTER
|
||
|
||
History:
|
||
|
||
16-Feb-1996 anirudhs Created.
|
||
|
||
Notes:
|
||
|
||
The function works by making two passes through the Instructions string.
|
||
In the first pass the string lengths are determined and saved, and the
|
||
required size of the temporary buffer is calculated. In the second
|
||
pass the parameters are actually converted to Unicode.
|
||
|
||
--*/
|
||
{
|
||
ANSI_STRING AnsiStrings [MAX_STRINGS_PER_API] = {0};
|
||
UNICODE_STRING UnicodeStrings[MAX_STRINGS_PER_API] = {0};
|
||
ULONG Bytes = 0; // Size of buffer to allocate
|
||
DWORD status = WN_SUCCESS;
|
||
|
||
//
|
||
// The caller must have initialized the buffer pointer to NULL, so
|
||
// he can free the buffer even if this function fails.
|
||
//
|
||
ASSERT(*ppBuffer == NULL);
|
||
|
||
__try
|
||
{
|
||
//
|
||
// For two passes through Instructions
|
||
//
|
||
#define FIRST_PASS (iPass == 0)
|
||
for (ULONG iPass = 0; iPass <= 1; iPass++)
|
||
{
|
||
ULONG iString = 0; // Index into AnsiStrings and UnicodeStrings
|
||
|
||
//
|
||
// For each character in Instructions
|
||
//
|
||
const CHAR * pInstruction; // Pointer into Instructions
|
||
ULONG iParm; // Index into InputParms and OutputParms
|
||
for (pInstruction = Instructions, iParm = 0;
|
||
*pInstruction;
|
||
pInstruction++, iParm++)
|
||
{
|
||
MPR_LOG(ANSI, "Processing instruction '%hc'\n", *pInstruction);
|
||
|
||
switch (*pInstruction)
|
||
{
|
||
case 'B':
|
||
//
|
||
// The next 2 InputParms are a buffer pointer and size.
|
||
// Note that this code could cause an exception.
|
||
//
|
||
if (InputParms[iParm].lpvoid == NULL)
|
||
{
|
||
// A NULL pointer stays NULL; the size pointer is ignored
|
||
OutputParms[iParm].lpbyte = NULL;
|
||
}
|
||
else if (FIRST_PASS)
|
||
{
|
||
// Probe the original buffer
|
||
if (IS_BAD_BYTE_BUFFER(InputParms[iParm].lpvoid,
|
||
InputParms[iParm+1].lpdword))
|
||
{
|
||
status = WN_BAD_POINTER;
|
||
__leave;
|
||
}
|
||
|
||
// Reserve the intermediate buffer area
|
||
Bytes = ROUND_UP_TO_DWORD(Bytes);
|
||
OutputParms[iParm].dword = Bytes;
|
||
OutputParms[iParm+1].dword =
|
||
(*InputParms[iParm+1].lpdword) * sizeof(WCHAR);
|
||
|
||
// Check for an optional 's' in Instructions
|
||
if (*(pInstruction+1) == 's')
|
||
{
|
||
// CODEWORK: Check for DWORD alignment on RISC?
|
||
// if (!IS_DWORD_ALIGNED(InputParms[iParm].lpvoid))
|
||
// { status = WN_BAD_POINTER; __leave; }
|
||
|
||
// InputParms[iParm+2].dword holds the size of the
|
||
// fixed-length structure that will go at the start
|
||
// of the buffer. We don't want to multiply its
|
||
// size by sizeof(WCHAR).
|
||
if (OutputParms[iParm+1].dword/sizeof(WCHAR) <
|
||
InputParms[iParm+2].dword)
|
||
{
|
||
OutputParms[iParm+1].dword /= sizeof(WCHAR);
|
||
}
|
||
else
|
||
{
|
||
OutputParms[iParm+1].dword -=
|
||
InputParms[iParm+2].dword*(sizeof(WCHAR)-1);
|
||
}
|
||
}
|
||
|
||
Bytes += OutputParms[iParm+1].dword;
|
||
}
|
||
else // Non-NULL pointer, second pass
|
||
{
|
||
// Convert the offset to a pointer
|
||
OutputParms[iParm].lpbyte =
|
||
*ppBuffer + OutputParms[iParm].dword;
|
||
ASSERT(IS_DWORD_ALIGNED(OutputParms[iParm].lpbyte));
|
||
}
|
||
|
||
iParm++; // iParm+1 was for the buffer size
|
||
|
||
if (*(pInstruction+1) == 's')
|
||
{
|
||
pInstruction++;
|
||
iParm++; // iParm+2 was for the fixed structure size
|
||
}
|
||
break;
|
||
|
||
case 'S':
|
||
//
|
||
// InputParm is a string to be converted.
|
||
// A NULL string stays NULL.
|
||
//
|
||
if (FIRST_PASS)
|
||
{
|
||
ASSERT(iString < MAX_STRINGS_PER_API);
|
||
Bytes = ROUND_UP_TO_WCHAR(Bytes);
|
||
status = StringParmToUnicodePass1(
|
||
InputParms[iParm].lpcstr,
|
||
&AnsiStrings[iString],
|
||
&UnicodeStrings[iString],
|
||
&Bytes);
|
||
}
|
||
else
|
||
{
|
||
status = StringParmToUnicodePass2(
|
||
&AnsiStrings[iString],
|
||
&UnicodeStrings[iString],
|
||
*ppBuffer,
|
||
&OutputParms[iParm].lpwstr);
|
||
}
|
||
|
||
if (status != WN_SUCCESS)
|
||
{
|
||
__leave;
|
||
}
|
||
|
||
iString++;
|
||
break;
|
||
|
||
case 'N':
|
||
//
|
||
// InputParm is a NETRESOURCEA to be converted, and the
|
||
// next character in Instructions tells which of its string
|
||
// fields are to be converted.
|
||
// NULL strings remain NULL; ignored fields are copied
|
||
// unchanged.
|
||
//
|
||
|
||
pInstruction++;
|
||
|
||
if (InputParms[iParm].lpNetResA == NULL)
|
||
{
|
||
// A null netresource stays null
|
||
OutputParms[iParm].lpNetResW = NULL;
|
||
break;
|
||
}
|
||
|
||
{
|
||
// First deal with the fixed-size part of the structure.
|
||
const NETRESOURCEA *pNetResA =
|
||
InputParms[iParm].lpNetResA;
|
||
NETRESOURCEW *pNetResW;
|
||
|
||
if (FIRST_PASS)
|
||
{
|
||
// Reserve space for the NETRESOURCEW
|
||
Bytes = ROUND_UP_TO_DWORD(Bytes);
|
||
OutputParms[iParm].dword = Bytes;
|
||
Bytes += sizeof(NETRESOURCEW);
|
||
ASSERT(IS_WCHAR_ALIGNED(Bytes));
|
||
}
|
||
else
|
||
{
|
||
// Copy fixed-size fields and NULL pointers
|
||
pNetResW = (NETRESOURCEW *)
|
||
(*ppBuffer + OutputParms[iParm].dword);
|
||
ASSERT(IS_DWORD_ALIGNED(pNetResW));
|
||
RtlCopyMemory(pNetResW, pNetResA, sizeof(NETRESOURCEA));
|
||
|
||
OutputParms[iParm].lpNetResW = pNetResW;
|
||
}
|
||
|
||
// Next add each non-null string specified in the
|
||
// field mask.
|
||
CHAR FieldMask = *pInstruction;
|
||
ASSERT(FieldMask != 0);
|
||
|
||
for (ULONG iField = 0;
|
||
iField < NUMBER_OF_NETRESFIELD;
|
||
iField++)
|
||
{
|
||
if ((FieldMask >> iField) & 1)
|
||
{
|
||
if (FIRST_PASS)
|
||
{
|
||
ASSERT(iString < MAX_STRINGS_PER_API);
|
||
status = StringParmToUnicodePass1(
|
||
pNetResA->*NRAField[iField],
|
||
&AnsiStrings[iString],
|
||
&UnicodeStrings[iString],
|
||
&Bytes);
|
||
}
|
||
else
|
||
{
|
||
status = StringParmToUnicodePass2(
|
||
&AnsiStrings[iString],
|
||
&UnicodeStrings[iString],
|
||
*ppBuffer,
|
||
&(pNetResW->*NRWField[iField]));
|
||
}
|
||
|
||
if (status != WN_SUCCESS)
|
||
{
|
||
__leave;
|
||
}
|
||
|
||
iString++;
|
||
}
|
||
}
|
||
}
|
||
break;
|
||
|
||
default:
|
||
ASSERT(0);
|
||
}
|
||
}
|
||
|
||
if (FIRST_PASS)
|
||
{
|
||
//
|
||
// Actually allocate the space for the Unicode parameters
|
||
//
|
||
*ppBuffer = (LPBYTE) LocalAlloc(0, Bytes);
|
||
if (*ppBuffer == NULL)
|
||
{
|
||
status = GetLastError();
|
||
MPR_LOG2(ERROR,
|
||
"InputParmsToUnicode: LocalAlloc for %lu bytes failed, %lu\n",
|
||
Bytes, status);
|
||
__leave;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
__except(EXCEPTION_EXECUTE_HANDLER)
|
||
{
|
||
#if DBG == 1
|
||
status = GetExceptionCode();
|
||
if (status != EXCEPTION_ACCESS_VIOLATION)
|
||
{
|
||
MPR_LOG(ERROR,"InputParmsToUnicode: Unexpected Exception %#lx\n",status);
|
||
}
|
||
#endif
|
||
status = WN_BAD_POINTER;
|
||
}
|
||
|
||
return status;
|
||
}
|
||
|
||
|
||
|
||
DWORD
|
||
StringParmToUnicodePass1 (
|
||
IN LPCSTR StringParm,
|
||
OUT PANSI_STRING AnsiString,
|
||
OUT PUNICODE_STRING UnicodeString,
|
||
IN OUT PULONG BufferOffset
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Helper function for InputParmsToUnicode.
|
||
|
||
--*/
|
||
{
|
||
RtlInitAnsiString( AnsiString, StringParm );
|
||
|
||
if (StringParm == NULL)
|
||
{
|
||
return WN_SUCCESS;
|
||
}
|
||
|
||
// Save the offset to the memory for this Unicode string, to be converted
|
||
// to a pointer after the memory is allocated
|
||
ULONG UnicodeLength = RtlAnsiStringToUnicodeSize( AnsiString );
|
||
if (UnicodeLength > MAXUSHORT)
|
||
{
|
||
MPR_LOG(ERROR,
|
||
"Unicode size of Ansi string parm is %lu, exceeds MAXUSHORT\n",
|
||
UnicodeLength);
|
||
return WN_BAD_VALUE;
|
||
}
|
||
UnicodeString->Buffer = (LPWSTR) UlongToPtr(*BufferOffset);
|
||
UnicodeString->MaximumLength = (USHORT) UnicodeLength;
|
||
|
||
*BufferOffset = ROUND_UP_TO_DWORD(*BufferOffset + UnicodeLength);
|
||
|
||
return WN_SUCCESS;
|
||
}
|
||
|
||
|
||
DWORD
|
||
StringParmToUnicodePass2 (
|
||
IN OUT PANSI_STRING AnsiString,
|
||
OUT PUNICODE_STRING UnicodeString,
|
||
IN const BYTE * BufferStart,
|
||
OUT LPWSTR * Result
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Helper function for InputParmsToUnicode.
|
||
|
||
--*/
|
||
{
|
||
if (AnsiString->Buffer == NULL)
|
||
{
|
||
*Result = NULL;
|
||
// NOTE: the UnicodeString is not initialized in this case
|
||
return WN_SUCCESS;
|
||
}
|
||
|
||
// Convert the previously stored buffer offset into a pointer
|
||
UnicodeString->Buffer = (LPWSTR)
|
||
(BufferStart + (ULONG_PTR) UnicodeString->Buffer);
|
||
ASSERT(IS_WCHAR_ALIGNED(UnicodeString->Buffer));
|
||
|
||
// Convert the string to Unicode
|
||
NTSTATUS ntstatus =
|
||
RtlAnsiStringToUnicodeString(UnicodeString, AnsiString, FALSE);
|
||
if (!NT_SUCCESS(ntstatus))
|
||
{
|
||
MPR_LOG(ERROR, "RtlAnsiStringToUnicodeString failed %#lx\n", ntstatus);
|
||
return RtlNtStatusToDosError(ntstatus);
|
||
}
|
||
*Result = UnicodeString->Buffer;
|
||
|
||
return WN_SUCCESS;
|
||
}
|
||
|
||
|
||
|
||
DWORD
|
||
OutputBufferToAnsi(
|
||
IN char BufferFormat,
|
||
IN LPBYTE SourceBuffer,
|
||
OUT LPVOID AnsiBuffer,
|
||
IN OUT LPDWORD pcbBufferSize
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function converts the data in the result buffer that was returned
|
||
from a Unicode API into Ansi and stores it in the Ansi caller's result
|
||
buffer. If the caller's buffer isn't large enough it saves the required
|
||
size in *pcbBufferSize and returns WN_MORE_DATA.
|
||
|
||
Nearly all the WNet APIs that have output buffers have only a single
|
||
field in the output buffer, so this API takes only a single character,
|
||
rather than a string, for the buffer format. APIs with more complicated
|
||
output buffers should handle the complexity themselves, by directly
|
||
calling the functions that this function calls.
|
||
|
||
Arguments:
|
||
|
||
BufferFormat - A character indicating the format of the SourceBuffer
|
||
field. Recognized values are:
|
||
|
||
'S' - SourceBuffer contains a Unicode string. Convert it to Ansi
|
||
and store the Ansi version in AnsiBuffer.
|
||
|
||
'N' - SourceBuffer contains a NETRESOURCEW with its associated
|
||
strings. Convert it to Ansi and store the Ansi version in
|
||
AnsiBuffer.
|
||
|
||
SourceBuffer - The output buffer returned from a Unicode API.
|
||
This must not be NULL.
|
||
|
||
AnsiBuffer - The output buffer that the caller of the Ansi API supplied.
|
||
This must not be NULL.
|
||
|
||
pcbBufferSize - On entry, the size of AnsiBuffer in bytes. If the
|
||
function returns WN_MORE_DATA, the required size is stored here;
|
||
otherwise this is unmodified.
|
||
This must not be NULL (must be a writeable DWORD pointer).
|
||
|
||
Return Value:
|
||
|
||
WN_SUCCESS - successful.
|
||
|
||
WN_MORE_DATA - The buffer specified by AnsiBuffer and pcbBufferSize was
|
||
not large enough to hold the converted data from SourceBuffer. In
|
||
this case the required buffer size (in bytes) is written to
|
||
*pcbBufferSize. The contents of AnsiBuffer are undefined (it will
|
||
be partially filled).
|
||
|
||
History:
|
||
|
||
16-Feb-1996 anirudhs Created.
|
||
|
||
Notes:
|
||
|
||
--*/
|
||
{
|
||
// Doesn't handle optional parameters for now
|
||
ASSERT(SourceBuffer != NULL &&
|
||
AnsiBuffer != NULL &&
|
||
pcbBufferSize != NULL);
|
||
|
||
ANSI_OUT_BUFFER Buf((LPBYTE) AnsiBuffer, *pcbBufferSize);
|
||
DWORD status;
|
||
|
||
switch (BufferFormat)
|
||
{
|
||
case 'S':
|
||
status = OutputStringToAnsi((LPCWSTR) SourceBuffer, &Buf);
|
||
break;
|
||
|
||
case 'N':
|
||
status = OutputNetResourceToAnsi((NETRESOURCEW *) SourceBuffer, &Buf);
|
||
break;
|
||
|
||
default:
|
||
ASSERT(0);
|
||
return ERROR_INVALID_LEVEL;
|
||
}
|
||
|
||
//
|
||
// Map the results to the conventions followed by the WNet APIs
|
||
//
|
||
if (status == WN_SUCCESS)
|
||
{
|
||
if (Buf.Overflow())
|
||
{
|
||
*pcbBufferSize = Buf.GetUsage();
|
||
status = WN_MORE_DATA;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
ASSERT(status != WN_MORE_DATA);
|
||
}
|
||
|
||
return status;
|
||
}
|
||
|
||
|
||
|
||
DWORD
|
||
OutputStringToAnsi(
|
||
IN LPCWSTR UnicodeIn,
|
||
IN OUT ANSI_OUT_BUFFER * Buf
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function converts a Unicode string to Ansi and calculates the number
|
||
of bytes required to store it. If the caller passes a buffer that has
|
||
enough remaining free space, it stores the Ansi data in the buffer.
|
||
Otherwise it just increments the buffer's space usage by the number of
|
||
bytes required.
|
||
|
||
Arguments:
|
||
|
||
UnicodeIn - A Unicode string to be converted to Ansi.
|
||
This must not be NULL.
|
||
|
||
Buf - A structure whose elements are interpreted as follows:
|
||
|
||
_Start - Start address of a buffer to contain the Ansi data.
|
||
This buffer must be writeable, or an exception will occur.
|
||
|
||
_Size - The total size of the buffer for the Ansi data.
|
||
|
||
_Used - On entry, the number of bytes in the buffer that have
|
||
already been used. The function will begin writing data at
|
||
_Start + _Used and will never write past the total size
|
||
specified by _Size. If there is not enough room left
|
||
in the buffer it will be partially filled or unmodified.
|
||
On a successful return, _Used is incremented by the number
|
||
of bytes that would be required to store the converted Ansi
|
||
data, whether or not it was actually stored in the buffer.
|
||
(This is done because the WNet APIs need to return the
|
||
required buffer size if the caller's buffer was too small.)
|
||
|
||
The use of this structure simplifies the writing of routines that
|
||
use this function and need to convert multiple fields of Unicode
|
||
data. Callers that need to convert only a single field can use
|
||
OutputBufferToAnsi.
|
||
|
||
Return Value:
|
||
|
||
WN_SUCCESS - successful. The Ansi data was written to the buffer if
|
||
Buf->_Used <= Buf->_Size. Otherwise, Buf->_Used was incremented
|
||
without completely writing the data.
|
||
|
||
Note that WN_MORE_DATA is never returned.
|
||
|
||
History:
|
||
|
||
16-Feb-1996 anirudhs Created.
|
||
|
||
Notes:
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS ntStatus;
|
||
UNICODE_STRING unicodeString;
|
||
ANSI_STRING ansiString;
|
||
|
||
ASSERT(UnicodeIn != NULL); // Doesn't handle optional parameters for now
|
||
|
||
//
|
||
// Initialize the string structures
|
||
//
|
||
RtlInitUnicodeString(&unicodeString, UnicodeIn);
|
||
|
||
ansiString.Buffer = (PCHAR) Buf->Next();
|
||
ansiString.MaximumLength = (Buf->FreeSpace() > MAXUSHORT ?
|
||
MAXUSHORT :
|
||
(USHORT) Buf->FreeSpace()
|
||
);
|
||
|
||
//
|
||
// Call the conversion function
|
||
//
|
||
ntStatus = RtlUnicodeStringToAnsiString (
|
||
&ansiString, // Destination
|
||
&unicodeString, // Source
|
||
(BOOLEAN)FALSE); // Don't allocate the destination
|
||
|
||
if (NT_SUCCESS(ntStatus))
|
||
{
|
||
// Add on the buffer space we used
|
||
Buf->AddUsed(ansiString.Length + 1);
|
||
ASSERT(! Buf->Overflow());
|
||
return WN_SUCCESS;
|
||
}
|
||
else if (ntStatus == STATUS_BUFFER_OVERFLOW)
|
||
{
|
||
// We couldn't fit the string in the buffer, but still figure out
|
||
// how much buffer space we would have used if we could
|
||
Buf->AddUsed(RtlUnicodeStringToAnsiSize(&unicodeString));
|
||
ASSERT(Buf->Overflow());
|
||
return WN_SUCCESS;
|
||
}
|
||
else
|
||
{
|
||
MPR_LOG(ERROR, "RtlUnicodeStringToAnsiString failed %#lx\n", ntStatus);
|
||
DWORD status = RtlNtStatusToDosError(ntStatus);
|
||
ASSERT(status != WN_MORE_DATA);
|
||
return status;
|
||
}
|
||
}
|
||
|
||
|
||
|
||
DWORD
|
||
OutputNetResourceToAnsi(
|
||
IN NETRESOURCEW * lpNetResW,
|
||
IN OUT ANSI_OUT_BUFFER * Buf
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function converts a NETRESOURCEW and its associated Unicode strings
|
||
to Ansi and returns the number of bytes required to store them. If the
|
||
caller passes a buffer that has enough remaining free space, it stores
|
||
the Ansi data in the buffer.
|
||
|
||
Arguments:
|
||
|
||
lpNetResW - A Unicode net resource to be converted to Ansi.
|
||
This must not be NULL.
|
||
|
||
Buf - same as OutputStringToAnsi.
|
||
|
||
Return Value:
|
||
|
||
Same as OutputStringToAnsi.
|
||
|
||
History:
|
||
|
||
16-Feb-1996 anirudhs Created.
|
||
|
||
Notes:
|
||
|
||
--*/
|
||
{
|
||
//
|
||
// Copy the fixed-size part of the structure, including NULL pointers,
|
||
// and/or add on the buffer space it would take
|
||
//
|
||
LPNETRESOURCEA lpNetResA = (LPNETRESOURCEA) Buf->Next();
|
||
if (Buf->HasRoomFor(sizeof(NETRESOURCEA)))
|
||
{
|
||
RtlCopyMemory(lpNetResA, lpNetResW, sizeof(NETRESOURCEA));
|
||
}
|
||
Buf->AddUsed(sizeof(NETRESOURCEA));
|
||
|
||
//
|
||
// Copy each non-NULL string field,
|
||
// and/or add on the buffer space it would take
|
||
//
|
||
for (DWORD iField = 0;
|
||
iField < NUMBER_OF_NETRESFIELD;
|
||
iField++)
|
||
{
|
||
if (lpNetResW->*NRWField[iField] != NULL)
|
||
{
|
||
// Save a pointer to the Ansi string we are about to create
|
||
// in the Ansi net resource
|
||
lpNetResA->*NRAField[iField] = (LPSTR) Buf->Next();
|
||
|
||
// Convert the string
|
||
DWORD status = OutputStringToAnsi(lpNetResW->*NRWField[iField], Buf);
|
||
if (status != WN_SUCCESS)
|
||
{
|
||
ASSERT(status != WN_MORE_DATA);
|
||
return status;
|
||
}
|
||
}
|
||
}
|
||
|
||
return WN_SUCCESS;
|
||
}
|
||
|
||
|
||
|
||
DWORD
|
||
OutputStringToAnsiInPlace(
|
||
IN LPWSTR UnicodeIn
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function converts a Unicode string to Ansi in place.
|
||
This is the same as OutputStringToAnsi, optimized for in-place conversions.
|
||
|
||
Arguments:
|
||
|
||
UnicodeIn - A Unicode string to be converted to Ansi.
|
||
This may be NULL, in which case the function does nothing.
|
||
|
||
Return Value:
|
||
|
||
WN_SUCCESS - successful.
|
||
|
||
Note that WN_MORE_DATA is never returned.
|
||
|
||
History:
|
||
|
||
08-Aug-1996 anirudhs Created.
|
||
|
||
Notes:
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS ntStatus;
|
||
UNICODE_STRING unicodeString;
|
||
ANSI_STRING ansiString;
|
||
|
||
if (UnicodeIn == NULL)
|
||
{
|
||
return WN_SUCCESS;
|
||
}
|
||
|
||
//
|
||
// Initialize the string structures
|
||
//
|
||
RtlInitUnicodeString(&unicodeString, UnicodeIn);
|
||
|
||
ansiString.Buffer = (PCHAR) UnicodeIn;
|
||
ansiString.MaximumLength = unicodeString.MaximumLength;
|
||
|
||
//
|
||
// Call the conversion function
|
||
//
|
||
ntStatus = RtlUnicodeStringToAnsiString (
|
||
&ansiString, // Destination
|
||
&unicodeString, // Source
|
||
(BOOLEAN)FALSE); // Don't allocate the destination
|
||
|
||
ASSERT(ntStatus != STATUS_BUFFER_OVERFLOW);
|
||
|
||
if (NT_SUCCESS(ntStatus))
|
||
{
|
||
return WN_SUCCESS;
|
||
}
|
||
else
|
||
{
|
||
MPR_LOG(ERROR, "RtlUnicodeStringToAnsiString failed %#lx\n", ntStatus);
|
||
DWORD status = RtlNtStatusToDosError(ntStatus);
|
||
ASSERT(status != WN_MORE_DATA);
|
||
return status;
|
||
}
|
||
}
|
||
|
||
|
||
//////////////////////////////////////////////////////////////////////////
|
||
//////////////////////////////////////////////////////////////////////////
|
||
|
||
|
||
DWORD APIENTRY
|
||
WNetGetNetworkInformationA(
|
||
IN LPCSTR lpProvider,
|
||
IN OUT LPNETINFOSTRUCT lpNetInfoStruct
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Arguments:
|
||
|
||
Return Value:
|
||
|
||
--*/
|
||
{
|
||
ANSI_API_WITHOUT_ANSI_OUTPUT(
|
||
1,
|
||
AParm[0].lpcstr = lpProvider; ,
|
||
"S",
|
||
WNetGetNetworkInformationW(UParm[0].lpwstr, lpNetInfoStruct);
|
||
)
|
||
}
|
||
|
||
|
||
|
||
DWORD APIENTRY
|
||
WNetGetProviderNameA(
|
||
IN DWORD dwNetType,
|
||
OUT LPSTR lpProviderName,
|
||
IN OUT LPDWORD lpBufferSize
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Arguments:
|
||
|
||
Return Value:
|
||
|
||
--*/
|
||
{
|
||
ANSI_API_WITH_ANSI_OUTPUT(
|
||
2,
|
||
AParm[0].lpvoid = lpProviderName;
|
||
AParm[1].lpdword = lpBufferSize; ,
|
||
"B",
|
||
WNetGetProviderNameW(dwNetType, UParm[0].lpwstr, lpBufferSize); ,
|
||
OutputBufferToAnsi('S', UParm[0].lpbyte, lpProviderName, lpBufferSize);
|
||
)
|
||
}
|
||
|
||
|
||
DWORD
|
||
WNetGetProviderTypeA(
|
||
IN LPCSTR lpProvider,
|
||
OUT LPDWORD lpdwNetType
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Arguments:
|
||
|
||
Return Value:
|
||
|
||
--*/
|
||
{
|
||
ANSI_API_WITHOUT_ANSI_OUTPUT(
|
||
1,
|
||
AParm[0].lpcstr = lpProvider; ,
|
||
"S",
|
||
WNetGetProviderTypeW(UParm[0].lpwstr, lpdwNetType);
|
||
)
|
||
}
|
||
|
||
|
||
|
||
DWORD APIENTRY
|
||
WNetAddConnectionA (
|
||
IN LPCSTR lpRemoteName,
|
||
IN LPCSTR lpPassword,
|
||
IN LPCSTR lpLocalName
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Arguments:
|
||
|
||
Return Value:
|
||
|
||
--*/
|
||
{
|
||
DWORD status;
|
||
LPBYTE tempBuffer = NULL;
|
||
ANSI_PARM AParm[3];
|
||
UNICODE_PARM UParm[3];
|
||
|
||
AParm[0].lpcstr = lpRemoteName;
|
||
AParm[1].lpcstr = lpPassword;
|
||
AParm[2].lpcstr = lpLocalName;
|
||
|
||
UParm[1].lpwstr = NULL;
|
||
|
||
status = InputParmsToUnicode("SSS", AParm, UParm, &tempBuffer);
|
||
|
||
if (status == WN_SUCCESS)
|
||
{
|
||
status = WNetAddConnectionW(
|
||
UParm[0].lpwstr,
|
||
UParm[1].lpwstr,
|
||
UParm[2].lpwstr
|
||
);
|
||
}
|
||
|
||
MprClearString(UParm[1].lpwstr);
|
||
|
||
LocalFree(tempBuffer);
|
||
|
||
SET_AND_RETURN(status)
|
||
}
|
||
|
||
DWORD APIENTRY
|
||
WNetAddConnection2A (
|
||
IN LPNETRESOURCEA lpNetResource,
|
||
IN LPCSTR lpPassword,
|
||
IN LPCSTR lpUserName,
|
||
IN DWORD dwFlags
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Arguments:
|
||
|
||
Return Value:
|
||
|
||
--*/
|
||
{
|
||
return (WNetUseConnectionA(
|
||
NULL,
|
||
lpNetResource,
|
||
lpPassword,
|
||
lpUserName,
|
||
dwFlags,
|
||
NULL,
|
||
NULL,
|
||
NULL
|
||
));
|
||
}
|
||
|
||
DWORD APIENTRY
|
||
WNetAddConnection3A (
|
||
IN HWND hwndOwner,
|
||
IN LPNETRESOURCEA lpNetResource,
|
||
IN LPCSTR lpPassword,
|
||
IN LPCSTR lpUserName,
|
||
IN DWORD dwFlags
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Arguments:
|
||
|
||
Return Value:
|
||
|
||
--*/
|
||
{
|
||
return (WNetUseConnectionA(
|
||
hwndOwner,
|
||
lpNetResource,
|
||
lpPassword,
|
||
lpUserName,
|
||
dwFlags,
|
||
NULL,
|
||
NULL,
|
||
NULL
|
||
));
|
||
}
|
||
|
||
|
||
|
||
DWORD APIENTRY
|
||
WNetUseConnectionA(
|
||
IN HWND hwndOwner,
|
||
IN LPNETRESOURCEA lpNetResource,
|
||
IN LPCSTR lpPassword,
|
||
IN LPCSTR lpUserID,
|
||
IN DWORD dwFlags,
|
||
OUT LPSTR lpAccessName OPTIONAL,
|
||
IN OUT LPDWORD lpBufferSize OPTIONAL, // Optional only if lpAccessName absent
|
||
OUT LPDWORD lpResult
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Arguments:
|
||
|
||
Return Value:
|
||
|
||
--*/
|
||
{
|
||
DWORD status;
|
||
LPBYTE tempBuffer = NULL;
|
||
ANSI_PARM AParm[5];
|
||
UNICODE_PARM UParm[5];
|
||
|
||
AParm[0].lpNetResA = lpNetResource;
|
||
AParm[1].lpcstr = lpPassword;
|
||
AParm[2].lpcstr = lpUserID;
|
||
AParm[3].lpvoid = lpAccessName;
|
||
AParm[4].lpdword = lpBufferSize;
|
||
|
||
UParm[1].lpwstr = NULL;
|
||
|
||
status = InputParmsToUnicode("N" NETRES_LRP "SSB", AParm, UParm, &tempBuffer);
|
||
|
||
if (status == WN_SUCCESS)
|
||
{
|
||
status = WNetUseConnectionW(
|
||
hwndOwner,
|
||
UParm[0].lpNetResW,
|
||
UParm[1].lpwstr,
|
||
UParm[2].lpwstr,
|
||
dwFlags,
|
||
UParm[3].lpwstr,
|
||
lpBufferSize,
|
||
lpResult
|
||
);
|
||
|
||
if (status == WN_SUCCESS)
|
||
{
|
||
if (ARGUMENT_PRESENT(lpAccessName))
|
||
{
|
||
//
|
||
// Note: At this point, we know that lpBufferSize is writeable.
|
||
//
|
||
status = OutputBufferToAnsi(
|
||
'S', UParm[3].lpbyte, lpAccessName, lpBufferSize);
|
||
}
|
||
}
|
||
}
|
||
|
||
MprClearString(UParm[1].lpwstr);
|
||
|
||
LocalFree(tempBuffer);
|
||
|
||
SET_AND_RETURN(status)
|
||
}
|
||
|
||
|
||
|
||
DWORD APIENTRY
|
||
WNetCancelConnection2A (
|
||
IN LPCSTR lpName,
|
||
IN DWORD dwFlags,
|
||
IN BOOL fForce
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Arguments:
|
||
|
||
Return Value:
|
||
|
||
--*/
|
||
{
|
||
ANSI_API_WITHOUT_ANSI_OUTPUT(
|
||
1,
|
||
AParm[0].lpcstr = lpName; ,
|
||
"S",
|
||
WNetCancelConnection2W(UParm[0].lpwstr, dwFlags, fForce);
|
||
)
|
||
}
|
||
|
||
DWORD APIENTRY
|
||
WNetCancelConnectionA (
|
||
IN LPCSTR lpName,
|
||
IN BOOL fForce
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is provided for Win 3.1 compatibility.
|
||
|
||
Arguments:
|
||
|
||
Return Value:
|
||
|
||
--*/
|
||
{
|
||
return WNetCancelConnection2A( lpName, CONNECT_UPDATE_PROFILE, fForce ) ;
|
||
}
|
||
|
||
DWORD APIENTRY
|
||
WNetGetConnectionA (
|
||
IN LPCSTR lpLocalName,
|
||
OUT LPSTR lpRemoteName,
|
||
IN OUT LPDWORD lpnLength
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function returns the RemoteName that is associated with a
|
||
LocalName (or drive letter).
|
||
|
||
Arguments:
|
||
|
||
lpLocalName - This is a pointer to the string that contains the LocalName.
|
||
|
||
lpRemoteName - This is a pointer to the buffer that will contain the
|
||
RemoteName string upon exit.
|
||
|
||
lpnLength - This is a pointer to the size (in characters) of the buffer
|
||
that is to be filled in with the RemoteName string. It is assumed
|
||
upon entry, that characters are all single byte characters.
|
||
If the buffer is too small and WN_MORE_DATA is returned, the data
|
||
at this location contains buffer size information - in number of
|
||
characters (bytes). This information indicates how large the buffer
|
||
should be (in bytes) to obtain the remote name. It is assumed that
|
||
all Unicode characteres translate into DBCS characters.
|
||
|
||
|
||
Return Value:
|
||
|
||
|
||
--*/
|
||
{
|
||
DWORD status;
|
||
LPBYTE tempBuffer = NULL;
|
||
ANSI_PARM AParm[3];
|
||
UNICODE_PARM UParm[3];
|
||
|
||
AParm[0].lpcstr = lpLocalName;
|
||
AParm[1].lpvoid = lpRemoteName;
|
||
AParm[2].lpdword = lpnLength;
|
||
|
||
status = InputParmsToUnicode("SB", AParm, UParm, &tempBuffer);
|
||
|
||
if (status == WN_SUCCESS)
|
||
{
|
||
status = WNetGetConnectionW(UParm[0].lpwstr, UParm[1].lpwstr, lpnLength);
|
||
|
||
if (status == WN_SUCCESS || status == WN_CONNECTION_CLOSED)
|
||
{
|
||
DWORD tempStatus =
|
||
OutputBufferToAnsi('S', UParm[1].lpbyte, lpRemoteName, lpnLength);
|
||
if (tempStatus != WN_SUCCESS)
|
||
{
|
||
status = tempStatus;
|
||
}
|
||
}
|
||
}
|
||
|
||
LocalFree(tempBuffer);
|
||
|
||
SET_AND_RETURN(status)
|
||
}
|
||
|
||
DWORD APIENTRY
|
||
WNetGetConnection2A (
|
||
IN LPSTR lpLocalName,
|
||
OUT LPVOID lpBuffer,
|
||
IN OUT LPDWORD lpnLength
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function returns the RemoteName that is associated with a
|
||
LocalName (or drive letter) and the provider name that made the
|
||
connection.
|
||
|
||
Arguments:
|
||
|
||
lpLocalName - This is a pointer to the string that contains the LocalName.
|
||
|
||
lpBuffer - This is a pointer to the buffer that will contain the
|
||
WNET_CONNECTIONINFO structure upon exit.
|
||
|
||
lpnLength - This is a pointer to the size (in characters) of the buffer
|
||
that is to be filled in with the RemoteName string. It is assumed
|
||
upon entry, that characters are all single byte characters.
|
||
If the buffer is too small and WN_MORE_DATA is returned, the data
|
||
at this location contains buffer size information - in number of
|
||
characters (bytes). This information indicates how large the buffer
|
||
should be (in bytes) to obtain the remote name. It is assumed that
|
||
all Unicode characters translate into DBCS characters.
|
||
|
||
|
||
Return Value:
|
||
|
||
|
||
--*/
|
||
{
|
||
DWORD status;
|
||
LPBYTE tempBuffer = NULL;
|
||
ANSI_PARM AParm[4];
|
||
UNICODE_PARM UParm[4];
|
||
|
||
AParm[0].lpcstr = lpLocalName;
|
||
AParm[1].lpvoid = lpBuffer;
|
||
AParm[2].lpdword = lpnLength;
|
||
AParm[3].dword = sizeof(WNET_CONNECTIONINFO);
|
||
|
||
status = InputParmsToUnicode("SBs", AParm, UParm, &tempBuffer);
|
||
|
||
if (status == WN_SUCCESS)
|
||
{
|
||
status = WNetGetConnection2W(
|
||
UParm[0].lpwstr,
|
||
UParm[1].lpbyte,
|
||
&UParm[2].dword
|
||
);
|
||
|
||
if (status == WN_SUCCESS || status == WN_CONNECTION_CLOSED)
|
||
{
|
||
ANSI_OUT_BUFFER Buf((LPBYTE) lpBuffer, *lpnLength);
|
||
|
||
//
|
||
// Copy the fixed-size part of the structure, including NULL pointers,
|
||
// and/or add on the buffer space it would take
|
||
//
|
||
WNET_CONNECTIONINFOW * pconninfow = (WNET_CONNECTIONINFOW *) UParm[1].lpbyte;
|
||
WNET_CONNECTIONINFOA * pconninfoa = (WNET_CONNECTIONINFOA *) Buf.Next();
|
||
ASSERT(Buf.HasRoomFor(sizeof(WNET_CONNECTIONINFOA)));
|
||
RtlCopyMemory(pconninfoa, pconninfow, sizeof(WNET_CONNECTIONINFOA));
|
||
Buf.AddUsed(sizeof(WNET_CONNECTIONINFOA));
|
||
|
||
//
|
||
// Copy each non-NULL string field,
|
||
// and/or add on the buffer space it would take
|
||
//
|
||
DWORD tempStatus = WN_SUCCESS;
|
||
if (pconninfow->lpRemoteName != NULL)
|
||
{
|
||
pconninfoa->lpRemoteName = (LPSTR) Buf.Next();
|
||
tempStatus = OutputStringToAnsi(pconninfow->lpRemoteName, &Buf);
|
||
}
|
||
|
||
if (tempStatus == WN_SUCCESS &&
|
||
pconninfow->lpProvider != NULL)
|
||
{
|
||
pconninfoa->lpProvider = (LPSTR) Buf.Next();
|
||
tempStatus = OutputStringToAnsi(pconninfow->lpProvider, &Buf);
|
||
}
|
||
|
||
//
|
||
// Map the results to WNet API conventions
|
||
//
|
||
if (tempStatus != WN_SUCCESS)
|
||
{
|
||
status = tempStatus;
|
||
}
|
||
else if (Buf.Overflow())
|
||
{
|
||
*lpnLength = Buf.GetUsage();
|
||
status = WN_MORE_DATA;
|
||
}
|
||
}
|
||
else if (status == WN_MORE_DATA)
|
||
{
|
||
//
|
||
// Adjust the required buffer size for ansi/DBCS.
|
||
//
|
||
// We don't know how many characters will be required so we have to
|
||
// assume the worst case (all characters are DBCS characters).
|
||
//
|
||
*lpnLength = UParm[2].dword;
|
||
}
|
||
}
|
||
|
||
LocalFree(tempBuffer);
|
||
|
||
SET_AND_RETURN(status)
|
||
}
|
||
|
||
|
||
|
||
DWORD APIENTRY
|
||
WNetGetConnection3A(
|
||
IN LPCSTR lpLocalName,
|
||
IN LPCSTR lpProviderName OPTIONAL,
|
||
IN DWORD dwLevel,
|
||
OUT LPVOID lpBuffer,
|
||
IN OUT LPDWORD lpBufferSize // in bytes
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Arguments:
|
||
|
||
Return Value:
|
||
|
||
--*/
|
||
{
|
||
// For the only supported level, the output buffer is a DWORD, so no
|
||
// conversion of the output buffer is necessary
|
||
ANSI_API_WITHOUT_ANSI_OUTPUT(
|
||
2,
|
||
AParm[0].lpcstr = lpLocalName;
|
||
AParm[1].lpcstr = lpProviderName; ,
|
||
"SS",
|
||
WNetGetConnection3W(
|
||
UParm[0].lpwstr,
|
||
UParm[1].lpwstr,
|
||
dwLevel,
|
||
lpBuffer,
|
||
lpBufferSize
|
||
);
|
||
)
|
||
}
|
||
|
||
|
||
|
||
DWORD
|
||
WNetGetUniversalNameA (
|
||
IN LPCSTR lpLocalPath,
|
||
IN DWORD dwInfoLevel,
|
||
OUT LPVOID lpBuffer,
|
||
IN OUT LPDWORD lpBufferSize
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Arguments:
|
||
|
||
Return Value:
|
||
|
||
--*/
|
||
{
|
||
DWORD status;
|
||
LPBYTE tempBuffer = NULL;
|
||
ANSI_PARM AParm[4];
|
||
UNICODE_PARM UParm[4];
|
||
|
||
DWORD dwStructSize =
|
||
(dwInfoLevel == UNIVERSAL_NAME_INFO_LEVEL) ? sizeof(UNIVERSAL_NAME_INFO) :
|
||
(dwInfoLevel == REMOTE_NAME_INFO_LEVEL) ? sizeof(REMOTE_NAME_INFO) :
|
||
0;
|
||
|
||
AParm[0].lpcstr = lpLocalPath;
|
||
AParm[1].lpvoid = lpBuffer;
|
||
AParm[2].lpdword = lpBufferSize;
|
||
AParm[3].dword = dwStructSize;
|
||
|
||
status = InputParmsToUnicode("SBs", AParm, UParm, &tempBuffer);
|
||
|
||
if (status == WN_SUCCESS)
|
||
{
|
||
status = WNetGetUniversalNameW(
|
||
UParm[0].lpwstr,
|
||
dwInfoLevel,
|
||
UParm[1].lpbyte,
|
||
&UParm[2].dword
|
||
);
|
||
|
||
if (status == WN_SUCCESS || status == WN_CONNECTION_CLOSED)
|
||
{
|
||
DWORD tempStatus = WN_SUCCESS;
|
||
ANSI_OUT_BUFFER Buf((LPBYTE) lpBuffer, *lpBufferSize);
|
||
|
||
//
|
||
// Copy the fixed-size part of the structure, including NULL pointers,
|
||
// and/or add on the buffer space it would take
|
||
//
|
||
ASSERT(Buf.HasRoomFor(dwStructSize));
|
||
RtlCopyMemory(Buf.Next(), UParm[1].lpbyte, dwStructSize);
|
||
|
||
if (dwInfoLevel == REMOTE_NAME_INFO_LEVEL)
|
||
{
|
||
// -----------------------------------
|
||
// REMOTE_NAME_INFO_LEVEL
|
||
// -----------------------------------
|
||
|
||
LPREMOTE_NAME_INFOW pRemoteNameInfoW =
|
||
(LPREMOTE_NAME_INFOW) UParm[1].lpbyte;
|
||
LPREMOTE_NAME_INFOA pRemoteNameInfoA =
|
||
(LPREMOTE_NAME_INFOA) Buf.Next();
|
||
Buf.AddUsed(dwStructSize);
|
||
|
||
//
|
||
// Convert the returned Unicode string and string size back to
|
||
// ansi.
|
||
//
|
||
if (pRemoteNameInfoW->lpUniversalName != NULL)
|
||
{
|
||
pRemoteNameInfoA->lpUniversalName = (LPSTR) Buf.Next();
|
||
tempStatus = OutputStringToAnsi(pRemoteNameInfoW->lpUniversalName, &Buf);
|
||
}
|
||
|
||
if (tempStatus == WN_SUCCESS && pRemoteNameInfoW->lpConnectionName != NULL)
|
||
{
|
||
pRemoteNameInfoA->lpConnectionName = (LPSTR) Buf.Next();
|
||
tempStatus = OutputStringToAnsi(pRemoteNameInfoW->lpConnectionName, &Buf);
|
||
}
|
||
|
||
if (tempStatus == WN_SUCCESS && pRemoteNameInfoW->lpRemainingPath != NULL)
|
||
{
|
||
pRemoteNameInfoA->lpRemainingPath = (LPSTR) Buf.Next();
|
||
tempStatus = OutputStringToAnsi(pRemoteNameInfoW->lpRemainingPath, &Buf);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// -----------------------------------
|
||
// Must be UNIVERSAL_NAME_INFO_LEVEL
|
||
// -----------------------------------
|
||
ASSERT(dwInfoLevel == UNIVERSAL_NAME_INFO_LEVEL);
|
||
|
||
LPUNIVERSAL_NAME_INFOW pUniNameInfoW =
|
||
(LPUNIVERSAL_NAME_INFOW) UParm[1].lpbyte;
|
||
LPUNIVERSAL_NAME_INFOA pUniNameInfoA =
|
||
(LPUNIVERSAL_NAME_INFOA) Buf.Next();
|
||
Buf.AddUsed(dwStructSize);
|
||
|
||
//
|
||
// Convert the returned Unicode string and string size back to
|
||
// ansi.
|
||
//
|
||
if (pUniNameInfoW->lpUniversalName != NULL)
|
||
{
|
||
pUniNameInfoA->lpUniversalName = (LPSTR) Buf.Next();
|
||
tempStatus = OutputStringToAnsi(pUniNameInfoW->lpUniversalName, &Buf);
|
||
}
|
||
}
|
||
|
||
//
|
||
// Map the results to WNet API conventions
|
||
//
|
||
if (tempStatus != WN_SUCCESS)
|
||
{
|
||
status = tempStatus;
|
||
}
|
||
else if (Buf.Overflow())
|
||
{
|
||
*lpBufferSize = Buf.GetUsage();
|
||
status = WN_MORE_DATA;
|
||
}
|
||
}
|
||
else if (status == WN_MORE_DATA)
|
||
{
|
||
//
|
||
// Adjust the required buffer size for ansi/DBCS.
|
||
//
|
||
// We don't know how many characters will be required so we have to
|
||
// assume the worst case (all characters are DBCS characters).
|
||
//
|
||
*lpBufferSize = UParm[2].dword;
|
||
}
|
||
}
|
||
|
||
LocalFree(tempBuffer);
|
||
|
||
SET_AND_RETURN(status)
|
||
}
|
||
|
||
|
||
|
||
DWORD APIENTRY
|
||
WNetSetConnectionA(
|
||
IN LPCSTR lpName,
|
||
IN DWORD dwProperties,
|
||
IN OUT LPVOID pvValues
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Arguments:
|
||
|
||
Return Value:
|
||
|
||
--*/
|
||
{
|
||
//
|
||
// pvValues points to various types of structures depending on the value
|
||
// of dwProperties.
|
||
// Currently there is only one valid value for dwProperties, and its
|
||
// corresponding pvValues points to a DWORD, so we don't need to worry
|
||
// about converting pvValues to Unicode.
|
||
//
|
||
ANSI_API_WITHOUT_ANSI_OUTPUT(
|
||
1,
|
||
AParm[0].lpcstr = lpName; ,
|
||
"S",
|
||
WNetSetConnectionW(UParm[0].lpwstr, dwProperties, pvValues);
|
||
)
|
||
}
|
||
|
||
|
||
|
||
DWORD APIENTRY
|
||
MultinetGetConnectionPerformanceA(
|
||
IN LPNETRESOURCEA lpNetResource,
|
||
OUT LPNETCONNECTINFOSTRUCT lpNetConnectInfoStruct
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Arguments:
|
||
|
||
Return Value:
|
||
|
||
--*/
|
||
{
|
||
ANSI_API_WITHOUT_ANSI_OUTPUT(
|
||
1,
|
||
AParm[0].lpNetResA = lpNetResource; ,
|
||
"N" NETRES_LRP,
|
||
MultinetGetConnectionPerformanceW(
|
||
UParm[0].lpNetResW,
|
||
lpNetConnectInfoStruct);
|
||
)
|
||
}
|
||
|
||
|
||
|
||
DWORD APIENTRY
|
||
WNetOpenEnumA (
|
||
IN DWORD dwScope,
|
||
IN DWORD dwType,
|
||
IN DWORD dwUsage,
|
||
IN LPNETRESOURCEA lpNetResource,
|
||
OUT LPHANDLE lphEnum
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Arguments:
|
||
|
||
Return Value:
|
||
|
||
--*/
|
||
{
|
||
ANSI_API_WITHOUT_ANSI_OUTPUT(
|
||
1,
|
||
AParm[0].lpNetResA = lpNetResource; ,
|
||
"N" NETRES_RP,
|
||
WNetOpenEnumW(dwScope, dwType, dwUsage, UParm[0].lpNetResW, lphEnum);
|
||
)
|
||
}
|
||
|
||
DWORD APIENTRY
|
||
WNetEnumResourceA (
|
||
IN HANDLE hEnum,
|
||
IN OUT LPDWORD lpcCount,
|
||
OUT LPVOID lpBuffer,
|
||
IN OUT LPDWORD lpBufferSize
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function calls the unicode version of WNetEnumResource and
|
||
then converts the strings that are returned into ansi strings.
|
||
Since the user provided buffer is used to contain the unicode strings,
|
||
that buffer should be allocated with the size of unicode strings
|
||
in mind.
|
||
|
||
Arguments:
|
||
|
||
|
||
Return Value:
|
||
|
||
|
||
--*/
|
||
{
|
||
DWORD status = WNetEnumResourceW(
|
||
hEnum,
|
||
lpcCount,
|
||
lpBuffer,
|
||
lpBufferSize);
|
||
|
||
if (status == WN_SUCCESS)
|
||
{
|
||
//
|
||
// The output buffer contains an array of NETRESOURCEWs, plus strings.
|
||
// Convert the Unicode strings pointed to by these NETRESOURCEWs
|
||
// to Ansi strings, in place.
|
||
//
|
||
LPNETRESOURCEW lpNetResW = (LPNETRESOURCEW) lpBuffer;
|
||
for (DWORD i=0; i<*lpcCount; i++, lpNetResW++)
|
||
{
|
||
for (UINT iField = 0;
|
||
iField < NUMBER_OF_NETRESFIELD;
|
||
iField++)
|
||
{
|
||
if (lpNetResW->*NRWField[iField] != NULL)
|
||
{
|
||
status = OutputStringToAnsiInPlace(
|
||
lpNetResW->*NRWField[iField]);
|
||
|
||
if (status != WN_SUCCESS)
|
||
{
|
||
MPR_LOG0(ERROR,"WNetEnumResourceA: Couldn't convert all structs\n");
|
||
status = WN_SUCCESS;
|
||
*lpcCount = i;
|
||
break; // breaks out of both loops
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
SET_AND_RETURN(status)
|
||
}
|
||
|
||
|
||
|
||
DWORD APIENTRY
|
||
WNetGetResourceInformationA(
|
||
IN LPNETRESOURCEA lpNetResource,
|
||
OUT LPVOID lpBuffer,
|
||
IN OUT LPDWORD lpBufferSize,
|
||
OUT LPSTR * lplpSystem
|
||
)
|
||
{
|
||
DWORD status;
|
||
LPBYTE tempBuffer = NULL;
|
||
ANSI_PARM AParm[4];
|
||
UNICODE_PARM UParm[4];
|
||
|
||
AParm[0].lpNetResA = lpNetResource;
|
||
AParm[1].lpvoid = lpBuffer;
|
||
AParm[2].lpdword = lpBufferSize;
|
||
AParm[3].dword = sizeof(NETRESOURCE);
|
||
|
||
status = InputParmsToUnicode("N" NETRES_RP "Bs", AParm, UParm, &tempBuffer);
|
||
|
||
if (status == WN_SUCCESS)
|
||
{
|
||
status = WNetGetResourceInformationW(
|
||
UParm[0].lpNetResW,
|
||
UParm[1].lpbyte,
|
||
&UParm[2].dword,
|
||
(LPWSTR *) lplpSystem
|
||
);
|
||
|
||
if (status == WN_SUCCESS)
|
||
{
|
||
ANSI_OUT_BUFFER Buf((LPBYTE) lpBuffer, *lpBufferSize);
|
||
|
||
//
|
||
// Convert the Unicode netresource returned to Ansi
|
||
//
|
||
status = OutputNetResourceToAnsi(UParm[1].lpNetResW, &Buf);
|
||
|
||
if (status == WN_SUCCESS)
|
||
{
|
||
//
|
||
// Convert the Unicode string (*lplpSystem) returned to Ansi
|
||
//
|
||
LPWSTR lpSystemW = * (LPWSTR *) lplpSystem;
|
||
if (lpSystemW != NULL)
|
||
{
|
||
*lplpSystem = (LPSTR) Buf.Next();
|
||
status = OutputStringToAnsi(lpSystemW, &Buf);
|
||
}
|
||
}
|
||
|
||
//
|
||
// Map the results to WNet API conventions
|
||
//
|
||
if (status == WN_SUCCESS && Buf.Overflow())
|
||
{
|
||
*lpBufferSize = Buf.GetUsage();
|
||
status = WN_MORE_DATA;
|
||
}
|
||
}
|
||
else if (status == WN_MORE_DATA)
|
||
{
|
||
//
|
||
// Adjust the required buffer size for ansi/DBCS.
|
||
//
|
||
// We don't know how many characters will be required so we have to
|
||
// assume the worst case (all characters are DBCS characters).
|
||
//
|
||
*lpBufferSize = UParm[2].dword;
|
||
}
|
||
}
|
||
|
||
LocalFree(tempBuffer);
|
||
|
||
SET_AND_RETURN(status)
|
||
}
|
||
|
||
|
||
DWORD APIENTRY
|
||
WNetGetResourceParentA(
|
||
IN LPNETRESOURCEA lpNetResource,
|
||
OUT LPVOID lpBuffer,
|
||
IN OUT LPDWORD lpBufferSize
|
||
)
|
||
{
|
||
DWORD status;
|
||
LPBYTE tempBuffer = NULL;
|
||
ANSI_PARM AParm[4];
|
||
UNICODE_PARM UParm[4];
|
||
|
||
AParm[0].lpNetResA = lpNetResource;
|
||
AParm[1].lpvoid = lpBuffer;
|
||
AParm[2].lpdword = lpBufferSize;
|
||
AParm[3].dword = sizeof(NETRESOURCE);
|
||
|
||
status = InputParmsToUnicode("N" NETRES_RP "Bs", AParm, UParm, &tempBuffer);
|
||
|
||
if (status == WN_SUCCESS)
|
||
{
|
||
status = WNetGetResourceParentW(
|
||
UParm[0].lpNetResW,
|
||
UParm[1].lpbyte,
|
||
&UParm[2].dword
|
||
);
|
||
|
||
if (status == WN_SUCCESS)
|
||
{
|
||
//
|
||
// Convert the Unicode netresource returned to Ansi
|
||
//
|
||
status = OutputBufferToAnsi('N', UParm[1].lpbyte, lpBuffer, lpBufferSize);
|
||
}
|
||
else if (status == WN_MORE_DATA)
|
||
{
|
||
//
|
||
// Adjust the required buffer size for ansi/DBCS.
|
||
//
|
||
// We don't know how many characters will be required so we have to
|
||
// assume the worst case (all characters are DBCS characters).
|
||
//
|
||
*lpBufferSize = UParm[2].dword;
|
||
}
|
||
}
|
||
|
||
LocalFree(tempBuffer);
|
||
|
||
SET_AND_RETURN(status)
|
||
}
|
||
|
||
|
||
|
||
DWORD APIENTRY
|
||
WNetGetUserA (
|
||
IN LPCSTR lpName,
|
||
OUT LPSTR lpUserName,
|
||
IN OUT LPDWORD lpnLength
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function retreives the current default user name or the username
|
||
used to establish a network connection.
|
||
|
||
Arguments:
|
||
|
||
lpName - Points to a null-terminated string that specifies either the
|
||
name or the local device to return the user name for, or a network
|
||
name that the user has made a connection to. If the pointer is
|
||
NULL, the name of the current user is returned.
|
||
|
||
lpUserName - Points to a buffer to receive the null-terminated
|
||
user name.
|
||
|
||
lpnLength - Specifies the size (in characters) of the buffer pointed
|
||
to by the lpUserName parameter. If the call fails because the
|
||
buffer is not big enough, this location is used to return the
|
||
required buffer size.
|
||
|
||
Return Value:
|
||
|
||
|
||
--*/
|
||
{
|
||
ANSI_API_WITH_ANSI_OUTPUT(
|
||
3,
|
||
AParm[0].lpcstr = lpName;
|
||
AParm[1].lpvoid = lpUserName;
|
||
AParm[2].lpdword = lpnLength; ,
|
||
"SB",
|
||
WNetGetUserW(UParm[0].lpwstr, UParm[1].lpwstr, lpnLength); ,
|
||
OutputBufferToAnsi('S', UParm[1].lpbyte, lpUserName, lpnLength);
|
||
)
|
||
}
|
||
|
||
|
||
DWORD
|
||
RestoreConnectionA0 (
|
||
IN HWND hwnd,
|
||
IN LPSTR lpDevice
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Arguments:
|
||
|
||
Return Value:
|
||
|
||
--*/
|
||
{
|
||
ANSI_API_WITHOUT_ANSI_OUTPUT(
|
||
1,
|
||
AParm[0].lpcstr = lpDevice; ,
|
||
"S",
|
||
WNetRestoreConnectionW(hwnd, UParm[0].lpwstr);
|
||
)
|
||
}
|
||
|
||
|
||
DWORD
|
||
RestoreConnection2A0 (
|
||
IN HWND hwnd,
|
||
IN LPSTR lpDevice,
|
||
IN DWORD dwFlags,
|
||
OUT BOOL* pfReconnectFailed
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Arguments:
|
||
|
||
Return Value:
|
||
|
||
--*/
|
||
{
|
||
ANSI_API_WITHOUT_ANSI_OUTPUT(
|
||
1,
|
||
AParm[0].lpcstr = lpDevice; ,
|
||
"S",
|
||
WNetRestoreConnection2W(hwnd, UParm[0].lpwstr, dwFlags, pfReconnectFailed);
|
||
)
|
||
}
|
||
|
||
|
||
DWORD
|
||
WNetGetDirectoryTypeA (
|
||
IN LPSTR lpName,
|
||
OUT LPINT lpType,
|
||
IN BOOL bFlushCache
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Arguments:
|
||
|
||
Return Value:
|
||
|
||
--*/
|
||
{
|
||
ANSI_API_WITHOUT_ANSI_OUTPUT(
|
||
1,
|
||
AParm[0].lpcstr = lpName; ,
|
||
"S",
|
||
WNetGetDirectoryTypeW(UParm[0].lpwstr, lpType, bFlushCache);
|
||
)
|
||
}
|
||
|
||
DWORD
|
||
WNetDirectoryNotifyA (
|
||
IN HWND hwnd,
|
||
IN LPSTR lpDir,
|
||
IN DWORD dwOper
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Arguments:
|
||
|
||
Return Value:
|
||
|
||
--*/
|
||
{
|
||
ANSI_API_WITHOUT_ANSI_OUTPUT(
|
||
1,
|
||
AParm[0].lpcstr = lpDir; ,
|
||
"S",
|
||
WNetDirectoryNotifyW(hwnd, UParm[0].lpwstr, dwOper);
|
||
)
|
||
}
|
||
|
||
DWORD APIENTRY
|
||
WNetGetLastErrorA (
|
||
OUT LPDWORD lpError,
|
||
OUT LPSTR lpErrorBuf,
|
||
IN DWORD nErrorBufSize,
|
||
OUT LPSTR lpNameBuf,
|
||
IN DWORD nNameBufSize
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Arguments:
|
||
|
||
Return Value:
|
||
|
||
--*/
|
||
{
|
||
DWORD status;
|
||
|
||
//
|
||
// We re-use the Ansi buffers for the Unicode API.
|
||
// There are no input Ansi parameters to convert to Unicode.
|
||
//
|
||
// Call the Unicode version of the function.
|
||
// Note: The sizes for the buffers that are passed in assume that
|
||
// the returned unicode strings will return DBCS characters.
|
||
//
|
||
status = WNetGetLastErrorW(
|
||
lpError,
|
||
(LPWSTR) lpErrorBuf,
|
||
nErrorBufSize / sizeof(WCHAR),
|
||
(LPWSTR) lpNameBuf,
|
||
nNameBufSize / sizeof(WCHAR)
|
||
);
|
||
|
||
//
|
||
// Convert the returned strings to Ansi, in place.
|
||
// There should be no buffer overflow.
|
||
//
|
||
if (status == WN_SUCCESS)
|
||
{
|
||
status = OutputStringToAnsiInPlace((LPWSTR) lpErrorBuf);
|
||
|
||
if (status == WN_SUCCESS)
|
||
{
|
||
status = OutputStringToAnsiInPlace((LPWSTR) lpNameBuf);
|
||
}
|
||
}
|
||
|
||
SET_AND_RETURN(status)
|
||
}
|
||
|
||
|
||
|
||
VOID
|
||
WNetSetLastErrorA(
|
||
IN DWORD err,
|
||
IN LPSTR lpError,
|
||
IN LPSTR lpProviders
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Arguments:
|
||
|
||
Return Value:
|
||
|
||
--*/
|
||
{
|
||
DWORD status;
|
||
LPBYTE tempBuffer = NULL;
|
||
ANSI_PARM AParm[2];
|
||
UNICODE_PARM UParm[2];
|
||
|
||
AParm[0].lpcstr = lpError;
|
||
AParm[1].lpcstr = lpProviders;
|
||
|
||
status = InputParmsToUnicode("SS", AParm, UParm, &tempBuffer);
|
||
|
||
if (status != WN_SUCCESS)
|
||
{
|
||
UParm[0].lpwstr = NULL;
|
||
UParm[1].lpwstr = NULL;
|
||
}
|
||
|
||
WNetSetLastErrorW(err, UParm[0].lpwstr, UParm[1].lpwstr);
|
||
|
||
LocalFree(tempBuffer);
|
||
|
||
return;
|
||
}
|
||
|
||
|
||
|
||
DWORD APIENTRY
|
||
MultinetGetErrorTextA(
|
||
OUT LPSTR lpErrorTextBuf OPTIONAL,
|
||
IN OUT LPDWORD lpnErrorBufSize OPTIONAL,
|
||
OUT LPSTR lpProviderNameBuf OPTIONAL,
|
||
IN OUT LPDWORD lpnNameBufSize OPTIONAL
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Arguments:
|
||
|
||
Return Value:
|
||
|
||
--*/
|
||
{
|
||
// CODEWORK: This could be simplified by re-using the Unicode buffers,
|
||
// like WNetGetLastErrorA.
|
||
|
||
DWORD status;
|
||
LPBYTE tempBuffer = NULL;
|
||
ANSI_PARM AParm[4];
|
||
UNICODE_PARM UParm[4];
|
||
|
||
AParm[0].lpvoid = lpErrorTextBuf;
|
||
AParm[1].lpdword = lpnErrorBufSize;
|
||
AParm[2].lpvoid = lpProviderNameBuf;
|
||
AParm[3].lpdword = lpnNameBufSize;
|
||
|
||
status = InputParmsToUnicode("BB", AParm, UParm, &tempBuffer);
|
||
|
||
if (status == WN_SUCCESS)
|
||
{
|
||
// Remember the sizes before calling the function
|
||
DWORD nErrorBufSize;
|
||
DWORD nNameBufSize;
|
||
if (ARGUMENT_PRESENT(lpErrorTextBuf))
|
||
{
|
||
nErrorBufSize = *lpnErrorBufSize;
|
||
}
|
||
if (ARGUMENT_PRESENT(lpProviderNameBuf))
|
||
{
|
||
nNameBufSize = *lpnNameBufSize;
|
||
}
|
||
|
||
status = MultinetGetErrorTextW(
|
||
UParm[0].lpwstr,
|
||
lpnErrorBufSize,
|
||
UParm[2].lpwstr,
|
||
lpnNameBufSize
|
||
);
|
||
|
||
if (status == WN_SUCCESS || status == WN_MORE_DATA)
|
||
{
|
||
if (ARGUMENT_PRESENT(lpErrorTextBuf) &&
|
||
nErrorBufSize == *lpnErrorBufSize)
|
||
{
|
||
// The Unicode API must have written the error text buffer
|
||
DWORD status2 = OutputBufferToAnsi(
|
||
'S',
|
||
UParm[0].lpbyte,
|
||
lpErrorTextBuf,
|
||
lpnErrorBufSize);
|
||
|
||
if (status2 != WN_SUCCESS)
|
||
{
|
||
status = status2;
|
||
}
|
||
}
|
||
}
|
||
|
||
if (status == WN_SUCCESS || status == WN_MORE_DATA)
|
||
{
|
||
if (ARGUMENT_PRESENT(lpProviderNameBuf) &&
|
||
nNameBufSize == *lpnNameBufSize)
|
||
{
|
||
// The Unicode API must have written the provider name buffer
|
||
DWORD status2 = OutputBufferToAnsi(
|
||
'S',
|
||
UParm[2].lpbyte,
|
||
lpProviderNameBuf,
|
||
lpnNameBufSize);
|
||
|
||
if (status2 != WN_SUCCESS)
|
||
{
|
||
status = status2;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
LocalFree(tempBuffer);
|
||
|
||
SET_AND_RETURN(status)
|
||
}
|
||
|
||
|
||
|
||
DWORD
|
||
WNetPropertyDialogA (
|
||
HWND hwndParent,
|
||
DWORD iButton,
|
||
DWORD nPropSel,
|
||
LPSTR lpszName,
|
||
DWORD nType
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Arguments:
|
||
|
||
Return Value:
|
||
|
||
--*/
|
||
{
|
||
ANSI_API_WITHOUT_ANSI_OUTPUT(
|
||
1,
|
||
AParm[0].lpcstr = lpszName; ,
|
||
"S",
|
||
WNetPropertyDialogW(hwndParent, iButton, nPropSel, UParm[0].lpwstr, nType);
|
||
)
|
||
}
|
||
|
||
|
||
DWORD
|
||
WNetGetPropertyTextA (
|
||
IN DWORD iButton,
|
||
IN DWORD nPropSel,
|
||
IN LPSTR lpszName,
|
||
OUT LPSTR lpszButtonName,
|
||
IN DWORD nButtonNameLen,
|
||
IN DWORD nType
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Arguments:
|
||
|
||
Return Value:
|
||
|
||
--*/
|
||
{
|
||
ANSI_API_WITH_ANSI_OUTPUT(
|
||
3,
|
||
AParm[0].lpcstr = lpszName;
|
||
AParm[1].lpvoid = lpszButtonName;
|
||
AParm[2].lpdword = &nButtonNameLen; ,
|
||
"SB",
|
||
WNetGetPropertyTextW(iButton, nPropSel, UParm[0].lpwstr,
|
||
UParm[1].lpwstr, nButtonNameLen, nType); ,
|
||
OutputBufferToAnsi('S', UParm[1].lpbyte, lpszButtonName, &nButtonNameLen);
|
||
)
|
||
}
|
||
|
||
|
||
|
||
DWORD APIENTRY
|
||
WNetFormatNetworkNameA(
|
||
IN LPCSTR lpProvider,
|
||
IN LPCSTR lpRemoteName,
|
||
OUT LPSTR lpFormattedName,
|
||
IN OUT LPDWORD lpnLength, // In characters!
|
||
IN DWORD dwFlags,
|
||
IN DWORD dwAveCharPerLine
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Arguments:
|
||
|
||
Return Value:
|
||
|
||
--*/
|
||
{
|
||
ANSI_API_WITH_ANSI_OUTPUT(
|
||
4,
|
||
AParm[0].lpcstr = lpProvider;
|
||
AParm[1].lpcstr = lpRemoteName;
|
||
AParm[2].lpvoid = lpFormattedName;
|
||
AParm[3].lpdword = lpnLength; ,
|
||
"SSB",
|
||
WNetFormatNetworkNameW(
|
||
UParm[0].lpwstr,
|
||
UParm[1].lpwstr,
|
||
UParm[2].lpwstr,
|
||
lpnLength,
|
||
dwFlags,
|
||
dwAveCharPerLine
|
||
); ,
|
||
OutputBufferToAnsi('S', UParm[2].lpbyte, lpFormattedName, lpnLength);
|
||
)
|
||
}
|
||
|
||
|