I have the following code:
private void Form2_Load(object sender, EventArgs e)
{
string[] files = Directory.GetFiles(Form1.programdir + "\\card_images", "*", SearchOption.TopDirectoryOnly);
MessageBox.Show(files.ElementAt(1).ToString());
PictureBox[] cards = new PictureBox[files.Count()];
for (int i = 0; i < files.Count(); i++)
{
MessageBox.Show(i.ToString());
cards[i] = new PictureBox();
cards[i].BackgroundImage = new Bitmap(Form1.programdir + "\\card_images\\" + files[i]);
MessageBox.Show(Form1.programdir + "\\card_images\\" + files[i]);
cards[i].Padding = new Padding(0);
cards[i].BackgroundImageLayout = ImageLayout.Stretch;
cards[i].MouseDown += new MouseEventHandler(card_click);
cards[i].Size = new Size((int)(this.ClientSize.Width / 2) - 15, images.Height);
images.Controls.Add(cards[i]);
}
}
Note: "images" is a FlowLayoutPanel in my program's graphic designer. I use it to easily keep track of the images.
I'm trying to get it to display images of a few poker cards, from the directory. The directory is correct, the folder is there, and previous uses of the folder have worked; Form1 is the first form of the program, and "programdir" is:
public static string programdir = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
Messageboxes seem to display the correct diagnostic information (folder location, card file names, even files.Count() seems to be correct), but I can't get any files displayed in pictureboxes. Any advice?
EDIT: Apparently, the line
MessageBox.Show(Form1.programdir + "\\card_images\\" + files[i]);
Does not run, ever, at all, even though
MessageBox.Show(files.ElementAt(1).ToString());
Does run. As well,
MessageBox.Show(i.ToString());
Only runs once, outputting "0" in a messagebox (since "i" is set to 0 initially), even though it should run 4 times, since the size of the array "files" is 4.
EDIT 2: The new code, which runs flawlessly, is:
private void Form2_Load(object sender, EventArgs e)
{
Uri baseUri = new Uri(Form1.programdir + "\\card_images\\");
string[] files = Directory.GetFiles(Form1.programdir + "\\card_images", "*", SearchOption.TopDirectoryOnly);
MessageBox.Show(files.Count().ToString());
PictureBox[] cards = new PictureBox[files.Count()];
for (int i = 0; i < files.Count(); i++)
{
Bitmap bmp = null;
Uri completeUri = new Uri(baseUri, files[i]);
try
{
bmp = new Bitmap(completeUri.LocalPath);
}
catch (Exception exc)
{
// remove this if you don't want to see the exception message
MessageBox.Show(exc.Message);
continue;
}
MessageBox.Show(i.ToString());
cards[i] = new PictureBox();
cards[i].BackgroundImage = bmp;
MessageBox.Show(Form1.programdir + "\\card_images\\" + files[i]);
cards[i].Padding = new Padding(0);
cards[i].BackgroundImageLayout = ImageLayout.Stretch;
cards[i].MouseDown += new MouseEventHandler(card_click);
cards[i].Size = new Size((int)(this.ClientSize.Width / 2) - 15, images.Height);
cards[i].Visible = true;
images.Controls.Add(cards[i]);
}
}
The try/catch block isn't mandatory because it doesn't catch any errors anymore, but I'm leading it just in case something else happens some time down the road. This code will grab all images from the folder (with the assumption that only image files are in the folder, which is a separate issue), display them, and bake you a cake all at once.
So the problem appears to be that the path you are attempting to load from is invalid, because of some assumptions about the output of Directory.GetFiles(), combined with the fact that the exception you would normally expect to see is being silently dropped.
With that in mind, here's my take on a rewrite:
private void Form2_Load(object sender, EventArgs e)
{
string[] files = Directory.GetFiles(Form1.programdir + "\\card_images", "*", SearchOption.TopDirectoryOnly);
foreach (var filename in files)
{
Bitmap bmp = null;
try
{
bmp = new Bitmap(filename);
}
catch (Exception e)
{
// remove this if you don't want to see the exception message
MessageBox.Show(e.Message);
continue;
}
var card = new PictureBox();
card.BackgroundImage = bmp;
card.Padding = new Padding(0);
card.BackgroundImageLayout = ImageLayout.Stretch;
card.MouseDown += new MouseEventHandler(card_click);
card.Size = new Size((int)(this.ClientSize.Width / 2) - 15, images.Height);
images.Controls.Add(card);
}
}
I skipped creating an array since you're not keeping it anyway, and took out your diagnostic MessageBox calls. This code should load any files it finds, ignoring any that it failed to load for whatever reason, and create a PictureBox for each one that loads successfully.
Incidentally, one of the possible reasons for failure is if there are any files in the card_images folder that can't be handled by the Bitmap class. It's good, but it won't render an image from a document file or a DLL :P
Final thought: breakpoints and single-step debugging will definitely help you find the issues much faster. Visual Studio Express is sufficient for the task if you don't have anything else.
Update: Dealing with long path names
Long story short, long filenames are a pain in the rear end.
And the long story....
After a bit of checking it seems that the .NET framework by design (see this series of articles from 2007) will not handle long path names. The \\?\ prefix is rejected by all .NET classes, and UNC paths in the form //localhost/C$/........... are also rejected if they exceed MAX_PATH characters in length.
There are only a few things you can do about this:
The solution suggested by the .NET designers is to get rid of the long paths by relocating the files to a shorter path. (In other words, don't even try to use long paths.)
Create new versions of the System.IO classes with long path support. (Not for the faint of heart.)
A variety of hacks abound, including using the DefineDosDevice API (the core of the old subst dos command) to map an available drive letter to some subset of the path that fits inside the MAX_PATH limit. (Fun, but hacky.)
Use the GetShortPathName API function to turn a long path into an abbreviated version of itself using the 8.3 abbreviations created in the filesystem.
I'll focus on that last option.
public static class NativeMethods
{
const int MAX_PATH = 260;
// Force unicode version to get long-path support
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
static extern uint GetShortPathNameW(
[MarshalAs(UnmanagedType.LPTStr)]
string lpszLongPath,
[MarshalAs(UnmanagedType.LPTStr)]
StringBuilder lpszShortPath,
uint cchBuffer
);
public static string ShortenPath(string longPath)
{
// check if path is already short enough
if (string.IsNullOrWhiteSpace(longPath) || longPath.Length <= MAX_PATH)
return longPath;
// Get short version of path
StringBuilder shortNameBuffer = new StringBuilder(MAX_PATH);
uint result = GetShortPathNameW(#"\\?\" + longPath, shortNameBuffer, (uint)MAX_PATH);
// result is length of returned path. Must be >4 bytes to be valid
if (result <= 4)
return null;
// Get result, removing "\\?\" prefix
var res = shortNameBuffer.ToString().Substring(4);
return res;
}
}
Call NativeMethods.ShortenPath with a valid path of any length and it will try to shorten it for you if necessary. Will fail on long paths if the file couldn't be found, and might return invalid results if the resultant shortened filename is greater than MAX_PATH characters in length... which means you have 27+ directories with long names in the path, which is pretty silly anyway :P
And of course now that you've posted your workaround... it turns out that the path isn't actually too long. sigh If you ever hit the path limit, this will still help.
Related
I am attempting to get the metadata from a few music files and failing miserably. Online, there seems to be absolutely NO HOPE in finding an answer; no matter what I google. I thought it would be a great time to come and ask here because of this.
The specific error I got was: Error HRESULT E_FAIL has been returned from a call to a COM component. I really wish I could elaborate on this issue, but I'm simply getting nothing back from the COMException object. The error code was -2147467259, and it in hex is -0x7FFFBFFB, and Microsoft have not documented this specific error.
I 70% sure that its not the file's fault. My code will run through a directory full of music and convert the file into a song, hence the ConvertFileToSong name. The function would not be running if the file were to not exist is what I'm trying to say.
The only thing I can really say is that I'm using Dotnet 6, and have a massive headache.
Well, I guess I could also share another problem I had before this error showed up. Dotnet6 has top level code or whatever its called, this means that I can't add the [STAThread] attribute. To solve this, I simply added the code bellow to the top. Not sure why I have to set it to unknown, but that's what I (someone else on Stack Overflow) have to do. That solved that previous problem that the Shell32 could not start, but could that be causing my current problem? Who knows... definitely not me.
Thread.CurrentThread.SetApartmentState(ApartmentState.Unknown);
Thread.CurrentThread.SetApartmentState(ApartmentState.STA);
Here is the code:
// Help from: https://stackoverflow.com/questions/37869388/how-to-read-extended-file-properties-file-metadata
public static Song ConvertFileToSong(FileInfo file)
{
Song song = new Song();
List<string> headers = new List<string>();
// initialise the windows shell to parse attributes from
Shell32.Shell shell = new Shell32.Shell();
Shell32.Folder objFolder = null;
try
{
objFolder = shell.NameSpace(file.FullName);
}
catch (COMException e)
{
int code = e.ErrorCode;
string hex = code.ToString();
Console.WriteLine("MESSAGE: " + e.Message + ", CODE: " + hex);
return null;
}
Shell32.FolderItem folderItem = objFolder.ParseName(file.Name);
// the rest of the code is not important, but I'll leave it there anyway
// pretty much loop infinetly with a counter better than
// while loop because we don't have to declare an int on a new
// line
for (int i = 0; i < short.MaxValue; i++)
{
string header = objFolder.GetDetailsOf(null, i);
// the header does not exist, so we must exit
if (String.IsNullOrEmpty(header)) break;
headers.Add(header);
}
// Once the code works, I'll try and get this to work
song.Title = objFolder.GetDetailsOf(folderItem, 0);
return song;
}
Good night,
Diseased Finger
Ok, so the solution isn't that hard. I used file.FullName which includes the file's name, but Shell32.NameSpace ONLY requires the directory name (discluding the file name).
This is the code that fixed it:
public static Song ConvertFileToSong(FileInfo file)
{
// .....
Shell32.Shell shell = new Shell32.Shell();
Shell32.Folder objFolder = file.DirectoryName;
Shell32.FolderItem folderItem = objFolder.ParseName(file.Name);
// .....
return something;
}
I have a program with a FileSystemWatcher which watches for itself to be updated to a new version by an external program (which involves renaming the current executable and copying a new one in its place).
The problem is, when the file it's watching is in the Program Files directory, the FileVersionInfo.GetVersionInfo() doesn't get the new version information, it returns the same thing it got the first time. So if it updated from 1.1 to 1.2, it would say "Upgraded from 1.1 to 1.1" instead of "Upgraded from 1.1 to 1.2". It works correctly in the debug directory, but under Program Files, it won't get the correct value.
Here's the essence of what it's doing, without all the exception handling and disposing and logging and thread invoking and such:
string oldVersion;
long oldSize;
DateTime oldLastModified;
FileSystemWatcher fs;
string fullpath;
public void Watch()
{
fullpath = Assembly.GetEntryAssembly().Location;
oldVersion = FileVersionInfo.GetVersionInfo(fullpath).ProductVersion;
var fi = new FileInfo(fullpath);
oldSize = fi.Length;
oldLastModified = fi.LastWriteTime;
fs = new FileSystemWatcher(
Path.GetDirectoryName(fullpath), Path.GetFileName(file));
fs.Changed += FileSystemEventHandler;
fs.Created += FileSystemEventHandler;
fs.EnableRaisingEvents = true;
}
void FileSystemEventHandler(object sender, FileSystemEventArgs e)
{
if (string.Equals(e.FullPath, fullpath, StringComparison.OrdinalIgnoreCase))
{
var fi = new FileInfo(fullpath);
if (fi.Length != oldSize
|| fi.LastWriteTime != oldLastModified)
{
var newversion = FileVersionInfo.GetVersionInfo(fullpath).ProductVersion;
NotifyUser(oldVersion, newversion);
}
}
}
How do I make GetVersionInfo() refresh to see the new version? Is there something else I should be calling instead?
I'm answering my own question because there doesn't seem to be much interest. If anyone has a better answer, I'll accept that instead...
As far as I can tell, there is no way to make it refresh. Instead I worked around the issue:
return AssemblyName.GetAssemblyName(fullpath).Version.ToString();
Combined with code that makes sure it only gets called once, it seems to work just fine.
i am trying to use the various file functions in C# like File.GetLastWriteTime, copy command on the file placed at the path greater than maximum allowed path on windows 7 i.e 260. Its giving me an error on long path name. On MSDN support i they have asked to use the \\?\ before the path. I did the same but still i got the same error, it seems it doesn't make any change. Below is my code. Please let me know if i am using it correct or i need to add any thing:
These all lib i am using as the code is having other things also:
the below is the respective code:
filesToBeCopied = Directory.GetFiles(path,"*",SearchOption.AllDirectories);
for (int j = 0; j < filesToBeCopied.Length; j++)
{
try
{
String filepath = #"\\?\" + filesToBeCopied[j];
File.GetLastWriteTime(filepath);
}
catch (Exception ex)
{
MessageBox.Show("Error Inside the single file iteration for the path:" +
filesToBeCopied[j] + " . The exception is :" + ex.Message);
}
}
where as path is the path to the folder at windows machine starting with drive letter. for ex.: d:\abc\bcd\cd\cdc\dc\..........
Here's a solution for at least the copying portion of your request (thank you pinvoke.net):
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
static extern bool CopyFile(string lpExistingFileName, string lpNewFileName, bool bFailIfExists);
And then to actually copy your file:
// Don't forget the '\\?\' for long paths
string reallyLongPath = #"\\?\d:\abc\bcd\cd\cdc\dc\..........";
string destination = #"C:\some\other\path\filename.txt";
CopyFile(reallyLongPath , destination, false);
As far as I know, you can't access a file directly if its path is too long (by directly, I mean using the methods of File, by creating a FileInfo via the constructor, or by using Directory.GetFiles(string fileName).
The only way I've found that will let you access such a file is to access a directory somewhere in the path before it gets too long, and then programatically walk down the tree until you get to your file, as seen here.
I've taken my code from there and modified it a little to return a FileInfo object for a file with a path that is "too long". Using this code, you can access the necessary properties on the returned FileInfo object (like LastWriteTime). It still has some limitations though, like the inability to use functions like CopyTo() or OpenText().
// Only call GetFileWithLongPath() if the path is too long
// ... otherwise, new FileInfo() is sufficient
private static FileInfo GetFile(string path)
{
if (path.Length >= MAX_FILE_PATH)
{
return GetFileWithLongPath(path);
}
else return new FileInfo(path);
}
static int MAX_FILE_PATH = 260;
static int MAX_DIR_PATH = 248;
private static FileInfo GetFileWithLongPath(string path)
{
string[] subpaths = path.Split('\\');
StringBuilder sbNewPath = new StringBuilder(subpaths[0]);
// Build longest sub-path that is less than MAX_PATH characters
for (int i = 1; i < subpaths.Length; i++)
{
if (sbNewPath.Length + subpaths[i].Length >= MAX_DIR_PATH)
{
subpaths = subpaths.Skip(i).ToArray();
break;
}
sbNewPath.Append("\\" + subpaths[i]);
}
DirectoryInfo dir = new DirectoryInfo(sbNewPath.ToString());
bool foundMatch = dir.Exists;
if (foundMatch)
{
// Make sure that all of the subdirectories in our path exist.
// Skip the last entry in subpaths, since it is our filename.
// If we try to specify the path in dir.GetDirectories(),
// We get a max path length error.
int i = 0;
while (i < subpaths.Length - 1 && foundMatch)
{
foundMatch = false;
foreach (DirectoryInfo subDir in dir.GetDirectories())
{
if (subDir.Name == subpaths[i])
{
// Move on to the next subDirectory
dir = subDir;
foundMatch = true;
break;
}
}
i++;
}
if (foundMatch)
{
// Now that we've gone through all of the subpaths, see if our file exists.
// Once again, If we try to specify the path in dir.GetFiles(),
// we get a max path length error.
foreach (FileInfo fi in dir.GetFiles())
{
if (fi.Name == subpaths[subpaths.Length - 1])
{
return fi;
}
}
}
}
// If we didn't find a match, return null;
return null;
}
Now that you've seen that, go rinse your eyes and shorten your paths.
try with this code
var path = Path.Combine(#"\\?\", filesToBeCopied[j]); //don't forget extension
"\?\" prefix to a path string tells the Windows APIs to disable all string parsing and to send the string that follows it straight to the file system.
Important : Not all file I/O APIs support "\?\", you should look at the reference topic for each API
http://www.codinghorror.com/blog/2006/11/filesystem-paths-how-long-is-too-long.html
I recently imported some source code for a customer that exceeded the maximum path limit of 256 characters.
The path you pasted was 285 characters long.
As you noted in your comment, MSDN's link here (http://msdn.microsoft.com/en-us/library/aa365247%28VS.85%29.aspx#maximum%5Fpath%5Flength) explains this length in greater detail:
In the Windows API (with some exceptions discussed in the following paragraphs), the maximum length for a path is MAX_PATH, which is defined as 260 characters. A local path is structured in the following order: drive letter, colon, backslash, name components separated by backslashes, and a terminating null character. For example, the maximum path on drive D is "D:\some 256-character path string" where "" represents the invisible terminating null character for the current system codepage. (The characters < > are used here for visual clarity and cannot be part of a valid path string.)
With respect to the \\?\ functionality:
Many but not all file I/O APIs support "\?\"; you should look at the reference topic for each API to be sure.
EDIT 8/8/2012: I've made some significant changes to the code I'm using and would like some fresh help on one last problem I'm having. I'm going to rewrite most of this question.
I have a small program which iterates recursively through each file and folder under a target directory checking the names for specific characters. It works just fine but I'm looking for help on how to make a specific method work faster.
Here's the code I'm currently using. This is just a couple of lines from the method that kicks everything off:
if(getFullList(initialPathTB.Text))
SearchFolder();
And these are the two methods you need to see:
private void SearchFolder()
{
int newRow;
int numItems = 0;
numItems = itemsMaster.Length;
for (int x = 0; x < numItems; x++)
{
if (hasIllegalChars(itemsMaster[x]) == true)
{
newRow = dataGridView1.Rows.Add();
dataGridView1.Rows[newRow].Cells[0].Value = itemsMaster[x];
filesFound++;
}
}
}
private bool getFullList(string folderPath)
{
try
{
if (checkBox17.Checked)
itemsMaster = Directory.GetFileSystemEntries(folderPath, "*", SearchOption.AllDirectories);
else
itemsMaster = Directory.GetFileSystemEntries(folderPath, "*", SearchOption.TopDirectoryOnly);
return true;
}
catch (UnauthorizedAccessException e)
{
if(folderPath[folderPath.Length - 1] != '\\')
folderPath += #"\";
if (e.Message == "Access to the path '" + folderPath + "' is denied.")
{
MessageBox.Show("You do not have read permission for the following directory:\n\n\t" + folderPath + "\n\nPlease select another folder or log in as a user with read access to this folder.", "Access Denied", MessageBoxButtons.OK, MessageBoxIcon.Error);
folderPath = folderPath.Substring(0, folderPath.Length - 1);
}
else
{
if (accessDenied == null)
accessDenied = new StringBuilder("");
accessDenied.AppendLine(e.Message.Substring(20, e.Message.Length - 32));
}
return false;
}
}
initialPathTB.Text is populated with something like "F:\COMMON\Administration".
Here's my problem. When the top level that's passed to folderPath is one which the user does not have read access everything works fine. When the top level and all subordinate directories are folders which the user has read access everything works fine again. The issue lies with directories where the user has read access to the top level but does not for some child folder deeper within. This is why getFullList() is a bool; if there are any UnauthorizedAccessExceptions then itemsMaster remains empty and SearchFolder() fails on numItems = itemsMaster.Length;.
What I'd like is to populate itemsMaster with every item within folderPath and simply skip the items for which the user doesn't have read access but I don't know how to do that without recursively crawling and checking each directory.
This code works so much faster than my old method so I'd rather not abandon it for something else entirely. Is there any way to make the Directory.GetFileSystemEntries() method do what I want?
Directory.GetFileSystemEntries(folderPath, "*", SearchOption.AllDirectories).Length
or another option (with this option, keep in mind the first 3-5 elements in fullstring will be garbage text from the output which you should remove):
Process process = new Process();
List<string> fullstring = new List<string>();
process.StartInfo.FileName = "cmd.exe";
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardInput = true;
process.StartInfo.UseShellExecute = false;
process.OutputDataReceived += (sender, args2) => fullstring.Add(args2.Data);
process.Start();
process.StandardInput.WriteLine(#"dir /b /s c:\temp | find """" /v");
process.BeginOutputReadLine();
process.WaitForExit(10000); //or whatever is appropriate time
process.Close();
If you want to track down errors better, make these changes:
Declare List<string> fullstring = new List<string>(); globally, then change the event handler of OutputDataReceived like below:
process.OutputDataReceived += new DataReceivedEventHandler(process_OutputDataReceived);
}
static void process_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
try
{
fullstring.Add(e.Data);
}
catch (Exception ex)
{
Debug.WriteLine(ex.ToString());
//log exception
}
}
You write that "I'd like the progress bar to actually indicate how far through the list of items the program is, so therefore I need a number of items to set the ProgressBar.Maximum property to."
This is kind of a specific desire, and I'm not sure its worthwhile in the given case. If your ProgressBar is (say) 800 px wide, 1 percentage point would be 0.125px wide. For a list "over a hundred thousand items" -- let's make that a minimum of 100,000 -- you have to process 8,000 items to move the bar to move a single pixel. How much time does it take for your program to process 8,000 items? That will help you understand what kind of actual feedback you're giving the user. If it takes too long, it might look like things have hung, even if it's working.
If you're looking to give good user feedback, I'd suggest setting your ProgressBar's style to Marquee and providing a "Now checking file #x" textual indicator.
I've googled about this all over the Internet and still haven't found a solution. As an ultimate try, I hope someone can give me an exact answer.
I get that error when I try to copy a file from a directory to another in an File Explorer I'm trying to do on my own. It has a treeview control to browse for directories and a listview control to display the contents of the directory. This is how the code would look like, partially:
private void copyToolStripMenuItem_Click(object sender, EventArgs e)
{
sourceDir = treeView1.SelectedNode.FullPath;
for (int i = 0; i < listView1.SelectedItems.Count; ++i)
{
ListViewItem l = listView1.SelectedItems[i];
toBeCopied[i] = l.Text; // string[] toBeCopied, the place where I save the file names I want to save
}
}
private void pasteToolStripMenuItem_Click(object sender, EventArgs e)
{
targetDir = treeView1.SelectedNode.FullPath;
try
{
for (int i = 0; i < toBeCopied.Length; ++i)
{
File.Copy(sourceDir + "\\" + toBeCopied[i], targetDir + "\\" + toBeCopied[i], true);
refreshToolStripMenuItem_Click(sender, e);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message + Environment.NewLine + ex.TargetSite);
}
}
The place where I got the error is at File.Copy(sourceDir + "\\" + toBeCopied[i] ....
I've read that it could be something that has to do with the mapping of devices, but I don't really know what that is.
Can you take a look at the Path.Combine method on MSDN? This will help make sure all your entire path doesn't have extra \'s where they shouldn't be.
i.e. Path.Combine(sourceDir, toBeCopied[i])
If you are still getting an error, let me know what the value if the above.
Does the target path up to the file name exist? File.Copy() will not create any missing intermediate path, you would need to do this yourself. Use the debugger to see both the source and target paths you are creating and make sure the source exists and the target exists at least up to the parent of the target file.
You do not show where toBeCopied is created. It looks like you are probably running past the end of the values that are set in the click event, and trying to copy a bunch of files with empty names.
You should add this to the beginning of your click event
toBeCopied = new string[listView1.SelectedItems.Count];
Also (as others have noted) instead of
sourceDir + "\\" + toBeCopied[i]
you should use
Path.Combine(sourceDir, toBeCopied[i])
Assuming both sourceDir and targetDir exist (which you can and should check), you might be doubling up a trailing \. When building paths, you should use Path.Combine.
File.Copy(Path.Combine(sourceDir, toBeCopied[i]), Path.Combine(targetDir, toBeCopied[i]), true);
Borrowing from Henk's loop, but I'd add the file & directory checks, since it is the path not found errors that need checking/creating that the OP has the problem with.
for (int i = 0; i < toBeCopied.Length; ++i)
{
string sourceFile = Path.Combine(sourceDir, toBeCopied[i]);
if(File.Exists(sourceFile))
{
string targetFile = Path.Combine(targetDir, toBeCopied[i]);
if(!Directory.Exists(targetDir))
Directory.CreateDirectory(targetDir);
File.Copy(sourceFile, targetFile, true);
}
refreshToolStripMenuItem_Click(sender, e)
}