Resolved Abandon

Gloops

Well-known member
Joined
Jun 30, 2022
Messages
137
Programming Experience
10+
Hello everybody,

I am treating the request of abandon by the user, in a recursive treatment (in a WinForms project, .Net 5.0).

The user has depressed the escape key, and thanks to GetAsyncKeyState, a confirmation has been given, and flags positioned, first to abandon current folder, and then after a messagebox, to abandon the rest of the treatment.

This last point is the difficulty. By putting the treatment in a condition
Condition to execute a procedure:
if(!totalabandon)
{
    dostuff;
}
it is easy to abandon the current directory.

But imagine we are at the fifth level : abandoning the current folder is easy, but four parents are in the calls stack. Break does not go so far. End would close the form, which is not the aim, the user must be able to restart.

So, the treatment stops, that is OK, but if the user clicks on the button to start again, strange error messages appear
Type of strange error message:
System.IO.IOException: Incorrect parameter (followed by the path of a file)

With a goto, I went to the end of the procedure, but that did not release the caller.

My first idea looked like this :
C#:
            foreach (FileInfo fi in di.GetFiles())
            {
                if ((GetAsyncKeyState(Keys.Escape) & 0x8000) != 0)
                {
                    break;
                }
            }

but then it had no loop to break. Hence the goto ... I imagine I am missing something there.

There is the possibility to throw an exception, that must be catched by the level above.

I imagine the catch has to throw the exception again, except if it is at the first level, otherwise the exception is thrown to the user. So, this supposes to increment a level integer variable, each time you enter a new level.

Do you think I am on the good path ?
 
Last edited:
Do you think I am on the good path ?
No. Never use exceptions for flow control. Also using goto should be avoided because eventually it will lead to spaghetti code that is hard to understand and reason with.

What's wrong with simply having something like a state or unit of work context variable? In pseudo code something like this:

C#:
at the top level:
var context = new Context() { Cancel = false };
DoRecursiveJob(context, "C:\\" );

C#:
void DoRecursiveJob(Context context, string path)
{
    foreach(var dir in Directory.EnumerateDirectories(path))
    {
        CheckForUserCancel(context);
        if (context.Cancel)
            break;

         DoRecursiveJob(context, dir);
    }

    foreach(var file in Directory.EnumerateFiles(path))
    {
        CheckForUserCancel(context);
        if (context.Cancel)
            break;

        DoWorkOnFile(context, file);
    }
}

C#:
void CheckForUserCancel(Context context)
{
    if detect Ctrl-Break or Escape key
        confirm user wants to cancel
        if user confirms
            context.Cancel = true;
}
 
No. Never use exceptions for flow control. Also using goto should be avoided because eventually it will lead to spaghetti code that is hard to understand and reason with.
So, it seems it was a good idea to ask the question first 😊
What's wrong with simply having something like a state or unit of work context variable? In pseudo code something like this:

C#:
at the top level:
var context = new Context() { Cancel = false };
DoRecursiveJob(context, "C:\\" );
Could be a good idea, I have to read that calmly to understand the implementation to do of it.
 
Oh yes, but this was not a supposition from me, but the answer of the compiler.
Post the exact code you were using, and the error you were getting. I suspect that you had other errors or warnings before that snippet. The code you have there is perfectly valid syntactically because it follows the pattern:
C#:
foreach(...)
{
    if (...)
    {
         break;
    }
}
 
Post the exact code you were using, and the error you were getting. I suspect that you had other errors or warnings before that snippet. The code you have there is perfectly valid syntactically because it follows the pattern:
C#:
foreach(...)
{
    if (...)
    {
         break;
    }
}
Oh, this opens the perspective to a much more simple answer.
I am going to experiment that in a test program.
 
No compiler errors here:

C#:
using System;
                    
public class Program
{
    public static void Main()
    {
        foreach(var value in new [] { 1, 2, 3, 4, 5, 6, 7 })
        {
            if (value == 4)
                break;
            
            Console.WriteLine(value);
        }
    }
}
 
