Conectar y desconectar unidades de red

Unidad de red

Algunas veces nos encontramos con la necesidad de que nuestra aplicación acceda a archivos almacenados en un ordenador diferente, aunque conectado a la misma red.

En esta entrada veremos cómo conectarse y cómo desconectarse a una unidad de red, usando el API de Windows. Mientras exista esa conexión, podremos acceder a ficheros en la unidad remota del mismo modo que a cualquier fichero local.

Básicamente usaremos dos funciones del API de Windows: WNetAddConnection2 y WNetCancelConnection2, para crear y eliminar una conexión, respectivamente.

Estas funciones están en la librería de Windows "Mpr", por lo tanto, tendremos que incluirla en la fase de enlazado de nuestro programa.

Para el programa de ejemplo usaremos una carpeta en una unidad de disco local, por ejemplo, C:\temp. Aunque si estamos en una red podremos conectar a cualquier recurso compartido de otros ordenadores, siempre que nuestro usuario tenga los permisos adecuados.

Antes de poder crear una unidad de red deberemos compartir ese recurso en la red, para ello usaremos el explorador de archivos de Windows, y accederemos a las propiedades de la carpeta que queramos compartir. Vamos a la pestaña de "Compartir", y pulsamos el botón de "Compartir". En el siguiente cuadro de diálogo nos permitirá elegir con qué usuarios queremos compartir el recurso, y una vez elegidos, nos mostrará los datos relativos a ese recurso. En nuestro ejemplo algo como:

temp (\\<etiqueta>)
\\<etiqueta>\temp

Donde <etiqueta> es el nombre de nuestro ordenador.

Este nombre se puede sustituir por la IP, en nuestro ejemplo"127.0.0.1", o por el nombre que tenga asignado en el DNS local, por ejemplo "localhost".

En general, la etiqueta corresponderá al nombre de un equipo conectado a la red, y el nombre de la unidad o carpeta compartida será diferente.

Las funciones para conectarse y desconectarse a una unidad remota tendrán esta forma, más o menos:

bool ConectarRecurso()
{
    NETRESOURCE nr;
    DWORD ret;
    const char *letra = "Z:";
    const char *recurso = "\\\\localhost\\temp";
    const char *usuario = "usuario";
    const char *password = "contraseña";
    bool conexionRemota;

    nr.dwType = RESOURCETYPE_ANY;
    nr.lpLocalName = (LPSTR)letra;
    nr.lpRemoteName = (LPSTR)recurso;
    nr.lpProvider = NULL;
    ret = WNetAddConnection2(&nr, password, usuario, 0);

    if(ret !=NO_ERROR)
        switch(ret) {
            case ERROR_ACCESS_DENIED:
               std::printf("Access to the network resource was denied.");
               break;
            case ERROR_ALREADY_ASSIGNED:
               std::printf("The local device specified by lpLocalName is already connected to a network resource.");
               break;
            case ERROR_BAD_DEV_TYPE:
               std::printf("The type of local device and the type of network resource do not match.");
               break;
            case ERROR_BAD_DEVICE:
               std::printf("The value specified by lpLocalName is invalid.");
               break;
            case ERROR_BAD_NET_NAME:
               std::printf("The value specified by lpRemoteName is not acceptable to any network resource provider. The resource name is invalid, or the named resource cannot be located.");
               break;
            case ERROR_BAD_PROFILE:
               std::printf("The user profile is in an incorrect format.");
               break;
            case ERROR_BAD_PROVIDER:
               std::printf("The value specified by lpProvider does not match any provider.");
               break;
            case ERROR_BAD_USERNAME:
               std::printf("The specified user name is not valid.");
               break;
            case ERROR_BUSY:
               std::printf("The router or provider is busy, possibly initializing. The caller should retry.");
               break;
            case ERROR_CANCELLED:
               std::printf("The attempt to make the connection was cancelled by the user through a dialog box from one of the network resource providers, or by a called resource.");
               break;
            case ERROR_CANNOT_OPEN_PROFILE:
               std::printf("The system is unable to open the user profile to process persistent connections.");
               break;
            case ERROR_DEVICE_ALREADY_REMEMBERED:
               std::printf("An entry for the device specified in lpLocalName is already in the user profile.");
               break;
            case ERROR_EXTENDED_ERROR:
               std::printf("A network-specific error occured. Call the WNetGetLastError function to get a description of the error.");
               break;
            case ERROR_INVALID_ADDRESS:
               std::printf("An attempt was made to access an invalid address.");
               break;
            case ERROR_INVALID_PARAMETER:
               std::printf("A parameter is incorrect.");
               break;
            case ERROR_INVALID_PASSWORD:
               std::printf("The specified password is invalid.");
               break;
            case ERROR_LOGON_FAILURE:
               std::printf("A logon failure because of an unknown user name or a bad password.");
               break;
            case ERROR_NO_NET_OR_BAD_PATH:
               std::printf("A network component has not started, or the specified name could not be handled.");
               break;
            case ERROR_NO_NETWORK:
               std::printf("There is no network present.");
               break;
            default:
               std::printf("Error %d, desconocido", ret);
               break;
        }
    conexionRemota = ((ret == NO_ERROR) || (ret == ERROR_ALREADY_ASSIGNED));
    return conexionRemota;
}

void DesconectarRecurso()
{
    const char *letra = "Z:";

    WNetCancelConnection2(letra, 0, TRUE);
}

Habría que sustituir "usuario" y "contraseña" por los valores adecuados en cada caso.

Nombre Fichero Fecha Tamaño Contador Descarga
Unidad de red UnidadRed.zip 2020-09-27 3263 bytes 478