throwing UnauthorizedAccessException when accessing an image file - c#

I have a problem with accessing and copying an image file. Here my code
private void button1_Click(object sender, EventArgs e)
{
OpenFileDialog openFileDialog1 = new OpenFileDialog();
openFileDialog1.ShowDialog();
string fileName = "";
fileName = openFileDialog1.FileName;
string newPath = #"C:\Users\grafik5\source\repos\ConsoleApplication1\x64\Debug";
string newFileName = #"image";
string ext = Path.GetExtension(fileName);
openFileDialog1.Dispose();
newPath = Path.Combine(newPath, newFileName + ext);
if (fileName != "")
{
try
{
FileSecurity oFileSecurity = new FileSecurity();
oFileSecurity.AddAccessRule(new FileSystemAccessRule("Everyone", FileSystemRights.FullControl, AccessControlType.Allow));
File.SetAccessControl(fileName, oFileSecurity);
}
catch (UnauthorizedAccessException)
{
MessageBox.Show("Error");
}
File.Copy(fileName, newPath, true);
Process process = new Process();
process.StartInfo.FileName = #"C:\Users\grafik5\source\repos\ConsoleApplication1\x64\Debug\ConsoleApplication1.exe";
process.Start();
process.WaitForExit();
flag1 = true;
}
}
I don't know what I need to do. My program always throws the error message.
Another process will read the copied image. It will do image processing.
There is no problem with the process of working. I checked it.
Error is at File.SetAccessControl(fileName, oFileSecurity);

Any young Codeling Jedi should have looked at the documentation, which i assume you have. However -
File.SetAccessControl Method (String, FileSecurity)
Applies access control list (ACL) entries described by a FileSecurity
object to the specified file.
Exceptions
UnauthorizedAccessException
The path parameter specified a file that is read-only.
This operation is not supported on the current platform.
The path parameter specified a directory.
The caller does not have the required permission.
This is probably a permissions thing. The easiest fix, is make sure your application has the appropriate permissions to do this.
Either
Elevate your app by running it as Administrator,
Give your user the appropriate permissions to set the ACL
However it should be wise and prudent, to check if the other conditions apply

Related

Directory could not be found

