PDA

View Full Version : Is PowerPoint still a single instance app?



Howard Kaikow
05-20-2005, 10:13 AM
As of Powerpoint 2000, it is my understanding that there can only be a
single instance of Powerpoint running.
Is that still true for Powerpoint 2002 and 2003?

I've been using code such as the following:

'Get existing instance of PowerPoint; otherwise create a new one
' Powerpoint is a single instance application
On Error Resume Next
Set appPPT = GetObject(, "PowerPoint.Application")
If Err.Number = 0 Then
blnNewPPT = False
Else
Set appPPT = New PowerPoint.Application
blnNewPPT = True
End If
On Error GoTo 0

and then

With appPPT
If blnNewPPT Then
.Quit
Else
.ActivePresentation.Close
End If
End With

However, I suspect that code may not be good enough.
Do I not need to know whether the single instance of Powerpoint is being
used by another user, even if I created the instance within the code?

Killian
05-20-2005, 05:34 PM
Hi Howard,

I just ran a couple of quick tests on 2002 and 2003 and can't get a new instance of Powerpoint to launch with code from an existing one - which is a shame simce running another instance of an app in the background can be useful sometimes. Oh well, them's the breaks...

Howard Kaikow
05-20-2005, 08:44 PM
Hi Howard,

I just ran a couple of quick tests on 2002 and 2003 and can't get a new instance of Powerpoint to launch with code from an existing one - which is a shame simce running another instance of an app in the background can be useful sometimes. Oh well, them's the breaks...

The critical question is:



Do I not need to know whether the single instance of Powerpoint is being
used by another user, even if I created the instance within the code?

I might create an instance of Powerpoint in code, and some user might start a Powerpoint session outside the code, so I cannot safely kill the instance I created.

Killian
05-21-2005, 04:55 AM
I see.

Yes, you're quite right. A user launching PowerPoint will, in fact, activate your instance. I don't see there's anyway round that and since there's no new process thread for the user's action I don't see a way of detecting if it's happened.

I guess all you can do is check the Presentations collection having tidied up your code driven stuff to see if there's anything left...?

Howard Kaikow
05-21-2005, 09:14 AM
I see.

Yes, you're quite right. A user launching PowerPoint will, in fact, activate your instance. I don't see there's anyway round that and since there's no new process thread for the user's action I don't see a way of detecting if it's happened.

I guess all you can do is check the Presentations collection having tidied up your code driven stuff to see if there's anything left...?

It has ben suggested that if, instead of killing the powerpoint instance, if
i just set it to Nothing, the instance of powerpoint will go away if there
are no other powerpoint sessions.

I'll try this later.

I would feel comfortable relying on this only if I saw documentation of this
behavior, and for powerpoint 97, 2000, 2002 and 2003.

Not sure that behavior would work automating via VB .NET, but I have no plans to use the code in .NET.

The last resort would be to lock the desktop momentarily. If the presentation count is 1, th kill the critter, otherwise let it live. This ASSuMEs that there is a different instance of powerpoint on each desktop on a multi-user system. Otherwise, kablooey!

Howard Kaikow
05-21-2005, 10:45 AM
Came up with a "solution".
Seems too simple to be correct.

For the code below, one needs a Userform with 3 buttons.

1. Shut down any running PowerPoint.
2. Click on the Create PPT button.
3. After the program creates a PPT session, create a PPT session via the GUI, not using the icon minimized by the code.
4. Click on the Close PPT button.
5. Click on the Bye Bye button.

This code would appear to work for those cases in which my code need not keep a presentation alive. So, if I close all the code's presentations, this method appears to work.

If I have to keep a presentation alive, that should be no problem as I just would not close PowerPoint, just set its object variable = Nothing.

Does this hanky panky solve the problem?


Option Explicit
Private appPPT As Powerpoint.Application
Private blnNewPPT As Boolean
' Private MyPrivateName As String

Private Sub btnByeBye_Click()
Unload Me
End Sub

