List of all physical drives - c#

How to get list of all physical drives in UWP (Windows 10) App? I'm try to use Windows.Storage.KnownFolders, but this way I can get only folders from Library.

In UWP you cannot list all the files/drives just like that (with official API) - this is by design, probably for security reasons. Windows Store apps work are isolated and the access is only granted to limited resources/locations. In this case you are freely able to access virtual locations like MusicLibray, PicturesLibrary and so on. The list of access permisions you will find at MSDN.
If you want to access a file/folder from out of above scope, the user will have to grand the access to it for your app. For this purpose you can use pickers.

I know you asked this question a long time ago, but I created a question (Get Internal Drives Using Windows.Storage Namespace in UWP) to provide my method for getting internal drives and encourage feedback/discussion on a better alternative.
I had exactly the same problem to solve and everything else I can find online doesn't fit with what I'm trying to do. So, with the broadFileSystemAccess attribute added to the manifest file and File System access switched on for the app in Privacy Settings, it is possible to call StorageFolder.GetFolderFromPathAsync for a drive letter and it will return an instance of StorageFolder if the drive exists.
Sadly there isn't a method to list the drives, so I wrote something to cycle through all the letters of the alphabet and call GetFolderFromPathAsync to see if a drive handle is returned.
The method I created to obtain the list of drives is as follows:
public List<StorageFolder> GetInternalDrives()
{
string driveLetters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
int driveLettersLen = driveLetters.Length;
string removableDriveLetters = "";
string driveLetter;
List<StorageFolder> drives = new List<StorageFolder>();
StorageFolder removableDevices = KnownFolders.RemovableDevices;
IReadOnlyList<StorageFolder> folders = Task.Run<IReadOnlyList<StorageFolder>>(async () => await removableDevices.GetFoldersAsync()).Result;
foreach (StorageFolder removableDevice in folders)
{
if (string.IsNullOrEmpty(removableDevice.Path)) continue;
driveLetter = removableDevice.Path.Substring(0, 1).ToUpper();
if (driveLetters.IndexOf(driveLetter) > -1) removableDriveLetters += driveLetter;
}
for (int curDrive = 0; curDrive < driveLettersLen; curDrive++)
{
driveLetter = driveLetters.Substring(curDrive, 1);
if (removableDriveLetters.IndexOf(driveLetter) > -1) continue;
try
{
StorageFolder drive = Task.Run<StorageFolder>(async () => await StorageFolder.GetFolderFromPathAsync(driveLetter + ":")).Result;
drives.Add(drive);
}
catch (System.AggregateException) { }
}
return drives;
}
And here is the calling code:
List<StorageFolder> drives = GetInternalDrives();
panScanParams.Children.Clear();
foreach (StorageFolder drive in drives)
{
CheckBox cb = new CheckBox();
cb.Content = drive.DisplayName;
cb.IsChecked = true;
panScanParams.Children.Add(cb);
}
Whilst the code works, it's not good practice to call methods with bad parameters and handle the exception. But with a lack of suitable alternative, I don't know what other choice there is.

Related

Monitor FTP directory in ASP.NET/C#