I have recently started to get an error which states my directory can not be found I have tried a number of ways to solve this but have yet to find a solution.
The method should allow the user to select an image for their computer and add it to a folder called images inside the applications folder structure. The problem is that when using the File.copy(imageFilename, path); it throws the error. I have tried changing the path and you will see from the code snip it. It is even doing it when the program itself has passed the file path for the application and is still throwing me the error.
this is the method.
private void btnImageUpload_Click(object sender, RoutedEventArgs e)
{
OpenFileDialog imageFile = new OpenFileDialog();
imageFile.InitialDirectory = #"C:\";
imageFile.Filter = "Image Files (*.jpg)|*.jpg|All Files(*.*)|*.*";
imageFile.FilterIndex = 1;
if (imageFile.ShowDialog() == true)
{
if(imageFile.CheckFileExists)
{
string path = AppDomain.CurrentDomain.BaseDirectory;
System.IO.File.Copy(imageFile.FileName, path);
}
}
}
I am using VS2013 and have included the using Microsoft.win32
Any further information needed please ask.
Thanks
There are 2 things need to be taken into consideration
private void btnImageUpload_Click(object sender, RoutedEventArgs e)
{
OpenFileDialog imageFile = new OpenFileDialog();
imageFile.InitialDirectory = #"C:\";
imageFile.Filter = "Image Files (*.jpg)|*.jpg|All Files(*.*)|*.*";
imageFile.FilterIndex = 1;
if (imageFile.ShowDialog() == true)
{
if(imageFile.CheckFileExists)
{
string path = AppDomain.CurrentDomain.BaseDirectory; // You wont need it
System.IO.File.Copy(imageFile.FileName, path); // Copy Needs Source File Name and Destination File Name
}
}
}
string path = AppDomain.CurrentDomain.BaseDirectory; You won need this because the default directory is your current directory where your program is running.
Secondly
System.IO.File.Copy(imageFile.FileName, path); Copy Needs Source File Name and Destination File Name so you just need to give the file name instead of path
so your updated code will be
private void btnImageUpload_Click(object sender, RoutedEventArgs e)
{
OpenFileDialog imageFile = new OpenFileDialog();
imageFile.InitialDirectory = #"C:\";
imageFile.Filter = "Image Files (*.jpg)|*.jpg|All Files(*.*)|*.*";
imageFile.FilterIndex = 1;
if (imageFile.ShowDialog() == true)
{
if(imageFile.CheckFileExists)
{
System.IO.File.Copy(imageFile.FileName, SomeName + ".jpg"); // SomeName Must change everytime like ID or something
}
}
}
I'm not sure if that's the problem, but the File.Copy method expects a source file name and a target file name, not a source file name and directory: https://msdn.microsoft.com/en-us/library/c6cfw35a(v=vs.110).aspx
So, to make this work, in your case you'd have to do something like the following (namespaces omitted):
File.Copy(imageFile.FileName, Path.Combine(path, Path.GetFileName(imageFile.FileName));
Note that this will fail if the destination file exists, to overwrite it, you need to add an extra parameter to the Copy method (true).
EDIT:
Just a note, the OpenFileDialog.CheckFileExists does not return a value indicating if the selected file exists. Instead, it is a value indicating whether a file dialog displays a warning if the user specifies a file name that does not exist. So instead of checking this property after the dialog is closed, you should set it to true before you open it (https://msdn.microsoft.com/en-us/library/microsoft.win32.filedialog.checkfileexists(v=vs.110).aspx)

Check if the process exists before process.start();

I made a little program that execute executable file (.exe) but when you write down no existed file I get an error, the file specific not found.
So I'm wondering if there's a way to check if the process exists first before running it, and if it doesn't exist you can show a message box.
This is my code
private void btn_Start_Click(object sender, EventArgs e)
{
string text = textBox1.Text;
Process process = new Process();
if (!textBox1.Text.Contains(".exe"))
{
process.StartInfo.FileName = text + ".exe";
}
else
{
process.StartInfo.FileName = text;
}
process.Start();
}
Check that file is exists before start process:
var processFileName = !textBox1.Text.Contains(".exe")
? text + ".exe"
: text;
if (File.Exists(processFileName))
{
Process process = new Process();
process.Start(processFileName);
}
Please try the following code:
->(You have to add #using System.IO; before using "File.Exists" command)
button1_Click(object sender, EventArgs )
{
string exepath = "C:\\example\\example.xlsx";
if(File.Exists(exepath))
{
Process.Start(exepath);
}
else
{
MessageBox.Show("File not found!");
}
}
Hope it's working !
You can string the path and string the filename in other string, and then you can even check the Folder, and if the folder exists ,then check the file!
Also you can use your textbox1 as filename, but you have to add the path, unless it will be search in the program directory.(bin/debug)
If i was wrong, forgive me, i am learning c# at the moment!
Have a good day!

Wont download file to My documents folder

One of my customers having a problem with my ActiveX control. The ActiveX is supposed to download an Excel file, save it in a folder in My documents and then Run Excel and open the file.
Here is the code snippet for downloading and opening the file:
private string Checkout(string strFileUrl, string strPhysicalDir, string strPhysicalName)
{
string strMyDocumentFolder = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
string strCiroDocFolder = String.Format(#"{0}\CiroDoc", strMyDocumentFolder);
string strCheckoutFolder = String.Format(#"{0}\{1}", strCiroDocFolder, strPhysicalDir);
string strFilePath = String.Format(#"{0}\{1}", strCheckoutFolder, strPhysicalName);
try
{
if (!Directory.Exists(strCiroDocFolder))
Directory.CreateDirectory(strCiroDocFolder);
if (!Directory.Exists(strCheckoutFolder))
Directory.CreateDirectory(strCheckoutFolder);
if (File.Exists(strFilePath))
File.Delete(strFilePath);
WebClient myWebClient = new WebClient();
myWebClient.DownloadFile(strFileUrl, strFilePath);
}
catch (Exception e)
{
return e.Message;
}
return Run(strFilePath);
}
private string Run(string strFilePath)
{
if (!File.Exists(strFilePath))
return "filenotfound";
if (IsExecutable(strFilePath))
return "isexecutable";
try
{
System.Diagnostics.Process.Start(strFilePath);
}
catch (Exception e)
{
//This get returned
return String.Format("{0} ({1})", e.Message, strFilePath);
}
return "success";
}
The Run method returns the exception "an error occurred when the command is sent to the program".
When I check the My documents folder, the file is not there. Since it's not there, I would expect the Run method stop and return "filenotfound".
This confuses me. Why does the File.Exists return true? Is it Windows file virtualization that kicks in and the file is saved in VirtualStore folder? If so, how can stop that behaviour? Or could it be something else in my customer's machine that causes this behaviour?
I haven't been able to reproduce this problem on my own machine yet. If you know how I would be grateful.
My customer's computer setup
OS: Windows 7
Browser: IE 10
Antivirus: McAfee
If there is some relevant information Im missing I'll try to get it.
Having Internet Explorer in Protective mode and UAC enabled causes System.Diagnostics.Process.Start(strFilePath); not to run as expected.
Using this code instead will open the Excel file, even in Protective mode.
Process myProcess = new Process();
myProcess.EnableRaisingEvents = false;
myProcess.StartInfo.FileName = "excel";
myProcess.StartInfo.Arguments = String.Format(#"""{0}""", strFilePath);
myProcess.Start();

take ownership of a file c#

I am trying to take ownership of a file and delete it via C#.
The file is iexplorer.exe, current owner by default - TrustedInstaller.
The method FileSecurity.SetOwner seems to set the specified ownership, but actually doesn't change the initial owner and throws no exception.
Obviously, the next attempt to delete the file throws an exception.
What should be changed in the code to take ownership of the file and delete it ?
var fileS = File.GetAccessControl(#"C:\Program Files (x86)\Internet Explorer\iexplore.exe");
fileS.SetOwner(new System.Security.Principal.NTAccount(Environment.UserDomainName, Environment.UserName));
File.Delete(#"C:\Program Files (x86)\Internet Explorer\iexplore.exe");
You must explicitly enable SeTakeOwnershipPrivilege:
Required to take ownership of an object without being granted
discretionary access. This privilege allows the owner value to be set
only to those values that the holder may legitimately assign as the
owner of an object. User Right: Take ownership of files or other
objects.
I suggest you to read the great article written by Mark Novak: Manipulate Privileges in Managed Code Reliably, Securely, and Efficiently.
And/or take a look at his sample.
Update
Example usage:
var fileS = File.GetAccessControl(#"C:\Program Files (x86)\Internet Explorer\iexplore.exe");
Privilege p;
bool ownerChanged = false;
try
{
p = new Privilege(Privilege.TakeOwnership);
p.Enable();
fileS.SetOwner(new System.Security.Principal.NTAccount(
Environment.UserDomainName, Environment.UserName));
ownerChanged = true;
}
catch(PrivilegeNotHeldException e)
{
// privilege not held
// TODO: show an error message, write logs, etc.
}
finally
{
p.Revert();
}
if (ownerChanged)
File.Delete(#"C:\Program Files (x86)\Internet Explorer\iexplore.exe");
string filepath = #"C:\Program Files (x86)\Internet Explorer\iexplore.exe";
//Get Currently Applied Access Control
FileSecurity fileS = File.GetAccessControl(filepath);
//Update it, Grant Current User Full Control
SecurityIdentifier cu = WindowsIdentity.GetCurrent().User;
fileS.SetOwner(cu);
fileS.SetAccessRule(new FileSystemAccessRule(cu, FileSystemRights.FullControl, AccessControlType.Allow));
//Update the Access Control on the File
File.SetAccessControl(filepath, fileS);
//Delete the file
File.Delete(filepath);
Add the following imports
using System.IO;
using System.Security.AccessControl;
using System.Security.Principal;
Run the Code in Elevated Mode.
Powered in Windows 8.1 using class Privilege from example:
Manipulate Privileges in Managed Code Reliably, Securely, and Efficiently
private bool TryDeleteFile(string fileName)
{
string filePath = Path.GetFullPath(fileName);
var fi = new FileInfo(filePath);
bool ownerChanged = false;
bool accessChanged = false;
bool isDelete = false;
FileSecurity fs = fi.GetAccessControl();
Privilege p = new Privilege(Privilege.TakeOwnership);
try
{
p.Enable();
fs.SetOwner(WindowsIdentity.GetCurrent().User);
File.SetAccessControl(filePath, fs); //Update the Access Control on the File
ownerChanged = true;
}
catch (PrivilegeNotHeldException ex) { }
finally { p.Revert(); }
try
{
fs.SetAccessRule(new FileSystemAccessRule(WindowsIdentity.GetCurrent().User, FileSystemRights.FullControl, AccessControlType.Allow));
File.SetAccessControl(filePath, fs);
accessChanged = true;
}
catch (UnauthorizedAccessException ex) { }
if (ownerChanged && accessChanged)
{
try
{
fi.Delete();
isDelete = true;
}
catch (Exception ex) { }
}
return isDelete;
}
See these registry entries for adding a context menu. I was able to rename the folder as well as iexplorer_OFF.exe on Windows 7.
You can probably shell/execute the same from your code.
https://www.howtogeek.com/howto/windows-vista/add-take-ownership-to-explorer-right-click-menu-in-vista/

How can I watch a directory with a FileSystemWatcher and still allow for it to be properly deleted?

Consider this code:
string dir = Environment.CurrentDirectory + #"\a";
Directory.CreateDirectory(dir);
FileSystemWatcher watcher = new FileSystemWatcher(dir);
watcher.IncludeSubdirectories = false;
watcher.EnableRaisingEvents = true;
Console.WriteLine("Deleting " + dir);
Directory.Delete(dir, true);
if (Directory.Exists(dir))
{
Console.WriteLine("Getting dirs of " + dir);
Directory.GetDirectories(dir);
}
Console.ReadLine();
Interestingly this throws an UnauthorizedAccessException on Directory.GetDirectories(dir).
Deleting the watched directory returns without error, but Directory.Exists() still returns true and the directory is still listed. Furthermore accessing the directory yields "Access denied" for any program. Once the .NET application with the FileSystemWatcher exits the directory vanishes.
How can I watch a directory while still allowing it to be properly deleted?
You did in fact delete the directory. But the directory won't be physically removed from the file system until the last handle that references it is closed. Any attempt to open it in between (like you did with GetDirectories) will fail with an access denied error.
The same mechanism exists for files. Review FileShare.Delete
Try this line:
if (new DirectoryInfo(dir).Exists)
instead of:
if (Directory.Exists(dir))
You should use FileSystemInfo.Refresh. After .Refresh() .Exists shows correct result:
var dir = new DirectoryInfo(path);
// delete dir in explorer
System.Diagnostics.Debug.Assert(dir.Exists); // true
dir.Refresh();
System.Diagnostics.Debug.Assert(!dir.Exists); // false
Unfortunately FileSystemWatcher has taken a handle to the directory this means that when the directory is deleted that there is still a handle to the directory marked as PENDING DELETE. I've tried some experiments and it seems that you can use the Error event handler from FileSystemWatcher to identify when this happens.
public myClass(String dir)
{
mDir = dir;
Directory.CreateDirectory(mDir);
InitFileSystemWatcher();
Console.WriteLine("Deleting " + mDir);
Directory.Delete(mDir, true);
}
private FileSystemWatcher watcher;
private string mDir;
private void MyErrorHandler(object sender, FileSystemEventArgs args)
{
// You can try to recreate the FileSystemWatcher here
try
{
mWatcher.Error -= MyErrorHandler;
mWatcher.Dispose();
InitFileSystemWatcher();
}
catch (Exception)
{
// a bit nasty catching Exception, but you can't do much
// but the handle should be released now
}
// you might not be able to check immediately as your old FileSystemWatcher
// is in your current callstack, but it's a start.
}
private void InitFileSystemWatcher()
{
mWatcher = new FileSystemWatcher(mDir);
mWatcher.IncludeSubdirectories = false;
mWatcher.EnableRaisingEvents = true;
mWatcher.Error += MyErrorHandler;
}

Categories