157 votes

Accès à un fichier partagé (UNC) à partir d'un domaine distant non fiable avec des informations d'identification

Nous avons rencontré une situation intéressante qui doit être résolue, et mes recherches n'ont rien donné. Je fais donc appel à l'aide de la communauté de l'OS.

Le problème est le suivant : nous avons besoin d'accéder par programmation à un fichier partagé qui n'est pas dans notre domaine, et qui n'est pas dans un domaine externe de confiance via le partage de fichiers à distance / UNC. Naturellement, nous devons fournir des informations d'identification à la machine distante.

En général, on résout ce problème de deux manières :

  1. Mettez en correspondance le partage de fichiers avec un lecteur et fournissez les informations d'identification à ce moment-là. Cela se fait généralement à l'aide de la commande NET USE ou les fonctions Win32 qui dupliquent la commande NET USE .
  2. Accédez au fichier avec un chemin UNC comme si l'ordinateur distant était sur le domaine et assurez-vous que le compte sous lequel le programme s'exécute est dupliqué (y compris le mot de passe) sur la machine distante comme un utilisateur local. En gros, exploitez le fait que Windows fournira automatiquement les informations d'identification de l'utilisateur actuel lorsque ce dernier tentera d'accéder à un fichier partagé.
  3. N'utilisez pas le partage de fichiers à distance. Utilisez le FTP (ou un autre moyen) pour transférer le fichier, travaillez dessus localement, puis retransférez-le.

Pour des raisons diverses et variées, nos architectes sécurité/réseau ont rejeté les deux premières approches. La deuxième approche est évidemment une faille de sécurité ; si l'ordinateur distant est compromis, l'ordinateur local est maintenant en danger. La première approche n'est pas satisfaisante car le lecteur nouvellement monté est une ressource partagée disponible pour d'autres programmes sur l'ordinateur local pendant l'accès aux fichiers par le programme. Même s'il est tout à fait possible de rendre cette situation temporaire, il s'agit toujours d'une faille à leurs yeux.

Ils sont ouverts à la troisième option, mais les administrateurs du réseau distant insistent sur SFTP plutôt que FTPS, et FtpWebRequest ne supporte que FTPS. SFTP est l'option la plus respectueuse du pare-feu et il existe quelques bibliothèques que je pourrais utiliser pour cette approche, mais je préfère réduire mes dépendances si je le peux.

J'ai cherché sur MSDN un moyen géré ou win32 d'utiliser le partage de fichiers à distance, mais je n'ai rien trouvé d'utile.

Et donc je demande : Y a-t-il un autre moyen ? Ai-je manqué une fonction win32 super secrète qui fait ce que je veux ? Ou dois-je poursuivre une variante de l'option 3 ?

0 votes

J'ai vu l'option 3 mise en œuvre avec Outils JScape d'une manière assez simple. Vous pouvez l'essayer. Il n'est pas gratuit, mais il fait son travail.

0 votes

J'ai résolu le problème avec l'approche de l'usurpation d'identité, mais c'est entre deux machines en dehors d'un domaine. Je ne sais pas si cela poserait un problème de parler d'un domaine à un ordinateur hors du domaine. stackoverflow.com/questions/17221476/

185voto

Brian R. Bondy Points 141769

La façon de résoudre votre problème est d'utiliser une API Win32 appelée WNetUseConnection .
Utilisez cette fonction pour vous connecter à un chemin UNC avec authentification, et NON pour mapper un lecteur. .

Cela vous permettra de vous connecter à une machine distante, même si elle ne se trouve pas sur le même domaine, et même si elle a un nom d'utilisateur et un mot de passe différents.

Une fois que vous aurez utilisé WNetUseConnection, vous pourrez accéder au fichier via un chemin UNC comme si vous étiez sur le même domaine. Le meilleur moyen est probablement de passer par les partages intégrés à l'administration.
Exemple : \\computername\c $ \program fichiers \Folder\file.txt

Voici un exemple de code C# qui utilise WNetUseConnection.
Remarque : pour la NetResource, vous devez passer null pour lpLocalName et lpProvider. Le dwType doit être RESOURCETYPE_DISK. L'élément lpRemoteName doit être \\ComputerName.

using System;
using System.Runtime.InteropServices ;
using System.Threading;

namespace ExtremeMirror
{
    public class PinvokeWindowsNetworking
    {
        #region Consts
        const int RESOURCE_CONNECTED = 0x00000001;
        const int RESOURCE_GLOBALNET = 0x00000002;
        const int RESOURCE_REMEMBERED = 0x00000003;

