Skip to content

Inherit from 'AsyncPackage' instead of from 'Package' #1

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions HangFixer/HangFixer.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<PropertyGroup>
<RootNamespace>MobileEssentials</RootNamespace>
<AssemblyName>MobileEssentials.HangFixer</AssemblyName>
<TargetFramework>net46</TargetFramework>
<TargetFramework>net472</TargetFramework>
<TargetVsixContainerName>MobileEssentials.HangFixer.vsix</TargetVsixContainerName>
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>HangFixer.snk</AssemblyOriginatorKeyFile>
Expand All @@ -29,7 +29,12 @@
</Content>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.VSSDK.BuildTools" Version="15.0.26201" />
<PackageReference Include="Xamarin.VsSDK.BuildTools" Version="0.2.1-pre-build0021" />
<PackageReference Include="Microsoft.VisualStudio.Shell.15.0" Version="16.1.28917.181" />
<PackageReference Include="Microsoft.VisualStudio.Shell.Interop" Version="7.10.6072" />
<PackageReference Include="Microsoft.VSSDK.BuildTools" Version="16.1.3128">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Xamarin.VsSDK.BuildTools" Version="0.3.0-alpha.17" />
</ItemGroup>
</Project>
343 changes: 178 additions & 165 deletions HangFixer/HangFixerPackage.cs
Original file line number Diff line number Diff line change
@@ -1,166 +1,179 @@
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Shell.Interop;
using System;
using System.Runtime.InteropServices;
using Microsoft.VisualStudio;
using System.IO;

