使用P / Invoke更改窗口透明度

时间:2016-11-30 11:09:16

标签: c# wpf unity3d pinvoke

我在更改窗口的透明度方面遇到了问题。

我正在努力实现的目标

我开发了一个WPF应用程序,它与另一个应用程序(在Unity3D中开发的游戏)有一些交互。我的目标是将游戏“集成”到我的WPF应用程序中,使其看起来像游戏是WPF应用程序的自然组成部分。因此,当我移动主窗口时,我也使用PInvoke移动游戏窗口,我使用PInvoke来隐藏游戏窗口的窗口边界等。这一切都很有效。

然而,当我试图隐藏游戏而不关闭游戏时会出现问题。我的第一种方法是使用PInvoke将游戏窗口设置为隐藏:

[DllImport("user32.dll")]
static extern bool ShowWindow(IntPtr hwnd, int show);

const int SW_HIDE = 0;
const int SW_Show = 5;

ShowWindow(Handle, SW_HIDE);

使用此函数调用窗口会消失,但结果是游戏进程的CPU使用率从1%跃升至20%。到目前为止,我不知道为什么会这样。也许它与Unity有关,也许不是。 (但是当我再次显示窗口时CPU恢复正常)。

我的第二种方法不是使用ShowWindow调用隐藏窗口,而是将窗口的不透明度设置为0(as suggested in this thread)。在我的设置,这工作得很好(没有CPU疯狂),但在其他设置,窗口将保持可见。

更新图形驱动程序有时会解决问题,但并非总能如此。我有一台老式的Vista机器,一切正常,我也在安装了Windows 10的新款戴尔笔记本电脑上尝试过,它不起作用。我在使用Windows 10和Boot Camp的Mac上没有这个问题。所以我不知道是什么导致了这个问题。

有没有人遇到过类似的问题?有没有其他方法来隐藏窗口或有人知道为什么CPU在使用ShowWindow()方法时会发疯?

非常感谢任何提示。

修改

很高兴知道为什么这篇文章被大量投票,但没关系。我认为特别是CPU使用情况是一个有趣的问题,如果有人认为这很明显而且我是个白痴,我会非常抱歉。

对于那些也感兴趣的人来说,这是我的问题的最小WPF重建:

MainWindow.xaml

<Window x:Class="SampleWpfApp.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="1024" Width="1280"
    KeyDown="MainWindow_OnKeyDown">
<Grid>
</Grid>
</Window>

MainWindow.xaml.cs

public partial class MainWindow : Window
{
    const int SW_HIDE = 0;
    const int SW_SHOW = 5;

    private Process gameProcess;
    private IntPtr gameWindowHandle;

    private bool windowHidden = false;

    public MainWindow()
    {
        InitializeComponent();

        this.SizeChanged += OnSizeChanged;
    }

    private void OnSizeChanged(object sender, SizeChangedEventArgs e)
    {
        StartGame();
    }

    private void MainWindow_OnKeyDown(object sender, KeyEventArgs e)
    {
        if (e.Key == Key.Space)
        {
            if (windowHidden)
            {
                NativeMethods.ShowWindow(gameWindowHandle, SW_HIDE);
                windowHidden = false;
            }
            else
            {
                NativeMethods.ShowWindow(gameWindowHandle, SW_SHOW);
                windowHidden = true;
            }
        }
    }

    private void StartGame()
    {
        var mainWindowHandle = new  WindowInteropHelper(this).Handle;
        var processStartInfo = new ProcessStartInfo(@"Path\To\SampleUnityApp.exe");
        processStartInfo.Arguments += "-parentHWND " + mainWindowHandle.ToInt32() + " " + Environment.CommandLine + " ";
        processStartInfo.CreateNoWindow = true;
        processStartInfo.UseShellExecute = false;

        gameProcess = Process.Start(processStartInfo);
        gameProcess.WaitForInputIdle();

        NativeMethods.EnumChildWindows(mainWindowHandle,
            (hwnd, lparam) =>
            {
                // Set the window handle of the game
                gameWindowHandle = hwnd;
                return 0;
            }, IntPtr.Zero);
    }

    static class NativeMethods
    {

        [DllImport("user32.dll")]
        internal static extern bool ShowWindow(IntPtr hwnd, int show);

        [DllImport("user32.dll")]
        internal static extern bool EnumChildWindows(IntPtr hwnd, WindowEnumProc func, IntPtr lParam);

        internal delegate int WindowEnumProc(IntPtr hwnd, IntPtr lparam);
    }
}

我使用的SampleUnityApp只是一个带有主摄像头的空白Unity项目。没有其他游戏对象。我写的没有代码。它是使用Unity 5.3.4f1 Personal创建的。

可见窗口的TaskManager的屏幕截图 When window is visible

隐藏窗口的TaskManager的屏幕截图 enter image description here

0 个答案:

没有答案