1 /* 2 * MPR WNet functions 3 * 4 * Copyright 1999 Ulrich Weigand 5 * Copyright 2004 Juan Lang 6 * Copyright 2007 Maarten Lankhorst 7 * Copyright 2016-2018 Pierre Schweitzer 8 * 9 * This library is free software; you can redistribute it and/or 10 * modify it under the terms of the GNU Lesser General Public 11 * License as published by the Free Software Foundation; either 12 * version 2.1 of the License, or (at your option) any later version. 13 * 14 * This library is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 * Lesser General Public License for more details. 18 * 19 * You should have received a copy of the GNU Lesser General Public 20 * License along with this library; if not, write to the Free Software 21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 22 */ 23 24 #include <stdarg.h> 25 #include "windef.h" 26 #include "winbase.h" 27 #include "winnls.h" 28 #include "winioctl.h" 29 #include "winnetwk.h" 30 #include "npapi.h" 31 #include "winreg.h" 32 #include "winuser.h" 33 #define WINE_MOUNTMGR_EXTENSIONS 34 #include "ddk/mountmgr.h" 35 #include "wine/debug.h" 36 #include "wine/unicode.h" 37 #include "mprres.h" 38 #include "wnetpriv.h" 39 40 WINE_DEFAULT_DEBUG_CHANNEL(mpr); 41 42 /* Data structures representing network service providers. Assumes only one 43 * thread creates them, and that they are constant for the life of the process 44 * (and therefore doesn't synchronize access). 45 * FIXME: only basic provider data and enumeration-related data are implemented 46 * so far, need to implement the rest too. 47 */ 48 typedef struct _WNetProvider 49 { 50 HMODULE hLib; 51 PWSTR name; 52 PF_NPGetCaps getCaps; 53 DWORD dwSpecVersion; 54 DWORD dwNetType; 55 DWORD dwEnumScopes; 56 PF_NPOpenEnum openEnum; 57 PF_NPEnumResource enumResource; 58 PF_NPCloseEnum closeEnum; 59 PF_NPGetResourceInformation getResourceInformation; 60 PF_NPAddConnection addConnection; 61 PF_NPAddConnection3 addConnection3; 62 PF_NPCancelConnection cancelConnection; 63 #ifdef __REACTOS__ 64 PF_NPGetConnection getConnection; 65 #endif 66 } WNetProvider, *PWNetProvider; 67 68 typedef struct _WNetProviderTable 69 { 70 LPWSTR entireNetwork; 71 DWORD numAllocated; 72 DWORD numProviders; 73 WNetProvider table[1]; 74 } WNetProviderTable, *PWNetProviderTable; 75 76 #define WNET_ENUMERATOR_TYPE_GLOBAL 0 77 #define WNET_ENUMERATOR_TYPE_PROVIDER 1 78 #define WNET_ENUMERATOR_TYPE_CONTEXT 2 79 #define WNET_ENUMERATOR_TYPE_CONNECTED 3 80 #define WNET_ENUMERATOR_TYPE_REMEMBERED 4 81 82 /* An WNet enumerator. Note that the type doesn't correspond to the scope of 83 * the enumeration; it represents one of the following types: 84 * - a global enumeration, one that's executed across all providers 85 * - a provider-specific enumeration, one that's only executed by a single 86 * provider 87 * - a context enumeration. I know this contradicts what I just said about 88 * there being no correspondence between the scope and the type, but it's 89 * necessary for the special case that a "Entire Network" entry needs to 90 * be enumerated in an enumeration of the context scope. Thus an enumeration 91 * of the context scope results in a context type enumerator, which morphs 92 * into a global enumeration (so the enumeration continues across all 93 * providers). 94 * - a remembered enumeration, not related to providers themselves, but it 95 * is a registry enumeration for saved connections 96 */ 97 typedef struct _WNetEnumerator 98 { 99 DWORD enumType; 100 DWORD providerIndex; 101 HANDLE handle; 102 BOOL providerDone; 103 DWORD dwScope; 104 DWORD dwType; 105 DWORD dwUsage; 106 union 107 { 108 NETRESOURCEW* net; 109 HANDLE* handles; 110 struct 111 { 112 HKEY registry; 113 DWORD index; 114 } remembered; 115 } specific; 116 } WNetEnumerator, *PWNetEnumerator; 117 118 #define BAD_PROVIDER_INDEX (DWORD)0xffffffff 119 120 /* Returns an index (into the global WNetProviderTable) of the provider with 121 * the given name, or BAD_PROVIDER_INDEX if not found. 122 */ 123 static DWORD _findProviderIndexW(LPCWSTR lpProvider); 124 125 static PWNetProviderTable providerTable; 126 127 /* 128 * Global provider table functions 129 */ 130 131 static void _tryLoadProvider(PCWSTR provider) 132 { 133 static const WCHAR servicePrefix[] = { 'S','y','s','t','e','m','\\', 134 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\', 135 'S','e','r','v','i','c','e','s','\\',0 }; 136 static const WCHAR serviceFmt[] = { '%','s','%','s','\\', 137 'N','e','t','w','o','r','k','P','r','o','v','i','d','e','r',0 }; 138 WCHAR serviceName[MAX_PATH]; 139 HKEY hKey; 140 141 TRACE("%s\n", debugstr_w(provider)); 142 snprintfW(serviceName, ARRAY_SIZE(serviceName), serviceFmt, servicePrefix, provider); 143 serviceName[ARRAY_SIZE(serviceName) - 1] = '\0'; 144 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, serviceName, 0, KEY_READ, &hKey) == 145 ERROR_SUCCESS) 146 { 147 static const WCHAR szProviderPath[] = { 'P','r','o','v','i','d','e','r', 148 'P','a','t','h',0 }; 149 WCHAR providerPath[MAX_PATH]; 150 DWORD type, size = sizeof(providerPath); 151 152 if (RegQueryValueExW(hKey, szProviderPath, NULL, &type, 153 (LPBYTE)providerPath, &size) == ERROR_SUCCESS && (type == REG_SZ || type == REG_EXPAND_SZ)) 154 { 155 static const WCHAR szProviderName[] = { 'N','a','m','e',0 }; 156 PWSTR name = NULL; 157 158 if (type == REG_EXPAND_SZ) 159 { 160 WCHAR path[MAX_PATH]; 161 if (ExpandEnvironmentStringsW(providerPath, path, MAX_PATH)) lstrcpyW( providerPath, path ); 162 } 163 164 size = 0; 165 RegQueryValueExW(hKey, szProviderName, NULL, NULL, NULL, &size); 166 if (size) 167 { 168 name = HeapAlloc(GetProcessHeap(), 0, size); 169 if (RegQueryValueExW(hKey, szProviderName, NULL, &type, 170 (LPBYTE)name, &size) != ERROR_SUCCESS || type != REG_SZ) 171 { 172 HeapFree(GetProcessHeap(), 0, name); 173 name = NULL; 174 } 175 } 176 if (name) 177 { 178 HMODULE hLib = LoadLibraryW(providerPath); 179 180 if (hLib) 181 { 182 #define MPR_GETPROC(proc) ((PF_##proc)GetProcAddress(hLib, #proc)) 183 184 PF_NPGetCaps getCaps = MPR_GETPROC(NPGetCaps); 185 186 TRACE("loaded lib %p\n", hLib); 187 if (getCaps) 188 { 189 DWORD connectCap; 190 PWNetProvider provider = 191 &providerTable->table[providerTable->numProviders]; 192 193 provider->hLib = hLib; 194 provider->name = name; 195 TRACE("name is %s\n", debugstr_w(name)); 196 provider->getCaps = getCaps; 197 provider->dwSpecVersion = getCaps(WNNC_SPEC_VERSION); 198 provider->dwNetType = getCaps(WNNC_NET_TYPE); 199 TRACE("net type is 0x%08x\n", provider->dwNetType); 200 provider->dwEnumScopes = getCaps(WNNC_ENUMERATION); 201 if (provider->dwEnumScopes) 202 { 203 TRACE("supports enumeration\n"); 204 provider->openEnum = MPR_GETPROC(NPOpenEnum); 205 TRACE("NPOpenEnum %p\n", provider->openEnum); 206 provider->enumResource = MPR_GETPROC(NPEnumResource); 207 TRACE("NPEnumResource %p\n", provider->enumResource); 208 provider->closeEnum = MPR_GETPROC(NPCloseEnum); 209 TRACE("NPCloseEnum %p\n", provider->closeEnum); 210 provider->getResourceInformation = MPR_GETPROC(NPGetResourceInformation); 211 TRACE("NPGetResourceInformation %p\n", provider->getResourceInformation); 212 if (!provider->openEnum || 213 !provider->enumResource || 214 !provider->closeEnum) 215 { 216 provider->openEnum = NULL; 217 provider->enumResource = NULL; 218 provider->closeEnum = NULL; 219 provider->dwEnumScopes = 0; 220 WARN("Couldn't load enumeration functions\n"); 221 } 222 } 223 connectCap = getCaps(WNNC_CONNECTION); 224 if (connectCap & WNNC_CON_ADDCONNECTION) 225 provider->addConnection = MPR_GETPROC(NPAddConnection); 226 if (connectCap & WNNC_CON_ADDCONNECTION3) 227 provider->addConnection3 = MPR_GETPROC(NPAddConnection3); 228 if (connectCap & WNNC_CON_CANCELCONNECTION) 229 provider->cancelConnection = MPR_GETPROC(NPCancelConnection); 230 #ifdef __REACTOS__ 231 if (connectCap & WNNC_CON_GETCONNECTIONS) 232 provider->getConnection = MPR_GETPROC(NPGetConnection); 233 #endif 234 TRACE("NPAddConnection %p\n", provider->addConnection); 235 TRACE("NPAddConnection3 %p\n", provider->addConnection3); 236 TRACE("NPCancelConnection %p\n", provider->cancelConnection); 237 providerTable->numProviders++; 238 } 239 else 240 { 241 WARN("Provider %s didn't export NPGetCaps\n", 242 debugstr_w(provider)); 243 HeapFree(GetProcessHeap(), 0, name); 244 FreeLibrary(hLib); 245 } 246 247 #undef MPR_GETPROC 248 } 249 else 250 { 251 WARN("Couldn't load library %s for provider %s\n", 252 debugstr_w(providerPath), debugstr_w(provider)); 253 HeapFree(GetProcessHeap(), 0, name); 254 } 255 } 256 else 257 { 258 WARN("Couldn't get provider name for provider %s\n", 259 debugstr_w(provider)); 260 } 261 } 262 else 263 WARN("Couldn't open value %s\n", debugstr_w(szProviderPath)); 264 RegCloseKey(hKey); 265 } 266 else 267 WARN("Couldn't open service key for provider %s\n", 268 debugstr_w(provider)); 269 } 270 271 void wnetInit(HINSTANCE hInstDll) 272 { 273 static const WCHAR providerOrderKey[] = { 'S','y','s','t','e','m','\\', 274 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\', 275 'C','o','n','t','r','o','l','\\', 276 'N','e','t','w','o','r','k','P','r','o','v','i','d','e','r','\\', 277 'O','r','d','e','r',0 }; 278 static const WCHAR providerOrder[] = { 'P','r','o','v','i','d','e','r', 279 'O','r','d','e','r',0 }; 280 HKEY hKey; 281 282 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, providerOrderKey, 0, KEY_READ, &hKey) 283 == ERROR_SUCCESS) 284 { 285 DWORD size = 0; 286 287 RegQueryValueExW(hKey, providerOrder, NULL, NULL, NULL, &size); 288 if (size) 289 { 290 PWSTR providers = HeapAlloc(GetProcessHeap(), 0, size); 291 292 if (providers) 293 { 294 DWORD type; 295 296 if (RegQueryValueExW(hKey, providerOrder, NULL, &type, 297 (LPBYTE)providers, &size) == ERROR_SUCCESS && type == REG_SZ) 298 { 299 PWSTR ptr; 300 DWORD numToAllocate; 301 302 TRACE("provider order is %s\n", debugstr_w(providers)); 303 /* first count commas as a heuristic for how many to 304 * allocate space for */ 305 for (ptr = providers, numToAllocate = 1; ptr; ) 306 { 307 ptr = strchrW(ptr, ','); 308 if (ptr) { 309 numToAllocate++; 310 ptr++; 311 } 312 } 313 providerTable = 314 HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 315 sizeof(WNetProviderTable) 316 + (numToAllocate - 1) * sizeof(WNetProvider)); 317 if (providerTable) 318 { 319 PWSTR ptrPrev; 320 int entireNetworkLen; 321 LPCWSTR stringresource; 322 323 entireNetworkLen = LoadStringW(hInstDll, 324 IDS_ENTIRENETWORK, (LPWSTR)&stringresource, 0); 325 providerTable->entireNetwork = HeapAlloc( 326 GetProcessHeap(), 0, (entireNetworkLen + 1) * 327 sizeof(WCHAR)); 328 if (providerTable->entireNetwork) 329 { 330 memcpy(providerTable->entireNetwork, stringresource, entireNetworkLen*sizeof(WCHAR)); 331 providerTable->entireNetwork[entireNetworkLen] = 0; 332 } 333 providerTable->numAllocated = numToAllocate; 334 for (ptr = providers; ptr; ) 335 { 336 ptrPrev = ptr; 337 ptr = strchrW(ptr, ','); 338 if (ptr) 339 *ptr++ = '\0'; 340 _tryLoadProvider(ptrPrev); 341 } 342 } 343 } 344 HeapFree(GetProcessHeap(), 0, providers); 345 } 346 } 347 RegCloseKey(hKey); 348 } 349 } 350 351 void wnetFree(void) 352 { 353 if (providerTable) 354 { 355 DWORD i; 356 357 for (i = 0; i < providerTable->numProviders; i++) 358 { 359 HeapFree(GetProcessHeap(), 0, providerTable->table[i].name); 360 FreeModule(providerTable->table[i].hLib); 361 } 362 HeapFree(GetProcessHeap(), 0, providerTable->entireNetwork); 363 HeapFree(GetProcessHeap(), 0, providerTable); 364 providerTable = NULL; 365 } 366 } 367 368 static DWORD _findProviderIndexW(LPCWSTR lpProvider) 369 { 370 DWORD ret = BAD_PROVIDER_INDEX; 371 372 if (providerTable && providerTable->numProviders) 373 { 374 DWORD i; 375 376 for (i = 0; i < providerTable->numProviders && 377 ret == BAD_PROVIDER_INDEX; i++) 378 if (!strcmpW(lpProvider, providerTable->table[i].name)) 379 ret = i; 380 } 381 return ret; 382 } 383 384 /* 385 * Browsing Functions 386 */ 387 388 static LPNETRESOURCEW _copyNetResourceForEnumW(LPNETRESOURCEW lpNet) 389 { 390 LPNETRESOURCEW ret; 391 392 if (lpNet) 393 { 394 ret = HeapAlloc(GetProcessHeap(), 0, sizeof(NETRESOURCEW)); 395 if (ret) 396 { 397 size_t len; 398 399 *ret = *lpNet; 400 ret->lpLocalName = ret->lpComment = ret->lpProvider = NULL; 401 if (lpNet->lpRemoteName) 402 { 403 len = strlenW(lpNet->lpRemoteName) + 1; 404 ret->lpRemoteName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); 405 if (ret->lpRemoteName) 406 strcpyW(ret->lpRemoteName, lpNet->lpRemoteName); 407 } 408 } 409 } 410 else 411 ret = NULL; 412 return ret; 413 } 414 415 static void _freeEnumNetResource(LPNETRESOURCEW lpNet) 416 { 417 if (lpNet) 418 { 419 HeapFree(GetProcessHeap(), 0, lpNet->lpRemoteName); 420 HeapFree(GetProcessHeap(), 0, lpNet); 421 } 422 } 423 424 static PWNetEnumerator _createGlobalEnumeratorW(DWORD dwScope, DWORD dwType, 425 DWORD dwUsage, LPNETRESOURCEW lpNet) 426 { 427 PWNetEnumerator ret = HeapAlloc(GetProcessHeap(), 428 HEAP_ZERO_MEMORY, sizeof(WNetEnumerator)); 429 430 if (ret) 431 { 432 ret->enumType = WNET_ENUMERATOR_TYPE_GLOBAL; 433 ret->dwScope = dwScope; 434 ret->dwType = dwType; 435 ret->dwUsage = dwUsage; 436 ret->specific.net = _copyNetResourceForEnumW(lpNet); 437 } 438 return ret; 439 } 440 441 static PWNetEnumerator _createProviderEnumerator(DWORD dwScope, DWORD dwType, 442 DWORD dwUsage, DWORD index, HANDLE handle) 443 { 444 PWNetEnumerator ret; 445 446 if (!providerTable || index >= providerTable->numProviders) 447 ret = NULL; 448 else 449 { 450 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WNetEnumerator)); 451 if (ret) 452 { 453 ret->enumType = WNET_ENUMERATOR_TYPE_PROVIDER; 454 ret->providerIndex = index; 455 ret->dwScope = dwScope; 456 ret->dwType = dwType; 457 ret->dwUsage = dwUsage; 458 ret->handle = handle; 459 } 460 } 461 return ret; 462 } 463 464 static PWNetEnumerator _createContextEnumerator(DWORD dwScope, DWORD dwType, 465 DWORD dwUsage) 466 { 467 PWNetEnumerator ret = HeapAlloc(GetProcessHeap(), 468 HEAP_ZERO_MEMORY, sizeof(WNetEnumerator)); 469 470 if (ret) 471 { 472 ret->enumType = WNET_ENUMERATOR_TYPE_CONTEXT; 473 ret->dwScope = dwScope; 474 ret->dwType = dwType; 475 ret->dwUsage = dwUsage; 476 } 477 return ret; 478 } 479 480 static PWNetEnumerator _createConnectedEnumerator(DWORD dwScope, DWORD dwType, 481 DWORD dwUsage) 482 { 483 PWNetEnumerator ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WNetEnumerator)); 484 if (ret) 485 { 486 ret->enumType = WNET_ENUMERATOR_TYPE_CONNECTED; 487 ret->dwScope = dwScope; 488 ret->dwType = dwType; 489 ret->dwUsage = dwUsage; 490 ret->specific.handles = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(HANDLE) * providerTable->numProviders); 491 if (!ret->specific.handles) 492 { 493 HeapFree(GetProcessHeap(), 0, ret); 494 ret = NULL; 495 } 496 } 497 return ret; 498 } 499 500 static PWNetEnumerator _createRememberedEnumerator(DWORD dwScope, DWORD dwType, 501 HKEY remembered) 502 { 503 PWNetEnumerator ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WNetEnumerator)); 504 if (ret) 505 { 506 ret->enumType = WNET_ENUMERATOR_TYPE_REMEMBERED; 507 ret->dwScope = dwScope; 508 ret->dwType = dwType; 509 ret->specific.remembered.registry = remembered; 510 } 511 return ret; 512 } 513 514 /* Thunks the array of wide-string LPNETRESOURCEs lpNetArrayIn into buffer 515 * lpBuffer, with size *lpBufferSize. lpNetArrayIn contains *lpcCount entries 516 * to start. On return, *lpcCount reflects the number thunked into lpBuffer. 517 * Returns WN_SUCCESS on success (all of lpNetArrayIn thunked), WN_MORE_DATA 518 * if not all members of the array could be thunked, and something else on 519 * failure. 520 */ 521 static DWORD _thunkNetResourceArrayWToA(const NETRESOURCEW *lpNetArrayIn, 522 const DWORD *lpcCount, LPVOID lpBuffer, const DWORD *lpBufferSize) 523 { 524 DWORD i, numToThunk, totalBytes, ret; 525 LPSTR strNext; 526 527 if (!lpNetArrayIn) 528 return WN_BAD_POINTER; 529 if (!lpcCount) 530 return WN_BAD_POINTER; 531 if (*lpcCount == -1) 532 return WN_BAD_VALUE; 533 if (!lpBuffer) 534 return WN_BAD_POINTER; 535 if (!lpBufferSize) 536 return WN_BAD_POINTER; 537 538 for (i = 0, numToThunk = 0, totalBytes = 0; i < *lpcCount; i++) 539 { 540 const NETRESOURCEW *lpNet = lpNetArrayIn + i; 541 542 totalBytes += sizeof(NETRESOURCEA); 543 if (lpNet->lpLocalName) 544 totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpLocalName, 545 -1, NULL, 0, NULL, NULL); 546 if (lpNet->lpRemoteName) 547 totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpRemoteName, 548 -1, NULL, 0, NULL, NULL); 549 if (lpNet->lpComment) 550 totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpComment, 551 -1, NULL, 0, NULL, NULL); 552 if (lpNet->lpProvider) 553 totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpProvider, 554 -1, NULL, 0, NULL, NULL); 555 if (totalBytes < *lpBufferSize) 556 numToThunk = i + 1; 557 } 558 strNext = (LPSTR)((LPBYTE)lpBuffer + numToThunk * sizeof(NETRESOURCEA)); 559 for (i = 0; i < numToThunk; i++) 560 { 561 LPNETRESOURCEA lpNetOut = (LPNETRESOURCEA)lpBuffer + i; 562 const NETRESOURCEW *lpNetIn = lpNetArrayIn + i; 563 564 memcpy(lpNetOut, lpNetIn, sizeof(NETRESOURCEA)); 565 /* lie about string lengths, we already verified how many 566 * we have space for above 567 */ 568 if (lpNetIn->lpLocalName) 569 { 570 lpNetOut->lpLocalName = strNext; 571 strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpLocalName, -1, 572 lpNetOut->lpLocalName, *lpBufferSize, NULL, NULL); 573 } 574 if (lpNetIn->lpRemoteName) 575 { 576 lpNetOut->lpRemoteName = strNext; 577 strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpRemoteName, -1, 578 lpNetOut->lpRemoteName, *lpBufferSize, NULL, NULL); 579 } 580 if (lpNetIn->lpComment) 581 { 582 lpNetOut->lpComment = strNext; 583 strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpComment, -1, 584 lpNetOut->lpComment, *lpBufferSize, NULL, NULL); 585 } 586 if (lpNetIn->lpProvider) 587 { 588 lpNetOut->lpProvider = strNext; 589 strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpProvider, -1, 590 lpNetOut->lpProvider, *lpBufferSize, NULL, NULL); 591 } 592 } 593 ret = numToThunk < *lpcCount ? WN_MORE_DATA : WN_SUCCESS; 594 TRACE("numToThunk is %d, *lpcCount is %d, returning %d\n", numToThunk, 595 *lpcCount, ret); 596 return ret; 597 } 598 599 /* Thunks the array of multibyte-string LPNETRESOURCEs lpNetArrayIn into buffer 600 * lpBuffer, with size *lpBufferSize. lpNetArrayIn contains *lpcCount entries 601 * to start. On return, *lpcCount reflects the number thunked into lpBuffer. 602 * Returns WN_SUCCESS on success (all of lpNetArrayIn thunked), WN_MORE_DATA 603 * if not all members of the array could be thunked, and something else on 604 * failure. 605 */ 606 static DWORD _thunkNetResourceArrayAToW(const NETRESOURCEA *lpNetArrayIn, 607 const DWORD *lpcCount, LPVOID lpBuffer, const DWORD *lpBufferSize) 608 { 609 DWORD i, numToThunk, totalBytes, ret; 610 LPWSTR strNext; 611 612 if (!lpNetArrayIn) 613 return WN_BAD_POINTER; 614 if (!lpcCount) 615 return WN_BAD_POINTER; 616 if (*lpcCount == -1) 617 return WN_BAD_VALUE; 618 if (!lpBuffer) 619 return WN_BAD_POINTER; 620 if (!lpBufferSize) 621 return WN_BAD_POINTER; 622 623 for (i = 0, numToThunk = 0, totalBytes = 0; i < *lpcCount; i++) 624 { 625 const NETRESOURCEA *lpNet = lpNetArrayIn + i; 626 627 totalBytes += sizeof(NETRESOURCEW); 628 if (lpNet->lpLocalName) 629 totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpLocalName, 630 -1, NULL, 0) * sizeof(WCHAR); 631 if (lpNet->lpRemoteName) 632 totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpRemoteName, 633 -1, NULL, 0) * sizeof(WCHAR); 634 if (lpNet->lpComment) 635 totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpComment, 636 -1, NULL, 0) * sizeof(WCHAR); 637 if (lpNet->lpProvider) 638 totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpProvider, 639 -1, NULL, 0) * sizeof(WCHAR); 640 if (totalBytes < *lpBufferSize) 641 numToThunk = i + 1; 642 } 643 strNext = (LPWSTR)((LPBYTE)lpBuffer + numToThunk * sizeof(NETRESOURCEW)); 644 for (i = 0; i < numToThunk; i++) 645 { 646 LPNETRESOURCEW lpNetOut = (LPNETRESOURCEW)lpBuffer + i; 647 const NETRESOURCEA *lpNetIn = lpNetArrayIn + i; 648 649 memcpy(lpNetOut, lpNetIn, sizeof(NETRESOURCEW)); 650 /* lie about string lengths, we already verified how many 651 * we have space for above 652 */ 653 if (lpNetIn->lpLocalName) 654 { 655 lpNetOut->lpLocalName = strNext; 656 strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpLocalName, 657 -1, lpNetOut->lpLocalName, *lpBufferSize); 658 } 659 if (lpNetIn->lpRemoteName) 660 { 661 lpNetOut->lpRemoteName = strNext; 662 strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpRemoteName, 663 -1, lpNetOut->lpRemoteName, *lpBufferSize); 664 } 665 if (lpNetIn->lpComment) 666 { 667 lpNetOut->lpComment = strNext; 668 strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpComment, 669 -1, lpNetOut->lpComment, *lpBufferSize); 670 } 671 if (lpNetIn->lpProvider) 672 { 673 lpNetOut->lpProvider = strNext; 674 strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpProvider, 675 -1, lpNetOut->lpProvider, *lpBufferSize); 676 } 677 } 678 ret = numToThunk < *lpcCount ? WN_MORE_DATA : WN_SUCCESS; 679 TRACE("numToThunk is %d, *lpcCount is %d, returning %d\n", numToThunk, 680 *lpcCount, ret); 681 return ret; 682 } 683 684 /********************************************************************* 685 * WNetOpenEnumA [MPR.@] 686 * 687 * See comments for WNetOpenEnumW. 688 */ 689 DWORD WINAPI WNetOpenEnumA( DWORD dwScope, DWORD dwType, DWORD dwUsage, 690 LPNETRESOURCEA lpNet, LPHANDLE lphEnum ) 691 { 692 DWORD ret; 693 694 TRACE( "(%08X, %08X, %08X, %p, %p)\n", 695 dwScope, dwType, dwUsage, lpNet, lphEnum ); 696 697 if (!lphEnum) 698 ret = WN_BAD_POINTER; 699 else if (!providerTable || providerTable->numProviders == 0) 700 { 701 *lphEnum = NULL; 702 ret = WN_NO_NETWORK; 703 } 704 else 705 { 706 if (lpNet) 707 { 708 LPNETRESOURCEW lpNetWide = NULL; 709 BYTE buf[1024]; 710 DWORD size = sizeof(buf), count = 1; 711 BOOL allocated = FALSE; 712 713 ret = _thunkNetResourceArrayAToW(lpNet, &count, buf, &size); 714 if (ret == WN_MORE_DATA) 715 { 716 lpNetWide = HeapAlloc(GetProcessHeap(), 0, 717 size); 718 if (lpNetWide) 719 { 720 ret = _thunkNetResourceArrayAToW(lpNet, &count, lpNetWide, 721 &size); 722 allocated = TRUE; 723 } 724 else 725 ret = WN_OUT_OF_MEMORY; 726 } 727 else if (ret == WN_SUCCESS) 728 lpNetWide = (LPNETRESOURCEW)buf; 729 if (ret == WN_SUCCESS) 730 ret = WNetOpenEnumW(dwScope, dwType, dwUsage, lpNetWide, 731 lphEnum); 732 if (allocated) 733 HeapFree(GetProcessHeap(), 0, lpNetWide); 734 } 735 else 736 ret = WNetOpenEnumW(dwScope, dwType, dwUsage, NULL, lphEnum); 737 } 738 if (ret) 739 SetLastError(ret); 740 TRACE("Returning %d\n", ret); 741 return ret; 742 } 743 744 /********************************************************************* 745 * WNetOpenEnumW [MPR.@] 746 * 747 * Network enumeration has way too many parameters, so I'm not positive I got 748 * them right. What I've got so far: 749 * 750 * - If the scope is RESOURCE_GLOBALNET, and no LPNETRESOURCE is passed, 751 * all the network providers should be enumerated. 752 * 753 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and 754 * and neither the LPNETRESOURCE's lpRemoteName nor the LPNETRESOURCE's 755 * lpProvider is set, all the network providers should be enumerated. 756 * (This means the enumeration is a list of network providers, not that the 757 * enumeration is passed on to the providers.) 758 * 759 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and the 760 * resource matches the "Entire Network" resource (no remote name, no 761 * provider, comment is the "Entire Network" string), a RESOURCE_GLOBALNET 762 * enumeration is done on every network provider. 763 * 764 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and 765 * the LPNETRESOURCE's lpProvider is set, enumeration will be passed through 766 * only to the given network provider. 767 * 768 * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and 769 * no lpProvider is set, enumeration will be tried on every network provider, 770 * in the order in which they're loaded. 771 * 772 * - The LPNETRESOURCE should be disregarded for scopes besides 773 * RESOURCE_GLOBALNET. MSDN states that lpNet must be NULL if dwScope is not 774 * RESOURCE_GLOBALNET, but Windows doesn't return an error if it isn't NULL. 775 * 776 * - If the scope is RESOURCE_CONTEXT, MS includes an "Entire Network" net 777 * resource in the enumerated list, as well as any machines in your 778 * workgroup. The machines in your workgroup come from doing a 779 * RESOURCE_CONTEXT enumeration of every Network Provider. 780 */ 781 DWORD WINAPI WNetOpenEnumW( DWORD dwScope, DWORD dwType, DWORD dwUsage, 782 LPNETRESOURCEW lpNet, LPHANDLE lphEnum ) 783 { 784 DWORD ret; 785 786 TRACE( "(%08X, %08X, %08X, %p, %p)\n", 787 dwScope, dwType, dwUsage, lpNet, lphEnum ); 788 789 if (!lphEnum) 790 ret = WN_BAD_POINTER; 791 else if (!providerTable || providerTable->numProviders == 0) 792 { 793 *lphEnum = NULL; 794 ret = WN_NO_NETWORK; 795 } 796 else 797 { 798 switch (dwScope) 799 { 800 case RESOURCE_GLOBALNET: 801 if (lpNet) 802 { 803 if (lpNet->lpProvider) 804 { 805 DWORD index = _findProviderIndexW(lpNet->lpProvider); 806 807 if (index != BAD_PROVIDER_INDEX) 808 { 809 if (providerTable->table[index].openEnum && 810 providerTable->table[index].dwEnumScopes & WNNC_ENUM_GLOBAL) 811 { 812 HANDLE handle; 813 PWSTR RemoteName = lpNet->lpRemoteName; 814 815 if ((lpNet->dwUsage & RESOURCEUSAGE_CONTAINER) && 816 RemoteName && !strcmpW(RemoteName, lpNet->lpProvider)) 817 lpNet->lpRemoteName = NULL; 818 819 ret = providerTable->table[index].openEnum( 820 dwScope, dwType, dwUsage, lpNet, &handle); 821 if (ret == WN_SUCCESS) 822 { 823 *lphEnum = _createProviderEnumerator( 824 dwScope, dwType, dwUsage, index, handle); 825 ret = *lphEnum ? WN_SUCCESS : 826 WN_OUT_OF_MEMORY; 827 } 828 829 lpNet->lpRemoteName = RemoteName; 830 } 831 else 832 ret = WN_NOT_SUPPORTED; 833 } 834 else 835 ret = WN_BAD_PROVIDER; 836 } 837 else if (lpNet->lpRemoteName) 838 { 839 *lphEnum = _createGlobalEnumeratorW(dwScope, 840 dwType, dwUsage, lpNet); 841 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY; 842 } 843 else 844 { 845 if (lpNet->lpComment && !strcmpW(lpNet->lpComment, 846 providerTable->entireNetwork)) 847 { 848 /* comment matches the "Entire Network", enumerate 849 * global scope of every provider 850 */ 851 *lphEnum = _createGlobalEnumeratorW(dwScope, 852 dwType, dwUsage, lpNet); 853 } 854 else 855 { 856 /* this is the same as not having passed lpNet */ 857 *lphEnum = _createGlobalEnumeratorW(dwScope, 858 dwType, dwUsage, NULL); 859 } 860 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY; 861 } 862 } 863 else 864 { 865 *lphEnum = _createGlobalEnumeratorW(dwScope, dwType, 866 dwUsage, lpNet); 867 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY; 868 } 869 break; 870 case RESOURCE_CONTEXT: 871 *lphEnum = _createContextEnumerator(dwScope, dwType, dwUsage); 872 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY; 873 break; 874 case RESOURCE_CONNECTED: 875 *lphEnum = _createConnectedEnumerator(dwScope, dwType, dwUsage); 876 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY; 877 break; 878 case RESOURCE_REMEMBERED: 879 { 880 HKEY remembered, user_profile; 881 882 ret = WN_OUT_OF_MEMORY; 883 if (RegOpenCurrentUser(KEY_READ, &user_profile) == ERROR_SUCCESS) 884 { 885 WCHAR subkey[8] = {'N', 'e', 't', 'w', 'o', 'r', 'k', 0}; 886 887 if (RegOpenKeyExW(user_profile, subkey, 0, KEY_READ, &remembered) == ERROR_SUCCESS) 888 { 889 *lphEnum = _createRememberedEnumerator(dwScope, dwType, remembered); 890 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY; 891 } 892 893 RegCloseKey(user_profile); 894 } 895 } 896 break; 897 default: 898 WARN("unknown scope 0x%08x\n", dwScope); 899 ret = WN_BAD_VALUE; 900 } 901 } 902 if (ret) 903 SetLastError(ret); 904 TRACE("Returning %d\n", ret); 905 return ret; 906 } 907 908 /********************************************************************* 909 * WNetEnumResourceA [MPR.@] 910 */ 911 DWORD WINAPI WNetEnumResourceA( HANDLE hEnum, LPDWORD lpcCount, 912 LPVOID lpBuffer, LPDWORD lpBufferSize ) 913 { 914 DWORD ret; 915 916 TRACE( "(%p, %p, %p, %p)\n", hEnum, lpcCount, lpBuffer, lpBufferSize ); 917 918 if (!hEnum) 919 ret = WN_BAD_POINTER; 920 else if (!lpcCount) 921 ret = WN_BAD_POINTER; 922 else if (!lpBuffer) 923 ret = WN_BAD_POINTER; 924 else if (!lpBufferSize) 925 ret = WN_BAD_POINTER; 926 else if (*lpBufferSize < sizeof(NETRESOURCEA)) 927 { 928 *lpBufferSize = sizeof(NETRESOURCEA); 929 ret = WN_MORE_DATA; 930 } 931 else 932 { 933 DWORD localCount = *lpcCount, localSize = *lpBufferSize; 934 LPVOID localBuffer = HeapAlloc(GetProcessHeap(), 0, localSize); 935 936 if (localBuffer) 937 { 938 ret = WNetEnumResourceW(hEnum, &localCount, localBuffer, 939 &localSize); 940 if (ret == WN_SUCCESS || (ret == WN_MORE_DATA && localCount != -1)) 941 { 942 /* FIXME: this isn't necessarily going to work in the case of 943 * WN_MORE_DATA, because our enumerator may have moved on to 944 * the next provider. MSDN states that a large (16KB) buffer 945 * size is the appropriate usage of this function, so 946 * hopefully it won't be an issue. 947 */ 948 ret = _thunkNetResourceArrayWToA(localBuffer, &localCount, 949 lpBuffer, lpBufferSize); 950 *lpcCount = localCount; 951 } 952 HeapFree(GetProcessHeap(), 0, localBuffer); 953 } 954 else 955 ret = WN_OUT_OF_MEMORY; 956 } 957 if (ret) 958 SetLastError(ret); 959 TRACE("Returning %d\n", ret); 960 return ret; 961 } 962 963 static DWORD _countProviderBytesW(PWNetProvider provider) 964 { 965 DWORD ret; 966 967 if (provider) 968 { 969 ret = sizeof(NETRESOURCEW); 970 ret += 2 * (strlenW(provider->name) + 1) * sizeof(WCHAR); 971 } 972 else 973 ret = 0; 974 return ret; 975 } 976 977 static DWORD _enumerateProvidersW(PWNetEnumerator enumerator, LPDWORD lpcCount, 978 LPVOID lpBuffer, const DWORD *lpBufferSize) 979 { 980 DWORD ret; 981 982 if (!enumerator) 983 return WN_BAD_POINTER; 984 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL) 985 return WN_BAD_VALUE; 986 if (!lpcCount) 987 return WN_BAD_POINTER; 988 if (!lpBuffer) 989 return WN_BAD_POINTER; 990 if (!lpBufferSize) 991 return WN_BAD_POINTER; 992 if (*lpBufferSize < sizeof(NETRESOURCEA)) 993 return WN_MORE_DATA; 994 995 if (!providerTable || enumerator->providerIndex >= 996 providerTable->numProviders) 997 ret = WN_NO_MORE_ENTRIES; 998 else 999 { 1000 DWORD bytes = 0, count = 0, countLimit, i; 1001 LPNETRESOURCEW resource; 1002 LPWSTR strNext; 1003 1004 countLimit = *lpcCount == -1 ? 1005 providerTable->numProviders - enumerator->providerIndex : *lpcCount; 1006 while (count < countLimit && bytes < *lpBufferSize) 1007 { 1008 DWORD bytesNext = _countProviderBytesW( 1009 &providerTable->table[count + enumerator->providerIndex]); 1010 1011 if (bytes + bytesNext < *lpBufferSize) 1012 { 1013 bytes += bytesNext; 1014 count++; 1015 } 1016 } 1017 strNext = (LPWSTR)((LPBYTE)lpBuffer + count * sizeof(NETRESOURCEW)); 1018 for (i = 0, resource = lpBuffer; i < count; i++, resource++) 1019 { 1020 resource->dwScope = RESOURCE_GLOBALNET; 1021 resource->dwType = RESOURCETYPE_ANY; 1022 resource->dwDisplayType = RESOURCEDISPLAYTYPE_NETWORK; 1023 resource->dwUsage = RESOURCEUSAGE_CONTAINER | 1024 RESOURCEUSAGE_RESERVED; 1025 resource->lpLocalName = NULL; 1026 resource->lpRemoteName = strNext; 1027 strcpyW(resource->lpRemoteName, 1028 providerTable->table[i + enumerator->providerIndex].name); 1029 strNext += strlenW(resource->lpRemoteName) + 1; 1030 resource->lpComment = NULL; 1031 resource->lpProvider = strNext; 1032 strcpyW(resource->lpProvider, 1033 providerTable->table[i + enumerator->providerIndex].name); 1034 strNext += strlenW(resource->lpProvider) + 1; 1035 } 1036 enumerator->providerIndex += count; 1037 *lpcCount = count; 1038 ret = count > 0 ? WN_SUCCESS : WN_MORE_DATA; 1039 } 1040 TRACE("Returning %d\n", ret); 1041 return ret; 1042 } 1043 1044 /* Advances the enumerator (assumed to be a global enumerator) to the next 1045 * provider that supports the enumeration scope passed to WNetOpenEnum. Does 1046 * not open a handle with the next provider. 1047 * If the existing handle is NULL, may leave the enumerator unchanged, since 1048 * the current provider may support the desired scope. 1049 * If the existing handle is not NULL, closes it before moving on. 1050 * Returns WN_SUCCESS on success, WN_NO_MORE_ENTRIES if there is no available 1051 * provider, and another error on failure. 1052 */ 1053 static DWORD _globalEnumeratorAdvance(PWNetEnumerator enumerator) 1054 { 1055 if (!enumerator) 1056 return WN_BAD_POINTER; 1057 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL) 1058 return WN_BAD_VALUE; 1059 if (!providerTable || enumerator->providerIndex >= 1060 providerTable->numProviders) 1061 return WN_NO_MORE_ENTRIES; 1062 1063 if (enumerator->providerDone) 1064 { 1065 DWORD dwEnum = 0; 1066 enumerator->providerDone = FALSE; 1067 if (enumerator->handle) 1068 { 1069 providerTable->table[enumerator->providerIndex].closeEnum( 1070 enumerator->handle); 1071 enumerator->handle = NULL; 1072 enumerator->providerIndex++; 1073 } 1074 if (enumerator->dwScope == RESOURCE_CONNECTED) 1075 dwEnum = WNNC_ENUM_LOCAL; 1076 else if (enumerator->dwScope == RESOURCE_GLOBALNET) 1077 dwEnum = WNNC_ENUM_GLOBAL; 1078 else if (enumerator->dwScope == RESOURCE_CONTEXT) 1079 dwEnum = WNNC_ENUM_CONTEXT; 1080 for (; enumerator->providerIndex < providerTable->numProviders && 1081 !(providerTable->table[enumerator->providerIndex].dwEnumScopes 1082 & dwEnum); enumerator->providerIndex++) 1083 ; 1084 } 1085 return enumerator->providerIndex < providerTable->numProviders ? 1086 WN_SUCCESS : WN_NO_MORE_ENTRIES; 1087 } 1088 1089 /* "Passes through" call to the next provider that supports the enumeration 1090 * type. 1091 * FIXME: if one call to a provider's enumerator succeeds while there's still 1092 * space in lpBuffer, I don't call to the next provider. The caller may not 1093 * expect that it should call EnumResourceW again with a return value of 1094 * WN_SUCCESS (depending what *lpcCount was to begin with). That means strings 1095 * may have to be moved around a bit, ick. 1096 */ 1097 static DWORD _enumerateGlobalPassthroughW(PWNetEnumerator enumerator, 1098 LPDWORD lpcCount, LPVOID lpBuffer, LPDWORD lpBufferSize) 1099 { 1100 DWORD ret; 1101 1102 if (!enumerator) 1103 return WN_BAD_POINTER; 1104 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL) 1105 return WN_BAD_VALUE; 1106 if (!lpcCount) 1107 return WN_BAD_POINTER; 1108 if (!lpBuffer) 1109 return WN_BAD_POINTER; 1110 if (!lpBufferSize) 1111 return WN_BAD_POINTER; 1112 if (*lpBufferSize < sizeof(NETRESOURCEW)) 1113 return WN_MORE_DATA; 1114 1115 ret = _globalEnumeratorAdvance(enumerator); 1116 if (ret == WN_SUCCESS) 1117 { 1118 ret = providerTable->table[enumerator->providerIndex]. 1119 openEnum(enumerator->dwScope, enumerator->dwType, 1120 enumerator->dwUsage, enumerator->specific.net, 1121 &enumerator->handle); 1122 if (ret == WN_SUCCESS) 1123 { 1124 ret = providerTable->table[enumerator->providerIndex]. 1125 enumResource(enumerator->handle, lpcCount, lpBuffer, 1126 lpBufferSize); 1127 if (ret != WN_MORE_DATA) 1128 enumerator->providerDone = TRUE; 1129 } 1130 } 1131 TRACE("Returning %d\n", ret); 1132 return ret; 1133 } 1134 1135 static DWORD _enumerateGlobalW(PWNetEnumerator enumerator, LPDWORD lpcCount, 1136 LPVOID lpBuffer, LPDWORD lpBufferSize) 1137 { 1138 DWORD ret; 1139 1140 if (!enumerator) 1141 return WN_BAD_POINTER; 1142 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL) 1143 return WN_BAD_VALUE; 1144 if (!lpcCount) 1145 return WN_BAD_POINTER; 1146 if (!lpBuffer) 1147 return WN_BAD_POINTER; 1148 if (!lpBufferSize) 1149 return WN_BAD_POINTER; 1150 if (*lpBufferSize < sizeof(NETRESOURCEW)) 1151 return WN_MORE_DATA; 1152 if (!providerTable) 1153 return WN_NO_NETWORK; 1154 1155 switch (enumerator->dwScope) 1156 { 1157 case RESOURCE_GLOBALNET: 1158 if (enumerator->specific.net) 1159 ret = _enumerateGlobalPassthroughW(enumerator, lpcCount, 1160 lpBuffer, lpBufferSize); 1161 else 1162 ret = _enumerateProvidersW(enumerator, lpcCount, lpBuffer, 1163 lpBufferSize); 1164 break; 1165 case RESOURCE_CONTEXT: 1166 ret = _enumerateGlobalPassthroughW(enumerator, lpcCount, lpBuffer, 1167 lpBufferSize); 1168 break; 1169 default: 1170 WARN("unexpected scope 0x%08x\n", enumerator->dwScope); 1171 ret = WN_NO_MORE_ENTRIES; 1172 } 1173 TRACE("Returning %d\n", ret); 1174 return ret; 1175 } 1176 1177 static DWORD _enumerateProviderW(PWNetEnumerator enumerator, LPDWORD lpcCount, 1178 LPVOID lpBuffer, LPDWORD lpBufferSize) 1179 { 1180 if (!enumerator) 1181 return WN_BAD_POINTER; 1182 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_PROVIDER) 1183 return WN_BAD_VALUE; 1184 if (!enumerator->handle) 1185 return WN_BAD_VALUE; 1186 if (!lpcCount) 1187 return WN_BAD_POINTER; 1188 if (!lpBuffer) 1189 return WN_BAD_POINTER; 1190 if (!lpBufferSize) 1191 return WN_BAD_POINTER; 1192 if (!providerTable) 1193 return WN_NO_NETWORK; 1194 if (enumerator->providerIndex >= providerTable->numProviders) 1195 return WN_NO_MORE_ENTRIES; 1196 if (!providerTable->table[enumerator->providerIndex].enumResource) 1197 return WN_BAD_VALUE; 1198 return providerTable->table[enumerator->providerIndex].enumResource( 1199 enumerator->handle, lpcCount, lpBuffer, lpBufferSize); 1200 } 1201 1202 static DWORD _enumerateContextW(PWNetEnumerator enumerator, LPDWORD lpcCount, 1203 LPVOID lpBuffer, LPDWORD lpBufferSize) 1204 { 1205 DWORD ret; 1206 size_t cchEntireNetworkLen, bytesNeeded; 1207 1208 if (!enumerator) 1209 return WN_BAD_POINTER; 1210 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_CONTEXT) 1211 return WN_BAD_VALUE; 1212 if (!lpcCount) 1213 return WN_BAD_POINTER; 1214 if (!lpBuffer) 1215 return WN_BAD_POINTER; 1216 if (!lpBufferSize) 1217 return WN_BAD_POINTER; 1218 if (!providerTable) 1219 return WN_NO_NETWORK; 1220 1221 cchEntireNetworkLen = strlenW(providerTable->entireNetwork) + 1; 1222 bytesNeeded = sizeof(NETRESOURCEW) + cchEntireNetworkLen * sizeof(WCHAR); 1223 if (*lpBufferSize < bytesNeeded) 1224 { 1225 *lpBufferSize = bytesNeeded; 1226 ret = WN_MORE_DATA; 1227 } 1228 else 1229 { 1230 LPNETRESOURCEW lpNet = lpBuffer; 1231 1232 lpNet->dwScope = RESOURCE_GLOBALNET; 1233 lpNet->dwType = enumerator->dwType; 1234 lpNet->dwDisplayType = RESOURCEDISPLAYTYPE_ROOT; 1235 lpNet->dwUsage = RESOURCEUSAGE_CONTAINER; 1236 lpNet->lpLocalName = NULL; 1237 lpNet->lpRemoteName = NULL; 1238 lpNet->lpProvider = NULL; 1239 /* odd, but correct: put comment at end of buffer, so it won't get 1240 * overwritten by subsequent calls to a provider's enumResource 1241 */ 1242 lpNet->lpComment = (LPWSTR)((LPBYTE)lpBuffer + *lpBufferSize - 1243 (cchEntireNetworkLen * sizeof(WCHAR))); 1244 strcpyW(lpNet->lpComment, providerTable->entireNetwork); 1245 ret = WN_SUCCESS; 1246 } 1247 if (ret == WN_SUCCESS) 1248 { 1249 DWORD bufferSize = *lpBufferSize - bytesNeeded; 1250 1251 /* "Entire Network" entry enumerated--morph this into a global 1252 * enumerator. enumerator->lpNet continues to be NULL, since it has 1253 * no meaning when the scope isn't RESOURCE_GLOBALNET. 1254 */ 1255 enumerator->enumType = WNET_ENUMERATOR_TYPE_GLOBAL; 1256 ret = _enumerateGlobalW(enumerator, lpcCount, 1257 (LPBYTE)lpBuffer + bytesNeeded, &bufferSize); 1258 if (ret == WN_SUCCESS) 1259 { 1260 /* reflect the fact that we already enumerated "Entire Network" */ 1261 (*lpcCount)++; 1262 *lpBufferSize = bufferSize + bytesNeeded; 1263 } 1264 else 1265 { 1266 /* the provider enumeration failed, but we already succeeded in 1267 * enumerating "Entire Network"--leave type as global to allow a 1268 * retry, but indicate success with a count of one. 1269 */ 1270 ret = WN_SUCCESS; 1271 *lpcCount = 1; 1272 *lpBufferSize = bytesNeeded; 1273 } 1274 } 1275 TRACE("Returning %d\n", ret); 1276 return ret; 1277 } 1278 1279 static DWORD _copyStringToEnumW(const WCHAR *source, DWORD* left, void** end) 1280 { 1281 DWORD len; 1282 WCHAR* local = *end; 1283 1284 len = strlenW(source) + 1; 1285 len *= sizeof(WCHAR); 1286 if (*left < len) 1287 return WN_MORE_DATA; 1288 1289 local -= (len / sizeof(WCHAR)); 1290 memcpy(local, source, len); 1291 *left -= len; 1292 *end = local; 1293 1294 return WN_SUCCESS; 1295 } 1296 1297 static DWORD _enumerateConnectedW(PWNetEnumerator enumerator, DWORD* user_count, 1298 void* user_buffer, DWORD* user_size) 1299 { 1300 DWORD ret, index, count, total_count, size, i, left; 1301 void* end; 1302 NETRESOURCEW* curr, * buffer; 1303 HANDLE* handles; 1304 1305 if (!enumerator) 1306 return WN_BAD_POINTER; 1307 if (enumerator->enumType != WNET_ENUMERATOR_TYPE_CONNECTED) 1308 return WN_BAD_VALUE; 1309 if (!user_count || !user_buffer || !user_size) 1310 return WN_BAD_POINTER; 1311 if (!providerTable) 1312 return WN_NO_NETWORK; 1313 1314 handles = enumerator->specific.handles; 1315 left = *user_size; 1316 size = *user_size; 1317 buffer = HeapAlloc(GetProcessHeap(), 0, *user_size); 1318 if (!buffer) 1319 return WN_NO_NETWORK; 1320 1321 curr = user_buffer; 1322 end = (char *)user_buffer + size; 1323 count = *user_count; 1324 total_count = 0; 1325 1326 ret = WN_NO_MORE_ENTRIES; 1327 for (index = 0; index < providerTable->numProviders; index++) 1328 { 1329 if (providerTable->table[index].dwEnumScopes) 1330 { 1331 if (handles[index] == 0) 1332 { 1333 ret = providerTable->table[index].openEnum(enumerator->dwScope, 1334 enumerator->dwType, 1335 enumerator->dwUsage, 1336 NULL, &handles[index]); 1337 if (ret != WN_SUCCESS) 1338 continue; 1339 } 1340 1341 ret = providerTable->table[index].enumResource(handles[index], 1342 &count, buffer, 1343 &size); 1344 total_count += count; 1345 if (ret == WN_MORE_DATA) 1346 break; 1347 1348 if (ret == WN_SUCCESS) 1349 { 1350 for (i = 0; i < count; ++i) 1351 { 1352 if (left < sizeof(NETRESOURCEW)) 1353 { 1354 ret = WN_MORE_DATA; 1355 break; 1356 } 1357 1358 memcpy(curr, &buffer[i], sizeof(NETRESOURCEW)); 1359 left -= sizeof(NETRESOURCEW); 1360 1361 ret = _copyStringToEnumW(buffer[i].lpLocalName, &left, &end); 1362 if (ret == WN_MORE_DATA) 1363 break; 1364 curr->lpLocalName = end; 1365 1366 ret = _copyStringToEnumW(buffer[i].lpRemoteName, &left, &end); 1367 if (ret == WN_MORE_DATA) 1368 break; 1369 curr->lpRemoteName = end; 1370 1371 ret = _copyStringToEnumW(buffer[i].lpProvider, &left, &end); 1372 if (ret == WN_MORE_DATA) 1373 break; 1374 curr->lpProvider = end; 1375 1376 ++curr; 1377 } 1378 1379 size = left; 1380 } 1381 1382 if (*user_count != -1) 1383 count = *user_count - total_count; 1384 else 1385 count = *user_count; 1386 } 1387 } 1388 1389 if (total_count == 0) 1390 ret = WN_NO_MORE_ENTRIES; 1391 1392 *user_count = total_count; 1393 if (ret != WN_MORE_DATA && ret != WN_NO_MORE_ENTRIES) 1394 ret = WN_SUCCESS; 1395 1396 HeapFree(GetProcessHeap(), 0, buffer); 1397 1398 TRACE("Returning %d\n", ret); 1399 return ret; 1400 } 1401 1402 static const WCHAR connectionType[] = { 'C','o','n','n','e','c','t','i','o','n','T','y','p','e',0 }; 1403 static const WCHAR providerName[] = { 'P','r','o','v','i','d','e','r','N','a','m','e',0 }; 1404 static const WCHAR remotePath[] = { 'R','e','m','o','t','e','P','a','t','h',0 }; 1405 1406 static WCHAR *get_reg_str(HKEY hkey, const WCHAR *value, DWORD *len) 1407 { 1408 DWORD type; 1409 WCHAR *ret = NULL; 1410 1411 if (!RegQueryValueExW(hkey, value, NULL, &type, NULL, len) && type == REG_SZ) 1412 { 1413 if (!(ret = HeapAlloc(GetProcessHeap(), 0, *len))) return NULL; 1414 RegQueryValueExW(hkey, value, 0, 0, (BYTE *)ret, len); 1415 } 1416 1417 return ret; 1418 } 1419 1420 static DWORD _enumeratorRememberedW(PWNetEnumerator enumerator, DWORD* user_count, 1421 void* user_buffer, DWORD* user_size) 1422 { 1423 HKEY registry, connection; 1424 WCHAR buffer[255]; 1425 LONG size_left; 1426 DWORD index, ret, type, len, size, registry_size, full_size = 0, total_count; 1427 NETRESOURCEW * net_buffer = user_buffer; 1428 WCHAR * str, * registry_string; 1429 1430 /* we will do the work in a single loop, so here is some things: 1431 * we write netresource at the begin of the user buffer 1432 * we write strings at the end of the user buffer 1433 */ 1434 size_left = *user_size; 1435 total_count = 0; 1436 type = enumerator->dwType; 1437 registry = enumerator->specific.remembered.registry; 1438 str = (WCHAR *)((ULONG_PTR)user_buffer + *user_size - sizeof(WCHAR)); 1439 for (index = enumerator->specific.remembered.index; ; ++index) 1440 { 1441 enumerator->specific.remembered.index = index; 1442 1443 if (*user_count != -1 && total_count == *user_count) 1444 { 1445 ret = WN_SUCCESS; 1446 break; 1447 } 1448 1449 len = ARRAY_SIZE(buffer); 1450 ret = RegEnumKeyExW(registry, index, buffer, &len, NULL, NULL, NULL, NULL); 1451 if (ret != ERROR_SUCCESS) 1452 { 1453 if (ret == ERROR_NO_MORE_ITEMS) ret = WN_SUCCESS; 1454 break; 1455 } 1456 1457 if (RegOpenKeyExW(registry, buffer, 0, KEY_READ, &connection) != ERROR_SUCCESS) 1458 { 1459 continue; 1460 } 1461 1462 full_size = sizeof(NETRESOURCEW); 1463 size_left -= sizeof(NETRESOURCEW); 1464 1465 if (size_left > 0) 1466 { 1467 size = sizeof(DWORD); 1468 RegQueryValueExW(connection, connectionType, NULL, NULL, (BYTE *)&net_buffer->dwType, &size); 1469 if (type != RESOURCETYPE_ANY && net_buffer->dwType != type) 1470 { 1471 size_left += sizeof(NETRESOURCEW); 1472 RegCloseKey(connection); 1473 continue; 1474 } 1475 1476 net_buffer->dwScope = RESOURCE_REMEMBERED; 1477 net_buffer->dwDisplayType = RESOURCEDISPLAYTYPE_GENERIC; 1478 net_buffer->dwUsage = RESOURCEUSAGE_CONNECTABLE; 1479 } 1480 else 1481 ret = WN_MORE_DATA; 1482 1483 /* FIXME: this only supports drive letters */ 1484 full_size += 3 * sizeof(WCHAR); 1485 size_left -= 3 * sizeof(WCHAR); 1486 if (size_left > 0) 1487 { 1488 str -= 3; 1489 str[0] = buffer[0]; 1490 str[1] = ':'; 1491 str[2] = 0; 1492 net_buffer->lpLocalName = str; 1493 } 1494 1495 registry_size = 0; 1496 registry_string = get_reg_str(connection, providerName, ®istry_size); 1497 if (registry_string) 1498 { 1499 full_size += registry_size; 1500 size_left -= registry_size; 1501 1502 if (size_left > 0) 1503 { 1504 str -= (registry_size / sizeof(WCHAR)); 1505 lstrcpyW(str, registry_string); 1506 net_buffer->lpProvider = str; 1507 } 1508 else 1509 ret = WN_MORE_DATA; 1510 1511 HeapFree(GetProcessHeap(), 0, registry_string); 1512 } 1513 1514 registry_size = 0; 1515 registry_string = get_reg_str(connection, remotePath, ®istry_size); 1516 if (registry_string) 1517 { 1518 full_size += registry_size; 1519 size_left -= registry_size; 1520 1521 if (size_left > 0) 1522 { 1523 str -= (registry_size / sizeof(WCHAR)); 1524 lstrcpyW(str, registry_string); 1525 net_buffer->lpRemoteName = str; 1526 } 1527 else 1528 ret = WN_MORE_DATA; 1529 1530 HeapFree(GetProcessHeap(), 0, registry_string); 1531 } 1532 1533 RegCloseKey(connection); 1534 1535 net_buffer->lpComment = NULL; 1536 1537 if (size_left < 0) 1538 break; 1539 1540 ++total_count; 1541 ++net_buffer; 1542 } 1543 1544 if (total_count == 0) 1545 ret = WN_NO_MORE_ENTRIES; 1546 1547 *user_count = total_count; 1548 1549 if (ret != WN_MORE_DATA && ret != WN_NO_MORE_ENTRIES) 1550 ret = WN_SUCCESS; 1551 1552 if (ret == WN_MORE_DATA) 1553 *user_size = *user_size + full_size; 1554 1555 return ret; 1556 } 1557 1558 /********************************************************************* 1559 * WNetEnumResourceW [MPR.@] 1560 */ 1561 DWORD WINAPI WNetEnumResourceW( HANDLE hEnum, LPDWORD lpcCount, 1562 LPVOID lpBuffer, LPDWORD lpBufferSize ) 1563 { 1564 DWORD ret; 1565 1566 TRACE( "(%p, %p, %p, %p)\n", hEnum, lpcCount, lpBuffer, lpBufferSize ); 1567 1568 if (!hEnum) 1569 ret = WN_BAD_POINTER; 1570 else if (!lpcCount) 1571 ret = WN_BAD_POINTER; 1572 else if (!lpBuffer) 1573 ret = WN_BAD_POINTER; 1574 else if (!lpBufferSize) 1575 ret = WN_BAD_POINTER; 1576 else if (*lpBufferSize < sizeof(NETRESOURCEW)) 1577 { 1578 *lpBufferSize = sizeof(NETRESOURCEW); 1579 ret = WN_MORE_DATA; 1580 } 1581 else 1582 { 1583 PWNetEnumerator enumerator = (PWNetEnumerator)hEnum; 1584 1585 switch (enumerator->enumType) 1586 { 1587 case WNET_ENUMERATOR_TYPE_GLOBAL: 1588 ret = _enumerateGlobalW(enumerator, lpcCount, lpBuffer, 1589 lpBufferSize); 1590 break; 1591 case WNET_ENUMERATOR_TYPE_PROVIDER: 1592 ret = _enumerateProviderW(enumerator, lpcCount, lpBuffer, 1593 lpBufferSize); 1594 break; 1595 case WNET_ENUMERATOR_TYPE_CONTEXT: 1596 ret = _enumerateContextW(enumerator, lpcCount, lpBuffer, 1597 lpBufferSize); 1598 break; 1599 case WNET_ENUMERATOR_TYPE_CONNECTED: 1600 ret = _enumerateConnectedW(enumerator, lpcCount, lpBuffer, 1601 lpBufferSize); 1602 break; 1603 case WNET_ENUMERATOR_TYPE_REMEMBERED: 1604 ret = _enumeratorRememberedW(enumerator, lpcCount, lpBuffer, 1605 lpBufferSize); 1606 break; 1607 default: 1608 WARN("bogus enumerator type!\n"); 1609 ret = WN_NO_NETWORK; 1610 } 1611 } 1612 if (ret) 1613 SetLastError(ret); 1614 TRACE("Returning %d\n", ret); 1615 return ret; 1616 } 1617 1618 /********************************************************************* 1619 * WNetCloseEnum [MPR.@] 1620 */ 1621 DWORD WINAPI WNetCloseEnum( HANDLE hEnum ) 1622 { 1623 DWORD ret, index; 1624 HANDLE *handles; 1625 1626 TRACE( "(%p)\n", hEnum ); 1627 1628 if (hEnum) 1629 { 1630 PWNetEnumerator enumerator = (PWNetEnumerator)hEnum; 1631 1632 switch (enumerator->enumType) 1633 { 1634 case WNET_ENUMERATOR_TYPE_GLOBAL: 1635 if (enumerator->specific.net) 1636 _freeEnumNetResource(enumerator->specific.net); 1637 if (enumerator->handle) 1638 providerTable->table[enumerator->providerIndex]. 1639 closeEnum(enumerator->handle); 1640 ret = WN_SUCCESS; 1641 break; 1642 case WNET_ENUMERATOR_TYPE_PROVIDER: 1643 if (enumerator->handle) 1644 providerTable->table[enumerator->providerIndex]. 1645 closeEnum(enumerator->handle); 1646 ret = WN_SUCCESS; 1647 break; 1648 case WNET_ENUMERATOR_TYPE_CONNECTED: 1649 handles = enumerator->specific.handles; 1650 for (index = 0; index < providerTable->numProviders; index++) 1651 { 1652 if (providerTable->table[index].dwEnumScopes && handles[index]) 1653 providerTable->table[index].closeEnum(handles[index]); 1654 } 1655 HeapFree(GetProcessHeap(), 0, handles); 1656 ret = WN_SUCCESS; 1657 break; 1658 case WNET_ENUMERATOR_TYPE_REMEMBERED: 1659 RegCloseKey(enumerator->specific.remembered.registry); 1660 ret = WN_SUCCESS; 1661 break; 1662 default: 1663 WARN("bogus enumerator type!\n"); 1664 ret = WN_BAD_HANDLE; 1665 } 1666 HeapFree(GetProcessHeap(), 0, hEnum); 1667 } 1668 else 1669 ret = WN_BAD_HANDLE; 1670 if (ret) 1671 SetLastError(ret); 1672 TRACE("Returning %d\n", ret); 1673 return ret; 1674 } 1675 1676 /********************************************************************* 1677 * WNetGetResourceInformationA [MPR.@] 1678 * 1679 * See WNetGetResourceInformationW 1680 */ 1681 DWORD WINAPI WNetGetResourceInformationA( LPNETRESOURCEA lpNetResource, 1682 LPVOID lpBuffer, LPDWORD cbBuffer, 1683 LPSTR *lplpSystem ) 1684 { 1685 DWORD ret; 1686 1687 TRACE( "(%p, %p, %p, %p)\n", 1688 lpNetResource, lpBuffer, cbBuffer, lplpSystem ); 1689 1690 if (!providerTable || providerTable->numProviders == 0) 1691 ret = WN_NO_NETWORK; 1692 else if (lpNetResource) 1693 { 1694 LPNETRESOURCEW lpNetResourceW = NULL; 1695 DWORD size = 1024, count = 1; 1696 DWORD len; 1697 1698 lpNetResourceW = HeapAlloc(GetProcessHeap(), 0, size); 1699 ret = _thunkNetResourceArrayAToW(lpNetResource, &count, lpNetResourceW, &size); 1700 if (ret == WN_MORE_DATA) 1701 { 1702 HeapFree(GetProcessHeap(), 0, lpNetResourceW); 1703 lpNetResourceW = HeapAlloc(GetProcessHeap(), 0, size); 1704 if (lpNetResourceW) 1705 ret = _thunkNetResourceArrayAToW(lpNetResource, 1706 &count, lpNetResourceW, &size); 1707 else 1708 ret = WN_OUT_OF_MEMORY; 1709 } 1710 if (ret == WN_SUCCESS) 1711 { 1712 LPWSTR lpSystemW = NULL; 1713 LPVOID lpBufferW; 1714 size = 1024; 1715 lpBufferW = HeapAlloc(GetProcessHeap(), 0, size); 1716 if (lpBufferW) 1717 { 1718 ret = WNetGetResourceInformationW(lpNetResourceW, 1719 lpBufferW, &size, &lpSystemW); 1720 if (ret == WN_MORE_DATA) 1721 { 1722 HeapFree(GetProcessHeap(), 0, lpBufferW); 1723 lpBufferW = HeapAlloc(GetProcessHeap(), 0, size); 1724 if (lpBufferW) 1725 ret = WNetGetResourceInformationW(lpNetResourceW, 1726 lpBufferW, &size, &lpSystemW); 1727 else 1728 ret = WN_OUT_OF_MEMORY; 1729 } 1730 if (ret == WN_SUCCESS) 1731 { 1732 ret = _thunkNetResourceArrayWToA(lpBufferW, 1733 &count, lpBuffer, cbBuffer); 1734 HeapFree(GetProcessHeap(), 0, lpNetResourceW); 1735 lpNetResourceW = lpBufferW; 1736 size = sizeof(NETRESOURCEA); 1737 size += WideCharToMultiByte(CP_ACP, 0, lpNetResourceW->lpRemoteName, 1738 -1, NULL, 0, NULL, NULL); 1739 size += WideCharToMultiByte(CP_ACP, 0, lpNetResourceW->lpProvider, 1740 -1, NULL, 0, NULL, NULL); 1741 1742 len = WideCharToMultiByte(CP_ACP, 0, lpSystemW, 1743 -1, NULL, 0, NULL, NULL); 1744 if ((len) && ( size + len < *cbBuffer)) 1745 { 1746 *lplpSystem = (char*)lpBuffer + *cbBuffer - len; 1747 WideCharToMultiByte(CP_ACP, 0, lpSystemW, -1, 1748 *lplpSystem, len, NULL, NULL); 1749 ret = WN_SUCCESS; 1750 } 1751 else 1752 ret = WN_MORE_DATA; 1753 } 1754 else 1755 ret = WN_OUT_OF_MEMORY; 1756 HeapFree(GetProcessHeap(), 0, lpBufferW); 1757 } 1758 else 1759 ret = WN_OUT_OF_MEMORY; 1760 HeapFree(GetProcessHeap(), 0, lpSystemW); 1761 } 1762 HeapFree(GetProcessHeap(), 0, lpNetResourceW); 1763 } 1764 else 1765 ret = WN_NO_NETWORK; 1766 1767 if (ret) 1768 SetLastError(ret); 1769 TRACE("Returning %d\n", ret); 1770 return ret; 1771 } 1772 1773 /********************************************************************* 1774 * WNetGetResourceInformationW [MPR.@] 1775 * 1776 * WNetGetResourceInformationW function identifies the network provider 1777 * that owns the resource and gets information about the type of the resource. 1778 * 1779 * PARAMS: 1780 * lpNetResource [ I] the pointer to NETRESOURCEW structure, that 1781 * defines a network resource. 1782 * lpBuffer [ O] the pointer to buffer, containing result. It 1783 * contains NETRESOURCEW structure and strings to 1784 * which the members of the NETRESOURCEW structure 1785 * point. 1786 * cbBuffer [I/O] the pointer to DWORD number - size of buffer 1787 * in bytes. 1788 * lplpSystem [ O] the pointer to string in the output buffer, 1789 * containing the part of the resource name without 1790 * names of the server and share. 1791 * 1792 * RETURNS: 1793 * NO_ERROR if the function succeeds. System error code if the function fails. 1794 */ 1795 1796 DWORD WINAPI WNetGetResourceInformationW( LPNETRESOURCEW lpNetResource, 1797 LPVOID lpBuffer, LPDWORD cbBuffer, 1798 LPWSTR *lplpSystem ) 1799 { 1800 DWORD ret = WN_NO_NETWORK; 1801 DWORD index; 1802 1803 TRACE( "(%p, %p, %p, %p)\n", 1804 lpNetResource, lpBuffer, cbBuffer, lplpSystem); 1805 1806 if (!(lpBuffer)) 1807 ret = WN_OUT_OF_MEMORY; 1808 else if (providerTable != NULL) 1809 { 1810 /* FIXME: For function value of a variable is indifferent, it does 1811 * search of all providers in a network. 1812 */ 1813 for (index = 0; index < providerTable->numProviders; index++) 1814 { 1815 if(providerTable->table[index].getCaps(WNNC_DIALOG) & 1816 WNNC_DLG_GETRESOURCEINFORMATION) 1817 { 1818 if (providerTable->table[index].getResourceInformation) 1819 ret = providerTable->table[index].getResourceInformation( 1820 lpNetResource, lpBuffer, cbBuffer, lplpSystem); 1821 else 1822 ret = WN_NO_NETWORK; 1823 if (ret == WN_SUCCESS) 1824 break; 1825 } 1826 } 1827 } 1828 if (ret) 1829 SetLastError(ret); 1830 return ret; 1831 } 1832 1833 /********************************************************************* 1834 * WNetGetResourceParentA [MPR.@] 1835 */ 1836 DWORD WINAPI WNetGetResourceParentA( LPNETRESOURCEA lpNetResource, 1837 LPVOID lpBuffer, LPDWORD lpBufferSize ) 1838 { 1839 FIXME( "(%p, %p, %p): stub\n", 1840 lpNetResource, lpBuffer, lpBufferSize ); 1841 1842 SetLastError(WN_NO_NETWORK); 1843 return WN_NO_NETWORK; 1844 } 1845 1846 /********************************************************************* 1847 * WNetGetResourceParentW [MPR.@] 1848 */ 1849 DWORD WINAPI WNetGetResourceParentW( LPNETRESOURCEW lpNetResource, 1850 LPVOID lpBuffer, LPDWORD lpBufferSize ) 1851 { 1852 FIXME( "(%p, %p, %p): stub\n", 1853 lpNetResource, lpBuffer, lpBufferSize ); 1854 1855 SetLastError(WN_NO_NETWORK); 1856 return WN_NO_NETWORK; 1857 } 1858 1859 1860 1861 /* 1862 * Connection Functions 1863 */ 1864 1865 /********************************************************************* 1866 * WNetAddConnectionA [MPR.@] 1867 */ 1868 DWORD WINAPI WNetAddConnectionA( LPCSTR lpRemoteName, LPCSTR lpPassword, 1869 LPCSTR lpLocalName ) 1870 { 1871 NETRESOURCEA resourcesA; 1872 1873 memset(&resourcesA, 0, sizeof(resourcesA)); 1874 resourcesA.lpRemoteName = (LPSTR)lpRemoteName; 1875 resourcesA.lpLocalName = (LPSTR)lpLocalName; 1876 return WNetUseConnectionA(NULL, &resourcesA, lpPassword, NULL, 0, NULL, 0, NULL); 1877 } 1878 1879 /********************************************************************* 1880 * WNetAddConnectionW [MPR.@] 1881 */ 1882 DWORD WINAPI WNetAddConnectionW( LPCWSTR lpRemoteName, LPCWSTR lpPassword, 1883 LPCWSTR lpLocalName ) 1884 { 1885 NETRESOURCEW resourcesW; 1886 1887 memset(&resourcesW, 0, sizeof(resourcesW)); 1888 resourcesW.lpRemoteName = (LPWSTR)lpRemoteName; 1889 resourcesW.lpLocalName = (LPWSTR)lpLocalName; 1890 return WNetUseConnectionW(NULL, &resourcesW, lpPassword, NULL, 0, NULL, 0, NULL); 1891 } 1892 1893 /********************************************************************* 1894 * WNetAddConnection2A [MPR.@] 1895 */ 1896 DWORD WINAPI WNetAddConnection2A( LPNETRESOURCEA lpNetResource, 1897 LPCSTR lpPassword, LPCSTR lpUserID, 1898 DWORD dwFlags ) 1899 { 1900 return WNetUseConnectionA(NULL, lpNetResource, lpPassword, lpUserID, dwFlags, 1901 NULL, 0, NULL); 1902 } 1903 1904 /********************************************************************* 1905 * WNetAddConnection2W [MPR.@] 1906 */ 1907 DWORD WINAPI WNetAddConnection2W( LPNETRESOURCEW lpNetResource, 1908 LPCWSTR lpPassword, LPCWSTR lpUserID, 1909 DWORD dwFlags ) 1910 { 1911 return WNetUseConnectionW(NULL, lpNetResource, lpPassword, lpUserID, dwFlags, 1912 NULL, 0, NULL); 1913 } 1914 1915 /********************************************************************* 1916 * WNetAddConnection3A [MPR.@] 1917 */ 1918 DWORD WINAPI WNetAddConnection3A( HWND hwndOwner, LPNETRESOURCEA lpNetResource, 1919 LPCSTR lpPassword, LPCSTR lpUserID, 1920 DWORD dwFlags ) 1921 { 1922 return WNetUseConnectionA(hwndOwner, lpNetResource, lpPassword, lpUserID, 1923 dwFlags, NULL, 0, NULL); 1924 } 1925 1926 /********************************************************************* 1927 * WNetAddConnection3W [MPR.@] 1928 */ 1929 DWORD WINAPI WNetAddConnection3W( HWND hwndOwner, LPNETRESOURCEW lpNetResource, 1930 LPCWSTR lpPassword, LPCWSTR lpUserID, 1931 DWORD dwFlags ) 1932 { 1933 return WNetUseConnectionW(hwndOwner, lpNetResource, lpPassword, lpUserID, 1934 dwFlags, NULL, 0, NULL); 1935 } 1936 1937 struct use_connection_context 1938 { 1939 HWND hwndOwner; 1940 NETRESOURCEW *resource; 1941 NETRESOURCEA *resourceA; /* only set for WNetUseConnectionA */ 1942 WCHAR *password; 1943 WCHAR *userid; 1944 DWORD flags; 1945 void *accessname; 1946 DWORD *buffer_size; 1947 DWORD *result; 1948 DWORD (*pre_set_accessname)(struct use_connection_context*, WCHAR *); 1949 void (*set_accessname)(struct use_connection_context*, WCHAR *); 1950 }; 1951 1952 static DWORD use_connection_pre_set_accessnameW(struct use_connection_context *ctxt, WCHAR *local_name) 1953 { 1954 if (ctxt->accessname && ctxt->buffer_size && *ctxt->buffer_size) 1955 { 1956 DWORD len; 1957 1958 if (local_name) 1959 len = strlenW(local_name); 1960 else 1961 len = strlenW(ctxt->resource->lpRemoteName); 1962 1963 if (++len > *ctxt->buffer_size) 1964 { 1965 *ctxt->buffer_size = len; 1966 return ERROR_MORE_DATA; 1967 } 1968 } 1969 else 1970 ctxt->accessname = NULL; 1971 1972 return ERROR_SUCCESS; 1973 } 1974 1975 static void use_connection_set_accessnameW(struct use_connection_context *ctxt, WCHAR *local_name) 1976 { 1977 WCHAR *accessname = ctxt->accessname; 1978 if (local_name) 1979 { 1980 strcpyW(accessname, local_name); 1981 if (ctxt->result) 1982 *ctxt->result = CONNECT_LOCALDRIVE; 1983 } 1984 else 1985 strcpyW(accessname, ctxt->resource->lpRemoteName); 1986 } 1987 1988 static DWORD wnet_use_provider( struct use_connection_context *ctxt, NETRESOURCEW * netres, WNetProvider *provider, BOOLEAN redirect ) 1989 { 1990 DWORD caps, ret; 1991 1992 caps = provider->getCaps(WNNC_CONNECTION); 1993 if (!(caps & (WNNC_CON_ADDCONNECTION | WNNC_CON_ADDCONNECTION3))) 1994 return ERROR_BAD_PROVIDER; 1995 1996 ret = WN_ACCESS_DENIED; 1997 do 1998 { 1999 if ((caps & WNNC_CON_ADDCONNECTION3) && provider->addConnection3) 2000 ret = provider->addConnection3(ctxt->hwndOwner, netres, ctxt->password, ctxt->userid, ctxt->flags); 2001 else if ((caps & WNNC_CON_ADDCONNECTION) && provider->addConnection) 2002 ret = provider->addConnection(netres, ctxt->password, ctxt->userid); 2003 2004 if (ret == WN_ALREADY_CONNECTED && redirect) 2005 netres->lpLocalName[0] -= 1; 2006 } while (redirect && ret == WN_ALREADY_CONNECTED && netres->lpLocalName[0] >= 'C'); 2007 2008 if (ret == WN_SUCCESS && ctxt->accessname) 2009 ctxt->set_accessname(ctxt, netres->lpLocalName); 2010 2011 return ret; 2012 } 2013 2014 static const WCHAR providerType[] = { 'P','r','o','v','i','d','e','r','T','y','p','e',0 }; 2015 static const WCHAR userName[] = { 'U','s','e','r','N','a','m','e',0 }; 2016 2017 static DWORD wnet_use_connection( struct use_connection_context *ctxt ) 2018 { 2019 WNetProvider *provider; 2020 DWORD index, ret = WN_NO_NETWORK; 2021 BOOL redirect = FALSE; 2022 WCHAR letter[3] = {'Z', ':', 0}; 2023 NETRESOURCEW netres; 2024 2025 if (!providerTable || providerTable->numProviders == 0) 2026 return WN_NO_NETWORK; 2027 2028 if (!ctxt->resource) 2029 return ERROR_INVALID_PARAMETER; 2030 netres = *ctxt->resource; 2031 2032 if (!netres.lpLocalName && (ctxt->flags & CONNECT_REDIRECT)) 2033 { 2034 if (netres.dwType != RESOURCETYPE_DISK && netres.dwType != RESOURCETYPE_PRINT) 2035 return ERROR_BAD_DEV_TYPE; 2036 2037 if (netres.dwType == RESOURCETYPE_PRINT) 2038 { 2039 FIXME("Local device selection is not implemented for printers.\n"); 2040 return WN_NO_NETWORK; 2041 } 2042 2043 redirect = TRUE; 2044 netres.lpLocalName = letter; 2045 } 2046 2047 if (ctxt->flags & CONNECT_INTERACTIVE) 2048 return ERROR_BAD_NET_NAME; 2049 2050 if ((ret = ctxt->pre_set_accessname(ctxt, netres.lpLocalName))) 2051 return ret; 2052 2053 if (netres.lpProvider) 2054 { 2055 index = _findProviderIndexW(netres.lpProvider); 2056 if (index == BAD_PROVIDER_INDEX) 2057 return ERROR_BAD_PROVIDER; 2058 2059 provider = &providerTable->table[index]; 2060 ret = wnet_use_provider(ctxt, &netres, provider, redirect); 2061 } 2062 else 2063 { 2064 for (index = 0; index < providerTable->numProviders; index++) 2065 { 2066 provider = &providerTable->table[index]; 2067 ret = wnet_use_provider(ctxt, &netres, provider, redirect); 2068 if (ret == WN_SUCCESS || ret == WN_ALREADY_CONNECTED) 2069 break; 2070 } 2071 } 2072 2073 if (ret == WN_SUCCESS && ctxt->flags & CONNECT_UPDATE_PROFILE) 2074 { 2075 HKEY user_profile; 2076 2077 if (netres.dwType == RESOURCETYPE_PRINT) 2078 { 2079 FIXME("Persistent connection are not supported for printers\n"); 2080 return ret; 2081 } 2082 2083 if (RegOpenCurrentUser(KEY_ALL_ACCESS, &user_profile) == ERROR_SUCCESS) 2084 { 2085 HKEY network; 2086 WCHAR subkey[10] = {'N', 'e', 't', 'w', 'o', 'r', 'k', '\\', netres.lpLocalName[0], 0}; 2087 2088 if (RegCreateKeyExW(user_profile, subkey, 0, NULL, REG_OPTION_NON_VOLATILE, 2089 KEY_ALL_ACCESS, NULL, &network, NULL) == ERROR_SUCCESS) 2090 { 2091 DWORD dword_arg = RESOURCETYPE_DISK; 2092 DWORD len = (strlenW(provider->name) + 1) * sizeof(WCHAR); 2093 static const WCHAR empty[1] = {0}; 2094 2095 RegSetValueExW(network, connectionType, 0, REG_DWORD, (const BYTE *)&dword_arg, sizeof(DWORD)); 2096 RegSetValueExW(network, providerName, 0, REG_SZ, (const BYTE *)provider->name, len); 2097 RegSetValueExW(network, providerType, 0, REG_DWORD, (const BYTE *)&provider->dwNetType, sizeof(DWORD)); 2098 len = (strlenW(netres.lpRemoteName) + 1) * sizeof(WCHAR); 2099 RegSetValueExW(network, remotePath, 0, REG_SZ, (const BYTE *)netres.lpRemoteName, len); 2100 len = sizeof(empty); 2101 RegSetValueExW(network, userName, 0, REG_SZ, (const BYTE *)empty, len); 2102 RegCloseKey(network); 2103 } 2104 2105 RegCloseKey(user_profile); 2106 } 2107 } 2108 2109 return ret; 2110 } 2111 2112 /***************************************************************** 2113 * WNetUseConnectionW [MPR.@] 2114 */ 2115 DWORD WINAPI WNetUseConnectionW( HWND hwndOwner, NETRESOURCEW *resource, LPCWSTR password, 2116 LPCWSTR userid, DWORD flags, LPWSTR accessname, DWORD *buffer_size, DWORD *result ) 2117 { 2118 struct use_connection_context ctxt; 2119 2120 TRACE( "(%p, %p, %p, %s, 0x%08X, %p, %p, %p)\n", 2121 hwndOwner, resource, password, debugstr_w(userid), flags, 2122 accessname, buffer_size, result ); 2123 2124 ctxt.hwndOwner = hwndOwner; 2125 ctxt.resource = resource; 2126 ctxt.resourceA = NULL; 2127 ctxt.password = (WCHAR*)password; 2128 ctxt.userid = (WCHAR*)userid; 2129 ctxt.flags = flags; 2130 ctxt.accessname = accessname; 2131 ctxt.buffer_size = buffer_size; 2132 ctxt.result = result; 2133 ctxt.pre_set_accessname = use_connection_pre_set_accessnameW; 2134 ctxt.set_accessname = use_connection_set_accessnameW; 2135 2136 return wnet_use_connection(&ctxt); 2137 } 2138 2139 static DWORD use_connection_pre_set_accessnameA(struct use_connection_context *ctxt, WCHAR *local_name) 2140 { 2141 if (ctxt->accessname && ctxt->buffer_size && *ctxt->buffer_size) 2142 { 2143 DWORD len; 2144 2145 if (local_name) 2146 len = WideCharToMultiByte(CP_ACP, 0, local_name, -1, NULL, 0, NULL, NULL) - 1; 2147 else 2148 len = strlen(ctxt->resourceA->lpRemoteName); 2149 2150 if (++len > *ctxt->buffer_size) 2151 { 2152 *ctxt->buffer_size = len; 2153 return ERROR_MORE_DATA; 2154 } 2155 } 2156 else 2157 ctxt->accessname = NULL; 2158 2159 return ERROR_SUCCESS; 2160 } 2161 2162 static void use_connection_set_accessnameA(struct use_connection_context *ctxt, WCHAR *local_name) 2163 { 2164 char *accessname = ctxt->accessname; 2165 if (local_name) 2166 { 2167 WideCharToMultiByte(CP_ACP, 0, local_name, -1, accessname, *ctxt->buffer_size, NULL, NULL); 2168 if (ctxt->result) 2169 *ctxt->result = CONNECT_LOCALDRIVE; 2170 } 2171 else 2172 strcpy(accessname, ctxt->resourceA->lpRemoteName); 2173 } 2174 2175 static LPWSTR strdupAtoW( LPCSTR str ) 2176 { 2177 LPWSTR ret; 2178 INT len; 2179 2180 if (!str) return NULL; 2181 len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 ); 2182 ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ); 2183 if (ret) MultiByteToWideChar( CP_ACP, 0, str, -1, ret, len ); 2184 return ret; 2185 } 2186 2187 static void netresource_a_to_w( NETRESOURCEA *resourceA, NETRESOURCEW *resourceW ) 2188 { 2189 resourceW->dwScope = resourceA->dwScope; 2190 resourceW->dwType = resourceA->dwType; 2191 resourceW->dwDisplayType = resourceA->dwDisplayType; 2192 resourceW->dwUsage = resourceA->dwUsage; 2193 resourceW->lpLocalName = strdupAtoW(resourceA->lpLocalName); 2194 resourceW->lpRemoteName = strdupAtoW(resourceA->lpRemoteName); 2195 resourceW->lpComment = strdupAtoW(resourceA->lpComment); 2196 resourceW->lpProvider = strdupAtoW(resourceA->lpProvider); 2197 } 2198 2199 static void free_netresourceW( NETRESOURCEW *resource ) 2200 { 2201 HeapFree(GetProcessHeap(), 0, resource->lpLocalName); 2202 HeapFree(GetProcessHeap(), 0, resource->lpRemoteName); 2203 HeapFree(GetProcessHeap(), 0, resource->lpComment); 2204 HeapFree(GetProcessHeap(), 0, resource->lpProvider); 2205 } 2206 2207 /***************************************************************** 2208 * WNetUseConnectionA [MPR.@] 2209 */ 2210 DWORD WINAPI WNetUseConnectionA( HWND hwndOwner, NETRESOURCEA *resource, 2211 LPCSTR password, LPCSTR userid, DWORD flags, LPSTR accessname, 2212 DWORD *buffer_size, DWORD *result ) 2213 { 2214 struct use_connection_context ctxt; 2215 NETRESOURCEW resourceW; 2216 DWORD ret; 2217 2218 TRACE( "(%p, %p, %p, %s, 0x%08X, %p, %p, %p)\n", hwndOwner, resource, password, debugstr_a(userid), flags, 2219 accessname, buffer_size, result ); 2220 2221 netresource_a_to_w(resource, &resourceW); 2222 2223 ctxt.hwndOwner = hwndOwner; 2224 ctxt.resource = &resourceW; 2225 ctxt.resourceA = resource; 2226 ctxt.password = strdupAtoW(password); 2227 ctxt.userid = strdupAtoW(userid); 2228 ctxt.flags = flags; 2229 ctxt.accessname = accessname; 2230 ctxt.buffer_size = buffer_size; 2231 ctxt.result = result; 2232 ctxt.pre_set_accessname = use_connection_pre_set_accessnameA; 2233 ctxt.set_accessname = use_connection_set_accessnameA; 2234 2235 ret = wnet_use_connection(&ctxt); 2236 2237 free_netresourceW(&resourceW); 2238 HeapFree(GetProcessHeap(), 0, ctxt.password); 2239 HeapFree(GetProcessHeap(), 0, ctxt.userid); 2240 2241 return ret; 2242 } 2243 2244 /********************************************************************* 2245 * WNetCancelConnectionA [MPR.@] 2246 */ 2247 DWORD WINAPI WNetCancelConnectionA( LPCSTR lpName, BOOL fForce ) 2248 { 2249 return WNetCancelConnection2A(lpName, 0, fForce); 2250 } 2251 2252 /********************************************************************* 2253 * WNetCancelConnectionW [MPR.@] 2254 */ 2255 DWORD WINAPI WNetCancelConnectionW( LPCWSTR lpName, BOOL fForce ) 2256 { 2257 return WNetCancelConnection2W(lpName, 0, fForce); 2258 } 2259 2260 /********************************************************************* 2261 * WNetCancelConnection2A [MPR.@] 2262 */ 2263 DWORD WINAPI WNetCancelConnection2A( LPCSTR lpName, DWORD dwFlags, BOOL fForce ) 2264 { 2265 DWORD ret; 2266 WCHAR * name = strdupAtoW(lpName); 2267 if (!name) 2268 return ERROR_NOT_CONNECTED; 2269 2270 ret = WNetCancelConnection2W(name, dwFlags, fForce); 2271 HeapFree(GetProcessHeap(), 0, name); 2272 2273 return ret; 2274 } 2275 2276 /********************************************************************* 2277 * WNetCancelConnection2W [MPR.@] 2278 */ 2279 DWORD WINAPI WNetCancelConnection2W( LPCWSTR lpName, DWORD dwFlags, BOOL fForce ) 2280 { 2281 DWORD ret = WN_NO_NETWORK; 2282 DWORD index; 2283 2284 if (providerTable != NULL) 2285 { 2286 for (index = 0; index < providerTable->numProviders; index++) 2287 { 2288 if(providerTable->table[index].getCaps(WNNC_CONNECTION) & 2289 WNNC_CON_CANCELCONNECTION) 2290 { 2291 if (providerTable->table[index].cancelConnection) 2292 ret = providerTable->table[index].cancelConnection((LPWSTR)lpName, fForce); 2293 else 2294 ret = WN_NO_NETWORK; 2295 if (ret == WN_SUCCESS || ret == WN_OPEN_FILES) 2296 break; 2297 } 2298 } 2299 } 2300 2301 if (ret == WN_SUCCESS && dwFlags & CONNECT_UPDATE_PROFILE) 2302 { 2303 HKEY user_profile; 2304 2305 /* FIXME: Only remove it if that's a drive letter */ 2306 if (isalphaW(lpName[0]) && lpName[1] == ':' && 2307 RegOpenCurrentUser(KEY_ALL_ACCESS, &user_profile) == ERROR_SUCCESS) 2308 { 2309 WCHAR subkey[10] = {'N', 'e', 't', 'w', 'o', 'r', 'k', '\\', lpName[0], 0}; 2310 2311 RegDeleteKeyW(user_profile, subkey); 2312 2313 RegCloseKey(user_profile); 2314 } 2315 } 2316 2317 return ret; 2318 } 2319 2320 /***************************************************************** 2321 * WNetRestoreConnectionA [MPR.@] 2322 */ 2323 DWORD WINAPI WNetRestoreConnectionA( HWND hwndOwner, LPCSTR lpszDevice ) 2324 { 2325 FIXME( "(%p, %s), stub\n", hwndOwner, debugstr_a(lpszDevice) ); 2326 2327 SetLastError(WN_NO_NETWORK); 2328 return WN_NO_NETWORK; 2329 } 2330 2331 /***************************************************************** 2332 * WNetRestoreConnectionW [MPR.@] 2333 */ 2334 DWORD WINAPI WNetRestoreConnectionW( HWND hwndOwner, LPCWSTR lpszDevice ) 2335 { 2336 FIXME( "(%p, %s), stub\n", hwndOwner, debugstr_w(lpszDevice) ); 2337 2338 SetLastError(WN_NO_NETWORK); 2339 return WN_NO_NETWORK; 2340 } 2341 2342 /************************************************************************** 2343 * WNetGetConnectionA [MPR.@] 2344 * 2345 * RETURNS 2346 * - WN_BAD_LOCALNAME lpLocalName makes no sense 2347 * - WN_NOT_CONNECTED drive is a local drive 2348 * - WN_MORE_DATA buffer isn't big enough 2349 * - WN_SUCCESS success (net path in buffer) 2350 * 2351 * FIXME: need to test return values under different errors 2352 */ 2353 DWORD WINAPI WNetGetConnectionA( LPCSTR lpLocalName, 2354 LPSTR lpRemoteName, LPDWORD lpBufferSize ) 2355 { 2356 DWORD ret; 2357 2358 if (!lpLocalName) 2359 ret = WN_BAD_POINTER; 2360 else if (!lpBufferSize) 2361 ret = WN_BAD_POINTER; 2362 else if (!lpRemoteName && *lpBufferSize) 2363 ret = WN_BAD_POINTER; 2364 else 2365 { 2366 int len = MultiByteToWideChar(CP_ACP, 0, lpLocalName, -1, NULL, 0); 2367 2368 if (len) 2369 { 2370 PWSTR wideLocalName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); 2371 2372 if (wideLocalName) 2373 { 2374 WCHAR wideRemoteStatic[MAX_PATH]; 2375 DWORD wideRemoteSize = ARRAY_SIZE(wideRemoteStatic); 2376 2377 MultiByteToWideChar(CP_ACP, 0, lpLocalName, -1, wideLocalName, len); 2378 2379 /* try once without memory allocation */ 2380 ret = WNetGetConnectionW(wideLocalName, wideRemoteStatic, 2381 &wideRemoteSize); 2382 if (ret == WN_SUCCESS) 2383 { 2384 int len = WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic, 2385 -1, NULL, 0, NULL, NULL); 2386 2387 if (len <= *lpBufferSize) 2388 { 2389 WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic, -1, 2390 lpRemoteName, *lpBufferSize, NULL, NULL); 2391 ret = WN_SUCCESS; 2392 } 2393 else 2394 { 2395 *lpBufferSize = len; 2396 ret = WN_MORE_DATA; 2397 } 2398 } 2399 else if (ret == WN_MORE_DATA) 2400 { 2401 PWSTR wideRemote = HeapAlloc(GetProcessHeap(), 0, 2402 wideRemoteSize * sizeof(WCHAR)); 2403 2404 if (wideRemote) 2405 { 2406 ret = WNetGetConnectionW(wideLocalName, wideRemote, 2407 &wideRemoteSize); 2408 if (ret == WN_SUCCESS) 2409 { 2410 if (len <= *lpBufferSize) 2411 { 2412 WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic, 2413 -1, lpRemoteName, *lpBufferSize, NULL, NULL); 2414 ret = WN_SUCCESS; 2415 } 2416 else 2417 { 2418 *lpBufferSize = len; 2419 ret = WN_MORE_DATA; 2420 } 2421 } 2422 HeapFree(GetProcessHeap(), 0, wideRemote); 2423 } 2424 else 2425 ret = WN_OUT_OF_MEMORY; 2426 } 2427 HeapFree(GetProcessHeap(), 0, wideLocalName); 2428 } 2429 else 2430 ret = WN_OUT_OF_MEMORY; 2431 } 2432 else 2433 ret = WN_BAD_LOCALNAME; 2434 } 2435 if (ret) 2436 SetLastError(ret); 2437 TRACE("Returning %d\n", ret); 2438 return ret; 2439 } 2440 2441 /* find the network connection for a given drive; helper for WNetGetConnection */ 2442 static DWORD get_drive_connection( WCHAR letter, LPWSTR remote, LPDWORD size ) 2443 { 2444 #ifndef __REACTOS__ 2445 char buffer[1024]; 2446 struct mountmgr_unix_drive *data = (struct mountmgr_unix_drive *)buffer; 2447 HANDLE mgr; 2448 DWORD ret = WN_NOT_CONNECTED; 2449 DWORD bytes_returned; 2450 2451 if ((mgr = CreateFileW( MOUNTMGR_DOS_DEVICE_NAME, GENERIC_READ|GENERIC_WRITE, 2452 FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 2453 0, 0 )) == INVALID_HANDLE_VALUE) 2454 { 2455 ERR( "failed to open mount manager err %u\n", GetLastError() ); 2456 return ret; 2457 } 2458 memset( data, 0, sizeof(*data) ); 2459 data->letter = letter; 2460 if (DeviceIoControl( mgr, IOCTL_MOUNTMGR_QUERY_UNIX_DRIVE, data, sizeof(*data), 2461 data, sizeof(buffer), &bytes_returned, NULL )) 2462 { 2463 char *p, *mount_point = buffer + data->mount_point_offset; 2464 DWORD len; 2465 2466 if (data->mount_point_offset && !strncmp( mount_point, "unc/", 4 )) 2467 { 2468 mount_point += 2; 2469 mount_point[0] = '\\'; 2470 for (p = mount_point; *p; p++) if (*p == '/') *p = '\\'; 2471 2472 len = MultiByteToWideChar( CP_UNIXCP, 0, mount_point, -1, NULL, 0 ); 2473 if (len > *size) 2474 { 2475 *size = len; 2476 ret = WN_MORE_DATA; 2477 } 2478 else 2479 { 2480 *size = MultiByteToWideChar( CP_UNIXCP, 0, mount_point, -1, remote, *size); 2481 ret = WN_SUCCESS; 2482 } 2483 } 2484 } 2485 CloseHandle( mgr ); 2486 return ret; 2487 #else 2488 DWORD ret = WN_NO_NETWORK; 2489 DWORD index; 2490 WCHAR local[3] = {letter, ':', 0}; 2491 2492 if (providerTable != NULL) 2493 { 2494 for (index = 0; index < providerTable->numProviders; index++) 2495 { 2496 if(providerTable->table[index].getCaps(WNNC_CONNECTION) & 2497 WNNC_CON_GETCONNECTIONS) 2498 { 2499 if (providerTable->table[index].getConnection) 2500 ret = providerTable->table[index].getConnection( 2501 local, remote, size); 2502 else 2503 ret = WN_NO_NETWORK; 2504 if (ret == WN_SUCCESS || ret == WN_MORE_DATA) 2505 break; 2506 } 2507 } 2508 } 2509 if (ret) 2510 SetLastError(ret); 2511 return ret; 2512 #endif 2513 } 2514 2515 /************************************************************************** 2516 * WNetGetConnectionW [MPR.@] 2517 * 2518 * FIXME: need to test return values under different errors 2519 */ 2520 DWORD WINAPI WNetGetConnectionW( LPCWSTR lpLocalName, 2521 LPWSTR lpRemoteName, LPDWORD lpBufferSize ) 2522 { 2523 DWORD ret; 2524 2525 TRACE("(%s, %p, %p)\n", debugstr_w(lpLocalName), lpRemoteName, 2526 lpBufferSize); 2527 2528 if (!lpLocalName) 2529 ret = WN_BAD_POINTER; 2530 else if (!lpBufferSize) 2531 ret = WN_BAD_POINTER; 2532 else if (!lpRemoteName && *lpBufferSize) 2533 ret = WN_BAD_POINTER; 2534 else if (!lpLocalName[0]) 2535 ret = WN_BAD_LOCALNAME; 2536 else 2537 { 2538 if (lpLocalName[1] == ':') 2539 { 2540 switch(GetDriveTypeW(lpLocalName)) 2541 { 2542 case DRIVE_REMOTE: 2543 ret = get_drive_connection( lpLocalName[0], lpRemoteName, lpBufferSize ); 2544 break; 2545 case DRIVE_REMOVABLE: 2546 case DRIVE_FIXED: 2547 case DRIVE_CDROM: 2548 TRACE("file is local\n"); 2549 ret = WN_NOT_CONNECTED; 2550 break; 2551 default: 2552 ret = WN_BAD_LOCALNAME; 2553 } 2554 } 2555 else 2556 ret = WN_BAD_LOCALNAME; 2557 } 2558 if (ret) 2559 SetLastError(ret); 2560 TRACE("Returning %d\n", ret); 2561 return ret; 2562 } 2563 2564 /************************************************************************** 2565 * WNetSetConnectionA [MPR.@] 2566 */ 2567 DWORD WINAPI WNetSetConnectionA( LPCSTR lpName, DWORD dwProperty, 2568 LPVOID pvValue ) 2569 { 2570 FIXME( "(%s, %08X, %p): stub\n", debugstr_a(lpName), dwProperty, pvValue ); 2571 2572 SetLastError(WN_NO_NETWORK); 2573 return WN_NO_NETWORK; 2574 } 2575 2576 /************************************************************************** 2577 * WNetSetConnectionW [MPR.@] 2578 */ 2579 DWORD WINAPI WNetSetConnectionW( LPCWSTR lpName, DWORD dwProperty, 2580 LPVOID pvValue ) 2581 { 2582 FIXME( "(%s, %08X, %p): stub\n", debugstr_w(lpName), dwProperty, pvValue ); 2583 2584 SetLastError(WN_NO_NETWORK); 2585 return WN_NO_NETWORK; 2586 } 2587 2588 /***************************************************************** 2589 * WNetGetUniversalNameA [MPR.@] 2590 */ 2591 DWORD WINAPI WNetGetUniversalNameA ( LPCSTR lpLocalPath, DWORD dwInfoLevel, 2592 LPVOID lpBuffer, LPDWORD lpBufferSize ) 2593 { 2594 DWORD err, size; 2595 2596 FIXME( "(%s, 0x%08X, %p, %p): stub\n", 2597 debugstr_a(lpLocalPath), dwInfoLevel, lpBuffer, lpBufferSize); 2598 2599 switch (dwInfoLevel) 2600 { 2601 case UNIVERSAL_NAME_INFO_LEVEL: 2602 { 2603 LPUNIVERSAL_NAME_INFOA info = lpBuffer; 2604 2605 if (GetDriveTypeA(lpLocalPath) != DRIVE_REMOTE) 2606 { 2607 err = ERROR_NOT_CONNECTED; 2608 break; 2609 } 2610 2611 size = sizeof(*info) + lstrlenA(lpLocalPath) + 1; 2612 if (*lpBufferSize < size) 2613 { 2614 err = WN_MORE_DATA; 2615 break; 2616 } 2617 info->lpUniversalName = (char *)info + sizeof(*info); 2618 lstrcpyA(info->lpUniversalName, lpLocalPath); 2619 err = WN_NO_ERROR; 2620 break; 2621 } 2622 case REMOTE_NAME_INFO_LEVEL: 2623 err = WN_NOT_CONNECTED; 2624 break; 2625 2626 default: 2627 err = WN_BAD_VALUE; 2628 break; 2629 } 2630 2631 SetLastError(err); 2632 return err; 2633 } 2634 2635 /***************************************************************** 2636 * WNetGetUniversalNameW [MPR.@] 2637 */ 2638 DWORD WINAPI WNetGetUniversalNameW ( LPCWSTR lpLocalPath, DWORD dwInfoLevel, 2639 LPVOID lpBuffer, LPDWORD lpBufferSize ) 2640 { 2641 DWORD err, size; 2642 2643 FIXME( "(%s, 0x%08X, %p, %p): stub\n", 2644 debugstr_w(lpLocalPath), dwInfoLevel, lpBuffer, lpBufferSize); 2645 2646 switch (dwInfoLevel) 2647 { 2648 case UNIVERSAL_NAME_INFO_LEVEL: 2649 { 2650 LPUNIVERSAL_NAME_INFOW info = lpBuffer; 2651 2652 if (GetDriveTypeW(lpLocalPath) != DRIVE_REMOTE) 2653 { 2654 err = ERROR_NOT_CONNECTED; 2655 break; 2656 } 2657 2658 size = sizeof(*info) + (lstrlenW(lpLocalPath) + 1) * sizeof(WCHAR); 2659 if (*lpBufferSize < size) 2660 { 2661 *lpBufferSize = size; 2662 err = WN_MORE_DATA; 2663 break; 2664 } 2665 info->lpUniversalName = (LPWSTR)((char *)info + sizeof(*info)); 2666 lstrcpyW(info->lpUniversalName, lpLocalPath); 2667 err = WN_NO_ERROR; 2668 break; 2669 } 2670 case REMOTE_NAME_INFO_LEVEL: 2671 err = WN_NO_NETWORK; 2672 break; 2673 2674 default: 2675 err = WN_BAD_VALUE; 2676 break; 2677 } 2678 2679 if (err != WN_NO_ERROR) SetLastError(err); 2680 return err; 2681 } 2682 2683 /***************************************************************** 2684 * WNetClearConnections [MPR.@] 2685 */ 2686 DWORD WINAPI WNetClearConnections ( HWND owner ) 2687 { 2688 HANDLE connected; 2689 PWSTR connection; 2690 DWORD ret, size, count; 2691 NETRESOURCEW * resources, * iter; 2692 2693 ret = WNetOpenEnumW(RESOURCE_CONNECTED, RESOURCETYPE_ANY, 0, NULL, &connected); 2694 if (ret != WN_SUCCESS) 2695 { 2696 if (ret != WN_NO_NETWORK) 2697 { 2698 return ret; 2699 } 2700 2701 /* Means no provider, then, clearing is OK */ 2702 return WN_SUCCESS; 2703 } 2704 2705 size = 0x1000; 2706 resources = HeapAlloc(GetProcessHeap(), 0, size); 2707 if (!resources) 2708 { 2709 WNetCloseEnum(connected); 2710 return WN_OUT_OF_MEMORY; 2711 } 2712 2713 for (;;) 2714 { 2715 size = 0x1000; 2716 count = -1; 2717 2718 memset(resources, 0, size); 2719 ret = WNetEnumResourceW(connected, &count, resources, &size); 2720 if (ret == WN_SUCCESS || ret == WN_MORE_DATA) 2721 { 2722 for (iter = resources; count; count--, iter++) 2723 { 2724 if (iter->lpLocalName && iter->lpLocalName[0]) 2725 connection = iter->lpLocalName; 2726 else 2727 connection = iter->lpRemoteName; 2728 2729 WNetCancelConnection2W(connection, 0, TRUE); 2730 } 2731 } 2732 else 2733 break; 2734 } 2735 2736 HeapFree(GetProcessHeap(), 0, resources); 2737 WNetCloseEnum(connected); 2738 2739 return ret; 2740 } 2741 2742 2743 /* 2744 * Other Functions 2745 */ 2746 2747 /************************************************************************** 2748 * WNetGetUserA [MPR.@] 2749 * 2750 * FIXME: we should not return ourselves, but the owner of the drive lpName 2751 */ 2752 DWORD WINAPI WNetGetUserA( LPCSTR lpName, LPSTR lpUserID, LPDWORD lpBufferSize ) 2753 { 2754 if (GetUserNameA( lpUserID, lpBufferSize )) return WN_SUCCESS; 2755 return GetLastError(); 2756 } 2757 2758 /***************************************************************** 2759 * WNetGetUserW [MPR.@] 2760 * 2761 * FIXME: we should not return ourselves, but the owner of the drive lpName 2762 */ 2763 DWORD WINAPI WNetGetUserW( LPCWSTR lpName, LPWSTR lpUserID, LPDWORD lpBufferSize ) 2764 { 2765 if (GetUserNameW( lpUserID, lpBufferSize )) return WN_SUCCESS; 2766 return GetLastError(); 2767 } 2768 2769 /********************************************************************* 2770 * WNetConnectionDialog [MPR.@] 2771 */ 2772 DWORD WINAPI WNetConnectionDialog( HWND hwnd, DWORD dwType ) 2773 { 2774 CONNECTDLGSTRUCTW conn_dlg; 2775 NETRESOURCEW net_res; 2776 2777 ZeroMemory(&conn_dlg, sizeof(conn_dlg)); 2778 ZeroMemory(&net_res, sizeof(net_res)); 2779 2780 conn_dlg.cbStructure = sizeof(conn_dlg); 2781 conn_dlg.lpConnRes = &net_res; 2782 conn_dlg.hwndOwner = hwnd; 2783 net_res.dwType = dwType; 2784 2785 return WNetConnectionDialog1W(&conn_dlg); 2786 } 2787 2788 /********************************************************************* 2789 * WNetConnectionDialog1A [MPR.@] 2790 */ 2791 DWORD WINAPI WNetConnectionDialog1A( LPCONNECTDLGSTRUCTA lpConnDlgStruct ) 2792 { 2793 FIXME( "(%p): stub\n", lpConnDlgStruct ); 2794 2795 SetLastError(WN_NO_NETWORK); 2796 return WN_NO_NETWORK; 2797 } 2798 2799 /********************************************************************* 2800 * WNetConnectionDialog1W [MPR.@] 2801 */ 2802 DWORD WINAPI WNetConnectionDialog1W( LPCONNECTDLGSTRUCTW lpConnDlgStruct ) 2803 { 2804 FIXME( "(%p): stub\n", lpConnDlgStruct ); 2805 2806 SetLastError(WN_NO_NETWORK); 2807 return WN_NO_NETWORK; 2808 } 2809 2810 /********************************************************************* 2811 * WNetDisconnectDialog [MPR.@] 2812 */ 2813 DWORD WINAPI WNetDisconnectDialog( HWND hwnd, DWORD dwType ) 2814 { 2815 FIXME( "(%p, %08X): stub\n", hwnd, dwType ); 2816 2817 SetLastError(WN_NO_NETWORK); 2818 return WN_NO_NETWORK; 2819 } 2820 2821 /********************************************************************* 2822 * WNetDisconnectDialog1A [MPR.@] 2823 */ 2824 DWORD WINAPI WNetDisconnectDialog1A( LPDISCDLGSTRUCTA lpConnDlgStruct ) 2825 { 2826 FIXME( "(%p): stub\n", lpConnDlgStruct ); 2827 2828 SetLastError(WN_NO_NETWORK); 2829 return WN_NO_NETWORK; 2830 } 2831 2832 /********************************************************************* 2833 * WNetDisconnectDialog1W [MPR.@] 2834 */ 2835 DWORD WINAPI WNetDisconnectDialog1W( LPDISCDLGSTRUCTW lpConnDlgStruct ) 2836 { 2837 FIXME( "(%p): stub\n", lpConnDlgStruct ); 2838 2839 SetLastError(WN_NO_NETWORK); 2840 return WN_NO_NETWORK; 2841 } 2842 2843 /********************************************************************* 2844 * WNetGetLastErrorA [MPR.@] 2845 */ 2846 DWORD WINAPI WNetGetLastErrorA( LPDWORD lpError, 2847 LPSTR lpErrorBuf, DWORD nErrorBufSize, 2848 LPSTR lpNameBuf, DWORD nNameBufSize ) 2849 { 2850 FIXME( "(%p, %p, %d, %p, %d): stub\n", 2851 lpError, lpErrorBuf, nErrorBufSize, lpNameBuf, nNameBufSize ); 2852 2853 SetLastError(WN_NO_NETWORK); 2854 return WN_NO_NETWORK; 2855 } 2856 2857 /********************************************************************* 2858 * WNetGetLastErrorW [MPR.@] 2859 */ 2860 DWORD WINAPI WNetGetLastErrorW( LPDWORD lpError, 2861 LPWSTR lpErrorBuf, DWORD nErrorBufSize, 2862 LPWSTR lpNameBuf, DWORD nNameBufSize ) 2863 { 2864 FIXME( "(%p, %p, %d, %p, %d): stub\n", 2865 lpError, lpErrorBuf, nErrorBufSize, lpNameBuf, nNameBufSize ); 2866 2867 SetLastError(WN_NO_NETWORK); 2868 return WN_NO_NETWORK; 2869 } 2870 2871 /********************************************************************* 2872 * WNetGetNetworkInformationA [MPR.@] 2873 */ 2874 DWORD WINAPI WNetGetNetworkInformationA( LPCSTR lpProvider, 2875 LPNETINFOSTRUCT lpNetInfoStruct ) 2876 { 2877 DWORD ret; 2878 2879 TRACE( "(%s, %p)\n", debugstr_a(lpProvider), lpNetInfoStruct ); 2880 2881 if (!lpProvider) 2882 ret = WN_BAD_POINTER; 2883 else 2884 { 2885 int len; 2886 2887 len = MultiByteToWideChar(CP_ACP, 0, lpProvider, -1, NULL, 0); 2888 if (len) 2889 { 2890 LPWSTR wideProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); 2891 2892 if (wideProvider) 2893 { 2894 MultiByteToWideChar(CP_ACP, 0, lpProvider, -1, wideProvider, 2895 len); 2896 ret = WNetGetNetworkInformationW(wideProvider, lpNetInfoStruct); 2897 HeapFree(GetProcessHeap(), 0, wideProvider); 2898 } 2899 else 2900 ret = WN_OUT_OF_MEMORY; 2901 } 2902 else 2903 ret = GetLastError(); 2904 } 2905 if (ret) 2906 SetLastError(ret); 2907 TRACE("Returning %d\n", ret); 2908 return ret; 2909 } 2910 2911 /********************************************************************* 2912 * WNetGetNetworkInformationW [MPR.@] 2913 */ 2914 DWORD WINAPI WNetGetNetworkInformationW( LPCWSTR lpProvider, 2915 LPNETINFOSTRUCT lpNetInfoStruct ) 2916 { 2917 DWORD ret; 2918 2919 TRACE( "(%s, %p)\n", debugstr_w(lpProvider), lpNetInfoStruct ); 2920 2921 if (!lpProvider) 2922 ret = WN_BAD_POINTER; 2923 else if (!lpNetInfoStruct) 2924 ret = WN_BAD_POINTER; 2925 else if (lpNetInfoStruct->cbStructure < sizeof(NETINFOSTRUCT)) 2926 ret = WN_BAD_VALUE; 2927 else 2928 { 2929 if (providerTable && providerTable->numProviders) 2930 { 2931 DWORD providerIndex = _findProviderIndexW(lpProvider); 2932 2933 if (providerIndex != BAD_PROVIDER_INDEX) 2934 { 2935 lpNetInfoStruct->cbStructure = sizeof(NETINFOSTRUCT); 2936 lpNetInfoStruct->dwProviderVersion = 2937 providerTable->table[providerIndex].dwSpecVersion; 2938 lpNetInfoStruct->dwStatus = NO_ERROR; 2939 lpNetInfoStruct->dwCharacteristics = 0; 2940 lpNetInfoStruct->dwHandle = 0; 2941 lpNetInfoStruct->wNetType = 2942 HIWORD(providerTable->table[providerIndex].dwNetType); 2943 lpNetInfoStruct->dwPrinters = -1; 2944 lpNetInfoStruct->dwDrives = -1; 2945 ret = WN_SUCCESS; 2946 } 2947 else 2948 ret = WN_BAD_PROVIDER; 2949 } 2950 else 2951 ret = WN_NO_NETWORK; 2952 } 2953 if (ret) 2954 SetLastError(ret); 2955 TRACE("Returning %d\n", ret); 2956 return ret; 2957 } 2958 2959 /***************************************************************** 2960 * WNetGetProviderNameA [MPR.@] 2961 */ 2962 DWORD WINAPI WNetGetProviderNameA( DWORD dwNetType, 2963 LPSTR lpProvider, LPDWORD lpBufferSize ) 2964 { 2965 DWORD ret; 2966 2967 TRACE("(0x%08x, %s, %p)\n", dwNetType, debugstr_a(lpProvider), 2968 lpBufferSize); 2969 2970 if (!lpProvider) 2971 ret = WN_BAD_POINTER; 2972 else if (!lpBufferSize) 2973 ret = WN_BAD_POINTER; 2974 else 2975 { 2976 if (providerTable) 2977 { 2978 DWORD i; 2979 2980 ret = WN_NO_NETWORK; 2981 for (i = 0; i < providerTable->numProviders && 2982 HIWORD(providerTable->table[i].dwNetType) != HIWORD(dwNetType); 2983 i++) 2984 ; 2985 if (i < providerTable->numProviders) 2986 { 2987 DWORD sizeNeeded = WideCharToMultiByte(CP_ACP, 0, 2988 providerTable->table[i].name, -1, NULL, 0, NULL, NULL); 2989 2990 if (*lpBufferSize < sizeNeeded) 2991 { 2992 *lpBufferSize = sizeNeeded; 2993 ret = WN_MORE_DATA; 2994 } 2995 else 2996 { 2997 WideCharToMultiByte(CP_ACP, 0, providerTable->table[i].name, 2998 -1, lpProvider, *lpBufferSize, NULL, NULL); 2999 ret = WN_SUCCESS; 3000 /* FIXME: is *lpBufferSize set to the number of characters 3001 * copied? */ 3002 } 3003 } 3004 } 3005 else 3006 ret = WN_NO_NETWORK; 3007 } 3008 if (ret) 3009 SetLastError(ret); 3010 TRACE("Returning %d\n", ret); 3011 return ret; 3012 } 3013 3014 /***************************************************************** 3015 * WNetGetProviderNameW [MPR.@] 3016 */ 3017 DWORD WINAPI WNetGetProviderNameW( DWORD dwNetType, 3018 LPWSTR lpProvider, LPDWORD lpBufferSize ) 3019 { 3020 DWORD ret; 3021 3022 TRACE("(0x%08x, %s, %p)\n", dwNetType, debugstr_w(lpProvider), 3023 lpBufferSize); 3024 3025 if (!lpProvider) 3026 ret = WN_BAD_POINTER; 3027 else if (!lpBufferSize) 3028 ret = WN_BAD_POINTER; 3029 else 3030 { 3031 if (providerTable) 3032 { 3033 DWORD i; 3034 3035 ret = WN_NO_NETWORK; 3036 for (i = 0; i < providerTable->numProviders && 3037 HIWORD(providerTable->table[i].dwNetType) != HIWORD(dwNetType); 3038 i++) 3039 ; 3040 if (i < providerTable->numProviders) 3041 { 3042 DWORD sizeNeeded = strlenW(providerTable->table[i].name) + 1; 3043 3044 if (*lpBufferSize < sizeNeeded) 3045 { 3046 *lpBufferSize = sizeNeeded; 3047 ret = WN_MORE_DATA; 3048 } 3049 else 3050 { 3051 strcpyW(lpProvider, providerTable->table[i].name); 3052 ret = WN_SUCCESS; 3053 /* FIXME: is *lpBufferSize set to the number of characters 3054 * copied? */ 3055 } 3056 } 3057 } 3058 else 3059 ret = WN_NO_NETWORK; 3060 } 3061 if (ret) 3062 SetLastError(ret); 3063 TRACE("Returning %d\n", ret); 3064 return ret; 3065 } 3066