mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-05 18:57:19 +02:00
Self-contained .NET (#22217)
* dotnet sc
* MD preview - C# app
- working self-contained
* Gcode preview - C# app
* DevFiles preview - C# app
* Fix passing path with spaces as cmd arg and monacocpp proj file
* Pdf preview - C# app
* Svg preview - C# app
* Fix comment
* Gcode thumbnail - C# app
TODO:
- installer
- why IThumbnailProvider and IIntializeWithFile doesn't work?
* Pdf thumbnail - C# app
TODO:
- installer
- why IThumbnailProvider and IIntializeWithFile doesn't work?
* Pdf thumbnail - C# app
TODO:
- installer
- why IThumbnailProvider and IIntializeWithFile doesn't work?
* Fix GcodeThumbnailProviderCpp.vcxproj
* Svg thumbnail - C# app
TODO:
- installer
- why IThumbnailProvider and IIntializeWithFile doesn't work?
* Fix Svg tests
* Thumbnail providers - installer
* Self-contained Hosts and FileLocksmith
* Fix hardcoded <RuntimeIdentifier>
* Remove unneeded files
* Try to fix Nuget in PR CI
* Prefix new dlls with PowerToys.
Sign new dlls and exes
* Add new .exe files to ProcessList
* ci: debug by listing all env vars
* ci: try setting variable in the right ci file
* Bring back hardcoded RuntimeIdentifier
* ci: Add comment and remove debug action
* Remove unneeded lib
* [WIP] Platform conditional dotnet files & hardlinks
* Cleanup
* Update expect.txt
* Test fix - ARM installer
* Fix uninstall bug
* Update docs
* Fix failing test
* Add dll details
* Minor cleanup
* Improve resizing
* Add some logs
* Test fix - release build
* Remove InvokeOnControlThread
* Test fix: logger initialization
* Fix arm64 installer
Co-authored-by: Jaime Bernardo <jaime@janeasystems.com>
Co-authored-by: Dustin L. Howett <dustin@howett.net>
This commit is contained in:
@@ -33,5 +33,9 @@ namespace PreviewHandlerCommon.ComInterop
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true)]
|
||||
public static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static extern bool GetClientRect(IntPtr hWnd, ref Common.ComInterlop.RECT rect);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Windows.Forms;
|
||||
using Common.ComInterlop;
|
||||
using PreviewHandlerCommon.ComInterop;
|
||||
|
||||
namespace Common
|
||||
@@ -49,75 +50,57 @@ namespace Common
|
||||
public void QueryFocus(out IntPtr result)
|
||||
{
|
||||
var getResult = IntPtr.Zero;
|
||||
this.InvokeOnControlThread(() =>
|
||||
{
|
||||
getResult = NativeMethods.GetFocus();
|
||||
});
|
||||
getResult = NativeMethods.GetFocus();
|
||||
result = getResult;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void SetBackgroundColor(Color argbColor)
|
||||
{
|
||||
this.InvokeOnControlThread(() =>
|
||||
{
|
||||
this.BackColor = argbColor;
|
||||
});
|
||||
this.BackColor = argbColor;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void SetFocus()
|
||||
{
|
||||
this.InvokeOnControlThread(() =>
|
||||
{
|
||||
this.Focus();
|
||||
});
|
||||
this.Focus();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void SetFont(Font font)
|
||||
{
|
||||
this.InvokeOnControlThread(() =>
|
||||
{
|
||||
this.Font = font;
|
||||
});
|
||||
this.Font = font;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void SetRect(Rectangle windowBounds)
|
||||
public void SetRect(Rectangle rect)
|
||||
{
|
||||
this.UpdateWindowBounds(windowBounds);
|
||||
this.UpdateWindowBounds(parentHwnd);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void SetTextColor(Color color)
|
||||
{
|
||||
this.InvokeOnControlThread(() =>
|
||||
{
|
||||
this.ForeColor = color;
|
||||
});
|
||||
this.ForeColor = color;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void SetWindow(IntPtr hwnd, Rectangle rect)
|
||||
{
|
||||
this.parentHwnd = hwnd;
|
||||
this.UpdateWindowBounds(rect);
|
||||
this.UpdateWindowBounds(hwnd);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public virtual void Unload()
|
||||
{
|
||||
this.InvokeOnControlThread(() =>
|
||||
this.Visible = false;
|
||||
foreach (Control c in this.Controls)
|
||||
{
|
||||
this.Visible = false;
|
||||
foreach (Control c in this.Controls)
|
||||
{
|
||||
c.Dispose();
|
||||
}
|
||||
c.Dispose();
|
||||
}
|
||||
|
||||
this.Controls.Clear();
|
||||
});
|
||||
this.Controls.Clear();
|
||||
|
||||
// Call garbage collection at the time of unloading of Preview.
|
||||
// Which is preventing prevhost.exe to exit at the time of closing File explorer.
|
||||
@@ -132,33 +115,27 @@ namespace Common
|
||||
this.Visible = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Executes the specified delegate on the thread that owns the control's underlying window handle.
|
||||
/// </summary>
|
||||
/// <param name="func">Delegate to run.</param>
|
||||
public void InvokeOnControlThread(MethodInvoker func)
|
||||
{
|
||||
this.Invoke(func);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update the Form Control window with the passed rectangle.
|
||||
/// </summary>
|
||||
/// <param name="windowBounds">An instance of rectangle.</param>
|
||||
private void UpdateWindowBounds(Rectangle windowBounds)
|
||||
public void UpdateWindowBounds(IntPtr hwnd)
|
||||
{
|
||||
this.InvokeOnControlThread(() =>
|
||||
// We must set the WS_CHILD style to change the form to a control within the Explorer preview pane
|
||||
int windowStyle = NativeMethods.GetWindowLong(Handle, gwlStyle);
|
||||
if ((windowStyle & wsChild) == 0)
|
||||
{
|
||||
// We must set the WS_CHILD style to change the form to a control within the Explorer preview pane
|
||||
int windowStyle = NativeMethods.GetWindowLong(Handle, gwlStyle);
|
||||
if ((windowStyle & wsChild) == 0)
|
||||
{
|
||||
_ = NativeMethods.SetWindowLong(Handle, gwlStyle, windowStyle | wsChild);
|
||||
}
|
||||
_ = NativeMethods.SetWindowLong(Handle, gwlStyle, windowStyle | wsChild);
|
||||
}
|
||||
|
||||
NativeMethods.SetParent(Handle, parentHwnd);
|
||||
Bounds = windowBounds;
|
||||
});
|
||||
NativeMethods.SetParent(Handle, hwnd);
|
||||
|
||||
RECT s = default(RECT);
|
||||
NativeMethods.GetClientRect(hwnd, ref s);
|
||||
|
||||
if (Bounds.Right != s.Right || Bounds.Bottom != s.Bottom || Bounds.Left != s.Left || Bounds.Top != s.Top)
|
||||
{
|
||||
Bounds = s.ToRectangle();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ using System.Drawing;
|
||||
namespace Common
|
||||
{
|
||||
/// <summary>
|
||||
/// Interface defining methods requirement by the <see cref="PreviewHandlerBase"/> control.
|
||||
/// Interface defining preview handler control.
|
||||
/// </summary>
|
||||
public interface IPreviewHandlerControl
|
||||
{
|
||||
|
||||
@@ -55,46 +55,43 @@ namespace Common
|
||||
/// <param name="dataSource">Path to the file.</param>
|
||||
public override void DoPreview<T>(T dataSource)
|
||||
{
|
||||
this.InvokeOnControlThread(() =>
|
||||
var filePath = dataSource as string;
|
||||
|
||||
_browser = new WebView2();
|
||||
_browser.Dock = DockStyle.Fill;
|
||||
_browser.Visible = true;
|
||||
_browser.NavigationCompleted += (object sender, CoreWebView2NavigationCompletedEventArgs args) =>
|
||||
{
|
||||
var filePath = dataSource as string;
|
||||
// Put here logic needed after WebView2 control is done navigating to url/page
|
||||
};
|
||||
|
||||
_browser = new WebView2();
|
||||
_browser.Dock = DockStyle.Fill;
|
||||
_browser.Visible = true;
|
||||
_browser.NavigationCompleted += (object sender, CoreWebView2NavigationCompletedEventArgs args) =>
|
||||
ConfiguredTaskAwaitable<CoreWebView2Environment>.ConfiguredTaskAwaiter
|
||||
webView2EnvironmentAwaiter = CoreWebView2Environment
|
||||
.CreateAsync(userDataFolder: System.Environment.GetEnvironmentVariable("USERPROFILE") +
|
||||
"\\AppData\\LocalLow\\Microsoft\\PowerToys\\CustomControlTest-Temp")
|
||||
.ConfigureAwait(true).GetAwaiter();
|
||||
webView2EnvironmentAwaiter.OnCompleted(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
// Put here logic needed after WebView2 control is done navigating to url/page
|
||||
};
|
||||
_webView2Environment = webView2EnvironmentAwaiter.GetResult();
|
||||
await _browser.EnsureCoreWebView2Async(_webView2Environment).ConfigureAwait(true);
|
||||
await _browser.CoreWebView2.AddScriptToExecuteOnDocumentCreatedAsync("window.addEventListener('contextmenu', window => {window.preventDefault();});");
|
||||
_browser.CoreWebView2.SetVirtualHostNameToFolderMapping(VirtualHostName, AssemblyDirectory, CoreWebView2HostResourceAccessKind.Allow);
|
||||
|
||||
ConfiguredTaskAwaitable<CoreWebView2Environment>.ConfiguredTaskAwaiter
|
||||
webView2EnvironmentAwaiter = CoreWebView2Environment
|
||||
.CreateAsync(userDataFolder: System.Environment.GetEnvironmentVariable("USERPROFILE") +
|
||||
"\\AppData\\LocalLow\\Microsoft\\PowerToys\\CustomControlTest-Temp")
|
||||
.ConfigureAwait(true).GetAwaiter();
|
||||
webView2EnvironmentAwaiter.OnCompleted(async () =>
|
||||
// Navigate to page represented as a string
|
||||
_browser.NavigateToString("Test");
|
||||
|
||||
// Or navigate to Uri
|
||||
_browser.Source = new Uri(filePath);
|
||||
}
|
||||
catch (NullReferenceException)
|
||||
{
|
||||
try
|
||||
{
|
||||
_webView2Environment = webView2EnvironmentAwaiter.GetResult();
|
||||
await _browser.EnsureCoreWebView2Async(_webView2Environment).ConfigureAwait(true);
|
||||
await _browser.CoreWebView2.AddScriptToExecuteOnDocumentCreatedAsync("window.addEventListener('contextmenu', window => {window.preventDefault();});");
|
||||
_browser.CoreWebView2.SetVirtualHostNameToFolderMapping(VirtualHostName, AssemblyDirectory, CoreWebView2HostResourceAccessKind.Allow);
|
||||
|
||||
// Navigate to page represented as a string
|
||||
_browser.NavigateToString("Test");
|
||||
|
||||
// Or navigate to Uri
|
||||
_browser.Source = new Uri(filePath);
|
||||
}
|
||||
catch (NullReferenceException)
|
||||
{
|
||||
}
|
||||
});
|
||||
|
||||
this.Controls.Add(_browser);
|
||||
base.DoPreview(dataSource);
|
||||
}
|
||||
});
|
||||
|
||||
this.Controls.Add(_browser);
|
||||
base.DoPreview(dataSource);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
// 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.Runtime.InteropServices;
|
||||
|
||||
namespace Common
|
||||
{
|
||||
/// <summary>
|
||||
/// This is a example custom handler to show how to extend the library.
|
||||
/// </summary>
|
||||
[Guid("22a1a8e8-e929-4732-90ce-91eaff38b614")]
|
||||
[ClassInterface(ClassInterfaceType.None)]
|
||||
[ComVisible(true)]
|
||||
public class TestCustomHandler : FileBasedPreviewHandler, IDisposable
|
||||
{
|
||||
private CustomControlTest _previewHandlerControl;
|
||||
private bool disposedValue;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void DoPreview()
|
||||
{
|
||||
_previewHandlerControl.DoPreview(FilePath);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override IPreviewHandlerControl CreatePreviewHandlerControl()
|
||||
{
|
||||
_previewHandlerControl = new CustomControlTest();
|
||||
|
||||
return _previewHandlerControl;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disposes objects
|
||||
/// </summary>
|
||||
/// <param name="disposing">Is Disposing</param>
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (!disposedValue)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
_previewHandlerControl.Dispose();
|
||||
}
|
||||
|
||||
disposedValue = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Dispose()
|
||||
{
|
||||
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
|
||||
Dispose(disposing: true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
// 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.Runtime.InteropServices;
|
||||
using Common.Cominterop;
|
||||
|
||||
namespace Common
|
||||
{
|
||||
/// <summary>
|
||||
/// Extends the <see cref="PreviewHandlerBase" /> by implementing IInitializeWithFile.
|
||||
/// </summary>
|
||||
public abstract class FileBasedPreviewHandler : PreviewHandlerBase, IInitializeWithFile
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the file path.
|
||||
/// </summary>
|
||||
public string FilePath { get; private set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Initialize([MarshalAs(UnmanagedType.LPWStr)] string pszFilePath, uint grfMode)
|
||||
{
|
||||
// Ignore the grfMode always use read mode to access the file.
|
||||
this.FilePath = pszFilePath;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,163 +0,0 @@
|
||||
// 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.ComponentModel;
|
||||
using System.Drawing;
|
||||
using Common.ComInterlop;
|
||||
|
||||
namespace Common
|
||||
{
|
||||
/// <summary>
|
||||
/// Preview Handler base class implementing interfaces required by Preview Handler.
|
||||
/// </summary>
|
||||
public abstract class PreviewHandlerBase : IPreviewHandler, IOleWindow, IObjectWithSite, IPreviewHandlerVisuals
|
||||
{
|
||||
/// <summary>
|
||||
/// An instance of Preview Control Used by the Handler.
|
||||
/// </summary>
|
||||
private IPreviewHandlerControl previewControl;
|
||||
|
||||
/// <summary>
|
||||
/// Hold reference for the window handle.
|
||||
/// </summary>
|
||||
private IntPtr parentHwnd;
|
||||
|
||||
/// <summary>
|
||||
/// Hold the bounds of the window.
|
||||
/// </summary>
|
||||
private Rectangle windowBounds;
|
||||
|
||||
/// <summary>
|
||||
/// Holds the site pointer.
|
||||
/// </summary>
|
||||
private object unkSite;
|
||||
|
||||
/// <summary>
|
||||
/// Holds reference for the IPreviewHandlerFrame.
|
||||
/// </summary>
|
||||
private IPreviewHandlerFrame frame;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PreviewHandlerBase"/> class.
|
||||
/// </summary>
|
||||
public PreviewHandlerBase()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PreviewHandlerBase"/> class.
|
||||
/// </summary>
|
||||
public void Initialize()
|
||||
{
|
||||
previewControl = CreatePreviewHandlerControl();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public abstract void DoPreview();
|
||||
|
||||
/// <inheritdoc />
|
||||
public void SetWindow(IntPtr hwnd, ref RECT rect)
|
||||
{
|
||||
this.parentHwnd = hwnd;
|
||||
this.windowBounds = rect.ToRectangle();
|
||||
this.previewControl.SetWindow(hwnd, this.windowBounds);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void SetRect(ref RECT rect)
|
||||
{
|
||||
this.windowBounds = rect.ToRectangle();
|
||||
this.previewControl.SetRect(this.windowBounds);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Unload()
|
||||
{
|
||||
this.previewControl.Unload();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void SetFocus()
|
||||
{
|
||||
this.previewControl.SetFocus();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void QueryFocus(out IntPtr phwnd)
|
||||
{
|
||||
this.previewControl.QueryFocus(out IntPtr result);
|
||||
phwnd = result;
|
||||
if (phwnd == IntPtr.Zero)
|
||||
{
|
||||
throw new Win32Exception();
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public uint TranslateAccelerator(ref MSG pmsg)
|
||||
{
|
||||
// Current implementation simply directs all Keystrokes to IPreviewHandlerFrame. This is the recommended approach to handle keystokes for all low-integrity preview handlers.
|
||||
// Source: https://learn.microsoft.com/windows/win32/shell/building-preview-handlers#ipreviewhandlertranslateaccelerator
|
||||
if (this.frame != null)
|
||||
{
|
||||
return this.frame.TranslateAccelerator(ref pmsg);
|
||||
}
|
||||
|
||||
const uint S_FALSE = 1;
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void GetWindow(out IntPtr phwnd)
|
||||
{
|
||||
phwnd = this.previewControl.GetWindowHandle();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void ContextSensitiveHelp(bool fEnterMode)
|
||||
{
|
||||
// Should always return NotImplementedException. Source: https://learn.microsoft.com/windows/win32/shell/building-preview-handlers#iolewindowcontextsensitivehelp
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void SetSite(object pUnkSite)
|
||||
{
|
||||
// Implementation logic details: https://learn.microsoft.com/windows/win32/shell/building-preview-handlers#iobjectwithsitesetsite
|
||||
this.unkSite = pUnkSite;
|
||||
this.frame = this.unkSite as IPreviewHandlerFrame;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void GetSite(ref Guid riid, out object ppvSite)
|
||||
{
|
||||
ppvSite = this.unkSite;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void SetBackgroundColor(COLORREF color)
|
||||
{
|
||||
this.previewControl.SetBackgroundColor(color.Color);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void SetFont(ref LOGFONT plf)
|
||||
{
|
||||
this.previewControl.SetFont(Font.FromLogFont(plf));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void SetTextColor(COLORREF color)
|
||||
{
|
||||
this.previewControl.SetTextColor(color.Color);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Provide instance of the implementation of <see cref="IPreviewHandlerControl"/>. Should be overridden by the implementation class with a control object to be used.
|
||||
/// </summary>
|
||||
/// <returns>Instance of the <see cref="IPreviewHandlerControl"/>.</returns>
|
||||
protected abstract IPreviewHandlerControl CreatePreviewHandlerControl();
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
// 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.Runtime.InteropServices.ComTypes;
|
||||
using Common.ComInterlop;
|
||||
|
||||
namespace Common
|
||||
{
|
||||
/// <summary>
|
||||
/// Extends the <see cref="PreviewHandlerBase" /> by implementing IInitializeWithStream.
|
||||
/// </summary>
|
||||
public abstract class StreamBasedPreviewHandler : PreviewHandlerBase, IInitializeWithStream
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the stream object to access file.
|
||||
/// </summary>
|
||||
public IStream Stream { get; private set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Initialize(IStream pstream, uint grfMode)
|
||||
{
|
||||
// Ignore the grfMode always use read mode to access the file.
|
||||
this.Stream = pstream;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user