Click here to Skip to main content
15,887,683 members
Please Sign up or sign in to vote.
1.00/5 (2 votes)
See more:
My updated code, however pressing the button still generates one at a time and does not generate all of them automatically. Code updated.

C#
private void openToolStripMenuItem_Click(object sender, EventArgs e)
       {
           if (dlgDirectoryBrowser.ShowDialog() == DialogResult.OK)
           {
               ImageList smallImageArray = new ImageList();
               int smallImageArray_Index = 0;
               listDetailedResults.SmallImageList = smallImageArray;

               try
               {
                   listDetailedResults.Items.Clear();
                   string[] fileEntriesFromDirectoryBrowser = System.IO.Directory.GetFiles(dlgDirectoryBrowser.SelectedPath);

                   foreach (string fileEntry in fileEntriesFromDirectoryBrowser)
                   {
                       Properties.Settings.Default.fileSizeBeforeConversion = new System.IO.FileInfo(fileEntry).Length;
                       Icon fileEntryIcon = Icon.ExtractAssociatedIcon(fileEntry);

                       smallImageArray.Images.Add(fileEntryIcon);

                       listDetailedResults.Items.Add(System.IO.Path.GetFileName(fileEntry).ToLower(), smallImageArray_Index);
                       listDetailedResults.Items[smallImageArray_Index].SubItems.Add(GetSizeReadable(Properties.Settings.Default.fileSizeBeforeConversion));
                       smallImageArray_Index++;
                   }

                   foreach (ColumnHeader columns in listDetailedResults.Columns)
                       columns.Width = -2;
               }
               catch (Exception ex) { }
               Properties.Settings.Default.count = 0;
               Properties.Settings.Default.Save();
           }
       }

       public static string GetSizeReadable(long i)
       {
           string sign = (i < 0 ? "-" : "");
           double readable = (i < 0 ? -i : i);
           string suffix;

           if (i >= 0x40000000) // Gigabyte
           {
               suffix = "GB";
               readable = (double)(i >> 20);
           }
           else if (i >= 0x100000) // Megabyte
           {
               suffix = "MB";
               readable = (double)(i >> 10);
           }
           else if (i >= 0x400) // Kilobyte
           {
               suffix = "KB";
               readable = (double)i;
           }
           else
           {
               return i.ToString(sign + "0 B"); // Byte
           }

           readable = readable / 1024;

           return sign + readable.ToString("0.## ") + suffix;
       }

       private void bgw_Md5_DoWork(object md5_sender, DoWorkEventArgs md5_e)
       {
           byte[] buffer;
           byte[] oldBuffer;
           int bytesRead;
           int oldBytesRead;
           long size;
           long totalBytesRead = 0;

           using (System.IO.Stream stream = System.IO.File.OpenRead((string)md5_e.Argument))
           using (System.Security.Cryptography.HashAlgorithm Hash_md5_Algorithm = MD5.Create())
           {
               size = stream.Length;
               buffer = new byte[4096];
               bytesRead = stream.Read(buffer, 0, buffer.Length);
               totalBytesRead += bytesRead;
               do
               {
                   oldBytesRead = bytesRead;
                   oldBuffer = buffer;

                   buffer = new byte[4096];
                   bytesRead = stream.Read(buffer, 0, buffer.Length);

                   totalBytesRead += bytesRead;

                   if (bytesRead == 0)
                   {
                       Hash_md5_Algorithm.TransformFinalBlock(oldBuffer, 0, oldBytesRead);
                   }
                   else
                   {
                       Hash_md5_Algorithm.TransformBlock(oldBuffer, 0, oldBytesRead, oldBuffer, 0);
                   }

                   bgWorkerDigest5.ReportProgress((int)((double)totalBytesRead * 100 / size));

               } while (bytesRead != 0);
               md5_e.Result = Hash_md5_Algorithm.Hash;
           }
       }

       private void bgw_Md5_RunWorkerCompleted(object md5_sender, RunWorkerCompletedEventArgs md5_e)
       {
           StringBuilder sb;
           sb = new StringBuilder();
           //pbBar.Visible = false;

           foreach (byte b in (byte[])md5_e.Result)
           {
               sb.AppendFormat("{0:X2}", b);
           }

           ListViewItem update_lvi = listDetailedResults.Items[Properties.Settings.Default.count];
           update_lvi.SubItems.Add(sb.ToString().ToLower());

           //Resize Columns For Each Listview Item
           foreach (ColumnHeader columns in listDetailedResults.Columns)
               columns.Width = -2;
           listDetailedResults.Enabled = true;
           listDetailedResults.Focus();
           Properties.Settings.Default.count++;

       }

       private void startToolStripMenuItem_Click(object sender, EventArgs e)
       {
           foreach (ListViewItem item in listDetailedResults.Items)
           {
               if (!bgWorkerDigest5.IsBusy)
                   bgWorkerDigest5.RunWorkerAsync(dlgDirectoryBrowser.SelectedPath + "\\" + item.Text);

           }
       }