I have FileSystem watcher for a local directory. It's working fine. I want same to implement for FTP. Is there any way I can achieve it? I have checked many solutions but it's not clear.
Logic: Want to get files from FTP later than some timestamp.
Problem faced: Getting all files from FTP and then filtering the result is hitting the performance (used FtpWebRequest).
Is there any right way to do this? (WinSCP is on hold. Cant use it now.)
FileSystemWatcher oFsWatcher = new FileSystemWatcher();
OFSWatchers.Add(oFsWatcher);
oFsWatcher.Path = sFilePath;
oFsWatcher.Filter = string.IsNullOrWhiteSpace(sFileFilter) ? "*.*" : sFileFilter;
oFsWatcher.NotifyFilter = NotifyFilters.FileName;
oFsWatcher.EnableRaisingEvents = true;
oFsWatcher.IncludeSubdirectories = bIncludeSubdirectories;
oFsWatcher.Created += new FileSystemEventHandler(OFsWatcher_Created);
You cannot use the FileSystemWatcher or any other way, because the FTP protocol does not have any API to notify a client about changes in the remote directory.
All you can do is to periodically iterate the remote tree and find changes.
It's actually rather easy to implement, if you use an FTP client library that supports recursive listing of a remote tree. Unfortunately, the built-in .NET FTP client, the FtpWebRequest does not. But for example with WinSCP .NET assembly, you can use the Session.EnumerateRemoteFiles method.
See the article Watching for changes in SFTP/FTP server:
// Setup session options
SessionOptions sessionOptions = new SessionOptions
{
Protocol = Protocol.Ftp,
HostName = "example.com",
UserName = "user",
Password = "password",
};
using (Session session = new Session())
{
// Connect
session.Open(sessionOptions);
List<string> prevFiles = null;
while (true)
{
// Collect file list
List<string> files =
session.EnumerateRemoteFiles(
"/remote/path", "*.*", EnumerationOptions.AllDirectories)
.Select(fileInfo => fileInfo.FullName)
.ToList();
if (prevFiles == null)
{
// In the first round, just print number of files found
Console.WriteLine("Found {0} files", files.Count);
}
else
{
// Then look for differences against the previous list
IEnumerable<string> added = files.Except(prevFiles);
if (added.Any())
{
Console.WriteLine("Added files:");
foreach (string path in added)
{
Console.WriteLine(path);
}
}
IEnumerable<string> removed = prevFiles.Except(files);
if (removed.Any())
{
Console.WriteLine("Removed files:");
foreach (string path in removed)
{
Console.WriteLine(path);
}
}
}
prevFiles = files;
Console.WriteLine("Sleeping 10s...");
Thread.Sleep(10000);
}
}
(I'm the author of WinSCP)
Though, if you actually want to just download the changes, it's a way easier. Just use the Session.SynchronizeDirectories in the loop.
while (true)
{
SynchronizationResult result =
session.SynchronizeDirectories(
SynchronizationMode.Local, "/remote/path", #"C:\local\path", true);
result.Check();
// You can inspect result.Downloads for a list for updated files
Console.WriteLine("Sleeping 10s...");
Thread.Sleep(10000);
}
This will update even modified files, not only new files.
Though using WinSCP .NET assembly from a web application might be problematic. If you do not want to use a 3rd party library, you have to do with limitations of the FtpWebRequest. For an example how to recursively list a remote directory tree with the FtpWebRequest, see my answer to List names of files in FTP directory and its subdirectories.
You have edited your question to say that you have performance problems with the solutions I've suggested. Though you have already asked a new question that covers this:
Get FTP file details based on datetime in C#
Unless you have access to the OS which hosts the service; it will be a bit harder.
FileSystemWatcher places a hook on the filesystem, which will notify your application as soon as something happened.
FTP command specifications does not have such a hook. Besides that it's always initiated by the client.
Therefor, to implement such logic you should periodical perform a NLST to list the FTP-directory contents and track the changes (or hashes, perhaps (MDTM)) yourself.
More info:
FTP return codes
FTP
I have got an alternative solution to do my functionality.
Explanation:
I am downloading the files from FTP (Read permission reqd.) with same folder structure.
So everytime the job/service runs I can check into the physical path same file(Full Path) exists or not If not exists then it can be consider as a new file. And Ii can do some action for the same and download as well.
Its just an alternative solution.
Code Changes:
private static void GetFiles()
{
using (FtpClient conn = new FtpClient())
{
string ftpPath = "ftp://myftp/";
string downloadFileName = #"C:\temp\FTPTest\";
downloadFileName += "\\";
conn.Host = ftpPath;
//conn.Credentials = new NetworkCredential("ftptest", "ftptest");
conn.Connect();
//Get all directories
foreach (FtpListItem item in conn.GetListing(conn.GetWorkingDirectory(),
FtpListOption.Modify | FtpListOption.Recursive))
{
// if this is a file
if (item.Type == FtpFileSystemObjectType.File)
{
string localFilePath = downloadFileName + item.FullName;
//Only newly created files will be downloaded.
if (!File.Exists(localFilePath))
{
conn.DownloadFile(localFilePath, item.FullName);
//Do any action here.
Console.WriteLine(item.FullName);
}
}
}
}
}

Trouble with transfer function in WIA C#

I have a problem with the below code. I want to scan a document by clicking a button in a WinForms C# application.
I use WIA, Visual studio and the scanner Fujitsu N7100A working with Windows 8. I am following a tutorial online for using WIA.
But the program doesn't run as expected. It seems to break down at the Transfer method.
// Create a DeviceManager instance
var deviceManager = new DeviceManager();
// Create an empty variable to store the scanner instance
DeviceInfo firstScannerAvailable = null;
// Loop through the list of devices to choose the first available
AddLogs(deviceManager.DeviceInfos.Count.ToString(), filename);
foreach (DeviceInfo d in deviceManager.DeviceInfos)
{
if (d.Type == WiaDeviceType.ScannerDeviceType)
{
firstScannerAvailable = d;
}
}
// Connect to the first available scanner
var device = firstScannerAvailable.Connect();
// Select the scanner
var scannerItem = device.Items[0];
// Retrieve a image in JPEG format and store it into a variable
var imageFile = (ImageFile)scannerItem.Transfer(FormatID.wiaFormatPNG);
//Save the image in some path with filename
var path = #"C:\Documents\scan.png";
if (File.Exists(path))
{
File.Delete(path);
}
// Save image !
imageFile.SaveFile(path);
I just have to remove the addition of lines in the file of log.
This is much more of a workaround since i have no idea about your scanner.
I would assume that all scanners has a drive where they store their scanned documents, like mine, So i would suggest that you read all available drives loop through them check for DriveType and VolumeLabel and then read it's files and copy the document where you want
Something like this :
foreach (var item in DriveInfo.GetDrives())
{
//VolumeLabel differs from a scanner to another
if (item.VolumeLabel == "Photo scan" && item.DriveType == DriveType.Removable)
{
foreach (var obj in Directory.GetFiles(item.Name))
{
File.Copy(obj, "[YOUR NEW PATH]");
break;
}
break;
}
}
Finaly a TWAIN application work with this scanner. I will work with that. I don't said why do that work with TWAIN and not with WIA but that the reality. Sorry for this waste of time. Thank you for the answers. Have a nice day.
I am currently solving this very problem. It seems the N7100A driver sets the Pages property of the device to 0, which should mean continous scanning, but the transfer method is unable to handle this value. You must set that property to 1:
var pages = 1;
// Not all devices have this property, but Fujitsu N7100A has.
device.Properties["Pages"]?.set_Value(ref pages);
I think the problem is here
var scannerItem = device.Items[0];
as WIA indexes are NOT zero based so it should be 1 instead
var scannerItem = device.Items[1];

Check if user added new music on Windows Phone 8.1

I'm trying to find out if a user added new music to the Music folder on the phone since app was last used.
I try to do this by checking the DateModified of the Music folder (which updates correctly on the computer when adding new music to the phone):
async void GetModifiedDate ()
{
BasicProperties props = await KnownFolders.MusicLibrary.GetBasicPropertiesAsync();
Debug.WriteLine("DATEMODIFIED: " + props.DateModified.ToString());
}
Unfortunately this returns:
DATEMODIFIED: 1/1/1601 1:00:00 AM +01:00
Am I doing something wrong or is there another quick way to check if user added new music?
KnownFolders.MusicLibrary is a virtual location. Therefore I think, may be a problem in getting its properties.
The other problem is that DateModified may be a bad idea, as it may stay the same when user adds a file. You cannot relay on it. (some information). You can check it - when I've tried to move files in folders, their DateModified hadn't changed.
So in this case, I'm afraid you will have to list your files in MusicLibrary and then decide, what to save for future comparison. The sum of filesizes can be a good idea, hence there is a little chance that two different music files would be the same size. It depends also if you want to be notified if the user had moved file from one folder to another (total size won't change). If you want to ensure more you can remember the whole list of Tuple<file.FolderRelativeId, fileSize> (for ecample).
As FileQueries are not yet available for Windows Phone, you will have to retrive files recursively the simple code can look like this:
// first - a method to retrieve files from folder recursively
private async Task RetriveFilesInFolder(List<StorageFile> list, StorageFolder parent)
{
foreach (var item in await parent.GetFilesAsync()) list.Add(item);
foreach (var item in await parent.GetFoldersAsync()) await RetriveFilesInFolder(list, item);
}
private async Task<List<StorageFile>> GetFilesInMusic()
{
StorageFolder folder = KnownFolders.MusicLibrary;
List<StorageFile> listOfFiles = new List<StorageFile>();
await RetriveFilesInFolder(listOfFiles, folder);
return listOfFiles;
}
Once you have a list of your files, you can decide what to remember for further comparison upon next app launch.
You can check the folder size instead:
ulong musicFolderSize = (ulong)ApplicationData.Current.LocalSettings.Values["musicFolderSize"];
BasicProperties props = await KnownFolders.MusicLibrary.GetBasicPropertiesAsync();
if (props.Size != musicFolderSize)
{
// ...
ApplicationData.Current.LocalSettings.Values["musicFolderSize"] = props.Size;
}
Adding onto Romansz's answer:
The only way to guarantee that you know of a file change would be to track the files on the device and then compare if there is a change between launches.
A lazier way to get all of the files would be to use KnownFolders.MusicLibrary.GetFilesAsync(CommonFileQuery.OrderByName); which is a deep query by default. It will grab all of the files in one query, but can be really slow on massive directories. You then have to page through all of the files as shown
//cache the virtual storage folder for the loop
StorageFolder musicLibrary = KnownFolders.MusicLibrary;
uint stepSize= 50;
uint startIndex = 0;
while (true)
{
IReadOnlyList<StorageFile> files = await musicLibrary.GetFilesAsync(CommonFileQuery.OrderByName,startIndex,stepSize);
foreach (var file in files)
{
//compare to see if file is in your list
}
if (files.Count < stepSize) break;
startIndex += stepSize;
}

Get all folders from network

I'm kind of lost, I have a task to get all folders from a network domain,
E.g. (My Network Places/Entire Network/Microsoft Windows Network/xyNetwork).
I have to get all folders and sub-folders then get all security groups assigned to this folder and the rights granted to each security group.
The second part I have done before, however, the first part which is getting a list of all folders seems to be very complicated.
Any guides or references that might help?
Well, there is a code in another similar entry that lists all the computer names from the network... That's the first part of your requirement. For the second part I think you need to dig into System.DirectoryServices classes since there are some for permissions as well... good luck.
//Lists all available computer names on the network.
public static List<String> ListNetworkComputers()
{
var computerNames = new List<String>();
var computerSchema = "Computer";
var entries = new System.DirectoryServices.DirectoryEntry("WinNT:");
foreach (var domains in entries.Children)
{
foreach (var computer in domains.Children)
{
if (computer.SchemaClassName.ToLower().Contains(computerSchema .ToLower()))
{
computerNames.Add(computer.Name);
}
}
}
return computerNames;
}
I just printed out the values and it worked fine for me.
foreach (string lst in ListNetworkComputers())
{
Console.WriteLine("PC: " + lst);
}
(Above code taken from: Getting computer names from my network places )
What you need is to access the Win32_Share WMI from your code.
Add the reference to System.Management.dll and use the following code.
code example in VB.NET from the topic here:
http://www.pcreview.co.uk/forums/finding-share-s-directory-spec-t3064222.html
C# version of the VB.net program:
class Program
{
static void Main(string[] args)
{
var objClass = new System.Management.ManagementClass("Win32_Share");
foreach(var objShare in objClass.GetInstances())
{
Console.WriteLine(String.Format("{0} -> {1}",
objShare.Properties["Name"].Value, objShare.Properties["Path"].Value));
}
}
}
You can compare the results of the code above against the result that you get by running the following command in a windows command prompt:
C:\net share
Which will give you the Share Name (shared name given when sharing i.e. MySharedDir) and the Resource (windows path i.e. C:\myshareddir).
you can simply use GetDirectories. For example:
var folders = Directory.GetDirectories(#"\\server\share");
to get all directories (i.e. include subdirectories), use the following:
var folders = Directory.GetDirectories(#"\\server\share", "*", SearchOption.AllDirectories));

How do I get folder size with Exchange Web Services 2010 Managed API?

I'm attempting to use EWS 2010 Managed API to get the total size of a user's mailbox. I haven't found a web service method to get this data, so I figured I would try to calculate it. I found one seemingly-applicable question on another site about finding mailbox sizes with EWS 2007, but either I'm not understanding what it's asking me to do, or that method just doesn't work with EWS 2010.
Noodling around in the code insight, I was able to write what I thought was a method that would traverse the folder structure recursively and result in a combined total for all folders inside the Inbox:
private int traverseChildFoldersForSize(Folder f)
{
int folderSizeSum = 0;
if (f.ChildFolderCount > 0)
{
foreach (Folder c in f.FindFolders(new FolderView(10000)))
{
folderSizeSum += traverseChildFoldersForSize(c);
}
}
folderSizeSum += (int)f.ManagedFolderInformation.FolderSize;
return folderSizeSum;
}
(Assumes there aren't more than 10,000 folders inside a given folder. Figure that's a safe bet...)
Unfortunately, this doesn't work.
I'm initiating the recursion with this code:
Folder root = Folder.Bind(svc, WellKnownFolderName.Inbox);
int totalSize = traverseChildFoldersForSize(root);
But a Null Reference Exception is thrown, essentially saying that [folder].ManagedFolderInformation is a null object reference.
For clarity, I also attempted to just get the size of the root folder:
Console.Write(root.ManagedFolderInformation.FolderSize.ToString());
Which threw the same NRE exception, so I know that it's not just that once you get to a certain depth in the directory tree that ManagedFolderInformation doesn't exist.
Any ideas on how to get the total size of the user's mailbox? Am I barking up the wrong tree?
Using the EWS Managad APi, you can use this code to get the cumulative folder size of a mailbox:
internal class Program
{
private static readonly ExtendedPropertyDefinition PidTagMessageSizeExtended = new ExtendedPropertyDefinition(0xe08,
MapiPropertyType
.Long);
public static void Main(string[] args)
{
var service = new ExchangeService(ExchangeVersion.Exchange2010_SP1)
{Credentials = new NetworkCredential("mail", "pw!")};
service.AutodiscoverUrl("mail", url => true);
var offset = 0;
const int pagesize = 12;
long size = 0;
FindFoldersResults folders;
do
{
folders = service.FindFolders(WellKnownFolderName.MsgFolderRoot,
new FolderView(pagesize, offset, OffsetBasePoint.Beginning)
{
Traversal = FolderTraversal.Deep,
PropertySet =
new PropertySet(BasePropertySet.IdOnly, PidTagMessageSizeExtended,
FolderSchema.DisplayName)
});
foreach (var folder in folders)
{
long folderSize;
if (folder.TryGetProperty(PidTagMessageSizeExtended, out folderSize))
{
Console.Out.WriteLine("{0}: {1:00.00} MB", folder.DisplayName, folderSize/1048576);
size += folderSize;
}
}
offset += pagesize;
} while (folders.MoreAvailable);
Console.Out.WriteLine("size = {0:0.00} MB", size/1048576);
}
}
The first link is the way you want to go. The post describes that the default folders are not considered "managed folders" which is why you are getting the NRE on the ManagedFolderInformation property for some folders.
What the post is suggesting is to add an Extended Property to the request for the folders. Here's the MSDN page on how to do that using the Managed API.
I tried to find a good example but didn't come up with one. This should point you in the right direction. If I find anything I'll update my answer.

Categories