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