-2

I have the following snippets of a working code which I call from a VB6 app. The ONLY exposed function is the void Run() function. The function uses the backgroundWorker and I can easily see the result of the process using e.Result in backgroundWorker_RunWorkerCompleted. So, if I call Run() from VB6 then all is going perfect, but I cannot return that value of e.Result to the VB6 caller. I also cannot use string Run() cause I have nothing to return in Run().

public void Run(string param)
{
    backgroundWorker.RunWorkerAsync(argument: param);
}

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    e.Result = "Done!";
}

private void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    string result = (string)e.Result;
}

How can I return the final string (e.result) to the calling void Run()? I can't just use the e.result because I'm calling the "Run()" from the VB6 app, and I'm expecting to get the returned result in there.

Thanks for your help...

Dave Gahan
  • 299
  • 2
  • 14
  • Erm, you can't. If you want to do it asynchronously, the calling code needs to support that. Make two functions `BeginRun` and `EndRun` – Charlieface Mar 04 '21 at 14:18
  • Would it be a possibility to make the background worker `public`? Then, your calling code could subscribe to the worker's `RunWorkerCompleted` event. – Nate W Mar 04 '21 at 14:24
  • See the last two duplicates for the modern idiomatic approach. I.e. subscribe to the `RunWorkerCompleted` event with a handler that sets the value in a `TaskCompletionSource` object, then return that object's `Task` property as your operation's future result. – Peter Duniho Mar 04 '21 at 17:38
  • The canonical example is WebBrowser, you Navigate() somewhere and the browser works in the background to get the page loaded. When it is done many milliseconds later, it raises its DocumentCompleted event. Do the same thing, raise an event from your BackgroundWorker.RunWorkerCompleted event handler. – Hans Passant Mar 08 '21 at 15:33

1 Answers1

-2

Does it have to be a backgroundworker? You can effectively achieve the results you're looking for without one:

        static void Main(string[] args)
        {
            Run();
            System.Console.ReadKey();
        }
        private static void Run()
        {
            System.Threading.Tasks.Task<string> task = DoWork();

            while (!task.IsCompleted)
            {
                System.Windows.Forms.Application.DoEvents();
            }
            System.Console.WriteLine($"Task Complete, Result=\"{task.Result}\"");
        }
        public static System.Threading.Tasks.Task<string> DoWork()
        {
            return System.Threading.Tasks.Task.Factory.StartNew(() =>
            {
                System.Threading.Thread.Sleep(1000);
                return "this is my result";
            });
        }

Updated with backgroundworker:

        static void Main(string[] args)
        {
            Run();
            System.Console.ReadKey();
        }
        private static System.ComponentModel.BackgroundWorker bgw;
        private static string resultWeWant = string.Empty;
        private static void Run()
        {
            bgw = new System.ComponentModel.BackgroundWorker();
            bgw.DoWork += (sender, e) =>
            {
                System.Threading.Thread.Sleep(5000);
                e.Result = "this is the result";
            };
            bgw.RunWorkerCompleted += (sender, e) =>
            {
                if (e.Error != null)
                {
                    System.Console.WriteLine($"{e.Error.ToString()}");
                }
                else
                {
                    resultWeWant = e.Result.ToString();
                }
            };
            System.Threading.Tasks.Task task = System.Threading.Tasks.Task.Factory.StartNew(() =>
            {
                bgw.RunWorkerAsync();
                while (bgw.IsBusy)
                {
                    System.Windows.Forms.Application.DoEvents();
                }
            });
            task.Wait();
            System.Console.WriteLine($"backgrounderworker is done, result=\"{resultWeWant}\"");
        }
jamesstap
  • 217
  • 4
  • 6
  • It defeats the entire purpose of using another thread if you're just going to synchronously wait for it to finish right away. You might as well just run the actual work directly from the Run method, it'd behave the same minus some unneeded complexity and performance overhead. – Servy Mar 04 '21 at 15:25
  • Yea, that's totally true. Depends on what we're trying to achieve here, the question just asked for getting the string result in the `Run()` method. There are no other specs provided. If perhaps the `Run()` method is on the UI thread and we need to keep the UI active, that definitely is a valid reason this is not a good answer lol – jamesstap Mar 04 '21 at 16:12
  • It *doesn't* matter what the question is trying to achieve. There isn't any possible situation in which this solution would be better than just performing the work in line in the current thread, which is also probably not what they want to do, but this is just a strictly worse version of that. – Servy Mar 04 '21 at 16:14
  • Yes you're right. With backgroundworkers, I've typically seen them used for running a process intensive task and updating a UI with its progress. So I'll update my answer with an assumption we want to keep the `Run()` method on the UI thread but keep our application active. – jamesstap Mar 04 '21 at 16:27
  • The purpose of this question is using VB6 app to invoke .NET DLL that performs async functions and retrieves the result back. I've found that it works well only with the BackgroundWorker, but then I cannot return the result. – Dave Gahan Mar 07 '21 at 07:38
  • I had a feeling there was a unique reason for it. I was able to achieve the desired results using a backgroundworker. I've updated my answer. – jamesstap Mar 08 '21 at 15:23