[MPR]
[reactos.git] / reactos / dll / win32 / mpr / wnet.c
index 2cf1c8b..e634af7 100644 (file)
@@ -48,6 +48,10 @@ typedef struct _WNetProvider
     PF_NPGetResourceInformation getResourceInformation;
     PF_NPAddConnection addConnection;
     PF_NPAddConnection3 addConnection3;
+    PF_NPCancelConnection cancelConnection;
+#ifdef __REACTOS__
+    PF_NPGetConnection getConnection;
+#endif
 } WNetProvider, *PWNetProvider;
 
 typedef struct _WNetProviderTable
@@ -58,10 +62,11 @@ typedef struct _WNetProviderTable
     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_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
 
 /* An WNet enumerator.  Note that the type doesn't correspond to the scope of
  * the enumeration; it represents one of the following types:
@@ -86,7 +91,7 @@ typedef struct _WNetEnumerator
     DWORD          dwScope;
     DWORD          dwType;
     DWORD          dwUsage;
-    LPNETRESOURCEW lpNet;
+    LPVOID         lpBuffer;
 } WNetEnumerator, *PWNetEnumerator;
 
 #define BAD_PROVIDER_INDEX (DWORD)0xffffffff
@@ -196,8 +201,13 @@ static void _tryLoadProvider(PCWSTR provider)
                         }
                         provider->addConnection = MPR_GETPROC(NPAddConnection);
                         provider->addConnection3 = MPR_GETPROC(NPAddConnection3);
+                        provider->cancelConnection = MPR_GETPROC(NPCancelConnection);
+#ifdef __REACTOS__
+                        provider->getConnection = MPR_GETPROC(NPGetConnection);
+#endif
                         TRACE("NPAddConnection %p\n", provider->addConnection);
                         TRACE("NPAddConnection3 %p\n", provider->addConnection3);
+                        TRACE("NPCancelConnection %p\n", provider->cancelConnection);
                         providerTable->numProviders++;
                     }
                     else
@@ -407,7 +417,7 @@ static PWNetEnumerator _createGlobalEnumeratorW(DWORD dwScope, DWORD dwType,
         ret->dwScope = dwScope;
         ret->dwType  = dwType;
         ret->dwUsage = dwUsage;
-        ret->lpNet   = _copyNetResourceForEnumW(lpNet);
+        ret->lpBuffer = _copyNetResourceForEnumW(lpNet);
     }
     return ret;
 }
@@ -451,6 +461,28 @@ static PWNetEnumerator _createContextEnumerator(DWORD dwScope, DWORD dwType,
     return ret;
 }
 
+static PWNetEnumerator _createConnectedEnumerator(DWORD dwScope, DWORD dwType,
+ DWORD dwUsage)
+{
+    PWNetEnumerator ret = HeapAlloc(GetProcessHeap(),
+     HEAP_ZERO_MEMORY, sizeof(WNetEnumerator));
+
+    if (ret)
+    {
+        ret->enumType = WNET_ENUMERATOR_TYPE_CONNECTED;
+        ret->dwScope = dwScope;
+        ret->dwType  = dwType;
+        ret->dwUsage = dwUsage;
+        ret->lpBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(HANDLE) * providerTable->numProviders);
+        if (!ret->lpBuffer)
+        {
+            HeapFree(GetProcessHeap(), 0, ret);
+            ret = NULL;
+        }
+    }
+    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.
@@ -750,6 +782,11 @@ DWORD WINAPI WNetOpenEnumW( DWORD dwScope, DWORD dwType, DWORD dwUsage,
                              providerTable->table[index].dwEnumScopes & WNNC_ENUM_GLOBAL)
                             {
                                 HANDLE handle;
+                                PWSTR RemoteName = lpNet->lpRemoteName;
+
+                                if ((lpNet->dwUsage & RESOURCEUSAGE_CONTAINER) &&
+                                    RemoteName && !strcmpW(RemoteName, lpNet->lpProvider))
+                                    lpNet->lpRemoteName = NULL;
 
                                 ret = providerTable->table[index].openEnum(
                                  dwScope, dwType, dwUsage, lpNet, &handle);
@@ -760,6 +797,8 @@ DWORD WINAPI WNetOpenEnumW( DWORD dwScope, DWORD dwType, DWORD dwUsage,
                                     ret = *lphEnum ? WN_SUCCESS :
                                      WN_OUT_OF_MEMORY;
                                 }
+
+                                lpNet->lpRemoteName = RemoteName;
                             }
                             else
                                 ret = WN_NOT_SUPPORTED;
@@ -805,10 +844,13 @@ DWORD WINAPI WNetOpenEnumW( DWORD dwScope, DWORD dwType, DWORD dwUsage,
                 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
                 break;
             case RESOURCE_REMEMBERED:
-            case RESOURCE_CONNECTED:
                 *lphEnum = _createNullEnumerator();
                 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
                 break;
+            case RESOURCE_CONNECTED:
+                *lphEnum = _createConnectedEnumerator(dwScope, dwType, dwUsage);
+                ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
+                break;
             default:
                 WARN("unknown scope 0x%08x\n", dwScope);
                 ret = WN_BAD_VALUE;
@@ -1032,7 +1074,7 @@ static DWORD _enumerateGlobalPassthroughW(PWNetEnumerator enumerator,
     {
         ret = providerTable->table[enumerator->providerIndex].
          openEnum(enumerator->dwScope, enumerator->dwType,
-         enumerator->dwUsage, enumerator->lpNet,
+         enumerator->dwUsage, enumerator->lpBuffer,
          &enumerator->handle);
         if (ret == WN_SUCCESS)
         {
@@ -1070,7 +1112,7 @@ static DWORD _enumerateGlobalW(PWNetEnumerator enumerator, LPDWORD lpcCount,
     switch (enumerator->dwScope)
     {
         case RESOURCE_GLOBALNET:
-            if (enumerator->lpNet)
+            if (enumerator->lpBuffer)
                 ret = _enumerateGlobalPassthroughW(enumerator, lpcCount,
                  lpBuffer, lpBufferSize);
             else
@@ -1191,6 +1233,143 @@ static DWORD _enumerateContextW(PWNetEnumerator enumerator, LPDWORD lpcCount,
     return ret;
 }
 
+static DWORD _enumerateConnectedW(PWNetEnumerator enumerator, LPDWORD lpcCount,
+ LPVOID lpBuffer, LPDWORD lpBufferSize)
+{
+    DWORD ret, index, count, size, i, len, left;
+    PVOID end;
+    LPNETRESOURCEW curr, buffer;
+    PHANDLE handles;
+
+    if (!enumerator)
+        return WN_BAD_POINTER;
+    if (enumerator->enumType != WNET_ENUMERATOR_TYPE_CONNECTED)
+        return WN_BAD_VALUE;
+    if (!lpcCount)
+        return WN_BAD_POINTER;
+    if (!lpBuffer)
+        return WN_BAD_POINTER;
+    if (!lpBufferSize)
+        return WN_BAD_POINTER;
+    if (!providerTable)
+        return WN_NO_NETWORK;
+
+    handles = enumerator->lpBuffer;
+    left = *lpBufferSize;
+    size = *lpBufferSize;
+    buffer = HeapAlloc(GetProcessHeap(), 0, *lpBufferSize);
+    if (!buffer)
+        return WN_NO_NETWORK;
+
+    curr = lpBuffer;
+    end = (PVOID)((ULONG_PTR)lpBuffer + size);
+    count = *lpcCount;
+
+
+    for (index = 0; index < providerTable->numProviders; index++)
+    {
+        if (providerTable->table[index].dwEnumScopes)
+        {
+            if (handles[index] == 0)
+            {
+                ret = providerTable->table[index].openEnum(enumerator->dwScope,
+                                                           enumerator->dwType,
+                                                           enumerator->dwUsage,
+                                                           NULL, &handles[index]);
+                if (ret != WN_SUCCESS)
+                    continue;
+            }
+
+            ret = providerTable->table[index].enumResource(handles[index],
+                                                           &count,
+                                                           buffer,
+                                                           &size);
+
+            if (ret == WN_MORE_DATA)
+            {
+
+                break;
+            }
+
+            if (ret == WN_SUCCESS)
+            {
+                for (i = 0; i < count; ++i)
+                {
+                    if (left < sizeof(NETRESOURCEW))
+                    {
+                        ret = WN_MORE_DATA;
+                        break;
+                    }
+
+                    memcpy(curr, &buffer[i], sizeof(NETRESOURCEW));
+                    left -= sizeof(NETRESOURCEW);
+
+                    len = WideCharToMultiByte(CP_ACP, 0, buffer[i].lpLocalName, -1, NULL, 0, NULL, NULL);
+                    len *= sizeof(WCHAR);
+                    if (left < len)
+                    {
+                        ret = WN_MORE_DATA;
+                        break;
+                    }
+
+                    end = (PVOID)((ULONG_PTR)end - len);
+                    curr->lpLocalName = end;
+                    memcpy(end, buffer[i].lpLocalName, len);
+                    left -= len;
+
+                    len = WideCharToMultiByte(CP_ACP, 0, buffer[i].lpRemoteName, -1, NULL, 0, NULL, NULL);
+                    len *= sizeof(WCHAR);
+                    if (left < len)
+                    {
+                        ret = WN_MORE_DATA;
+                        break;
+                    }
+
+                    end = (PVOID)((ULONG_PTR)end - len);
+                    curr->lpRemoteName = end;
+                    memcpy(end, buffer[i].lpRemoteName, len);
+                    left -= len;
+
+                    len = WideCharToMultiByte(CP_ACP, 0, buffer[i].lpProvider, -1, NULL, 0, NULL, NULL);
+                    len *= sizeof(WCHAR);
+                    if (left < len)
+                    {
+                        ret = WN_MORE_DATA;
+                        break;
+                    }
+
+                    end = (PVOID)((ULONG_PTR)end - len);
+                    curr->lpProvider = end;
+                    memcpy(end, buffer[i].lpProvider, len);
+                    left -= len;
+
+                    ++curr;
+                }
+
+                count = *lpcCount - count;
+                size = left;
+            }
+
+            if (ret != WN_SUCCESS || count == 0)
+            {
+                break;
+            }
+        }
+    }
+
+    if (count == 0)
+        ret = WN_NO_MORE_ENTRIES;
+
+    *lpcCount = *lpcCount - count;
+    if (ret != WN_MORE_DATA && ret != WN_NO_MORE_ENTRIES)
+        ret = WN_SUCCESS;
+
+    HeapFree(GetProcessHeap(), 0, buffer);
+
+    TRACE("Returning %d\n", ret);
+    return ret;
+}
+
 /*********************************************************************
  * WNetEnumResourceW [MPR.@]
  */
