Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix ChromeWindow bug. #46

Open
wants to merge 7 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions samples/MetroRadiance.Showcase/MetroRadiance.Showcase.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,9 @@
<Compile Include="UI\BlurWindowSample.xaml.cs">
<DependentUpon>BlurWindowSample.xaml</DependentUpon>
</Compile>
<Compile Include="UI\ExternalChromeSamples.xaml.cs">
<DependentUpon>ExternalChromeSamples.xaml</DependentUpon>
</Compile>
<Compile Include="UI\ImmersiveColorSamples.xaml.cs">
<DependentUpon>ImmersiveColorSamples.xaml</DependentUpon>
</Compile>
Expand All @@ -111,6 +114,10 @@
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="UI\ExternalChromeSamples.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="UI\ImmersiveColorSamples.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
Expand Down
71 changes: 71 additions & 0 deletions samples/MetroRadiance.Showcase/UI/ExternalChromeSamples.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
<UserControl x:Class="MetroRadiance.Showcase.UI.ExternalChromeSamples"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignWidth="300"
d:DesignHeight="300">
<DockPanel>
<TextBlock DockPanel.Dock="Top"
Text="Windows"
FontFamily="Segoe UI Light"
FontSize="18"
Foreground="{DynamicResource ForegroundBrushKey}"
HorizontalAlignment="Center"
Margin="0,0,0,8" />
<StackPanel DockPanel.Dock="Bottom"
Orientation="Horizontal"
HorizontalAlignment="Right"
Margin="0,0,8,8">
<Button Margin="8,0,0,0"
Content="Refresh"
Width="100"
Height="30"
HorizontalAlignment="Left"
Click="HandleRefreshClicked" />
<Button Margin="8,0,0,0"
Content="Apply"
Width="100"
Height="30"
HorizontalAlignment="Left"
Click="HandleMetroChromeClicked" />
</StackPanel>
<ListView x:Name="WindowsListView"
Margin="8,0,8,8"
Background="Transparent"
BorderBrush="Transparent"
BorderThickness="0"
ItemsSource="{Binding}"
ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel IsItemsHost="True"
Margin="8,0,8,8" />
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.ItemTemplate>
<DataTemplate>
<DockPanel>
<Border DockPanel.Dock="Left"
Background="White">
<Image Width="32"
Height="32"
Source="{Binding Icon}" />
</Border>
<TextBlock Foreground="{DynamicResource SemiActiveForegroundBrushKey}"
Margin="12,4"
VerticalAlignment="Center"
TextTrimming="CharacterEllipsis">
<Run Foreground="{DynamicResource ActiveForegroundBrushKey}"
Text="{Binding Title}" />
<Run Text="(PID:" />
<Run Text="{Binding ProcessId, Mode=OneTime}" />
<Run Text=")" />
</TextBlock>
</DockPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</DockPanel>
</UserControl>
219 changes: 219 additions & 0 deletions samples/MetroRadiance.Showcase/UI/ExternalChromeSamples.xaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
using Livet;
using MetroRadiance.Chrome;
using MetroRadiance.Interop.Win32;
using MetroRadiance.Platform;
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Media.Imaging;

