Conectar una unidad de red con C#

Conectar una unidad de red con C#

No puedo creer que el framework no tenga implementado de serie una forma de conectar una unidad de red.

Me lo crea o no, a día de hoy es así y lo peor es que la propia MicroSoft me lo confirma: http://support.microsoft.com/kb/173011 - en este link cuentan los mismo que yo aqui! (pero peor!).

En un proyecto reciente he tenido precisamente esta necesidad - conectar una unidad de red. Alguien podría pensar en conectarla manualmente y utilizarla sin más, pero mi problema era algo más complejo ya que el programa era un servicio (los servicios se ejecutan en una cuenta de usuario diferente por lo que no es posible utilizar una unidad de red conectada manualmente).

Conectar una unidad de red programaticamente no es fácil, tenemos que utilizar directamente el API de Windows por lo que al final tuve que crear una clase especifica y encapsular la funcionalidad - seguro que a más de uno le será utilidad.

Debemos declarar primero la estructura NETRESOURCE. La definición es la siguiente :

 

using System.Runtime.InteropServices;

 

public struct NETRESOURCE {

[MarshalAs(UnmanagedType.I4)]

public int dwScope;

[MarshalAs(UnmanagedType.I4)]

public int dwType;

[MarshalAs(UnmanagedType.I4)]

public int dwDisplayType;

[MarshalAs(UnmanagedType.I4)]

public int dwUsage;

[MarshalAs(UnmanagedType.LPWStr)]

public string lpLocalName;

[MarshalAs(UnmanagedType.LPWStr)]

public string lpRemoteName;

[MarshalAs(UnmanagedType.LPWStr)]

public string lpComment;

[MarshalAs(UnmanagedType.LPWStr)]

public string lpProvider;

}

Es muy importante decorar los parametros con MarshalAs al tipo correcto, ya que si no lo hacemos podremos obtener errores de muy dificil detección. El atributo  MarshalAs  indica a que tipo "no controlado" deben convertirse los tipos "controlados" de .NET.

Bien, ahora creamos una clase de utilidad a la que llamamos UnidadRedUtil , y definimos una serie de constantes necesarias para trabajar correctamente con  NETRESOURCE.

 

using System.Runtime.InteropServices;

 

class UnidadRedUtil

{

 

const int NO_ERROR = 0;

const int CONNECT_UPDATE_PROFILE = 1;

const int RESOURCETYPE_DISK = 1;

 

// Constantes para NETRESOURCE

const int RESOURCETYPE_PRINT = 2;

const int RESOURCETYPE_ANY = 0;

const int RESOURCE_CONNECTED = 1;

const int RESOURCE_REMEMBERED = 3;

const int RESOURCE_GLOBALNET = 2;

const int RESOURCEDISPLAYTYPE_DOMAIN = 1;

const int RESOURCEDISPLAYTYPE_GENERIC = 0;

const int RESOURCEDISPLAYTYPE_SERVER = 2;

const int RESOURCEDISPLAYTYPE_SHARE = 3;

const int RESOURCEUSAGE_CONNECTABLE = 1;

const int RESOURCEUSAGE_CONTAINER = 2;

 

// Códigos de error:

const int ERROR_ACCESS_DENIED = 5;

const int ERROR_ALREADY_ASSIGNED = 85;

const int ERROR_BAD_DEV_TYPE = 66;

const int ERROR_BAD_DEVICE = 1200;

const int ERROR_BAD_NET_NAME = 67;

const int ERROR_BAD_PROFILE = 1206;

const int ERROR_BAD_PROVIDER = 1204;

const int ERROR_BUSY = 170;

const int ERROR_CANCELLED = 1223;

const int ERROR_CANNOT_OPEN_PROFILE = 1205;

const int ERROR_DEVICE_ALREADY_REMEMBERED = 1202;

const int ERROR_EXTENDED_ERROR = 1208;

const int ERROR_INVALID_PASSWORD = 86;

const int ERROR_NO_NET_OR_BAD_PATH = 1203;

 

//Importar las API de Windows ...

 

//Codigo para añadir la unidad de red ...

 

//Codigo para desconectar la unidad de red ...

 

}

Lo siguiente que debemos hacer es en nuestro archivo de clase es importar las llamadas a las API de Windows que nos van a permitir trabajar con las unidades de red.

 

[DllImport("mpr.dll",

EntryPoint = "WNetAddConnection2W",

CharSet = CharSet.Unicode )]

private static extern int

