VB.NET + Add folders to treeview and files to listview - vb.net

I want to create a simple printer manager to use in our Terminal server environment. Because of GPO restrictions, there are limits of what built-in functionality I can use. So I decided to try to write my own simple GUI to do that.
Now, the printers are distributed in a folder, with subfolders to categorize them. In each folder there are .lnk files to the actual printer on the printserver.
What I want to do is to populate a treeview with the folders, and the printers in a listview, based on which item is clicked on the treeview.
I've already managed to search for directories and to search the files for each item I've clicked. But I realized, why not use a collection or similar to do this during the startup of the form? That way, it'll be faster. Because right now, there's a small delay each time I click an item in the treeview. Because it scans for files each time.
How can I add the same to a collection and use that instead?
Here's my current code:
Public Sub populateTreeView(ByVal strPath As String)
Dim di As New IO.DirectoryInfo(strPath)
Dim diar1 As IO.DirectoryInfo() = di.GetDirectories()
Dim dra As IO.DirectoryInfo
For Each dra In diar1
ImageList1.Images.Add(GetSmallIcon(dra.FullName))
TreeView1.Nodes.Add("", dra.Name, nIndex)
nIndex = nIndex + 1
Next
End Sub
Private Sub TreeView1_AfterSelect(sender As Object, e As TreeViewEventArgs) Handles TreeView1.AfterSelect
ListView1.Clear()
nIndex = 0
Dim di As New IO.DirectoryInfo(strIniSettings & "\" & TreeView1.SelectedNode.Text)
Dim diar1 As IO.FileInfo() = di.GetFiles()
Dim dra As IO.FileInfo
For Each dra In diar1
Dim strName As String
strName = Replace(dra.Name, ".lnk", "")
ImageList2.Images.Add(GetLargeIcon(dra.FullName))
ListView1.Items.Add("", strName, nIndex)
nIndex = nIndex + 1
Next
End Sub
Notice the Imagelists? I also get the Icon for each item as well.

Since your data is not complex, a simple LookUp may be the right collection for you (or just a plain Dictionary).
Just query the printers once, and store it in a member variable, or just use the Tag property of the TreeNodes so store the file names.
In the example below, I'm using a simple Linq query to create a LookUp where the Key is the directory name (you could also just use full path to the directory), and the items are the file names.
You could then either query the collection by a given Key (the directory name), or use the Tag property.
LINQPad example:
Sub Main
' query printers once (just replace C:\test with your path)
' store the result in a member variable of your form
Dim printer = new DirectoryInfo("C:\test").GetDirectories() _
.SelectMany(Function(d) d.GetFiles()) _
.ToLookup(Function(f) f.Directory.Name, Function(f) f.Name)
' Or, using a Dictionary
' Dim printer = new DirectoryInfo("C:\test").GetDirectories() _
' .ToDictionary(Function(d) d.Name, Function(d) d.GetFiles().Select(Function(f) f.Name).ToList())
Dim l = new ListView() With {.Dock = DockStyle.Right}
Dim t = new TreeView() With {.Dock = DockStyle.Left}
AddHandler t.AfterSelect, Sub(s, e)
' This is your AfterSelect event handler
' The filenames are stored in the Tag of the TreeNode
' You could also use 'For Each p As String in printer(e.Node.Text)'
l.Items.Clear()
For Each p As String in e.Node.Tag
Dim item = l.Items.Add(p.Replace(".lnk", ""))
'TODO: Set Icon on item
Next
End Sub
' Populate TreeView once
For Each folder in printer
Dim fNode = t.Nodes.Add(folder.Key)
'TODO: Set Icon on fNode
' store the files in the Tag of the node.
' You don't have to, but it will make it easier
fNode.Tag = folder
Next
' Show test form
Dim w = new Form()
w.Controls.Add(t)
w.Controls.Add(l)
w.Show()
End Sub

Related

How to remove files from a directory if they don't contain the list of specified files provided?

I'm currently doing a project where I need to search through a specific directory for files. If the files found are not the approved extension then the files must be moved to an archive folder. I need to user to be allowed to remove and add extensions so the list is not a set size and will most likely change weekly.
So far I'm able to loop through the directories and list all the files in there into a listbox. My problem comes when trying to differentiate between the approved list and the current list and I can't narrow down the files and display them in the list box.
My error is : 'An unhandled exception of type 'System.ArgumentOutOfRangeException' occurred in mscorlib.dll' where my 'list1' variable count is 0 because no children were found even when there are matching approved data and current data.
Any help would be appreciate from stack overflow community! Thanks!!
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim list1 As List(Of String)
list1 = (From item As String In Me.ListBox1.Items Select item Where Me.ListBox1.Items.Contains(Me.lstApprovedItems.Items)).ToList()
ListBox1.Items.Add(list1(0))
End Sub
Dim fri As FileInfo
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim FileName1 As String = ""
Dim dir2 As New DirectoryInfo("D:\Administrator\Desktop\File Management System v0.2\File Management System\File Directories\File Directories\00000000.00F")
Dim dir1 As DirectoryInfo() = dir2.GetDirectories()
Dim fri2 As DirectoryInfo
For Each fri2 In dir1
FileName1 = Convert.ToString(fri2.Name)
Dim dir As New DirectoryInfo("D:\Administrator\Desktop\File Management System v0.2\File Management System\File Directories\File Directories\00000000.00F\" + FileName1)
Dim fiArr As FileInfo() = dir.GetFiles()
For Each Me.fri In fiArr
ListBox1.Items.Add(fri.Name)
Next fri
Next
End Sub
End Class
There are several ways to go about this, this way is similar to what you have.
' first get OK extension into an array (or list)
Dim Auth(lbAuthExt.Items.Count - 1) As String
lbAuthExt.Items.CopyTo(Auth, 0)
' storage for the result
' only save the Authorized ones if that is all you care about
Dim AuthList As New List(Of FileInfo)
Dim NoAuthList As New List(Of FileInfo)
Dim dir = New DirectoryInfo("C:\Temp")
For Each fi As FileInfo In dir.GetFiles
If Auth.Contains(fi.Extension) Then
AuthList.Add(fi)
Else
NoAuthList.Add(fi)
End If
Next
I am saving FileInfo because (presumably) you might display the names to the user without all the redundant path info. But your code will need the full path name for later Copy/Move ops.
' set the list as the datasource
lbResult.DataSource = AuthList
' display file name
lbResult.DisplayMember = "Name"
' return full name to code
lbResult.ValueMember = "FullName"
The code can of course simply loop on AuthList to do its job. If you need to show the results to the user first, there is no need to make 2 copies. DisplayMember is used to tell the ListBox which property value to display while retaining all the other info in the list.
Finally, a linq version which simply saves the full file name:
Dim myAuthList = (From func In Directory.EnumerateFiles("C:\Temp", "*.*",
System.IO.SearchOption.AllDirectories)
Where Auth.Contains(Path.GetExtension(func),
StringComparer.InvariantCultureIgnoreCase)).ToList

How to read files in folders?

I am trying to get my application to check for folders in the folderbrowserdialogs selectedpath and then get those files, but it doesn't work I have tried both listed ways below. The second way gives me an error: (Expression is of type char which is not a collection type)
For Each folder In FileBrowserDialog.SelectedPath
Dim counter As _
System.Collections.ObjectModel.ReadOnlyCollection(Of String)
counter = My.Computer.FileSystem.GetFiles(folder)
Label1.Text = counter.Count.ToString
Next
For Each folder In FileBrowserDialog.SelectedPath
Dim counter As _
System.Collections.ObjectModel.ReadOnlyCollection(Of String)
For Each foundfile In folder
counter = My.Computer.FileSystem.GetFiles(foundfile)
Label1.Text = counter.Count.ToString
Next
Any help is appreciated.
FolderBrowserDialog1.SelectedPath will return the path the user selected in the dialog. You still need to write code to go get the files. There may not be a need to get the folders and then files in them. Net has ways to do that for you:
FolderBrowserDialog1.ShowDialog()
Dim myPath As String = FolderBrowserDialog1.SelectedPath
' get all files for a folder
Dim files = Directory.GetFiles(myPath)
' get all files for all sub folders
Dim files = Directory.GetFiles(myPath, "*.*",
System.IO.SearchOption.AllDirectories)
' get certain file types for folder and subs
Dim files = Directory.GetFiles(myPath, "*.jpg",
System.IO.SearchOption.AllDirectories)
You also are not going to be able to simply assign the results to a ReadOnlyCollection like that, because they are ReadOnly. The collection needs to be created/instanced with the complete list:
Dim counter As new ReadOnlyCollection(Of String)(files)

Extracting Filename and Path from a running process

I'm writing a screen capture application for a client. The capture part is fine, but he wants to get the name and path of the file that the capture is of.
Using system.diagnostics.process I am able to get the process that the capture is of, and can get the full path of the EXE, but not the file that is open.
ie. Notepad is open with 'TextFile1.txt' as its document. I can get from the process the MainWindowTitle which would be 'TextFile1.txt - Notepad' but what I need is more like 'c:\users....\TextFile1.txt'
Is there a way of getting more information from the process?
I'm sure there is a way, but I can't figure it out
Any help greatly appreciated.
You can use ManagementObjectSearcher to get the command line arguments for a process, and in this notepad example, you can parse out the file name. Here's a simple console app example that writes out the full path and file name of all open files in notepad..
Imports System
Imports System.ComponentModel
Imports System.Management
Module Module1
Sub Main()
Dim cl() As String
For Each p As Process In Process.GetProcessesByName("notepad")
Try
Using searcher As New ManagementObjectSearcher("SELECT CommandLine FROM Win32_Process WHERE ProcessId = " & p.Id)
For Each mgmtObj As ManagementObject In searcher.Get()
cl = mgmtObj.Item("CommandLine").ToString().Split("""")
Console.WriteLine(cl(cl.Length - 1))
Next
End Using
Catch ex As Win32Exception
'handle error
End Try
Next
System.Threading.Thread.Sleep(1000000)
End Sub
End Module
I had to add a reference to this specific dll:
C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\System.Managment.dll
i think it is the simplest way
For Each prog As Process In Process.GetProcesses
If prog.ProcessName = "notepad" Then
ListBox1.Items.Add(prog.ProcessName)
End If
Next
I know this post is old, but since I've searched for this two days ago, I'm sure others would be interested. My code below will get you the file paths from Notepad, Wordpad, Excel, Microsoft Word, PowerPoint, Publisher, Inkscape, and any other text or graphic editor's process, as long as the filename and extension is in the title bar of the opened window.
Instead of searching, it obtains the file's target path from Windows' hidden Recent Items directory, which logs recently opened and saved files as shortcuts. I discovered this hidden directory in Windows 7. You're gonna have to check if Windows 10 or 11 has this:
C:\Users\ "username" \AppData\Roaming\Microsoft\Windows\Recent
I slapped this code together under Framework 4, running as 64bit. The COM dlls that must be referenced in order for the code to work are Microsoft Word 14.0 Object Library, Microsoft Excel 14.0 Object Library, Microsoft PowerPoint 14.0 Object Library, and Microsoft Shell Controls And Automation.
For testing, the code below needs a textbox, a listbox, a button, and 3 labels (Label1, FilenameLabel, Filepath).
Once you have this working, after submitting a process name, you will have to click the filename item in the ListBox to start the function to retrieve it's directory path.
Option Strict On
Option Explicit On
Imports System.Runtime.InteropServices
Imports Microsoft.Office.Interop.Excel
Imports Microsoft.Office.Interop.Word
Imports Microsoft.Office.Interop.PowerPoint
Imports Shell32
Public Class Form1
'function gets names of all opened Excel workbooks, adding them to the ListBox
Public Shared Function ExcelProcess(ByVal strings As String) As String
Dim Excel As Microsoft.Office.Interop.Excel.Application = CType(Marshal.GetActiveObject("Excel.Application"), Microsoft.Office.Interop.Excel.Application)
For Each Workbook As Microsoft.Office.Interop.Excel.Workbook In Excel.Workbooks
Form1.ListBox1.Items.Add(Workbook.Name.ToString() & " - " & Form1.TextBox1.Text)
Next
Return strings
End Function
'function gets names of all opened Word documents, adding them to the ListBox
Public Shared Function WordProcess(ByVal strings As String) As String
Dim Word As Microsoft.Office.Interop.Word.Application = CType(Marshal.GetActiveObject("Word.Application"), Microsoft.Office.Interop.Word.Application)
For Each Document As Microsoft.Office.Interop.Word.Document In Word.Documents
Form1.ListBox1.Items.Add(Document.Name.ToString() & " - " & Form1.TextBox1.Text)
Next
Return strings
End Function
'function gets names of all opened PowerPoint presentations, adding them to the ListBox
Public Shared Function PowerPointProcess(ByVal strings As String) As String
Dim PowerPoint As Microsoft.Office.Interop.PowerPoint.Application = CType(Marshal.GetActiveObject("PowerPoint.Application"), Microsoft.Office.Interop.PowerPoint.Application)
For Each Presentation As Microsoft.Office.Interop.PowerPoint.Presentation In PowerPoint.Presentations
Form1.ListBox1.Items.Add(Presentation.Name.ToString() & " - " & Form1.TextBox1.Text)
Next
Return strings
End Function
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
'clears listbox to prepare for new process items
ListBox1.Items.Clear()
'gets process title from TextBox1
Dim ProcessName As String = TextBox1.Text
'prepare string's case format for
ProcessName = ProcessName.ToLower
'corrects Office process names
If ProcessName = "microsoft excel" Then
ProcessName = "excel"
Else
If ProcessName = "word" Or ProcessName = "microsoft word" Then
ProcessName = "winword"
Else
If ProcessName = "powerpoint" Or ProcessName = "microsoft powerpoint" Then
ProcessName = "powerpnt"
Else
End If
End If
End If
'get processes by name (finds only one instance of Excel or Microsoft Word)
Dim proclist() As Process = Process.GetProcessesByName(ProcessName)
'adds window titles of all processes to a ListBox
For Each prs As Process In proclist
If ProcessName = "excel" Then
'calls function to add all Excel process instances' workbook names to the ListBox
ExcelProcess(ProcessName)
Else
If ProcessName = "winword" Then
'calls function to add all Word process instances' document names to the ListBox
WordProcess(ProcessName)
Else
If ProcessName = "powerpnt" Then
'calls function to add all Word process instances' document names to the ListBox
PowerPointProcess(ProcessName)
Else
'adds all Notepad or Wordpad process instances' filenames
ListBox1.Items.Add(prs.MainWindowTitle)
End If
End If
End If
Next
End Sub
Private Sub ListBox1_MouseClick(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles ListBox1.MouseClick
Try
'add ListBox item (full window title) to string
Dim ListBoxSelection As String = String.Join(Environment.NewLine, ListBox1.SelectedItems.Cast(Of String).ToArray)
'get full process title after "-" from ListBoxSelection
Dim GetProcessTitle As String = ListBoxSelection.Split("-"c).Last()
'create string to remove from ListBoxSelection
Dim Remove As String = " - " & GetProcessTitle
'Extract filename from ListBoxSelection string, minus process full name
Dim Filename As String = ListBoxSelection.Substring(0, ListBoxSelection.Length - Remove.Length + 1)
'display filename
FilenameLabel.Text = "Filename: " & Filename
'for every file opened and saved via savefiledialogs and openfiledialogs in editing software
'Microsoft Windows always creates and modifies shortcuts of them in Recent Items directory:
'C:\Users\ "Username" \AppData\Roaming\Microsoft\Windows\Recent
'so the below function gets the target path from files's shortcuts Windows created
FilePathLabel.Text = "File Path: " & GetLnkTarget("C:\Users\" & Environment.UserName & "\AppData\Roaming\Microsoft\Windows\Recent\" & Filename & ".lnk")
Catch ex As Exception
'no file path to show if nothing was saved yet
FilePathLabel.Text = "File Path: Not saved yet."
End Try
End Sub
'gets file's shortcut's target path
Public Shared Function GetLnkTarget(ByVal lnkPath As String) As String
Dim shl = New Shell32.Shell()
lnkPath = System.IO.Path.GetFullPath(lnkPath)
Dim dir = shl.NameSpace(System.IO.Path.GetDirectoryName(lnkPath))
Dim itm = dir.Items().Item(System.IO.Path.GetFileName(lnkPath))
Dim lnk = DirectCast(itm.GetLink, Shell32.ShellLinkObject)
Return lnk.Target.Path
End Function
End Class

Set a treeview to specific location

I have a folder in my C: drive that I want to access as soon as my form loads. I don't want to scroll through opening each node everytime. I'm wanting to use a treeview as I know how to use a lot of the features in these and it will suit my purpose.
I shall give you an example of what i am wanting using a basic file structure:
C:\Users\user\Documents\Visual Studio 2010\Projects
This would take me a number of nodes to gain access to if I was to to it through the entire treeview. I want my treeview to to start with, so the main node to be
Projects
How would I go about doing this?
Here is an example which assumes the name of the node is the full path of the folder:
Protected Overrides Sub OnLoad(e As EventArgs)
Dim name As String = "c:\users\blairg\documents\visual studio 2010\projects"
Dim testNode As New TreeNode("Projects")
testNode.Name = name
TreeView1.Nodes.Add(testNode)
Dim node() As TreeNode = TreeView1.Nodes.Find(name, True)
If node.Count = 1 Then
TreeView1.SelectedNode = node(0)
End If
MyBase.OnLoad(e)
End Sub
I am sure that the answer above would work. However i managed to sort it out by doing:
Dim backupfolder As String = netpath & "\MANUFPC BACKUP PROCESS\" & site & "\" & factory & "\" & line & "\" & pc
Dim mRootNode As New TreeNode
mRootNode.Text = pc
mRootNode.Tag = backupfolder
mRootNode.Nodes.Add("*DUMMY*")
'adds plus icon to allow extension
backupFolderDirectory.Nodes.Add(mRootNode)
then the two other functions:
Private Sub TreeView1_BeforeCollapse(ByVal sender As Object, ByVal e As TreeViewCancelEventArgs) Handles backupFolderDirectory.BeforeCollapse
' clear the node that is being collapsed
e.Node.Nodes.Clear()
' add a dummy TreeNode to the node being collapsed so it is expandable
e.Node.Nodes.Add("*DUMMY*")
End Sub
Private Sub TreeView1_BeforeExpand(ByVal sender As Object, ByVal e As TreeViewCancelEventArgs) Handles backupFolderDirectory.BeforeExpand
' clear the expanding node so we can re-populate it, or else we end up with duplicate nodes
e.Node.Nodes.Clear()
' get the directory representing this node
Dim mNodeDirectory As DirectoryInfo
mNodeDirectory = New DirectoryInfo(e.Node.Tag.ToString)
' add each subdirectory from the file system to the expanding node as a child node
Try
For Each mDirectory As DirectoryInfo In mNodeDirectory.GetDirectories
' declare a child TreeNode for the next subdirectory
Dim mDirectoryNode As New TreeNode
Dim mystring(1) As String
mystring(0) = mDirectory.FullName
mystring(1) = "directory"
' store the full path to this directory in the child TreeNode's Tag property
mDirectoryNode.Tag = mystring(0)
' set the child TreeNodes's display text
mDirectoryNode.Text = mDirectory.Name
' add a dummy TreeNode to this child TreeNode to make it expandable
mDirectoryNode.Nodes.Add("*DUMMY*")
' add this child TreeNode to the expanding TreeNode
e.Node.Nodes.Add(mDirectoryNode)
Next
For Each mFiles As FileInfo In mNodeDirectory.GetFiles
' declare a child TreeNode for the next subdirectory
Dim mFileNode As New TreeNode
Dim mystring(1) As String
mystring(0) = mFiles.FullName
mystring(1) = "file"
' store the full path to this directory in the child TreeNode's Tag property
mFileNode.Tag = mystring(0)
' set the child TreeNodes's display text
mFileNode.Text = mFiles.Name
' add this child TreeNode to the expanding TreeNode
e.Node.Nodes.Add(mFileNode)
Next
Catch ex As IOException
'sets up 2 different exceptions then the last one catches other exceptions that could be made from adding folder/files etc
e.Node.Remove()
MsgBox("Device/Folder not accessible", MsgBoxStyle.OkOnly, "Device not Ready")
Catch exc As NullReferenceException
e.Node.Remove()
MsgBox("Sorry this File/Folder can not be added", MsgBoxStyle.OkOnly, "Sorry")
Catch exce As Exception
e.Node.Remove()
MsgBox("Device/Folder not accessible", MsgBoxStyle.OkOnly, "Device not Ready")
End Try
End Sub

File Icons and List view

How to retrieve file icons associated with the file types and add them with the items of Listview in vb.net
I read about SHGetFileInfo but I didn't understand anything from that
please give me solution or please explain me ho system works with the .net controls in details
Having looked up SHGetFileInfo I can see why you're confused by it, but I think it might be slightly overkill for what I think you're trying to do i.e. enumerating the contents of a folder and adding items to the Listview.
If we have a form that contains a ListView and an ImageList, with the two related by having the ListView's LargeImageList property set to the ImageList, then here's how we put the contents of a folder into the ListView with the icons coming from the associated EXE file for each file.
Imports System.IO
Imports System.Drawing
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim dirInfo As DirectoryInfo
Dim fileInfo As FileInfo
Dim exePath As String
Dim exeIcon As Icon
dirInfo = New DirectoryInfo(path_to_some_folder
'We use this For...Each to iterate over the collection of files in the folder
For Each fileInfo In dirInfo.GetFiles
'We can only find associated exes by extension, so don't show any files that have no extension
If fileInfo.Extension = String.Empty Then
Else
'Use the function to get the path to the executable for the file
exePath = GetAssociatedProgram(fileInfo.Extension)
'Use ExtractAssociatedIcon to get an icon from the path
exeIcon = Drawing.Icon.ExtractAssociatedIcon(exePath)
'Add the icon if we haven't got it already, with the executable path as the key
If ImageList1.Images.ContainsKey(exePath) Then
Else
ImageList1.Images.Add(exePath, exeIcon)
End If
'Add the file to the ListView, with the executable path as the key to the ImageList's image
ListView1.Items.Add(fileInfo.Name, exePath)
End If
Next
End Sub
GetAssociatedProgram comes from developer.com
Public Function GetAssociatedProgram(ByVal FileExtension As _
String) As String
' Returns the application associated with the specified
' FileExtension
' ie, path\denenv.exe for "VB" files
Dim objExtReg As Microsoft.Win32.RegistryKey = _
Microsoft.Win32.Registry.ClassesRoot
Dim objAppReg As Microsoft.Win32.RegistryKey = _
Microsoft.Win32.Registry.ClassesRoot
Dim strExtValue As String
Try
' Add trailing period if doesn't exist
If FileExtension.Substring(0, 1) <> "." Then _
FileExtension = "." & FileExtension
' Open registry areas containing launching app details
objExtReg = objExtReg.OpenSubKey(FileExtension.Trim)
strExtValue = objExtReg.GetValue("").ToString
objAppReg = objAppReg.OpenSubKey(strExtValue & _
"\shell\open\command")
' Parse out, tidy up and return result
Dim SplitArray() As String
SplitArray = Split(objAppReg.GetValue(Nothing).ToString, """")
If SplitArray(0).Trim.Length > 0 Then
Return SplitArray(0).Replace("%1", "")
Else
Return SplitArray(1).Replace("%1", "")
End If
Catch
Return ""
End Try
End Function
At the end of all of that, when you run this code on this folder:
alt text http://www.philippursglove.com/stackoverflow/listview1.png
you should get:
alt text http://www.philippursglove.com/stackoverflow/listview2.png
If you know the file name of the file whose icon you want, you can use the System.Drawing.Icon.ExtractAssociatedIcon function for that purpose. e.g.
Icon ico = System.Drawing.Icon.ExtractAssociatedIcon(#"C:\WINDOWS\system32\notepad.exe");
You can also refer to my answer to a related question for more implementation details.