Why is PictureBox.Load locking image on some systems? - c#

(Please see the edit on the bottom of the question, if you do not want to read the whole story.)
Hi,
I am new to stackoverflow. Don’t get me wrong, I use it quite often. But up until now I never actually posted something. This is because I did not have something new/useful to say and my English is not that good. The first thing (might have) changed, the latter did not.
I ran into a problem at a customer's Windows 7 system quite recently. I was shipping a C# .Net 4.0 Windows Forms application via ClickOnce. Basically, it is an application that creates a bitmap file and shows it to the user. If the bitmap exists prior to the creation, the existing file gets deleted first. After that the new file is created and loaded by a PictureBox.
The following thing occurred at the customer’s system: After starting the application the first creation succeeds – the second and all following ones do not. The file cannot be deleted, because some process is blocking it. This process is the application itself.
System.IO.IOException: The process cannot access the file “filename” because it is being used by another process.
Well, of course that is nothing unusual. The thing is I tested the application on several systems. None showed this exception. And until now I am unable to see an code error.
So I looked a little bit closer on the customer’s system: The only difference I could find is, that they changed the users folder so that they are not located on the windows partition, but on a different one (C:\Users --> D:\Users). I searched for an instruction on the internet and did the same thing on one of my test systems. To my surprise I got the same exception when I ran my application on it.
With that I could change my code so that the exception does not occur anymore. But I do not understand why that is. So maybe there is something wrong with my code and the error just reveals itself under that special circumstances. Or maybe the code is okay and the reason lies somewhere else. I just hoped that you might be able to help me.
So here is some code I put together, that shows the same behavior. I used 3 buttons, an OpenFileDialog and a PictureBox on a Form. First thing to do is to choose an image file. By pressing one of the two remaining buttons it gets copied into the main folder of the application. After being copied it is shown by the PictureBox. By the way, it does not seem to matter if it is a ClickOnce-application or a “normal” one.
String m_FileName;
private void btnChooseFile_Click(object sender, EventArgs e) {
if(openFileDialog1.ShowDialog() == System.Windows.Forms.DialogResult.OK) { // If file was chosen, set file name for later use and activate buttons.
m_FileName = "Test" + Path.GetExtension(openFileDialog1.FileName);
}
}
private void button1_Click(object sender, EventArgs e) {
// This is not working.
if(this.pictureBox1.Image != null) {
//Image img = this.pictureBox1.Image; // I was not sure, if maybe the pictureBox somehow prevents the disposing of the image, as long as it's assigned to it.
//this.pictureBox1.ImageLocation = null; // So I set them null, both the image and the image location.
//this.pictureBox1.Image = null;
//img.Dispose(); // Then I disposed the image.
this.pictureBox1.Image.Dispose(); // The short version. It is not working either way.
this.pictureBox1.Image = null;
}
(new FileInfo(openFileDialog1.FileName)).CopyTo(m_FileName, true); // But still this is where the Exception occurs.
this.pictureBox1.Load(m_FileName);
}
private void button2_Click(object sender, EventArgs e) {
//This is working.
if(this.pictureBox1.Image != null) {
//Image img = this.pictureBox1.Image;
//this.pictureBox1.Image = null;
//img.Dispose();
this.pictureBox1.Image.Dispose();
this.pictureBox1.Image = null;
}
(new FileInfo(openFileDialog1.FileName)).CopyTo(m_FileName, true);
pictureBox1.Image = Image.FromFile(m_FileName);
}
What happens now is the following: If I start the application and click button1 twice, I will get the exception (on the second click). If I start it and click button2 twice, I will not. If I start the application and click buttons1 first and after that button2, I will get the exception. So, the Picture.Load-Function somehow blocks the file, even if I dispose it.
When I searched on the internet, I found an article from microsoft: http://support.microsoft.com/kb/309482/en-us. But it does not hit the bull's eye.
Take into account, that both versions are working on all my test machines. I just get the exception when I change the users folder to a non-windows-partition.
Why is that? And where is the difference in the presented versions?
Edit
Okay, because of the first and only reaction so far, it seems to me, that it is still not clear, what really happens: If I take the above code, put it in a Windows Forms application, compile it and run it on different computers (at work, at home, does not matter) it works - both button1 and button2 (with the Click-functions linked to them) can be used as often as I like - no exception thrown. If I run the application on a computer, where I changed the users folder, and click button1 the second time - bam - IOException, file locked by process. Button2 works as long as I do not press button1.
The first answer implies, that I should get the locking on every system. But I DO NOT (as long as I do not change the users folder)! I tested it on every single computer I could get my hands on - no IOException. I set up a new system, just to rule out some special changes to the systems in my company - both buttonx_Click functions worked - no exception either. I even compiled the program on another computer - same behavior. The only three systems to throw that exception were the ones with the changed users folder.
So far I have no clue, why this difference in behavior occurs. Can somebody help me?
Anybody?