        const int RESOURCETYPE_ANY = 0x00000000;
        const int RESOURCETYPE_DISK = 0x00000001;
        const int RESOURCETYPE_PRINT = 0x00000002;

        const int RESOURCEDISPLAYTYPE_GENERIC = 0x00000000;
        const int RESOURCEDISPLAYTYPE_DOMAIN = 0x00000001;
        const int RESOURCEDISPLAYTYPE_SERVER = 0x00000002;
        const int RESOURCEDISPLAYTYPE_SHARE = 0x00000003;
        const int RESOURCEDISPLAYTYPE_FILE = 0x00000004;
        const int RESOURCEDISPLAYTYPE_GROUP = 0x00000005;

        const int RESOURCEUSAGE_CONNECTABLE = 0x00000001;
        const int RESOURCEUSAGE_CONTAINER = 0x00000002;

        const int CONNECT_INTERACTIVE = 0x00000008;
        const int CONNECT_PROMPT = 0x00000010;
        const int CONNECT_REDIRECT = 0x00000080;
        const int CONNECT_UPDATE_PROFILE = 0x00000001;
        const int CONNECT_COMMANDLINE = 0x00000800;
        const int CONNECT_CMD_SAVECRED = 0x00001000;

        const int CONNECT_LOCALDRIVE = 0x00000100;
        #endregion

        #region Errors
        const int NO_ERROR = 0;

        const int ERROR_ACCESS_DENIED = 5;
        const int ERROR_ALREADY_ASSIGNED = 85;
        const int ERROR_BAD_DEVICE = 1200;
        const int ERROR_BAD_NET_NAME = 67;
        const int ERROR_BAD_PROVIDER = 1204;
        const int ERROR_CANCELLED = 1223;
        const int ERROR_EXTENDED_ERROR = 1208;
        const int ERROR_INVALID_ADDRESS = 487;
        const int ERROR_INVALID_PARAMETER = 87;
        const int ERROR_INVALID_PASSWORD = 1216;
        const int ERROR_MORE_DATA = 234;
        const int ERROR_NO_MORE_ITEMS = 259;
        const int ERROR_NO_NET_OR_BAD_PATH = 1203;
        const int ERROR_NO_NETWORK = 1222;

        const int ERROR_BAD_PROFILE = 1206;
        const int ERROR_CANNOT_OPEN_PROFILE = 1205;
        const int ERROR_DEVICE_IN_USE = 2404;
        const int ERROR_NOT_CONNECTED = 2250;
        const int ERROR_OPEN_FILES  = 2401;

        private struct ErrorClass 
        {
            public int num;
            public string message;
            public ErrorClass(int num, string message) 
            {
                this.num = num;
                this.message = message;
            }
        }

        // Created with excel formula:
        // ="new ErrorClass("&A1&", """&PROPER(SUBSTITUTE(MID(A1,7,LEN(A1)-6), "_", " "))&"""), "
        private static ErrorClass[] ERROR_LIST = new ErrorClass[] {
            new ErrorClass(ERROR_ACCESS_DENIED, "Error: Access Denied"), 
            new ErrorClass(ERROR_ALREADY_ASSIGNED, "Error: Already Assigned"), 
            new ErrorClass(ERROR_BAD_DEVICE, "Error: Bad Device"), 
            new ErrorClass(ERROR_BAD_NET_NAME, "Error: Bad Net Name"), 
            new ErrorClass(ERROR_BAD_PROVIDER, "Error: Bad Provider"), 
            new ErrorClass(ERROR_CANCELLED, "Error: Cancelled"), 
            new ErrorClass(ERROR_EXTENDED_ERROR, "Error: Extended Error"), 
            new ErrorClass(ERROR_INVALID_ADDRESS, "Error: Invalid Address"), 
            new ErrorClass(ERROR_INVALID_PARAMETER, "Error: Invalid Parameter"), 
            new ErrorClass(ERROR_INVALID_PASSWORD, "Error: Invalid Password"), 
            new ErrorClass(ERROR_MORE_DATA, "Error: More Data"), 
            new ErrorClass(ERROR_NO_MORE_ITEMS, "Error: No More Items"), 
            new ErrorClass(ERROR_NO_NET_OR_BAD_PATH, "Error: No Net Or Bad Path"), 
            new ErrorClass(ERROR_NO_NETWORK, "Error: No Network"), 
            new ErrorClass(ERROR_BAD_PROFILE, "Error: Bad Profile"), 
            new ErrorClass(ERROR_CANNOT_OPEN_PROFILE, "Error: Cannot Open Profile"), 
            new ErrorClass(ERROR_DEVICE_IN_USE, "Error: Device In Use"), 
            new ErrorClass(ERROR_EXTENDED_ERROR, "Error: Extended Error"), 
            new ErrorClass(ERROR_NOT_CONNECTED, "Error: Not Connected"), 
            new ErrorClass(ERROR_OPEN_FILES, "Error: Open Files"), 
        };

