Currently I'm developing a project that needs to show a preview image of all opened process and display it on a grid.
Exactly like Microsoft Teams shows when you try to select a window to be shared.
So far I've achive the following design
Which is mounted using the following code:
private void CreateOpenedWindowsMenuItems(IEnumerable<CapturableWindow> openedWindows)
{
var dataGridRowNumber = 0;
var dataGridRowColumnNumber = 0;
CreateNewRowDefinition();
foreach (var openedWindow in openedWindows)
{
if (dataGridRowColumnNumber == MaxItemsPerRow)
dataGridRowColumnNumber = AddNewRowToGrid(ref dataGridRowNumber);
var openedWindowCard = CreateCard(CardSize);
var selectItemCheckbox = new CheckBox { IsEnabled = false, Margin = new Thickness(5,0,0,0)};
var openedWindowCardStackPanel = CreateStackPanel(openedWindow, selectItemCheckbox);
openedWindowCard.Content = openedWindowCardStackPanel;
openedWindowCard.MouseLeftButtonDown += (sender, args) =>
{
if (selectItemCheckbox.IsChecked == true)
_capturedWindows.Remove(openedWindow);
else
_capturedWindows.Add(openedWindow);
selectItemCheckbox.IsChecked = !selectItemCheckbox.IsChecked;
};
Grid.SetRow(openedWindowCard, dataGridRowNumber);
Grid.SetColumn(openedWindowCard, dataGridRowColumnNumber);
AvailableCapturableWindows.Children.Add(openedWindowCard);
dataGridRowColumnNumber++;
}
}
private StackPanel CreateStackPanel(CapturableWindow window, CheckBox selectItemCheckbox)
{
var stackPanel = new StackPanel();
var textStackPanel = new StackPanel { Orientation = Orientation.Horizontal };
textStackPanel.Children.Add(new TextBlock
{
Text = $"{window.Name.Substring(0, 25)}...",
TextWrapping = TextWrapping.NoWrap,
TextAlignment = TextAlignment.Center,
FontSize = 10,
FontWeight = FontWeights.Bold,
Foreground = new SolidColorBrush(Colors.White),
});
textStackPanel.Children.Add(selectItemCheckbox);
stackPanel.Children.Add(textStackPanel);
var previewImage = CreatePreviewImage(window.Handle);
if (previewImage != null) stackPanel.Children.Add(previewImage);
return stackPanel;
}
private UIElement CreatePreviewImage(IntPtr hWnd)
{
try
{
var handle = hWnd;
if (!NativeMethods.IsWindow(handle))
return null;
var hdcSrc = NativeMethods.GetWindowDC(handle);
NativeMethods.GetWindowRect(handle, out var windowRect);
var width = windowRect.Right - windowRect.Left;
var height = windowRect.Bottom - windowRect.Top;
var hdcDest = NativeMethods.CreateCompatibleDC(hdcSrc);
var hBitmap = NativeMethods.CreateCompatibleBitmap(hdcSrc, width, height);
var hOld = NativeMethods.SelectObject(hdcDest, hBitmap);
var bRet = NativeMethods.BitBlt(hdcDest, 0, 0, width, height, hdcSrc, 0, 0, NativeMethods.SRCCOPY);
NativeMethods.SelectObject(hdcDest, hOld);
NativeMethods.DeleteDC(hdcDest);
NativeMethods.ReleaseDC(handle, hdcSrc);
var imageSource = Imaging.CreateBitmapSourceFromHBitmap(
hBitmap,
IntPtr.Zero,
Int32Rect.Empty,
BitmapSizeOptions.FromEmptyOptions());
return new Image { Source = imageSource, VerticalAlignment = VerticalAlignment.Center, HorizontalAlignment = HorizontalAlignment.Center };
}
catch (Exception)
{
return new PackIcon { Kind = PackIconKind.Image };
}
}
private static Card CreateCard(int cardSize)
{
var card = new Card
{
Width = cardSize,
Height = cardSize,
VerticalAlignment = VerticalAlignment.Center,
HorizontalContentAlignment = HorizontalAlignment.Center,
Margin = new Thickness(10),
Cursor = Cursors.Hand
};
card.MouseEnter += (sender, args) =>
{
card.Width = CardSizeHovered;
card.Height = CardSizeHovered;
};
card.MouseLeave += (sender, args) =>
{
card.Width = cardSize;
card.Height = cardSize;
};
return card;
}
private int AddNewRowToGrid(ref int dataGridRowNumber)
{
dataGridRowNumber++;
CreateNewRowDefinition();
return InitialColumnItemNumber;
}
private void CreateNewRowDefinition()
{
AvailableCapturableWindows.RowDefinitions.Add(new RowDefinition { Height = new GridLength(256) });
}
I also have a NativeMethods Class:
public static class NativeMethods
{
public const int SRCCOPY = 0x00CC0020;
[DllImport("user32.dll")]
public static extern bool PrintWindow(IntPtr hwnd, IntPtr hdcBlt, int nFlags);
[DllImport("gdi32.dll")]
public static extern bool DeleteObject(IntPtr hObject);
[DllImport("gdi32.dll")]
public static extern IntPtr CreateCompatibleDC(IntPtr hdc);
[DllImport("gdi32.dll")]
public static extern IntPtr CreateCompatibleBitmap(IntPtr hdc, int nWidth, int nHeight);
[DllImport("gdi32.dll")]
public static extern IntPtr SelectObject(IntPtr hdc, IntPtr hg);
[DllImport("user32.dll")]
public static extern IntPtr GetWindowDC(IntPtr hwnd);
[DllImport("user32.dll")]
public static extern int ReleaseDC(IntPtr hwnd, IntPtr hdc);
[DllImport("gdi32.dll")]
public static extern bool DeleteDC(IntPtr hdc);
[DllImport("gdi32.dll")]
public static extern int BitBlt(IntPtr hdcDest, int xDest, int yDest, int wDest, int hDest, IntPtr hdcSource, int xSrc, int ySrc, int rop);
[DllImport("user32.dll")]
public static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool PrintWindow(IntPtr hwnd, IntPtr hDC, uint nFlags);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);
[DllImport("d3d11.dll", EntryPoint = "CreateDirect3D11DeviceFromDXGIDevice", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern uint CreateDirect3D11DeviceFromDXGIDevice(IntPtr dxgiDevice, out IntPtr graphicsDevice);
public delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool EnumWindows(EnumWindowsProc lpEnumFunc, IntPtr lParam);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern int GetWindowTextLength(IntPtr hWnd);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);
[DllImport("user32.dll")]
public static extern bool IsWindow(IntPtr hWnd);
[DllImport("user32.dll")]
public static extern bool IsWindowVisible(IntPtr hWnd);
[DllImport("user32.dll", SetLastError = true)]
public static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
public static IntPtr GetActiveWindow() => GetForegroundWindow();
[DllImport("CoreMessaging.dll", EntryPoint = "CreateDispatcherQueueController", SetLastError = true, CharSet = CharSet.Unicode,ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern uint CreateDispatcherQueueController(DispatcherQueueOptions options, out IntPtr dispatcherQueueController);
}
How can i get the preview window image, and use It in my card element, after the window text name,based on IntPtr?