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:
Stefan Markovic
2022-12-14 13:37:23 +01:00
committed by GitHub
parent a2c0febccc
commit 6ac508fb93
215 changed files with 9060 additions and 2328 deletions

View File

@@ -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);
}
}

View File

@@ -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();
}
}
}
}

View File

@@ -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
{

View File

@@ -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);
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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();
}
}

View File

@@ -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;
}
}
}