mirror of https://github.com/tongzx/nt5src
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.
794 lines
21 KiB
794 lines
21 KiB
/*++
|
|
|
|
Copyright (c) 1991 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
userdir.cxx
|
|
|
|
Abstract:
|
|
|
|
This file contains the API entry points for the following functions:
|
|
|
|
WNetGetUserW
|
|
WNetGetDirectoryTypeW
|
|
WNetDirectoryNotifyW
|
|
WNetGetHomeDirectoryW
|
|
|
|
Author:
|
|
|
|
Dan Lafferty (danl) 17-Oct-1991
|
|
|
|
Environment:
|
|
|
|
User Mode - Win32
|
|
|
|
Revision History:
|
|
|
|
05-May-1999 jschwart
|
|
Make provider addition/removal dynamic
|
|
|
|
12-Jul-1995 anirudhs
|
|
Add WNetGetHomeDirectory.
|
|
|
|
17-Jun-1994 danl
|
|
WNetGetDirectoryTypeW: Cache the drive letter and provider index
|
|
to make file manager faster.
|
|
|
|
27-May-1994 danl
|
|
WNetGetDirectoryTypeW & WNetDirectoryNotifyW: If no provider
|
|
claims the connection in question, then we try all providers.
|
|
The actual rule is that we need to pass it to the lanman
|
|
provider anyway (so it can check for a share). But to play
|
|
completely fair, we'll pass it to everyone.
|
|
|
|
28-Aug-1992 danl
|
|
When GetUsername returns the name, it didn't handle the case where
|
|
the buffer was too small. (This may have been a bug in GetUserName).
|
|
Now this code copies it into a temp buffer (MAX_PATH) and determines
|
|
the size.
|
|
|
|
03-Aug-1992 danl
|
|
WNetGetUser now calls GetUsername when the device name parameter
|
|
is NULL.
|
|
|
|
17-Oct-1991 danl
|
|
Created
|
|
|
|
|
|
--*/
|
|
//
|
|
// INCLUDES
|
|
//
|
|
|
|
#include "precomp.hxx"
|
|
#include <tstring.h> // STRCPY
|
|
|
|
//
|
|
// DEFINES
|
|
//
|
|
|
|
|
|
|
|
DWORD
|
|
WNetGetUserW (
|
|
IN LPCWSTR lpName,
|
|
OUT LPWSTR lpUserName,
|
|
IN OUT LPDWORD lpBufferSize
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Returns the user name that is associated with making a particular
|
|
connection. If no connection is specified, the current username
|
|
for the process is returned.
|
|
|
|
Arguments:
|
|
|
|
lpName - This is a pointer to a device name string. If NULL, the
|
|
username for the current user of this process is returned.
|
|
|
|
lpUserName - This is a pointer to the buffer that will receive the
|
|
username string.
|
|
|
|
lpBufferSize - This is the size (in characters) of the buffer that
|
|
will receive the username.
|
|
|
|
Return Value:
|
|
|
|
|
|
Note:
|
|
|
|
|
|
--*/
|
|
{
|
|
DWORD status = WN_SUCCESS;
|
|
DWORD indexArray[DEFAULT_MAX_PROVIDERS];
|
|
LPDWORD index = indexArray;
|
|
DWORD numProviders;
|
|
DWORD statusFlag = 0; // used to indicate major error types
|
|
BOOL fcnSupported = FALSE; // Is fcn supported by a provider?
|
|
DWORD i;
|
|
WCHAR pDriveLetter[4];
|
|
UINT uDriveType;
|
|
DWORD providerIndex; // ignored
|
|
|
|
//
|
|
// If the device or network name is NULL then we
|
|
// will return the name of the current user.
|
|
//
|
|
__try
|
|
{
|
|
if (IS_EMPTY_STRING(lpName)) {
|
|
|
|
//
|
|
// GetUserName modifies *lpBufferSize on success -- we don't
|
|
//
|
|
DWORD dwTempSize = *lpBufferSize;
|
|
|
|
lpName = NULL;
|
|
|
|
if (!GetUserName(lpUserName, &dwTempSize))
|
|
{
|
|
status = GetLastError();
|
|
MPR_LOG(ERROR,"WNetGetUserW: GetUserName Failed %d\n",status);
|
|
if (status == ERROR_INSUFFICIENT_BUFFER)
|
|
{
|
|
*lpBufferSize = dwTempSize;
|
|
status = WN_MORE_DATA;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
|
|
//
|
|
// As long as we're already in a try-except block,
|
|
// try setting up the check to see if lpName is
|
|
// a local drive.
|
|
//
|
|
pDriveLetter[0] = lpName[0];
|
|
pDriveLetter[1] = lpName[1];
|
|
}
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER) {
|
|
|
|
status = GetExceptionCode();
|
|
if (status != EXCEPTION_ACCESS_VIOLATION) {
|
|
MPR_LOG(ERROR,"WNetGetUser:Unexpected Exception 0x%lx\n",status);
|
|
}
|
|
status = WN_BAD_POINTER;
|
|
}
|
|
|
|
if (lpName == NULL || status != WN_SUCCESS) {
|
|
goto CleanExit;
|
|
}
|
|
|
|
pDriveLetter[2] = L'\\';
|
|
pDriveLetter[3] = L'\0';
|
|
|
|
uDriveType = GetDriveType(pDriveLetter);
|
|
|
|
//
|
|
// Eliminate all cases of drives that aren't connected to
|
|
// a network resource. Note that network provider names
|
|
// and UNC shares return DRIVE_NO_ROOT_DIR, so we need to
|
|
// make sure it's a valid drive name in that case.
|
|
//
|
|
if (uDriveType == DRIVE_REMOVABLE ||
|
|
uDriveType == DRIVE_FIXED ||
|
|
uDriveType == DRIVE_CDROM ||
|
|
uDriveType == DRIVE_RAMDISK ||
|
|
(uDriveType == DRIVE_NO_ROOT_DIR && pDriveLetter[1] == L':'))
|
|
|
|
{
|
|
status = WN_NOT_CONNECTED;
|
|
goto CleanExit;
|
|
}
|
|
|
|
{
|
|
MprCheckProviders();
|
|
|
|
CProviderSharedLock PLock;
|
|
|
|
//
|
|
// If the device or network name is the name of a network
|
|
// provider, then we will return the name of the current user.
|
|
// Only a Level 1 init is needed for MprGetProviderIndex
|
|
//
|
|
if (!(GlobalInitLevel & FIRST_LEVEL)) {
|
|
status = MprLevel1Init();
|
|
if (status != WN_SUCCESS) {
|
|
return(status);
|
|
}
|
|
}
|
|
|
|
if (MprGetProviderIndex(lpName, &providerIndex))
|
|
{
|
|
lpName = NULL;
|
|
|
|
if (!GetUserName(lpUserName, lpBufferSize))
|
|
{
|
|
status = GetLastError();
|
|
MPR_LOG(ERROR,"WNetGetUserW: GetUserName Failed %d\n",status);
|
|
if (status == ERROR_INSUFFICIENT_BUFFER)
|
|
{
|
|
status = WN_MORE_DATA;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (lpName == NULL || status != WN_SUCCESS) {
|
|
goto CleanExit;
|
|
}
|
|
|
|
//
|
|
// Find the list of providers to call for this request.
|
|
// If there are no active providers, MprFindCallOrder returns
|
|
// WN_NO_NETWORK.
|
|
//
|
|
INIT_IF_NECESSARY(NETWORK_LEVEL,status);
|
|
|
|
status = MprFindCallOrder(
|
|
NULL,
|
|
&index,
|
|
&numProviders,
|
|
NETWORK_TYPE);
|
|
|
|
if (status != WN_SUCCESS) {
|
|
goto CleanExit;
|
|
}
|
|
|
|
//
|
|
// if none of them are started, return error
|
|
//
|
|
if (!MprNetIsAvailable())
|
|
{
|
|
status = WN_NO_NETWORK;
|
|
goto CleanExit;
|
|
}
|
|
|
|
//
|
|
// Loop through the list of providers until one answers the request,
|
|
// or the list is exhausted.
|
|
//
|
|
for (i=0; i<numProviders; i++) {
|
|
|
|
//
|
|
// Call the appropriate providers API entry point
|
|
//
|
|
LPPROVIDER provider = &GlobalProviderInfo[ index[i] ];
|
|
|
|
if (provider->GetUser != NULL) {
|
|
|
|
fcnSupported = TRUE;
|
|
|
|
__try {
|
|
status = provider->GetUser(
|
|
(LPWSTR) lpName,
|
|
lpUserName,
|
|
lpBufferSize);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER) {
|
|
status = GetExceptionCode();
|
|
if (status != EXCEPTION_ACCESS_VIOLATION) {
|
|
MPR_LOG(ERROR,"WNetGetUser:Unexpected Exception 0x%lx\n",status);
|
|
}
|
|
status = WN_BAD_POINTER;
|
|
}
|
|
|
|
//
|
|
// WN_CONNECTED_OTHER_PASSWORD_DEFAULT will be returned when user X mapped a
|
|
// drive as user Y and the credentials for user Y were stored in CredMan when
|
|
// the connection was made. Since the username is correctly filled in with
|
|
// user Y in this case, simply massage the return code to success.
|
|
//
|
|
|
|
if (status == WN_CONNECTED_OTHER_PASSWORD_DEFAULT)
|
|
{
|
|
status = WN_SUCCESS;
|
|
}
|
|
|
|
if (status == WN_NO_NETWORK) {
|
|
statusFlag |= NO_NET;
|
|
}
|
|
else if ((status == WN_NOT_CONNECTED) ||
|
|
(status == WN_BAD_LOCALNAME)){
|
|
|
|
statusFlag |= BAD_NAME;
|
|
}
|
|
else {
|
|
//
|
|
// If it wasn't one of those errors, then the provider
|
|
// must have accepted responsibility for the request.
|
|
// so we exit and process the results. Note that the
|
|
// statusFlag is cleared because we want to ignore other
|
|
// error information that we gathered up until now.
|
|
//
|
|
statusFlag = 0;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (fcnSupported == FALSE) {
|
|
//
|
|
// No providers in the list support the API function. Therefore,
|
|
// we assume that no networks are installed.
|
|
//
|
|
status = WN_NOT_SUPPORTED;
|
|
}
|
|
|
|
//
|
|
// Handle special errors.
|
|
//
|
|
if (statusFlag == (NO_NET | BAD_NAME)) {
|
|
//
|
|
// Check to see if there was a mix of special errors that occured.
|
|
// If so, pass back the combined error message. Otherwise, let the
|
|
// last error returned get passed back.
|
|
//
|
|
status = WN_NO_NET_OR_BAD_PATH;
|
|
}
|
|
|
|
CleanExit:
|
|
//
|
|
// If memory was allocated by MprFindCallOrder, free it.
|
|
//
|
|
if (index != indexArray) {
|
|
LocalFree(index);
|
|
}
|
|
|
|
if (status != WN_SUCCESS){
|
|
SetLastError(status);
|
|
}
|
|
|
|
return(status);
|
|
}
|
|
|
|
|
|
DWORD
|
|
WNetGetDirectoryTypeW (
|
|
IN LPTSTR lpName,
|
|
OUT LPINT lpType,
|
|
IN BOOL bFlushCache
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
Note:
|
|
|
|
|
|
--*/
|
|
{
|
|
DWORD status = WN_SUCCESS;
|
|
LPDWORD index;
|
|
DWORD indexArray[DEFAULT_MAX_PROVIDERS];
|
|
DWORD numProviders = 0;
|
|
DWORD providerIndex;
|
|
DWORD statusFlag = 0; // used to indicate major error types
|
|
WCHAR lpDriveName[4];
|
|
UINT uDriveType;
|
|
|
|
index = indexArray;
|
|
|
|
//
|
|
// Probe the drive letter portion of the lpName.
|
|
//
|
|
__try {
|
|
|
|
lpDriveName[0] = lpName[0];
|
|
lpDriveName[1] = lpName[1];
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER) {
|
|
|
|
status = GetExceptionCode();
|
|
if (status != EXCEPTION_ACCESS_VIOLATION) {
|
|
MPR_LOG(ERROR,"WNetGetDirectoryType:Unexpected Exception 0x%lx\n",status);
|
|
}
|
|
status = WN_BAD_POINTER;
|
|
}
|
|
|
|
if (status != WN_SUCCESS) {
|
|
return(status);
|
|
}
|
|
|
|
lpDriveName[2] = L'\\';
|
|
lpDriveName[3] = L'\0';
|
|
|
|
uDriveType = GetDriveType(lpDriveName);
|
|
|
|
if (uDriveType == DRIVE_REMOVABLE ||
|
|
uDriveType == DRIVE_FIXED ||
|
|
uDriveType == DRIVE_CDROM ||
|
|
uDriveType == DRIVE_RAMDISK)
|
|
{
|
|
*lpType = 0; // 0 means a non-network drive
|
|
return WN_SUCCESS;
|
|
}
|
|
|
|
MprCheckProviders();
|
|
|
|
CProviderSharedLock PLock;
|
|
|
|
INIT_IF_NECESSARY(NETWORK_LEVEL,status);
|
|
|
|
//
|
|
// Find the Provider Index associated with the drive letter in
|
|
// the pathname (lpszName).
|
|
// NOTE: This function handles exceptions.
|
|
//
|
|
|
|
status = MprFindProviderForPath(lpName, &providerIndex);
|
|
if (status != WN_SUCCESS) {
|
|
MPR_LOG1(ERROR,"WNetGetDirectoryType: Couldn't find provider for this "
|
|
"path. Error = %d\n",status);
|
|
|
|
//
|
|
// Find the list of providers to call for this request.
|
|
// Since no provider claimed this path, then
|
|
// we need to at least try the lanman provider.
|
|
// Actually we'll give them all a chance.
|
|
//
|
|
|
|
status = MprFindCallOrder(
|
|
NULL,
|
|
&index,
|
|
&numProviders,
|
|
NETWORK_TYPE);
|
|
|
|
if (status != WN_SUCCESS) {
|
|
return(status);
|
|
}
|
|
}
|
|
else {
|
|
numProviders = 1;
|
|
index[0] = providerIndex;
|
|
}
|
|
|
|
//
|
|
// Loop through the list of providers until one answers the request,
|
|
// or the list is exhausted.
|
|
//
|
|
BOOL fcnSupported = FALSE; // Is fcn supported by a provider?
|
|
for (DWORD i=0; i<numProviders; i++) {
|
|
//
|
|
// Call the appropriate provider's API entry point
|
|
//
|
|
LPPROVIDER provider = &GlobalProviderInfo[ index[i] ];
|
|
|
|
if (provider->GetDirectoryType != NULL) {
|
|
|
|
fcnSupported = TRUE;
|
|
|
|
__try {
|
|
status = provider->GetDirectoryType(
|
|
lpName,
|
|
lpType,
|
|
bFlushCache) ;
|
|
}
|
|
|
|
__except(EXCEPTION_EXECUTE_HANDLER) {
|
|
status = GetExceptionCode();
|
|
if (status != EXCEPTION_ACCESS_VIOLATION) {
|
|
MPR_LOG(ERROR,"WNetGetDirectoryType:Unexpected Exception 0x%lx\n",status);
|
|
}
|
|
status = WN_BAD_POINTER;
|
|
}
|
|
if (status == WN_NO_NETWORK) {
|
|
statusFlag |= NO_NET;
|
|
}
|
|
else if ((status == WN_NOT_CONNECTED) ||
|
|
(status == WN_BAD_LOCALNAME)){
|
|
|
|
statusFlag |= BAD_NAME;
|
|
}
|
|
else {
|
|
//
|
|
// If it wasn't one of those errors, then the provider
|
|
// must have accepted responsibility for the request.
|
|
// so we exit and process the results. Note that the
|
|
// statusFlag is cleared because we want to ignore other
|
|
// error information that we gathered up until now.
|
|
//
|
|
statusFlag = 0;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (fcnSupported == FALSE) {
|
|
//
|
|
// No providers in the list support the API function. Therefore,
|
|
// we assume that no networks are installed.
|
|
//
|
|
status = WN_NOT_SUPPORTED;
|
|
}
|
|
|
|
//
|
|
// If memory was allocated by MprFindCallOrder, free it.
|
|
//
|
|
if (index != indexArray) {
|
|
LocalFree(index);
|
|
}
|
|
|
|
//
|
|
// Handle special errors.
|
|
//
|
|
if (statusFlag == (NO_NET | BAD_NAME)) {
|
|
//
|
|
// Check to see if there was a mix of special errors that occured.
|
|
// If so, pass back the combined error message. Otherwise, let the
|
|
// last error returned get passed back.
|
|
//
|
|
status = WN_NO_NET_OR_BAD_PATH;
|
|
}
|
|
|
|
if (status != WN_SUCCESS){
|
|
SetLastError(status);
|
|
}
|
|
|
|
return(status);
|
|
}
|
|
|
|
|
|
DWORD
|
|
WNetDirectoryNotifyW (
|
|
IN HWND hwnd,
|
|
IN LPTSTR lpDir,
|
|
IN DWORD dwOper
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
Note:
|
|
|
|
|
|
--*/
|
|
{
|
|
DWORD providerIndex;
|
|
DWORD status;
|
|
LPDWORD index;
|
|
DWORD indexArray[DEFAULT_MAX_PROVIDERS];
|
|
DWORD numProviders;
|
|
LPPROVIDER provider;
|
|
DWORD statusFlag = 0; // used to indicate major error types
|
|
BOOL fcnSupported = FALSE; // Is fcn supported by a provider?
|
|
DWORD i;
|
|
|
|
MprCheckProviders();
|
|
|
|
CProviderSharedLock PLock;
|
|
|
|
INIT_IF_NECESSARY(NETWORK_LEVEL,status);
|
|
|
|
index = indexArray;
|
|
|
|
//
|
|
// Find the Provider Index associated with the drive letter in
|
|
// the pathname (lpszName).
|
|
// NOTE: This function handles exceptions.
|
|
//
|
|
status = MprFindProviderForPath(lpDir, &providerIndex);
|
|
if (status != WN_SUCCESS) {
|
|
MPR_LOG1(TRACE,"WNetDirectoryNotify: Couldn't find provider for this "
|
|
"path. Error = %d\n",status);
|
|
|
|
//
|
|
// Find the list of providers to call for this request.
|
|
// Since no provider claimed this path, then
|
|
// we need to at least try the lanman provider.
|
|
// Actually we'll give them all a chance.
|
|
//
|
|
|
|
status = MprFindCallOrder(
|
|
NULL,
|
|
&index,
|
|
&numProviders,
|
|
NETWORK_TYPE);
|
|
|
|
if (status != WN_SUCCESS) {
|
|
MPR_LOG(ERROR,"WNetDirectoryNotifyW: FindCallOrder Failed\n",0);
|
|
return(status);
|
|
}
|
|
}
|
|
else {
|
|
numProviders = 1;
|
|
index[0] = providerIndex;
|
|
}
|
|
|
|
//
|
|
// Loop through the list of providers until one answers the request,
|
|
// or the list is exhausted.
|
|
//
|
|
for (i=0; i<numProviders; i++) {
|
|
//
|
|
// Call the appropriate provider's API entry point
|
|
//
|
|
provider = GlobalProviderInfo + index[i];
|
|
|
|
if (provider->DirectoryNotify != NULL) {
|
|
|
|
fcnSupported = TRUE;
|
|
|
|
__try {
|
|
status = provider->DirectoryNotify(
|
|
hwnd,
|
|
lpDir,
|
|
dwOper);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER) {
|
|
status = GetExceptionCode();
|
|
if (status != EXCEPTION_ACCESS_VIOLATION) {
|
|
MPR_LOG(ERROR,"WNetDirectoryNotify:Unexpected Exception 0x%lx\n",status);
|
|
}
|
|
status = WN_BAD_POINTER;
|
|
}
|
|
if (status == WN_NO_NETWORK) {
|
|
statusFlag |= NO_NET;
|
|
}
|
|
else if ((status == WN_NOT_CONNECTED) ||
|
|
(status == WN_BAD_LOCALNAME)){
|
|
|
|
statusFlag |= BAD_NAME;
|
|
}
|
|
else {
|
|
//
|
|
// If it wasn't one of those errors, then the provider
|
|
// must have accepted responsibility for the request.
|
|
// so we exit and process the results. Note that the
|
|
// statusFlag is cleared because we want to ignore other
|
|
// error information that we gathered up until now.
|
|
//
|
|
statusFlag = 0;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (fcnSupported == FALSE) {
|
|
//
|
|
// No providers in the list support the API function. Therefore,
|
|
// we assume that no networks are installed.
|
|
//
|
|
status = WN_NOT_SUPPORTED;
|
|
}
|
|
|
|
//
|
|
// If memory was allocated by MprFindCallOrder, free it.
|
|
//
|
|
if (index != indexArray) {
|
|
LocalFree(index);
|
|
}
|
|
|
|
//
|
|
// Handle special errors.
|
|
//
|
|
if (statusFlag == (NO_NET | BAD_NAME)) {
|
|
//
|
|
// Check to see if there was a mix of special errors that occured.
|
|
// If so, pass back the combined error message. Otherwise, let the
|
|
// last error returned get passed back.
|
|
//
|
|
status = WN_NO_NET_OR_BAD_PATH;
|
|
}
|
|
|
|
//
|
|
// Handle normal errors passed back from the provider
|
|
//
|
|
if (status != WN_SUCCESS){
|
|
MPR_LOG(TRACE,"WNetDirectoryNotifyW: Call Failed %d\n",status);
|
|
SetLastError(status);
|
|
}
|
|
|
|
return(status);
|
|
}
|
|
|
|
|
|
DWORD
|
|
WNetGetHomeDirectoryW (
|
|
IN LPCWSTR lpProviderName,
|
|
OUT LPWSTR lpDirectory,
|
|
IN OUT LPDWORD lpBufferSize
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Returns the user's home directory.
|
|
|
|
Arguments:
|
|
|
|
lpProviderName - Specifies the name of the network provider for which the
|
|
home directory is retrieved. This parameter exists for Win95 compati-
|
|
bility, and is ignored.
|
|
|
|
lpDirectory - Buffer in which to return the directory path. This will be
|
|
in either UNC or drive-relative form.
|
|
|
|
lpBufferSize - Specifies the size of the lpDirectory buffer, in characters.
|
|
If the call fails because the buffer is not big enough, this will be
|
|
set to the required buffer size.
|
|
|
|
Return Value:
|
|
|
|
WN_SUCCESS - successful
|
|
|
|
WN_MORE_DATA - buffer not large enough
|
|
|
|
WN_NOT_SUPPORTED - user doesn't have a home directory
|
|
|
|
Note:
|
|
|
|
This is an unpublished function, so it doesn't catch exceptions.
|
|
|
|
The path is obtained from environment variables and equals
|
|
%HOMESHARE%%HOMEPATH% if the %HOMESHARE% variable is set, else
|
|
%HOMEDIR%%HOMEPATH% .
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// If HOMESHARE is set, use it in preference to HOMEDRIVE
|
|
//
|
|
LPWSTR ExpandString = L"%HOMEDRIVE%%HOMEPATH%";
|
|
if (GetEnvironmentVariable(L"HOMESHARE", NULL, 0))
|
|
{
|
|
ExpandString = L"%HOMESHARE%%HOMEPATH%";
|
|
}
|
|
|
|
//
|
|
// Expand the environment variables into the buffer
|
|
//
|
|
DWORD cchReturned = ExpandEnvironmentStrings(
|
|
ExpandString,
|
|
lpDirectory,
|
|
*lpBufferSize
|
|
);
|
|
|
|
if (cchReturned == 0)
|
|
{
|
|
// ExpandEnvironmentStrings failed
|
|
return GetLastError();
|
|
}
|
|
|
|
if (cchReturned > *lpBufferSize)
|
|
{
|
|
// Buffer too small; cchReturned is the required size
|
|
*lpBufferSize = cchReturned;
|
|
return WN_MORE_DATA;
|
|
}
|
|
|
|
//
|
|
// Fail if HOMEDRIVE or HOMEPATH is not set - detected by the result
|
|
// string beginning with %HOMEDRIVE% or ending with %HOMEPATH%
|
|
//
|
|
if (wcsncmp(lpDirectory, L"%HOMEPATH%", sizeof("%HOMEPATH%") - 1) == 0 ||
|
|
(cchReturned > sizeof("%HOMEPATH%") &&
|
|
wcscmp(&lpDirectory[cchReturned-sizeof("%HOMEPATH%")], L"%HOMEPATH%") == 0))
|
|
{
|
|
return WN_NOT_SUPPORTED;
|
|
}
|
|
|
|
return WN_SUCCESS;
|
|
}
|
|
|