Mooore aggressive GC; rewrite native dll

This commit is contained in:
Paddy Xu
2017-05-29 00:11:16 +03:00
parent 13dfa7a815
commit 5ad20b8a53
15 changed files with 252 additions and 352 deletions

View File

@@ -5,22 +5,12 @@
#define EXPORT extern "C" __declspec(dllexport)
EXPORT int GetFocusedWindowType()
EXPORT Shell32::FocusedWindowType GetFocusedWindowType()
{
return Shell32::GetFocusedWindowType();
}
EXPORT void SaveCurrentSelection()
EXPORT void GetCurrentSelection(PWCHAR buffer)
{
Shell32::SaveCurrentSelection();
}
EXPORT int GetCurrentSelectionCount()
{
return Shell32::GetCurrentSelectionCount();
}
EXPORT void GetCurrentSelectionBuffer(PWCHAR buffer)
{
Shell32::GetCurrentSelectionBuffer(buffer);
Shell32::GetCurrentSelection(buffer);
}

View File

@@ -1,201 +1,19 @@
#include "stdafx.h"
#include "Shell32.h"
#include <atlcomcli.h>
using namespace std;
vector<wstring> Shell32::vector_items;
void Shell32::SaveCurrentSelection()
{
vector_items.clear();
switch (GetFocusedWindowType())
{
case EXPLORER:
SaveSelectedFromExplorer();
break;
case DESKTOP:
SaveSelectedFromDesktop();
break;
default:
break;
}
}
UINT Shell32::GetCurrentSelectionCount()
{
return vector_items.size();
}
void Shell32::GetCurrentSelectionBuffer(PWCHAR buffer)
{
PWCHAR pos = buffer;
for (vector<wstring>::iterator it = vector_items.begin(); it < vector_items.end(); ++it)
{
int l = it->length();
wcscpy_s(pos, l + 1, it->c_str());
pos += l;
// overwrite NULL
wcscpy_s(pos++, 2, L"|");
}
// remove last "|"
wcscpy_s(pos - 1, 1, L"");
}
void Shell32::SaveSelectedFromExplorer()
{
CoInitialize(nullptr);
CComPtr<IShellWindows> psw;
HRESULT ret = psw.CoCreateInstance(CLSID_ShellWindows);
auto hwndFGW = GetForegroundWindow();
auto fFound = FALSE;
for (int i = 0; !fFound; i++)
{
VARIANT vi;
V_VT(&vi) = VT_I4;
V_I4(&vi) = i;
CComPtr<IDispatch> pdisp;
// ReSharper disable once CppSomeObjectMembersMightNotBeInitialized
if (SUCCEEDED(psw->Item(vi, &pdisp)))
{
CComPtr<IWebBrowserApp> pwba;
if (SUCCEEDED(pdisp->QueryInterface(IID_IWebBrowserApp, reinterpret_cast<void**>(&pwba))))
{
HWND hwndWBA;
if (SUCCEEDED(pwba->get_HWND(reinterpret_cast<LONG_PTR*>(&hwndWBA))) && hwndWBA == hwndFGW)
{
fFound = TRUE;
CComPtr<IDispatch> ppdisp;
if (SUCCEEDED(pwba->get_Document(&ppdisp)))
{
CComPtr<IShellFolderViewDual2> pshvd;
if (SUCCEEDED(ppdisp->QueryInterface(IID_IShellFolderViewDual2, reinterpret_cast<void**>(&pshvd))))
{
CComPtr<FolderItems> pfis;
if (SUCCEEDED(pshvd->SelectedItems(&pfis)))
{
LONG pCount = 0L;
pfis->get_Count(&pCount);
for (int ii = 0; ii < pCount; ii++)
{
VARIANT vii;
V_VT(&vii) = VT_I4;
V_I4(&vii) = ii;
CComPtr<FolderItem> pfi;
// ReSharper disable once CppSomeObjectMembersMightNotBeInitialized
if (SUCCEEDED(pfis->Item(vii, &pfi)))
{
CComBSTR pbs = SysAllocStringLen(L"", MAX_PATH);
pfi->get_Path(&pbs);
wstring ws = wstring(pbs);
ws.shrink_to_fit();
vector_items.push_back(ws);
}
}
}
}
}
}
}
}
}
}
CComQIPtr<IWebBrowser2> Shell32::AttachDesktopShellWindow()
{
CoInitialize(nullptr);
CComPtr<IShellWindows> psw;
CComQIPtr<IWebBrowser2> pdispOut;
if (SUCCEEDED(psw.CoCreateInstance(CLSID_ShellWindows)))
{
VARIANT pvarLoc = {VT_EMPTY};
long phwnd;
psw->FindWindowSW(&pvarLoc, &pvarLoc, SWC_DESKTOP, &phwnd, SWFO_NEEDDISPATCH, reinterpret_cast<IDispatch**>(&pdispOut));
}
return pdispOut;
}
void Shell32::SaveSelectedFromDesktop()
{
auto pWebBrowser2 = AttachDesktopShellWindow();
if (!pWebBrowser2)
return;
CComQIPtr<IServiceProvider> psp(pWebBrowser2);
if (!psp) return;
CComPtr<IShellBrowser> psb;
if (SUCCEEDED(psp->QueryService(SID_STopLevelBrowser, IID_IShellBrowser, reinterpret_cast<LPVOID*>(&psb))))
{
CComPtr<IShellView> psv;
if (SUCCEEDED(psb->QueryActiveShellView(&psv)))
{
CComPtr<IFolderView> pfv;
if (SUCCEEDED(psv->QueryInterface(IID_IFolderView, reinterpret_cast<void**>(&pfv))))
{
CComPtr<IDataObject> dao;
if (SUCCEEDED(psv->GetItemObject(SVGIO_SELECTION, IID_IDataObject, reinterpret_cast<void**>(&dao))))
vectorFromDataObject(dao);
}
}
}
}
void Shell32::vectorFromDataObject(CComPtr<IDataObject> dao)
{
FORMATETC formatetc;
STGMEDIUM medium;
formatetc.cfFormat = CF_HDROP;
formatetc.ptd = nullptr;
formatetc.dwAspect = DVASPECT_CONTENT;
formatetc.lindex = -1;
formatetc.tymed = TYMED_HGLOBAL;
medium.tymed = TYMED_HGLOBAL;
if (SUCCEEDED(dao->GetData(&formatetc, &medium)))
{
int n = DragQueryFile(HDROP(medium.hGlobal), 0xFFFFFFFF, nullptr, 0);
for (int i = 0; i < n; i++)
{
WCHAR buffer[MAX_PATH];
DragQueryFile(HDROP(medium.hGlobal), i, buffer, MAX_PATH - 1);
wstring ws = wstring(buffer);
ws.shrink_to_fit();
vector_items.push_back(ws);
}
}
}
Shell32::FocusedWindowType Shell32::GetFocusedWindowType()
{
auto type = INVALID;
auto hwndfg = GetForegroundWindow();
if (isCursorActivated(hwndfg))
return INVALID;
auto classBuffer = new WCHAR[MAX_PATH];
if (SUCCEEDED(GetClassName(hwndfg, classBuffer, MAX_PATH)))
{
@@ -215,3 +33,132 @@ Shell32::FocusedWindowType Shell32::GetFocusedWindowType()
return type;
}
void Shell32::GetCurrentSelection(PWCHAR buffer)
{
switch (GetFocusedWindowType())
{
case EXPLORER:
getSelectedFromExplorer(buffer);
break;
case DESKTOP:
getSelectedFromDesktop(buffer);
break;
default:
break;
}
}
void Shell32::getSelectedFromExplorer(PWCHAR buffer)
{
CoInitialize(nullptr);
CComPtr<IShellWindows> psw;
if (FAILED(psw.CoCreateInstance(CLSID_ShellWindows)))
return;
auto hwndFGW = GetForegroundWindow();
auto count = 0L;
psw->get_Count(&count);
for (auto i = 0; i < count; i++)
{
VARIANT vi;
V_VT(&vi) = VT_I4;
V_I4(&vi) = i;
CComPtr<IDispatch> pdisp;
// ReSharper disable once CppSomeObjectMembersMightNotBeInitialized
if (FAILED(psw->Item(vi, &pdisp)))
continue;
CComQIPtr<IWebBrowserApp> pwba;
if (FAILED(pdisp->QueryInterface(IID_IWebBrowserApp, reinterpret_cast<void**>(&pwba))))
continue;
HWND hwndWBA;
if (FAILED(pwba->get_HWND(reinterpret_cast<LONG_PTR*>(&hwndWBA))))
continue;
if (hwndWBA != hwndFGW || isCursorActivated(hwndWBA))
continue;
getSelectedInternal(pwba, buffer);
}
}
void Shell32::getSelectedFromDesktop(PWCHAR buffer)
{
CoInitialize(nullptr);
CComPtr<IShellWindows> psw;
CComQIPtr<IWebBrowserApp> pwba;
if (FAILED(psw.CoCreateInstance(CLSID_ShellWindows)))
return;
VARIANT pvarLoc = {VT_EMPTY};
long phwnd;
if (FAILED(psw->FindWindowSW(&pvarLoc, &pvarLoc, SWC_DESKTOP, &phwnd, SWFO_NEEDDISPATCH, reinterpret_cast<IDispatch**>(&pwba))))
return;
if (isCursorActivated(reinterpret_cast<HWND>(phwnd)))
return;
getSelectedInternal(pwba, buffer);
}
void Shell32::getSelectedInternal(CComQIPtr<IWebBrowserApp> pwba, PWCHAR buffer)
{
CComQIPtr<IServiceProvider> psp;
if (FAILED(pwba->QueryInterface(IID_IServiceProvider, reinterpret_cast<void**>(&psp))))
return;
CComPtr<IShellBrowser> psb;
if (FAILED(psp->QueryService(SID_STopLevelBrowser, IID_IShellBrowser, reinterpret_cast<LPVOID*>(&psb))))
return;
CComPtr<IShellView> psv;
if (FAILED(psb->QueryActiveShellView(&psv)))
return;
CComPtr<IDataObject> dao;
if (FAILED(psv->GetItemObject(SVGIO_SELECTION, IID_IDataObject, reinterpret_cast<void**>(&dao))))
return;
return obtainFirstItem(dao, buffer);
}
void Shell32::obtainFirstItem(CComPtr<IDataObject> dao, PWCHAR buffer)
{
FORMATETC formatetc;
STGMEDIUM medium;
formatetc.cfFormat = CF_HDROP;
formatetc.ptd = nullptr;
formatetc.dwAspect = DVASPECT_CONTENT;
formatetc.lindex = -1;
formatetc.tymed = TYMED_HGLOBAL;
medium.tymed = TYMED_HGLOBAL;
if (FAILED(dao->GetData(&formatetc, &medium)))
return;
int n = DragQueryFile(HDROP(medium.hGlobal), 0xFFFFFFFF, nullptr, 0);
if (n < 1)
return;
DragQueryFile(HDROP(medium.hGlobal), 0, buffer, MAX_PATH - 1);
}
bool Shell32::isCursorActivated(HWND hwnd)
{
auto tId = GetWindowThreadProcessId(hwnd, nullptr);
GUITHREADINFO gui = {sizeof gui};
GetGUIThreadInfo(tId, &gui);
return gui.flags || gui.hwndCaret;
}

View File

@@ -13,16 +13,13 @@ public:
};
static FocusedWindowType GetFocusedWindowType();
static void SaveCurrentSelection();
static UINT GetCurrentSelectionCount();
static void GetCurrentSelectionBuffer(PWCHAR buffer);
static void GetCurrentSelection(PWCHAR buffer);
private:
static std::vector<std::wstring> vector_items;
static void getSelectedFromDesktop(PWCHAR buffer);
static void getSelectedFromExplorer(PWCHAR buffer);
static void SaveSelectedFromDesktop();
static void SaveSelectedFromExplorer();
static CComQIPtr<IWebBrowser2> AttachDesktopShellWindow();
static void vectorFromDataObject(CComPtr<IDataObject> dao);
static void getSelectedInternal(CComQIPtr<IWebBrowserApp> pWebBrowserApp, PWCHAR buffer);
static void obtainFirstItem(CComPtr<IDataObject> dao, PWCHAR buffer);
static bool isCursorActivated(HWND hwndfg);
};

