0

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

enter image description here 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?

Vinicius Andrade
  • 151
  • 1
  • 4
  • 22

1 Answers1

0

After some while

My SelectCapturableWindowClass working code:

public partial class SelectCapturableWindows : Window
{
    public const int InitialColumnItemNumber = 0;
    public const int MaxItemsPerRow = 3;
    public const int CardSize = 192;
    public const int CardSizeHovered = 202;
    public const int StackPanelTitleMaxLength = 25;
    private readonly IWindowsProcessServices _windowsProcessServices;
    private readonly ICapturableWindowsMonitoringService _capturableWindowsMonitoringService;
    private readonly WindowCaptureService _windowCaptureService;
    private ObservableCollection<CapturableWindow> _capturedWindows;

    public SelectCapturableWindows(IWindowsProcessServices windowsProcessServices,
        ICapturableWindowsMonitoringService capturableWindowsMonitoringService,
        WindowCaptureService windowCaptureService
        , ObservableCollection<CapturableWindow> capturedWindows = null
        )
    {
        _windowsProcessServices = windowsProcessServices;
        _capturableWindowsMonitoringService = capturableWindowsMonitoringService;
        _windowCaptureService = windowCaptureService;
        _capturedWindows = capturedWindows ?? new ObservableCollection<CapturableWindow>();
        InitializeComponent();
    }

    public void Pick(params Window[] ignoredWindows)
    {
        var ignoredWindowsWithMe = ignoredWindows?.Append(this)?.ToArray() ?? new Window[]{this};
         
        CreateOpenedWindowsMenuItems(_windowsProcessServices.GetOpenedWindows(ignoredWindowsWithMe));
        Show();
    }

    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 isMonitored = _capturableWindowsMonitoringService.IsMonitored(openedWindow.Handle);
            var openedWindowCard = CreateCard(CardSize);
            var selectItemCheckbox = new CheckBox { IsEnabled = false, Margin = new Thickness(5, 0, 0, 0), IsChecked = isMonitored };
            var openedWindowCardStackPanel = CreateStackPanel(openedWindow, selectItemCheckbox);
            openedWindowCard.Content = openedWindowCardStackPanel;
            openedWindowCard.MouseLeftButtonDown += (sender, args) =>
            {
                isMonitored = _capturableWindowsMonitoringService.IsMonitored(openedWindow.Handle);
                if (_capturedWindows.Contains(openedWindow))
                    _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 };
        var stackPanelTitleMaxLength = WindowNameTitleMaxLengthExceedsLimits(window)
            ? StackPanelTitleMaxLength
            : window.Name.Length;
        textStackPanel.Children.Add(CreateStackPanelTitle(window, stackPanelTitleMaxLength));
        textStackPanel.Children.Add(selectItemCheckbox);
        stackPanel.Children.Add(textStackPanel);
        var previewImage = CreatePreviewImage(window.Handle);
        if (previewImage != null) stackPanel.Children.Add(previewImage);


        return stackPanel;
    }

    private static TextBlock CreateStackPanelTitle(CapturableWindow window, int stackPanelTitleMaxLength)
    {
        return new TextBlock
        {
            Text = $"{window.Name.Substring(0, stackPanelTitleMaxLength)}...",
            TextWrapping = TextWrapping.NoWrap,
            TextAlignment = TextAlignment.Center,
            FontSize = 10,
            FontWeight = FontWeights.Bold,
            Foreground = new System.Windows.Media.SolidColorBrush(Colors.White),

        };
    }

    private static bool WindowNameTitleMaxLengthExceedsLimits(CapturableWindow window)
    {
        return window.Name.Length > StackPanelTitleMaxLength;
    }

    private UIElement CreatePreviewImage(IntPtr hWnd)
    {
        var grid = new Grid();
        
        grid.RowDefinitions.Add(new RowDefinition{Height = GridLength.Auto});
        grid.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto });
        grid.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto });

        NativeMethods.GetWindowRect(hWnd, out var rect);
        var width = rect.Right - rect.Left;
        var height = rect.Bottom - rect.Top;
        var bmp = new Bitmap(width, height, PixelFormat.Format32bppArgb);
        using (var graphics = Graphics.FromImage(bmp))
            graphics.CopyFromScreen(rect.Left, rect.Top, 0, 0, new System.Drawing.Size(width, height), CopyPixelOperation.SourceCopy);
        var memoryStream = new MemoryStream();
        bmp.Save(memoryStream, ImageFormat.Png);
        var image = new Image
        {
            Margin = new Thickness(10),
            Source = BitmapFrame.Create(memoryStream, BitmapCreateOptions.None, BitmapCacheOption.OnLoad),
            Width = 192,
            Height = 108,
            Stretch = Stretch.UniformToFill
        };
        
        Grid.SetRow(image,1);
        grid.Children.Add(image);
        return grid;
    }
    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) });
    }

    private void CancellButton_MouseLeftButtonDown(object sender, RoutedEventArgs routedEventArgs)
    {
        Close();
    }

    private void Apply_MouseLeftButtonDown(object sender, RoutedEventArgs e)
    {
        foreach (var openedWindow in _capturedWindows)
        {
            _windowCaptureService.StopCapture();
            if (_capturableWindowsMonitoringService.IsMonitored(openedWindow.Handle))
                _capturableWindowsMonitoringService.RemoveMonitoringWindow(openedWindow.Handle);
            else
                _capturableWindowsMonitoringService.AddMonitoringWindow(openedWindow);
            _capturableWindowsMonitoringService.FocusFirstMonitoringWindow();
        }
        Close();
    }
}

And NativeMethodsHelper

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

}
Vinicius Andrade
  • 151
  • 1
  • 4
  • 22