Yes, this is normal. Happens on any operating system, doesn't have anything to do with the Users folder location. The PictureBox.Load() method was intented to be used to load images from locations other than the file system. Like a web site. Which is slow, it avoids freezing the UI while the download is taking place.
It internally uses a FileStream when it discovers that the url you pass is actually a file and not a website name. This FileStream does not get disposed until the PictureBox itself is disposed or you call the Load() method again. A requirement because Image.FromStream() requires the stream to remain readable until the image is no longer used. It is this FileStream that keeps a lock on the file. Disposing the PictureBox.Image is not enough to also dispose the FileStream, the Image object doesn't know that it is being displayed inside a picture box.
There are several ways to solve this problem:
Use the Image property instead of Load(), assign it from Image.FromFile(). Disposing the Image now also releases the lock on the file. As you found out
Keep a dummy image around, one that perhaps displays a "Loading..." bitmap. Load() it first to release the lock on the file
Dispose the PictureBox and recreate it.

This works and unlocks the file
Image img= Image.FromFile(mypath);
Graphics g = pictureBox1.CreateGraphics();
g.DrawImage(img,0,0);
img.Dispose();

Related

UIAutomation throws AccessViolationException on Windows 11

The issue:
We have an application written in C# that uses UIAutomation to get the current text (either selected or the word behind the carret) in other applications (Word, OpenOffice, Notepad, etc.).
All is working great on Windows 10, even up to 21H2, last update check done today.
But we had several clients informing us that the application is closing abruptly on Windows 11.
After some debugging I've seen some System.AccessViolationException thrown when trying to use the TextPatternRange.GetText() method:
System.AccessViolationException: 'Attempted to read or write protected memory. This is often an indication that other memory is corrupt.'
What we've tried so far:
Setting uiaccess=true in manifest and signing the app : as mentionned here https://social.msdn.microsoft.com/Forums/windowsdesktop/en-US/350ceab8-436b-4ef1-8512-3fee4b470c0a/problem-with-manifest-and-uiaccess-set-to-true?forum=windowsgeneraldevelopmentissues => no changes (app is in C:\Program Files\
In addition to the above, I did try to set the level to "requireAdministrator" in the manifest, no changes either
As I've seen that it may come from a bug in Windows 11 (https://forum.emclient.com/t/emclient-9-0-1317-0-up-to-9-0-1361-0-password-correction-crashes-the-app/79904), I tried to install the 22H2 Preview release, still no changes.
Reproductible example
In order to be able to isolate the issue (and check it was not something else in our app that was causing the exception) I quickly made the following test (based on : How to get selected text of currently focused window? validated answer)
private void btnRefresh_Click(object sender, RoutedEventArgs e)
{
var p = Process.GetProcessesByName("notepad").FirstOrDefault();
var root = AutomationElement.FromHandle(p.MainWindowHandle);
var documentControl = new
PropertyCondition(AutomationElement.ControlTypeProperty,
ControlType.Document);
var textPatternAvailable = new PropertyCondition(AutomationElement.IsTextPatternAvailableProperty, true);
var findControl = new AndCondition(documentControl, textPatternAvailable);
var targetDocument = root.FindFirst(TreeScope.Descendants, findControl);
var textPattern = targetDocument.GetCurrentPattern(TextPattern.Pattern) as TextPattern;
string text = "";
foreach (var selection in textPattern.GetSelection())
{
text += selection.GetText(255);
Console.WriteLine($"Selection: \"{selection.GetText(255)}\"");
}
lblFocusedProcess.Content = p.ProcessName;
lblSelectedText.Content = text;
}
When pressing a button, this method is called and the results displayed in labels.
The method uses UIAutomation to get the notepad process and extract the selected text.
This works well in Windows 10 with latest update, crashes immediately on Windows 11 with the AccessViolationException.
On Windows 10 it works even without the uiaccess=true setting in the manifest.
Questions/Next steps
Do anyone know/has a clue about what can cause this?
Is Windows 11 way more regarding towards UIAutomation?
On my side I'll probably open an issue by Microsoft.
And one track we might follow is getting an EV and sign the app itself and the installer as it'll also enhance the installation process, removing the big red warnings. But as this is an app distributed for free we had not done it as it was working without it.
I'll also continue testing with the reproductible code and update this question should anything new appear.
I posted the same question on MSDN forums and got this answer:
https://learn.microsoft.com/en-us/answers/questions/915789/uiautomation-throws-accessviolationexception-on-wi.html
Using IUIautomation instead of System.Windows.Automation works on Windows 11.
So I'm marking this as solved but if anyone has another idea or knows what happens you're welcome to comment!

