在预览模式下使用WPF崩溃的C#中的Windows屏幕保护程序

时间:2017-05-04 20:59:32

标签: c# wpf windows screensaver

我刚刚开始学习C#并且正在尝试编写屏幕保护程序。我的App.xaml.cs包含以下用于何时使用/ p参数的代码:

else if (arg1 == "/p")
            {
                if (e.Args[1] == null)
                {
                    System.Windows.Forms.MessageBox.Show("Invalid or missing window handle.");
                    System.Windows.Application.Current.Shutdown();
                }
                IntPtr previewHandle = new IntPtr(long.Parse(e.Args[1]));
                System.Windows.Application.Current.Run(new MainWindow(previewHandle));
            }

然后在我的MainWindow.xaml.cs中,此构造处理预览调用:

public MainWindow(IntPtr previewHandle)
    {
        App.Current.Properties["isPreviewMode"] = true;
        App.Current.Properties["previewHandle"] = previewHandle;
        InitializeComponent();
    }

在此之后,它崩溃了。在我的MainWindow.xaml中,我有Loaded =" MainWindow_Loaded"。

在MainWindows.xaml.cs中,这是MainWindow_Loaded:

private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
        if ((bool)App.Current.Properties["isPreviewMode"])
        {
            IntPtr myHandle = new WindowInteropHelper(this).Handle;
            SetParent(myHandle, (IntPtr)App.Current.Properties["previewHandle"]);
            SetWindowLong(myHandle, -16, new IntPtr(GetWindowLong(myHandle, -16) | 0x40000000));
            Rectangle ParentRect;
            GetClientRect((IntPtr)App.Current.Properties["previewHandle"], out ParentRect);
            this.Top = ParentRect.X;
            this.Left = ParentRect.Y;
            this.Height = ParentRect.Height;
            this.Width = ParentRect.Width;
        }
        ssimage.Source = new BitmapImage(new Uri("pack://application:,,,/Resources/EmbeddedImage.PNG"));
}
[DllImport("user32.dll")]
static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);

[DllImport("user32.dll")]
static extern int SetWindowLong(IntPtr hWnd, int nIndex, IntPtr dwNewLong);

[DllImport("user32.dll", SetLastError = true)]
static extern int GetWindowLong(IntPtr hWnd, int nIndex);

[DllImport("user32.dll")]
static extern bool GetClientRect(IntPtr hWnd, out Rectangle lpRect);

我在App.xaml.cs中有其他代码来处理更改计时器上的图像以及MainWindow.xaml.cs中的其他代码来处理鼠标移动,点击和按键。正常运行屏幕保护程序时一切正常。只是预览失败了。我做错了什么?

2 个答案:

答案 0 :(得分:0)

据我所知,WPF不允许您重新定位窗口句柄,因此使用您的技术在WPF中执行屏幕保护程序预览是不可能的。

但是,有一种解决方法:如果您将WPF配置为渲染到位图目标(请参阅RenderTargetBitmap),则可以将该位图blit到所需的目标窗口句柄上 - 但这将涉及到unholy混合GDI和WPF可能具有糟糕的运行时性能;我怀疑这是值得的。

答案 1 :(得分:0)

我最终做的是使用WPF窗口显示屏幕保护程序在全屏运行时使用/ s。我创建了一个新的常规Windows窗体previewForm.cs,其中包含一个用于预览的图片框。这很好,并没有性能问题。我认为图片框正在使用GDI。

这是我修改后的App.xaml.cs,用于处理/ p参数:

else if (arg1 == "/p")
            {
                if (e.Args[1] == null)
                {
                    System.Windows.Forms.MessageBox.Show("Invalid or missing window handle.");
                    System.Windows.Application.Current.Shutdown();
                }
                IntPtr previewHandle = new IntPtr(long.Parse(e.Args[1]));
                pw = new previewForm(previewHandle);
                GetImages();
                pw.Show();
            }

和我的previewForm.cs构造来处理预览:

public previewForm(IntPtr previewHandle)
    {
        InitializeComponent();
        IntPtr myHandle = this.Handle;
        SetParent(myHandle, previewHandle);
        SetWindowLong(myHandle, -16, new IntPtr(GetWindowLong(myHandle, -16) | 0x40000000));
        Rectangle ParentRect;
        GetClientRect(previewHandle, out ParentRect);
        this.Size = ParentRect.Size;
        this.pictureBox1.Size = ParentRect.Size;
        this.Location = new Point(0, 0);
    }

所以我使用了WPF表单和常规窗体的混合来实现这一目标。而且表现还不错。仅使用14-18MB的RAM,几乎没有CPU。