PowerPoint DocumentWindows Collection Issue
Okay COM Interop C# Experts, here's a toughie:
I'm hosting PowerPoint in a .NET UserControl I created using
WebBrowserControl. Note, the important part about this whole deal is
PowerPoint creates and *runs* a slideshow. That's why, when you open a PPT
document in the browser, it's full-screen and moves from page to page with
clickity clicks. You can NOT get it into any other mode via any "straight
forward" means that I'm aware of.
Now, what I show below took me a long time with much sweat and tears to
figure out. Basically, you need to do some GetType() and InvokeMember()
stuff to get the SlideShowView, turn it off with the .Exit() member function
(via the late-bound Invoke), and then you can get the DocumentWindows object
via an InvokeMember.
Note that the DocumentWindows object is a Collection which has, as
collection members, PowerPoint DocumentWindow object. Here's how I would
*expect* to work with these values via any "normal" type means in C#, more or
less:
using PowerPoint.Interop; (load the PowerPoint Primary Interop Assembly).
I'm using Office 2003.
PowerPoint.DocumentWindows myDocWindows = (collection gathered via magical
means to see below);
PowerPoint.DocumentWindow = myDocWindows[1];
That should work, in theory. In practice, it doesn't
First. let me state that things in this fashion work differently in a Form
control versus a User Control. Meaning, if you create a Form and add the
WebBrowserControl, you'll be able to do stuff you can NOT do if you create a
Windows Control Library in C#. With that said, here's basically what I'm
doing:
In the NavigateComplete2 callback:
private void wbControl_NavigateComplete2(object sender,
AxSHDocVw.DWebBrowserEvents2_NavigateComplete2Event e)
//Object Defines for Any Office Application
//We need these objects for all documents viewed regarless
//of which application loads the document
//Create the OFParameters object for use as needed below
object[] OFParameters = null;
//The "object" is a member of the event as pDisp
Object o = e.pDisp;
//Generic "Document" object returned.
//This is a "late binding" call which gets the object
oDocument =
o.GetType().InvokeMember("Document",BindingFlags.GetProperty,null,o,null);
//Generic "Application" object -- late bound call.
Object oApplication =
o.GetType().InvokeMember("Application",BindingFlags.GetProperty,null,oDocument,null);
//Every generic "Application" object has a "Name" property which
//describes the program opening the document
Object oName = o.GetType().InvokeMember("Name",BindingFlags.GetProperty
,null,oApplication,null);
//Unnecessary message box to "test" that this callback,
NavigateComplete2, did in fact fire.
MessageBox.Show("Viewing Office document with " + oName.ToString());
if (oName.ToString() == "Microsoft PowerPoint")
{
try //Attempting to handle the errors
{
//Unnecessary Message Box to tell us we're withing
//the PowerPoint block.
MessageBox.Show("Inside PowerPoint Block");
//Note: Everything below, except the CommandBar stuff
//is done via the "late binding" methods -- including
//calling member fuctions, etc.
//Casting each of these object types as their "real" types
//and using them does NOT work and will generate an error
//which is NOT caught in this try/catch block.
//Desired Return Type: PowerPoint Presentation
//PowerPoint Presentation Object
Object pptPresentation = o.GetType().InvokeMember("ActivePresentation",
BindingFlags.GetProperty, null, oApplication, null);
//Desired Return Type: PowerPoint SlideShowWindow object
Object pptSlideShowWindow =
pptPresentation.GetType().InvokeMember("SlideShowWindow",
BindingFlags.GetProperty, null, pptPresentation, null);
//Need the PowerPoint SlideShowView object from the PowerPoint
SlideShowWindow object
Object pptSlideShowView =
pptSlideShowWindow.GetType().InvokeMember("View", BindingFlags.GetProperty,
null, pptSlideShowWindow, null);
//Important View Property for us: SlideShowView State
Object pptSlideShowViewState =
pptSlideShowView.GetType().InvokeMember("State", BindingFlags.GetProperty,
null, pptSlideShowView, null);
//Ignore this for now. I *may* need it later, so keeping
//it in the code.
//OFInvokeParams = new Object[1];
//OFInvokeParams[0] = 0;
//Late-bound "Invoke" on the Exit() method
Object pptExitView = pptSlideShowView.GetType().InvokeMember("Exit",
BindingFlags.InvokeMethod, null, pptSlideShowView, null);
//Desired Return Type: Windows from Presentation which represents a
PowerPoint.DocumentWindows Collection
//NOTE: We can not successfully get the Windows until AFTER we shut
down the SlideShow
// -- this doesn't work --- PowerPoint.DocumentWindows
pptSlideShowWindows =
(PowerPoint.DocumentWindows)pptPresentation.GetType().InvokeMember("Windows",
BindingFlags.GetProperty, null, pptPresentation, null);
Object pptSlideShowWindows =
pptPresentation.GetType().InvokeMember("Windows", BindingFlags.GetProperty,
null, pptPresentation, null);
Object oCount = pptSlideShowWindows.GetType().InvokeMember("Count",
BindingFlags.GetProperty, null, pptSlideShowWindows, null);
MessageBox.Show("Number of PowerPoint Document Windows is/are " +
oCount.ToString());
********************************NOTHING BELOW THIS AREA
WORKS********************************************
//Object pptDocWindows =
pptPresentation.GetType().InvokeMember("Windows", BindingFlags.GetProperty,
null, pptPresentation, null);
//System.Reflection.Binder myBinder;
//PowerPoint.DocumentWindow myDocWindow;
//System.Globalization.CultureInfo myCulture;
//myBinder.ChangeType(pptDocWindows, myDocWindow.GetType(), myCulture);
//Desired Return Type: Single Window from the Windows Collection.
//OFParameters = new Object[1];
//OFParameters[0] = 1;
//System.Int32 DocIndexValue = 1;
//Object pptDocumentWindow =
pptSlideShowWindows.GetType().InvokeMember("_Index",
BindingFlags.InvokeMethod, null, pptSlideShowWindows, new object[]
{DocIndexValue});
System.Collections.IEnumerator myEnum =
(System.Collections.IEnumerator)pptSlideShowWindows.GetType().InvokeMember("GetEnumerator", BindingFlags.InvokeMethod, null, pptSlideShowWindows, null);
********************************NOTHING ABOVE THIS AREA
WORKS********************************************
//CommandBars ia a collection of CommandBar values
//Casting works here. I don't have a clue why.
CommandBars oCommandBars;
oCommandBars =
(CommandBars)pptPresentation.GetType().InvokeMember("CommandBars",
BindingFlags.GetProperty , null, pptPresentation ,null);
//Grab the "Formatting" menu as I want it OFF.
CommandBar oReviewingBar = oCommandBars["Formatting"];
//Grab the "Drawing" menu (commandbar) as I also want this OFF.
CommandBar oDrawingBar = oCommandBars["Drawing"];
//Using "Visible" doesn't work here, so using "Enabled" instead.
//Turns off both extra Command Bars from the menu. Only
//the "Standard" bar is available.
oReviewingBar.Enabled = false;
oDrawingBar.Enabled = false;
}
catch (Exception myException)
{
MessageBox.Show("Error occurred " + myException.Message.ToString());
}
Note: First I get the Application, then the ActivePresentation, then the
SlideShowWindow, then the SlideShowView, then I turn it off with the .Exit()
method.
Only after that, can I get the DocumentWindows object which is retrieved via
the "Windows" property of the Presentation object.
Now, the CommandBar stuff works, so I just left it in there for a reference
in case anyone else wants to see how to do that with PowerPoint.
You can see some of the stuff I'm trying and commenting out. Now, you'd
think that:
Object pptDocumentWindow =
pptSlideShowWindows.GetType().InvokeMember("DocumentWindow",
BindingFlags.GetProperty, null, pptSlideShowWindows, new object[]
{DocIndexValue});
I've also tried:
Object pptDocumentWindow =
pptSlideShowWindows.GetType().InvokeMember("this", BindingFlags.GetProperty,
null, pptSlideShowWindows, new object[] {DocIndexValue});
and a few others.
*would* work and return the collection window at index 1 (I'm assuming the
indexes start at 1 rather than 0 here).
Regardless, the errors I'm getting are "Error occurred Unknown name" (in the
catch messagebox). This tells me, and I'm only guessing here, that the
"name" parameter which is the first parameter in the InvokeMember() function,
is incorrect.
However, I'm using the Object Browser part of Visual Studio .NET 2003 to
view the object via the Primary Interop Assembly, and I don't see any other
way to "name" this value.
Likewise, for some reason, the objects all return as System._COMObject and
hence are not really "viewable" via a Quickwatch. Interestingly enough, Word
and Excel object cast really well and are viewable. PowerPoint, however,
doesn't play well in the COM to .NET interop in that fashion.
Hence, I'm more or less blindly groping for named objects within objects via
the InvokeMember method.
WHAT I NEED:
=========
I need a way to get the DocumentWindow object because ultimately, I need the
ViewType property from that for which I can set it to ppViewTypeNormal and
hence get a PowerPoint presentation in "normal" view mode hosted within a
WebBrowserControl in an Internet Explorer session.
Thanks!
---Dan---
date: Mon, 7 Mar 2005 13:57:02 -0800
author: AmiciDan