2020-08-11 00:53:43 +02:00
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System ;
using System.Collections.Generic ;
2020-11-02 18:33:43 +01:00
using System.IO.Abstractions ;
2020-08-11 00:53:43 +02:00
using System.Text ;
2020-10-24 00:05:07 +02:00
using ManagedCommon ;
2020-08-11 00:53:43 +02:00
using Microsoft.Plugin.Uri.UriHelper ;
2021-02-23 09:53:08 +01:00
using Wox.Infrastructure ;
2020-08-11 00:53:43 +02:00
using Wox.Infrastructure.Storage ;
using Wox.Plugin ;
2020-10-23 13:06:22 -07:00
using Wox.Plugin.Logger ;
2020-08-11 00:53:43 +02:00
namespace Microsoft.Plugin.Uri
{
public class Main : IPlugin , IPluginI18n , IContextMenu , ISavable , IDisposable
{
2020-11-02 18:33:43 +01:00
private static readonly IFileSystem FileSystem = new FileSystem ( ) ;
private static readonly IPath Path = FileSystem . Path ;
private static readonly IFile File = FileSystem . File ;
2020-08-11 00:53:43 +02:00
private readonly ExtendedUriParser _uriParser ;
private readonly UriResolver _uriResolver ;
private readonly PluginJsonStorage < UriSettings > _storage ;
private bool _disposed ;
private UriSettings _uriSettings ;
2020-10-30 14:41:59 -04:00
private RegistryWrapper _registryWrapper ;
2020-08-11 00:53:43 +02:00
public Main ( )
{
_storage = new PluginJsonStorage < UriSettings > ( ) ;
_uriSettings = _storage . Load ( ) ;
_uriParser = new ExtendedUriParser ( ) ;
_uriResolver = new UriResolver ( ) ;
2020-10-30 14:41:59 -04:00
_registryWrapper = new RegistryWrapper ( ) ;
2020-08-11 00:53:43 +02:00
}
public string BrowserIconPath { get ; set ; }
public string DefaultIconPath { get ; set ; }
public PluginInitContext Context { get ; protected set ; }
2021-02-26 13:21:58 +02:00
public string Name = > Properties . Resources . Microsoft_plugin_uri_plugin_name ;
public string Description = > Properties . Resources . Microsoft_plugin_uri_plugin_description ;
2020-08-11 00:53:43 +02:00
public List < ContextMenuResult > LoadContextMenus ( Result selectedResult )
{
return new List < ContextMenuResult > ( 0 ) ;
}
public List < Result > Query ( Query query )
{
var results = new List < Result > ( ) ;
if ( ! string . IsNullOrEmpty ( query ? . Search )
& & _uriParser . TryParse ( query . Search , out var uriResult )
& & _uriResolver . IsValidHost ( uriResult ) )
{
var uriResultString = uriResult . ToString ( ) ;
results . Add ( new Result
{
Title = uriResultString ,
2020-09-02 15:24:59 -07:00
SubTitle = Properties . Resources . Microsoft_plugin_uri_website ,
2020-08-11 00:53:43 +02:00
IcoPath = _uriSettings . ShowBrowserIcon
? BrowserIconPath
: DefaultIconPath ,
Action = action = >
{
2021-02-23 09:53:08 +01:00
if ( ! Helper . OpenInShell ( uriResultString ) )
2020-08-11 00:53:43 +02:00
{
2021-02-23 09:53:08 +01:00
var title = $"Plugin: {Properties.Resources.Microsoft_plugin_uri_plugin_name}" ;
var message = $"{Properties.Resources.Microsoft_plugin_uri_open_failed}: {uriResultString}" ;
Context . API . ShowMsg ( title , message ) ;
return false ;
}
2020-08-11 00:53:43 +02:00
return true ;
} ,
} ) ;
}
return results ;
}
public void Init ( PluginInitContext context )
{
Context = context ? ? throw new ArgumentNullException ( nameof ( context ) ) ;
Context . API . ThemeChanged + = OnThemeChanged ;
UpdateIconPath ( Context . API . GetCurrentTheme ( ) ) ;
UpdateBrowserIconPath ( Context . API . GetCurrentTheme ( ) ) ;
}
public string GetTranslatedPluginTitle ( )
{
2020-09-08 11:51:24 -07:00
return Properties . Resources . Microsoft_plugin_uri_plugin_name ;
2020-08-11 00:53:43 +02:00
}
public string GetTranslatedPluginDescription ( )
{
2020-09-08 11:51:24 -07:00
return Properties . Resources . Microsoft_plugin_uri_plugin_description ;
2020-08-11 00:53:43 +02:00
}
public void Save ( )
{
_storage . Save ( ) ;
}
private void OnThemeChanged ( Theme oldtheme , Theme newTheme )
{
UpdateIconPath ( newTheme ) ;
UpdateBrowserIconPath ( newTheme ) ;
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "We want to keep the process alive but will log the exception")]
private void UpdateBrowserIconPath ( Theme newTheme )
{
try
{
2020-10-30 14:41:59 -04:00
var progId = _registryWrapper . GetRegistryValue ( "HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\Shell\\Associations\\UrlAssociations\\http\\UserChoice" , "ProgId" ) ;
2020-08-11 00:53:43 +02:00
var programLocation =
// Resolve App Icon (UWP)
2020-10-30 14:41:59 -04:00
_registryWrapper . GetRegistryValue ( "HKEY_CLASSES_ROOT\\" + progId + "\\Application" , "ApplicationIcon" )
2020-08-11 00:53:43 +02:00
// Resolves default file association icon (UWP + Normal)
2020-10-30 14:41:59 -04:00
? ? _registryWrapper . GetRegistryValue ( "HKEY_CLASSES_ROOT\\" + progId + "\\DefaultIcon" , null ) ;
2020-08-11 00:53:43 +02:00
// "Handles 'Indirect Strings' (UWP programs)"
2020-10-30 16:43:09 -07:00
// Using Ordinal since this is internal and used with a symbol
2020-08-11 00:53:43 +02:00
if ( programLocation . StartsWith ( "@" , StringComparison . Ordinal ) )
{
var directProgramLocationStringBuilder = new StringBuilder ( 128 ) ;
if ( NativeMethods . SHLoadIndirectString ( programLocation , directProgramLocationStringBuilder , ( uint ) directProgramLocationStringBuilder . Capacity , IntPtr . Zero ) = =
NativeMethods . Hresult . Ok )
{
// Check if there's a postfix with contract-white/contrast-black icon is available and use that instead
var directProgramLocation = directProgramLocationStringBuilder . ToString ( ) ;
var themeIcon = newTheme = = Theme . Light | | newTheme = = Theme . HighContrastWhite ? "contrast-white" : "contrast-black" ;
var extension = Path . GetExtension ( directProgramLocation ) ;
var themedProgLocation = $"{directProgramLocation.Substring(0, directProgramLocation.Length - extension.Length)}_{themeIcon}{extension}" ;
BrowserIconPath = File . Exists ( themedProgLocation )
? themedProgLocation
: directProgramLocation ;
}
}
else
{
2020-10-30 16:43:09 -07:00
// Using Ordinal since this is internal and used with a symbol
2020-08-11 00:53:43 +02:00
var indexOfComma = programLocation . IndexOf ( ',' , StringComparison . Ordinal ) ;
BrowserIconPath = indexOfComma > 0
? programLocation . Substring ( 0 , indexOfComma )
: programLocation ;
}
}
catch ( Exception e )
{
BrowserIconPath = DefaultIconPath ;
2020-10-30 14:42:11 -04:00
Log . Exception ( "Exception when retrieving icon" , e , GetType ( ) ) ;
2020-08-11 00:53:43 +02:00
}
}
private void UpdateIconPath ( Theme theme )
{
if ( theme = = Theme . Light | | theme = = Theme . HighContrastWhite )
{
DefaultIconPath = "Images/uri.light.png" ;
}
else
{
DefaultIconPath = "Images/uri.dark.png" ;
}
}
public void Dispose ( )
{
Dispose ( true ) ;
GC . SuppressFinalize ( this ) ;
}
protected virtual void Dispose ( bool disposing )
{
if ( ! _disposed & & disposing )
{
Context . API . ThemeChanged - = OnThemeChanged ;
_disposed = true ;
}
}
}
}