View File

@@ -4,6 +4,7 @@ using System.IO;
using System.Linq;
using System.Reflection;
using System.Windows;
using QuickLook.Helpers;
namespace QuickLook
{

View File

@@ -17,6 +17,7 @@ namespace QuickLook
public void Dispose()
{
_hook?.Dispose();
_hook = null;
}
private void HotkeyEventHandler(object sender, KeyEventArgs e)

View File

@@ -1,19 +1,18 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using QuickLook.Helpers;
namespace QuickLook
{
internal class FocusMonitor
{
public delegate void FocusedItemChangedEventHandler(FocusedItemChangedEventArgs e);
public delegate void HeartbeatEventHandler(HeartbeatEventArgs e);
private static FocusMonitor _instance;
public bool IsRunning { get; private set; }
public event FocusedItemChangedEventHandler FocusedItemChanged;
public event HeartbeatEventHandler Heartbeat;
public void Start()
{
@@ -21,21 +20,16 @@ namespace QuickLook
new Task(() =>
{
var currentPath = NativeMethods.QuickLook.GetCurrentSelectionFirst();
while (IsRunning)
{
Thread.Sleep(500);
if (WindowHelper.IsFocusedControlExplorerItem())
{
var file = NativeMethods.QuickLook.GetCurrentSelectionFirst();
if (file != currentPath)
{
FocusedItemChanged?.Invoke(new FocusedItemChangedEventArgs(file));
currentPath = file;
}
}
if (NativeMethods.QuickLook.GetFocusedWindowType() ==
NativeMethods.QuickLook.FocusedWindowType.Invalid)
continue;
var file = NativeMethods.QuickLook.GetCurrentSelection();
Heartbeat?.Invoke(new HeartbeatEventArgs(DateTime.Now.Ticks, file));
}
}).Start();
}
@@ -51,13 +45,15 @@ namespace QuickLook
}
}
internal class FocusedItemChangedEventArgs : EventArgs
internal class HeartbeatEventArgs : EventArgs
{
public FocusedItemChangedEventArgs(string files)
public HeartbeatEventArgs(long tick, string files)
{
InvokeTick = tick;
FocusedFile = files;
}
public long InvokeTick { get; }
public string FocusedFile { get; }
}
}