        private static string getErrorForNumber(int errNum) 
        {
            foreach (ErrorClass er in ERROR_LIST) 
            {
                if (er.num == errNum) return er.message;
            }
            return "Error: Unknown, " + errNum;
        }
        #endregion

        [DllImport("Mpr.dll")] private static extern int WNetUseConnection(
            IntPtr hwndOwner,
            NETRESOURCE lpNetResource,
            string lpPassword,
            string lpUserID,
            int dwFlags,
            string lpAccessName,
            string lpBufferSize,
            string lpResult
        );

        [DllImport("Mpr.dll")] private static extern int WNetCancelConnection2(
            string lpName,
            int dwFlags,
            bool fForce
        );

        [StructLayout(LayoutKind.Sequential)] private class NETRESOURCE
        { 
            public int dwScope = 0;
            public int dwType = 0;
            public int dwDisplayType = 0;
            public int dwUsage = 0;
            public string lpLocalName = "";
            public string lpRemoteName = "";
            public string lpComment = "";
            public string lpProvider = "";
        }

        public static string connectToRemote(string remoteUNC, string username, string password) 
        {
            return connectToRemote(remoteUNC, username, password, false);
        }

        public static string connectToRemote(string remoteUNC, string username, string password, bool promptUser) 
        {
            NETRESOURCE nr = new NETRESOURCE();
            nr.dwType = RESOURCETYPE_DISK;
            nr.lpRemoteName = remoteUNC;
            //          nr.lpLocalName = "F:";

            int ret;
            if (promptUser) 
                ret = WNetUseConnection(IntPtr.Zero, nr, "", "", CONNECT_INTERACTIVE | CONNECT_PROMPT, null, null, null);
            else 
                ret = WNetUseConnection(IntPtr.Zero, nr, password, username, 0, null, null, null);

            if (ret == NO_ERROR) return null;
            return getErrorForNumber(ret);
        }

        public static string disconnectRemote(string remoteUNC) 
        {
            int ret = WNetCancelConnection2(remoteUNC, CONNECT_UPDATE_PROFILE, false);
            if (ret == NO_ERROR) return null;
            return getErrorForNumber(ret);
        }
    }
}

0 votes

Existe-t-il un moyen d'utiliser des fonctions comme celles-ci pour ouvrir/fermer explicitement des connexions à une machine du réseau en utilisant les informations d'identification actuelles, c'est-à-dire sans fournir le nom d'utilisateur et le mot de passe ? Je suis particulièrement intéressé par la fermeture d'une connexion après l'accès à un partage de fichiers.

0 votes

Pas pour la connexion, sauf si l'ordinateur lui-même n'a pas de nom d'utilisateur ou de mot de passe. Pour la déconnexion, bien sûr que vous pouvez. Vous pouvez même le faire via la ligne de commande.

1 votes

Bonjour Brian. La documentation dont vous donnez le lien indique que vous pouvez passer NULL pour le nom d'utilisateur et le mot de passe afin d'utiliser les informations d'identification actuelles. Je vais faire quelques tests pour voir si cela fonctionne.

137voto

GameScripting Points 2922

Pour les personnes à la recherche d'une solution rapide, vous pouvez utiliser l'application NetworkShareAccesser J'ai écrit récemment (sur la base cette réponse (merci beaucoup !)) :

Utilisation :

using (NetworkShareAccesser.Access(REMOTE_COMPUTER_NAME, DOMAIN, USER_NAME, PASSWORD))
{
    File.Copy(@"C:\Some\File\To\copy.txt", @"\\REMOTE-COMPUTER\My\Shared\Target\file.txt");
}

