65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.84/5 (9投票s)

2005年5月5日

CPOL

5分钟阅读

viewsIcon

57479

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

引言

您是否遇到过这样的应用程序,它们既用作服务,又拥有有用(甚至非常有用)的用户界面,但当您需要它们作为服务时,它们却开始占据其 UI 空间?让我简单说明一下,即使您只需要 PowerPoint 的自动化功能,例如使用数据库中的数据生成 PowerPoint 演示文稿,PowerPoint 也必须显示在屏幕上。好了,这里有一些您可以让它静默工作的方法。嗯,几乎可以说是静默。

环境

像任何其他魔术一样,您应该拥有您的工具

  • PowerPoint(我使用的是 2003 版 – V11。)
  • Windows 2000 或更高版本。
  • Visual Studio .NET

如何做到?

相当简单

  1. 获取您想要隐藏的窗口的句柄。
  2. 将窗口设置为完全透明。(这甚至允许鼠标点击穿过窗口到达下面的窗口 – 非常酷。)
  3. 使用 ITaskbarList 接口从任务栏中删除应用程序按钮(还有比这更酷的吗!)。
  4. 为此吹嘘一下。

演练

我将修改 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 的原始示例,看看其中的区别。

© . All rights reserved.