Trying Upload same file in windows form

I am working to develop a Windows form Project, we should use a Product picture.
Every this working well, we use File.Exists() to check if the file already exists then copy the image to the product Image folder.
if (image.ShowDialog() == DialogResult.OK && !string.IsNullOrEmpty(image.FileName))
{
_view.FirmLogo.Image = new Bitmap(image.FileName);
_view.LogoURL = Path.Combine(System.IO.Path.GetFullPath(#"..\..\"), #"Resources\ProductImage\", Path.GetFileName(image.FileName));
//
if (File.Exists(_view.LogoURL))
{
File.Delete(_view.LogoURL);
}
//File.Move(#"c:\test\SomeFile.txt", #"c:\test\Test\SomeFile.txt");
File.Copy(image.FileName, _view.LogoURL);
}
The Bug
when we try to update the same file it fired an error:
"because it is being used by another process.
Ex. if we upload pic1, everything is well, we try to change to pic2 great job.
but if we try to back the pic1 fired the error especially if it happens in the same seesion.

C#, No video, audio only, VLC using multiple forms, Black Screen?

Can someone please tell me whey I am getting a black screen with no video, only sound?
private void screen1btnPlay_Click(object sender, EventArgs e)
{
ScreenOne playScreen1 = new ScreenOne();
playScreen1.PlayScreenOne();
}
... and the other form is like this:
public partial class ScreenOne : Form
{
public ScreenOne()
{
InitializeComponent();
}
public void PlayScreenOne()
{
axVLCPlugin21.playlist.add("file:///" + #"Filepath", null);
axVLCPlugin21.playlist.play();
}
}
Sound works fine, but no video. All the properties of the VLC are left to default, is there something I need to change when using this plugin across multiple forms? Anyone know what's wrong?
Update:: I rebuilt the program in WPF and I am having the same problem. When I have a button on the second form (same form as player) it works fine, as soon as I call it from the main form, sound only. ugh!
I dont know but i can give some solution suggestions,
Make sure the VLC program is installed as 32-bit. I dont know, I've solved a problem that way.
I think high probabilty your problem is based on about "C:\Program Files (x86)\VideoLAN\VLC\plugins" Check your plugins. maybe your audio_filter, audio_mixer, audio_output plugins are missing.
you can remove Vlc, then download and install last VLC 32 bit.
I think that will solve your problem. Dont forget AxAXVLC works with vlc plugins.
I figured out my problem on my own!
When I was creating this instance,
ScreenOne playScreen1 = new ScreenOne();
I was actually creating a redundant instance of what I was trying to do, I'm not sure if that's the right way to put it but I basically already had an instance of the second form and was making another separate instance of the form that was named differently.
I already had in my code to open the second form
Screen2 Screen2 = new Screen2();
private void openScreen2Button_Click(object sender, EventArgs e)
{
Screen2.Show();
}
Then later was doing this which is WRONG, I was adding playscreen1 when I should still have been using Screen2.
Screen2 playScreen1 = new Screen2();
playScreen1.PlayScreenOne();
So when I wanted to use the method to play the media player on the second form from the first one, I just needed to use the same instance of Screen2 that I had created to open the form to begin with instead of created a new instance for what method I wanted to use.
IDK if my explanation makes sense, or maybe its basics to most people (I'm a noob), but if anyone comes across this problem, message me and I'll try to help.
o7

EMGU CV Face Recognition from Image

I've been working with OpenCV before for C++ work and It was working great. Now, I'm developing a C# project and using EMGU CV for gender recognition. I've got problem with predict function. Every time I ran it, program crashed on Predict function, when I erased predict line, it is running. Here's my code:
private void Window_Loaded(object sender, RoutedEventArgs e)
{
FaceRecognizer face = new FisherFaceRecognizer(0, 3500);
face.Load("colorFisherFaceModel.yml");
Image<Bgr, Byte> img1 = new Image<Bgr, Byte>("C:\\Users\\sguthesis\\Pictures\\me.jpg");
cascade = new CascadeClassifier("C:\\Users\\sguthesis\\documents\\visual studio 2013\\Projects\\EmguCV FFR with Image\\EmguCV FFR with Image\\haarcascade_frontalface_alt_tree.xml");
FaceRecognizer.PredictionResult predictedLabel = face.Predict(img1);
}
Also, I want to get an output, 1 or 2. 1 for male and 2 for female. I have trained many data that saved on colorFisherFaceModel.yml. It was run well on OpenCV. But I don't know how to use it in EMGU CV.
I'm also working on EmguCV, so I guess I can point few things here,
So first thing is you load "yml" file, Is this file you saved after recognizer is trained or you obtained from somewhere. Because my understanding is first you have to train your Recognizer, what is the structure of the yml file. Why do you load the cascade, where are you going to use it? (normally this is used to detect the face)
If you're saying that program crashed most probably because there are no items in the trained set. (in this case i guess it would be yml file) or as what I've read you need minimum of two faces in training set in order to use Fisher recognizer.
this happens because the FaceRecognizer wants to be trained before the Predict method can be called.
You can even load an existing xml Training file by the face.Load(yourTrainingFile.xml) method or by face.Train(yourImages.ToArray, imageIds.ToArray()) method.
Place your FaceRecognizer.PredictionResult predictedLabel = face.Predict(img1); code part within a trycatch block the the debugger wont close and you will catch the error message.
PS : if the number of pictures have been changed since the last Training.xml file has been created, then it's recommended to call the face.Train method instead of face.Load method!

Flajaxian Custom Folder Save Location

I see a lot of people coming up with some excessive ways to change the folder location on the fly with flajaxian multiple file upload control.
Was just wondering if the more experienced could take a look at the way I've come up with and let me know if there are any major issues I should be concerned about. (Assuming I have the proper error checking in place.)
I planned on initializing the control as seen below. :
<cc1:FileUploader ID="FileUploader1" runat="server" OnFileReceived="fileUploader_FileReceived" RequestAsPostBack="true">
</cc1:FileUploader>
(I RequestAsPostBack="true" as there are some other controls I need to check in my event handler)
I simply change the HttpFileCollection.SaveAs property in the fileUploader_FileReceived event. Since flajaxian does this one file upload at a time, we can expect that there is only 1 file in the collection (or else we could use a loop).
protected void fileUploader_FileReceived(object sender,
com.flajaxian.FileReceivedEventArgs e)
{
HttpFileCollection files = Request.Files;
// Change path to whichever folder I need
String TempFileName = "C:\\NEW\\PATH\\TO\\Folder\\" + files[0].FileName;
// Save the file.
files[0].SaveAs(TempFileName);
}
This implementation seems to work great as long as the folder is existing! I was just wondering if there is anything technically wrong with an implementation like this, again , assuming all error checking was in place.
Thanks!
A better way to do this would be to use an adapter, and over write the folder location in the
OnFileNameDetermining event. This way, we also get all the goodies with the adapter.
<cc1:FileUploader ID="FileUploader1" runat="server"` OnFileReceived="fileUploader_FileReceived" RequestAsPostBack="true">
<Adapters>
<cc1:FileSaverAdapter runat="server" FolderName="Ups" OnFileNameDetermining="fileUploader_FileDetermined" />
</Adapters>
</cc1:FileUploader>
In the file determined event, we can change the folder location programatically
protected void fileUploader_FileDetermined(object sender, com.flajaxian.FileNameDeterminingEventArgs e)
{
e.FileName = "C:\\NewFolder\\" + e.File.FileName;
}
We can use the FileReceived event to check if the folder exists, and if not, create it.
protected void fileUploader_FileReceived(object sender, com.flajaxian.FileReceivedEventArgs e)
{
int fileIndex = e.Index;
if (fileIndex == 0)
{
// We are on our first file, check if the new folder exists, if not, create it
}
}
What you are doing is fine, although, if you are saving files within the web site, consider using the MapPath method to create a physical folder from a virtual path within the web site
MapPath("/Images/User1")
This my mininal APSX implementation
<fjx:FileUploader ID="FileUploader1" runat="server" OnFileReceived="FileUploader2_FileReceived">
</fjx:FileUploader>
No adapters or folder is specified. When the FileRecevied event fires, I save files to a folder based on the Forms Authentication user name (names do not use characters not allowed in folder names).
Also note that the FileReceivedEventArgs has a reference to the (HTTP) file
e.File
The FileUploader control will show all files processed - you can even set the status code (e.g. 550) if there is an error, which is returned to the client.
Note that, the server call to the FileReceived event does not occur inside a nornal page postback, even if you specify
RequestAsPostBack="true"
So, a PagePreRender does not take place.
The only issue is, how do you perform any other processing at the client after the uploads complete (e.g. showing images uploaded).
Work I have in progress to this end is to use the client side event
FileStateChanged
When the last file is processed
if (file.state > Flajaxian.File_Uploading && isLast) {
I use JQuery to click a hidden submit button. The postback looks through session values stored when the files were saved, and renders back the images into a DIV.
However, an immediate submit causes issues with empty session inside the FileReceived event for some reason (I assume because the internal asynchronous call back has not completed). A pause of a few seconds before initiating the postback works OK.

Categories