ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

wnet.c
Go to the documentation of this file.
00001 /*
00002  * MPR WNet functions
00003  *
00004  * Copyright 1999 Ulrich Weigand
00005  * Copyright 2004 Juan Lang
00006  * Copyright 2007 Maarten Lankhorst
00007  *
00008  * This library is free software; you can redistribute it and/or
00009  * modify it under the terms of the GNU Lesser General Public
00010  * License as published by the Free Software Foundation; either
00011  * version 2.1 of the License, or (at your option) any later version.
00012  *
00013  * This library is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00016  * Lesser General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU Lesser General Public
00019  * License along with this library; if not, write to the Free Software
00020  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
00021  */
00022 
00023 #include <stdarg.h>
00024 #include "windef.h"
00025 #include "winbase.h"
00026 #include "winnls.h"
00027 #include "winioctl.h"
00028 #include "winnetwk.h"
00029 #include "npapi.h"
00030 #include "winreg.h"
00031 #include "winuser.h"
00032 #define WINE_MOUNTMGR_EXTENSIONS
00033 #include "ddk/mountmgr.h"
00034 #include "wine/debug.h"
00035 #include "wine/unicode.h"
00036 #include "mprres.h"
00037 #include "wnetpriv.h"
00038 
00039 WINE_DEFAULT_DEBUG_CHANNEL(mpr);
00040 
00041 /* Data structures representing network service providers.  Assumes only one
00042  * thread creates them, and that they are constant for the life of the process
00043  * (and therefore doesn't synchronize access).
00044  * FIXME: only basic provider data and enumeration-related data are implemented
00045  * so far, need to implement the rest too.
00046  */
00047 typedef struct _WNetProvider
00048 {
00049     HMODULE           hLib;
00050     PWSTR             name;
00051     PF_NPGetCaps      getCaps;
00052     DWORD             dwSpecVersion;
00053     DWORD             dwNetType;
00054     DWORD             dwEnumScopes;
00055     PF_NPOpenEnum     openEnum;
00056     PF_NPEnumResource enumResource;
00057     PF_NPCloseEnum    closeEnum;
00058     PF_NPGetResourceInformation getResourceInformation;
00059 } WNetProvider, *PWNetProvider;
00060 
00061 typedef struct _WNetProviderTable
00062 {
00063     LPWSTR           entireNetwork;
00064     DWORD            numAllocated;
00065     DWORD            numProviders;
00066     WNetProvider     table[1];
00067 } WNetProviderTable, *PWNetProviderTable;
00068 
00069 #define WNET_ENUMERATOR_TYPE_NULL     0
00070 #define WNET_ENUMERATOR_TYPE_GLOBAL   1
00071 #define WNET_ENUMERATOR_TYPE_PROVIDER 2
00072 #define WNET_ENUMERATOR_TYPE_CONTEXT  3
00073 
00074 /* An WNet enumerator.  Note that the type doesn't correspond to the scope of
00075  * the enumeration; it represents one of the following types:
00076  * - a 'null' enumeration, one that contains no members
00077  * - a global enumeration, one that's executed across all providers
00078  * - a provider-specific enumeration, one that's only executed by a single
00079  *   provider
00080  * - a context enumeration.  I know this contradicts what I just said about
00081  *   there being no correspondence between the scope and the type, but it's
00082  *   necessary for the special case that a "Entire Network" entry needs to
00083  *   be enumerated in an enumeration of the context scope.  Thus an enumeration
00084  *   of the context scope results in a context type enumerator, which morphs
00085  *   into a global enumeration (so the enumeration continues across all
00086  *   providers).
00087  */
00088 typedef struct _WNetEnumerator
00089 {
00090     DWORD          enumType;
00091     DWORD          providerIndex;
00092     HANDLE         handle;
00093     BOOL           providerDone;
00094     DWORD          dwScope;
00095     DWORD          dwType;
00096     DWORD          dwUsage;
00097     LPNETRESOURCEW lpNet;
00098 } WNetEnumerator, *PWNetEnumerator;
00099 
00100 #define BAD_PROVIDER_INDEX (DWORD)0xffffffff
00101 
00102 /* Returns an index (into the global WNetProviderTable) of the provider with
00103  * the given name, or BAD_PROVIDER_INDEX if not found.
00104  */
00105 static DWORD _findProviderIndexW(LPCWSTR lpProvider);
00106 
00107 static PWNetProviderTable providerTable;
00108 
00109 /*
00110  * Global provider table functions
00111  */
00112 
00113 static void _tryLoadProvider(PCWSTR provider)
00114 {
00115     static const WCHAR servicePrefix[] = { 'S','y','s','t','e','m','\\',
00116      'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
00117      'S','e','r','v','i','c','e','s','\\',0 };
00118     static const WCHAR serviceFmt[] = { '%','s','%','s','\\',
00119      'N','e','t','w','o','r','k','P','r','o','v','i','d','e','r',0 };
00120     WCHAR serviceName[MAX_PATH];
00121     HKEY hKey;
00122 
00123     TRACE("%s\n", debugstr_w(provider));
00124     snprintfW(serviceName, sizeof(serviceName) / sizeof(WCHAR), serviceFmt,
00125      servicePrefix, provider);
00126     serviceName[sizeof(serviceName) / sizeof(WCHAR) - 1] = '\0';
00127     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, serviceName, 0, KEY_READ, &hKey) ==
00128      ERROR_SUCCESS)
00129     {
00130         static const WCHAR szProviderPath[] = { 'P','r','o','v','i','d','e','r',
00131          'P','a','t','h',0 };
00132         WCHAR providerPath[MAX_PATH];
00133         DWORD type, size = sizeof(providerPath);
00134 
00135         if (RegQueryValueExW(hKey, szProviderPath, NULL, &type,
00136          (LPBYTE)providerPath, &size) == ERROR_SUCCESS && type == REG_SZ)
00137         {
00138             static const WCHAR szProviderName[] = { 'N','a','m','e',0 };
00139             PWSTR name = NULL;
00140            
00141             size = 0;
00142             RegQueryValueExW(hKey, szProviderName, NULL, NULL, NULL, &size);
00143             if (size)
00144             {
00145                 name = HeapAlloc(GetProcessHeap(), 0, size);
00146                 if (RegQueryValueExW(hKey, szProviderName, NULL, &type,
00147                  (LPBYTE)name, &size) != ERROR_SUCCESS || type != REG_SZ)
00148                 {
00149                     HeapFree(GetProcessHeap(), 0, name);
00150                     name = NULL;
00151                 }
00152             }
00153             if (name)
00154             {
00155                 HMODULE hLib = LoadLibraryW(providerPath);
00156 
00157                 if (hLib)
00158                 {
00159                     PF_NPGetCaps getCaps = (PF_NPGetCaps)GetProcAddress(hLib,
00160                      "NPGetCaps");
00161 
00162                     TRACE("loaded lib %p\n", hLib);
00163                     if (getCaps)
00164                     {
00165                         PWNetProvider provider =
00166                          &providerTable->table[providerTable->numProviders];
00167 
00168                         provider->hLib = hLib;
00169                         provider->name = name;
00170                         TRACE("name is %s\n", debugstr_w(name));
00171                         provider->getCaps = getCaps;
00172                         provider->dwSpecVersion = getCaps(WNNC_SPEC_VERSION);
00173                         provider->dwNetType = getCaps(WNNC_NET_TYPE);
00174                         TRACE("net type is 0x%08x\n", provider->dwNetType);
00175                         provider->dwEnumScopes = getCaps(WNNC_ENUMERATION);
00176                         if (provider->dwEnumScopes)
00177                         {
00178                             TRACE("supports enumeration\n");
00179                             provider->openEnum = (PF_NPOpenEnum)
00180                              GetProcAddress(hLib, "NPOpenEnum");
00181                             TRACE("openEnum is %p\n", provider->openEnum);
00182                             provider->enumResource = (PF_NPEnumResource)
00183                              GetProcAddress(hLib, "NPEnumResource");
00184                             TRACE("enumResource is %p\n",
00185                              provider->enumResource);
00186                             provider->closeEnum = (PF_NPCloseEnum)
00187                              GetProcAddress(hLib, "NPCloseEnum");
00188                             TRACE("closeEnum is %p\n", provider->closeEnum);
00189                             provider->getResourceInformation = (PF_NPGetResourceInformation)
00190                                     GetProcAddress(hLib, "NPGetResourceInformation");
00191                             TRACE("getResourceInformation is %p\n",
00192                                   provider->getResourceInformation);
00193                             if (!provider->openEnum || !provider->enumResource
00194                              || !provider->closeEnum)
00195                             {
00196                                 provider->openEnum = NULL;
00197                                 provider->enumResource = NULL;
00198                                 provider->closeEnum = NULL;
00199                                 provider->dwEnumScopes = 0;
00200                                 WARN("Couldn't load enumeration functions\n");
00201                             }
00202                         }
00203                         providerTable->numProviders++;
00204                     }
00205                     else
00206                     {
00207                         WARN("Provider %s didn't export NPGetCaps\n",
00208                          debugstr_w(provider));
00209                         HeapFree(GetProcessHeap(), 0, name);
00210                         FreeLibrary(hLib);
00211                     }
00212                 }
00213                 else
00214                 {
00215                     WARN("Couldn't load library %s for provider %s\n",
00216                      debugstr_w(providerPath), debugstr_w(provider));
00217                     HeapFree(GetProcessHeap(), 0, name);
00218                 }
00219             }
00220             else
00221             {
00222                 WARN("Couldn't get provider name for provider %s\n",
00223                  debugstr_w(provider));
00224             }
00225         }
00226         else
00227             WARN("Couldn't open value %s\n", debugstr_w(szProviderPath));
00228         RegCloseKey(hKey);
00229     }
00230     else
00231         WARN("Couldn't open service key for provider %s\n",
00232          debugstr_w(provider));
00233 }
00234 
00235 void wnetInit(HINSTANCE hInstDll)
00236 {
00237     static const WCHAR providerOrderKey[] = { 'S','y','s','t','e','m','\\',
00238      'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
00239      'C','o','n','t','r','o','l','\\',
00240      'N','e','t','w','o','r','k','P','r','o','v','i','d','e','r','\\',
00241      'O','r','d','e','r',0 };
00242      static const WCHAR providerOrder[] = { 'P','r','o','v','i','d','e','r',
00243       'O','r','d','e','r',0 };
00244     HKEY hKey;
00245 
00246     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, providerOrderKey, 0, KEY_READ, &hKey)
00247      == ERROR_SUCCESS)
00248     {
00249         DWORD size = 0;
00250 
00251         RegQueryValueExW(hKey, providerOrder, NULL, NULL, NULL, &size);
00252         if (size)
00253         {
00254             PWSTR providers = HeapAlloc(GetProcessHeap(), 0, size);
00255 
00256             if (providers)
00257             {
00258                 DWORD type;
00259 
00260                 if (RegQueryValueExW(hKey, providerOrder, NULL, &type,
00261                  (LPBYTE)providers, &size) == ERROR_SUCCESS && type == REG_SZ)
00262                 {
00263                     PWSTR ptr;
00264                     DWORD numToAllocate;
00265 
00266                     TRACE("provider order is %s\n", debugstr_w(providers));
00267                     /* first count commas as a heuristic for how many to
00268                      * allocate space for */
00269                     for (ptr = providers, numToAllocate = 1; ptr; )
00270                     {
00271                         ptr = strchrW(ptr, ',');
00272                         if (ptr) {
00273                             numToAllocate++;
00274                             ptr++;
00275                         }
00276                     }
00277                     providerTable =
00278                      HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
00279                      sizeof(WNetProviderTable)
00280                      + (numToAllocate - 1) * sizeof(WNetProvider));
00281                     if (providerTable)
00282                     {
00283                         PWSTR ptrPrev;
00284                         int entireNetworkLen;
00285                         LPCWSTR stringresource;
00286 
00287                         entireNetworkLen = LoadStringW(hInstDll,
00288                          IDS_ENTIRENETWORK, (LPWSTR)&stringresource, 0);
00289                         providerTable->entireNetwork = HeapAlloc(
00290                          GetProcessHeap(), 0, (entireNetworkLen + 1) *
00291                          sizeof(WCHAR));
00292                         if (providerTable->entireNetwork)
00293                         {
00294                             memcpy(providerTable->entireNetwork, stringresource, entireNetworkLen*sizeof(WCHAR));
00295                             providerTable->entireNetwork[entireNetworkLen] = 0;
00296                         }
00297                         providerTable->numAllocated = numToAllocate;
00298                         for (ptr = providers; ptr; )
00299                         {
00300                             ptrPrev = ptr;
00301                             ptr = strchrW(ptr, ',');
00302                             if (ptr)
00303                                 *ptr++ = '\0';
00304                             _tryLoadProvider(ptrPrev);
00305                         }
00306                     }
00307                 }
00308                 HeapFree(GetProcessHeap(), 0, providers);
00309             }
00310         }
00311         RegCloseKey(hKey);
00312     }
00313 }
00314 
00315 void wnetFree(void)
00316 {
00317     if (providerTable)
00318     {
00319         DWORD i;
00320 
00321         for (i = 0; i < providerTable->numProviders; i++)
00322         {
00323             HeapFree(GetProcessHeap(), 0, providerTable->table[i].name);
00324             FreeModule(providerTable->table[i].hLib);
00325         }
00326         HeapFree(GetProcessHeap(), 0, providerTable->entireNetwork);
00327         HeapFree(GetProcessHeap(), 0, providerTable);
00328         providerTable = NULL;
00329     }
00330 }
00331 
00332 static DWORD _findProviderIndexW(LPCWSTR lpProvider)
00333 {
00334     DWORD ret = BAD_PROVIDER_INDEX;
00335 
00336     if (providerTable && providerTable->numProviders)
00337     {
00338         DWORD i;
00339 
00340         for (i = 0; i < providerTable->numProviders &&
00341          ret == BAD_PROVIDER_INDEX; i++)
00342             if (!strcmpW(lpProvider, providerTable->table[i].name))
00343                 ret = i;
00344     }
00345     return ret;
00346 }
00347 
00348 /*
00349  * Browsing Functions
00350  */
00351 
00352 static LPNETRESOURCEW _copyNetResourceForEnumW(LPNETRESOURCEW lpNet)
00353 {
00354     LPNETRESOURCEW ret;
00355 
00356     if (lpNet)
00357     {
00358         ret = HeapAlloc(GetProcessHeap(), 0, sizeof(NETRESOURCEW));
00359         if (ret)
00360         {
00361             size_t len;
00362 
00363             *ret = *lpNet;
00364             ret->lpLocalName = ret->lpComment = ret->lpProvider = NULL;
00365             if (lpNet->lpRemoteName)
00366             {
00367                 len = strlenW(lpNet->lpRemoteName) + 1;
00368                 ret->lpRemoteName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
00369                 if (ret->lpRemoteName)
00370                     strcpyW(ret->lpRemoteName, lpNet->lpRemoteName);
00371             }
00372         }
00373     }
00374     else
00375         ret = NULL;
00376     return ret;
00377 }
00378 
00379 static void _freeEnumNetResource(LPNETRESOURCEW lpNet)
00380 {
00381     if (lpNet)
00382     {
00383         HeapFree(GetProcessHeap(), 0, lpNet->lpRemoteName);
00384         HeapFree(GetProcessHeap(), 0, lpNet);
00385     }
00386 }
00387 
00388 static PWNetEnumerator _createNullEnumerator(void)
00389 {
00390     PWNetEnumerator ret = HeapAlloc(GetProcessHeap(),
00391      HEAP_ZERO_MEMORY, sizeof(WNetEnumerator));
00392 
00393     if (ret)
00394         ret->enumType = WNET_ENUMERATOR_TYPE_NULL;
00395     return ret;
00396 }
00397 
00398 static PWNetEnumerator _createGlobalEnumeratorW(DWORD dwScope, DWORD dwType,
00399  DWORD dwUsage, LPNETRESOURCEW lpNet)
00400 {
00401     PWNetEnumerator ret = HeapAlloc(GetProcessHeap(),
00402      HEAP_ZERO_MEMORY, sizeof(WNetEnumerator));
00403 
00404     if (ret)
00405     {
00406         ret->enumType = WNET_ENUMERATOR_TYPE_GLOBAL;
00407         ret->dwScope = dwScope;
00408         ret->dwType  = dwType;
00409         ret->dwUsage = dwUsage;
00410         ret->lpNet   = _copyNetResourceForEnumW(lpNet);
00411     }
00412     return ret;
00413 }
00414 
00415 static PWNetEnumerator _createProviderEnumerator(DWORD dwScope, DWORD dwType,
00416  DWORD dwUsage, DWORD index, HANDLE handle)
00417 {
00418     PWNetEnumerator ret;
00419 
00420     if (!providerTable || index >= providerTable->numProviders)
00421         ret = NULL;
00422     else
00423     {
00424         ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WNetEnumerator));
00425         if (ret)
00426         {
00427             ret->enumType      = WNET_ENUMERATOR_TYPE_PROVIDER;
00428             ret->providerIndex = index;
00429             ret->dwScope       = dwScope;
00430             ret->dwType        = dwType;
00431             ret->dwUsage       = dwUsage;
00432             ret->handle        = handle;
00433         }
00434     }
00435     return ret;
00436 }
00437 
00438 static PWNetEnumerator _createContextEnumerator(DWORD dwScope, DWORD dwType,
00439  DWORD dwUsage)
00440 {
00441     PWNetEnumerator ret = HeapAlloc(GetProcessHeap(),
00442      HEAP_ZERO_MEMORY, sizeof(WNetEnumerator));
00443 
00444     if (ret)
00445     {
00446         ret->enumType = WNET_ENUMERATOR_TYPE_CONTEXT;
00447         ret->dwScope = dwScope;
00448         ret->dwType  = dwType;
00449         ret->dwUsage = dwUsage;
00450     }
00451     return ret;
00452 }
00453 
00454 /* Thunks the array of wide-string LPNETRESOURCEs lpNetArrayIn into buffer
00455  * lpBuffer, with size *lpBufferSize.  lpNetArrayIn contains *lpcCount entries
00456  * to start.  On return, *lpcCount reflects the number thunked into lpBuffer.
00457  * Returns WN_SUCCESS on success (all of lpNetArrayIn thunked), WN_MORE_DATA
00458  * if not all members of the array could be thunked, and something else on
00459  * failure.
00460  */
00461 static DWORD _thunkNetResourceArrayWToA(const NETRESOURCEW *lpNetArrayIn,
00462  const DWORD *lpcCount, LPVOID lpBuffer, const DWORD *lpBufferSize)
00463 {
00464     DWORD i, numToThunk, totalBytes, ret;
00465     LPSTR strNext;
00466 
00467     if (!lpNetArrayIn)
00468         return WN_BAD_POINTER;
00469     if (!lpcCount)
00470         return WN_BAD_POINTER;
00471     if (*lpcCount == -1)
00472         return WN_BAD_VALUE;
00473     if (!lpBuffer)
00474         return WN_BAD_POINTER;
00475     if (!lpBufferSize)
00476         return WN_BAD_POINTER;
00477 
00478     for (i = 0, numToThunk = 0, totalBytes = 0; i < *lpcCount; i++)
00479     {
00480         const NETRESOURCEW *lpNet = lpNetArrayIn + i;
00481 
00482         totalBytes += sizeof(NETRESOURCEA);
00483         if (lpNet->lpLocalName)
00484             totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpLocalName,
00485              -1, NULL, 0, NULL, NULL);
00486         if (lpNet->lpRemoteName)
00487             totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpRemoteName,
00488              -1, NULL, 0, NULL, NULL);
00489         if (lpNet->lpComment)
00490             totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpComment,
00491              -1, NULL, 0, NULL, NULL);
00492         if (lpNet->lpProvider)
00493             totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpProvider,
00494              -1, NULL, 0, NULL, NULL);
00495         if (totalBytes < *lpBufferSize)
00496             numToThunk = i + 1;
00497     }
00498     strNext = (LPSTR)((LPBYTE)lpBuffer + numToThunk * sizeof(NETRESOURCEA));
00499     for (i = 0; i < numToThunk; i++)
00500     {
00501         LPNETRESOURCEA lpNetOut = (LPNETRESOURCEA)lpBuffer + i;
00502         const NETRESOURCEW *lpNetIn = lpNetArrayIn + i;
00503 
00504         memcpy(lpNetOut, lpNetIn, sizeof(NETRESOURCEA));
00505         /* lie about string lengths, we already verified how many
00506          * we have space for above
00507          */
00508         if (lpNetIn->lpLocalName)
00509         {
00510             lpNetOut->lpLocalName = strNext;
00511             strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpLocalName, -1,
00512              lpNetOut->lpLocalName, *lpBufferSize, NULL, NULL);
00513         }
00514         if (lpNetIn->lpRemoteName)
00515         {
00516             lpNetOut->lpRemoteName = strNext;
00517             strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpRemoteName, -1,
00518              lpNetOut->lpRemoteName, *lpBufferSize, NULL, NULL);
00519         }
00520         if (lpNetIn->lpComment)
00521         {
00522             lpNetOut->lpComment = strNext;
00523             strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpComment, -1,
00524              lpNetOut->lpComment, *lpBufferSize, NULL, NULL);
00525         }
00526         if (lpNetIn->lpProvider)
00527         {
00528             lpNetOut->lpProvider = strNext;
00529             strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpProvider, -1,
00530              lpNetOut->lpProvider, *lpBufferSize, NULL, NULL);
00531         }
00532     }
00533     ret = numToThunk < *lpcCount ? WN_MORE_DATA : WN_SUCCESS;
00534     TRACE("numToThunk is %d, *lpcCount is %d, returning %d\n", numToThunk,
00535      *lpcCount, ret);
00536     return ret;
00537 }
00538 
00539 /* Thunks the array of multibyte-string LPNETRESOURCEs lpNetArrayIn into buffer
00540  * lpBuffer, with size *lpBufferSize.  lpNetArrayIn contains *lpcCount entries
00541  * to start.  On return, *lpcCount reflects the number thunked into lpBuffer.
00542  * Returns WN_SUCCESS on success (all of lpNetArrayIn thunked), WN_MORE_DATA
00543  * if not all members of the array could be thunked, and something else on
00544  * failure.
00545  */
00546 static DWORD _thunkNetResourceArrayAToW(const NETRESOURCEA *lpNetArrayIn,
00547  const DWORD *lpcCount, LPVOID lpBuffer, const DWORD *lpBufferSize)
00548 {
00549     DWORD i, numToThunk, totalBytes, ret;
00550     LPWSTR strNext;
00551 
00552     if (!lpNetArrayIn)
00553         return WN_BAD_POINTER;
00554     if (!lpcCount)
00555         return WN_BAD_POINTER;
00556     if (*lpcCount == -1)
00557         return WN_BAD_VALUE;
00558     if (!lpBuffer)
00559         return WN_BAD_POINTER;
00560     if (!lpBufferSize)
00561         return WN_BAD_POINTER;
00562 
00563     for (i = 0, numToThunk = 0, totalBytes = 0; i < *lpcCount; i++)
00564     {
00565         const NETRESOURCEA *lpNet = lpNetArrayIn + i;
00566 
00567         totalBytes += sizeof(NETRESOURCEW);
00568         if (lpNet->lpLocalName)
00569             totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpLocalName,
00570              -1, NULL, 0) * sizeof(WCHAR);
00571         if (lpNet->lpRemoteName)
00572             totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpRemoteName,
00573              -1, NULL, 0) * sizeof(WCHAR);
00574         if (lpNet->lpComment)
00575             totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpComment,
00576              -1, NULL, 0) * sizeof(WCHAR);
00577         if (lpNet->lpProvider)
00578             totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpProvider,
00579              -1, NULL, 0) * sizeof(WCHAR);
00580         if (totalBytes < *lpBufferSize)
00581             numToThunk = i + 1;
00582     }
00583     strNext = (LPWSTR)((LPBYTE)lpBuffer + numToThunk * sizeof(NETRESOURCEW));
00584     for (i = 0; i < numToThunk; i++)
00585     {
00586         LPNETRESOURCEW lpNetOut = (LPNETRESOURCEW)lpBuffer + i;
00587         const NETRESOURCEA *lpNetIn = lpNetArrayIn + i;
00588 
00589         memcpy(lpNetOut, lpNetIn, sizeof(NETRESOURCEW));
00590         /* lie about string lengths, we already verified how many
00591          * we have space for above
00592          */
00593         if (lpNetIn->lpLocalName)
00594         {
00595             lpNetOut->lpLocalName = strNext;
00596             strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpLocalName,
00597              -1, lpNetOut->lpLocalName, *lpBufferSize);
00598         }
00599         if (lpNetIn->lpRemoteName)
00600         {
00601             lpNetOut->lpRemoteName = strNext;
00602             strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpRemoteName,
00603              -1, lpNetOut->lpRemoteName, *lpBufferSize);
00604         }
00605         if (lpNetIn->lpComment)
00606         {
00607             lpNetOut->lpComment = strNext;
00608             strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpComment,
00609              -1, lpNetOut->lpComment, *lpBufferSize);
00610         }
00611         if (lpNetIn->lpProvider)
00612         {
00613             lpNetOut->lpProvider = strNext;
00614             strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpProvider,
00615              -1, lpNetOut->lpProvider, *lpBufferSize);
00616         }
00617     }
00618     ret = numToThunk < *lpcCount ? WN_MORE_DATA : WN_SUCCESS;
00619     TRACE("numToThunk is %d, *lpcCount is %d, returning %d\n", numToThunk,
00620      *lpcCount, ret);
00621     return ret;
00622 }
00623 
00624 /*********************************************************************
00625  * WNetOpenEnumA [MPR.@]
00626  *
00627  * See comments for WNetOpenEnumW.
00628  */
00629 DWORD WINAPI WNetOpenEnumA( DWORD dwScope, DWORD dwType, DWORD dwUsage,
00630                             LPNETRESOURCEA lpNet, LPHANDLE lphEnum )
00631 {
00632     DWORD ret;
00633 
00634     TRACE( "(%08X, %08X, %08X, %p, %p)\n",
00635         dwScope, dwType, dwUsage, lpNet, lphEnum );
00636 
00637     if (!lphEnum)
00638         ret = WN_BAD_POINTER;
00639     else if (!providerTable || providerTable->numProviders == 0)
00640     {
00641         lphEnum = NULL;
00642         ret = WN_NO_NETWORK;
00643     }
00644     else
00645     {
00646         if (lpNet)
00647         {
00648             LPNETRESOURCEW lpNetWide = NULL;
00649             BYTE buf[1024];
00650             DWORD size = sizeof(buf), count = 1;
00651             BOOL allocated = FALSE;
00652 
00653             ret = _thunkNetResourceArrayAToW(lpNet, &count, buf, &size);
00654             if (ret == WN_MORE_DATA)
00655             {
00656                 lpNetWide = HeapAlloc(GetProcessHeap(), 0,
00657                  size);
00658                 if (lpNetWide)
00659                 {
00660                     ret = _thunkNetResourceArrayAToW(lpNet, &count, lpNetWide,
00661                      &size);
00662                     allocated = TRUE;
00663                 }
00664                 else
00665                     ret = WN_OUT_OF_MEMORY;
00666             }
00667             else if (ret == WN_SUCCESS)
00668                 lpNetWide = (LPNETRESOURCEW)buf;
00669             if (ret == WN_SUCCESS)
00670                 ret = WNetOpenEnumW(dwScope, dwType, dwUsage, lpNetWide,
00671                  lphEnum);
00672             if (allocated)
00673                 HeapFree(GetProcessHeap(), 0, lpNetWide);
00674         }
00675         else
00676             ret = WNetOpenEnumW(dwScope, dwType, dwUsage, NULL, lphEnum);
00677     }
00678     if (ret)
00679         SetLastError(ret);
00680     TRACE("Returning %d\n", ret);
00681     return ret;
00682 }
00683 
00684 /*********************************************************************
00685  * WNetOpenEnumW [MPR.@]
00686  *
00687  * Network enumeration has way too many parameters, so I'm not positive I got
00688  * them right.  What I've got so far:
00689  *
00690  * - If the scope is RESOURCE_GLOBALNET, and no LPNETRESOURCE is passed,
00691  *   all the network providers should be enumerated.
00692  *
00693  * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
00694  *   and neither the LPNETRESOURCE's lpRemoteName nor the LPNETRESOURCE's
00695  *   lpProvider is set, all the network providers should be enumerated.
00696  *   (This means the enumeration is a list of network providers, not that the
00697  *   enumeration is passed on to the providers.)
00698  *
00699  * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and the
00700  *   resource matches the "Entire Network" resource (no remote name, no
00701  *   provider, comment is the "Entire Network" string), a RESOURCE_GLOBALNET
00702  *   enumeration is done on every network provider.
00703  *
00704  * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
00705  *   the LPNETRESOURCE's lpProvider is set, enumeration will be passed through
00706  *   only to the given network provider.
00707  *
00708  * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and
00709  *   no lpProvider is set, enumeration will be tried on every network provider,
00710  *   in the order in which they're loaded.
00711  *
00712  * - The LPNETRESOURCE should be disregarded for scopes besides
00713  *   RESOURCE_GLOBALNET.  MSDN states that lpNet must be NULL if dwScope is not
00714  *   RESOURCE_GLOBALNET, but Windows doesn't return an error if it isn't NULL.
00715  *
00716  * - If the scope is RESOURCE_CONTEXT, MS includes an "Entire Network" net
00717  *   resource in the enumerated list, as well as any machines in your
00718  *   workgroup.  The machines in your workgroup come from doing a
00719  *   RESOURCE_CONTEXT enumeration of every Network Provider.
00720  */
00721 DWORD WINAPI WNetOpenEnumW( DWORD dwScope, DWORD dwType, DWORD dwUsage,
00722                             LPNETRESOURCEW lpNet, LPHANDLE lphEnum )
00723 {
00724     DWORD ret;
00725 
00726     TRACE( "(%08X, %08X, %08X, %p, %p)\n",
00727           dwScope, dwType, dwUsage, lpNet, lphEnum );
00728 
00729     if (!lphEnum)
00730         ret = WN_BAD_POINTER;
00731     else if (!providerTable || providerTable->numProviders == 0)
00732     {
00733         lphEnum = NULL;
00734         ret = WN_NO_NETWORK;
00735     }
00736     else
00737     {
00738         switch (dwScope)
00739         {
00740             case RESOURCE_GLOBALNET:
00741                 if (lpNet)
00742                 {
00743                     if (lpNet->lpProvider)
00744                     {
00745                         DWORD index = _findProviderIndexW(lpNet->lpProvider);
00746 
00747                         if (index != BAD_PROVIDER_INDEX)
00748                         {
00749                             if (providerTable->table[index].openEnum &&
00750                              providerTable->table[index].dwEnumScopes & WNNC_ENUM_GLOBAL)
00751                             {
00752                                 HANDLE handle;
00753 
00754                                 ret = providerTable->table[index].openEnum(
00755                                  dwScope, dwType, dwUsage, lpNet, &handle);
00756                                 if (ret == WN_SUCCESS)
00757                                 {
00758                                     *lphEnum = _createProviderEnumerator(
00759                                      dwScope, dwType, dwUsage, index, handle);
00760                                     ret = *lphEnum ? WN_SUCCESS :
00761                                      WN_OUT_OF_MEMORY;
00762                                 }
00763                             }
00764                             else
00765                                 ret = WN_NOT_SUPPORTED;
00766                         }
00767                         else
00768                             ret = WN_BAD_PROVIDER;
00769                     }
00770                     else if (lpNet->lpRemoteName)
00771                     {
00772                         *lphEnum = _createGlobalEnumeratorW(dwScope,
00773                          dwType, dwUsage, lpNet);
00774                         ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
00775                     }
00776                     else
00777                     {
00778                         if (lpNet->lpComment && !strcmpW(lpNet->lpComment,
00779                          providerTable->entireNetwork))
00780                         {
00781                             /* comment matches the "Entire Network", enumerate
00782                              * global scope of every provider
00783                              */
00784                             *lphEnum = _createGlobalEnumeratorW(dwScope,
00785                              dwType, dwUsage, lpNet);
00786                         }
00787                         else
00788                         {
00789                             /* this is the same as not having passed lpNet */
00790                             *lphEnum = _createGlobalEnumeratorW(dwScope,
00791                              dwType, dwUsage, NULL);
00792                         }
00793                         ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
00794                     }
00795                 }
00796                 else
00797                 {
00798                     *lphEnum = _createGlobalEnumeratorW(dwScope, dwType,
00799                      dwUsage, lpNet);
00800                     ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
00801                 }
00802                 break;
00803             case RESOURCE_CONTEXT:
00804                 *lphEnum = _createContextEnumerator(dwScope, dwType, dwUsage);
00805                 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
00806                 break;
00807             case RESOURCE_REMEMBERED:
00808             case RESOURCE_CONNECTED:
00809                 *lphEnum = _createNullEnumerator();
00810                 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
00811                 break;
00812             default:
00813                 WARN("unknown scope 0x%08x\n", dwScope);
00814                 ret = WN_BAD_VALUE;
00815         }
00816     }
00817     if (ret)
00818         SetLastError(ret);
00819     TRACE("Returning %d\n", ret);
00820     return ret;
00821 }
00822 
00823 /*********************************************************************
00824  * WNetEnumResourceA [MPR.@]
00825  */
00826 DWORD WINAPI WNetEnumResourceA( HANDLE hEnum, LPDWORD lpcCount,
00827                                 LPVOID lpBuffer, LPDWORD lpBufferSize )
00828 {
00829     DWORD ret;
00830 
00831     TRACE( "(%p, %p, %p, %p)\n", hEnum, lpcCount, lpBuffer, lpBufferSize );
00832 
00833     if (!hEnum)
00834         ret = WN_BAD_POINTER;
00835     else if (!lpcCount)
00836         ret = WN_BAD_POINTER;
00837     else if (!lpBuffer)
00838         ret = WN_BAD_POINTER;
00839     else if (!lpBufferSize)
00840         ret = WN_BAD_POINTER;
00841     else if (*lpBufferSize < sizeof(NETRESOURCEA))
00842     {
00843         *lpBufferSize = sizeof(NETRESOURCEA);
00844         ret = WN_MORE_DATA;
00845     }
00846     else
00847     {
00848         DWORD localCount = *lpcCount, localSize = *lpBufferSize;
00849         LPVOID localBuffer = HeapAlloc(GetProcessHeap(), 0, localSize);
00850 
00851         if (localBuffer)
00852         {
00853             ret = WNetEnumResourceW(hEnum, &localCount, localBuffer,
00854              &localSize);
00855             if (ret == WN_SUCCESS || (ret == WN_MORE_DATA && localCount != -1))
00856             {
00857                 /* FIXME: this isn't necessarily going to work in the case of
00858                  * WN_MORE_DATA, because our enumerator may have moved on to
00859                  * the next provider.  MSDN states that a large (16KB) buffer
00860                  * size is the appropriate usage of this function, so
00861                  * hopefully it won't be an issue.
00862                  */
00863                 ret = _thunkNetResourceArrayWToA(localBuffer, &localCount,
00864                  lpBuffer, lpBufferSize);
00865                 *lpcCount = localCount;
00866             }
00867             HeapFree(GetProcessHeap(), 0, localBuffer);
00868         }
00869         else
00870             ret = WN_OUT_OF_MEMORY;
00871     }
00872     if (ret)
00873         SetLastError(ret);
00874     TRACE("Returning %d\n", ret);
00875     return ret;
00876 }
00877 
00878 static DWORD _countProviderBytesW(PWNetProvider provider)
00879 {
00880     DWORD ret;
00881 
00882     if (provider)
00883     {
00884         ret = sizeof(NETRESOURCEW);
00885         ret += 2 * (strlenW(provider->name) + 1) * sizeof(WCHAR);
00886     }
00887     else
00888         ret = 0;
00889     return ret;
00890 }
00891 
00892 static DWORD _enumerateProvidersW(PWNetEnumerator enumerator, LPDWORD lpcCount,
00893  LPVOID lpBuffer, const DWORD *lpBufferSize)
00894 {
00895     DWORD ret;
00896 
00897     if (!enumerator)
00898         return WN_BAD_POINTER;
00899     if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL)
00900         return WN_BAD_VALUE;
00901     if (!lpcCount)
00902         return WN_BAD_POINTER;
00903     if (!lpBuffer)
00904         return WN_BAD_POINTER;
00905     if (!lpBufferSize)
00906         return WN_BAD_POINTER;
00907     if (*lpBufferSize < sizeof(NETRESOURCEA))
00908         return WN_MORE_DATA;
00909 
00910     if (!providerTable || enumerator->providerIndex >= 
00911      providerTable->numProviders)
00912         ret = WN_NO_MORE_ENTRIES;
00913     else
00914     {
00915         DWORD bytes = 0, count = 0, countLimit, i;
00916         LPNETRESOURCEW resource;
00917         LPWSTR strNext;
00918 
00919         countLimit = *lpcCount == -1 ?
00920          providerTable->numProviders - enumerator->providerIndex : *lpcCount;
00921         while (count < countLimit && bytes < *lpBufferSize)
00922         {
00923             DWORD bytesNext = _countProviderBytesW(
00924              &providerTable->table[count + enumerator->providerIndex]);
00925 
00926             if (bytes + bytesNext < *lpBufferSize)
00927             {
00928                 bytes += bytesNext;
00929                 count++;
00930             }
00931         }
00932         strNext = (LPWSTR)((LPBYTE)lpBuffer + count * sizeof(NETRESOURCEW));
00933         for (i = 0, resource = lpBuffer; i < count; i++, resource++)
00934         {
00935             resource->dwScope = RESOURCE_GLOBALNET;
00936             resource->dwType = RESOURCETYPE_ANY;
00937             resource->dwDisplayType = RESOURCEDISPLAYTYPE_NETWORK;
00938             resource->dwUsage = RESOURCEUSAGE_CONTAINER |
00939              RESOURCEUSAGE_RESERVED;
00940             resource->lpLocalName = NULL;
00941             resource->lpRemoteName = strNext;
00942             strcpyW(resource->lpRemoteName,
00943              providerTable->table[i + enumerator->providerIndex].name);
00944             strNext += strlenW(resource->lpRemoteName) + 1;
00945             resource->lpComment = NULL;
00946             resource->lpProvider = strNext;
00947             strcpyW(resource->lpProvider,
00948              providerTable->table[i + enumerator->providerIndex].name);
00949             strNext += strlenW(resource->lpProvider) + 1;
00950         }
00951         enumerator->providerIndex += count;
00952         *lpcCount = count;
00953         ret = count > 0 ? WN_SUCCESS : WN_MORE_DATA;
00954     }
00955     TRACE("Returning %d\n", ret);
00956     return ret;
00957 }
00958 
00959 /* Advances the enumerator (assumed to be a global enumerator) to the next
00960  * provider that supports the enumeration scope passed to WNetOpenEnum.  Does
00961  * not open a handle with the next provider.
00962  * If the existing handle is NULL, may leave the enumerator unchanged, since
00963  * the current provider may support the desired scope.
00964  * If the existing handle is not NULL, closes it before moving on.
00965  * Returns WN_SUCCESS on success, WN_NO_MORE_ENTRIES if there is no available
00966  * provider, and another error on failure.
00967  */
00968 static DWORD _globalEnumeratorAdvance(PWNetEnumerator enumerator)
00969 {
00970     if (!enumerator)
00971         return WN_BAD_POINTER;
00972     if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL)
00973         return WN_BAD_VALUE;
00974     if (!providerTable || enumerator->providerIndex >=
00975      providerTable->numProviders)
00976         return WN_NO_MORE_ENTRIES;
00977 
00978     if (enumerator->providerDone)
00979     {
00980         DWORD dwEnum = 0;
00981         enumerator->providerDone = FALSE;
00982         if (enumerator->handle)
00983         {
00984             providerTable->table[enumerator->providerIndex].closeEnum(
00985              enumerator->handle);
00986             enumerator->handle = NULL;
00987             enumerator->providerIndex++;
00988         }
00989         if (enumerator->dwScope == RESOURCE_CONNECTED)
00990             dwEnum = WNNC_ENUM_LOCAL;
00991         else if (enumerator->dwScope == RESOURCE_GLOBALNET)
00992             dwEnum = WNNC_ENUM_GLOBAL;
00993         else if (enumerator->dwScope == RESOURCE_CONTEXT)
00994             dwEnum = WNNC_ENUM_CONTEXT;
00995         for (; enumerator->providerIndex < providerTable->numProviders &&
00996          !(providerTable->table[enumerator->providerIndex].dwEnumScopes
00997          & dwEnum); enumerator->providerIndex++)
00998             ;
00999     }
01000     return enumerator->providerIndex < providerTable->numProviders ?
01001      WN_SUCCESS : WN_NO_MORE_ENTRIES;
01002 }
01003 
01004 /* "Passes through" call to the next provider that supports the enumeration
01005  * type.
01006  * FIXME: if one call to a provider's enumerator succeeds while there's still
01007  * space in lpBuffer, I don't call to the next provider.  The caller may not
01008  * expect that it should call EnumResourceW again with a return value of
01009  * WN_SUCCESS (depending what *lpcCount was to begin with).  That means strings
01010  * may have to be moved around a bit, ick.
01011  */
01012 static DWORD _enumerateGlobalPassthroughW(PWNetEnumerator enumerator,
01013  LPDWORD lpcCount, LPVOID lpBuffer, LPDWORD lpBufferSize)
01014 {
01015     DWORD ret;
01016 
01017     if (!enumerator)
01018         return WN_BAD_POINTER;
01019     if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL)
01020         return WN_BAD_VALUE;
01021     if (!lpcCount)
01022         return WN_BAD_POINTER;
01023     if (!lpBuffer)
01024         return WN_BAD_POINTER;
01025     if (!lpBufferSize)
01026         return WN_BAD_POINTER;
01027     if (*lpBufferSize < sizeof(NETRESOURCEW))
01028         return WN_MORE_DATA;
01029 
01030     ret = _globalEnumeratorAdvance(enumerator);
01031     if (ret == WN_SUCCESS)
01032     {
01033         ret = providerTable->table[enumerator->providerIndex].
01034          openEnum(enumerator->dwScope, enumerator->dwType,
01035          enumerator->dwUsage, enumerator->lpNet,
01036          &enumerator->handle);
01037         if (ret == WN_SUCCESS)
01038         {
01039             ret = providerTable->table[enumerator->providerIndex].
01040              enumResource(enumerator->handle, lpcCount, lpBuffer,
01041              lpBufferSize);
01042             if (ret != WN_MORE_DATA)
01043                 enumerator->providerDone = TRUE;
01044         }
01045     }
01046     TRACE("Returning %d\n", ret);
01047     return ret;
01048 }
01049 
01050 static DWORD _enumerateGlobalW(PWNetEnumerator enumerator, LPDWORD lpcCount,
01051  LPVOID lpBuffer, LPDWORD lpBufferSize)
01052 {
01053     DWORD ret;
01054 
01055     if (!enumerator)
01056         return WN_BAD_POINTER;
01057     if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL)
01058         return WN_BAD_VALUE;
01059     if (!lpcCount)
01060         return WN_BAD_POINTER;
01061     if (!lpBuffer)
01062         return WN_BAD_POINTER;
01063     if (!lpBufferSize)
01064         return WN_BAD_POINTER;
01065     if (*lpBufferSize < sizeof(NETRESOURCEW))
01066         return WN_MORE_DATA;
01067     if (!providerTable)
01068         return WN_NO_NETWORK;
01069 
01070     switch (enumerator->dwScope)
01071     {
01072         case RESOURCE_GLOBALNET:
01073             if (enumerator->lpNet)
01074                 ret = _enumerateGlobalPassthroughW(enumerator, lpcCount,
01075                  lpBuffer, lpBufferSize);
01076             else
01077                 ret = _enumerateProvidersW(enumerator, lpcCount, lpBuffer,
01078                  lpBufferSize);
01079             break;
01080         case RESOURCE_CONTEXT:
01081             ret = _enumerateGlobalPassthroughW(enumerator, lpcCount, lpBuffer,
01082              lpBufferSize);
01083             break;
01084         default:
01085             WARN("unexpected scope 0x%08x\n", enumerator->dwScope);
01086             ret = WN_NO_MORE_ENTRIES;
01087     }
01088     TRACE("Returning %d\n", ret);
01089     return ret;
01090 }
01091 
01092 static DWORD _enumerateProviderW(PWNetEnumerator enumerator, LPDWORD lpcCount,
01093  LPVOID lpBuffer, LPDWORD lpBufferSize)
01094 {
01095     if (!enumerator)
01096         return WN_BAD_POINTER;
01097     if (enumerator->enumType != WNET_ENUMERATOR_TYPE_PROVIDER)
01098         return WN_BAD_VALUE;
01099     if (!enumerator->handle)
01100         return WN_BAD_VALUE;
01101     if (!lpcCount)
01102         return WN_BAD_POINTER;
01103     if (!lpBuffer)
01104         return WN_BAD_POINTER;
01105     if (!lpBufferSize)
01106         return WN_BAD_POINTER;
01107     if (!providerTable)
01108         return WN_NO_NETWORK;
01109     if (enumerator->providerIndex >= providerTable->numProviders)
01110         return WN_NO_MORE_ENTRIES;
01111     if (!providerTable->table[enumerator->providerIndex].enumResource)
01112         return WN_BAD_VALUE;
01113     return providerTable->table[enumerator->providerIndex].enumResource(
01114      enumerator->handle, lpcCount, lpBuffer, lpBufferSize);
01115 }
01116 
01117 static DWORD _enumerateContextW(PWNetEnumerator enumerator, LPDWORD lpcCount,
01118  LPVOID lpBuffer, LPDWORD lpBufferSize)
01119 {
01120     DWORD ret;
01121     size_t cchEntireNetworkLen, bytesNeeded;
01122 
01123     if (!enumerator)
01124         return WN_BAD_POINTER;
01125     if (enumerator->enumType != WNET_ENUMERATOR_TYPE_CONTEXT)
01126         return WN_BAD_VALUE;
01127     if (!lpcCount)
01128         return WN_BAD_POINTER;
01129     if (!lpBuffer)
01130         return WN_BAD_POINTER;
01131     if (!lpBufferSize)
01132         return WN_BAD_POINTER;
01133     if (!providerTable)
01134         return WN_NO_NETWORK;
01135 
01136     cchEntireNetworkLen = strlenW(providerTable->entireNetwork) + 1;
01137     bytesNeeded = sizeof(NETRESOURCEW) + cchEntireNetworkLen * sizeof(WCHAR);
01138     if (*lpBufferSize < bytesNeeded)
01139     {
01140         *lpBufferSize = bytesNeeded;
01141         ret = WN_MORE_DATA;
01142     }
01143     else
01144     {
01145         LPNETRESOURCEW lpNet = lpBuffer;
01146 
01147         lpNet->dwScope = RESOURCE_GLOBALNET;
01148         lpNet->dwType = enumerator->dwType;
01149         lpNet->dwDisplayType = RESOURCEDISPLAYTYPE_ROOT;
01150         lpNet->dwUsage = RESOURCEUSAGE_CONTAINER;
01151         lpNet->lpLocalName = NULL;
01152         lpNet->lpRemoteName = NULL;
01153         lpNet->lpProvider = NULL;
01154         /* odd, but correct: put comment at end of buffer, so it won't get
01155          * overwritten by subsequent calls to a provider's enumResource
01156          */
01157         lpNet->lpComment = (LPWSTR)((LPBYTE)lpBuffer + *lpBufferSize -
01158          (cchEntireNetworkLen * sizeof(WCHAR)));
01159         strcpyW(lpNet->lpComment, providerTable->entireNetwork);
01160         ret = WN_SUCCESS;
01161     }
01162     if (ret == WN_SUCCESS)
01163     {
01164         DWORD bufferSize = *lpBufferSize - bytesNeeded;
01165 
01166         /* "Entire Network" entry enumerated--morph this into a global
01167          * enumerator.  enumerator->lpNet continues to be NULL, since it has
01168          * no meaning when the scope isn't RESOURCE_GLOBALNET.
01169          */
01170         enumerator->enumType = WNET_ENUMERATOR_TYPE_GLOBAL;
01171         ret = _enumerateGlobalW(enumerator, lpcCount,
01172          (LPBYTE)lpBuffer + bytesNeeded, &bufferSize);
01173         if (ret == WN_SUCCESS)
01174         {
01175             /* reflect the fact that we already enumerated "Entire Network" */
01176             lpcCount++;
01177             *lpBufferSize = bufferSize + bytesNeeded;
01178         }
01179         else
01180         {
01181             /* the provider enumeration failed, but we already succeeded in
01182              * enumerating "Entire Network"--leave type as global to allow a
01183              * retry, but indicate success with a count of one.
01184              */
01185             ret = WN_SUCCESS;
01186             *lpcCount = 1;
01187             *lpBufferSize = bytesNeeded;
01188         }
01189     }
01190     TRACE("Returning %d\n", ret);
01191     return ret;
01192 }
01193 
01194 /*********************************************************************
01195  * WNetEnumResourceW [MPR.@]
01196  */
01197 DWORD WINAPI WNetEnumResourceW( HANDLE hEnum, LPDWORD lpcCount,
01198                                 LPVOID lpBuffer, LPDWORD lpBufferSize )
01199 {
01200     DWORD ret;
01201 
01202     TRACE( "(%p, %p, %p, %p)\n", hEnum, lpcCount, lpBuffer, lpBufferSize );
01203 
01204     if (!hEnum)
01205         ret = WN_BAD_POINTER;
01206     else if (!lpcCount)
01207         ret = WN_BAD_POINTER;
01208     else if (!lpBuffer)
01209         ret = WN_BAD_POINTER;
01210     else if (!lpBufferSize)
01211         ret = WN_BAD_POINTER;
01212     else if (*lpBufferSize < sizeof(NETRESOURCEW))
01213     {
01214         *lpBufferSize = sizeof(NETRESOURCEW);
01215         ret = WN_MORE_DATA;
01216     }
01217     else
01218     {
01219         PWNetEnumerator enumerator = (PWNetEnumerator)hEnum;
01220 
01221         switch (enumerator->enumType)
01222         {
01223             case WNET_ENUMERATOR_TYPE_NULL:
01224                 ret = WN_NO_MORE_ENTRIES;
01225                 break;
01226             case WNET_ENUMERATOR_TYPE_GLOBAL:
01227                 ret = _enumerateGlobalW(enumerator, lpcCount, lpBuffer,
01228                  lpBufferSize);
01229                 break;
01230             case WNET_ENUMERATOR_TYPE_PROVIDER:
01231                 ret = _enumerateProviderW(enumerator, lpcCount, lpBuffer,
01232                  lpBufferSize);
01233                 break;
01234             case WNET_ENUMERATOR_TYPE_CONTEXT:
01235                 ret = _enumerateContextW(enumerator, lpcCount, lpBuffer,
01236                  lpBufferSize);
01237                 break;
01238             default:
01239                 WARN("bogus enumerator type!\n");
01240                 ret = WN_NO_NETWORK;
01241         }
01242     }
01243     if (ret)
01244         SetLastError(ret);
01245     TRACE("Returning %d\n", ret);
01246     return ret;
01247 }
01248 
01249 /*********************************************************************
01250  * WNetCloseEnum [MPR.@]
01251  */
01252 DWORD WINAPI WNetCloseEnum( HANDLE hEnum )
01253 {
01254     DWORD ret;
01255 
01256     TRACE( "(%p)\n", hEnum );
01257 
01258     if (hEnum)
01259     {
01260         PWNetEnumerator enumerator = (PWNetEnumerator)hEnum;
01261 
01262         switch (enumerator->enumType)
01263         {
01264             case WNET_ENUMERATOR_TYPE_NULL:
01265                 ret = WN_SUCCESS;
01266                 break;
01267             case WNET_ENUMERATOR_TYPE_GLOBAL:
01268                 if (enumerator->lpNet)
01269                     _freeEnumNetResource(enumerator->lpNet);
01270                 if (enumerator->handle)
01271                     providerTable->table[enumerator->providerIndex].
01272                      closeEnum(enumerator->handle);
01273                 ret = WN_SUCCESS;
01274                 break;
01275             case WNET_ENUMERATOR_TYPE_PROVIDER:
01276                 if (enumerator->handle)
01277                     providerTable->table[enumerator->providerIndex].
01278                      closeEnum(enumerator->handle);
01279                 ret = WN_SUCCESS;
01280                 break;
01281             default:
01282                 WARN("bogus enumerator type!\n");
01283                 ret = WN_BAD_HANDLE;
01284         }
01285         HeapFree(GetProcessHeap(), 0, hEnum);
01286     }
01287     else
01288         ret = WN_BAD_HANDLE;
01289     if (ret)
01290         SetLastError(ret);
01291     TRACE("Returning %d\n", ret);
01292     return ret;
01293 }
01294 
01295 /*********************************************************************
01296  * WNetGetResourceInformationA [MPR.@]
01297  *
01298  * See WNetGetResourceInformationW
01299  */
01300 DWORD WINAPI WNetGetResourceInformationA( LPNETRESOURCEA lpNetResource,
01301                                           LPVOID lpBuffer, LPDWORD cbBuffer,
01302                                           LPSTR *lplpSystem )
01303 {
01304     DWORD ret;
01305 
01306     TRACE( "(%p, %p, %p, %p)\n",
01307            lpNetResource, lpBuffer, cbBuffer, lplpSystem );
01308 
01309     if (!providerTable || providerTable->numProviders == 0)
01310         ret = WN_NO_NETWORK;
01311     else if (lpNetResource)
01312     {
01313         LPNETRESOURCEW lpNetResourceW = NULL;
01314         DWORD size = 1024, count = 1;
01315         DWORD len;
01316 
01317         lpNetResourceW = HeapAlloc(GetProcessHeap(), 0, size);
01318         ret = _thunkNetResourceArrayAToW(lpNetResource, &count, lpNetResourceW, &size);
01319         if (ret == WN_MORE_DATA)
01320         {
01321             HeapFree(GetProcessHeap(), 0, lpNetResourceW);
01322             lpNetResourceW = HeapAlloc(GetProcessHeap(), 0, size);
01323             if (lpNetResourceW)
01324                 ret = _thunkNetResourceArrayAToW(lpNetResource,
01325                         &count, lpNetResourceW, &size);
01326             else
01327                 ret = WN_OUT_OF_MEMORY;
01328         }
01329         if (ret == WN_SUCCESS)
01330         {
01331             LPWSTR lpSystemW = NULL;
01332             LPVOID lpBufferW;
01333             size = 1024;
01334             lpBufferW = HeapAlloc(GetProcessHeap(), 0, size);
01335             if (lpBufferW)
01336             {
01337                 ret = WNetGetResourceInformationW(lpNetResourceW,
01338                         lpBufferW, &size, &lpSystemW);
01339                 if (ret == WN_MORE_DATA)
01340                 {
01341                     HeapFree(GetProcessHeap(), 0, lpBufferW);
01342                     lpBufferW = HeapAlloc(GetProcessHeap(), 0, size);
01343                     if (lpBufferW)
01344                         ret = WNetGetResourceInformationW(lpNetResourceW,
01345                             lpBufferW, &size, &lpSystemW);
01346                     else
01347                         ret = WN_OUT_OF_MEMORY;
01348                 }
01349                 if (ret == WN_SUCCESS)
01350                 {
01351                     ret = _thunkNetResourceArrayWToA(lpBufferW,
01352                             &count, lpBuffer, cbBuffer);
01353                     HeapFree(GetProcessHeap(), 0, lpNetResourceW);
01354                     lpNetResourceW = lpBufferW;
01355                     size = sizeof(NETRESOURCEA);
01356                     size += WideCharToMultiByte(CP_ACP, 0, lpNetResourceW->lpRemoteName,
01357                             -1, NULL, 0, NULL, NULL);
01358                     size += WideCharToMultiByte(CP_ACP, 0, lpNetResourceW->lpProvider,
01359                             -1, NULL, 0, NULL, NULL);
01360 
01361                     len = WideCharToMultiByte(CP_ACP, 0, lpSystemW,
01362                                       -1, NULL, 0, NULL, NULL);
01363                     if ((len) && ( size + len < *cbBuffer))
01364                     {
01365                         *lplpSystem = (char*)lpBuffer + *cbBuffer - len;
01366                         WideCharToMultiByte(CP_ACP, 0, lpSystemW, -1,
01367                              *lplpSystem, len, NULL, NULL);
01368                          ret = WN_SUCCESS;
01369                     }
01370                     else
01371                         ret = WN_MORE_DATA;
01372                 }
01373                 else
01374                     ret = WN_OUT_OF_MEMORY;
01375                 HeapFree(GetProcessHeap(), 0, lpBufferW);
01376             }
01377             else
01378                 ret = WN_OUT_OF_MEMORY;
01379             HeapFree(GetProcessHeap(), 0, lpSystemW);
01380         }
01381         HeapFree(GetProcessHeap(), 0, lpNetResourceW);
01382     }
01383     else
01384         ret = WN_NO_NETWORK;
01385 
01386     if (ret)
01387         SetLastError(ret);
01388     TRACE("Returning %d\n", ret);
01389     return ret;
01390 }
01391 
01392 /*********************************************************************
01393  * WNetGetResourceInformationW [MPR.@]
01394  *
01395  * WNetGetResourceInformationW function identifies the network provider
01396  * that owns the resource and gets information about the type of the resource.
01397  *
01398  * PARAMS:
01399  *  lpNetResource    [ I]    the pointer to NETRESOURCEW structure, that
01400  *                          defines a network resource.
01401  *  lpBuffer         [ O]   the pointer to buffer, containing result. It
01402  *                          contains NETRESOURCEW structure and strings to
01403  *                          which the members of the NETRESOURCEW structure
01404  *                          point.
01405  *  cbBuffer         [I/O] the pointer to DWORD number - size of buffer
01406  *                          in bytes.
01407  *  lplpSystem       [ O]   the pointer to string in the output buffer,
01408  *                          containing the part of the resource name without
01409  *                          names of the server and share.
01410  *
01411  * RETURNS:
01412  *  NO_ERROR if the function succeeds. System error code if the function fails.
01413  */
01414 
01415 DWORD WINAPI WNetGetResourceInformationW( LPNETRESOURCEW lpNetResource,
01416                                           LPVOID lpBuffer, LPDWORD cbBuffer,
01417                                           LPWSTR *lplpSystem )
01418 {
01419     DWORD ret = WN_NO_NETWORK;
01420     DWORD index;
01421 
01422     TRACE( "(%p, %p, %p, %p)\n",
01423            lpNetResource, lpBuffer, cbBuffer, lplpSystem);
01424 
01425     if (!(lpBuffer))
01426         ret = WN_OUT_OF_MEMORY;
01427     else if (providerTable != NULL)
01428     {
01429         /* FIXME: For function value of a variable is indifferent, it does
01430          * search of all providers in a network.
01431          */
01432         for (index = 0; index < providerTable->numProviders; index++)
01433         {
01434             if(providerTable->table[index].getCaps(WNNC_DIALOG) &
01435                 WNNC_DLG_GETRESOURCEINFORMATION)
01436             {
01437                 if (providerTable->table[index].getResourceInformation)
01438                     ret = providerTable->table[index].getResourceInformation(
01439                         lpNetResource, lpBuffer, cbBuffer, lplpSystem);
01440                 else
01441                     ret = WN_NO_NETWORK;
01442                 if (ret == WN_SUCCESS)
01443                     break;
01444             }
01445         }
01446     }
01447     if (ret)
01448         SetLastError(ret);
01449     return ret;
01450 }
01451 
01452 /*********************************************************************
01453  * WNetGetResourceParentA [MPR.@]
01454  */
01455 DWORD WINAPI WNetGetResourceParentA( LPNETRESOURCEA lpNetResource,
01456                                      LPVOID lpBuffer, LPDWORD lpBufferSize )
01457 {
01458     FIXME( "(%p, %p, %p): stub\n",
01459            lpNetResource, lpBuffer, lpBufferSize );
01460 
01461     SetLastError(WN_NO_NETWORK);
01462     return WN_NO_NETWORK;
01463 }
01464 
01465 /*********************************************************************
01466  * WNetGetResourceParentW [MPR.@]
01467  */
01468 DWORD WINAPI WNetGetResourceParentW( LPNETRESOURCEW lpNetResource,
01469                                      LPVOID lpBuffer, LPDWORD lpBufferSize )
01470 {
01471     FIXME( "(%p, %p, %p): stub\n",
01472            lpNetResource, lpBuffer, lpBufferSize );
01473 
01474     SetLastError(WN_NO_NETWORK);
01475     return WN_NO_NETWORK;
01476 }
01477 
01478 
01479 
01480 /*
01481  * Connection Functions
01482  */
01483 
01484 /*********************************************************************
01485  *  WNetAddConnectionA [MPR.@]
01486  */
01487 DWORD WINAPI WNetAddConnectionA( LPCSTR lpRemoteName, LPCSTR lpPassword,
01488                                  LPCSTR lpLocalName )
01489 {
01490     FIXME( "(%s, %p, %s): stub\n",
01491            debugstr_a(lpRemoteName), lpPassword, debugstr_a(lpLocalName) );
01492 
01493     SetLastError(WN_NO_NETWORK);
01494     return WN_NO_NETWORK;
01495 }
01496 
01497 /*********************************************************************
01498  *  WNetAddConnectionW [MPR.@]
01499  */
01500 DWORD WINAPI WNetAddConnectionW( LPCWSTR lpRemoteName, LPCWSTR lpPassword,
01501                                  LPCWSTR lpLocalName )
01502 {
01503     FIXME( "(%s, %p, %s): stub\n",
01504            debugstr_w(lpRemoteName), lpPassword, debugstr_w(lpLocalName) );
01505 
01506     SetLastError(WN_NO_NETWORK);
01507     return WN_NO_NETWORK;
01508 }
01509 
01510 /*********************************************************************
01511  *  WNetAddConnection2A [MPR.@]
01512  */
01513 DWORD WINAPI WNetAddConnection2A( LPNETRESOURCEA lpNetResource,
01514                                   LPCSTR lpPassword, LPCSTR lpUserID,
01515                                   DWORD dwFlags )
01516 {
01517     FIXME( "(%p, %p, %s, 0x%08X): stub\n",
01518            lpNetResource, lpPassword, debugstr_a(lpUserID), dwFlags );
01519 
01520     SetLastError(WN_NO_NETWORK);
01521     return WN_NO_NETWORK;
01522 }
01523 
01524 /*********************************************************************
01525  * WNetAddConnection2W [MPR.@]
01526  */
01527 DWORD WINAPI WNetAddConnection2W( LPNETRESOURCEW lpNetResource,
01528                                   LPCWSTR lpPassword, LPCWSTR lpUserID,
01529                                   DWORD dwFlags )
01530 {
01531     FIXME( "(%p, %p, %s, 0x%08X): stub\n",
01532            lpNetResource, lpPassword, debugstr_w(lpUserID), dwFlags );
01533 
01534     SetLastError(WN_NO_NETWORK);
01535     return WN_NO_NETWORK;
01536 }
01537 
01538 /*********************************************************************
01539  * WNetAddConnection3A [MPR.@]
01540  */
01541 DWORD WINAPI WNetAddConnection3A( HWND hwndOwner, LPNETRESOURCEA lpNetResource,
01542                                   LPCSTR lpPassword, LPCSTR lpUserID,
01543                                   DWORD dwFlags )
01544 {
01545     FIXME( "(%p, %p, %p, %s, 0x%08X), stub\n",
01546            hwndOwner, lpNetResource, lpPassword, debugstr_a(lpUserID), dwFlags );
01547 
01548     SetLastError(WN_NO_NETWORK);
01549     return WN_NO_NETWORK;
01550 }
01551 
01552 /*********************************************************************
01553  * WNetAddConnection3W [MPR.@]
01554  */
01555 DWORD WINAPI WNetAddConnection3W( HWND hwndOwner, LPNETRESOURCEW lpNetResource,
01556                                   LPCWSTR lpPassword, LPCWSTR lpUserID,
01557                                   DWORD dwFlags )
01558 {
01559     FIXME( "(%p, %p, %p, %s, 0x%08X), stub\n",
01560            hwndOwner, lpNetResource, lpPassword, debugstr_w(lpUserID), dwFlags );
01561 
01562     SetLastError(WN_NO_NETWORK);
01563     return WN_NO_NETWORK;
01564 }
01565 
01566 /*****************************************************************
01567  *  WNetUseConnectionA [MPR.@]
01568  */
01569 DWORD WINAPI WNetUseConnectionA( HWND hwndOwner, LPNETRESOURCEA lpNetResource,
01570                                  LPCSTR lpPassword, LPCSTR lpUserID, DWORD dwFlags,
01571                                  LPSTR lpAccessName, LPDWORD lpBufferSize,
01572                                  LPDWORD lpResult )
01573 {
01574     FIXME( "(%p, %p, %p, %s, 0x%08X, %s, %p, %p), stub\n",
01575            hwndOwner, lpNetResource, lpPassword, debugstr_a(lpUserID), dwFlags,
01576            debugstr_a(lpAccessName), lpBufferSize, lpResult );
01577 
01578     SetLastError(WN_NO_NETWORK);
01579     return WN_NO_NETWORK;
01580 }
01581 
01582 /*****************************************************************
01583  *  WNetUseConnectionW [MPR.@]
01584  */
01585 DWORD WINAPI WNetUseConnectionW( HWND hwndOwner, LPNETRESOURCEW lpNetResource,
01586                                  LPCWSTR lpPassword, LPCWSTR lpUserID, DWORD dwFlags,
01587                                  LPWSTR lpAccessName, LPDWORD lpBufferSize,
01588                                  LPDWORD lpResult )
01589 {
01590     FIXME( "(%p, %p, %p, %s, 0x%08X, %s, %p, %p), stub\n",
01591            hwndOwner, lpNetResource, lpPassword, debugstr_w(lpUserID), dwFlags,
01592            debugstr_w(lpAccessName), lpBufferSize, lpResult );
01593 
01594     SetLastError(WN_NO_NETWORK);
01595     return WN_NO_NETWORK;
01596 }
01597 
01598 /*********************************************************************
01599  *  WNetCancelConnectionA [MPR.@]
01600  */
01601 DWORD WINAPI WNetCancelConnectionA( LPCSTR lpName, BOOL fForce )
01602 {
01603     FIXME( "(%s, %d), stub\n", debugstr_a(lpName), fForce );
01604 
01605     return WN_SUCCESS;
01606 }
01607 
01608 /*********************************************************************
01609  *  WNetCancelConnectionW [MPR.@]
01610  */
01611 DWORD WINAPI WNetCancelConnectionW( LPCWSTR lpName, BOOL fForce )
01612 {
01613     FIXME( "(%s, %d), stub\n", debugstr_w(lpName), fForce );
01614 
01615     return WN_SUCCESS;
01616 }
01617 
01618 /*********************************************************************
01619  *  WNetCancelConnection2A [MPR.@]
01620  */
01621 DWORD WINAPI WNetCancelConnection2A( LPCSTR lpName, DWORD dwFlags, BOOL fForce )
01622 {
01623     FIXME( "(%s, %08X, %d), stub\n", debugstr_a(lpName), dwFlags, fForce );
01624 
01625     return WN_SUCCESS;
01626 }
01627 
01628 /*********************************************************************
01629  *  WNetCancelConnection2W [MPR.@]
01630  */
01631 DWORD WINAPI WNetCancelConnection2W( LPCWSTR lpName, DWORD dwFlags, BOOL fForce )
01632 {
01633     FIXME( "(%s, %08X, %d), stub\n", debugstr_w(lpName), dwFlags, fForce );
01634 
01635     return WN_SUCCESS;
01636 }
01637 
01638 /*****************************************************************
01639  *  WNetRestoreConnectionA [MPR.@]
01640  */
01641 DWORD WINAPI WNetRestoreConnectionA( HWND hwndOwner, LPCSTR lpszDevice )
01642 {
01643     FIXME( "(%p, %s), stub\n", hwndOwner, debugstr_a(lpszDevice) );
01644 
01645     SetLastError(WN_NO_NETWORK);
01646     return WN_NO_NETWORK;
01647 }
01648 
01649 /*****************************************************************
01650  *  WNetRestoreConnectionW [MPR.@]
01651  */
01652 DWORD WINAPI WNetRestoreConnectionW( HWND hwndOwner, LPCWSTR lpszDevice )
01653 {
01654     FIXME( "(%p, %s), stub\n", hwndOwner, debugstr_w(lpszDevice) );
01655 
01656     SetLastError(WN_NO_NETWORK);
01657     return WN_NO_NETWORK;
01658 }
01659 
01660 /**************************************************************************
01661  * WNetGetConnectionA [MPR.@]
01662  *
01663  * RETURNS
01664  * - WN_BAD_LOCALNAME     lpLocalName makes no sense
01665  * - WN_NOT_CONNECTED     drive is a local drive
01666  * - WN_MORE_DATA         buffer isn't big enough
01667  * - WN_SUCCESS           success (net path in buffer)
01668  *
01669  * FIXME: need to test return values under different errors
01670  */
01671 DWORD WINAPI WNetGetConnectionA( LPCSTR lpLocalName,
01672                                  LPSTR lpRemoteName, LPDWORD lpBufferSize )
01673 {
01674     DWORD ret;
01675 
01676     if (!lpLocalName)
01677         ret = WN_BAD_POINTER;
01678     else if (!lpBufferSize)
01679         ret = WN_BAD_POINTER;
01680     else if (!lpRemoteName && *lpBufferSize)
01681         ret = WN_BAD_POINTER;
01682     else
01683     {
01684         int len = MultiByteToWideChar(CP_ACP, 0, lpLocalName, -1, NULL, 0);
01685 
01686         if (len)
01687         {
01688             PWSTR wideLocalName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
01689 
01690             if (wideLocalName)
01691             {
01692                 WCHAR wideRemoteStatic[MAX_PATH];
01693                 DWORD wideRemoteSize = sizeof(wideRemoteStatic) / sizeof(WCHAR);
01694 
01695                 MultiByteToWideChar(CP_ACP, 0, lpLocalName, -1, wideLocalName, len);
01696 
01697                 /* try once without memory allocation */
01698                 ret = WNetGetConnectionW(wideLocalName, wideRemoteStatic,
01699                  &wideRemoteSize);
01700                 if (ret == WN_SUCCESS)
01701                 {
01702                     int len = WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic,
01703                      -1, NULL, 0, NULL, NULL);
01704 
01705                     if (len <= *lpBufferSize)
01706                     {
01707                         WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic, -1,
01708                          lpRemoteName, *lpBufferSize, NULL, NULL);
01709                         ret = WN_SUCCESS;
01710                     }
01711                     else
01712                     {
01713                         *lpBufferSize = len;
01714                         ret = WN_MORE_DATA;
01715                     }
01716                 }
01717                 else if (ret == WN_MORE_DATA)
01718                 {
01719                     PWSTR wideRemote = HeapAlloc(GetProcessHeap(), 0,
01720                      wideRemoteSize * sizeof(WCHAR));
01721 
01722                     if (wideRemote)
01723                     {
01724                         ret = WNetGetConnectionW(wideLocalName, wideRemote,
01725                          &wideRemoteSize);
01726                         if (ret == WN_SUCCESS)
01727                         {
01728                             if (len <= *lpBufferSize)
01729                             {
01730                                 WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic,
01731                                  -1, lpRemoteName, *lpBufferSize, NULL, NULL);
01732                                 ret = WN_SUCCESS;
01733                             }
01734                             else
01735                             {
01736                                 *lpBufferSize = len;
01737                                 ret = WN_MORE_DATA;
01738                             }
01739                         }
01740                         HeapFree(GetProcessHeap(), 0, wideRemote);
01741                     }
01742                     else
01743                         ret = WN_OUT_OF_MEMORY;
01744                 }
01745                 HeapFree(GetProcessHeap(), 0, wideLocalName);
01746             }
01747             else
01748                 ret = WN_OUT_OF_MEMORY;
01749         }
01750         else
01751             ret = WN_BAD_LOCALNAME;
01752     }
01753     if (ret)
01754         SetLastError(ret);
01755     TRACE("Returning %d\n", ret);
01756     return ret;
01757 }
01758 
01759 /* find the network connection for a given drive; helper for WNetGetConnection */
01760 static DWORD get_drive_connection( WCHAR letter, LPWSTR remote, LPDWORD size )
01761 {
01762     char buffer[1024];
01763     struct mountmgr_unix_drive *data = (struct mountmgr_unix_drive *)buffer;
01764     HANDLE mgr;
01765     DWORD ret = WN_NOT_CONNECTED;
01766 
01767     if ((mgr = CreateFileW( MOUNTMGR_DOS_DEVICE_NAME, GENERIC_READ|GENERIC_WRITE,
01768                             FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
01769                             0, 0 )) == INVALID_HANDLE_VALUE)
01770     {
01771         ERR( "failed to open mount manager err %u\n", GetLastError() );
01772         return ret;
01773     }
01774     memset( data, 0, sizeof(*data) );
01775     data->letter = letter;
01776     if (DeviceIoControl( mgr, IOCTL_MOUNTMGR_QUERY_UNIX_DRIVE, data, sizeof(*data),
01777                          data, sizeof(buffer), NULL, NULL ))
01778     {
01779         char *p, *mount_point = buffer + data->mount_point_offset;
01780         DWORD len;
01781 
01782         if (data->mount_point_offset && !strncmp( mount_point, "unc/", 4 ))
01783         {
01784             mount_point += 2;
01785             mount_point[0] = '\\';
01786             for (p = mount_point; *p; p++) if (*p == '/') *p = '\\';
01787 
01788             len = MultiByteToWideChar( CP_UNIXCP, 0, mount_point, -1, NULL, 0 );
01789             if (len > *size)
01790             {
01791                 *size = len;
01792                 ret = WN_MORE_DATA;
01793             }
01794             else
01795             {
01796                 *size = MultiByteToWideChar( CP_UNIXCP, 0, mount_point, -1, remote, *size);
01797                 ret = WN_SUCCESS;
01798             }
01799         }
01800     }
01801     CloseHandle( mgr );
01802     return ret;
01803 }
01804 
01805 /**************************************************************************
01806  * WNetGetConnectionW [MPR.@]
01807  *
01808  * FIXME: need to test return values under different errors
01809  */
01810 DWORD WINAPI WNetGetConnectionW( LPCWSTR lpLocalName,
01811                                  LPWSTR lpRemoteName, LPDWORD lpBufferSize )
01812 {
01813     DWORD ret;
01814 
01815     TRACE("(%s, %p, %p)\n", debugstr_w(lpLocalName), lpRemoteName,
01816      lpBufferSize);
01817 
01818     if (!lpLocalName)
01819         ret = WN_BAD_POINTER;
01820     else if (!lpBufferSize)
01821         ret = WN_BAD_POINTER;
01822     else if (!lpRemoteName && *lpBufferSize)
01823         ret = WN_BAD_POINTER;
01824     else if (!lpLocalName[0])
01825         ret = WN_BAD_LOCALNAME;
01826     else
01827     {
01828         if (lpLocalName[1] == ':')
01829         {
01830             switch(GetDriveTypeW(lpLocalName))
01831             {
01832             case DRIVE_REMOTE:
01833                 ret = get_drive_connection( lpLocalName[0], lpRemoteName, lpBufferSize );
01834                 break;
01835             case DRIVE_REMOVABLE:
01836             case DRIVE_FIXED:
01837             case DRIVE_CDROM:
01838                 TRACE("file is local\n");
01839                 ret = WN_NOT_CONNECTED;
01840                 break;
01841             default:
01842                 ret = WN_BAD_LOCALNAME;
01843             }
01844         }
01845         else
01846             ret = WN_BAD_LOCALNAME;
01847     }
01848     if (ret)
01849         SetLastError(ret);
01850     TRACE("Returning %d\n", ret);
01851     return ret;
01852 }
01853 
01854 /**************************************************************************
01855  * WNetSetConnectionA [MPR.@]
01856  */
01857 DWORD WINAPI WNetSetConnectionA( LPCSTR lpName, DWORD dwProperty,
01858                                  LPVOID pvValue )
01859 {
01860     FIXME( "(%s, %08X, %p): stub\n", debugstr_a(lpName), dwProperty, pvValue );
01861 
01862     SetLastError(WN_NO_NETWORK);
01863     return WN_NO_NETWORK;
01864 }
01865 
01866 /**************************************************************************
01867  * WNetSetConnectionW [MPR.@]
01868  */
01869 DWORD WINAPI WNetSetConnectionW( LPCWSTR lpName, DWORD dwProperty,
01870                                  LPVOID pvValue )
01871 {
01872     FIXME( "(%s, %08X, %p): stub\n", debugstr_w(lpName), dwProperty, pvValue );
01873 
01874     SetLastError(WN_NO_NETWORK);
01875     return WN_NO_NETWORK;
01876 }
01877 
01878 /*****************************************************************
01879  * WNetGetUniversalNameA [MPR.@]
01880  */
01881 DWORD WINAPI WNetGetUniversalNameA ( LPCSTR lpLocalPath, DWORD dwInfoLevel,
01882                                      LPVOID lpBuffer, LPDWORD lpBufferSize )
01883 {
01884     DWORD err, size;
01885 
01886     FIXME( "(%s, 0x%08X, %p, %p): stub\n",
01887            debugstr_a(lpLocalPath), dwInfoLevel, lpBuffer, lpBufferSize);
01888 
01889     switch (dwInfoLevel)
01890     {
01891     case UNIVERSAL_NAME_INFO_LEVEL:
01892     {
01893         LPUNIVERSAL_NAME_INFOA info = lpBuffer;
01894 
01895         size = sizeof(*info) + lstrlenA(lpLocalPath) + 1;
01896         if (*lpBufferSize < size)
01897         {
01898             err = WN_MORE_DATA;
01899             break;
01900         }
01901         info->lpUniversalName = (char *)info + sizeof(*info);
01902         lstrcpyA(info->lpUniversalName, lpLocalPath);
01903         *lpBufferSize = size;
01904         err = WN_NO_ERROR;
01905         break;
01906     }
01907     case REMOTE_NAME_INFO_LEVEL:
01908         err = WN_NO_NETWORK;
01909         break;
01910 
01911     default:
01912         err = WN_BAD_VALUE;
01913         break;
01914     }
01915 
01916     SetLastError(err);
01917     return err;
01918 }
01919 
01920 /*****************************************************************
01921  * WNetGetUniversalNameW [MPR.@]
01922  */
01923 DWORD WINAPI WNetGetUniversalNameW ( LPCWSTR lpLocalPath, DWORD dwInfoLevel,
01924                                      LPVOID lpBuffer, LPDWORD lpBufferSize )
01925 {
01926     DWORD err, size;
01927 
01928     FIXME( "(%s, 0x%08X, %p, %p): stub\n",
01929            debugstr_w(lpLocalPath), dwInfoLevel, lpBuffer, lpBufferSize);
01930 
01931     switch (dwInfoLevel)
01932     {
01933     case UNIVERSAL_NAME_INFO_LEVEL:
01934     {
01935         LPUNIVERSAL_NAME_INFOW info = lpBuffer;
01936 
01937         size = sizeof(*info) + (lstrlenW(lpLocalPath) + 1) * sizeof(WCHAR);
01938         if (*lpBufferSize < size)
01939         {
01940             err = WN_MORE_DATA;
01941             break;
01942         }
01943         info->lpUniversalName = (LPWSTR)((char *)info + sizeof(*info));
01944         lstrcpyW(info->lpUniversalName, lpLocalPath);
01945         *lpBufferSize = size;
01946         err = WN_NO_ERROR;
01947         break;
01948     }
01949     case REMOTE_NAME_INFO_LEVEL:
01950         err = WN_NO_NETWORK;
01951         break;
01952 
01953     default:
01954         err = WN_BAD_VALUE;
01955         break;
01956     }
01957 
01958     if (err != WN_NO_ERROR) SetLastError(err);
01959     return err;
01960 }
01961 
01962 
01963 
01964 /*
01965  * Other Functions
01966  */
01967 
01968 /**************************************************************************
01969  * WNetGetUserA [MPR.@]
01970  *
01971  * FIXME: we should not return ourselves, but the owner of the drive lpName
01972  */
01973 DWORD WINAPI WNetGetUserA( LPCSTR lpName, LPSTR lpUserID, LPDWORD lpBufferSize )
01974 {
01975     if (GetUserNameA( lpUserID, lpBufferSize )) return WN_SUCCESS;
01976     return GetLastError();
01977 }
01978 
01979 /*****************************************************************
01980  * WNetGetUserW [MPR.@]
01981  *
01982  * FIXME: we should not return ourselves, but the owner of the drive lpName
01983  */
01984 DWORD WINAPI WNetGetUserW( LPCWSTR lpName, LPWSTR lpUserID, LPDWORD lpBufferSize )
01985 {
01986     if (GetUserNameW( lpUserID, lpBufferSize )) return WN_SUCCESS;
01987     return GetLastError();
01988 }
01989 
01990 /*********************************************************************
01991  * WNetConnectionDialog [MPR.@]
01992  */
01993 DWORD WINAPI WNetConnectionDialog( HWND hwnd, DWORD dwType )
01994 {
01995     FIXME( "(%p, %08X): stub\n", hwnd, dwType );
01996 
01997     SetLastError(WN_NO_NETWORK);
01998     return WN_NO_NETWORK;
01999 }
02000 
02001 /*********************************************************************
02002  * WNetConnectionDialog1A [MPR.@]
02003  */
02004 DWORD WINAPI WNetConnectionDialog1A( LPCONNECTDLGSTRUCTA lpConnDlgStruct )
02005 {
02006     FIXME( "(%p): stub\n", lpConnDlgStruct );
02007 
02008     SetLastError(WN_NO_NETWORK);
02009     return WN_NO_NETWORK;
02010 }
02011 
02012 /*********************************************************************
02013  * WNetConnectionDialog1W [MPR.@]
02014  */
02015 DWORD WINAPI WNetConnectionDialog1W( LPCONNECTDLGSTRUCTW lpConnDlgStruct )
02016 {
02017     FIXME( "(%p): stub\n", lpConnDlgStruct );
02018 
02019     SetLastError(WN_NO_NETWORK);
02020     return WN_NO_NETWORK;
02021 }
02022 
02023 /*********************************************************************
02024  * WNetDisconnectDialog [MPR.@]
02025  */
02026 DWORD WINAPI WNetDisconnectDialog( HWND hwnd, DWORD dwType )
02027 {
02028     FIXME( "(%p, %08X): stub\n", hwnd, dwType );
02029 
02030     SetLastError(WN_NO_NETWORK);
02031     return WN_NO_NETWORK;
02032 }
02033 
02034 /*********************************************************************
02035  * WNetDisconnectDialog1A [MPR.@]
02036  */
02037 DWORD WINAPI WNetDisconnectDialog1A( LPDISCDLGSTRUCTA lpConnDlgStruct )
02038 {
02039     FIXME( "(%p): stub\n", lpConnDlgStruct );
02040 
02041     SetLastError(WN_NO_NETWORK);
02042     return WN_NO_NETWORK;
02043 }
02044 
02045 /*********************************************************************
02046  * WNetDisconnectDialog1W [MPR.@]
02047  */
02048 DWORD WINAPI WNetDisconnectDialog1W( LPDISCDLGSTRUCTW lpConnDlgStruct )
02049 {
02050     FIXME( "(%p): stub\n", lpConnDlgStruct );
02051 
02052     SetLastError(WN_NO_NETWORK);
02053     return WN_NO_NETWORK;
02054 }
02055 
02056 /*********************************************************************
02057  * WNetGetLastErrorA [MPR.@]
02058  */
02059 DWORD WINAPI WNetGetLastErrorA( LPDWORD lpError,
02060                                 LPSTR lpErrorBuf, DWORD nErrorBufSize,
02061                                 LPSTR lpNameBuf, DWORD nNameBufSize )
02062 {
02063     FIXME( "(%p, %p, %d, %p, %d): stub\n",
02064            lpError, lpErrorBuf, nErrorBufSize, lpNameBuf, nNameBufSize );
02065 
02066     SetLastError(WN_NO_NETWORK);
02067     return WN_NO_NETWORK;
02068 }
02069 
02070 /*********************************************************************
02071  * WNetGetLastErrorW [MPR.@]
02072  */
02073 DWORD WINAPI WNetGetLastErrorW( LPDWORD lpError,
02074                                 LPWSTR lpErrorBuf, DWORD nErrorBufSize,
02075                          LPWSTR lpNameBuf, DWORD nNameBufSize )
02076 {
02077     FIXME( "(%p, %p, %d, %p, %d): stub\n",
02078            lpError, lpErrorBuf, nErrorBufSize, lpNameBuf, nNameBufSize );
02079 
02080     SetLastError(WN_NO_NETWORK);
02081     return WN_NO_NETWORK;
02082 }
02083 
02084 /*********************************************************************
02085  * WNetGetNetworkInformationA [MPR.@]
02086  */
02087 DWORD WINAPI WNetGetNetworkInformationA( LPCSTR lpProvider,
02088                                          LPNETINFOSTRUCT lpNetInfoStruct )
02089 {
02090     DWORD ret;
02091 
02092     TRACE( "(%s, %p)\n", debugstr_a(lpProvider), lpNetInfoStruct );
02093 
02094     if (!lpProvider)
02095         ret = WN_BAD_POINTER;
02096     else
02097     {
02098         int len;
02099 
02100         len = MultiByteToWideChar(CP_ACP, 0, lpProvider, -1, NULL, 0);
02101         if (len)
02102         {
02103             LPWSTR wideProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
02104 
02105             if (wideProvider)
02106             {
02107                 MultiByteToWideChar(CP_ACP, 0, lpProvider, -1, wideProvider,
02108                  len);
02109                 ret = WNetGetNetworkInformationW(wideProvider, lpNetInfoStruct);
02110                 HeapFree(GetProcessHeap(), 0, wideProvider);
02111             }
02112             else
02113                 ret = WN_OUT_OF_MEMORY;
02114         }
02115         else
02116             ret = GetLastError();
02117     }
02118     if (ret)
02119         SetLastError(ret);
02120     TRACE("Returning %d\n", ret);
02121     return ret;
02122 }
02123 
02124 /*********************************************************************
02125  * WNetGetNetworkInformationW [MPR.@]
02126  */
02127 DWORD WINAPI WNetGetNetworkInformationW( LPCWSTR lpProvider,
02128                                          LPNETINFOSTRUCT lpNetInfoStruct )
02129 {
02130     DWORD ret;
02131 
02132     TRACE( "(%s, %p)\n", debugstr_w(lpProvider), lpNetInfoStruct );
02133 
02134     if (!lpProvider)
02135         ret = WN_BAD_POINTER;
02136     else if (!lpNetInfoStruct)
02137         ret = WN_BAD_POINTER;
02138     else if (lpNetInfoStruct->cbStructure < sizeof(NETINFOSTRUCT))
02139         ret = WN_BAD_VALUE;
02140     else
02141     {
02142         if (providerTable && providerTable->numProviders)
02143         {
02144             DWORD providerIndex = _findProviderIndexW(lpProvider);
02145 
02146             if (providerIndex != BAD_PROVIDER_INDEX)
02147             {
02148                 lpNetInfoStruct->cbStructure = sizeof(NETINFOSTRUCT);
02149                 lpNetInfoStruct->dwProviderVersion =
02150                  providerTable->table[providerIndex].dwSpecVersion;
02151                 lpNetInfoStruct->dwStatus = NO_ERROR;
02152                 lpNetInfoStruct->dwCharacteristics = 0;
02153                 lpNetInfoStruct->dwHandle = 0;
02154                 lpNetInfoStruct->wNetType =
02155                  HIWORD(providerTable->table[providerIndex].dwNetType);
02156                 lpNetInfoStruct->dwPrinters = -1;
02157                 lpNetInfoStruct->dwDrives = -1;
02158                 ret = WN_SUCCESS;
02159             }
02160             else
02161                 ret = WN_BAD_PROVIDER;
02162         }
02163         else
02164             ret = WN_NO_NETWORK;
02165     }
02166     if (ret)
02167         SetLastError(ret);
02168     TRACE("Returning %d\n", ret);
02169     return ret;
02170 }
02171 
02172 /*****************************************************************
02173  *  WNetGetProviderNameA [MPR.@]
02174  */
02175 DWORD WINAPI WNetGetProviderNameA( DWORD dwNetType,
02176                                    LPSTR lpProvider, LPDWORD lpBufferSize )
02177 {
02178     DWORD ret;
02179 
02180     TRACE("(0x%08x, %s, %p)\n", dwNetType, debugstr_a(lpProvider),
02181      lpBufferSize);
02182 
02183     if (!lpProvider)
02184         ret = WN_BAD_POINTER;
02185     else if (!lpBufferSize)
02186         ret = WN_BAD_POINTER;
02187     else
02188     {
02189         if (providerTable)
02190         {
02191             DWORD i;
02192 
02193             ret = WN_NO_NETWORK;
02194             for (i = 0; i < providerTable->numProviders &&
02195              HIWORD(providerTable->table[i].dwNetType) != HIWORD(dwNetType);
02196              i++)
02197                 ;
02198             if (i < providerTable->numProviders)
02199             {
02200                 DWORD sizeNeeded = WideCharToMultiByte(CP_ACP, 0,
02201                  providerTable->table[i].name, -1, NULL, 0, NULL, NULL);
02202 
02203                 if (*lpBufferSize < sizeNeeded)
02204                 {
02205                     *lpBufferSize = sizeNeeded;
02206                     ret = WN_MORE_DATA;
02207                 }
02208                 else
02209                 {
02210                     WideCharToMultiByte(CP_ACP, 0, providerTable->table[i].name,
02211                      -1, lpProvider, *lpBufferSize, NULL, NULL);
02212                     ret = WN_SUCCESS;
02213                     /* FIXME: is *lpBufferSize set to the number of characters
02214                      * copied? */
02215                 }
02216             }
02217         }
02218         else
02219             ret = WN_NO_NETWORK;
02220     }
02221     if (ret)
02222         SetLastError(ret);
02223     TRACE("Returning %d\n", ret);
02224     return ret;
02225 }
02226 
02227 /*****************************************************************
02228  *  WNetGetProviderNameW [MPR.@]
02229  */
02230 DWORD WINAPI WNetGetProviderNameW( DWORD dwNetType,
02231                                    LPWSTR lpProvider, LPDWORD lpBufferSize )
02232 {
02233     DWORD ret;
02234 
02235     TRACE("(0x%08x, %s, %p)\n", dwNetType, debugstr_w(lpProvider),
02236      lpBufferSize);
02237 
02238     if (!lpProvider)
02239         ret = WN_BAD_POINTER;
02240     else if (!lpBufferSize)
02241         ret = WN_BAD_POINTER;
02242     else
02243     {
02244         if (providerTable)
02245         {
02246             DWORD i;
02247 
02248             ret = WN_NO_NETWORK;
02249             for (i = 0; i < providerTable->numProviders &&
02250              HIWORD(providerTable->table[i].dwNetType) != HIWORD(dwNetType);
02251              i++)
02252                 ;
02253             if (i < providerTable->numProviders)
02254             {
02255                 DWORD sizeNeeded = strlenW(providerTable->table[i].name) + 1;
02256 
02257                 if (*lpBufferSize < sizeNeeded)
02258                 {
02259                     *lpBufferSize = sizeNeeded;
02260                     ret = WN_MORE_DATA;
02261                 }
02262                 else
02263                 {
02264                     strcpyW(lpProvider, providerTable->table[i].name);
02265                     ret = WN_SUCCESS;
02266                     /* FIXME: is *lpBufferSize set to the number of characters
02267                      * copied? */
02268                 }
02269             }
02270         }
02271         else
02272             ret = WN_NO_NETWORK;
02273     }
02274     if (ret)
02275         SetLastError(ret);
02276     TRACE("Returning %d\n", ret);
02277     return ret;
02278 }

Generated on Sat May 26 2012 04:23:17 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.