@@ -1235,6 +1414,10 @@ DWORD WINAPI WNetEnumResourceW( HANDLE hEnum, LPDWORD lpcCount,
                 ret = _enumerateContextW(enumerator, lpcCount, lpBuffer,
                  lpBufferSize);
                 break;
+            case WNET_ENUMERATOR_TYPE_CONNECTED:
+                ret = _enumerateConnectedW(enumerator, lpcCount, lpBuffer,
+                 lpBufferSize);
+                break;
             default:
                 WARN("bogus enumerator type!\n");
                 ret = WN_NO_NETWORK;
@@ -1251,7 +1434,8 @@ DWORD WINAPI WNetEnumResourceW( HANDLE hEnum, LPDWORD lpcCount,
  */
 DWORD WINAPI WNetCloseEnum( HANDLE hEnum )
 {
-    DWORD ret;
+    DWORD ret, index;
+    PHANDLE handles;
 
     TRACE( "(%p)\n", hEnum );
 
@@ -1261,12 +1445,22 @@ DWORD WINAPI WNetCloseEnum( HANDLE hEnum )
 
         switch (enumerator->enumType)
         {
+            case WNET_ENUMERATOR_TYPE_CONNECTED:
+                handles = enumerator->lpBuffer;
+                for (index = 0; index < providerTable->numProviders; index++)
+                {
+                    if (providerTable->table[index].dwEnumScopes && handles[index] != 0)
+                        providerTable->table[index].closeEnum(handles[index]);
+                }
+                HeapFree(GetProcessHeap(), 0, handles);
+                ret = WN_SUCCESS;
+                break;
             case WNET_ENUMERATOR_TYPE_NULL:
                 ret = WN_SUCCESS;
                 break;
             case WNET_ENUMERATOR_TYPE_GLOBAL:
-                if (enumerator->lpNet)
-                    _freeEnumNetResource(enumerator->lpNet);
+                if (enumerator->lpBuffer)
+                    _freeEnumNetResource(enumerator->lpBuffer);
                 if (enumerator->handle)
                     providerTable->table[enumerator->providerIndex].
                      closeEnum(enumerator->handle);
@@ -1553,100 +1747,138 @@ DWORD WINAPI WNetAddConnection3W( HWND hwndOwner, LPNETRESOURCEW lpNetResource,
                               dwFlags, NULL, 0, NULL);
 }
 
-/* Convert an ANSI string to wide */
-static LPWSTR strdupAtoW( LPCSTR str )
+struct use_connection_context
 {
-    LPWSTR ret;
-    INT len;
+    HWND hwndOwner;
+    NETRESOURCEW *resource;
+    NETRESOURCEA *resourceA; /* only set for WNetUseConnectionA */
+    WCHAR *password;
+    WCHAR *userid;
+    DWORD flags;
+    void *accessname;
+    DWORD *buffer_size;
+    DWORD *result;
+    DWORD (*pre_set_accessname)(struct use_connection_context*, WCHAR *);
+    void  (*set_accessname)(struct use_connection_context*, WCHAR *);
+};
 
-    if (!str) return NULL;
-    len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
-    ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
-    if (ret) MultiByteToWideChar( CP_ACP, 0, str, -1, ret, len );
-    return ret;
-}
-
-/* Convert ANSI NETRESOURCE struct to wide structure */
-static VOID convert_netresourcea_to_w( LPNETRESOURCEA lpNetResourceA,
-                                       LPNETRESOURCEW lpNetResourceW )
+static DWORD use_connection_pre_set_accessnameW(struct use_connection_context *ctxt, WCHAR *local_name)
 {
-    lpNetResourceW->dwScope = lpNetResourceA->dwScope;
-    lpNetResourceW->dwType = lpNetResourceA->dwType;
-    lpNetResourceW->dwDisplayType = lpNetResourceA->dwDisplayType;
-    lpNetResourceW->dwUsage = lpNetResourceA->dwUsage;
-    lpNetResourceW->lpLocalName = strdupAtoW(lpNetResourceA->lpLocalName);
-    lpNetResourceW->lpRemoteName = strdupAtoW(lpNetResourceA->lpRemoteName);
-    lpNetResourceW->lpComment = strdupAtoW(lpNetResourceA->lpComment);
-    lpNetResourceW->lpProvider = strdupAtoW(lpNetResourceA->lpProvider);
+    if (ctxt->accessname && ctxt->buffer_size && *ctxt->buffer_size)
+    {
+        DWORD len;
+
+        if (local_name)
+            len = strlenW(local_name);
+        else
+            len = strlenW(ctxt->resource->lpRemoteName);
+
+        if (++len > *ctxt->buffer_size)
+        {
+            *ctxt->buffer_size = len;
+            return ERROR_MORE_DATA;
+        }
+    }
+    else
+        ctxt->accessname = NULL;
+
+    return ERROR_SUCCESS;
 }
 
-/*****************************************************************
- *  WNetUseConnectionA [MPR.@]
- */
-DWORD WINAPI WNetUseConnectionA( HWND hwndOwner, LPNETRESOURCEA lpNetResource,
-                                 LPCSTR lpPassword, LPCSTR lpUserID, DWORD dwFlags,
-                                 LPSTR lpAccessName, LPDWORD lpBufferSize,
-                                 LPDWORD lpResult )
-{
-    NETRESOURCEW resourcesW, *pRes = NULL;
-    PWSTR passW, userIDW, accessNameW = NULL;
-    DWORD ret = WN_MORE_DATA;
-    DWORD bufferSize = 1;
-    int len;
-
-    if (lpNetResource)
+static void use_connection_set_accessnameW(struct use_connection_context *ctxt, WCHAR *local_name)
+{
+    WCHAR *accessname = ctxt->accessname;
+    if (local_name)
     {
-        convert_netresourcea_to_w(lpNetResource, &resourcesW);
-        pRes = &resourcesW;
+        strcpyW(accessname, local_name);
+        if (ctxt->result)
+            *ctxt->result = CONNECT_LOCALDRIVE;
     }
+    else
+        strcpyW(accessname, ctxt->resource->lpRemoteName);
+}
+
+static DWORD wnet_use_provider( struct use_connection_context *ctxt, NETRESOURCEW * netres, WNetProvider *provider, BOOLEAN redirect )
+{
+    DWORD caps, ret;
 
-    passW = strdupAtoW(lpPassword);
-    userIDW = strdupAtoW(lpUserID);
+    caps = provider->getCaps(WNNC_CONNECTION);
+    if (!(caps & (WNNC_CON_ADDCONNECTION | WNNC_CON_ADDCONNECTION3)))
+        return ERROR_BAD_PROVIDER;
 
-    if (lpAccessName && lpBufferSize && *lpBufferSize)
+    ret = WN_ACCESS_DENIED;
+    do
     {
-        WCHAR probe;
+        if ((caps & WNNC_CON_ADDCONNECTION3) && provider->addConnection3)
+            ret = provider->addConnection3(ctxt->hwndOwner, netres, ctxt->password, ctxt->userid, ctxt->flags);
+        else if ((caps & WNNC_CON_ADDCONNECTION) && provider->addConnection)
+            ret = provider->addConnection(netres, ctxt->password, ctxt->userid);
 
-        ret = WNetUseConnectionW(hwndOwner, pRes, passW, userIDW, dwFlags,
-                                 &probe, &bufferSize, lpResult);
-        if (ret == WN_MORE_DATA)
-            accessNameW = HeapAlloc(GetProcessHeap(), 0, bufferSize * sizeof(WCHAR));
-    }
+        if (ret == WN_ALREADY_CONNECTED && redirect)
+            netres->lpLocalName[0] -= 1;
+    } while (redirect && ret == WN_ALREADY_CONNECTED && netres->lpLocalName[0] >= 'C');
 
-    if (ret == WN_MORE_DATA)
+    if (ret == WN_SUCCESS && ctxt->accessname)
+        ctxt->set_accessname(ctxt, netres->lpLocalName);
+
+    return ret;
+}
+
+static DWORD wnet_use_connection( struct use_connection_context *ctxt )
+{
+    WNetProvider *provider;
+    DWORD index, ret = WN_NO_NETWORK;
+    BOOL redirect = FALSE;
+    WCHAR letter[3] = {'Z', ':', 0};
+    NETRESOURCEW netres;
+
+    if (!providerTable || providerTable->numProviders == 0)
+        return WN_NO_NETWORK;
+
+    if (!ctxt->resource)
+        return ERROR_INVALID_PARAMETER;
+    netres = *ctxt->resource;
+
+    if (!netres.lpLocalName && (ctxt->flags & CONNECT_REDIRECT))
     {
-        ret = WNetUseConnectionW(hwndOwner, pRes, passW, userIDW, dwFlags,
-                                 accessNameW, &bufferSize, lpResult);
-        if (ret == WN_SUCCESS)
+        if (netres.dwType != RESOURCETYPE_DISK && netres.dwType != RESOURCETYPE_PRINT)
+            return ERROR_BAD_DEV_TYPE;
+
+        if (netres.dwType == RESOURCETYPE_PRINT)
         {
-            if (lpAccessName && lpBufferSize && *lpBufferSize && accessNameW)
-            {
-                len = WideCharToMultiByte(CP_ACP, 0, accessNameW, -1, NULL, 0, NULL, NULL);
-                if (len)
-                {
-                    if (len <= *lpBufferSize)
-                        WideCharToMultiByte(CP_ACP, 0, accessNameW, -1, lpAccessName, len, NULL, NULL);
-                    else
-                    {
-                        WNetCancelConnectionW(accessNameW, TRUE);
-                        *lpBufferSize = len;
-                       ret = WN_MORE_DATA;
-                    }
-                }
-            }
+            FIXME("Local device selection is not implemented for printers.\n");
+            return WN_NO_NETWORK;
         }
+
+        redirect = TRUE;
+        netres.lpLocalName = letter;
     }
 
-    if (lpNetResource)
+    if (ctxt->flags & CONNECT_INTERACTIVE)
+        return ERROR_BAD_NET_NAME;
+
+    if ((ret = ctxt->pre_set_accessname(ctxt, netres.lpLocalName)))
+        return ret;
+
+    if (netres.lpProvider)
     {
-        HeapFree(GetProcessHeap(), 0, resourcesW.lpLocalName);
-        HeapFree(GetProcessHeap(), 0, resourcesW.lpRemoteName);
-        HeapFree(GetProcessHeap(), 0, resourcesW.lpComment);
-        HeapFree(GetProcessHeap(), 0, resourcesW.lpProvider);
+        index = _findProviderIndexW(netres.lpProvider);
+        if (index == BAD_PROVIDER_INDEX)
+            return ERROR_BAD_PROVIDER;
+
+        provider = &providerTable->table[index];
+        ret = wnet_use_provider(ctxt, &netres, provider, redirect);
+    }
+    else
+    {
+        for (index = 0; index < providerTable->numProviders; index++)
+        {
+            provider = &providerTable->table[index];
+            ret = wnet_use_provider(ctxt, &netres, provider, redirect);
+            if (ret == WN_SUCCESS || ret == WN_ALREADY_CONNECTED)
+                break;
+        }
     }
-    HeapFree(GetProcessHeap(), 0, passW);
-    HeapFree(GetProcessHeap(), 0, userIDW);
-    HeapFree(GetProcessHeap(), 0, accessNameW);
 
     return ret;
 }
@@ -1657,74 +1889,128 @@ DWORD WINAPI WNetUseConnectionA( HWND hwndOwner, LPNETRESOURCEA lpNetResource,
 DWORD WINAPI WNetUseConnectionW( HWND hwndOwner, NETRESOURCEW *resource, LPCWSTR password,
     LPCWSTR userid, DWORD flags, LPWSTR accessname, DWORD *buffer_size, DWORD *result )
 {
-    WNetProvider *provider;
-    DWORD index, ret, caps;
+    struct use_connection_context ctxt;
 
     TRACE( "(%p, %p, %p, %s, 0x%08X, %p, %p, %p)\n",
            hwndOwner, resource, password, debugstr_w(userid), flags,
            accessname, buffer_size, result );
 
-    if (!providerTable || providerTable->numProviders == 0)
-        return WN_NO_NETWORK;
+    ctxt.hwndOwner = hwndOwner;
+    ctxt.resource = resource;
+    ctxt.resourceA = NULL;
+    ctxt.password = (WCHAR*)password;
+    ctxt.userid = (WCHAR*)userid;
+    ctxt.flags = flags;
+    ctxt.accessname = accessname;
+    ctxt.buffer_size = buffer_size;
+    ctxt.result = result;
+    ctxt.pre_set_accessname = use_connection_pre_set_accessnameW;
+    ctxt.set_accessname = use_connection_set_accessnameW;
 
-    if (!resource)
-        return ERROR_INVALID_PARAMETER;
-
-    if (!resource->lpProvider)
-    {
-        FIXME("Networking provider selection is not implemented.\n");
-        return WN_NO_NETWORK;
-    }
-
-    if (!resource->lpLocalName && (flags & CONNECT_REDIRECT))
-    {
-        FIXME("Locale device selection is not implemented.\n");
-        return WN_NO_NETWORK;
-    }
-
-    if (flags & CONNECT_INTERACTIVE)
-        return ERROR_BAD_NET_NAME;
-
-    index = _findProviderIndexW(resource->lpProvider);
-    if (index == BAD_PROVIDER_INDEX)
-        return ERROR_BAD_PROVIDER;
-
-    provider = &providerTable->table[index];
-    caps = provider->getCaps(WNNC_CONNECTION);
-    if (!(caps & (WNNC_CON_ADDCONNECTION | WNNC_CON_ADDCONNECTION3)))
-        return ERROR_BAD_PROVIDER;
+    return wnet_use_connection(&ctxt);
+}
 
-    if (accessname && buffer_size && *buffer_size)
+static DWORD use_connection_pre_set_accessnameA(struct use_connection_context *ctxt, WCHAR *local_name)
+{
+    if (ctxt->accessname && ctxt->buffer_size && *ctxt->buffer_size)
     {
         DWORD len;
 
-        if (resource->lpLocalName)
-            len = strlenW(resource->lpLocalName);
+        if (local_name)
+            len = WideCharToMultiByte(CP_ACP, 0, local_name, -1, NULL, 0, NULL, NULL) - 1;
         else
-            len = strlenW(resource->lpRemoteName);
+            len = strlen(ctxt->resourceA->lpRemoteName);
 
-        if (++len > *buffer_size)
+        if (++len > *ctxt->buffer_size)
         {
-            *buffer_size = len;
+            *ctxt->buffer_size = len;
             return ERROR_MORE_DATA;
         }
     }
     else
-        accessname = NULL;
+        ctxt->accessname = NULL;
 
-    ret = WN_ACCESS_DENIED;
-    if ((caps & WNNC_CON_ADDCONNECTION3) && provider->addConnection3)
-        ret = provider->addConnection3(hwndOwner, resource, (LPWSTR)password, (LPWSTR)userid, flags);
-    else if ((caps & WNNC_CON_ADDCONNECTION) && provider->addConnection)
-        ret = provider->addConnection(resource, (LPWSTR)password, (LPWSTR)userid);
+    return ERROR_SUCCESS;
+}
 
-    if (ret == WN_SUCCESS && accessname)
+static void use_connection_set_accessnameA(struct use_connection_context *ctxt, WCHAR *local_name)
+{
+    char *accessname = ctxt->accessname;
+    if (local_name)
     {
-        if (resource->lpLocalName)
-            strcpyW(accessname, resource->lpLocalName);
-        else
-            strcpyW(accessname, resource->lpRemoteName);
+        WideCharToMultiByte(CP_ACP, 0, local_name, -1, accessname, *ctxt->buffer_size, NULL, NULL);
+        if (ctxt->result)
+            *ctxt->result = CONNECT_LOCALDRIVE;
     }
+    else
+        strcpy(accessname, ctxt->resourceA->lpRemoteName);
+}
+
+static LPWSTR strdupAtoW( LPCSTR str )
+{
+    LPWSTR ret;
+    INT len;
+
+    if (!str) return NULL;
+    len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
+    ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
+    if (ret) MultiByteToWideChar( CP_ACP, 0, str, -1, ret, len );
+    return ret;
+}
+
+static void netresource_a_to_w( NETRESOURCEA *resourceA, NETRESOURCEW *resourceW )
+{
+    resourceW->dwScope = resourceA->dwScope;
+    resourceW->dwType = resourceA->dwType;
+    resourceW->dwDisplayType = resourceA->dwDisplayType;
+    resourceW->dwUsage = resourceA->dwUsage;
+    resourceW->lpLocalName = strdupAtoW(resourceA->lpLocalName);
+    resourceW->lpRemoteName = strdupAtoW(resourceA->lpRemoteName);
+    resourceW->lpComment = strdupAtoW(resourceA->lpComment);
+    resourceW->lpProvider = strdupAtoW(resourceA->lpProvider);
+}
+
+static void free_netresourceW( NETRESOURCEW *resource )
+{
+    HeapFree(GetProcessHeap(), 0, resource->lpLocalName);
+    HeapFree(GetProcessHeap(), 0, resource->lpRemoteName);
+    HeapFree(GetProcessHeap(), 0, resource->lpComment);
+    HeapFree(GetProcessHeap(), 0, resource->lpProvider);
+}
+
+/*****************************************************************
+ *  WNetUseConnectionA [MPR.@]
+ */
+DWORD WINAPI WNetUseConnectionA( HWND hwndOwner, NETRESOURCEA *resource,
+    LPCSTR password, LPCSTR userid, DWORD flags, LPSTR accessname,
+    DWORD *buffer_size, DWORD *result )
+{
+    struct use_connection_context ctxt;
+    NETRESOURCEW resourceW;
+    DWORD ret;
+
+    TRACE( "(%p, %p, %p, %s, 0x%08X, %p, %p, %p)\n", hwndOwner, resource, password, debugstr_a(userid), flags,
+        accessname, buffer_size, result );
+
+    netresource_a_to_w(resource, &resourceW);
+
+    ctxt.hwndOwner = hwndOwner;
+    ctxt.resource = &resourceW;
+    ctxt.resourceA = resource;
+    ctxt.password = strdupAtoW(password);
+    ctxt.userid = strdupAtoW(userid);
+    ctxt.flags = flags;
+    ctxt.accessname = accessname;
+    ctxt.buffer_size = buffer_size;
+    ctxt.result = result;
+    ctxt.pre_set_accessname = use_connection_pre_set_accessnameA;
+    ctxt.set_accessname = use_connection_set_accessnameA;
+
+    ret = wnet_use_connection(&ctxt);
+
+    free_netresourceW(&resourceW);
+    HeapFree(GetProcessHeap(), 0, ctxt.password);
+    HeapFree(GetProcessHeap(), 0, ctxt.userid);
 
     return ret;
 }
@@ -1734,9 +2020,7 @@ DWORD WINAPI WNetUseConnectionW( HWND hwndOwner, NETRESOURCEW *resource, LPCWSTR
  */
 DWORD WINAPI WNetCancelConnectionA( LPCSTR lpName, BOOL fForce )
 {
-    FIXME( "(%s, %d), stub\n", debugstr_a(lpName), fForce );
-
-    return WN_SUCCESS;
+    return WNetCancelConnection2A(lpName, 0, fForce);
 }
 
 /*********************************************************************
@@ -1744,9 +2028,7 @@ DWORD WINAPI WNetCancelConnectionA( LPCSTR lpName, BOOL fForce )
  */
 DWORD WINAPI WNetCancelConnectionW( LPCWSTR lpName, BOOL fForce )
 {
-    FIXME( "(%s, %d), stub\n", debugstr_w(lpName), fForce );
-
-    return WN_SUCCESS;
+    return WNetCancelConnection2W(lpName, 0, fForce);
 }
 
 /*********************************************************************
@@ -1754,9 +2036,15 @@ DWORD WINAPI WNetCancelConnectionW( LPCWSTR lpName, BOOL fForce )
  */
 DWORD WINAPI WNetCancelConnection2A( LPCSTR lpName, DWORD dwFlags, BOOL fForce )
 {
-    FIXME( "(%s, %08X, %d), stub\n", debugstr_a(lpName), dwFlags, fForce );
+    DWORD ret;
+    WCHAR * name = strdupAtoW(lpName);
+    if (!name)
+        return ERROR_NOT_CONNECTED;
 
-    return WN_SUCCESS;
+    ret = WNetCancelConnection2W(name, dwFlags, fForce);
+    HeapFree(GetProcessHeap(), 0, name);
+
+    return ret;
 }
 
 /*********************************************************************
@@ -1764,9 +2052,26 @@ DWORD WINAPI WNetCancelConnection2A( LPCSTR lpName, DWORD dwFlags, BOOL fForce )
  */
 DWORD WINAPI WNetCancelConnection2W( LPCWSTR lpName, DWORD dwFlags, BOOL fForce )
 {
-    FIXME( "(%s, %08X, %d), stub\n", debugstr_w(lpName), dwFlags, fForce );
+    DWORD ret = WN_NO_NETWORK;
+    DWORD index;
 
-    return WN_SUCCESS;
+    if (providerTable != NULL)
+    {
+        for (index = 0; index < providerTable->numProviders; index++)
+        {
+            if(providerTable->table[index].getCaps(WNNC_CONNECTION) &
+                WNNC_CON_CANCELCONNECTION)
+            {
+                if (providerTable->table[index].cancelConnection)
+                    ret = providerTable->table[index].cancelConnection((LPWSTR)lpName, fForce);
+                else
+                    ret = WN_NO_NETWORK;
+                if (ret == WN_SUCCESS || ret == WN_OPEN_FILES)
+                    break;
+            }
+        }
+    }
+    return ret;
 }
 
 /*****************************************************************
@@ -1893,6 +2198,7 @@ DWORD WINAPI WNetGetConnectionA( LPCSTR lpLocalName,
 /* find the network connection for a given drive; helper for WNetGetConnection */
 static DWORD get_drive_connection( WCHAR letter, LPWSTR remote, LPDWORD size )
 {
+#ifndef __REACTOS__
     char buffer[1024];
     struct mountmgr_unix_drive *data = (struct mountmgr_unix_drive *)buffer;
     HANDLE mgr;
@@ -1935,6 +2241,32 @@ static DWORD get_drive_connection( WCHAR letter, LPWSTR remote, LPDWORD size )
     }
     CloseHandle( mgr );
     return ret;
+#else
+    DWORD ret = WN_NO_NETWORK;
+    DWORD index;
+    WCHAR local[3] = {letter, ':', 0};
+
+    if (providerTable != NULL)
+    {
+        for (index = 0; index < providerTable->numProviders; index++)
+        {
+            if(providerTable->table[index].getCaps(WNNC_CONNECTION) &
+                WNNC_CON_GETCONNECTIONS)
+            {
+                if (providerTable->table[index].getConnection)
+                    ret = providerTable->table[index].getConnection(
+                        local, remote, size);
+                else
+                    ret = WN_NO_NETWORK;
+                if (ret == WN_SUCCESS || ret == WN_MORE_DATA)
+                    break;
+            }
+        }
+    }
+    if (ret)
+        SetLastError(ret);
+    return ret;
+#endif
 }
 
 /**************************************************************************
@@ -2045,7 +2377,7 @@ DWORD WINAPI WNetGetUniversalNameA ( LPCSTR lpLocalPath, DWORD dwInfoLevel,
         break;
     }
     case REMOTE_NAME_INFO_LEVEL:
-        err = WN_NO_NETWORK;
+        err = WN_NOT_CONNECTED;
         break;
 
     default:
@@ -2092,7 +2424,7 @@ DWORD WINAPI WNetGetUniversalNameW ( LPCWSTR lpLocalPath, DWORD dwInfoLevel,
         break;
     }
     case REMOTE_NAME_INFO_LEVEL:
-        err = WN_NOT_CONNECTED;
+        err = WN_NO_NETWORK;
         break;
 
     default: