为了便于调试,我在我的WPF应用程序中添加了一个控制台窗口,我可以在其中监视应用程序中的所有正在进行的事件。我还添加了一些很好的方法,可以自动将窗口移动到我的辅助屏幕,最大化它并将其不透明度设置为90%。
使用调试配置,它可以正常工作并且符合预期。但是一旦我使用发布配置,我就会发现一些奇怪的异常。使用此P / Invoke实现:
[DllImport("user32.dll", SetLastError = true)]
private static extern bool SetLayeredWindowAttributes(IntPtr hwnd, uint crKey, byte bAlpha, uint dwFlags);
public static void SetOpacity(byte alpha)
{
IntPtr handle = GetConsoleWindow();
if (handle == IntPtr.Zero) return;
Logging.Trace("Found console handle.");
Logging.Trace($"Setting console opacity to: {alpha}.");
if (!SetLayeredWindowAttributes(handle, 0, alpha, 0x2))
{
int error = Marshal.GetLastWin32Error();
Logging.Trace($"Return value: {error}");
if (error != 0)
throw new Win32Exception(error);
}
Logging.Trace("Set LW attributes.");
}
在没有记录的情况下运行它我回来了“ 87 :参数不正确”。当我添加日志时,我得到(很奇怪)“ 183 :当该文件已经存在时,无法创建文件。”
我真的不明白为什么会这样。为什么伐木会影响结果。为什么这可以使用调试配置。
答案 0 :(得分:1)
SetLayeredWindowAttributes()
仅适用于具有WS_EX_LAYERED
属性的窗口。有可能控制台窗口没有那种样式,这可以解释你所看到的错误87。因此,您必须事先使用SetWindowLongPtr()
设置样式,例如:
[DllImport("user32.dll", EntryPoint="GetWindowLong", SetLastError=true)]
private static extern IntPtr GetWindowLongPtr32(IntPtr hWnd, int nIndex);
[DllImport("user32.dll", EntryPoint="GetWindowLongPtr", SetLastError=true)]
private static extern IntPtr GetWindowLongPtr64(IntPtr hWnd, int nIndex);
[DllImport("user32.dll", EntryPoint="SetWindowLong", SetLastError=true)]
private static extern IntPtr SetWindowLongPtr32(IntPtr hWnd, int nIndex, IntPtr dwNewLong);
[DllImport("user32.dll", EntryPoint="SetWindowLongPtr", SetLastError=true)]
private static extern IntPtr SetWindowLongPtr64(IntPtr hWnd, int nIndex, IntPtr dwNewLong);
[DllImport("user32.dll", SetLastError=true)]
private static extern bool SetLayeredWindowAttributes(IntPtr hwnd, uint crKey, byte bAlpha, uint dwFlags);
[DllImport("kernel32.dll")]
static extern void SetLastError(uint dwErrorCode);
private static IntPtr GetWindowLongPtr(IntPtr hWnd, int nIndex)
{
if (IntPtr.Size == 8)
return GetWindowLongPtr64(hWnd, nIndex);
else
return GetWindowLongPtr32(hWnd, nIndex);
}
private static IntPtr SetWindowLongPtr(IntPtr hWnd, int nIndex, IntPtr dwNewLong)
{
if (IntPtr.Size == 8)
return SetWindowLongPtr64(hWnd, nIndex, dwNewLong);
else
return SetWindowLongPtr32(hWnd, nIndex, dwNewLong);
}
private const int GWL_EXSTYLE = -20;
private const int WS_EX_LAYERED = 0x00080000;
public static void SetOpacity(byte alpha)
{
if (alpha == byte.MaxValue)
{
MakeOpaque();
return;
}
IntPtr handle = GetConsoleWindow();
if (handle == IntPtr.Zero)
return;
Logging.Trace("Found console handle.");
int error;
SetLastError(0);
int winFlags = (int) GetWindowLongPtr(handle, GWL_EXSTYLE);
if (winFlags == 0)
{
error = Marshal.GetLastWin32Error();
if (error != 0)
{
Logging.Trace($"GetWindowLongPtr error: {error}");
throw new Win32Exception(error);
}
}
if ((winFlags & WS_EX_LAYERED) == 0)
{
Logging.Trace($"Setting console layered style.");
winFlags |= WS_EX_LAYERED;
SetLastError(0);
if (SetWindowLongPtr(handle, GWL_EXSTYLE, new IntPtr(winFlags)) == 0)
{
error = Marshal.GetLastWin32Error();
if (error != 0)
{
Logging.Trace($"SetWindowLongPtr error: {error}");
throw new Win32Exception(error);
}
}
}
Logging.Trace($"Setting console opacity to: {alpha}.");
if (!SetLayeredWindowAttributes(handle, 0, alpha, 0x2))
{
error = Marshal.GetLastWin32Error();
Logging.Trace($"SetLayeredWindowAttributes error: {error}");
throw new Win32Exception(error);
}
Logging.Trace("Set LW attributes.");
}
答案 1 :(得分:0)
经过大量研究后我发现SetLayeredWindowAttributes方法还有更多内容。我无法解释为什么在构建调试配置时这确实可以正常工作,但为了使其与发布配置一起工作,您需要首先使用SetWindowLongPtr增强窗口样式(您还需要GetWindowLongPtr )。 请注意,您应该使用带有后缀的方法' Ptr'因为只有那些适用于x86和x64 Windows版本。
[DllImport("user32.dll", EntryPoint = "SetWindowLong")]
private static extern int SetWindowLongPtr(HandleRef hWnd, int nIndex, int dwNewLong);
[DllImport("user32.dll", EntryPoint = "SetWindowLongPtr")]
private static extern IntPtr SetWindowLongPtr64(HandleRef hWnd, int nIndex, IntPtr dwNewLong);
[DllImport("user32.dll", EntryPoint = "GetWindowLong")]
private static extern IntPtr GetWindowLongPtr32(IntPtr hWnd, int nIndex);
[DllImport("user32.dll", EntryPoint = "GetWindowLongPtr")]
private static extern IntPtr GetWindowLongPtr64(IntPtr hWnd, int nIndex);
private const int GWL_EXSTYLE = -20;
private const int WS_EX_LAYERED = 0x00080000;
public static void SetOpacity(byte alpha)
{
if (alpha == byte.MaxValue)
{
MakeOpaque();
return;
}
IntPtr handle = GetConsoleWindow();
if (handle == IntPtr.Zero) return;
int error;
if (IntPtr.Size == 4) // x86
{
int winFlags = GetWindowLongPtr32(handle, GWL_EXSTYLE).ToInt32();
winFlags |= WS_EX_LAYERED;
if (SetWindowLongPtr(new HandleRef(Core.IDE, handle), GWL_EXSTYLE, winFlags) == 0)
{
error = Marshal.GetLastWin32Error();
throw new Win32Exception(error);
}
}
else // x64
{
long winFlags = GetWindowLongPtr64(handle, GWL_EXSTYLE).ToInt64();
winFlags |= WS_EX_LAYERED;
if (SetWindowLongPtr64(new HandleRef(Core.IDE, handle), GWL_EXSTYLE, new IntPtr(winFlags)).ToInt64() == 0)
{
error = Marshal.GetLastWin32Error();
throw new Win32Exception(error);
}
}
if (!SetLayeredWindowAttributes(handle, 0, alpha, 0x2))
{
error = Marshal.GetLastWin32Error();
Logging.Trace($"Return value: {error}");
if (error != 0)
throw new Win32Exception(error);
}
}
有了这一切,两种架构都能完美运行。简而言之,您可以在MSDN上找到该代码,您应该可以轻松地将其转换为C#。