View File

@@ -1,7 +1,7 @@
using System.Diagnostics;
using System.IO;
namespace QuickLook
namespace QuickLook.Helpers
{
internal static class PidHelper
{

View File

@@ -1,6 +1,5 @@
using System;
using System.Diagnostics;
using System.Text;
using System.Windows;
using System.Windows.Forms;
using System.Windows.Interop;
@@ -61,65 +60,21 @@ namespace QuickLook.Helpers
pixelY = (int) (matrix.M22 * unitY);
}
internal static bool IsForegroundWindowBelongToSelf()
{
var hwnd = User32.GetForegroundWindow();
if (hwnd == IntPtr.Zero)
return false;
User32.GetWindowThreadProcessId(hwnd, out uint procId);
return procId == Process.GetCurrentProcess().Id;
}
internal static void SetNoactivate(WindowInteropHelper window)
{
User32.SetWindowLong(window.Handle, User32.GWL_EXSTYLE,
User32.GetWindowLong(window.Handle, User32.GWL_EXSTYLE) |
User32.WS_EX_NOACTIVATE);
}
internal static string GetWindowClassName(IntPtr window)
{
var pClassName = new StringBuilder(256);
User32.GetClassName(window, pClassName, pClassName.Capacity);
return pClassName.ToString();
}
internal static IntPtr GetParentWindow(IntPtr child)
{
return User32.GetParent(child);
}
internal static IntPtr GetFocusedWindow()
{
var activeWindowHandle = User32.GetForegroundWindow();
var activeWindowThread = User32.GetWindowThreadProcessId(activeWindowHandle, IntPtr.Zero);
var currentThread = Kernel32.GetCurrentThreadId();
User32.AttachThreadInput(activeWindowThread, currentThread, true);
var focusedControlHandle = User32.GetFocus();
User32.AttachThreadInput(activeWindowThread, currentThread, false);
return focusedControlHandle;
}
internal static bool IsFocusedWindowSelf()
{
var procId = Process.GetCurrentProcess().Id;
uint activeProcId;
User32.GetWindowThreadProcessId(GetFocusedWindow(), out activeProcId);
return activeProcId == procId;
}
internal static bool IsFocusedControlExplorerItem()
{
if (NativeMethods.QuickLook.GetFocusedWindowType() == 0)
return false;
var focusedWindowClass = GetWindowClassName(GetFocusedWindow());
var focusedWindowParentClass =
GetWindowClassName(GetParentWindow(GetFocusedWindow()));
if (focusedWindowClass != "SysListView32" && focusedWindowClass != "DirectUIHWND")
return false;
if (focusedWindowParentClass != "SHELLDLL_DefView")
return false;
return true;
}
}
}

