await Task.WhenAll(saveTasks);
And everything is fine.
But without a break point it's throwing the exception :
ExternalException: A generic error occurred in GDI+.
This exception was originally thrown at this call stack:
System.Drawing.Image.Save(string, System.Drawing.Imaging.ImageCodecInfo, System.Drawing.Imaging.EncoderParameters)
System.Drawing.Image.Save(string, System.Drawing.Imaging.ImageFormat)
Extract.Form1.OnLoad.AnonymousMethod__1() in Form1.cs
System.Threading.Tasks.Task.InnerInvoke()
System.Threading.Tasks.Task.Execute()
System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(System.Threading.Tasks.Task)
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(System.Threading.Tasks.Task)
Extract.Form1.OnLoad(System.EventArgs) in Form1.cs
System.Runtime.CompilerServices.AsyncMethodBuilderCore.ThrowAsync.AnonymousMethod__6_0(object)
The full details :
System.Reflection.TargetInvocationException
HResult=0x80131604
Message=Exception has been thrown by the target of an invocation.
Source=mscorlib
StackTrace:
at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor)
at System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(Object obj, Object[] parameters, Object[] arguments)
at System.Delegate.DynamicInvokeImpl(Object[] args)
at System.Windows.Forms.Control.InvokeMarshaledCallbackDo(ThreadMethodEntry tme)
at System.Windows.Forms.Control.InvokeMarshaledCallbackHelper(Object obj)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Windows.Forms.Control.InvokeMarshaledCallback(ThreadMethodEntry tme)
at System.Windows.Forms.Control.InvokeMarshaledCallbacks()
at System.Windows.Forms.Control.WndProc(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr dwComponentID, Int32 reason, Int32 pvLoopData)
at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
at System.Windows.Forms.Application.Run(Form mainForm)
at Extract.Program.Main() in D:\Csharp Projects\Extract\Program.cs:line 19
This exception was originally thrown at this call stack:
System.Drawing.Image.Save(string, System.Drawing.Imaging.ImageCodecInfo, System.Drawing.Imaging.EncoderParameters)
System.Drawing.Image.Save(string, System.Drawing.Imaging.ImageFormat)
Extract.Form1.OnLoad.AnonymousMethod__1() in Form1.cs
System.Threading.Tasks.Task.InnerInvoke()
System.Threading.Tasks.Task.Execute()
System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(System.Threading.Tasks.Task)
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(System.Threading.Tasks.Task)
Extract.Form1.OnLoad(System.EventArgs) in Form1.cs
System.Runtime.CompilerServices.AsyncMethodBuilderCore.ThrowAsync.AnonymousMethod__6_0(object)
Inner Exception 1:
ExternalException: A generic error occurred in GDI+.
The error itself is likely caused by that program attempting to write to the same file location for every filename. The reason for this is that the code that's ran inside of Task.Run
isn't necessarily ran immediately. All that code does is schedule some work to be done with the ThreadPool:
https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.task.run?view=net-5.0
So the loop has already iterated to the end (having incremented 10 times) by the time that the inner function has even run. The result is that every instance attempts to write to satImage11.gif
. The fix is to make a copy of that global counter
value to a variable that won't change, then use that inside the Task.Run
callback instead, and it'll keep it's original value.
foreach (var filename in filenames) {
var counterCopy = counter;
saveTasks.Add(Task.Run(() => {
var newFilename = @"c:\bla\satImage" + counterCopy + ".gif";
Image.FromFile(filename).Save(newFilename, ImageFormat.Gif);
counter++;