Click here to Skip to main content
15,881,139 members
Articles / Programming Languages / C#
Article

How to avoid stubborn Windows applications from showing up

Rate me:
Please Sign up or sign in to vote.
3.84/5 (9 votes)
5 May 2005CPOL5 min read 56.7K   29   6
How to avoid stubborn Windows applications from showing up.

Introduction

Have you ever come across applications that are used as a service and also have a useful (or very useful) user interface but when you need them as a service they just start to claim their UI space? Let me make it simple, PowerPoint just has to show up on the screen even when you just need its automation capabilities, say to generate a PowerPoint presentation using the data from your database. Well here are a few things you can do to make it work silently. Well almost.

Environment

Like any other magic trick, you should have your tools of trade:

  • PowerPoint (I am using 2003 – V11.)
  • Windows 2000 or later.
  • Visual Studio .NET

How it is done?

Fairly simple:

  1. Get the handle to the window you want to vanish.
  2. Set the window to be completely transparent. (This even lets the mouse clicks to pass through the window to the windows below – very cool.)
  3. Use the ITaskbarList interface to remove the application button from the taskbar (can't get cooler than that).
  4. Brag about it.

The walk through

I am going to modify the existing sample available on MSDN on PowerPoint automation using C#. Search for "How to use automation to create and to show a PowerPoint 2002 presentation by using Visual C# .NET 2002" on MSDN to get the un-mutilated automation sample source code.

Here is some advice, if you hate COM and would like to stay out of it completely, then this is the right time to hit the back button otherwise you might start liking it, especially when you find out how easy it is to tap its power in .NET.

Note: You can use all the code segments below and join them to get a single .cs file. So go ahead and copy them together if the world is ending for you.

Step 1

Create a new project in Visual Studio (VS). I am using a console application.

Step 2

Include the universe.

C#
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..

One of the great tricks that we are going to use here is to use a feature in Shell32 to make the taskbar button disappear and appear at your command. Shell32 exposes this feature through a COM interface called ITaskbarList. Although you can look for the interface in SDK and create your own interop, it’s usually better to let Microsoft generate the interop for you. In any case the interface is very simple hence there is no chance of missing out on any marshalling specifics. I would suggest to use the .idl file that I have listed at the end of this article (save the text to a file with .idl extension) and use the MIDL tool to compile a .tlb file, which you can include as a COM component in your project using the add reference dialog. (Also try exploring other methods exposed by the interface, it's fun to play with it.)

Step 3

Now since we are going to make a few Windows API calls, here is some amount of homework we need to do to call them:

C#
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;

Step 4

Go on and create that application object:

C#
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();

Step 5

Do let the application window know before hand that you are going to play with it, or it might get upset. I mean you need to set the window style to have layers. This is done by setting the extended style attribute WS_EX_LAYERED for the window. This will let us set different transparency (opacity) values for the window which in our case will be to set the window to be completely transparent. One thing to remember here is, if any window has already set styles then we don’t want to disturb them, so we get the existing setup and just add our flag to it. This is how it is done:

C#
SetWindowLong((IntPtr)objApp.HWND, GWL_EXSTYLE, 
   GetWindowLong((IntPtr)objApp.HWND, GWL_EXSTYLE) | WS_EX_LAYERED);

That’s it, our PowerPoint application’s window is all set to magically disappear.

Step 6

The magic moment.

Here we set the opacity of the window to 0 using the SetLayeredWindowAttributes method. Which means the window will no longer be visible after this step and all our mouse clicks and key events will just pass through it, as if it didn’t exist. Here is how it is done:

C#
SetLayeredWindowAttributes((IntPtr)objApp.HWND,0,0,
                             LWA_ALPHA|LWA_COLORKEY); 

Step 7

The mandatory noise.

If you wish to automate and create presentations dynamically, the PowerPoint object model forces you to make the application visible.

C#
objApp.Visible = MsoTriState.msoTrue;

But since we have already set the application to be completely transparent, we don’t care even if we have to set the above flag to true.

Step 8

The almost trick.

We managed to make the window invisible but Windows will still display a task bar button for the application object, which in our case is PowerPoint. Although the task bar button can be used to track whether the object is available or not however on a server churning out PowerPoint slides which does not require any user interaction it does not make any sense to have one. So let’s make it disappear. The catch here is that the button should appear in order to make it disappear, that’s why we had set the application object to be visible in the previous step before we can remove it from the taskbar. Well yes the button will appear for a moment before it vanishes. Remember the ITaskbarList interface (listed at the end of this article) we talked about? Well, here is how it is used. We use the coclass declared in the interface to instantiate an object and call the DeleteTab method on it, passing the handle of our PowerPoint application object and that’s it, three lines of code to use the COM object and say bye-bye to the taskbar button.

C#
TaskbarList.TaskbarList tblc = new TaskbarList.TaskbarList();
tblc.HrInit(); // got to call this before we can do anything with the interface
tblc.DeleteTab(objApp.HWND );

Done!

Step 9

All the remaining unchanged code from the MSDN article. (Remember we don’t want to hide the slide show we created.)

C#
    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();
  }
 }
}

The ITaskBarList.idl file

Compile the .idl file using the MIDL compiler and include the generated .tlb into your project:

C#
//////////////////////////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;
    };
};
////////////////////////////////////////////////////////////////////////

I also suggest that you compile and run the original sample from MSDN too, and see the difference.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionHow can i hide the slide show window until i need it Pin
akan4717-Jul-09 3:27
akan4717-Jul-09 3:27 
QuestionAnother error trying to add the .tlb file to the project Pin
TxDot12-Feb-06 16:40
TxDot12-Feb-06 16:40 
AnswerRe: Another error trying to add the .tlb file to the project Pin
Ravi Gyani11-Jun-06 22:03
Ravi Gyani11-Jun-06 22:03 
Questionmidl.exe error Pin
TxDot12-Feb-06 15:14
TxDot12-Feb-06 15:14 
AnswerRe: midl.exe error Pin
TxDot12-Feb-06 16:12
TxDot12-Feb-06 16:12 
Generaljust what i was looking for Pin
Prakash Nadar14-Nov-05 5:20
Prakash Nadar14-Nov-05 5:20 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.