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