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