Connect to share ShareDrive with c# - c#

I want to connect with c# to a share drive.
The following code only works if entered path into the explorer before start the program (no password was needed). Then it will work till a restart the worksttion. Does anyone know how I can avoid this?
string _rootDirectory = #"\\mysites.inside-share.xxx.com#SSL\my\xxx\Documents\xxx\";
Directory.CreateDirectory(_rootDirectory);
Error Message: A first chance exception of type 'System.IO.IOException' occurred in mscorlib.dll
An unhandled exception of type 'System.IO.IOException' occurred in mscorlib.dll
Additional information: The network path was not found.
Environment: PC which tries to connect to a company sharepoint server. The program is running by a user

/// <summary>
/// Accessing network share folder.
/// </summary>
public class NetUse
{
string _sharename, _user, _password;
public NetUse(string ShareFolder,string Username, string Password)
{
_sharename = ShareFolder;
_user = Username;
_password = Password;
}
[DllImport("mpr.dll")]
private static extern int WNetAddConnection2A(ref NetResource pstNetRes, string psPassword, string psUsername, int piFlags);
[DllImport("mpr.dll")]
private static extern int WNetCancelConnection2A(string psName, int piFlags, int pfForce);
[StructLayout(LayoutKind.Sequential)]
private struct NetResource
{
public int iScope;
public int iType;
public int iDisplayType;
public int iUsage;
public string sLocalName;
public string sRemoteName;
public string sComment;
public string sProvider;
}
private const int RESOURCETYPE_DISK = 0x1;
public void Login()
{
string destinationDirectory = _sharename;
NetResource nr = new NetResource();
nr.iScope = 2;
nr.iType = RESOURCETYPE_DISK;
nr.iDisplayType = 3;
nr.iUsage = 1;
nr.sRemoteName = destinationDirectory;
nr.sLocalName = null;
int flags = 0;
int rc = WNetAddConnection2A(ref nr, _password, _user, flags);
if (rc != 0) throw new Win32Exception(rc);
}
public void Logout()
{
string destinationDirectory = _sharename;
int flags = 0;
int rc = WNetCancelConnection2A(destinationDirectory, flags, Convert.ToInt32(false));
}
}
usage:
var _NetUse = new NetUse(#"\\mysites.inside-share.xxx.com#SSL\my\xxx\Documents\xxx", "<username>", "<password>");
_NetUse.Login();
//Do the operations here
_NetUse.Logout();
Hope it helps.

Related

How to store a password to authenticate to mySQL [duplicate]

In a WPF application, I would like to provide the typical "Remember Me" option to remember credentials and use them automatically next time the application is launched.
Using a one-way hash is clearly not an option, and while I can store credentials in isolated storage or in the registry, there is one issue to deal with when encrypting the credentials.
If I use a symmetric key encryption algorithm, I will need to store the key somewhere. And if the key is, for example, hardcoded in memory, then I imagine it would be easy to disassemble the .NET assemblies and find it.
What is the best way to encrypt credentials in .NET and keep them secure, keeping the encryption key completely out of reach?
Here's a summary of my blog post: How to store a password on Windows?
You can use the Data Protection API and its .NET implementation (ProtectedData) to encrypt the password. Here's an example:
public static string Protect(string str)
{
byte[] entropy = Encoding.ASCII.GetBytes(Assembly.GetExecutingAssembly().FullName);
byte[] data = Encoding.ASCII.GetBytes(str);
string protectedData = Convert.ToBase64String(ProtectedData.Protect(data, entropy, DataProtectionScope.CurrentUser));
return protectedData;
}
public static string Unprotect(string str)
{
byte[] protectedData = Convert.FromBase64String(str);
byte[] entropy = Encoding.ASCII.GetBytes(Assembly.GetExecutingAssembly().FullName);
string data = Encoding.ASCII.GetString(ProtectedData.Unprotect(protectedData, entropy, DataProtectionScope.CurrentUser));
return data;
}
Or you can use the Windows Credential Manager (This is the way I prefer because it allows users to backup/restore/edit their credentials even if your application has no such functionality). I've created a NuGet package Meziantou.Framework.Win32.CredentialManager. How to use it:
CredentialManager.WriteCredential("ApplicationName", "username", "Pa$$w0rd", CredentialPersistence.Session);
var cred = CredentialManager.ReadCredential("ApplicationName");
Assert.AreEqual("username", cred.UserName);
Assert.AreEqual("Pa$$w0rd", cred.Password);
CredentialManager.DeleteCredential("ApplicationName");
Original answer with the native API wrapper (A more recent version of this is available on GitHub):
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;
using System.Text;
using System.ComponentModel;
public static class CredentialManager
{
public static Credential ReadCredential(string applicationName)
{
IntPtr nCredPtr;
bool read = CredRead(applicationName, CredentialType.Generic, 0, out nCredPtr);
if (read)
{
using (CriticalCredentialHandle critCred = new CriticalCredentialHandle(nCredPtr))
{
CREDENTIAL cred = critCred.GetCredential();
return ReadCredential(cred);
}
}
return null;
}
private static Credential ReadCredential(CREDENTIAL credential)
{
string applicationName = Marshal.PtrToStringUni(credential.TargetName);
string userName = Marshal.PtrToStringUni(credential.UserName);
string secret = null;
if (credential.CredentialBlob != IntPtr.Zero)
{
secret = Marshal.PtrToStringUni(credential.CredentialBlob, (int)credential.CredentialBlobSize / 2);
}
return new Credential(credential.Type, applicationName, userName, secret);
}
public static int WriteCredential(string applicationName, string userName, string secret)
{
byte[] byteArray = Encoding.Unicode.GetBytes(secret);
if (byteArray.Length > 512)
throw new ArgumentOutOfRangeException("secret", "The secret message has exceeded 512 bytes.");
CREDENTIAL credential = new CREDENTIAL();
credential.AttributeCount = 0;
credential.Attributes = IntPtr.Zero;
credential.Comment = IntPtr.Zero;
credential.TargetAlias = IntPtr.Zero;
credential.Type = CredentialType.Generic;
credential.Persist = (UInt32)CredentialPersistence.Session;
credential.CredentialBlobSize = (UInt32)Encoding.Unicode.GetBytes(secret).Length;
credential.TargetName = Marshal.StringToCoTaskMemUni(applicationName);
credential.CredentialBlob = Marshal.StringToCoTaskMemUni(secret);
credential.UserName = Marshal.StringToCoTaskMemUni(userName ?? Environment.UserName);
bool written = CredWrite(ref credential, 0);
int lastError = Marshal.GetLastWin32Error();
Marshal.FreeCoTaskMem(credential.TargetName);
Marshal.FreeCoTaskMem(credential.CredentialBlob);
Marshal.FreeCoTaskMem(credential.UserName);
if (written)
return 0;
throw new Exception(string.Format("CredWrite failed with the error code {0}.", lastError));
}
public static IReadOnlyList<Credential> EnumerateCrendentials()
{
List<Credential> result = new List<Credential>();
int count;
IntPtr pCredentials;
bool ret = CredEnumerate(null, 0, out count, out pCredentials);
if (ret)
{
for (int n = 0; n < count; n++)
{
IntPtr credential = Marshal.ReadIntPtr(pCredentials, n * Marshal.SizeOf(typeof(IntPtr)));
result.Add(ReadCredential((CREDENTIAL)Marshal.PtrToStructure(credential, typeof(CREDENTIAL))));
}
}
else
{
int lastError = Marshal.GetLastWin32Error();
throw new Win32Exception(lastError);
}
return result;
}
[DllImport("Advapi32.dll", EntryPoint = "CredReadW", CharSet = CharSet.Unicode, SetLastError = true)]
static extern bool CredRead(string target, CredentialType type, int reservedFlag, out IntPtr credentialPtr);
[DllImport("Advapi32.dll", EntryPoint = "CredWriteW", CharSet = CharSet.Unicode, SetLastError = true)]
static extern bool CredWrite([In] ref CREDENTIAL userCredential, [In] UInt32 flags);
[DllImport("advapi32", SetLastError = true, CharSet = CharSet.Unicode)]
static extern bool CredEnumerate(string filter, int flag, out int count, out IntPtr pCredentials);
[DllImport("Advapi32.dll", EntryPoint = "CredFree", SetLastError = true)]
static extern bool CredFree([In] IntPtr cred);
private enum CredentialPersistence : uint
{
Session = 1,
LocalMachine,
Enterprise
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
private struct CREDENTIAL
{
public UInt32 Flags;
public CredentialType Type;
public IntPtr TargetName;
public IntPtr Comment;
public System.Runtime.InteropServices.ComTypes.FILETIME LastWritten;
public UInt32 CredentialBlobSize;
public IntPtr CredentialBlob;
public UInt32 Persist;
public UInt32 AttributeCount;
public IntPtr Attributes;
public IntPtr TargetAlias;
public IntPtr UserName;
}
sealed class CriticalCredentialHandle : CriticalHandleZeroOrMinusOneIsInvalid
{
public CriticalCredentialHandle(IntPtr preexistingHandle)
{
SetHandle(preexistingHandle);
}
public CREDENTIAL GetCredential()
{
if (!IsInvalid)
{
CREDENTIAL credential = (CREDENTIAL)Marshal.PtrToStructure(handle, typeof(CREDENTIAL));
return credential;
}
throw new InvalidOperationException("Invalid CriticalHandle!");
}
protected override bool ReleaseHandle()
{
if (!IsInvalid)
{
CredFree(handle);
SetHandleAsInvalid();
return true;
}
return false;
}
}
}
public enum CredentialType
{
Generic = 1,
DomainPassword,
DomainCertificate,
DomainVisiblePassword,
GenericCertificate,
DomainExtended,
Maximum,
MaximumEx = Maximum + 1000,
}
public class Credential
{
private readonly string _applicationName;
private readonly string _userName;
private readonly string _password;
private readonly CredentialType _credentialType;
public CredentialType CredentialType
{
get { return _credentialType; }
}
public string ApplicationName
{
get { return _applicationName; }
}
public string UserName
{
get { return _userName; }
}
public string Password
{
get { return _password; }
}
public Credential(CredentialType credentialType, string applicationName, string userName, string password)
{
_applicationName = applicationName;
_userName = userName;
_password = password;
_credentialType = credentialType;
}
public override string ToString()
{
return string.Format("CredentialType: {0}, ApplicationName: {1}, UserName: {2}, Password: {3}", CredentialType, ApplicationName, UserName, Password);
}
}
Usage:
WriteCredential("ApplicationName", "Meziantou", "Passw0rd");
Console.WriteLine(ReadCredential("Demo"));

WNetAddConnection2 fails but net use succeeds

I am trying to Connect to a network resource using WNetAddConnection2 but its failing with error code ERROR_BAD_NET_NAME (Error Code 67).
But if use "net use" command with the same user name and password its succeeding though.
Any clues ?
public class NETRESOURCE
{
public int dwScope;
public int dwType;
public int dwDisplayType;
public int dwUsage;
public string LocalName;
public string RemoteName;
public string Comment;
public string Provider;
}
[DllImport("mpr.dll")]
public static extern int WNetAddConnection2(NETRESOURCE netResource, string password, string username, int flags);
public class ServerConnect
{
private string serverName;
private string userName;
private string password;
public int nResult;
public ServerConnect()
{
serverName = "";
userName = "";
password = "";
nResult = -1;
}
public void SetConnectionParam(string serName, string uName, string pwd)
{
serverName = serName;
userName = uName;
password = pwd;
}
public void Connect()
{
NETRESOURCE myResource = new NETRESOURCE();
myResource.dwScope = 0;
myResource.dwType = 0x00000001; //RESOURCETYPE_DISK
myResource.dwDisplayType = 0;
myResource.LocalName = "";
myResource.RemoteName = serverName;
myResource.dwUsage = 0;
myResource.Comment = "";
myResource.Provider = "";
nResult = WNetAddConnection2(myResource, password, userName, 0);
}
};
public void ConnectToDataServer(string serverName)
{
ServerConnect oConnect = new ServerConnect();
oConnect.SetConnectionParam(serverName, #"Domain\username", #"password");
Thread connectionThread = new Thread(new ThreadStart(oConnect.Connect));
connectionThread.Start();
while (!connectionThread.IsAlive) ;// Wait till thread starts and Alive
int nCount = 0;
while (connectionThread.IsAlive)
{
Thread.Sleep(500);
nCount++;
if (nCount == 10) // wait for 5 secs
{
//WriteLine(this, "Failed to Connect to to server " + serverName , LogStatus.Error);
connectionThread.Abort();
Thread.Sleep(1000);
}
}
//WriteLine(this, oConnect.nResult.ToString(), LogStatus.Success);
}
public void ConnectToServer()
{
ConnectToDataServer(#"\\ServerName");
}
For one, we would need to see your code, as WNetAddConnection2 is a Windows functions and thus P/Invoked, and P/Invoke operations are always very, very hairy.
On the note of assuming you've invoked correctly, there could be permissions in the way (this is especially true if you're running Windows 8). Try making sure to Run as Administrator when you luanch VS, as this will usually extend the same credentials to executing applications, whereas the console often has different permissions.

Is there a simple way of sending an email with attachments using the default mail client?

My issue is that I need to attach files with C# to the default mail client and show it to the user, much like using mailto:.
I read this post on the subject, but there are several issues:
I do not want to use mailto because attachments are not officially supported.
When using System.Net.Mail and the SMTP class (code supplied in the accepted answer), I am not sure how to pop up the message for the user to handle instead of just mailing it. Not sure if this is even possible.
Also when using the solution above (#2) I'm not sure how to get the user's email server.
In an answer supplied further down, a Code Project solution is presented using a custom wrapper for MAPI32.DLL. The issue here is that the license agreement specified by the writer of the article for this solution conflicts with the requirements that I am under for my project.
Due to time restrictions I cannot write my own MAPI wrapper
So, are there any other simple solutions to this problem? Is there another simple way to pop up the default mail client with the attachments pre-populated with .NET? Maybe another MAPI wrapper, but one with a VERY lenient license?
A .NET mapi wrapper is indeed the best solution - there are many results returned for a google of "mapi .net wrapper", I am sure one of these will have a suitable license:
http://www.codeproject.com/KB/IP/CMapiEx.aspx - CDDL license
If you are happy with attachments that are not embedded here's a whole lot of code that will do the job. This is more for others who may come looking than OP who I am certain must have already found an alternative. Add a comment if something is missing and I'll add the necessary stuff. Enjoy!
public class MailMessage
{
#region Constants and Fields
private readonly string _body;
private readonly string _subject;
private readonly List<MapiFileDesc> _attachments;
private readonly List<MapiRecipDesc> _recipients;
#endregion
#region Constructors and Destructors
private MailMessage()
{
}
public MailMessage(
string subject, string body, IEnumerable<MailAttachment> attachments, IEnumerable<MailRecipient> recipients)
{
this._subject = subject;
this._body = body;
this._attachments = new List<MapiFileDesc>();
this._recipients = new List<MapiRecipDesc>();
if (attachments != null)
{
foreach (var attachment in attachments)
{
_attachments.Add(attachment.GetMapiFileDesc());
}
}
if (recipients != null)
{
foreach (var recipient in recipients)
{
_recipients.Add(recipient.GetMapiRecipDesc());
}
}
}
#endregion
#region Public Methods
public void ShowDialog()
{
int result = this.ShowMail();
if (!IsSuccess(result))
{
throw new Exception(GetMapiErrorMessage(result));
}
}
#endregion
#region Methods
private int ShowMail()
{
var message = new MapiMessage();
message.Subject = this._subject;
message.NoteText = this._body;
int attachmentCount;
message.Files = AllocMapiDescArray(_attachments, out attachmentCount);
message.FileCount = attachmentCount;
int recipientCount;
message.Recipients = AllocMapiDescArray(_recipients, out recipientCount);
message.RecipientCount = recipientCount;
int error = Mapi32.MAPISendMail(IntPtr.Zero, IntPtr.Zero, message, Mapi32.MAPI_DIALOG, 0);
DeallocMapiDescArray<MapiFileDesc>(message.Files, message.FileCount);
DeallocMapiDescArray<MapiRecipDesc>(message.Recipients, message.RecipientCount);
return error;
}
private static IntPtr AllocMapiDescArray<T>(ICollection<T> mapiDescCollection, out int mapiDescCount)
{
IntPtr mapiMapiDescArrayPtr = IntPtr.Zero;
mapiDescCount = 0;
if (mapiDescCollection != null && mapiDescCollection.Count > 0)
{
int mapiDescSize = Marshal.SizeOf(typeof(T));
mapiMapiDescArrayPtr = Marshal.AllocHGlobal(mapiDescCollection.Count * mapiDescSize);
var tmp = (int)mapiMapiDescArrayPtr;
foreach (var mapiDesc in mapiDescCollection)
{
Marshal.StructureToPtr(mapiDesc, (IntPtr)tmp, false);
tmp += mapiDescSize;
}
mapiDescCount = mapiDescCollection.Count;
}
return mapiMapiDescArrayPtr;
}
private static void DeallocMapiDescArray<T>(IntPtr mapiDescArrayPtr, int mapiDescArrayCount)
{
if (mapiDescArrayPtr != IntPtr.Zero)
{
int mapiDescSize = Marshal.SizeOf(typeof(T));
var tmp = (int)mapiDescArrayPtr;
for (int i = 0; i < mapiDescArrayCount; i++)
{
Marshal.DestroyStructure((IntPtr)tmp, typeof(T));
tmp += mapiDescSize;
}
Marshal.FreeHGlobal(mapiDescArrayPtr);
}
}
private static bool IsSuccess(int errorCode)
{
return (errorCode == Mapi32.SUCCESS_SUCCESS || errorCode == Mapi32.MAPI_USER_ABORT);
}
private static string GetMapiErrorMessage(int errorCode)
{
// This should be localized
string error = string.Empty;
switch (errorCode)
{
case Mapi32.MAPI_USER_ABORT:
error = "User Aborted.";
break;
case Mapi32.MAPI_E_FAILURE:
error = "MAPI Failure.";
break;
case Mapi32.MAPI_E_LOGIN_FAILURE:
error = "Login Failure.";
break;
case Mapi32.MAPI_E_DISK_FULL:
error = "MAPI Disk full.";
break;
case Mapi32.MAPI_E_INSUFFICIENT_MEMORY:
error = "MAPI Insufficient memory.";
break;
case Mapi32.MAPI_E_BLK_TOO_SMALL:
error = "MAPI Block too small.";
break;
case Mapi32.MAPI_E_TOO_MANY_SESSIONS:
error = "MAPI Too many sessions.";
break;
case Mapi32.MAPI_E_TOO_MANY_FILES:
error = "MAPI too many files.";
break;
case Mapi32.MAPI_E_TOO_MANY_RECIPIENTS:
error = "MAPI too many recipients.";
break;
case Mapi32.MAPI_E_ATTACHMENT_NOT_FOUND:
error = "MAPI Attachment not found.";
break;
case Mapi32.MAPI_E_ATTACHMENT_OPEN_FAILURE:
error = "MAPI Attachment open failure.";
break;
case Mapi32.MAPI_E_ATTACHMENT_WRITE_FAILURE:
error = "MAPI Attachment Write Failure.";
break;
case Mapi32.MAPI_E_UNKNOWN_RECIPIENT:
error = "MAPI Unknown recipient.";
break;
case Mapi32.MAPI_E_BAD_RECIPTYPE:
error = "MAPI Bad recipient type.";
break;
case Mapi32.MAPI_E_NO_MESSAGES:
error = "MAPI No messages.";
break;
case Mapi32.MAPI_E_INVALID_MESSAGE:
error = "MAPI Invalid message.";
break;
case Mapi32.MAPI_E_TEXT_TOO_LARGE:
error = "MAPI Text too large.";
break;
case Mapi32.MAPI_E_INVALID_SESSION:
error = "MAPI Invalid session.";
break;
case Mapi32.MAPI_E_TYPE_NOT_SUPPORTED:
error = "MAPI Type not supported.";
break;
case Mapi32.MAPI_E_AMBIGUOUS_RECIPIENT:
error = "MAPI Ambiguous recipient.";
break;
case Mapi32.MAPI_E_MESSAGE_IN_USE:
error = "MAPI Message in use.";
break;
case Mapi32.MAPI_E_NETWORK_FAILURE:
error = "MAPI Network failure.";
break;
case Mapi32.MAPI_E_INVALID_EDITFIELDS:
error = "MAPI Invalid edit fields.";
break;
case Mapi32.MAPI_E_INVALID_RECIPS:
error = "MAPI Invalid Recipients.";
break;
case Mapi32.MAPI_E_NOT_SUPPORTED:
error = "MAPI Not supported.";
break;
case Mapi32.MAPI_E_NO_LIBRARY:
error = "MAPI No Library.";
break;
case Mapi32.MAPI_E_INVALID_PARAMETER:
error = "MAPI Invalid parameter.";
break;
}
return string.Format("Error sending email. Error: {0} (code = {1}).", error, errorCode);
}
#endregion
}
public class MailAttachment
{
private string _attachmentFilePath;
public MailAttachment(string attachmentFilePath)
{
_attachmentFilePath = attachmentFilePath;
}
public MapiFileDesc GetMapiFileDesc()
{
var mapiFileDesc = new MapiFileDesc();
mapiFileDesc.Position = -1;
mapiFileDesc.Path = _attachmentFilePath;
mapiFileDesc.Name = Path.GetFileName(_attachmentFilePath);
return mapiFileDesc;
}
}
public class MailRecipient
{
#region Constants and Fields
public string _emailAddress;
public string _displayName;
public MailRecipientType _mailRecipientType = MailRecipientType.To;
#endregion
#region Constructors and Destructors
public MailRecipient(string emailAddress, string displayName, MailRecipientType mailRecipientType)
{
this._emailAddress = emailAddress;
this._displayName = displayName;
this._mailRecipientType = mailRecipientType;
}
#endregion
#region Methods
public MapiRecipDesc GetMapiRecipDesc()
{
var recipDesc = new MapiRecipDesc();
if (this._displayName == null)
{
recipDesc.Name = this._emailAddress;
}
else
{
recipDesc.Name = this._displayName;
recipDesc.Address = this._emailAddress;
}
recipDesc.RecipientClass = (int)this._mailRecipientType;
return recipDesc;
}
#endregion
}
public enum MailRecipientType
{
To = 1,
CC = 2,
BCC = 3
} ;
internal class Mapi32
{
#region Constants and Fields
public const int MAPI_DIALOG = 0x8;
public const int MAPI_E_AMBIGUOUS_RECIPIENT = 21;
public const int MAPI_E_ATTACHMENT_NOT_FOUND = 11;
public const int MAPI_E_ATTACHMENT_OPEN_FAILURE = 12;
public const int MAPI_E_ATTACHMENT_WRITE_FAILURE = 13;
public const int MAPI_E_BAD_RECIPTYPE = 15;
public const int MAPI_E_BLK_TOO_SMALL = 6;
public const int MAPI_E_DISK_FULL = 4;
public const int MAPI_E_FAILURE = 2;
public const int MAPI_E_INSUFFICIENT_MEMORY = 5;
public const int MAPI_E_INVALID_EDITFIELDS = 24;
public const int MAPI_E_INVALID_MESSAGE = 17;
public const int MAPI_E_INVALID_PARAMETER = 998;
public const int MAPI_E_INVALID_RECIPS = 25;
public const int MAPI_E_INVALID_SESSION = 19;
public const int MAPI_E_LOGIN_FAILURE = 3;
public const int MAPI_E_MESSAGE_IN_USE = 22;
public const int MAPI_E_NETWORK_FAILURE = 23;
public const int MAPI_E_NOT_SUPPORTED = 26;
public const int MAPI_E_NO_LIBRARY = 999;
public const int MAPI_E_NO_MESSAGES = 16;
public const int MAPI_E_TEXT_TOO_LARGE = 18;
public const int MAPI_E_TOO_MANY_FILES = 9;
public const int MAPI_E_TOO_MANY_RECIPIENTS = 10;
public const int MAPI_E_TOO_MANY_SESSIONS = 8;
public const int MAPI_E_TYPE_NOT_SUPPORTED = 20;
public const int MAPI_E_UNKNOWN_RECIPIENT = 14;
public const int MAPI_LOGON_UI = 0x1;
public const int MAPI_USER_ABORT = 1;
public const int SUCCESS_SUCCESS = 0;
#endregion
#region Public Methods
[DllImport("MAPI32.DLL", CharSet = CharSet.Ansi)]
public static extern int MAPILogon(IntPtr hwnd, string prf, string pw, int flg, int rsv, ref IntPtr sess);
[DllImport("MAPI32.DLL")]
public static extern int MAPISendMail(IntPtr session, IntPtr hwnd, MapiMessage message, int flg, int rsv);
#endregion
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public class MapiFileDesc
{
public int Reserved;
public int Flags;
public int Position;
public string Path;
public string Name;
public IntPtr Type = IntPtr.Zero;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public class MapiMessage
{
public int Reserved;
public string Subject;
public string NoteText;
public string MessageType;
public string DateReceived;
public string ConversationID;
public int Flags;
public IntPtr Originator = IntPtr.Zero;
public int RecipientCount;
public IntPtr Recipients = IntPtr.Zero;
public int FileCount;
public IntPtr Files = IntPtr.Zero;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public class MapiRecipDesc
{
public int Reserved;
public int RecipientClass;
public string Name;
public string Address;
public int eIDSize;
public IntPtr EntryID = IntPtr.Zero;
}

PInvoke of NetUserAdd returns 24

I am calling NetUserAdd and it is returning 24 for every call. Does anyone know what 24 stands for? It is kind of hard to debug it when I don't know what the error means.
I am calling this from an Windows XP machine running as a local admin. I am also a local admin on the target computer. I tried this with USER_INFO_1 and it worked fine. I just need the level of control given by USER_INFO_2.
This link shows the return values for this call. They are further defined here with numeric values. Sadly none of these values = 24.
I know this is a very specific question. I guess I am hoping to find a PInvoke/NetAddUser expert out there who can help me out.
Here is my code in case it matters:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct USER_INFO_2
{
public string name;
public string password;
public int password_age;
public int priv;
public string home_dir;
public string comment;
public int flags;
public string script_path;
public int auth_flags;
public string full_name;
public string usr_comment;
public string parms;
public string workstations;
public int last_logon;
public int last_logoff;
public ulong acct_expires;
public int max_storage;
public int units_per_week;
public IntPtr logon_hours; // This is a PBYTE
public int bad_pw_count;
public int num_logons;
public string logon_server;
public int country_code;
public int code_page;
}
[DllImport("netapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern int NetUserAdd(
[MarshalAs(UnmanagedType.LPWStr)] string servername,
UInt32 level,
ref USER_INFO_2 userinfo,
out UInt32 parm_err);
private static uint CreateUser(string computer, string userName,
string psswrd, string fullname)
{
const int UF_DONT_EXPIRE_PASSWD = 0x10000;
const int UF_ACCOUNTDISABLE = 0x000002;
const int USER_PRIV_GUEST = 0; // lmaccess.h:656
const int USER_PRIV_USER = 1; // lmaccess.h:657
const int USER_PRIV_ADMIN = 2; // lmaccess.h:658
USER_INFO_2 userInfo2 = new USER_INFO_2()
{
acct_expires = long.MaxValue,
auth_flags = 0, // Must be 0 for NetUserAddCalls
bad_pw_count = -1, //ignored for NetUserAdd calls
//code_page = ?,
comment = "ScanTrack Account",
//country_code = ?,
flags = UF_DONT_EXPIRE_PASSWD,// & UF_ACCOUNTDISABLE,
full_name = fullname,
home_dir = "",
last_logoff = 0,
last_logon = 0,
logon_hours = IntPtr.Zero, // User is given no logon time.
logon_server = "", //ignored for NetUserAdd calls
max_storage = 0,
name = userName,
num_logons = -1, //ignored for NetUserAdd calls
parms = "",
password = psswrd,
password_age = -1,
priv = USER_PRIV_GUEST,
script_path = "",
units_per_week = -1, //ignored for NetUserAdd calls
usr_comment = "",
workstations = ""
};
uint output;
NetUserAdd(computer, 2, ref userInfo2, out output);
return output;
}
private void button1_Click(object sender, EventArgs e)
{
string computer = "ComputerName";
string userName = "testName";
string psswrd = "!t3st4Stuff";
string fullname = "Test Name Full";
uint output = CreateUser(computer, userName, psswrd, fullname);
MessageBox.Show(output.ToString());
}
From Error.h:
#define ERROR_BAD_LENGTH 24
...not sure how that relates to your code, but there it is.
Edit: I wonder whether it's this:
home_dir = ""
or similar - the documentation says "Pointer to a Unicode string specifying the path of the home directory for the user specified by the usri2_name member. The string can be null." - there's no mention of the string being given but empty, as you have it. Try null - maybe zero length strings can mean ERROR_BAD_LENGTH..

Accessing a Shared File (UNC) From a Remote, Non-Trusted Domain With Credentials

We've run into an interesting situation that needs solving, and my searches have turned up nill. I therefore appeal to the SO community for help.
The issue is this: we have a need to programmatically access a shared file that is not in our domain, and is not within a trusted external domain via remote file sharing / UNC. Naturally, we need to supply credentials to the remote machine.
Typically, one solves this problem in one of two ways:
Map the file share as a drive and supply the credentials at that time. This is typically done using the NET USE command or the Win32 functions that duplicate NET USE.
Access the file with a UNC path as if the remote computer were on the domain and ensure that the account under which the program runs is duplicated (including password) on the remote machine as a local user. Basically leverage the fact that Windows will automatically supply the current user's credentials when the user attempts to access a shared file.
Don't use remote file sharing. Use FTP (or some other means) to transfer the file, work on it locally, then transfer it back.
For various and sundry reasons, our security / network architects have rejected the first two approaches. The second approach is obviously a security hole; if the remote computer is compromised, the local computer is now at risk. The first approach is unsatisfactory because the newly mounted drive is a shared resource available to other programs on the local computer during file access by the program. Even though it's quite possible to make this temporary, it's still a hole in their opinion.
They're open to the third option, but the remote network admins insist on SFTP rather than FTPS, and FtpWebRequest only supports FTPS. SFTP is the more firewall-friendly option and there are a couple libraries I could use for that approach, but I'd prefer to reduce my dependencies if I can.
I've searched MSDN for either a managed or a win32 means of using remote file sharing, but I have failed to come up with anything useful.
And so I ask: Is there another way? Did I miss a super-secret win32 function that does what I want? Or must I pursue some variant of option 3?
The way to solve your problem is to use a Win32 API called WNetUseConnection.
Use this function to connect to a UNC path with authentication, NOT to map a drive.
This will allow you to connect to a remote machine, even if it is not on the same domain, and even if it has a different username and password.
Once you have used WNetUseConnection you will be able to access the file via a UNC path as if you were on the same domain. The best way is probably through the administrative built in shares.
Example: \\computername\c$\program files\Folder\file.txt
Here is some sample C# code that uses WNetUseConnection.
Note, for the NetResource, you should pass null for the lpLocalName and lpProvider. The dwType should be RESOURCETYPE_DISK. The lpRemoteName should be \\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);
}
}
}
For people looking for a quick solution, you can use the NetworkShareAccesser I wrote recently (based on this answer (thanks so much!)):
Usage:
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");
}
WARNING: Please make absolutely sure, that Dispose of the NetworkShareAccesser is called (even if you app crashes!), otherwise an open connection will remain on Windows. You can see all open connections by opening the cmd prompt and enter net use.
The 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);
}
}
AFAIK, you don't need to map the UNC path to a drive letter in order to establish credentials for a server. I regularly used batch scripts like:
net use \\myserver /user:username password
:: do something with \\myserver\the\file\i\want.xml
net use /delete \\my.server.com
However, any program running on the same account as your program would still be able to access everything that username:password has access to. A possible solution could be to isolate your program in its own local user account (the UNC access is local to the account that called NET USE).
Note: Using SMB accross domains is not quite a good use of the technology, IMO. If security is that important, the fact that SMB lacks encryption is a bit of a damper all by itself.
Rather than WNetUseConnection, I would recommend NetUseAdd. WNetUseConnection is a legacy function that's been superceded by WNetUseConnection2 and WNetUseConnection3, but all of those functions create a network device that's visible in Windows Explorer. NetUseAdd is the equivalent of calling net use in a DOS prompt to authenticate on a remote computer.
If you call NetUseAdd then subsequent attempts to access the directory should succeed.
While I don't know myself, I would certainly hope that #2 is incorrect...I'd like to think that Windows isn't going to AUTOMATICALLY give out my login information (least of all my password!) to any machine, let alone one that isn't part of my trust.
Regardless, have you explored the impersonation architecture? Your code is going to look similar to this:
using (System.Security.Principal.WindowsImpersonationContext context = System.Security.Principal.WindowsIdentity.Impersonate(token))
{
// Do network operations here
context.Undo();
}
In this case, the token variable is an IntPtr. In order to get a value for this variable, you'll have to call the unmanaged LogonUser Windows API function. A quick trip to pinvoke.net gives us the following signature:
[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
);
Username, domain, and password should seem fairly obvious. Have a look at the various values that can be passed to dwLogonType and dwLogonProvider to determine the one that best suits your needs.
This code hasn't been tested, as I don't have a second domain here where I can verify, but this should hopefully put you on the right track.
Here a minimal POC class w/ all the cruft removed
using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
public class UncShareWithCredentials : IDisposable
{
private string _uncShare;
public UncShareWithCredentials(string uncShare, string userName, string password)
{
var nr = new Native.NETRESOURCE
{
dwType = Native.RESOURCETYPE_DISK,
lpRemoteName = uncShare
};
int result = Native.WNetUseConnection(IntPtr.Zero, nr, password, userName, 0, null, null, null);
if (result != Native.NO_ERROR)
{
throw new Win32Exception(result);
}
_uncShare = uncShare;
}
public void Dispose()
{
if (!string.IsNullOrEmpty(_uncShare))
{
Native.WNetCancelConnection2(_uncShare, Native.CONNECT_UPDATE_PROFILE, false);
_uncShare = null;
}
}
private class Native
{
public const int RESOURCETYPE_DISK = 0x00000001;
public const int CONNECT_UPDATE_PROFILE = 0x00000001;
public const int NO_ERROR = 0;
[DllImport("mpr.dll")]
public static extern int WNetUseConnection(IntPtr hwndOwner, NETRESOURCE lpNetResource, string lpPassword, string lpUserID,
int dwFlags, string lpAccessName, string lpBufferSize, string lpResult);
[DllImport("mpr.dll")]
public static extern int WNetCancelConnection2(string lpName, int dwFlags, bool fForce);
[StructLayout(LayoutKind.Sequential)]
public class NETRESOURCE
{
public int dwScope;
public int dwType;
public int dwDisplayType;
public int dwUsage;
public string lpLocalName;
public string lpRemoteName;
public string lpComment;
public string lpProvider;
}
}
}
You can directly use \\server\share\folder w/ WNetUseConnection, no need to strip it to \\server part only beforehand.
Most SFTP servers support SCP as well which can be a lot easier to find libraries for. You could even just call an existing client from your code like pscp included with PuTTY.
If the type of file you're working with is something simple like a text or XML file, you could even go so far as to write your own client/server implementation to manipulate the file using something like .NET Remoting or web services.
im attach my vb.net code based on brian reference
Imports System.ComponentModel
Imports System.Runtime.InteropServices
Public Class PinvokeWindowsNetworking
Const NO_ERROR As Integer = 0
Private Structure ErrorClass
Public num As Integer
Public message As String
Public Sub New(ByVal num As Integer, ByVal message As String)
Me.num = num
Me.message = message
End Sub
End Structure
Private Shared ERROR_LIST As ErrorClass() = New ErrorClass() {
New ErrorClass(5, "Error: Access Denied"),
New ErrorClass(85, "Error: Already Assigned"),
New ErrorClass(1200, "Error: Bad Device"),
New ErrorClass(67, "Error: Bad Net Name"),
New ErrorClass(1204, "Error: Bad Provider"),
New ErrorClass(1223, "Error: Cancelled"),
New ErrorClass(1208, "Error: Extended Error"),
New ErrorClass(487, "Error: Invalid Address"),
New ErrorClass(87, "Error: Invalid Parameter"),
New ErrorClass(1216, "Error: Invalid Password"),
New ErrorClass(234, "Error: More Data"),
New ErrorClass(259, "Error: No More Items"),
New ErrorClass(1203, "Error: No Net Or Bad Path"),
New ErrorClass(1222, "Error: No Network"),
New ErrorClass(1206, "Error: Bad Profile"),
New ErrorClass(1205, "Error: Cannot Open Profile"),
New ErrorClass(2404, "Error: Device In Use"),
New ErrorClass(2250, "Error: Not Connected"),
New ErrorClass(2401, "Error: Open Files")}
Private Shared Function getErrorForNumber(ByVal errNum As Integer) As String
For Each er As ErrorClass In ERROR_LIST
If er.num = errNum Then Return er.message
Next
Try
Throw New Win32Exception(errNum)
Catch ex As Exception
Return "Error: Unknown, " & errNum & " " & ex.Message
End Try
Return "Error: Unknown, " & errNum
End Function
<DllImport("Mpr.dll")>
Private Shared Function WNetUseConnection(ByVal hwndOwner As IntPtr, ByVal lpNetResource As NETRESOURCE, ByVal lpPassword As String, ByVal lpUserID As String, ByVal dwFlags As Integer, ByVal lpAccessName As String, ByVal lpBufferSize As String, ByVal lpResult As String) As Integer
End Function
<DllImport("Mpr.dll")>
Private Shared Function WNetCancelConnection2(ByVal lpName As String, ByVal dwFlags As Integer, ByVal fForce As Boolean) As Integer
End Function
<StructLayout(LayoutKind.Sequential)>
Private Class NETRESOURCE
Public dwScope As Integer = 0
Public dwType As Integer = 0
Public dwDisplayType As Integer = 0
Public dwUsage As Integer = 0
Public lpLocalName As String = ""
Public lpRemoteName As String = ""
Public lpComment As String = ""
Public lpProvider As String = ""
End Class
Public Shared Function connectToRemote(ByVal remoteUNC As String, ByVal username As String, ByVal password As String) As String
Return connectToRemote(remoteUNC, username, password, False)
End Function
Public Shared Function connectToRemote(ByVal remoteUNC As String, ByVal username As String, ByVal password As String, ByVal promptUser As Boolean) As String
Dim nr As NETRESOURCE = New NETRESOURCE()
nr.dwType = ResourceTypes.Disk
nr.lpRemoteName = remoteUNC
Dim ret As Integer
If promptUser Then
ret = WNetUseConnection(IntPtr.Zero, nr, "", "", Connects.Interactive Or Connects.Prompt, Nothing, Nothing, Nothing)
Else
ret = WNetUseConnection(IntPtr.Zero, nr, password, username, 0, Nothing, Nothing, Nothing)
End If
If ret = NO_ERROR Then Return Nothing
Return getErrorForNumber(ret)
End Function
Public Shared Function disconnectRemote(ByVal remoteUNC As String) As String
Dim ret As Integer = WNetCancelConnection2(remoteUNC, Connects.UpdateProfile, False)
If ret = NO_ERROR Then Return Nothing
Return getErrorForNumber(ret)
End Function
Enum Resources As Integer
Connected = &H1
GlobalNet = &H2
Remembered = &H3
End Enum
Enum ResourceTypes As Integer
Any = &H0
Disk = &H1
Print = &H2
End Enum
Enum ResourceDisplayTypes As Integer
Generic = &H0
Domain = &H1
Server = &H2
Share = &H3
File = &H4
Group = &H5
End Enum
Enum ResourceUsages As Integer
Connectable = &H1
Container = &H2
End Enum
Enum Connects As Integer
Interactive = &H8
Prompt = &H10
Redirect = &H80
UpdateProfile = &H1
CommandLine = &H800
CmdSaveCred = &H1000
LocalDrive = &H100
End Enum
End Class
how to use it
Dim login = PinvokeWindowsNetworking.connectToRemote("\\ComputerName", "ComputerName\UserName", "Password")
If IsNothing(login) Then
'do your thing on the shared folder
PinvokeWindowsNetworking.disconnectRemote("\\ComputerName")
End If
I looked to MS to find the answers. The first solution assumes the user account running the application process has access to the shared folder or drive (Same domain). Make sure your DNS is resolved or try using IP address. Simply do the following:
DirectoryInfo di = new DirectoryInfo(PATH);
var files = di.EnumerateFiles("*.*", SearchOption.AllDirectories);
If you want across different domains .NET 2.0 with credentials follow this model:
WebRequest req = FileWebRequest.Create(new Uri(#"\\<server Name>\Dir\test.txt"));
req.Credentials = new NetworkCredential(#"<Domain>\<User>", "<Password>");
req.PreAuthenticate = true;
WebResponse d = req.GetResponse();
FileStream fs = File.Create("test.txt");
// here you can check that the cast was successful if you want.
fs = d.GetResponseStream() as FileStream;
fs.Close();

Categories