namespace MobileEssentials
{
[ProvideBindingPath]
[PackageRegistration (UseManagedResourcesOnly = true)]
[Guid ("0553379B-5124-48B6-80B0-09AF3A331CDD")]
[ProvideAutoLoad (SolutionOpening_string)]
public sealed class HangFixerPackage : Package, IVsSolutionLoadEvents, IVsSolutionEvents
{
/// <summary>Specifies a context in which a solution is being opened.</summary>
public const string SolutionOpening_string = "{D2567162-F94F-4091-8798-A096E61B8B50}";


uint cookie;
string flagFile;

protected override void Initialize ()
{
base.Initialize ();

var solution = (IVsSolution2)GetService(typeof(SVsSolution));
ErrorHandler.ThrowOnFailure (solution.AdviseSolutionEvents (this, out cookie));
}

// Order of callbacks is:
// OnBeforeOpenSolution > OnAfterOpenSolution > OnBeforeBackgroundSolutionLoadBegins > OnAfterBackgroundSolutionLoadComplete
// The last two will only happen if background solution load is enabled.
// Therefore, we will setup the flag file on both befores, and clear it on both afters.
public int OnBeforeOpenSolution (string pszSolutionFilename)
{
// If flag file exists, delete .vs and .suo, since it means we tried loading
// before, and we failed.
// This happens only once for a given solution, so it's safe to assume this
// is the "main" entry point event.
flagFile = Path.ChangeExtension (pszSolutionFilename, ".tmp");

if (File.Exists (flagFile)) {
var vsDir = Path.Combine(Path.GetDirectoryName(pszSolutionFilename), ".vs");
if (Directory.Exists (vsDir)) {
try {
Directory.Delete (vsDir, true);
} catch (IOException) {
// Never fail, no matter what.
}
}
foreach (var suoFile in Directory.EnumerateFiles (Path.GetDirectoryName (pszSolutionFilename), "*.suo")) {
try {
File.Delete (suoFile);
} catch (IOException) {
// Never fail, no matter what.
}
}
}

// Written outside the if, so that we always get the
// timestamp of the current solution load attempt.
File.WriteAllText (flagFile, "Visual Studio Hang Fixer");

// TODO: create the flag file
return VSConstants.S_OK;
}

public int OnAfterOpenSolution (object pUnkReserved, int fNewSolution)
{
// Load was successfull, clear the flag file.
ClearFlagFile ();
return VSConstants.S_OK;
}

public int OnBeforeBackgroundSolutionLoadBegins ()
{
// The OnAfterOpenSolution is called even when pending
// background solution load is pending (which is optional
// depending on user settings). So we write the flag file
// again to get the timestamp of the current background
// solution load attempt.
File.WriteAllText (flagFile, "Visual Studio Hang Fixer");
return VSConstants.S_OK;
}

public int OnAfterBackgroundSolutionLoadComplete ()
{
// Load was successfull, clear the flag file.
ClearFlagFile ();
return VSConstants.S_OK;
}

void ClearFlagFile ()
{
if (File.Exists (flagFile)) {
File.Delete (flagFile);
}
}

#region Unused

public int OnAfterCloseSolution (object pUnkReserved)
{
return VSConstants.S_OK;
}

public int OnAfterLoadProject (IVsHierarchy pStubHierarchy, IVsHierarchy pRealHierarchy)
{
return VSConstants.S_OK;
}

public int OnAfterLoadProjectBatch (bool fIsBackgroundIdleBatch)
{
return VSConstants.S_OK;
}

public int OnAfterOpenProject (IVsHierarchy pHierarchy, int fAdded)
{
return VSConstants.S_OK;
}

public int OnBeforeCloseProject (IVsHierarchy pHierarchy, int fRemoved)
{
return VSConstants.S_OK;
}

public int OnBeforeCloseSolution (object pUnkReserved)
{
return VSConstants.S_OK;
}

public int OnBeforeLoadProjectBatch (bool fIsBackgroundIdleBatch)
{
return VSConstants.S_OK;
}

public int OnBeforeUnloadProject (IVsHierarchy pRealHierarchy, IVsHierarchy pStubHierarchy)
{
return VSConstants.S_OK;
}

public int OnQueryBackgroundLoadProjectBatch (out bool pfShouldDelayLoadToNextIdle)
{
pfShouldDelayLoadToNextIdle = false;
return VSConstants.S_OK;
}

public int OnQueryCloseProject (IVsHierarchy pHierarchy, int fRemoving, ref int pfCancel)
{
return VSConstants.S_OK;
}

public int OnQueryCloseSolution (object pUnkReserved, ref int pfCancel)
{
return VSConstants.S_OK;
}

public int OnQueryUnloadProject (IVsHierarchy pRealHierarchy, ref int pfCancel)
{
return VSConstants.S_OK;
}

#endregion
}
using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading;
using Microsoft;
using Microsoft.VisualStudio;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Shell.Interop;

namespace MobileEssentials
{
[ProvideBindingPath]
[PackageRegistration(UseManagedResourcesOnly = true, AllowsBackgroundLoading = true)]
[Guid("0553379B-5124-48B6-80B0-09AF3A331CDD")]
[ProvideAutoLoad(SolutionOpening_string, PackageAutoLoadFlags.BackgroundLoad)]
public sealed class HangFixerPackage : AsyncPackage, IVsSolutionLoadEvents, IVsSolutionEvents
{
/// <summary>Specifies a context in which a solution is being opened.</summary>
public const string SolutionOpening_string = "{D2567162-F94F-4091-8798-A096E61B8B50}";

private string flagFile;

protected override async System.Threading.Tasks.Task InitializeAsync(CancellationToken cancellationToken, IProgress<ServiceProgressData> progress)
{
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken);
IVsSolution2 solution = (IVsSolution2)await GetServiceAsync(typeof(SVsSolution));
Assumes.Present(solution);

//System.Windows.Threading.Dispatcher.VerifyAccess();
ErrorHandler.ThrowOnFailure(solution.AdviseSolutionEvents(this, out _));
await base.InitializeAsync(cancellationToken, progress);
}

// Order of callbacks is:
// OnBeforeOpenSolution > OnAfterOpenSolution > OnBeforeBackgroundSolutionLoadBegins > OnAfterBackgroundSolutionLoadComplete
// The last two will only happen if background solution load is enabled.
// Therefore, we will setup the flag file on both befores, and clear it on both afters.
public int OnBeforeOpenSolution(string pszSolutionFilename)
{
// If flag file exists, delete .vs and .suo, since it means we tried loading
// before, and we failed.
// This happens only once for a given solution, so it's safe to assume this
// is the "main" entry point event.
flagFile = Path.ChangeExtension(pszSolutionFilename, ".tmp");

if (File.Exists(flagFile))
{
string vsDir = Path.Combine(Path.GetDirectoryName(pszSolutionFilename), ".vs");
if (Directory.Exists(vsDir))
{
try
{
Directory.Delete(vsDir, true);
}
catch (IOException)
{
// Never fail, no matter what.
}
}
foreach (string suoFile in Directory.EnumerateFiles(Path.GetDirectoryName(pszSolutionFilename), "*.suo"))
{
try
{
File.Delete(suoFile);
}
catch (IOException)
{
// Never fail, no matter what.
}
}
}

// Written outside the if, so that we always get the
// timestamp of the current solution load attempt.
File.WriteAllText(flagFile, "Visual Studio Hang Fixer");

// TODO: create the flag file
return VSConstants.S_OK;
}

public int OnAfterOpenSolution(object pUnkReserved, int fNewSolution)
{
// Load was successfull, clear the flag file.
ClearFlagFile();
return VSConstants.S_OK;
}

public int OnBeforeBackgroundSolutionLoadBegins()
{
// The OnAfterOpenSolution is called even when pending
// background solution load is pending (which is optional
// depending on user settings). So we write the flag file
// again to get the timestamp of the current background
// solution load attempt.
File.WriteAllText(flagFile, "Visual Studio Hang Fixer");
return VSConstants.S_OK;
}

public int OnAfterBackgroundSolutionLoadComplete()
{
// Load was successfull, clear the flag file.
ClearFlagFile();
return VSConstants.S_OK;
}

private void ClearFlagFile()
{
if (File.Exists(flagFile))
{
File.Delete(flagFile);
}
}

#region Unused

public int OnAfterCloseSolution(object pUnkReserved)
{
return VSConstants.S_OK;
}

public int OnAfterLoadProject(IVsHierarchy pStubHierarchy, IVsHierarchy pRealHierarchy)
{
return VSConstants.S_OK;
}

public int OnAfterLoadProjectBatch(bool fIsBackgroundIdleBatch)
{
return VSConstants.S_OK;
}

public int OnAfterOpenProject(IVsHierarchy pHierarchy, int fAdded)
{
return VSConstants.S_OK;
}

public int OnBeforeCloseProject(IVsHierarchy pHierarchy, int fRemoved)
{
return VSConstants.S_OK;
}

public int OnBeforeCloseSolution(object pUnkReserved)
{
return VSConstants.S_OK;
}

public int OnBeforeLoadProjectBatch(bool fIsBackgroundIdleBatch)
{
return VSConstants.S_OK;
}

public int OnBeforeUnloadProject(IVsHierarchy pRealHierarchy, IVsHierarchy pStubHierarchy)
{
return VSConstants.S_OK;
}

public int OnQueryBackgroundLoadProjectBatch(out bool pfShouldDelayLoadToNextIdle)
{
pfShouldDelayLoadToNextIdle = false;
return VSConstants.S_OK;
}

public int OnQueryCloseProject(IVsHierarchy pHierarchy, int fRemoving, ref int pfCancel)
{
return VSConstants.S_OK;
}

public int OnQueryCloseSolution(object pUnkReserved, ref int pfCancel)
{
return VSConstants.S_OK;
}

public int OnQueryUnloadProject(IVsHierarchy pRealHierarchy, ref int pfCancel)
{
return VSConstants.S_OK;
}

#endregion
}
}
2 changes: 1 addition & 1 deletion HangFixer/source.extension.vsixmanifest
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<PackageManifest Version="2.0.0" xmlns="http://schemas.microsoft.com/developer/vsx-schema/2011" xmlns:d="http://schemas.microsoft.com/developer/vsx-schema-design/2011">
<Metadata>
<Identity Id="MobileEssentials.HangFixer" Version="1.1" Language="en-US" Publisher="Mobile Essentials" />
<Identity Id="MobileEssentials.HangFixer" Version="1.1.1" Language="en-US" Publisher="Mobile Essentials" />
<DisplayName>Visual Studio Hang Fixer</DisplayName>
<Description xml:space="preserve">Fixes hangs that happen when opening a solution with a corrupt or invalid .vs directory or .suo file.</Description>
<MoreInfo>https://github.com/MobileEssentials/HangFixer</MoreInfo>
Expand Down