Private Sub btnClosePPT_Click()
With appPPT
If blnNewPPT Then
If .Presentations.Count = 0 Then
.Quit
lstActions.AddItem "New instance was Quit."
Else
lstActions.AddItem "New instance was NOT Quit."
End If
Else
On Error Resume Next
.ActivePresentation.Close
On Error GoTo 0
lstActions.AddItem "Extant instance was not Quit."
End If
End With
Set appPPT = Nothing
lstActions.AddItem "Set instance = Nothing."
On Error Resume Next
lstActions.AddItem Err.Number & ":" & Err.Description
On Error GoTo 0
End Sub

Private Sub btnCreatePPT_Click()
'Get existing instance of PowerPoint; otherwise create a new one
On Error Resume Next
Set appPPT = GetObject(, "PowerPoint.Application")
lstActions.AddItem Err.Number & ":" & Err.Description
If Err.Number = 0 Then
blnNewPPT = False
lstActions.AddItem "Extant instance is being used."
Else
Set appPPT = New Powerpoint.Application
blnNewPPT = True
lstActions.AddItem "New instance was created."
End If
With appPPT
' MyPrivateName = "HK" & Now & CDbl(Now)
.Visible = True
.WindowState = ppWindowMinimized
lstActions.AddItem "Presentations Count: " & .Presentations.Count
End With
On Error GoTo 0
End Sub

Howard Kaikow
05-21-2005, 09:22 PM
The "solution" does not detect a Powerpoint session that has no presentations, other than my own.

Is there an API, or some such that can tell me a reference count, or whatever, number of powerpoint instances being used?

I'm not yet ready to yell Uncle!


P.S.: I've been using the wrong terminology. MSFT uses "multi-use" and I've been using "single use".

Howard Kaikow
05-22-2005, 02:17 PM
I've come up with the following, is it valid?

1. Make sure that PowerPoint is not running.

2. Run a VB 6 program that creates a NEW instance of PowerPoint.

3. While the program in step 2 is still running, and PPT has not been Quit,
run another VB 6 program that enumerates desktop processes, call the output List 1.

4. While the PPT from step 2 is still running, start PowerPoint from the
desktop. Since I had already created an instance in step 2, both should end
up using the same instance as PowerPoint is multi-use, single instance.

5. Now, again run the program that enumerates desktop processes, call the
output List 2.

Both List 1 and List 2 give the same handle for PowerPoint, and the same
number of top level windows.

List 1 does not list an active presentation, whilst List 2 lists
Presentation1. So the first bit of info is that the caption PowerPoint window will include the latest use of Powerpoint. So this doesn't help solve my
problem.

However, the Total Thread Windows is 9 for List 1, 11 for List 2

I am enumerating the processes using code based on KB article 183009 and
only incrementing the counters when PP11FrameClass is found.

So, is it safe to ASSuME that I can determine that there is another user
using my PowerPoint object if the thread count is greater than the number
reported by List 1?

Howard Kaikow
05-22-2005, 03:05 PM
Not yet there, the code from the KB article is enumerating Windows, not processes, so doesn't handle case where presentation count = 0.

Howard Kaikow
05-22-2005, 03:19 PM
Appears that I can do the deed by iterating processes.
Needs further testing.

Later tonight.

Howard Kaikow
06-02-2005, 12:17 PM
Eureka, I think!

I believe that I can demonstrate how to detect whether there is 1, or more
than 1, use of Powerpoint, but I want to convert the code to C#, then VB
.NET, then VB 6 before I post a test.

This was interesting, but exhausting.

Killian
06-06-2005, 05:36 AM
Hi Howard,

just to let you know I'm following your progress with great interest :thumb

Howard Kaikow
06-06-2005, 06:27 AM
Hi Howard,

just to let you know I'm following your progress with great interest :thumb

I now have code in C++ .NET, C#, VB .NET and VB 6 that provides the info needed to test my hypothesis.

I need to try the code with PPT 97, 2000, 2002 and 2003 for validity.

Howard Kaikow
06-12-2005, 12:25 PM
Well, I've run a test in PowerPoint 97, 2000, 2002, and 2003.

Same resuls in all four (with 1 exception in, surprise!, PPT 97),

It appears that there's NEVER a REQUIREMENT to use Quit or to set the PPT
object to nothing. Indeed, one can get in trouble doing so.