Hello,
Yes I answered a little quickly (I am late in a certain number of domains). I had an error because I had put the break after the goto, that sent outside the loop.
So with a break, I just had to position flags to know, when coming back at the previous loop, that I have to stop.
So, the application stops.
Now, I have to understand why the same code, that worked nice the first time, says that GetFiles returns incorrect parameters, although it shows the path of an existing file.
I had a failure to access the clipboard to copy the whole error details, but I could transfer this :
HResult -2147024809 int

I am going to try that again after restarting the machine.
 
Well, restart does not help, I cannot copy the details from the message on the code, but after displaying them I can copy from the error details display window.
When clicking on the start button, I start with the same file as before the request to abandon.

C#:
-        $exception    {"Paramètre incorrect. : 'D:\\Projects Visual Studio\\Console\\BaseConvertie\\.git\\objects\\95\\c7e1efa9a5d8bf06740875e4f7c5e8bd5525bd'"}    System.IO.IOException
+        Data    {System.Collections.ListDictionaryInternal}    System.Collections.IDictionary {System.Collections.ListDictionaryInternal}
        HResult    -2147024809    int
        HelpLink    null    string
+        InnerException    null    System.Exception
        Message    "Paramètre incorrect. : 'D:\\Projects Visual Studio\\Console\\BaseConvertie\\.git\\objects\\95\\c7e1efa9a5d8bf06740875e4f7c5e8bd5525bd'"    string
        Source    "System.IO.FileSystem"    string
        StackTrace    "   à System.IO.Enumeration.FileSystemEnumerator`1.FindNextEntry()\r\n   à System.IO.Enumeration.FileSystemEnumerator`1.MoveNext()\r\n   à System.Collections.Generic.LargeArrayBuilder`1.AddRange(IEnumerable`1 items)\r\n   à System.Collections.Generic.EnumerableHelpers.ToArray[T](IEnumerable`1 source)\r\n   à SearchStringinFolder.Form1.browseFolder(DirectoryInfo di) dans D:\\Projects Visual Studio\\Winform\\SearchStringinFolder\\SearchStringinFolder\\Form1.cs :ligne 83\r\n   à SearchStringinFolder.Form1.fullfolder(DirectoryInfo di) dans D:\\Projects Visual Studio\\Winform\\SearchStringinFolder\\SearchStringinFolder\\Form1.cs :ligne 59\r\n   à SearchStringinFolder.Form1.btnOK_Click(Object sender, EventArgs e) dans D:\\Projects Visual Studio\\Winform\\SearchStringinFolder\\SearchStringinFolder\\Form1.cs :ligne 50\r\n   à System.Windows.Forms.Control.OnClick(EventArgs e)\r\n   à System.Windows.Forms.Button.OnClick(EventArgs e)\r\n   à System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent)\r\n   à System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)\r\n   à System.Windows.Forms.Control.WndProc(Message& m)\r\n   à System.Windows.Forms.ButtonBase.WndProc(Message& m)\r\n   à System.Windows.Forms.Button.WndProc(Message& m)\r\n   à System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)\r\n   à System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, WM msg, IntPtr wparam, IntPtr lparam)\r\n   à Interop.User32.DispatchMessageW(MSG& msg)\r\n   à System.Windows.Forms.Application.ComponentManager.Interop.Mso.IMsoComponentManager.FPushMessageLoop(UIntPtr dwComponentID, msoloop uReason, Void* pvLoopData)\r\n   à System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(msoloop reason, ApplicationContext context)\r\n   à System.Windows.Forms.Application.ThreadContext.RunMessageLoop(msoloop reason, ApplicationContext context)\r\n   à System.Windows.Forms.Application.Run(Form mainForm)\r\n   à SearchStringinFolder.Program.Main() dans D:\\Projects Visual Studio\\Winform\\SearchStringinFolder\\SearchStringinFolder\\Program.cs :ligne 20"    string
+        TargetSite    {Void FindNextEntry()}    System.Reflection.MethodBase {System.Reflection.RuntimeMethodInfo}
+        Membres statiques       
+        Membres non publics
 
Sorry, that's me.
The path to browse is saved in a label on the form, and during the treatment I put the name of the file in that label.
So, when clicking on start, I ask to browse a file, to see the files that it contains 😊

The remaining problem is between the keyboard and the chair, thank you to have clarified the situation, and why the breaks, that I first tried, did not work.
 
Back
Top Bottom