AVERTISSEMENT : Veuillez vous assurer que Dispose de la NetworkShareAccesser est appelé (même si votre application se plante !), sinon une connexion ouverte restera sur Windows. Vous pouvez voir toutes les connexions ouvertes en ouvrant la fenêtre cmd et entrer net use .

Le code :

/// <summary>
/// Provides access to a network share.
/// </summary>
public class NetworkShareAccesser : IDisposable
{
    private string _remoteUncName;
    private string _remoteComputerName;

    public string RemoteComputerName
    {
        get
        {
            return this._remoteComputerName;
        }
        set
        {
            this._remoteComputerName = value;
            this._remoteUncName = @"\\" + this._remoteComputerName;
        }
    }

    public string UserName
    {
        get;
        set;
    }
    public string Password
    {
        get;
        set;
    }

    #region Consts

    private const int RESOURCE_CONNECTED = 0x00000001;
    private const int RESOURCE_GLOBALNET = 0x00000002;
    private const int RESOURCE_REMEMBERED = 0x00000003;

    private const int RESOURCETYPE_ANY = 0x00000000;
    private const int RESOURCETYPE_DISK = 0x00000001;
    private const int RESOURCETYPE_PRINT = 0x00000002;

    private const int RESOURCEDISPLAYTYPE_GENERIC = 0x00000000;
    private const int RESOURCEDISPLAYTYPE_DOMAIN = 0x00000001;
    private const int RESOURCEDISPLAYTYPE_SERVER = 0x00000002;
    private const int RESOURCEDISPLAYTYPE_SHARE = 0x00000003;
    private const int RESOURCEDISPLAYTYPE_FILE = 0x00000004;
    private const int RESOURCEDISPLAYTYPE_GROUP = 0x00000005;

    private const int RESOURCEUSAGE_CONNECTABLE = 0x00000001;
    private const int RESOURCEUSAGE_CONTAINER = 0x00000002;

    private const int CONNECT_INTERACTIVE = 0x00000008;
    private const int CONNECT_PROMPT = 0x00000010;
    private const int CONNECT_REDIRECT = 0x00000080;
    private const int CONNECT_UPDATE_PROFILE = 0x00000001;
    private const int CONNECT_COMMANDLINE = 0x00000800;
    private const int CONNECT_CMD_SAVECRED = 0x00001000;

    private const int CONNECT_LOCALDRIVE = 0x00000100;

    #endregion

    #region Errors

    private const int NO_ERROR = 0;

    private const int ERROR_ACCESS_DENIED = 5;
    private const int ERROR_ALREADY_ASSIGNED = 85;
    private const int ERROR_BAD_DEVICE = 1200;
    private const int ERROR_BAD_NET_NAME = 67;
    private const int ERROR_BAD_PROVIDER = 1204;
    private const int ERROR_CANCELLED = 1223;
    private const int ERROR_EXTENDED_ERROR = 1208;
    private const int ERROR_INVALID_ADDRESS = 487;
    private const int ERROR_INVALID_PARAMETER = 87;
    private const int ERROR_INVALID_PASSWORD = 1216;
    private const int ERROR_MORE_DATA = 234;
    private const int ERROR_NO_MORE_ITEMS = 259;
    private const int ERROR_NO_NET_OR_BAD_PATH = 1203;
    private const int ERROR_NO_NETWORK = 1222;

    private const int ERROR_BAD_PROFILE = 1206;
    private const int ERROR_CANNOT_OPEN_PROFILE = 1205;
    private const int ERROR_DEVICE_IN_USE = 2404;
    private const int ERROR_NOT_CONNECTED = 2250;
    private const int ERROR_OPEN_FILES = 2401;

    #endregion

    #region PInvoke Signatures

    [DllImport("Mpr.dll")]
    private static extern int WNetUseConnection(
        IntPtr hwndOwner,
        NETRESOURCE lpNetResource,
        string lpPassword,
        string lpUserID,
        int dwFlags,
        string lpAccessName,
        string lpBufferSize,
        string lpResult
        );

    [DllImport("Mpr.dll")]
    private static extern int WNetCancelConnection2(
        string lpName,
        int dwFlags,
        bool fForce
        );

    [StructLayout(LayoutKind.Sequential)]
    private class NETRESOURCE
    {
        public int dwScope = 0;
        public int dwType = 0;
        public int dwDisplayType = 0;
        public int dwUsage = 0;
        public string lpLocalName = "";
        public string lpRemoteName = "";
        public string lpComment = "";
        public string lpProvider = "";
    }

