locked
warning VSTHRD010: Accessing "IVsOutputWindowPane" should only be done on the main thread. RRS feed

  • Question

  • I've recently been fixing a bunch of "VSTHRD010" warnings in one of my VS extensions, but I'm stuck on my last one.

    I run an external command and echo the output from my "Process" using the Process::OutputDataReceived event. In the handler I provide, I output the string it gives me to a IVsOutputWindowPane using OutputString. It been working fine for ages, but I can see that the thread calling this handler is not surprisingly not the "main" thread, and so I get this compilation warning:-

    warning VSTHRD010: Accessing "IVsOutputWindowPane" should only be done on the main thread. Call System.Windows.Threading.Dispatcher.VerifyAccess() first.

    How should I go about fixing this warning, or can I safely ignore it for IVsOutputWindowPane::OutputString()? I know about ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync() but not sure if that's useful inside the handler function.

    Any help much appreciated as it's making a bit nervous doing something that maybe isn't really supported.

    Wednesday, February 6, 2019 2:04 PM

All replies

  • Guidance for that particular analyzer warning can be found here:

    https://github.com/Microsoft/vs-threading/blob/master/doc/analyzers/VSTHRD010.md

    Sincerely,


    Ed Dore

    Thursday, February 7, 2019 8:28 PM
  • Thanks, but I was aware of that page having looked the warning up online. As I said above, I'm not sure how to go about using SwitchToMainThreadAsync() in OutputDataReceived event handler I provide and that page doesn't really help me there.
    Friday, February 8, 2019 11:02 AM
  • There's a threadsafe method, but the docs say to cast the interface to IVsOutputWindowPaneNoPump.

    But after reading the question a bit closer, I'm guessing the issue here is attempting to use SwitchToMainThreadAsync() from a synchronous OutputDataReceived event handler (not declared with async). If that's the case, you can use JoinableTaskFactory.Run, as described in Andrew Arnott's blog entry:

       Asynchronous and multithreaded programming within VS using the JoinableTaskFactory

    You can dig up more substantial examples, by querying for JoinableTaskFactory.Run on GitHub.  A quick search turns up a number of examples, where the specified delegate awaits SwitchToMainThreadAsync and then queries and invokes various methods on IVsxxxxx interfaces.

    Sincerely,


    Ed Dore

    Thursday, February 14, 2019 5:41 AM
  • Thanks again for your help.

    I'd tried the IVsOutputWindowPaneNoPump option, but I never seemed to be able to cast it and so could never call OutputStringNoPump(). It also gives the same warning that it should only be used on the main thread anyway.

    Going back to my original method, when I tried this handler

            public void Handler(object sender, System.Diagnostics.DataReceivedEventArgs e)
            {
                //NOTE: OutputString is supposed to be run on UI/Main thread
                //While it did seem to work, I've implemented what seemed to be the
                //'right' thing to do.
                ThreadHelper.JoinableTaskFactory.Run(async delegate
                {
                    await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
                    string line = e.Data;

                    if (line == null)
                    {
                        proc.CancelOutputRead();
                    }
                    else
                    {
                        pane.OutputString(line + "\n");
                    }
                });
            }

    I got this build error

    <cut>\packages\Microsoft.VSSDK.BuildTools.15.5.72\tools\VSSDK\Microsoft.VsSDK.targets(991,5): error : CreatePkgDef : error : ReflectionTypeLoadException: Unable to load one or more of the requested types. Retrieve the LoaderExceptions property for more information.
    <cut>\packages\Microsoft.VSSDK.BuildTools.15.5.72\tools\VSSDK\Microsoft.VsSDK.targets(991,5): error :    at System.Reflection.RuntimeModule.GetTypes(RuntimeModule module)
    <cut>\packages\Microsoft.VSSDK.BuildTools.15.5.72\tools\VSSDK\Microsoft.VsSDK.targets(991,5): error :    at System.Reflection.RuntimeModule.GetTypes()
    <cut>\packages\Microsoft.VSSDK.BuildTools.15.5.72\tools\VSSDK\Microsoft.VsSDK.targets(991,5): error :    at System.Reflection.Assembly.GetTypes()
    <cut>\packages\Microsoft.VSSDK.BuildTools.15.5.72\tools\VSSDK\Microsoft.VsSDK.targets(991,5): error :    at Microsoft.VisualStudio.Tools.CreatePkgDef.ProcessAssembly(String fileName, Hive hive, PkgDefContext context, Boolean register, RegistrationMode mode)
    <cut>\packages\Microsoft.VSSDK.BuildTools.15.5.72\tools\VSSDK\Microsoft.VsSDK.targets(991,5): error :    at Microsoft.VisualStudio.Tools.CreatePkgDef.DoCreatePkgDef(InputArguments inputArguments)
    <cut>\packages\Microsoft.VSSDK.BuildTools.15.5.72\tools\VSSDK\Microsoft.VsSDK.targets(991,5): error :    at Microsoft.VisualStudio.Tools.CreatePkgDef.Main(String[] arguments)
    <cut>\packages\Microsoft.VSSDK.BuildTools.15.5.72\tools\VSSDK\Microsoft.VsSDK.targets(991,5): error : Could not load file or assembly 'Microsoft.VisualStudio.Threading, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies. The system cannot find the file specified.

    Now I'm not sure what to do here. I've tried refreshing the NuGet stuff, and I seem to be including the Threading DLL as a reference. I'm targetting .NET Framework 4.5.2 as I think that's the latest supported by the previous version of VS, which my extension is still currently supporting.

    Thursday, February 21, 2019 5:42 PM
  • That's a build issue. I suspect you should be using the earlier version of the SDK if you're targeting an earlier version of VS here. I'm not certain the newer versions targeting version 15.x and 16.x are compatible with earlier versions of VS.



    Ed Dore

    Tuesday, February 26, 2019 7:41 AM