Of course, one might wish to do so in the context of a larger/longer running
app to free resources, BUT, as my headbanging these past few weeks has confirmed, it is NEVER safe to release a PPT object, especially if one's code created a NEW instance, as such an action could wipe other uses of PPT, in particualr thaose started by other code.

The only case that bothers me is when you create a NEW non-visible instance of PPT in code AND then some other code creates another non-visible intance which adds a presentation (not visible because the PPT is not visible), if you shut down the code WITHOUT a QUIT, PPT goes away anyway. However, this does not occur with PPT 97. Idendependently of whether onelikes the idea of PPT affecting another session with a non-visible presentation, that's a rather significant difference between PPT 97 and later versions, You'd think that the Officve 2000 documentation would have pointed this out. Has it? I've not checked.

The code I used for my test is given below, it's a hack, so it's not pretty.

Put the code in a VB 6 Form, you could tweak the code and run it from other apps, but NOT from PowerPoint.

Form has 7 buttons and 1 listbox:

btnPPTNew: "Create New PPT"
btnQuitNewPPT: "Quit New PPT"
btnPPTVisible: "Start a Visible PPT"
btnPPTNonVisible: "Start a Non-Visible PPT"
btnPPTNonVisibleWithPresentation: "Start a Non-Visible PPT with
presentation"
btnByeBye: "ByeBye!"
btnClearList: "Clear List"

lstActions

A file named PPTTest.txt is created in the directory in which the code is
executed.

Use the Task Manger to watch when PowerPoint is created/deleted.


' Author: Howard Kaikow
' Author URL: http://www.standards.com/
' Date: 12 June 2005
Option Explicit
Private Const LB_SETHORIZONTALEXTENT = &H194

Private Declare Function SendMessage Lib "user32" Alias _
"SendMessageA" (ByVal hWnd As Long, ByVal wMsg As Long, _
ByVal wParam As Long, lParam As Any) As Long

Private appPPTOriginal As PowerPoint.Application
Private appPPTVisible As PowerPoint.Application
Private appPPTNonVisible As PowerPoint.Application
Private appPPTNonVisibleWithPresentation As PowerPoint.Application

Private intFile As Integer

Private Sub btnPPTNonVisibleWithPresentation_Click()
Dim presPPT As PowerPoint.Presentation
On Error Resume Next
Set appPPTNonVisibleWithPresentation = GetObject(, "PowerPoint.Application")
If Err.Number = 0 Then
Print #intFile, "PowerPoint: Another non-Visible, with presentation, instance was created."
lstActions.AddItem "PowerPoint: Another non-Visible, with presentation, instance was created."
Debug.Print "PowerPoint: Another non-Visible, with presentation, instance was created."
Set presPPT = appPPTNonVisibleWithPresentation.Presentations.Add
Else
Print #intFile, "PowerPoint: Another non-Visible, with presentation, Huh!"
lstActions.AddItem "PowerPoint: Another non-Visible, with presentation, Huh!"
Debug.Print "PowerPoint: Another non-Visible, with presentation, Huh!"
End If
On Error GoTo 0
btnPPTNonVisibleWithPresentation.Visible = False
End Sub

Private Sub btnPPTNew_Click()
On Error Resume Next
'Check if PowerPoint is running
Do
Set appPPTOriginal = GetObject(, "PowerPoint.Application")
If Err.Number = 0 Then
If vbCancel = MsgBox("Stop all running instances of PowerPoint, and then choose Retry to continue this test." _
& vbCrLf & vbCrLf & "Or choose Cancel to cancel this test.", vbInformation + vbRetryCancel, "PowerPoint is currently running") Then
Unload Me
Exit Sub
End If
Else
Err.Clear
Exit Do
End If
Loop
' Verify that PowerPoint is still not running
Set appPPTOriginal = GetObject(, "PowerPoint.Application")
If Err.Number = 0 Then
MsgBox "PowerPoint is still running", vbInformation + vbOK, "Test cancelled"
Unload Me
Else
Set appPPTOriginal = New PowerPoint.Application
Print #intFile, "PowerPoint: New non-visible instance was created."
lstActions.AddItem "PowerPoint: New non-visible instance was created."
Debug.Print "PowerPoint: New non-visible instance was created."
btnPPTNew.Visible = False
btnPPTVisible.Visible = True
btnPPTNonVisible.Visible = True
btnPPTNonVisibleWithPresentation.Visible = True
btnQuitNewPPT.Visible = True
End If
On Error GoTo 0
btnClearList.Visible = True
End Sub

