[fxcop] preview handler common (#6762)

* FxCop adjustments

* initing due to change for abstract
This commit is contained in:
Clint Rutkas
2020-09-23 10:22:17 -07:00
committed by GitHub
parent 75ace74d37
commit 0148669e98
22 changed files with 241 additions and 138 deletions

View File

@@ -20,6 +20,14 @@ namespace Microsoft.PowerToys.PreviewHandler.Markdown
private MarkdownPreviewHandlerControl _markdownPreviewHandlerControl;
private bool disposedValue;
/// <summary>
/// Initializes a new instance of the <see cref="MarkdownPreviewHandler"/> class.
/// </summary>
public MarkdownPreviewHandler()
{
Initialize();
}
/// <inheritdoc />
public override void DoPreview()
{

View File

@@ -48,7 +48,7 @@ namespace Microsoft.PowerToys.PreviewHandler.Svg
{
_infoBarAdded = false;
string svgData = null;
using (var stream = new StreamWrapper(dataSource as IStream))
using (var stream = new ReadonlyStream(dataSource as IStream))
{
using (var reader = new StreamReader(stream))
{

View File

@@ -20,6 +20,14 @@ namespace Microsoft.PowerToys.PreviewHandler.Svg
private SvgPreviewControl _svgPreviewControl;
private bool disposedValue;
/// <summary>
/// Initializes a new instance of the <see cref="SvgPreviewHandler"/> class.
/// </summary>
public SvgPreviewHandler()
{
Initialize();
}
/// <inheritdoc/>
public override void DoPreview()
{

View File

@@ -225,7 +225,7 @@ namespace Microsoft.PowerToys.ThumbnailHandler.Svg
}
string svgData = null;
using (var stream = new StreamWrapper(this.Stream as IStream))
using (var stream = new ReadonlyStream(this.Stream as IStream))
{
using (var reader = new StreamReader(stream))
{

View File

@@ -58,7 +58,7 @@ namespace UnitTests_PreviewHandlerCommon
using (var testFormHandlerControl = new TestFormControl())
{
// Act
var handle = testFormHandlerControl.GetHandle();
var handle = testFormHandlerControl.Handle;
// Assert
Assert.AreEqual(testFormHandlerControl.Handle, handle);

View File

@@ -19,6 +19,11 @@ namespace UnitTests_PreviewHandlerCommon
public class TestPreviewHandler : PreviewHandlerBase
{
public TestPreviewHandler()
{
Initialize();
}
public override void DoPreview()
{
throw new NotImplementedException();
@@ -291,7 +296,7 @@ namespace UnitTests_PreviewHandlerCommon
// Arrange
var previewControlHandle = new IntPtr(5);
var mockPreviewControl = new Mock<IPreviewHandlerControl>();
mockPreviewControl.Setup(x => x.GetHandle())
mockPreviewControl.Setup(x => x.GetWindowHandle())
.Returns(previewControlHandle);
previewHandlerControl = mockPreviewControl.Object;

View File

@@ -26,7 +26,7 @@ namespace UnitTests_PreviewHandlerCommon
// Act
try
{
var streamWrapper = new StreamWrapper(stream);
var streamWrapper = new ReadonlyStream(stream);
}
catch (ArgumentNullException ex)
{
@@ -44,7 +44,7 @@ namespace UnitTests_PreviewHandlerCommon
var streamMock = new Mock<IStream>();
// Act
var streamWrapper = new StreamWrapper(streamMock.Object);
var streamWrapper = new ReadonlyStream(streamMock.Object);
// Assert
Assert.AreEqual(streamWrapper.CanRead, true);
@@ -57,7 +57,7 @@ namespace UnitTests_PreviewHandlerCommon
var streamMock = new Mock<IStream>();
// Act
var streamWrapper = new StreamWrapper(streamMock.Object);
var streamWrapper = new ReadonlyStream(streamMock.Object);
// Assert
Assert.AreEqual(streamWrapper.CanSeek, true);
@@ -70,7 +70,7 @@ namespace UnitTests_PreviewHandlerCommon
var streamMock = new Mock<IStream>();
// Act
var streamWrapper = new StreamWrapper(streamMock.Object);
var streamWrapper = new ReadonlyStream(streamMock.Object);
// Assert
Assert.AreEqual(streamWrapper.CanWrite, false);
@@ -89,7 +89,7 @@ namespace UnitTests_PreviewHandlerCommon
stremMock
.Setup(x => x.Stat(out stat, It.IsAny<int>()));
var streamWrapper = new StreamWrapper(stremMock.Object);
var streamWrapper = new ReadonlyStream(stremMock.Object);
// Act
var actualLength = streamWrapper.Length;
@@ -113,7 +113,7 @@ namespace UnitTests_PreviewHandlerCommon
{
Marshal.WriteInt64(plibNewPosition, currPosition);
});
var streamWrapper = new StreamWrapper(stremMock.Object);
var streamWrapper = new ReadonlyStream(stremMock.Object);
// Act
var actualPosition = streamWrapper.Position;
@@ -131,7 +131,7 @@ namespace UnitTests_PreviewHandlerCommon
int expectedDwOrigin = 0; // STREAM_SEEK_SET
var stremMock = new Mock<IStream>();
var streamWrapper = new StreamWrapper(stremMock.Object)
var streamWrapper = new ReadonlyStream(stremMock.Object)
{
// Act
Position = positionToSet,
@@ -168,7 +168,7 @@ namespace UnitTests_PreviewHandlerCommon
}
var stremMock = new Mock<IStream>();
var streamWrapper = new StreamWrapper(stremMock.Object);
var streamWrapper = new ReadonlyStream(stremMock.Object);
// Act
streamWrapper.Seek(offset, origin);
@@ -191,7 +191,7 @@ namespace UnitTests_PreviewHandlerCommon
Marshal.WriteInt64(plibNewPosition, position);
});
var streamWrapper = new StreamWrapper(stremMock.Object);
var streamWrapper = new ReadonlyStream(stremMock.Object);
// Act
var actualPosition = streamWrapper.Seek(0, SeekOrigin.Begin);
@@ -212,7 +212,7 @@ namespace UnitTests_PreviewHandlerCommon
var stremMock = new Mock<IStream>();
ArgumentOutOfRangeException exception = null;
var streamWrapper = new StreamWrapper(stremMock.Object);
var streamWrapper = new ReadonlyStream(stremMock.Object);
// Act
try
@@ -252,7 +252,7 @@ namespace UnitTests_PreviewHandlerCommon
Marshal.WriteInt32(bytesReadPtr, count);
});
var streamWrapper = new StreamWrapper(stremMock.Object);
var streamWrapper = new ReadonlyStream(stremMock.Object);
// Act
var bytesRead = streamWrapper.Read(inputBuffer, offset, count);
@@ -267,7 +267,7 @@ namespace UnitTests_PreviewHandlerCommon
{
// Arrange
var stremMock = new Mock<IStream>();
var streamWrapper = new StreamWrapper(stremMock.Object);
var streamWrapper = new ReadonlyStream(stremMock.Object);
NotImplementedException exception = null;
// Act
@@ -289,7 +289,7 @@ namespace UnitTests_PreviewHandlerCommon
{
// Arrange
var stremMock = new Mock<IStream>();
var streamWrapper = new StreamWrapper(stremMock.Object);
var streamWrapper = new ReadonlyStream(stremMock.Object);
NotImplementedException exception = null;
// Act
@@ -311,7 +311,7 @@ namespace UnitTests_PreviewHandlerCommon
{
// Arrange
var stremMock = new Mock<IStream>();
var streamWrapper = new StreamWrapper(stremMock.Object);
var streamWrapper = new ReadonlyStream(stremMock.Object);
NotImplementedException exception = null;
// Act

View File

@@ -110,6 +110,7 @@
<Compile Include="cominterop\IViewObject.cs" />
<Compile Include="cominterop\LOGFONT.cs" />
<Compile Include="cominterop\MSG.cs" />
<Compile Include="cominterop\NativeMethods.cs" />
<Compile Include="cominterop\RECT.cs" />
<Compile Include="controls\WebBrowserDownloadControlFlags.cs" />
<Compile Include="controls\WebBrowserExt.cs">
@@ -129,7 +130,7 @@
<Compile Include="handlers\PreviewHandlerBase.cs" />
<Compile Include="handlers\StreamBasedPreviewHandler.cs" />
<Compile Include="examplehandler\TestCustomHandler.cs" />
<Compile Include="Utilities\StreamWrapper.cs" />
<Compile Include="Utilities\ReadonlyStream.cs" />
</ItemGroup>
<ItemGroup>
<AdditionalFiles Include="..\..\..\codeAnalysis\StyleCop.json">
@@ -137,6 +138,11 @@
</AdditionalFiles>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers">
<Version>3.3.0</Version>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="StyleCop.Analyzers">
<Version>1.1.118</Version>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>

View File

@@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.
using System;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
@@ -15,17 +16,17 @@ namespace Common.Utilities
/// <remarks>
/// Implements only read from the stream functionality.
/// </remarks>
public class StreamWrapper : Stream
public class ReadonlyStream : Stream
{
private IStream stream;
private IStream _stream;
/// <summary>
/// Initializes a new instance of the <see cref="StreamWrapper"/> class.
/// Initializes a new instance of the <see cref="ReadonlyStream"/> class.
/// </summary>
/// <param name="stream">A pointer to an <see cref="IStream" /> interface that represents the stream source.</param>
public StreamWrapper(IStream stream)
public ReadonlyStream(IStream stream)
{
this.stream = stream ?? throw new ArgumentNullException(nameof(stream));
_stream = stream ?? throw new ArgumentNullException(nameof(stream));
}
/// <summary>
@@ -68,11 +69,11 @@ namespace Common.Utilities
{
get
{
this.CheckDisposed();
CheckDisposed();
System.Runtime.InteropServices.ComTypes.STATSTG stat;
// Stat called with STATFLAG_NONAME. The pwcsName is not required more details https://docs.microsoft.com/en-us/windows/win32/api/wtypes/ne-wtypes-statflag
this.stream.Stat(out stat, 1); // STATFLAG_NONAME
_stream.Stat(out stat, 1); // STATFLAG_NONAME
return stat.cbSize;
}
@@ -85,12 +86,12 @@ namespace Common.Utilities
{
get
{
return this.Seek(0, SeekOrigin.Current);
return Seek(0, SeekOrigin.Current);
}
set
{
this.Seek(value, SeekOrigin.Begin);
Seek(value, SeekOrigin.Begin);
}
}
@@ -103,11 +104,16 @@ namespace Common.Utilities
/// <returns>The total number of bytes read into the buffer. This can be less than the number of bytes requested if that many bytes are not currently available, or zero if the end of the stream has been reached.</returns>
public override int Read(byte[] buffer, int offset, int count)
{
this.CheckDisposed();
CheckDisposed();
if (offset < 0 || count < 0 || offset + count > buffer.Length)
if (buffer == null)
{
throw new ArgumentOutOfRangeException();
throw new NullReferenceException("buffer is null");
}
if (offset < 0 || count < 0 || (offset + count) > buffer.Length)
{
throw new ArgumentOutOfRangeException(nameof(buffer), "Out of range for buffer");
}
byte[] localBuffer = buffer;
@@ -121,7 +127,7 @@ namespace Common.Utilities
try
{
this.stream.Read(localBuffer, count, bytesReadPtr);
_stream.Read(localBuffer, count, bytesReadPtr);
int bytesRead = Marshal.ReadInt32(bytesReadPtr);
if (offset > 0)
@@ -145,7 +151,7 @@ namespace Common.Utilities
/// <returns>The new position within the current stream.</returns>
public override long Seek(long offset, SeekOrigin origin)
{
this.CheckDisposed();
CheckDisposed();
int dwOrigin;
// Maps the SeekOrigin with dworigin more details: https://docs.microsoft.com/en-us/windows/win32/api/objidl/ne-objidl-stream_seek
@@ -164,14 +170,14 @@ namespace Common.Utilities
break;
default:
throw new ArgumentOutOfRangeException();
throw new ArgumentOutOfRangeException(nameof(origin));
}
IntPtr posPtr = Marshal.AllocCoTaskMem(sizeof(long));
try
{
this.stream.Seek(offset, dwOrigin, posPtr);
_stream.Seek(offset, dwOrigin, posPtr);
return Marshal.ReadInt64(posPtr);
}
finally
@@ -220,22 +226,24 @@ namespace Common.Utilities
/// <inheritdoc/>
protected override void Dispose(bool disposing)
{
if (this.stream != null)
base.Dispose(true);
if (_stream != null)
{
if (Marshal.IsComObject(this.stream))
if (Marshal.IsComObject(_stream))
{
Marshal.ReleaseComObject(this.stream);
Marshal.ReleaseComObject(_stream);
}
this.stream = null;
_stream = null;
}
}
private void CheckDisposed()
{
if (this.stream == null)
if (_stream == null)
{
throw new ObjectDisposedException(nameof(StreamWrapper));
throw new ObjectDisposedException(nameof(ReadonlyStream));
}
}
}

View File

@@ -11,12 +11,13 @@ namespace Common.ComInterlop
/// The COLORREF value is used to specify an RGB color.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
[System.Diagnostics.CodeAnalysis.SuppressMessage("Performance", "CA1815:Override equals and operator equals on value types", Justification = "Interop")]
public struct COLORREF
{
/// <summary>
/// Stores an RGB color value in a 32 bit integer.
/// Gets or sets stores an RGB color value in a 32 bit integer.
/// </summary>
public uint Dword;
public uint Dword { get; set; }
/// <summary>
/// Gets RGB value stored in <see cref="Dword"/> in <see cref="Color"/> structure.
@@ -26,9 +27,9 @@ namespace Common.ComInterlop
get
{
return Color.FromArgb(
(int)(0x000000FFU & this.Dword),
(int)(0x0000FF00U & this.Dword) >> 8,
(int)(0x00FF0000U & this.Dword) >> 16);
(int)(0x000000FFU & Dword),
(int)(0x0000FF00U & Dword) >> 8,
(int)(0x00FF0000U & Dword) >> 16);
}
}
}

View File

@@ -10,10 +10,11 @@ namespace Common.ComInterlop
/// <summary>
/// Specifies the alpha type of the image.
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Naming", "CA1707:Identifiers should not contain underscores", Justification = "Interop")]
public enum WTS_ALPHATYPE : int
{
/// <summary>
/// he bitmap is an unknown format. The Shell tries nonetheless to detect whether the image has an alpha channel.
/// The bitmap is an unknown format. The Shell tries nonetheless to detect whether the image has an alpha channel.
/// </summary>
WTSAT_UNKNOWN = 0,

View File

@@ -10,79 +10,86 @@ namespace Common.ComInterlop
/// Defines the attributes of a font.
/// </summary>
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
[System.Diagnostics.CodeAnalysis.SuppressMessage("Performance", "CA1815:Override equals and operator equals on value types", Justification = "Interop")]
public struct LOGFONT
{
/// <summary>
/// Value of type INT that specifies the height, in logical units, of the font's character cell or character.
/// Gets or sets value of type INT that specifies the height, in logical units, of the font's character cell or character.
/// </summary>
public int LfHeight;
public int LfHeight { get; set; }
/// <summary>
/// Value of type INT that specifies the width, in logical units, of characters in the font.
/// Gets or sets value of type INT that specifies the width, in logical units, of characters in the font.
/// </summary>
public int LfWidth;
public int LfWidth { get; set; }
/// <summary>
/// Value of type INT that contains the angle, in tenths of degrees, between the escapement vector and the x-axis of the device. The escapement
/// Gets or sets value of type INT that contains the angle, in tenths of degrees, between the escapement vector and the x-axis of the device. The escapement
/// vector is parallel to the base line of a row of text.
/// </summary>
public int LfEscapement;
public int LfEscapement { get; set; }
/// <summary>
/// Value of type INT that specifies the angle, in tenths of degrees, between each character's base line and the x-axis of the device.
/// Gets or sets value of type INT that specifies the angle, in tenths of degrees, between each character's base line and the x-axis of the device.
/// </summary>
public int LfOrientation;
public int LfOrientation { get; set; }
/// <summary>
/// Value of type INT that specifies the weight of the font in the range from 0 through 1000.
/// Gets or sets value of type INT that specifies the weight of the font in the range from 0 through 1000.
/// </summary>
public int LfWeight;
public int LfWeight { get; set; }
/// <summary>
/// Value of type BYTE that specifies an italic font if set to TRUE.
/// Gets or sets value of type BYTE that specifies an italic font if set to TRUE.
/// </summary>
public byte LfItalic;
public byte LfItalic { get; set; }
/// <summary>
/// Value of type BYTE that specifies an underlined font if set to TRUE.
/// Gets or sets value of type BYTE that specifies an underlined font if set to TRUE.
/// </summary>
public byte LfUnderline;
public byte LfUnderline { get; set; }
/// <summary>
/// Value of type BYTE that specifies a strikeout font if set to TRUE.
/// Gets or sets value of type BYTE that specifies a strikeout font if set to TRUE.
/// </summary>
public byte LfStrikeOut;
public byte LfStrikeOut { get; set; }
/// <summary>
/// Value of type BYTE that specifies the character set.
/// Gets or sets value of type BYTE that specifies the character set.
/// </summary>
public byte LfCharSet;
public byte LfCharSet { get; set; }
/// <summary>
/// Value of type BYTE that specifies the output precision. The output precision defines how closely the output must match the requested
/// Gets or sets value of type BYTE that specifies the output precision. The output precision defines how closely the output must match the requested
/// font's height, width, character orientation, escapement, pitch, and font type.
/// </summary>
public byte LfOutPrecision;
public byte LfOutPrecision { get; set; }
/// <summary>
/// Value of type BYTE that specifies the clipping precision. The clipping precision defines how to clip characters that are partially outside the clipping region.
/// Gets or sets value of type BYTE that specifies the clipping precision. The clipping precision defines how to clip characters that are partially outside the clipping region.
/// </summary>
public byte LfClipPrecision;
public byte LfClipPrecision { get; set; }
/// <summary>
/// Value of type BYTE that specifies the output quality. The output quality defines how carefully the GDI must attempt to match the logical-font attributes to those of an actual physical font.
/// Gets or sets value of type BYTE that specifies the output quality. The output quality defines how carefully the GDI must attempt to match the logical-font attributes to those of an actual physical font.
/// </summary>
public byte LfQuality;
public byte LfQuality { get; set; }
/// <summary>
/// Value of type BYTE that specifies the pitch and family of the font.
/// Gets or sets value of type BYTE that specifies the pitch and family of the font.
/// </summary>
public byte LfPitchAndFamily;
public byte LfPitchAndFamily { get; set; }
/// <summary>
/// Array of wide characters that contains a null-terminated string that specifies the typeface name of the font. The length of the string must not exceed 32 characters, including the NULL terminator.
/// Gets or sets array of wide characters that contains a null-terminated string that specifies the typeface name of the font. The length of the string must not exceed 32 characters, including the NULL terminator.
/// </summary>
public string LfFaceName
{
get { return _lfFaceName; }
set { _lfFaceName = value; }
}
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
public string LfFaceName;
private string _lfFaceName;
}
}

View File

@@ -11,41 +11,42 @@ namespace Common.ComInterlop
/// Contains message information from a thread's message queue.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
[System.Diagnostics.CodeAnalysis.SuppressMessage("Performance", "CA1815:Override equals and operator equals on value types", Justification = "Interop")]
public struct MSG
{
/// <summary>
/// A handle to the window whose window procedure receives the message. This member is NULL when the message is a thread message.
/// Gets or sets a handle to the window whose window procedure receives the message. This member is NULL when the message is a thread message.
/// </summary>
public IntPtr Hwnd;
public IntPtr Hwnd { get; set; }
/// <summary>
/// The message identifier. Applications can only use the low word; the high word is reserved by the system.
/// Gets or sets the message identifier. Applications can only use the low word; the high word is reserved by the system.
/// </summary>
public int Message;
public int Message { get; set; }
/// <summary>
/// Additional information about the message. The exact meaning depends on the value of the message member.
/// Gets or sets additional information about the message. The exact meaning depends on the value of the message member.
/// </summary>
public IntPtr WParam;
public IntPtr WParam { get; set; }
/// <summary>
/// Additional information about the message. The exact meaning depends on the value of the message member.
/// Gets or sets additional information about the message. The exact meaning depends on the value of the message member.
/// </summary>
public IntPtr LParam;
public IntPtr LParam { get; set; }
/// <summary>
/// The time at which the message was posted.
/// Gets or sets the time at which the message was posted.
/// </summary>
public int Time;
public int Time { get; set; }
/// <summary>
/// The x coordinate of cursor position, in screen coordinates, when the message was posted.
/// Gets or sets the x coordinate of cursor position, in screen coordinates, when the message was posted.
/// </summary>
public int PtX;
public int PtX { get; set; }
/// <summary>
/// The y coordinate of cursor position, in screen coordinates, when the message was posted.
/// Gets or sets the y coordinate of cursor position, in screen coordinates, when the message was posted.
/// </summary>
public int PtY;
public int PtY { get; set; }
}
}

View File

@@ -0,0 +1,37 @@
// 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 PreviewHandlerCommon.ComInterop
{
/// <summary>
/// Interop methods
/// </summary>
internal class NativeMethods
{
/// <summary>
/// Changes the parent window of the specified child window.
/// </summary>
/// <param name="hWndChild">A handle to the child window.</param>
/// <param name="hWndNewParent">A handle to the new parent window.</param>
/// <returns>If the function succeeds, the return value is a handle to the previous parent window and NULL in case of failure.</returns>
[DllImport("user32.dll")]
public static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
/// <summary>
/// Retrieves the handle to the window that has the keyboard focus, if the window is attached to the calling thread's message queue.
/// </summary>
/// <returns>The return value is the handle to the window with the keyboard focus. If the calling thread's message queue does not have an associated window with the keyboard focus, the return value is NULL.</returns>
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr GetFocus();
[DllImport("user32.dll", SetLastError = true)]
public static extern int GetWindowLong(IntPtr hWnd, int nIndex);
[DllImport("user32.dll", SetLastError = true)]
public static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
}
}

View File

@@ -11,27 +11,28 @@ namespace Common.ComInterlop
/// The RECT structure defines a rectangle by the coordinates of its upper-left and lower-right corners.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
[System.Diagnostics.CodeAnalysis.SuppressMessage("Performance", "CA1815:Override equals and operator equals on value types", Justification = "Interop")]
public struct RECT
{
/// <summary>
/// Specifies the x-coordinate of the upper-left corner of the rectangle.
/// Gets or sets specifies the x-coordinate of the upper-left corner of the rectangle.
/// </summary>
public int Left;
public int Left { get; set; }
/// <summary>
/// Specifies the y-coordinate of the upper-left corner of the rectangle.
/// Gets or sets specifies the y-coordinate of the upper-left corner of the rectangle.
/// </summary>
public int Top;
public int Top { get; set; }
/// <summary>
/// Specifies the x-coordinate of the lower-right corner of the rectangle.
/// Gets or sets specifies the x-coordinate of the lower-right corner of the rectangle.
/// </summary>
public int Right;
public int Right { get; set; }
/// <summary>
/// Specifies the y-coordinate of the lower-right corner of the rectangle.
/// Gets or sets specifies the y-coordinate of the lower-right corner of the rectangle.
/// </summary>
public int Bottom;
public int Bottom { get; set; }
/// <summary>
/// Creates a <see cref="Rectangle" /> structure with the edge locations specified in the struct.
@@ -39,7 +40,7 @@ namespace Common.ComInterlop
/// <returns>Return a <see cref="Rectangle"/>.</returns>
public Rectangle ToRectangle()
{
return Rectangle.FromLTRB(this.Left, this.Top, this.Right, this.Bottom);
return Rectangle.FromLTRB(Left, Top, Right, Bottom);
}
}
}

View File

@@ -6,6 +6,7 @@ using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using PreviewHandlerCommon.ComInterop;
namespace Common
{
@@ -34,12 +35,13 @@ namespace Common
// This is important, because the thread that instantiates the preview handler component and calls its constructor is a single-threaded apartment (STA) thread, but the thread that calls into the interface members later on is a multithreaded apartment (MTA) thread. Windows Forms controls are meant to run on STA threads.
// More details: https://docs.microsoft.com/en-us/archive/msdn-magazine/2007/january/windows-vista-and-office-writing-your-own-preview-handlers.
var forceCreation = this.Handle;
this.FormBorderStyle = FormBorderStyle.None;
this.Visible = false;
}
/// <inheritdoc />
public IntPtr GetHandle()
public IntPtr GetWindowHandle()
{
return this.Handle;
}
@@ -50,7 +52,7 @@ namespace Common
var getResult = IntPtr.Zero;
this.InvokeOnControlThread(() =>
{
getResult = GetFocus();
getResult = NativeMethods.GetFocus();
});
result = getResult;
}
@@ -140,28 +142,6 @@ namespace Common
this.Invoke(func);
}
/// <summary>
/// Changes the parent window of the specified child window.
/// </summary>
/// <param name="hWndChild">A handle to the child window.</param>
/// <param name="hWndNewParent">A handle to the new parent window.</param>
/// <returns>If the function succeeds, the return value is a handle to the previous parent window and NULL in case of failure.</returns>
[DllImport("user32.dll")]
private static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
/// <summary>
/// Retrieves the handle to the window that has the keyboard focus, if the window is attached to the calling thread's message queue.
/// </summary>
/// <returns>The return value is the handle to the window with the keyboard focus. If the calling thread's message queue does not have an associated window with the keyboard focus, the return value is NULL.</returns>
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern IntPtr GetFocus();
[DllImport("user32.dll", SetLastError = true)]
private static extern int GetWindowLong(IntPtr hWnd, int nIndex);
[DllImport("user32.dll", SetLastError = true)]
private static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
/// <summary>
/// Update the Form Control window with the passed rectangle.
/// </summary>
@@ -171,14 +151,14 @@ namespace Common
this.InvokeOnControlThread(() =>
{
// We must set the WS_CHILD style to change the form to a control within the Explorer preview pane
int windowStyle = GetWindowLong(this.Handle, gwlStyle);
int windowStyle = NativeMethods.GetWindowLong(Handle, gwlStyle);
if ((windowStyle & wsChild) == 0)
{
SetWindowLong(this.Handle, gwlStyle, windowStyle | wsChild);
_ = NativeMethods.SetWindowLong(Handle, gwlStyle, windowStyle | wsChild);
}
SetParent(this.Handle, this.parentHwnd);
this.Bounds = windowBounds;
NativeMethods.SetParent(Handle, parentHwnd);
Bounds = windowBounds;
});
}
}

View File

@@ -47,7 +47,7 @@ namespace Common
/// Gets the HWND of the control window.
/// </summary>
/// <returns>Pointer to the window handle.</returns>
IntPtr GetHandle();
IntPtr GetWindowHandle();
/// <summary>
/// Hide the preview and free any resource used for the preview.

View File

@@ -9,6 +9,7 @@ using System;
/// Values of flags are defined in mshtmdid.h in distributed Windows Sdk.
/// </summary>
[Flags]
[System.Diagnostics.CodeAnalysis.SuppressMessage("Naming", "CA1707:Identifiers should not contain underscores", Justification = "Interop, keeping stuff in sync")]
public enum WebBrowserDownloadControlFlags : int
{
/// <summary>

View File

@@ -51,7 +51,8 @@ namespace PreviewHandlerCommon
public object InvokeMember(string name, BindingFlags invokeAttr, Binder binder, object target, object[] args, ParameterModifier[] modifiers, CultureInfo culture, string[] namedParameters)
{
object result;
if (name.Equals(DISPIDAMBIENTDLCONTROL))
if (name != null && name.Equals(DISPIDAMBIENTDLCONTROL, StringComparison.CurrentCulture))
{
result = Convert.ToInt32(
WebBrowserDownloadControlFlags.DLIMAGES |
@@ -65,11 +66,11 @@ namespace PreviewHandlerCommon
WebBrowserDownloadControlFlags.NO_DLACTIVEXCTLS |
WebBrowserDownloadControlFlags.NO_RUNACTIVEXCTLS |
WebBrowserDownloadControlFlags.NO_BEHAVIORS |
WebBrowserDownloadControlFlags.SILENT);
WebBrowserDownloadControlFlags.SILENT, CultureInfo.CurrentCulture);
}
else
{
result = this.GetType().InvokeMember(name, invokeAttr, binder, target, args, modifiers, culture, namedParameters);
result = GetType().InvokeMember(name, invokeAttr, binder, target, args, modifiers, culture, namedParameters);
}
return result;

View File

@@ -2,6 +2,7 @@
// 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.IO;
using System.Windows.Forms;
@@ -24,7 +25,7 @@ namespace Common
WebBrowser browser = new WebBrowser();
browser.DocumentText = "Test";
browser.Navigate(filePath);
browser.Navigate(new Uri(filePath));
browser.Dock = DockStyle.Fill;
browser.IsWebBrowserContextMenuEnabled = false;
this.Controls.Add(browser);

View File

@@ -2,6 +2,7 @@
// 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
@@ -12,21 +13,50 @@ namespace Common
[Guid("22a1a8e8-e929-4732-90ce-91eaff38b614")]
[ClassInterface(ClassInterfaceType.None)]
[ComVisible(true)]
public class TestCustomHandler : FileBasedPreviewHandler
public class TestCustomHandler : FileBasedPreviewHandler, IDisposable
{
private CustomControlTest previewHandlerControl;
private CustomControlTest _previewHandlerControl;
private bool disposedValue;
/// <inheritdoc />
public override void DoPreview()
{
this.previewHandlerControl.DoPreview(this.FilePath);
_previewHandlerControl.DoPreview(FilePath);
}
/// <inheritdoc />
protected override IPreviewHandlerControl CreatePreviewHandlerControl()
{
this.previewHandlerControl = new CustomControlTest();
return this.previewHandlerControl;
_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();
}
// TODO: free unmanaged resources (unmanaged objects) and override finalizer
// TODO: set large fields to null
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

@@ -46,7 +46,14 @@ namespace Common
/// </summary>
public PreviewHandlerBase()
{
this.previewControl = this.CreatePreviewHandlerControl();
}
/// <summary>
/// Initializes a new instance of the <see cref="PreviewHandlerBase"/> class.
/// </summary>
public void Initialize()
{
previewControl = CreatePreviewHandlerControl();
}
/// <inheritdoc />
@@ -107,7 +114,7 @@ namespace Common
/// <inheritdoc />
public void GetWindow(out IntPtr phwnd)
{
phwnd = this.previewControl.GetHandle();
phwnd = this.previewControl.GetWindowHandle();
}
/// <inheritdoc />