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