Posted
Updated 1-Dec-15 7:08am
v5
Comments
Richard MacCutchan 1-Dec-15 9:07am    
it says something along the lines of Thread being busy.
What does it actually say, and where?
Herboren 1-Dec-15 13:09pm    
Code updated in question.

Quote:
pressing the button still generates one at a time and does not generate all of them automatically

The result is hardly surprising. The first time through the loop, you tell the BackgroundWorker to start working on a background thread. The work takes longer than retrieving the next item from the list, so for all subsequent iterations of your loop, the IsBusy property returns true, and the work is never queued.

The simplest solution is probably to track the index of the item you're processing, and queue up the next item in the RunWorkerCompleted event:
C#
private int _currentIndex;

private void ProcessItem(int index)
{
    if (0 > index || index >= listDetailedResults.Items.Count)
    {
        listDetailedResults.Enabled = true;
        listDetailedResults.Focus();
    }
    else
    {
        _currentIndex = index;
        listDetailedResults.Enabled = false;
        bgWorkerDigest5.RunWorkerAsync(Path.Combine(dlgDirectoryBrowser.SelectedPath, listDetailedResults.Items[index].Text));
    }
}

private void startToolStripMenuItem_Click(object sender, EventArgs e)
{
    if (!bgWorkerDigest5.IsBusy)
    {
        ProcessItem(0);
    }
    else
    {
        bgWorkerDigest5.CancelAsync();
    }
}

private void bgw_Md5_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    // If the user cancelled, stop the process:
    if (e.Cancelled) 
    {
        listDetailedResults.Enabled = true;
        listDetailedResults.Focus();
        return;
    }
    
    // If there was an error, display it and stop:
    if (e.Error != null)
    {
        MessageBox.Show(e.Error.ToString(), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
        
        listDetailedResults.Enabled = true;
        listDetailedResults.Focus();
        return;
    }
    
    // Display the result:
    StringBuilder sb = new StringBuilder();
    foreach (byte b in (byte[])e.Result)
    {
        sb.AppendFormat("{0:x2}", b);
    }
    
    int index = _currentIndex;
    ListViewItem lvi = listDetailedResults.Items[index];
    lvi.SubItems.Add(sb.ToString());
    
    //Resize Columns For Each Listview Item
    foreach (ColumnHeader columns in listDetailedResults.Columns)
    {
        columns.Width = -2;
    }
    
    // Process the next item:
    ProcessItem(index + 1);
}

private void bgw_Md5_DoWork(object sender, DoWorkEventArgs e)
{
    using (Stream stream = File.OpenRead((string)e.Argument))
    using (HashAlgorithm md5 = MD5.Create())
    {
        // Simplified code from StackOverflow:
        // http://stackoverflow.com/a/3621316/124386
        
        long size = stream.Length;
        byte[] buffer = new byte[4096];
        long totalBytesRead = 0;
        int bytesRead;
        
        while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) != 0)
        {
            totalBytesRead += bytesRead;
            md5.TransformBlock(buffer, 0, bytesRead, null, 0);
            bgWorkerDigest5.ReportProgress((int)((double)totalBytesRead * 100 / size));
            
            // If the user wants to cancel, then bail out:
            if (bgWorkerDigest5.CancellationPending) 
            {
                e.Cancel = true;
                return;
            }
        }
        
        md5.TransformFinalBlock(new byte[0], 0, 0);
        e.Result = md5.Hash;
    }

    if (bgWorkerDigest5.CancellationPending) 
    {
        e.Cancel = true;
    }
}
 
Share this answer
 
v4
Comments
Herboren 1-Dec-15 14:41pm    
Your solution worked wonders and the tidying helped the code be more readable thank you =).

I was faced with this error after trying to hash multiple files ranging in the Gigabytes: Additional information: Value of '-2147483648' is not valid for 'Value'. 'Value' should be between 'minimum' and 'maximum'

from code:

private void bgw_Md5_ProgressChanged(object md5_sender, ProgressChangedEventArgs md5_e)
{
progressBackGroundWork.Value = md5_e.ProgressPercentage;
}

when hashing files larger than 1.5GB

However I am gonna assume that the value of the progress bar is not reseting and its just counting more than the maximum value.
Richard Deeming 1-Dec-15 14:47pm    
Sorry, the totalBytesRead variable needs to be a long, not an int.
Herboren 1-Dec-15 15:18pm    
totalBytesRead is long, still throwing.
Richard Deeming 1-Dec-15 15:24pm    
That's odd - I can't make equivalent code produce a value outside of the 0-100 range.

What values have you got in size and totalBytesRead when it throws?
Herboren 1-Dec-15 15:29pm    
When I set my breakpoint on