View File

@@ -66,7 +66,13 @@
Margin="10,0,0,0" Padding="5,0"
Focusable="False" Cursor="Hand"
Background="#E5EEEEEE" BorderBrush="#E59A9A9A"
WindowChrome.IsHitTestVisibleInChrome="True" Foreground="#FF404040" />
WindowChrome.IsHitTestVisibleInChrome="True" Foreground="#FF404040">
<Button.ContentTemplate>
<DataTemplate>
<ContentPresenter Content="{Binding}" RecognizesAccessKey="False" />
</DataTemplate>
</Button.ContentTemplate>
</Button>
<!-- set grid.background colour makes it clickable -->
<Grid x:Name="titleArea" Background="Transparent">
<TextBlock Text="{Binding ContextObject.Title, ElementName=mainWindow}" FontSize="14"

View File

@@ -3,13 +3,11 @@ using System.Diagnostics;
using System.IO;
using System.Runtime.ExceptionServices;
using System.Windows;
using System.Windows.Forms;
using System.Windows.Input;
using System.Windows.Threading;
using QuickLook.Helpers;
using QuickLook.Helpers.BlurLibrary;
using QuickLook.Plugin;
using KeyEventArgs = System.Windows.Forms.KeyEventArgs;
namespace QuickLook
{
@@ -38,16 +36,16 @@ namespace QuickLook
BlurWindow.EnableWindowBlur(this);
};
buttonCloseWindow.MouseLeftButtonUp += (sender, e) => ViewWindowManager.GetInstance()
.InvokeRoutine(new KeyEventArgs(Keys.Escape));
buttonCloseWindow.MouseLeftButtonUp += (sender, e) =>
ViewWindowManager.GetInstance().ClosePreview();
buttonOpenWith.Click += (sender, e) => ViewWindowManager.GetInstance()
.InvokeRoutine(new KeyEventArgs(Keys.Enter));
buttonOpenWith.Click += (sender, e) =>
ViewWindowManager.GetInstance().RunAndClosePreview();
}
public ContextObject ContextObject { get; private set; }
internal void RunAndClose()
internal void RunAndHide()
{
if (string.IsNullOrEmpty(_path))
return;
@@ -83,6 +81,12 @@ namespace QuickLook
internal void UnloadPlugin()
{
// the focused element will not processed by GC: https://stackoverflow.com/questions/30848939/memory-leak-due-to-window-efectivevalues-retention
FocusManager.SetFocusedElement(this, null);
Keyboard.DefaultRestoreFocusMode =
RestoreFocusMode.None; // WPF will put the focused item into a "_restoreFocus" list ... omg
Keyboard.ClearFocus();
ContextObject.Reset();
_plugin?.Cleanup();
@@ -151,10 +155,6 @@ namespace QuickLook
internal void BeginHide()
{
// the focused element will not processed by GC: https://stackoverflow.com/questions/30848939/memory-leak-due-to-window-efectivevalues-retention
FocusManager.SetFocusedElement(this, null);
Keyboard.ClearFocus();
UnloadPlugin();
Hide();

View File

@@ -1,5 +1,4 @@
using System.Linq;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
@@ -8,40 +7,30 @@ namespace QuickLook.NativeMethods
internal static class QuickLook
{
[DllImport("QuickLook.Native.Shell32.dll", CallingConvention = CallingConvention.Cdecl)]
internal static extern int GetFocusedWindowType();
internal static extern FocusedWindowType GetFocusedWindowType();
[DllImport("QuickLook.Native.Shell32.dll", CallingConvention = CallingConvention.Cdecl)]
internal static extern void SaveCurrentSelection();
[DllImport("QuickLook.Native.Shell32.dll", EntryPoint = "GetCurrentSelection",
CallingConvention = CallingConvention.Cdecl)]
internal static extern void GetCurrentSelectionNative([MarshalAs(UnmanagedType.LPWStr)] StringBuilder sb);
[DllImport("QuickLook.Native.Shell32.dll", CallingConvention = CallingConvention.Cdecl)]
internal static extern int GetCurrentSelectionCount();
[DllImport("QuickLook.Native.Shell32.dll", CallingConvention = CallingConvention.Cdecl)]
internal static extern void GetCurrentSelectionBuffer([MarshalAs(UnmanagedType.LPWStr)] StringBuilder buffer);
internal static string[] GetCurrentSelection()
internal static string GetCurrentSelection()
{
StringBuilder sb = null;
// communicate with COM in a separate thread
Task.Run(() =>
{
SaveCurrentSelection();
var n = GetCurrentSelectionCount();
if (n != 0)
{
sb = new StringBuilder(n * 261); // MAX_PATH + NULL = 261
GetCurrentSelectionBuffer(sb);
}
sb = new StringBuilder(255 + 1);
GetCurrentSelectionNative(sb);
}).Wait();
return sb == null || sb.Length == 0 ? new string[0] : sb.ToString().Split('|');
return sb?.ToString() ?? string.Empty;
}
internal static string GetCurrentSelectionFirst()
internal enum FocusedWindowType
{
var files = GetCurrentSelection();
return files.Any() ? files.First() : string.Empty;
Invalid,
Desktop,
Explorer
}
}
}

View File

@@ -31,8 +31,9 @@
</Image>
<Grid Grid.Column="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="20" />
<ColumnDefinition Width="5" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="10" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="10" />
@@ -42,7 +43,11 @@
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock x:Name="filename" Grid.Row="1" Grid.Column="1" FontSize="19" FontWeight="SemiBold" Padding="3">Filename.ext</TextBlock>
<TextBlock x:Name="filename" Grid.Row="1" Grid.Column="1" FontSize="19" FontWeight="SemiBold" Padding="3"
TextWrapping="Wrap"
LineHeight="25" MaxHeight="60" TextTrimming="CharacterEllipsis">
FilenameFilenameFilenameFilenameFilenameFilenameFilenameFilenameFilenameFilename.ext
</TextBlock>
<TextBlock x:Name="modDate" Grid.Row="3" Grid.Column="1" Padding="3">Last modified at 01/01/2017 00:00:00</TextBlock>
<TextBlock x:Name="totalSize" Grid.Row="4" Grid.Column="1" Padding="3">Calculating size...</TextBlock>
</Grid>

View File

@@ -116,7 +116,7 @@
<Compile Include="NativeMethods\Shell32\IWshShortcut.cs" />
<Compile Include="NativeMethods\Shell32\ShellLink.cs" />
<Compile Include="NativeMethods\Shell32\WshShell.cs" />
<Compile Include="PidHelper.cs" />
<Compile Include="Helpers\PidHelper.cs" />
<Compile Include="PluginManager.cs" />
<Compile Include="Plugin\InfoPanel\DpiHelpers.cs" />
<Compile Include="Plugin\InfoPanel\Extensions.cs" />

View File

@@ -3,7 +3,6 @@ using System.Diagnostics;
using System.Windows.Forms;
using QuickLook.Helpers;
using QuickLook.Properties;
using Application = System.Windows.Application;
namespace QuickLook
{
@@ -26,14 +25,17 @@ namespace QuickLook
{
_icon = new NotifyIcon
{
Text = $"QuickLook v{Application.ProductVersion}",
Icon = Resources.app,
Visible = true,
ContextMenu = new ContextMenu(new[]
{
new MenuItem($"Check for &Updates ({System.Windows.Forms.Application.ProductVersion})",
new MenuItem($"v{Application.ProductVersion}") {Enabled = false},
new MenuItem("-"),
new MenuItem("Check for &Updates...",
(sender, e) => Process.Start(@"http://pooi.moe/QuickLook/")),
_itemAutorun,
new MenuItem("&Quit", (sender, e) => Application.Current.Shutdown())
new MenuItem("&Quit", (sender, e) => System.Windows.Application.Current.Shutdown())
})
};

View File

@@ -9,13 +9,14 @@ using QuickLook.Plugin;
namespace QuickLook
{
internal class ViewWindowManager
internal class ViewWindowManager : IDisposable
{
private static ViewWindowManager _instance;
private readonly MainWindowNoTransparent _viewWindowNoTransparent;
private readonly MainWindowTransparent _viewWindowTransparentTransparent;
private MainWindowTransparent _currentMainWindow;
private long _lastSwitchTick;
private string _path = string.Empty;
@@ -27,10 +28,13 @@ namespace QuickLook
_currentMainWindow = _viewWindowTransparentTransparent;
}
public void Dispose()
{
StopFocusMonitor();
}
internal void InvokeRoutine(KeyEventArgs kea)
{
Debug.WriteLine(kea.KeyCode);
switch (kea.KeyCode)
{
case Keys.Up:
@@ -53,22 +57,29 @@ namespace QuickLook
}
}
private void RunAndClosePreview(KeyEventArgs kea = null)
internal void RunAndClosePreview(KeyEventArgs kea = null)
{
if (!WindowHelper.IsFocusedControlExplorerItem() && !WindowHelper.IsFocusedWindowSelf())
if (NativeMethods.QuickLook.GetFocusedWindowType() ==
NativeMethods.QuickLook.FocusedWindowType.Invalid)
if (!WindowHelper.IsForegroundWindowBelongToSelf())
return;
if (_currentMainWindow.Visibility != Visibility.Visible)
return;
StopFocusMonitor();
_currentMainWindow.RunAndClose();
_currentMainWindow.RunAndHide();
if (kea != null)
kea.Handled = true;
}
internal void ClosePreview(KeyEventArgs kea = null)
{
if (NativeMethods.QuickLook.GetFocusedWindowType() ==
NativeMethods.QuickLook.FocusedWindowType.Invalid)
if (!WindowHelper.IsForegroundWindowBelongToSelf())
return;
StopFocusMonitor();
_currentMainWindow.BeginHide();
@@ -78,7 +89,11 @@ namespace QuickLook
private void TogglePreview(KeyEventArgs kea = null)
{
if (!WindowHelper.IsFocusedControlExplorerItem() && !WindowHelper.IsFocusedWindowSelf())
_lastSwitchTick = DateTime.Now.Ticks;
if (NativeMethods.QuickLook.GetFocusedWindowType() ==
NativeMethods.QuickLook.FocusedWindowType.Invalid)
if (!WindowHelper.IsForegroundWindowBelongToSelf())
return;
if (_currentMainWindow.Visibility == Visibility.Visible)
@@ -87,7 +102,7 @@ namespace QuickLook
}
else
{
_path = NativeMethods.QuickLook.GetCurrentSelectionFirst();
_path = NativeMethods.QuickLook.GetCurrentSelection();
InvokeViewer();
}
if (kea != null)
@@ -99,38 +114,34 @@ namespace QuickLook
if (_currentMainWindow.Visibility != Visibility.Visible)
return;
if (!WindowHelper.IsFocusedControlExplorerItem())
_lastSwitchTick = DateTime.Now.Ticks;
if (NativeMethods.QuickLook.GetFocusedWindowType() ==
NativeMethods.QuickLook.FocusedWindowType.Invalid)
return;
_path = NativeMethods.QuickLook.GetCurrentSelectionFirst();
_path = NativeMethods.QuickLook.GetCurrentSelection();
InvokeViewer();
if (kea != null)
kea.Handled = false;
}
private void SwitchPreviewRemoteInvoke(FocusedItemChangedEventArgs e)
private void SwitchPreviewRemoteInvoke(HeartbeatEventArgs e)
{
Debug.WriteLine("SwitchPreviewRemoteInvoke");
// sleep for 1.5s
if (e.InvokeTick - _lastSwitchTick < 1.5 * TimeSpan.TicksPerSecond)
return;
if (e.FocusedFile == _path)
return;
Debug.WriteLine("SwitchPreviewRemoteInvoke:" + (e.InvokeTick - _lastSwitchTick));
if (string.IsNullOrEmpty(e.FocusedFile))
return;
_currentMainWindow?.Dispatcher.Invoke(() =>
{
if (_currentMainWindow.Visibility != Visibility.Visible)
return;
if (!WindowHelper.IsFocusedControlExplorerItem())
return;
_path = NativeMethods.QuickLook.GetCurrentSelectionFirst();
InvokeViewer();
});
_currentMainWindow?.Dispatcher.Invoke(() => SwitchPreview());
}
private void RunFocusMonitor()
@@ -138,7 +149,7 @@ namespace QuickLook
if (!FocusMonitor.GetInstance().IsRunning)
{
FocusMonitor.GetInstance().Start();
FocusMonitor.GetInstance().FocusedItemChanged += SwitchPreviewRemoteInvoke;
FocusMonitor.GetInstance().Heartbeat += SwitchPreviewRemoteInvoke;
}
}
@@ -147,7 +158,7 @@ namespace QuickLook
if (FocusMonitor.GetInstance().IsRunning)
{
FocusMonitor.GetInstance().Stop();
FocusMonitor.GetInstance().FocusedItemChanged -= SwitchPreviewRemoteInvoke;
FocusMonitor.GetInstance().Heartbeat -= SwitchPreviewRemoteInvoke;
}
}