https://git.reactos.org/?p=reactos.git;a=commitdiff;h=8b0a1264450b33807b412…
commit 8b0a1264450b33807b41249a939c6fd5b94bd1da
Author: Pierre Schweitzer <pierre(a)reactos.org>
AuthorDate: Sat Nov 17 21:55:57 2018 +0100
Commit: Pierre Schweitzer <pierre(a)reactos.org>
CommitDate: Sat Nov 17 22:13:25 2018 +0100
[MPR] Implement remembered connection enumeration
Submitted upstream
CORE-15310
---
dll/win32/mpr/wnet.c | 249 +++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 249 insertions(+)
diff --git a/dll/win32/mpr/wnet.c b/dll/win32/mpr/wnet.c
index 162b41f4b9..14192c8245 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;