* Copyright 1999 Ulrich Weigand
* Copyright 2004 Juan Lang
* Copyright 2007 Maarten Lankhorst
- * Copyright 2016 Pierre Schweitzer
+ * Copyright 2016-2018 Pierre Schweitzer
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
-#include "precomp.h"
-
-#include <winioctl.h>
-#include <npapi.h>
+#include <stdarg.h>
+#include "windef.h"
+#include "winbase.h"
+#include "winnls.h"
+#include "winioctl.h"
+#include "winnetwk.h"
+#include "npapi.h"
+#include "winreg.h"
+#include "winuser.h"
#define WINE_MOUNTMGR_EXTENSIONS
-#include <ddk/mountmgr.h>
-#include <wine/unicode.h>
+#include "ddk/mountmgr.h"
+#include "wine/debug.h"
+#include "wine/unicode.h"
+#include "mprres.h"
+#include "wnetpriv.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(mpr);
/* Data structures representing network service providers. Assumes only one
* thread creates them, and that they are constant for the life of the process
WNetProvider table[1];
} WNetProviderTable, *PWNetProviderTable;
-#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
+#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
/* 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
* - a global enumeration, one that's executed across all providers
* - a provider-specific enumeration, one that's only executed by a single
* provider
* 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
*/
typedef struct _WNetEnumerator
{
{
NETRESOURCEW* net;
HANDLE* handles;
+ struct
+ {
+ HKEY registry;
+ DWORD index;
+ } remembered;
} specific;
} WNetEnumerator, *PWNetEnumerator;
debugstr_w(provider));
}
-#ifdef __REACTOS__
-static void _restoreSavedConnection(HKEY connection, WCHAR * local)
-{
- NETRESOURCEW net;
- DWORD type, prov, index, size;
-
- net.lpProvider = NULL;
- net.lpRemoteName = NULL;
- net.lpLocalName = NULL;
-
- TRACE("Restoring: %S\n", local);
-
- size = sizeof(DWORD);
- if (RegQueryValueExW(connection, L"ConnectionType", NULL, &type, (BYTE *)&net.dwType, &size) != ERROR_SUCCESS)
- return;
-
- if (type != REG_DWORD || size != sizeof(DWORD))
- return;
-
- if (RegQueryValueExW(connection, L"ProviderName", NULL, &type, NULL, &size) != ERROR_SUCCESS)
- return;
-
- if (type != REG_SZ)
- return;
-
- net.lpProvider = HeapAlloc(GetProcessHeap(), 0, size);
- if (!net.lpProvider)
- return;
-
- if (RegQueryValueExW(connection, L"ProviderName", NULL, NULL, (BYTE *)net.lpProvider, &size) != ERROR_SUCCESS)
- goto cleanup;
-
- size = sizeof(DWORD);
- if (RegQueryValueExW(connection, L"ProviderType", NULL, &type, (BYTE *)&prov, &size) != ERROR_SUCCESS)
- goto cleanup;
-
- if (type != REG_DWORD || size != sizeof(DWORD))
- goto cleanup;
-
- index = _findProviderIndexW(net.lpProvider);
- if (index == BAD_PROVIDER_INDEX)
- goto cleanup;
-
- if (providerTable->table[index].dwNetType != prov)
- goto cleanup;
-
- if (RegQueryValueExW(connection, L"RemotePath", NULL, &type, NULL, &size) != ERROR_SUCCESS)
- goto cleanup;
-
- if (type != REG_SZ)
- goto cleanup;
-
- net.lpRemoteName = HeapAlloc(GetProcessHeap(), 0, size);
- if (!net.lpRemoteName)
- goto cleanup;
-
- if (RegQueryValueExW(connection, L"RemotePath", NULL, NULL, (BYTE *)net.lpRemoteName, &size) != ERROR_SUCCESS)
- goto cleanup;
-
- size = strlenW(local);
- net.lpLocalName = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR) + 2 * sizeof(WCHAR));
- if (!net.lpLocalName)
- goto cleanup;
-
- strcpyW(net.lpLocalName, local);
- net.lpLocalName[size] = ':';
- net.lpLocalName[size + 1] = 0;
-
- TRACE("Attempting connection\n");
-
- WNetAddConnection2W(&net, NULL, NULL, 0);
-
-cleanup:
- HeapFree(GetProcessHeap(), 0, net.lpProvider);
- HeapFree(GetProcessHeap(), 0, net.lpRemoteName);
- HeapFree(GetProcessHeap(), 0, net.lpLocalName);
-}
-#endif
-
void wnetInit(HINSTANCE hInstDll)
{
static const WCHAR providerOrderKey[] = { 'S','y','s','t','e','m','\\',
}
RegCloseKey(hKey);
}
-
-#ifdef __REACTOS__
- if (providerTable)
- {
- HKEY user_profile;
-
- if (RegOpenCurrentUser(KEY_ALL_ACCESS, &user_profile) == ERROR_SUCCESS)
- {
- HKEY network;
- WCHAR subkey[8] = {'N', 'e', 't', 'w', 'o', 'r', 'k', 0};
-
- if (RegOpenKeyExW(user_profile, subkey, 0, KEY_READ, &network) == ERROR_SUCCESS)
- {
- DWORD size, max;
-
- TRACE("Enumerating remembered connections\n");
-
- if (RegQueryInfoKey(network, NULL, NULL, NULL, &max, &size, NULL, NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
- {
- WCHAR *local;
-
- TRACE("There are %lu connections\n", max);
-
- local = HeapAlloc(GetProcessHeap(), 0, (size + 1) * sizeof(WCHAR));
- if (local)
- {
- DWORD index;
-
- for (index = 0; index < max; ++index)
- {
- DWORD len = size + 1;
- HKEY connection;
-
- TRACE("Trying connection %lu\n", index);
-
- if (RegEnumKeyExW(network, index, local, &len, NULL, NULL, NULL, NULL) != ERROR_SUCCESS)
- continue;
-
- TRACE("It is %S\n", local);
-
- if (RegOpenKeyExW(network, local, 0, KEY_READ, &connection) != ERROR_SUCCESS)
- continue;
-
- _restoreSavedConnection(connection, local);
- RegCloseKey(connection);
- }
-
- HeapFree(GetProcessHeap(), 0, local);
- }
- }
-
- RegCloseKey(network);
- }
-
- RegCloseKey(user_profile);
- }
- }
-#endif
}
void wnetFree(void)
}
}
-static PWNetEnumerator _createNullEnumerator(void)
-{
- PWNetEnumerator ret = HeapAlloc(GetProcessHeap(),
- HEAP_ZERO_MEMORY, sizeof(WNetEnumerator));
-
- if (ret)
- ret->enumType = WNET_ENUMERATOR_TYPE_NULL;
- return ret;
-}
-
static PWNetEnumerator _createGlobalEnumeratorW(DWORD dwScope, DWORD dwType,
DWORD dwUsage, LPNETRESOURCEW lpNet)
{
return ret;
}
+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;
+}
+
/* 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.
ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
break;
case RESOURCE_REMEMBERED:
- *lphEnum = _createNullEnumerator();
- ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
+ {
+ 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);
+ }
+ }
break;
default:
WARN("unknown scope 0x%08x\n", dwScope);
return ret;
}
+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 WCHAR *get_reg_str(HKEY hkey, const WCHAR *value, DWORD *len)
+{
+ DWORD type;
+ WCHAR *ret = NULL;
+
+ if (!RegQueryValueExW(hkey, value, NULL, &type, NULL, len) && type == REG_SZ)
+ {
+ if (!(ret = HeapAlloc(GetProcessHeap(), 0, *len))) return NULL;
+ RegQueryValueExW(hkey, value, 0, 0, (BYTE *)ret, len);
+ }
+
+ return ret;
+}
+
+static DWORD _enumeratorRememberedW(PWNetEnumerator enumerator, DWORD* user_count,
+ void* user_buffer, DWORD* user_size)
+{
+ HKEY registry, connection;
+ WCHAR buffer[255];
+ LONG size_left;
+ DWORD index, ret, type, len, size, registry_size, full_size = 0, total_count;
+ NETRESOURCEW * net_buffer = user_buffer;
+ WCHAR * str, * registry_string;
+
+ /* 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
+ */
+ size_left = *user_size;
+ 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;
+ }
+
+ len = ARRAY_SIZE(buffer);
+ ret = RegEnumKeyExW(registry, index, buffer, &len, NULL, NULL, NULL, NULL);
+ if (ret != ERROR_SUCCESS)
+ {
+ if (ret == ERROR_NO_MORE_ITEMS) ret = WN_SUCCESS;
+ break;
+ }
+
+ if (RegOpenKeyExW(registry, buffer, 0, KEY_READ, &connection) != ERROR_SUCCESS)
+ {
+ continue;
+ }
+
+ full_size = sizeof(NETRESOURCEW);
+ size_left -= sizeof(NETRESOURCEW);
+
+ if (size_left > 0)
+ {
+ size = sizeof(DWORD);
+ RegQueryValueExW(connection, connectionType, NULL, NULL, (BYTE *)&net_buffer->dwType, &size);
+ if (type != RESOURCETYPE_ANY && net_buffer->dwType != type)
+ {
+ size_left += sizeof(NETRESOURCEW);
+ RegCloseKey(connection);
+ continue;
+ }
+
+ net_buffer->dwScope = RESOURCE_REMEMBERED;
+ net_buffer->dwDisplayType = RESOURCEDISPLAYTYPE_GENERIC;
+ net_buffer->dwUsage = RESOURCEUSAGE_CONNECTABLE;
+ }
+ else
+ ret = WN_MORE_DATA;
+
+ /* FIXME: this only supports drive letters */
+ full_size += 3 * sizeof(WCHAR);
+ size_left -= 3 * sizeof(WCHAR);
+ if (size_left > 0)
+ {
+ str -= 3;
+ str[0] = buffer[0];
+ str[1] = ':';
+ str[2] = 0;
+ net_buffer->lpLocalName = str;
+ }
+
+ registry_size = 0;
+ registry_string = get_reg_str(connection, providerName, ®istry_size);
+ if (registry_string)
+ {
+ full_size += registry_size;
+ size_left -= registry_size;
+
+ if (size_left > 0)
+ {
+ str -= (registry_size / sizeof(WCHAR));
+ lstrcpyW(str, registry_string);
+ net_buffer->lpProvider = str;
+ }
+ else
+ ret = WN_MORE_DATA;
+
+ HeapFree(GetProcessHeap(), 0, registry_string);
+ }
+
+ registry_size = 0;
+ registry_string = get_reg_str(connection, remotePath, ®istry_size);
+ if (registry_string)
+ {
+ full_size += registry_size;
+ size_left -= registry_size;
+
+ if (size_left > 0)
+ {
+ str -= (registry_size / sizeof(WCHAR));
+ lstrcpyW(str, registry_string);
+ net_buffer->lpRemoteName = str;
+ }
+ else
+ ret = WN_MORE_DATA;
+
+ HeapFree(GetProcessHeap(), 0, registry_string);
+ }
+
+ RegCloseKey(connection);
+
+ net_buffer->lpComment = NULL;
+
+ if (size_left < 0)
+ break;
+
+ ++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;
+}
+
/*********************************************************************
* WNetEnumResourceW [MPR.@]
*/
switch (enumerator->enumType)
{
- case WNET_ENUMERATOR_TYPE_NULL:
- ret = WN_NO_MORE_ENTRIES;
- break;
case WNET_ENUMERATOR_TYPE_GLOBAL:
ret = _enumerateGlobalW(enumerator, lpcCount, lpBuffer,
lpBufferSize);
ret = _enumerateConnectedW(enumerator, lpcCount, lpBuffer,
lpBufferSize);
break;
+ case WNET_ENUMERATOR_TYPE_REMEMBERED:
+ ret = _enumeratorRememberedW(enumerator, lpcCount, lpBuffer,
+ lpBufferSize);
+ break;
default:
WARN("bogus enumerator type!\n");
ret = WN_NO_NETWORK;
switch (enumerator->enumType)
{
- case WNET_ENUMERATOR_TYPE_NULL:
- ret = WN_SUCCESS;
- break;
case WNET_ENUMERATOR_TYPE_GLOBAL:
if (enumerator->specific.net)
_freeEnumNetResource(enumerator->specific.net);
HeapFree(GetProcessHeap(), 0, handles);
ret = WN_SUCCESS;
break;
+ case WNET_ENUMERATOR_TYPE_REMEMBERED:
+ RegCloseKey(enumerator->specific.remembered.registry);
+ ret = WN_SUCCESS;
+ break;
default:
WARN("bogus enumerator type!\n");
ret = WN_BAD_HANDLE;
break;
}
case REMOTE_NAME_INFO_LEVEL:
- err = WN_NO_NETWORK;
+ err = WN_NOT_CONNECTED;
break;
default:
return err;
}
+/*****************************************************************
+ * WNetClearConnections [MPR.@]
+ */
+DWORD WINAPI WNetClearConnections ( HWND owner )
+{
+ HANDLE connected;
+ PWSTR connection;
+ DWORD ret, size, count;
+ NETRESOURCEW * resources, * iter;
+
+ ret = WNetOpenEnumW(RESOURCE_CONNECTED, RESOURCETYPE_ANY, 0, NULL, &connected);
+ if (ret != WN_SUCCESS)
+ {
+ if (ret != WN_NO_NETWORK)
+ {
+ return ret;
+ }
+
+ /* Means no provider, then, clearing is OK */
+ return WN_SUCCESS;
+ }
+
+ size = 0x1000;
+ resources = HeapAlloc(GetProcessHeap(), 0, size);
+ if (!resources)
+ {
+ WNetCloseEnum(connected);
+ return WN_OUT_OF_MEMORY;
+ }
+
+ for (;;)
+ {
+ size = 0x1000;
+ count = -1;
+
+ memset(resources, 0, size);
+ ret = WNetEnumResourceW(connected, &count, resources, &size);
+ if (ret == WN_SUCCESS || ret == WN_MORE_DATA)
+ {
+ for (iter = resources; count; count--, iter++)
+ {
+ if (iter->lpLocalName && iter->lpLocalName[0])
+ connection = iter->lpLocalName;
+ else
+ connection = iter->lpRemoteName;
+
+ WNetCancelConnection2W(connection, 0, TRUE);
+ }
+ }
+ else
+ break;
+ }
+
+ HeapFree(GetProcessHeap(), 0, resources);
+ WNetCloseEnum(connected);
+
+ return ret;
+}
/*