private void bgw_Md5_ProgressChanged(object md5_sender, ProgressChangedEventArgs md5_e)
{
progressBackGroundWork.Value = md5_e.ProgressPercentage;
}

I get

md5_e.ProgressPercentage = -2147483648
ProgressPercentage = -2147483648
UserState = null

I've found hash calculation only in one method bgw_Md5_DoWork; and it's not shown how it's called. The implementation suggests that you call it in a separate non-UI thread. Even though some loop is shown, there is only one object which receives the hash value, md5_e.Result. Even if it wasn't outside of the loop, it would be only one. I don't know what do you mean by "all of them", but you are not trying to calculate more than one hash value. If you need more than one hash value, you need some collection which works as a sink for multiple hash values. As a single hash value is array of bytes, byte [], the data type for the data holding several hash value should be some collection of arrays of arrays of bytes, or array of array of bytes, which would be less suitable, because you may not know total number of values in advance. This is just one thing you have to do.

Now, let's look at two methods you call in the loop. Even though your code does not comprehensively represent the problem, it's very unlikely that it can be anything but System.Security.Cryptography.TransformBlock and System.Security.Cryptography.TransformFinalBlock:
https://msdn.microsoft.com/en-us/library/system.security.cryptography.hashalgorithm.transformblock%28v=vs.110%29.aspx[^],
https://msdn.microsoft.com/en-us/library/system.security.cryptography.hashalgorithm.transformblock%28v=vs.110%29.aspx[^].

First method places data in output buffer, and the last one simply returns array of bytes. Your buffers are local variables, so you don't keep any data you would collect in output buffer on the method return. As to the second method, you simply ignore its return. No wonder you loose the hash data. So, if you need this data, you should not ignore the return, and need to save it in some data collection(s) object(s) created outside of this function; you will need to pass the collection reference to your method.

Also, if you really use non-UI thread for the operation, you may have some difficulty passing data into and our of the data of your methods called in this thread. For this purpose, look at my thread wrapper technique I've suggested and widely use. Everything is explained in my past answers:
Change parameters of thread (producer) after it is started[^],
How to pass ref parameter to the thread[^],
Classes in list updating in their own thread[^],
AsyncCallback and Threadings[^] (with fully operational sample),
MultiThreading in C#[^].

—SA
 
Share this answer
 
v3
Comments
Richard Deeming 1-Dec-15 14:19pm    
From the methods and events used, I suspect the OP is using a BackgroundWorker[^], which is what's calling the bgw_Md5_DoWork event handler.

I also suspect it's the outer loop triggering the background work which is the problem, and not the loop within the DoWork event handler.
Sergey Alexandrovich Kryukov 1-Dec-15 14:22pm    
Sure, agree. I actually mentioned "the implementation suggests that you call it in a separate non-UI thread", just did not want to mention BackgroundWorker specifically.
However, even the problems I spotted in the available part of code are troublesome enough and should be fixed.
—SA
Richard Deeming 1-Dec-15 14:24pm    
I don't know who down-voted your answer; it's a decent answer as always. I've countered with a 5.
Sergey Alexandrovich Kryukov 1-Dec-15 14:37pm    
Thank you very much, even though you don't have to "counter", I hope you just see how my advice could be useful.

I guess, this is another "hatred voting" season, which comes from time to time: one or a couple of members come on and vote 1 on just few answers in a row within the same second or few, which is clearly seen by timing; and such behavior is observed during several days. I never understood any rationale behind such patterns, sometimes it's done just on too short or too long answers, or maybe answers containing some judgement, or sometimes just first answers of a day... Pretty funny.

—SA
Herboren 1-Dec-15 15:13pm    
No, not at all. No hatred here friend. However I have seen some of your posts towards most of these people, and your enthusiasm seems a bit abrasive. I know you're an intelligent individual but most of time we are looking for simple answers and the only reason I say this is the level of intelligence that some people come in here with. Sometimes the syntax you explain is beyond our reach; in another sense, the key wording you use is beyond what our teacher is showing us. Those of us or are still in fundamental training in community college or fresh into a University, are just being exposed to this content.

I try to help people with fundamentals in /r/csharp but I don't want to coin their level of intelligence by throwing them something that their teachers haven't even offered them, so I have to work from a lower subject level with them and slowly migrate their way into something modern. I hope you smell my drift.

I will have you know I don't down vote because it really is depressing being down-voted. I will however select a solution, I won't lie. If star ratings are considered down voting, I am very sorry that wasn't the intention, I only mark it 5 stars because I know this issue is common with this particular snippet. So if anyone decides to stop and search code project, I'm hoping this thread will appear to help them before they ask. I know people are in a rush to get the answer, but some of us do stay for the fire works and it really does make the most in the end when understanding the logic behind it. I am sure your expectation of people is that they don't comeback after you offered help, this just means that select few finally listened and understand the bedrock.

So please accept my gesture as kind concern and understand the level of intelligence that you come face to face within the quick questions forum =)

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900