diff --git a/dll/win32/mpr/wnet.c b/dll/win32/mpr/wnet.c index 162b41f4b9d..14192c8245c 100644 --- a/dll/win32/mpr/wnet.c +++ b/dll/win32/mpr/wnet.c @@ -73,12 +73,21 @@ typedef struct _WNetProviderTable WNetProvider table[1]; } WNetProviderTable, *PWNetProviderTable; +#ifndef __REACTOS__ #define WNET_ENUMERATOR_TYPE_NULL 0 #define WNET_ENUMERATOR_TYPE_GLOBAL 1 #define WNET_ENUMERATOR_TYPE_PROVIDER 2 #define WNET_ENUMERATOR_TYPE_CONTEXT 3 #define WNET_ENUMERATOR_TYPE_CONNECTED 4 +#else +#define WNET_ENUMERATOR_TYPE_GLOBAL 0 +#define WNET_ENUMERATOR_TYPE_PROVIDER 1 +#define WNET_ENUMERATOR_TYPE_CONTEXT 2 +#define WNET_ENUMERATOR_TYPE_CONNECTED 3 +#define WNET_ENUMERATOR_TYPE_REMEMBERED 4 +#endif +#ifndef __REACTOS__ /* An WNet enumerator. Note that the type doesn't correspond to the scope of * the enumeration; it represents one of the following types: * - a 'null' enumeration, one that contains no members @@ -93,6 +102,23 @@ typedef struct _WNetProviderTable * into a global enumeration (so the enumeration continues across all * providers). */ +#else +/* An WNet enumerator. Note that the type doesn't correspond to the scope of + * the enumeration; it represents one of the following types: + * - a global enumeration, one that's executed across all providers + * - a provider-specific enumeration, one that's only executed by a single + * provider + * - a context enumeration. I know this contradicts what I just said about + * there being no correspondence between the scope and the type, but it's + * necessary for the special case that a "Entire Network" entry needs to + * be enumerated in an enumeration of the context scope. Thus an enumeration + * of the context scope results in a context type enumerator, which morphs + * into a global enumeration (so the enumeration continues across all + * providers). + * - a remembered enumeration, not related to providers themselves, but it + * is a registry enumeration for saved connections + */ +#endif typedef struct _WNetEnumerator { DWORD enumType; @@ -106,6 +132,13 @@ typedef struct _WNetEnumerator { NETRESOURCEW* net; HANDLE* handles; +#ifdef __REACTOS__ + struct + { + HKEY registry; + DWORD index; + } remembered; +#endif } specific; } WNetEnumerator, *PWNetEnumerator; @@ -553,6 +586,7 @@ static void _freeEnumNetResource(LPNETRESOURCEW lpNet) } } +#ifndef __REACTOS__ static PWNetEnumerator _createNullEnumerator(void) { PWNetEnumerator ret = HeapAlloc(GetProcessHeap(), @@ -562,6 +596,7 @@ static PWNetEnumerator _createNullEnumerator(void) ret->enumType = WNET_ENUMERATOR_TYPE_NULL; return ret; } +#endif static PWNetEnumerator _createGlobalEnumeratorW(DWORD dwScope, DWORD dwType, DWORD dwUsage, LPNETRESOURCEW lpNet) @@ -639,6 +674,22 @@ static PWNetEnumerator _createConnectedEnumerator(DWORD dwScope, DWORD dwType, return ret; } +#ifdef __REACTOS__ +static PWNetEnumerator _createRememberedEnumerator(DWORD dwScope, DWORD dwType, + HKEY remembered) +{ + PWNetEnumerator ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WNetEnumerator)); + if (ret) + { + ret->enumType = WNET_ENUMERATOR_TYPE_REMEMBERED; + ret->dwScope = dwScope; + ret->dwType = dwType; + ret->specific.remembered.registry = remembered; + } + return ret; +} +#endif + /* Thunks the array of wide-string LPNETRESOURCEs lpNetArrayIn into buffer * lpBuffer, with size *lpBufferSize. lpNetArrayIn contains *lpcCount entries * to start. On return, *lpcCount reflects the number thunked into lpBuffer. @@ -1004,8 +1055,28 @@ DWORD WINAPI WNetOpenEnumW( DWORD dwScope, DWORD dwType, DWORD dwUsage, ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY; break; case RESOURCE_REMEMBERED: +#ifndef __REACTOS__ *lphEnum = _createNullEnumerator(); ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY; +#else + { + HKEY remembered, user_profile; + + ret = WN_OUT_OF_MEMORY; + if (RegOpenCurrentUser(KEY_READ, &user_profile) == ERROR_SUCCESS) + { + WCHAR subkey[8] = {'N', 'e', 't', 'w', 'o', 'r', 'k', 0}; + + if (RegOpenKeyExW(user_profile, subkey, 0, KEY_READ, &remembered) == ERROR_SUCCESS) + { + *lphEnum = _createRememberedEnumerator(dwScope, dwType, remembered); + ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY; + } + + RegCloseKey(user_profile); + } + } +#endif break; default: WARN("unknown scope 0x%08x\n", dwScope); @@ -1512,6 +1583,168 @@ static DWORD _enumerateConnectedW(PWNetEnumerator enumerator, DWORD* user_count, return ret; } +#ifdef __REACTOS__ +static const WCHAR connectionType[] = { 'C','o','n','n','e','c','t', + 'i','o','n','T','y','p','e',0 }; +static const WCHAR providerName[] = { 'P','r','o','v','i','d','e','r', + 'N','a','m','e',0 }; +static const WCHAR remotePath[] = { 'R','e','m','o','t','e','P', + 'a','t','h',0 }; + +static DWORD _enumeratorRememberedW(PWNetEnumerator enumerator, DWORD* user_count, + void* user_buffer, DWORD* user_size) +{ + HKEY registry, connection; + WCHAR buffer[255]; + DWORD index, ret, type, len, size, provider_size, remote_size, full_size, total_count, size_left = *user_size; + NETRESOURCEW * net_buffer = user_buffer; + WCHAR * str; + + if (!enumerator) + return WN_BAD_POINTER; + if (enumerator->enumType != WNET_ENUMERATOR_TYPE_REMEMBERED) + return WN_BAD_VALUE; + if (!user_count || !user_buffer || !user_size) + return WN_BAD_POINTER; + if (!providerTable) + return WN_NO_NETWORK; + + /* We will do the work in a single loop, so here is some things: + * we write netresource at the begin of the user buffer + * we write strings at the end of the user buffer + */ + total_count = 0; + type = enumerator->dwType; + registry = enumerator->specific.remembered.registry; + str = (WCHAR *)((ULONG_PTR)user_buffer + *user_size - sizeof(WCHAR)); + for (index = enumerator->specific.remembered.index; ; ++index) + { + enumerator->specific.remembered.index = index; + + if (*user_count != -1 && total_count == *user_count) + { + ret = WN_SUCCESS; + break; + } + + if (size_left < sizeof(NETRESOURCEW)) + { + ret = WN_MORE_DATA; + break; + } + + len = ARRAY_SIZE(buffer); + ret = RegEnumKeyExW(registry, index, buffer, &len, NULL, NULL, NULL, NULL); + if (ret != ERROR_SUCCESS) + { + /* We're done, that's a success! */ + if (ret == ERROR_NO_MORE_ITEMS) + { + ret = WN_SUCCESS; + break; + } + + continue; + } + + if (RegOpenKeyExW(registry, buffer, 0, KEY_READ, &connection) != ERROR_SUCCESS) + { + continue; + } + + size = sizeof(DWORD); + RegQueryValueExW(connection, connectionType, NULL, NULL, (BYTE *)&net_buffer->dwType, &size); + if (type != RESOURCETYPE_ANY && net_buffer->dwType != type) + { + RegCloseKey(connection); + continue; + } + + net_buffer->dwScope = RESOURCE_REMEMBERED; + net_buffer->dwDisplayType = RESOURCEDISPLAYTYPE_GENERIC; + net_buffer->dwUsage = RESOURCEUSAGE_CONNECTABLE; + + size_left -= sizeof(NETRESOURCEW); + + /* Compute the whole size */ + full_size = 0; + if (RegQueryValueExW(connection, providerName, NULL, NULL, NULL, &provider_size) != ERROR_SUCCESS) + { + RegCloseKey(connection); + continue; + } + full_size += provider_size; + + if (RegQueryValueExW(connection, remotePath, NULL, NULL, NULL, &remote_size) != ERROR_SUCCESS) + { + RegCloseKey(connection); + continue; + } + full_size += remote_size; + + /* FIXME: this only supports drive letters */ + full_size += 3 * sizeof(WCHAR); + if (full_size > size_left) + { + RegCloseKey(connection); + ret = WN_MORE_DATA; + break; + } + + str -= 3; + str[0] = buffer[0]; + str[1] = L':'; + str[2] = 0; + net_buffer->lpLocalName = str; + size_left -= 3 * sizeof(WCHAR); + + size = provider_size; + str -= (provider_size / sizeof(WCHAR)); + ret = RegQueryValueExW(connection, providerName, NULL, NULL, (BYTE *)str, &size); + if (ret == ERROR_MORE_DATA) + { + RegCloseKey(connection); + ret = WN_MORE_DATA; + break; + } + net_buffer->lpProvider = str; + size_left -= size; + + size = remote_size; + str -= (remote_size / sizeof(WCHAR)); + ret = RegQueryValueExW(connection, remotePath, NULL, NULL, (BYTE *)str, &size); + if (ret == ERROR_MORE_DATA) + { + RegCloseKey(connection); + ret = WN_MORE_DATA; + break; + } + net_buffer->lpRemoteName = str; + size_left -= size; + + RegCloseKey(connection); + + net_buffer->lpComment = NULL; + + ++total_count; + ++net_buffer; + } + + if (total_count == 0) + ret = WN_NO_MORE_ENTRIES; + + *user_count = total_count; + + if (ret != WN_MORE_DATA && ret != WN_NO_MORE_ENTRIES) + ret = WN_SUCCESS; + + if (ret == WN_MORE_DATA) + *user_size = *user_size + full_size; + + return ret; +} +#endif + /********************************************************************* * WNetEnumResourceW [MPR.@] */ @@ -1541,9 +1774,11 @@ DWORD WINAPI WNetEnumResourceW( HANDLE hEnum, LPDWORD lpcCount, switch (enumerator->enumType) { +#ifndef __REACTOS__ case WNET_ENUMERATOR_TYPE_NULL: ret = WN_NO_MORE_ENTRIES; break; +#endif case WNET_ENUMERATOR_TYPE_GLOBAL: ret = _enumerateGlobalW(enumerator, lpcCount, lpBuffer, lpBufferSize); @@ -1560,6 +1795,12 @@ DWORD WINAPI WNetEnumResourceW( HANDLE hEnum, LPDWORD lpcCount, ret = _enumerateConnectedW(enumerator, lpcCount, lpBuffer, lpBufferSize); break; +#ifdef __REACTOS__ + case WNET_ENUMERATOR_TYPE_REMEMBERED: + ret = _enumeratorRememberedW(enumerator, lpcCount, lpBuffer, + lpBufferSize); + break; +#endif default: WARN("bogus enumerator type!\n"); ret = WN_NO_NETWORK; @@ -1587,9 +1828,11 @@ DWORD WINAPI WNetCloseEnum( HANDLE hEnum ) switch (enumerator->enumType) { +#ifndef __REACTOS__ case WNET_ENUMERATOR_TYPE_NULL: ret = WN_SUCCESS; break; +#endif case WNET_ENUMERATOR_TYPE_GLOBAL: if (enumerator->specific.net) _freeEnumNetResource(enumerator->specific.net); @@ -1614,6 +1857,12 @@ DWORD WINAPI WNetCloseEnum( HANDLE hEnum ) HeapFree(GetProcessHeap(), 0, handles); ret = WN_SUCCESS; break; +#ifdef __REACTOS__ + case WNET_ENUMERATOR_TYPE_REMEMBERED: + RegCloseKey(enumerator->specific.remembered.registry); + ret = WN_SUCCESS; + break; +#endif default: WARN("bogus enumerator type!\n"); ret = WN_BAD_HANDLE;