    #endregion

    /// <summary>
    /// Creates a NetworkShareAccesser for the given computer name. The user will be promted to enter credentials
    /// </summary>
    /// <param name="remoteComputerName"></param>
    /// <returns></returns>
    public static NetworkShareAccesser Access(string remoteComputerName)
    {
        return new NetworkShareAccesser(remoteComputerName);
    }

    /// <summary>
    /// Creates a NetworkShareAccesser for the given computer name using the given domain/computer name, username and password
    /// </summary>
    /// <param name="remoteComputerName"></param>
    /// <param name="domainOrComuterName"></param>
    /// <param name="userName"></param>
    /// <param name="password"></param>
    public static NetworkShareAccesser Access(string remoteComputerName, string domainOrComuterName, string userName, string password)
    {
        return new NetworkShareAccesser(remoteComputerName,
                                        domainOrComuterName + @"\" + userName,
                                        password);
    }

    /// <summary>
    /// Creates a NetworkShareAccesser for the given computer name using the given username (format: domainOrComputername\Username) and password
    /// </summary>
    /// <param name="remoteComputerName"></param>
    /// <param name="userName"></param>
    /// <param name="password"></param>
    public static NetworkShareAccesser Access(string remoteComputerName, string userName, string password)
    {
        return new NetworkShareAccesser(remoteComputerName, 
                                        userName,
                                        password);
    }

    private NetworkShareAccesser(string remoteComputerName)
    {
        RemoteComputerName = remoteComputerName;               

        this.ConnectToShare(this._remoteUncName, null, null, true);
    }

    private NetworkShareAccesser(string remoteComputerName, string userName, string password)
    {
        RemoteComputerName = remoteComputerName;
        UserName = userName;
        Password = password;

        this.ConnectToShare(this._remoteUncName, this.UserName, this.Password, false);
    }

    private void ConnectToShare(string remoteUnc, string username, string password, bool promptUser)
    {
        NETRESOURCE nr = new NETRESOURCE
        {
            dwType = RESOURCETYPE_DISK,
            lpRemoteName = remoteUnc
        };

        int result;
        if (promptUser)
        {
            result = WNetUseConnection(IntPtr.Zero, nr, "", "", CONNECT_INTERACTIVE | CONNECT_PROMPT, null, null, null);
        }
        else
        {
            result = WNetUseConnection(IntPtr.Zero, nr, password, username, 0, null, null, null);
        }

        if (result != NO_ERROR)
        {
            throw new Win32Exception(result);
        }
    }

    private void DisconnectFromShare(string remoteUnc)
    {
        int result = WNetCancelConnection2(remoteUnc, CONNECT_UPDATE_PROFILE, false);
        if (result != NO_ERROR)
        {
            throw new Win32Exception(result);
        }
    }

    /// <summary>
    /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
    /// </summary>
    /// <filterpriority>2</filterpriority>
    public void Dispose()
    {
        this.DisconnectFromShare(this._remoteUncName);
    }
}

5 votes

Vous devez également using System.Runtime.InteropServices; y using System.ComponentModel; para DllImport y Win32Exception

1 votes

Cette solution a mis fin à mes longues journées de recherche. Merci ! !! Fonctionne très bien comme prévu.

0 votes

Juste ce qu'il me fallait. Thx

16voto

Jacob Points 9117

AFAIK, vous n'avez pas besoin de carte le chemin UNC vers une lettre de lecteur afin d'établir les informations d'identification pour un serveur. J'utilisais régulièrement des scripts batch comme :

net use \\myserver /user:username password

:: do something with \\myserver\the\file\i\want.xml

net use /delete \\my.server.com

Cependant, tout programme fonctionnant sur le même compte que votre programme sera toujours en mesure d'accéder à tout ce que l'on peut trouver dans la base de données. username:password a accès. Une solution possible pourrait être d'isoler votre programme dans son propre compte utilisateur local (l'accès UNC est local au compte qui a appelé NET USE ).

Note : L'utilisation de SMB pour plusieurs domaines n'est pas une bonne utilisation de la technologie, selon moi. Si la sécurité est si importante, le fait que SMB ne soit pas crypté est un peu un frein en soi.

0 votes

Si vous avez raison de dire que l'accès UNC n'est disponible que pour le compte qui a appelé NET USE cela pourrait être une approche viable. Êtes-vous certain que nous devons utiliser un compte local, cependant ? Ne serait-ce pas le NET USE soit local à la machine sur laquelle il a été appelé ? Vous m'avez donné une bonne piste de recherche

