如何避免顽固的 Windows 应用程序出现






3.84/5 (9投票s)
如何避免顽固的 Windows 应用程序出现。
引言
您是否遇到过这样的应用程序,它们既用作服务,又拥有有用(甚至非常有用)的用户界面,但当您需要它们作为服务时,它们却开始占据其 UI 空间?让我简单说明一下,即使您只需要 PowerPoint 的自动化功能,例如使用数据库中的数据生成 PowerPoint 演示文稿,PowerPoint 也必须显示在屏幕上。好了,这里有一些您可以让它静默工作的方法。嗯,几乎可以说是静默。
环境
像任何其他魔术一样,您应该拥有您的工具
- PowerPoint(我使用的是 2003 版 – V11。)
- Windows 2000 或更高版本。
- Visual Studio .NET
如何做到?
相当简单
- 获取您想要隐藏的窗口的句柄。
- 将窗口设置为完全透明。(这甚至允许鼠标点击穿过窗口到达下面的窗口 – 非常酷。)
- 使用
ITaskbarList
接口从任务栏中删除应用程序按钮(还有比这更酷的吗!)。 - 为此吹嘘一下。
演练
我将修改 MSDN 上关于 PowerPoint 自动化(使用 C#)的现有示例。在 MSDN 上搜索“How to use automation to create and to show a PowerPoint 2002 presentation by using Visual C# .NET 2002”,以获取未被篡改的自动化示例源代码。
这里有一些建议,如果您讨厌 COM 并希望完全避开它,那么现在是时候点击返回按钮了,否则您可能会开始喜欢它,尤其是当您发现 .NET 中利用其强大功能有多么容易时。
注意:您可以复制下面所有的代码段并将它们合并成一个单独的 .cs 文件。所以,如果世界末日了,那就把它们复制在一起吧。
步骤 1
在 Visual Studio (VS) 中创建一个新项目。我使用的是控制台应用程序。
第二步
包含万象。
using System; // the universe
using Microsoft.Office.Core; // add the Microsoft Office 11.0
// Object Library reference
// from the com tab in add reference dialog
using PowerPointNS = PowerPoint; // add the Microsoft PowerPoint 11.0
// Object Library reference
// from the com tab in add reference dialog
using Graph; // add the Microsoft Graph 11.0 Object Library reference
// from the com tab in add reference dialog
using System.Runtime.InteropServices; // since we are using COM..
我们将在这里使用的一个绝招是利用 Shell32 的一项功能,该功能可以根据您的命令使任务栏按钮消失和出现。Shell32 通过一个名为 ITaskbarList
的 COM 接口公开此功能。尽管您可以在 SDK 中查找该接口并创建自己的互操作程序,但通常最好让 Microsoft 为您生成互操作程序。无论如何,该接口非常简单,因此没有遗漏任何封送特定信息的可能性。我建议使用本文末尾列出的 .idl 文件(将文本保存到一个扩展名为 .idl 的文件中),并使用 MIDL 工具编译一个 .tlb 文件,您可以通过“添加引用”对话框将其作为 COM 组件包含在您的项目中。(也可以尝试探索该接口公开的其他方法,玩玩它很有趣。)
步骤 3
现在,由于我们将调用一些 Windows API,因此我们需要做一些准备工作来调用它们。
namespace PPTest
{
class Class1
{
[DllImport("User32", CharSet=CharSet.Auto)]
// API call to get the current window layout
private static extern int GetWindowLong(IntPtr hWnd, int Index);
[DllImport("User32", CharSet=CharSet.Auto)]
// API call to set the window layout
private static extern int SetWindowLong(IntPtr hWnd,
int Index, int Value);
[DllImport("User32", CharSet=CharSet.Auto)]
// API call to make the window transpairent
private static extern int SetLayeredWindowAttributes(IntPtr hWnd,
int clrKey,Byte bAlpha,int dwFlags);
private const int LWA_COLORKEY = 1;
private const int LWA_ALPHA = 2;
private const int GWL_STYLE = -16;
private const int GWL_EXSTYLE = -20;
private const int WS_EX_LAYERED = 0x00080000;
步骤 4
去创建一个应用程序对象。
private static void ShowPresentation()
{
String strTemplate, strPic;
strTemplate =
"C:\\Program Files\\Microsoft Office\\Templates\\Presentation Designs\\Blends.pot";
strPic = "C:\\Windows\\Blue Lace 16.bmp";
bool bAssistantOn;
PowerPointNS.Application objApp;
PowerPointNS.Presentations objPresSet;
PowerPointNS._Presentation objPres;
PowerPointNS.Slides objSlides;
PowerPointNS._Slide objSlide;
PowerPointNS.TextRange objTextRng;
PowerPointNS.Shapes objShapes;
PowerPointNS.Shape objShape;
PowerPointNS.SlideShowWindows objSSWs;
PowerPointNS.SlideShowTransition objSST;
PowerPointNS.SlideShowSettings objSSS;
PowerPointNS.SlideRange objSldRng;
Graph.Chart objChart;
//Create a new presentation based on a template.
objApp = new PowerPointNS.Application();
步骤 5
请提前告知应用程序窗口您将要操作它,否则它可能会生气。我的意思是,您需要设置窗口样式以拥有图层。这是通过为窗口设置扩展样式属性 WS_EX_LAYERED
来完成的。这将允许我们为窗口设置不同的透明度(不透明度)值,在我们的情况下,这将是设置窗口完全透明。这里要记住的一点是,如果任何窗口已经设置了样式,我们不想干扰它们,所以我们获取现有的设置并在此基础上添加我们的标志。就这样做:
SetWindowLong((IntPtr)objApp.HWND, GWL_EXSTYLE,
GetWindowLong((IntPtr)objApp.HWND, GWL_EXSTYLE) | WS_EX_LAYERED);
就是这样,我们的 PowerPoint 应用程序窗口已经准备好神奇地消失了。
步骤 6
魔法时刻。
在这里,我们使用 SetLayeredWindowAttributes
方法将窗口的不透明度设置为 0。这意味着在该步骤之后,窗口将不再可见,我们所有的鼠标点击和键盘事件都将直接穿过它,就好像它不存在一样。这是如何做的:
SetLayeredWindowAttributes((IntPtr)objApp.HWND,0,0,
LWA_ALPHA|LWA_COLORKEY);
步骤 7
强制的噪音。
如果您希望动态地自动化和创建演示文稿,PowerPoint 对象模型会强制您使应用程序可见。
objApp.Visible = MsoTriState.msoTrue;
但由于我们已经将应用程序设置为完全透明,即使我们将上述标志设置为 true
,我们也无所谓。
步骤 8
几乎可以实现的神奇技巧。
我们成功地隐藏了窗口,但 Windows 仍然会为应用程序对象(在本例中为 PowerPoint)显示一个任务栏按钮。尽管任务栏按钮可用于跟踪对象是否可用,但对于一个不需要用户交互的、生成 PowerPoint 幻灯片的服务器来说,有一个任务栏按钮是没有意义的。所以,让我们让它消失。这里的问题是,为了让按钮消失,它必须先出现,这就是为什么我们在上一步中设置应用程序对象可见,然后才能从任务栏中删除它。是的,按钮会显示片刻然后消失。还记得我们之前提到的 ITaskbarList
接口(列在本文末尾)吗?好吧,这里是如何使用它。我们使用接口中声明的 coclass 来实例化一个对象,并对其调用 DeleteTab
方法,传递我们 PowerPoint 应用程序对象的句柄,就这样,三行代码就可以使用 COM 对象,告别任务栏按钮。
TaskbarList.TaskbarList tblc = new TaskbarList.TaskbarList();
tblc.HrInit(); // got to call this before we can do anything with the interface
tblc.DeleteTab(objApp.HWND );
完成!
步骤 9
MSDN 文章中所有未更改的代码。(请记住,我们不想隐藏我们创建的幻灯片放映。)
objPresSet = objApp.Presentations;
objPres = objPresSet.Open(strTemplate,
MsoTriState.msoFalse, MsoTriState.msoTrue, MsoTriState.msoTrue);
objSlides = objPres.Slides;
//Build Slide #1:
//Add text to the slide, change the font and insert/position a
//picture on the first slide.
objSlide = objSlides.Add(1,PowerPointNS.PpSlideLayout.ppLayoutTitleOnly);
objTextRng = objSlide.Shapes[1].TextFrame.TextRange;
objTextRng.Text = "My Sample Presentation";
objTextRng.Font.Name = "Comic Sans MS";
objTextRng.Font.Size = 48;
objSlide.Shapes.AddPicture(strPic, MsoTriState.msoFalse, MsoTriState.msoTrue,
150, 150, 500, 350);
//Build Slide #2:
//Add text to the slide title, format the text. Also add a chart to the
//slide and change the chart type to a 3D pie chart.
objSlide = objSlides.Add(2, PowerPointNS.PpSlideLayout.ppLayoutTitleOnly);
objTextRng = objSlide.Shapes[1].TextFrame.TextRange;
objTextRng.Text = "My Chart";
objTextRng.Font.Name = "Comic Sans MS";
objTextRng.Font.Size = 48;
objChart = (Graph.Chart) objSlide.Shapes.AddOLEObject(150,150,480,320,
"MSGraph.Chart.8", "",
MsoTriState.msoFalse, "", 0, "",
MsoTriState.msoFalse).OLEFormat.Object;
objChart.ChartType = Graph.XlChartType.xl3DPie;
objChart.Legend.Position=Graph.XlLegendPosition.xlLegendPositionBottom;
objChart.HasTitle = true;
objChart.ChartTitle.Text = "Here it is...";
//Build Slide #3:
//Change the background color of this slide only.
//Add a text effect to the slide
//and apply various color schemes and shadows to the text effect.
objSlide = objSlides.Add(3, PowerPointNS.PpSlideLayout.ppLayoutBlank);
objSlide.FollowMasterBackground = MsoTriState.msoFalse;
objShapes = objSlide.Shapes;
objShape = objShapes.AddTextEffect(MsoPresetTextEffect.msoTextEffect27,
"The End", "Impact", 96,
MsoTriState.msoFalse,
MsoTriState.msoFalse, 230, 200);
//Modify the slide show transition settings for all 3 slides in
//the presentattion.
int[] SlideIdx = new int[3];
for(int i=0;i<3;i++) SlideIdx[i]=i+1;
objSldRng = objSlides.Range(SlideIdx);
objSST = objSldRng.SlideShowTransition;
objSST.AdvanceOnTime = MsoTriState.msoTrue;
objSST.AdvanceTime = 3;
objSST.EntryEffect = PowerPointNS.PpEntryEffect.ppEffectBoxOut;
//Prevent Office Assistant from displaying alert messages:
bAssistantOn = objApp.Assistant.On;
objApp.Assistant.On = false;
//Run the Slide show from slides 1 thru 3.
objSSS = objPres.SlideShowSettings;
objSSS.StartingSlide = 1;
objSSS.EndingSlide = 3;
objSSS.Run();
//Wait for the slide show to end.
objSSWs = objApp.SlideShowWindows;
while(objSSWs.Count>=1) System.Threading.Thread.Sleep(100);
//Reenable Office Assisant, if it was on:
if(bAssistantOn)
{
objApp.Assistant.On = true;
objApp.Assistant.Visible = false;
}
//Close the presentation without saving changes and quit PowerPointNS.
objPres.Close();
objApp.Quit();
}
[STAThread]
static void Main(string[] args)
{
ShowPresentation();
GC.Collect();
}
}
}
ITaskBarList.idl 文件
使用 MIDL 编译器编译 .idl 文件,并将生成的 .tlb 包含到您的项目中。
//////////////////////////ITaskbarList.idl////////////////////////////
[
uuid(C52C7F93-54B9-11D3-ABF9-0040F6A4BFEC),
version(1.0),
helpstring("ITaskbarList - shell32")
]
library TaskbarList
{
// TLib: //TLib: OLE Automation: {00020430-0000-0000-C000-000000000046}
importlib("stdole2.tlb");
// Forward declare all types defined in this typelib
interface ITaskbarList;
[
odl,
uuid(56FDF342-FD6D-11D0-958A-006097C9A090),
helpstring("ITaskbarList interface")
]
interface ITaskbarList : IUnknown
{
[helpstring("This function must be called first to validate " +
"use of other members.")]
HRESULT _stdcall HrInit();
[helpstring("This function adds a tab for hwnd to the taskbar.")]
HRESULT _stdcall AddTab([in] long hwnd);
[helpstring("This function deletes a tab for hwnd from " +
"the taskbar.")]
HRESULT _stdcall DeleteTab([in] long hwnd);
[helpstring("This function activates the tab associated with " +
"hwnd on the taskbar.")]
HRESULT _stdcall ActivateTab([in] long hwnd);
[helpstring("This function marks hwnd in the taskbar as the " +
"active tab.")]
HRESULT _stdcall SetActivateAlt([in] long hwnd);
};
[
uuid(56FDF344-FD6D-11D0-958A-006097C9A090),
helpstring("TaskbarList class")
]
coclass TaskbarList
{
[default] interface ITaskbarList;
};
};
////////////////////////////////////////////////////////////////////////
我还建议您也编译并运行 MSDN 的原始示例,看看其中的区别。