我希望能够从任务栏隐藏另一个应用程序的窗口,而不隐藏窗口本身.具体来说,我希望在Alt + Tab列表中运行,可见,可用的几个不同的Web浏览器,但不占用任务栏上的空间.
(如果有人好奇为什么:我编写了一个仪表板应用程序,它使用Vista的DwmRegisterThumbnail API同时显示几个窗口的实时预览 - 如果你愿意的话,这是一种"画中画".此时,还有任务栏按钮对于那些窗口似乎是多余的.)
我知道将其他窗口的样式更改为include WS_EX_TOOLWINDOW会将其隐藏在任务栏中,我先尝试了.但是,正如预期的那样,它有一些我不想要的副作用:标题栏变得更短(不是很糟糕,我猜)并且最小化和最大化按钮消失了(不好).我还必须隐藏并重新显示窗口以使任务栏识别出更改,这会导致重新绘制工件,当我对IE窗口进行操作时.
我的下一个想法是,由于默认情况下窗口与所有者隐藏在任务栏中,也许我可以将其他窗口更改为我的所有权.但MSDN 非常清楚 "创建一个拥有的窗口,应用程序无法将窗口的所有权转移到另一个窗口."
我发现这个问题与我的问题类似,但它特别关注来自您自己的进程的窗口,您可以完全控制窗口所有权.
有没有人知道隐藏任务栏按钮的任何其他方法,这将适用于来自另一个进程的窗口?
更新: Tormod通过ITaskbarList让我走上正轨 - 它运行良好.pinvoke.net页面有一些错误(错误的GUID,按字母顺序而不是按接口顺序声明的方法),但我编辑了它,进行了更正,还添加了一个如何通过其coclass实例化ITaskbarList的示例.
更新2:如果您使用DeleteTab隐藏窗口的任务栏按钮,然后将其设置为活动窗口(例如,通过SetForegroundWindow或Alt + Tab),它的任务栏按钮将重新出现.为了保持任务栏按钮隐藏,我不得不添加一个计时器并继续调用DeleteTab.只要您不介意任务栏按钮在窗口聚焦时重新出现,这很有效.
我需要向C#公开一些C++类(我在Linux上构建,使用单声道,所以COM不是一个选项)
到目前为止我收集的证据表明,解决这个问题的最佳方法是:
我有以下问题:
我正在尝试在C#项目中使用C++非托管dll,并且在尝试调用一个无法找到入口点的函数时遇到错误.
public class Program
{
static void Main(string[] args)
{
IntPtr testIntPtr = aaeonAPIOpen(0);
Console.WriteLine(testIntPtr.ToString());
}
[DllImport("aonAPI.dll")]
public static extern unsafe IntPtr aaeonAPIOpen(uint reserved);
}
Run Code Online (Sandbox Code Playgroud)
这是函数的dumpbin:
5 4 00001020 ?aaeonAPIOpen@@YAPAXK@Z
Run Code Online (Sandbox Code Playgroud)
我改变了DLL进口[DllImport("aonAPI.dll", EntryPoint="?aaeonAPIOpen")]和[DllImport("aonAPI.dll", EntryPoint="_aaeonAPIOpen")]和没有运气.
首先是一个背景问题:
一般来说,int和之间有什么区别IntPtr?我的猜测是它是一个实际的对象,而不是像int或是一个值byte.假设是真的:
所以他们不一样.然而,我看到手柄代表两者.
Control.Handleint(或uint):PInvoke可以设置为返回一个int并且它可以正常工作:
[DllImport("coredll.dll", SetLastError = true)]
public static extern int GetForegroundWindow();
private string GetActiveWindow()
{
const int nChars = 256;
int handle = 0;
StringBuilder Buff = new StringBuilder(nChars);
handle = CoreDLL.GetForegroundWindow();
if (CoreDLL.GetWindowText(handle, Buff, nChars) > 0)
{
return Buff.ToString();
}
return "";
}
Run Code Online (Sandbox Code Playgroud)那么,intvs IntPtr?手柄有问题吗?你能用吗?
在尝试编写与此问题相关的自定义封送程序(P/Invoke从C到C#而不知道数组的大小)时,我遇到了一些我无法理解的问题.这是我写的第一个定制封送器,所以毫无疑问,由于我的无知,我错过了一些明显的东西.
这是我的C#代码:
using System;
using System.Runtime.InteropServices;
using System.Text;
namespace CustomMarshaler
{
public class MyCustomMarshaler : ICustomMarshaler
{
static MyCustomMarshaler static_instance;
public IntPtr MarshalManagedToNative(object managedObj)
{
if (managedObj == null)
return IntPtr.Zero;
if (!(managedObj is int[]))
throw new MarshalDirectiveException("VariableLengthArrayMarshaler must be used on an int array.");
int[] arr = (int[])managedObj;
int size = sizeof(int) + arr.Length * sizeof(int);
IntPtr pNativeData = Marshal.AllocHGlobal(size);
Marshal.WriteInt32(pNativeData, arr.Length);
Marshal.Copy(arr, 0, pNativeData + sizeof(int), arr.Length);
return pNativeData;
}
public object MarshalNativeToManaged(IntPtr pNativeData)
{
int …Run Code Online (Sandbox Code Playgroud) 我找到了一个使用Windows 的SetParent()函数在WPF中设置Excel实例的解决方案.
问题是,鼠标和键盘不会对工作表做出反应,而是对工作簿做出反应.
完整示例项目在此处下载
我也试过WindowsFormsHost,但它具有相同的效果.
XAML
<Window x:Class="ExcelEditor.SimpleWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:ExcelEditor"
mc:Ignorable="d" Loaded="Window_Loaded" Closing="Window_Closing"
Title="SimpleWindow" Height="450" Width="800">
<Grid x:Name="LayoutRoot">
</Grid>
Run Code Online (Sandbox Code Playgroud)
C#代码
using System;
using System.Windows;
namespace ExcelEditor
{
/// <summary>
/// Interaktionslogik für SimpleWindow.xaml
/// </summary>
public partial class SimpleWindow : Window
{
private Microsoft.Office.Interop.Excel.Application ExcelApplication;
public SimpleWindow()
{
InitializeComponent();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
System.Windows.Forms.Integration.ElementHost.EnableModelessKeyboardInterop(this); // <- testing only (no success)
ExcelApplication = new Microsoft.Office.Interop.Excel.Application();
ExcelApplication.DisplayAlerts = false;
System.Windows.Interop.HwndSource …Run Code Online (Sandbox Code Playgroud) 我想将键盘输入发送到另一个进程中的窗口,而不将该窗口带到前台.我可以PostMessage用来伪造WM_KEYDOWN和WM_KEYUP; 我需要知道的是哪个窗口句柄应该接收键盘输入 - 即类似GetFocus,但是对于另一个非活动应用程序.
该GetGUIThreadInfo API看起来很有希望-它返回hwndFocus另一个应用程序.但我没有运气在我的64位操作系统上使用C#工作.我已经复制(然后进一步调整)来自pinvoke.net的声明,但我所得到的只是一般错误代码(下面有更多详细信息).
我在调用GetGUIThreadInfo之前设置了cbSize,所以我避免了最明显的潜在问题.
我正在运行64位Vista,所以我不知道问题是我没有正确使用API,还是64位工作方式不同 - 我还没找到具体的代码示例说它在Win64中成功运行.
这是示例代码.我按照建议使用GetWindowThreadProcessId ,所以我不认为问题与将线程ID与线程句柄混合有关:
[StructLayout(LayoutKind.Sequential)]
internal struct Rect
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}
[StructLayout(LayoutKind.Sequential)]
internal class GuiThreadInfo
{
public int cbSize;
public uint flags;
public IntPtr hwndActive;
public IntPtr hwndFocus;
public IntPtr hwndCapture;
public IntPtr hwndMenuOwner;
public IntPtr hwndMoveSize;
public IntPtr hwndCaret;
public Rect rcCaret;
}
[DllImport("user32.dll")]
internal … 我的应用程序启动了另一个外部应用
我想在启动后删除此外部应用程序的标题栏.
这是可行的,如果是这样的话怎么办?
根据评论,我使用下面的工作代码
//Finds a window by class name
[DllImport("USER32.DLL")]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
//Sets a window to be a child window of another window
[DllImport("USER32.DLL")]
public static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
//Sets window attributes
[DllImport("USER32.DLL")]
public static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
//Gets window attributes
[DllImport("USER32.DLL")]
public static extern int GetWindowLong(IntPtr hWnd, int nIndex);
[DllImport("user32.dll", EntryPoint = "FindWindow", SetLastError = true)]
static extern IntPtr FindWindowByCaption(IntPtr ZeroOnly, string lpWindowName);
//assorted …Run Code Online (Sandbox Code Playgroud) 我想P/Invoke到GetWindowLongPtr和SetWindowLongPtr,我看到有关它们的相互矛盾的信息.
有些消息称,在32位平台上,GetWindowLongPtr只是一个调用GetWindowLong的预处理器宏,而GetWindowLongPtr不作为user32.dll中的入口点存在.例如:
因此,这些来源似乎表明*Ptr入口点根本不存在于32位Windows 7附带的user32.dll版本中.
但我在MSDN文档中没有看到这一点.根据MSDN,SetWindowLongPtr取代了SetWindowLong,简单明了.根据SetWindowLongPtr页面的要求部分,看起来SetWindowLongPtr自Windows 2000(客户端和服务器版本)以来一直在user32.dll中.同样,没有提到32位操作系统中缺少的入口点.
我怀疑事实介于两者之间:当你告诉C++编译器定位较旧的操作系统(即编译将在Win9x和NT4上运行的东西)时,头文件将SetWindowLongPtr声明为调用SetWindowLong的宏,但是入口点可能确实存在于Windows 2000及更高版本中,如果您告诉编译器定位这些平台,您将直接获取它(而不是宏).但这只是猜测; 我真的没有资源或技术可以深入挖掘并验证它.
目标平台也可能扮演一个角色 - 如果您为x86平台编译应用程序,那么就不应该在64位操作系统上调用SetWindowLongPtr.再一次,我知道这个问题,但我不知道如何找到答案.MSDN似乎暗示SetWindowLongPtr始终是正确的.
任何人都可以告诉我,简单的P/Invoke到SetWindowLongPtr是否安全并完成它?(假设Windows 2000及更高版本.)P /调用SetWindowLongPtr会给我正确的入口点:
我正试图在P/Invoking之前找到一种检测特征是否存在的好方法.例如,调用本机StrCmpLogicalW函数:
[SuppressUnmanagedCodeSecurity]
internal static class SafeNativeMethods
{
[DllImport("shlwapi.dll", CharSet = CharSet.Unicode)]
public static extern int StrCmpLogicalW(string psz1, string psz2);
}
Run Code Online (Sandbox Code Playgroud)
将在某些没有此功能的系统上崩溃.
我不想执行版本检查,因为这是不好的做法,有时可能只是错误(例如,当功能被反向移植时,或者可以卸载功能时).
正确的方法是检查导出的存在shlwapi.dll:
private static _StrCmpLogicalW: function(String psz1, String psz2): Integer;
private Boolean _StrCmpLogicalWInitialized;
public int StrCmpLogicalW(String psz1, psz2)
{
if (!_StrCmpLogialInitialized)
{
_StrCmpLogicalW = GetProcedure("shlwapi.dll", "StrCmpLogicalW");
_StrCmpLogicalWInitialized = true;
}
if (_StrCmpLogicalW)
return _StrCmpLogicalW(psz1, psz2)
else
return String.Compare(psz1, psz2, StringComparison.CurrentCultureIgnoreCase);
}
Run Code Online (Sandbox Code Playgroud)
当然,问题是C#不支持函数指针,即:
_StrCmpLogicalW = GetProcedure("shlwapi.dll", "StrCmpLogicalW");
Run Code Online (Sandbox Code Playgroud)
无法做到.
所以我试图找到替代语法来在.NET中执行相同的逻辑.到目前为止我有以下伪代码,但我受到了阻碍:
[SuppressUnmanagedCodeSecurity]
internal static class SafeNativeMethods …Run Code Online (Sandbox Code Playgroud)