0 votes

À ma connaissance, et je peux me tromper, l'accès UNC ne sera disponible que pour le principal de sécurité spécifique (compte SAM, etc.) sous lequel l'appel à NET USE a été effectué. Vous pouvez le vérifier en utilisant RunAs pour mapper le chemin d'accès, puis en essayant d'y accéder à partir d'un autre compte.

0 votes

Dans mon cas, j'ai dû utiliser net use \\myserver /user:username@domain password car l'utilisateur est sur un domaine différent.

4voto

Adam Robinson Points 88472

Bien que je ne le sache pas moi-même, j'espère que le numéro 2 est incorrect... J'aime à penser que Windows ne va pas donner AUTOMATIQUEMENT mes informations de connexion (et surtout mon mot de passe !) à n'importe quelle machine, et encore moins à une machine qui ne fait pas partie de ma confiance.

Quoi qu'il en soit, avez-vous exploré l'architecture de l'usurpation d'identité ? Votre code va ressembler à ça :

using (System.Security.Principal.WindowsImpersonationContext context = System.Security.Principal.WindowsIdentity.Impersonate(token))
{
    // Do network operations here

    context.Undo();
}

Dans ce cas, le token est un IntPtr. Pour obtenir une valeur pour cette variable, vous devez appeler la fonction non gérée LogonUser de l'API Windows. Un rapide voyage dans pinvoke.net nous donne la signature suivante :

[System.Runtime.InteropServices.DllImport("advapi32.dll", SetLastError = true)]
public static extern bool LogonUser(
    string lpszUsername,
    string lpszDomain,
    string lpszPassword,
    int dwLogonType,
    int dwLogonProvider,
    out IntPtr phToken
);

Le nom d'utilisateur, le domaine et le mot de passe devraient être assez évidents. Jetez un coup d'oeil aux différentes valeurs qui peuvent être passées à dwLogonType et dwLogonProvider pour déterminer celle qui convient le mieux à vos besoins.

Ce code n'a pas été testé, car je n'ai pas de deuxième domaine où je peux vérifier, mais cela devrait vous mettre sur la bonne voie.

7 votes

L'usurpation d'identité ne fonctionne pas lorsque vous essayez d'utiliser un identifiant de connexion provenant d'un domaine non fiable. L'identifiant de l'utilisateur doit être capable de se connecter localement.

0 votes

Oui, nous avons essayé cette voie, ça s'est terminé comme @Moose le dit : Le domaine n'est pas fiable et donc l'usurpation d'identité ne fonctionnera pas.

0 votes

Oui, dès que j'ai vu ce commentaire, c'est pourquoi j'ai posté la réponse en utilisant NetUseAdd (la principale différence entre cette fonction et les fonctions WNetUseConnection et WNetAddConnection étant que NetUseAdd ne rend pas la connexion visible dans l'explorateur Windows).

4voto

Adam Robinson Points 88472

Plutôt que WNetUseConnection, je recommande NetUseAdd . WNetUseConnection est une ancienne fonction qui a été remplacée par WNetUseConnection2 et WNetUseConnection3, mais toutes ces fonctions créent un périphérique réseau visible dans l'Explorateur Windows. NetUseAdd est l'équivalent de l'appel de net use dans une invite DOS pour s'authentifier sur un ordinateur distant.

Si vous appelez NetUseAdd, les tentatives ultérieures d'accès au répertoire devraient aboutir.

1 votes

@Adam Robinson : Ce n'est pas vrai. Il n'existe pas de WNetUseConnection2 ni de WNetUseConnection3. Je pense que vous pensez à WNetAddConnection qui a été remplacé par WNetAddConnection2 et WnetAddConnection3. De plus, l'information que vous avez donnée à ce sujet n'est pas vraie.

0 votes

WNetUseConnection est comme WNetAddConnection3, mais il a aussi une capacité optionnelle de créer un lecteur local mappé. Que vous n'êtes pas obligé d'utiliser.

0 votes

@BrianR.Bondy Ils existent en effet, mais ne sont pas implémentés en C#. Source : docs.microsoft.com/da-dk/Windows/win32/api/lmuse/ Citation : "Vous pouvez également utiliser les fonctions WNetAddConnection2 et WNetAddConnection3 pour rediriger un périphérique local vers une ressource réseau."

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X