AddConnection(

ref NETRESOURCE lpNetResource,

[MarshalAs(UnmanagedType.LPWStr)]

string Password,

[MarshalAs(UnmanagedType.LPWStr)]

string lpUserName,

[MarshalAs(UnmanagedType.I4 )]

int dwFlags);

 

[DllImport("mpr.dll",

EntryPoint = "WNetCancelConnection2W",

CharSet = CharSet.Unicode)]

private static extern int

CancelConnection(

[MarshalAs(UnmanagedType.LPWStr)]

string lpName,

[MarshalAs(UnmanagedType.I4)]

int dwFlags,

[MarshalAs(UnmanagedType.Bool)]

bool fForce);

La referencia de estas funciones podemos encontrarla en la propia página de MicroSoft

Por úlitmo añadimos a nuestra clase los métodos para conectar y desconectar la unidad de red. Primero conectar:

 

public void MapResource(string driveLetter, string path)

{

long result;

NETRESOURCE netResource = new NETRESOURCE();

netResource.dwScope = RESOURCE_GLOBALNET;

netResource.dwType = RESOURCETYPE_DISK;

netResource.dwDisplayType = RESOURCEDISPLAYTYPE_SHARE;

netResource.dwUsage = RESOURCEUSAGE_CONNECTABLE;

 

 

netResource.lpLocalName = driveLetter; // por ejemplo: "F:"

netResource.lpRemoteName = path; /* por ejemplo:

"\\ServerName\ShareName" */

 

  // en este caso lo he puesto aqui, pero mejor deberiamos

// parametrizar estos datos!

string user = "usuario";

string pwd = "la password!";

result = AddConnection(ref netResource,

pwd, user, CONNECT_UPDATE_PROFILE);

if (result != NO_ERROR)

{

// Sacar un mensaje mas amigable ya es tarea vuestra :-)

throw new ApplicationException(

String.Format(

"No se ha podido conectar, codigo de error {0}", result));

}

}

Y luego desconectar:

 

public void UnMapResource(string driverLetter)

{

long result = NO_ERROR;

result = CancelConnection(driverLetter,

CONNECT_UPDATE_PROFILE, true);

if (result != NO_ERROR)

{

// Sacar un mensaje mas amigable ya es tarea vuestra :-)

throw new ApplicationException(

String.Format(

"No se ha podido desconectar, codigo de error {0}", result));

}

}

Mejorar los errores de la excepcion para hacerlos más amigables os lo dejo a vosotros ...

Por último vamos a hacer un formulario que conectará y desconectará unidades de red utilizando nuestra clase.

El formulario tendrá dos controles en los que indicaresmos la letra de unidad (debe estar libre!) y la ruta a mapear.

El código para los botones de conectar y desconectar es el siguiente.

 

private void btnConectar_Click(object sender, EventArgs e)

{

UnidadRedUtil unidadRed = new UnidadRedUtil();

try

{

unidadRed.MapResource(txtLetra.Text, txtRuta.Text);

}

catch (Exception ex)

{

MessageBox.Show(ex.ToString());

}

}

 

private void btnDesconectar_Click(object sender, EventArgs e)

{

UnidadRedUtil unidadRed = new UnidadRedUtil();

try

{

unidadRed.UnMapResource (txtLetra.Text);

}

catch (Exception ex)

{

MessageBox.Show(ex.ToString());

}

}

Links relacionados (y utilizados como soporte para la realizacion de este articulo!)

Saludos,

Devjoker

Pedro  Herrarte  Sánchez
Conectar una unidad de red con C#
Pedro Herrarte Sánchez

Pedro Herrarte, es consultor independiente, ofreciendo servicios de consultoría, análisis, desarrollo y formación. Posee mas de diez años de experiencia trabajando para las principales empresas de España. Es especialista en tecnologías .NET, entornos Web (ASP.NET, ASP.NET MVC,jQuery, HTML5), bases de datos (SQL Server y ORACLE) e integración de sistemas. Es experto en desarrollo (C#, VB.Net, T-SQL, PL/SQL, , ASP, CGI , C, Pro*C, Java, Essbase, Vignette, PowerBuilder y Visual Basic ...) y bases de datos (SQL Server y ORACLE). Pedro es MCP y MAP 2012, es fundador, diseñador y programador de www.devjoker.com..
Fecha de alta:02/09/2009
Última actualizacion:10/02/2012
Visitas totales:13012
Valorar el contenido:
Últimas consultas realizadas en los foros
Últimas preguntas sin contestar en los foros de devjoker.com