namespace MetroRadiance.Showcase.UI
{
public partial class ExternalChromeSamples
{
private WindowChrome _metroChrome;

public ExternalChromeSamples()
{
this.InitializeComponent();

this.DataContext = GetWindowViewModels();
}

private void HandleMetroChromeClicked(object sender, RoutedEventArgs e)
{
var viewModel = (WindowViewModel)this.WindowsListView.SelectedItem;
if (viewModel == null) return;

var externalWindow = new ExternalWindow(viewModel.Handle);
if (this._metroChrome == null)
{
this._metroChrome = new WindowChrome();
}
this._metroChrome.Attach(externalWindow);
}

private void HandleRefreshClicked(object sender, RoutedEventArgs e)
{
this.DataContext = GetWindowViewModels();
}

private static WindowViewModel[] GetWindowViewModels()
{
var currentProcess = Process.GetCurrentProcess();
var windows = NativeMethods.GetWindows()
.Where(IsValidWindow)
.Select(hWnd =>
{
uint pid;
NativeMethods.GetWindowThreadProcessId(hWnd, out pid);

var process = Process.GetProcessById((int)pid);
return Tuple.Create(process, hWnd);
})
.Where(tuple => tuple.Item1.Id != currentProcess.Id);
var viewModels = windows.Select(tuple => new WindowViewModel(tuple.Item1, tuple.Item2));
return viewModels.ToArray();
}

private static bool IsValidWindow(IntPtr hWnd)
{
// ウィンドウハンドルであるか
if (!User32.IsWindow(hWnd)) return false;

// 見えるか
if (!User32.IsWindowVisible(hWnd)) return false;

// シェル ウィンドウでないか
if (NativeMethods.GetShellWindow() == hWnd) return false;

// 親ウィンドウであるか
if (NativeMethods.GetAncestor(hWnd, 2 /* GA_ROOT */) != hWnd) return false;

// 見えないウィンドウでないか
if (Dwmapi.DwmGetCloaked(hWnd)) return false;

return true;
}

internal static class NativeMethods
{
public delegate bool EnumWindowsCallback(IntPtr hWnd, int lParam);

[DllImport("user32.dll", ExactSpelling = true, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool EnumWindows(EnumWindowsCallback lpEnumFunc, IntPtr lParam);

public static IntPtr[] GetWindows()
{
var windows = new Collection<IntPtr>();
var ret = EnumWindows((hWnd, _) =>
{
windows.Add(hWnd);
return true;
}, IntPtr.Zero);
if (!ret) throw new Win32Exception(Marshal.GetLastWin32Error());
return windows.ToArray();
}

[DllImport("user32.dll", SetLastError = true)]
public static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);

[DllImport("user32.dll", ExactSpelling = true)]
public static extern IntPtr GetShellWindow();

[DllImport("user32.dll", ExactSpelling = true)]
public static extern IntPtr GetAncestor(IntPtr hwnd, uint flags);
}
}

public class WindowViewModel : ViewModel
{
public int ProcessId { get; }

public IntPtr Handle { get; }

#region Title 変更通知プロパティ

private string _Title;

public string Title
{
get { return this._Title; }
set
{
if (this._Title != value)
{
this._Title = value;
this.RaisePropertyChanged();
}
}
}

#endregion

#region Icon 変更通知プロパティ

private ImageSource _Icon;

public ImageSource Icon
{
get { return this._Icon; }
set
{
if (this._Icon != value)
{
this._Icon = value;
this.RaisePropertyChanged();
}
}
}

#endregion

public WindowViewModel(Process process, IntPtr hWnd)
{
this.ProcessId = process.Id;
this.Handle = hWnd;
this.Update();
}

public void Update()
{
try
{
var title = NativeMethods.GetWindowText(this.Handle);
if (string.IsNullOrWhiteSpace(title))
{
title = "(No title)";
}
this.Title = title;

var hIcon = User32.GetClassLong(this.Handle, ClassLongPtrIndex.GCLP_HICON);
this.Icon = hIcon != IntPtr.Zero
? Imaging.CreateBitmapSourceFromHIcon(hIcon, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions())
: null;
}
catch (Win32Exception) { }
}

private static class NativeMethods
{
[DllImport("user32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern int GetWindowTextLengthW(IntPtr hWnd);

[DllImport("user32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern int GetWindowTextW(IntPtr hWnd, StringBuilder lpString, int nMaxCount);

public static string GetWindowText(IntPtr hWnd)
{
var length = GetWindowTextLengthW(hWnd);
if (length == 0)
{
var err = Marshal.GetLastWin32Error();
if (err != 0)
{
throw new Win32Exception(err);
}
else
{
return string.Empty;
}
}

var builder = new StringBuilder(length);
var ret = GetWindowTextW(hWnd, builder, length + 1);
if (ret == 0) throw new Win32Exception(Marshal.GetLastWin32Error());

return builder.ToString();
}
}
}
}
20 changes: 20 additions & 0 deletions samples/MetroRadiance.Showcase/UI/MainWindow.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,17 @@

<chrome:WindowChrome.Instance>
<chrome:WindowChrome x:Name="WindowChrome">
<chrome:WindowChrome.Left>
<Border Background="DarkBlue"
Padding="24,3"
VerticalAlignment="Bottom">
<Border.LayoutTransform>
<RotateTransform Angle="90" />
</Border.LayoutTransform>
<TextBlock Text="UI element on Left"
Foreground="White" />
</Border>
</chrome:WindowChrome.Left>
<chrome:WindowChrome.Top>
<Border Background="DarkRed"
Padding="24,3"
Expand Down Expand Up @@ -192,6 +203,15 @@

<ui:ControlSamples />
</TabItem>

<TabItem>
<TabItem.Header>
<TextBlock Text="External Chrome"
Style="{StaticResource TabHeaderTextStyleKey}" />
</TabItem.Header>

<ui:ExternalChromeSamples />
</TabItem>
</TabControl>

<Grid Grid.Row="2"
Expand Down
Loading