I have a VB.net application from which I'd like to launch Powerpoint. When the user tries to save the presentation I want to control exactly where the file is saved (and collect some other data at the same time).
I can see how to create a powerpoint instance and either use with events or add handler to intercept the PresentationBeforeSave event using early binding but since I don't really know what version of Powerpoint I'll be dealing with I really want to use late binding.
The question is how do I add event handlers to a late bound object since the event template isn't available?
02-11-2005, 08:34 AM
You can't. The compiler cannot hook the events if it doesn't know what the interface of the object looks like and which events the object can raise.
In VB6 the usual solution to this is to bind to the earliest version that you plan to use your app with. I understand that this doesn't work that well in VB.Net, especially with anything below v10. I would suggest either sticking to one version, or making do without events, or using VB6 instead.
(There's a great saying in Swedish which roughly translates to "choosing between plague and cholera", i.e. having to choose between several bad alternatives... seems very applicable here!)
Perhaps somebody else has better ideas.
Edit: Mike_R is on the case and has some ideas that he needs to test; don't go away yet.
PS Welcome to the forum. :)
02-11-2005, 08:55 AM
Hang in there, I'm going to run a quick test... I might have an idea, but I'm not sure it works. I'll post back in just a few mins.
02-11-2005, 09:36 AM
I failed :(.
It is possible that someone who is a master of Reflection could possibly get this done, but it's beyond what I can do. It may also be outright impossible, I can't say for sure. It very well may not be exposed in any way? Not sure about that, but I can't get it. :(
Using VB.Net's late binding using 'WithEvents' or 'AddHandler' both fail, but I guess you figured that out already. I was sort-of hoping that the 'AddHandler' approach could work, but it does not. Since AddHandler occurs at Run-Time (actually, so does 'WithEvents', but that's another story), I was really hoping that VB's built in Late Binding (that is, built in Reflection) would be able to handle this, but it does not. :(
Is there a good reason you need to use Late Binding? With which versions do you hope to be compatible? Personally, I'm forcing anyone who uses my .Net stuff to have Office 11.0 installed, but I can have that luxury. I've not really kicked around cross-version compatiblity. I would hope that binding to the 10.0 or 9.0 verson should "just work" if you then run a higher numbered version (say 10.0 or 11.0), but you'd have to test to be sure...
Sorry couldn't do better :(,
Thanks for your efforts - I do appreciate it - I'll try binding to 9.0 and I'll let you know if it works.
The only other thing I can think of is building the App 3 times (once with each version of Office) and then work some cleverness into the installation process - I'll look forward to that...
Incidentally and somewhat off topic - I'm actually trying to capture the save event from Word and Excel as well as PowerPoint - interestingly it seem that for both Word and Excel it is possible to cancel the saveas and, whilst still in the "beforesave" event, issue a request to the office product to save the document to a specified location.
You can't do that with PowerPoint the SaveAs commend always fails if your in the "beforeSave" thread. If you let the thread executing the Beforesave from PowerPoint return to Powerpoint and then, in a different thread, issue the SaveAs request that works - strange but true.
02-11-2005, 02:42 PM
For Excel, you may have trouble if trying to listen to Excel.Application Events. There is a bug, of sorts, in Excel and Outlook where the Application-level Events are actually private, at least not exposed properly to .Net.
So you should have no trouble picking up the Excel.Workbook.BeforeSave() Event, but you will not be ablet to Handle the Excel.Application.WorkbookBeforeSave() Event. Weird, I know, but it's true.
It can be dealt with, but only by modifying the IL. It sounds scarier than it is, but you can expose the Excel.Application Events if you follow the directions here:
Error Using WithEvents or Delegates to Handle Excel Events from .Net (MSDN) (http://support.microsoft.com/default.aspx?scid=KB;EN-US;q316653&)
Anyway, if you have a particular Workbook in mind, you do not have to worry about any of this because the Excel.Workbook Events are all exposed properly. (Worksheet Events are too, it's only the Excel.Application events that are marked "Private".)
02-11-2005, 03:05 PM
Oh, I should have replied to this as well: Incidentally and somewhat off topic - I'm actually trying to capture the save event from Word and Excel as well as PowerPoint - interestingly it seem that for both Word and Excel it is possible to cancel the saveas and, whilst still in the "beforesave" event, issue a request to the office product to save the document to a specified location.
You can't do that with PowerPoint the SaveAs commend always fails if your in the "beforeSave" thread. Both situations should get you into trouble. What is happening is that you are creating infinite-recursion, and if there were no protections in place, you would get a Stack Overflow Error, which is generally fatal.
In essence you have set up a Recursion with no terminating condition, something like this:Sub DoSomething()
End Sub If you ever call this Sub now, it is doomed to have an infinite loop. In parallel fashion, your BeforeSave Event is calling Workbook.SaveAs() and so this Raises the BeforeSave Event, which then calls Workbook.SaveAs(), ad infinitum...
I don't know a thing about PowerPoint, but Excel can/will identify an infinite event loop. I forget how many loops it takes for it to pick it up (I think a lot, btw, I think 140? But it will notice the infinite loop eventually.). When Excel notices this, it then disables Events, or at least that event. So eventually you get a call to Workbook.SaveAs() but the BeforeSave Event is not triggered (because Excel turned it off) and so the SaveAs() goes through.
It sounds like PowerPoint has a protection of sorts as well (or it too would have a Stack Overflow). In this case, it seems that it may be disabling the SOURCE of the Event, in this case, disabling the .SaveAs() Method itself. In fact, it sounds like it may be better protected: I'm guessing that it picks this up after only one iteration; behind the scenes, raising the BeforeSave Event seems to be disabling the .SaveAs() command until the BeforeSave Event has exited.
If you let the thread executing the Beforesave from PowerPoint return to Powerpoint and then, in a different thread, issue the SaveAs request that works - strange but true. This is because you have let the code flow out of the BeforeSave Event, and the .SaveAs() Method is therefore free to execute it. Using a Timer-based call or a different Thread (either way) would allow the execution to flow out of the BeforeSave Event thereby re-enabling the .SaveAs() Method.
A typical strategy for dealing with this kind of "Infinite Event Recursion" is a structure something like this:Private Shared _beforeSaveEnabled As Boolean = True
Private Shared Sub xlWB_BeforeSave(ByVal SaveAsUI As Boolean, _
ByRef Cancel As Boolean) _
If _beforeSaveEnabled Then
_beforeSaveEnabled = False
_beforeSaveEnabled = True
End Sub In the above, the call to xlWB.SaveAs("...") will Raise the xlWB.BeforeSave Event, and so xlWB_BeforeSave() will get immediately called. But since _beforeSaveEnabled = False at this point, it will safely exit out of the Event Handler quietly and not call .SaveAs() a 2nd time.
When the xlWB.SaveAs("...") command is completed, the _beforeSaveEnabled value is restored = True so that it is properly set for the next time the Event is raised.
It seems that PowerPoint has a similar structure operating behind the scenes, although in this case they are disabling the .SaveAs() Method, not the BeforeSave Event...
Hope this made some sense?
02-11-2005, 04:10 PM
The list of usable application events in PowerPoint differ in each version.
As far as I know the PresentationBeforeSave event is only available from version 10.0 on (2002 & 2003).
Some MSDN (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vbapp10/html/ppmscNewEvtA2000.asp) info...
02-11-2005, 04:39 PM
As alternative you could maybe use the PresentationClose event which takes place before a presentation is closed.
Check the presentation's path, if "" save the presentation yourself (code wise of course).
If a path exisits, check if it is a valid one, and if not re-save the presentation on the correct location (and kill the other file?).
Not tested, but it could be a workable scenario :)
The PresentationClose event is available in the 9.0 version too (not sure about the 8.0 version).