Private Sub btnPPTVisible_Click()
On Error Resume Next
Set appPPTVisible = GetObject(, "PowerPoint.Application")
If Err.Number = 0 Then
Print #intFile, "PowerPoint: Visible instance was created."
lstActions.AddItem "PowerPoint: Visible instance was created."
Debug.Print "PowerPoint: Visible instance was created."
appPPTVisible.Visible = True
Else
Print #intFile, "PowerPoint: Visible Huh!"
lstActions.AddItem "PowerPoint: Visible Huh!"
Debug.Print "PowerPoint: Visible Huh!"
End If
On Error GoTo 0
btnPPTVisible.Visible = False
End Sub

Private Sub btnPPTNonVisible_Click()
On Error Resume Next
Set appPPTNonVisible = GetObject(, "PowerPoint.Application")
If Err.Number = 0 Then
Print #intFile, "PowerPoint: Another non-Visible instance was created."
lstActions.AddItem "PowerPoint: Another non-Visible instance was created."
Debug.Print "PowerPoint: Another non-Visible instance was created."
Else
Print #intFile, "PowerPoint: Another non-Visible Huh!"
lstActions.AddItem "PowerPoint: Another non-Visible Huh!"
Debug.Print "PowerPoint: Another non-Visible Huh!"
End If
On Error GoTo 0
btnPPTNonVisible.Visible = False
End Sub

Private Sub btnQuitNewPPT_Click()
If TypeName(appPPTOriginal) = "Application" Then
With appPPTOriginal
If .Presentations.Count = 0 Then
Print #intFile, "PowerPoint: (0)New non-visible instance was Quit."
lstActions.AddItem "PowerPoint: (0)New non-visible instance was Quit."
Debug.Print "PowerPoint: (0)New non-visible instance was Quit."
Else
Print #intFile, "PowerPoint: (not 0)New non-visible instance was Quit."
lstActions.AddItem "PowerPoint: (not 0)New non-visible instance was Quit."
Debug.Print "PowerPoint: (not 0)New non-visible instance was Quit."
End If
.Quit
Set appPPTOriginal = Nothing
End With
btnQuitNewPPT.Visible = False
Unload Me
End If
End Sub

Private Sub Form_Load()
btnClearList.Visible = False
btnPPTVisible.Visible = False
btnPPTNonVisible.Visible = False
btnPPTNonVisibleWithPresentation.Visible = False
btnQuitNewPPT.Visible = False
intFile = FreeFile
Open "PPTTest.txt" For Output As #intFile
End Sub

Private Sub Form_Activate()
With lstActions
SendMessage .hWnd, LB_SETHORIZONTALEXTENT, _
ScaleX(.Width, vbTwips, vbPixels) + 150, ByVal 0&
End With
End Sub

Private Sub btnByeBye_Click()
Dim PPTCount As Long
QuitPPT
Unload Me
End Sub

Private Sub QuitPPT()
If TypeName(appPPTOriginal) = "Application" Then
With appPPTOriginal
' Non-visible uses of PowerPoint added AFTER this code created NEW non-visible
' instance get killed if there is no VISIBLE use of PowerPoint.
If .Presentations.Count = 0 Then
Print #intFile, "PowerPoint: (0)New non-visible instance was NOT Quit."
lstActions.AddItem "PowerPoint: (0)New non-visible instance was NOT Quit."
Debug.Print "PowerPoint: (0)New non-visible instance was NOT Quit."
Else
Print #intFile, "PowerPoint: (not 0)New non-visible instance was NOT Quit."
lstActions.AddItem "PowerPoint: (not 0)New non-visible instance was NOT Quit."
Debug.Print "PowerPoint: (not 0)New non-visible instance was NOT Quit."
End If
End With
End If
End Sub

Private Sub btnClearList_Click()
lstActions.Clear
End Sub

Private Sub Form_Unload(Cancel As Integer)
On Error Resume Next
Close #intFile
On Error GoTo 0
End Sub