Does Application.Projects.Count have a known bug?

A

Ancient Brit

Hi

I have a macro that works fine (thanks to help received in the recent past
from august personages here :)) - unless I run it twice in succession...

The application is Project 2003 and the project file consists of a single
project (~300 tasks) with a single embedded subproject (~100 tasks). For more
background see "How to filter for milestones *and* their predecessors?" from
12/13/2007 et seq.

The macro works as expected when run once - it identifies milestone tasks in
both project and subproject and their respective predecessors and sets a flag
accordingly for each task/subtask in a column created for the purpose. These
flagged tasks are known as "milestone-related".

If however the macro is run again, it fails with an error 1004 (unexpected
error in method - the method being Projects(variable).Activate) and the
culprit appears to be Application.Projects.Count, which shows a value that is
one more than the correct count, causing Projects(variable).Activate to fail.

If I close the file and re-open it and run the macro, everything works fine
again.

I've searched around to see if I can find anything about a possible
Application.Projects.Count bug but so far no joy.

The workaround for now is to tell the users "don't run it more than once"
but of course that's not satisfactory...

Grateful for any clues,

Peter
 
A

Ancient Brit

Oops - it would help to know that "variable" in Projects(variable).Activate
has its value set by Application.Projects.Count... Sorry!
 
J

Jan De Messemaeker

Hi AB,

Never noted such a bug nor can I reproduce it.
I remember having had trouble with the .activate method though, when trying
to activate a project that already was the activeproject; unfortunately I
don't remember which version it was.
So... which version are you running?
Can you publish the code such that I can find a workaround if necessary?

Greetings,

--
Jan De Messemaeker
Microsoft Project Most Valuable Professional
+32 495 300 620
For availability check:
http://users.online.be/prom-ade/Calendar.pdf
 
A

Ancient Brit

Hi Jan

I've tried this with the following versions of MSP2003 Standard:

11.2.2005.1801.15, SP2 (on two different machines, MSP installed separately)
11.1.2004.1707.15, SP1 (on a third machine)

The code is basically this:

Sub MarkMRT2()

'Global Version testing bug
'
Dim pbMsg, pbStyle, pbTitle, pbHelp, pbCtxt, pbResponse, pbMyString 'Set
up for confirmation to proceed

Dim pbProjectCount As Long, pbProjectCountLoop As Long, pbTaskCount As
Long, pbNames As String 'Set up for counting and naming projects to work with

Dim pbTasks As Tasks 'Set up for collection of tasks

Dim pbTask As Task 'Set up for one task

pbProjectCount = Application.Projects.Count 'Get number of open projects

If pbProjectCount = 0 Then 'If the project count is zero we have nothing
to work with!

MsgBox "No projects open!", vbCritical
End 'Exit the macro altogether

End If

'We have at least one project to work with, and there should be one or more
embedded subprojects
'Now test to see if the column MRT exists already

SelectRow Row:=1, RowRelative:=False

foundMRTflag = "No MRT"
For Each fName In ActiveSelection.FieldNameList
If fName = "MRT" Then
foundMRTflag = "MRT Found"
End If
Next fName
If foundMRTflag = "No MRT" Then
MsgBox "No MRT column! Cannot proceed...", vbCritical
End 'Exit the macro altogether
End If

'Now expand all tasks and make sure we're filtering on all tasks

OutlineShowTasks expandinsertedprojects:=True 'Code from John - makes
sure all tasks are included by expanding all project and subprojects. NB: Do
not save changes to the embedded Subproject!

FilterApply Name:="&All Tasks"

'Code that checks and lists the project and subprojects that are about to be
used (i.e.embeds) and asks for clearance to continue
'First step: check for projects

pbNames = "" 'Set the master string to empty

For pbProjectCountLoop = 1 To pbProjectCount
Projects(pbProjectCountLoop).Activate
pbNames = pbNames & Str(pbProjectCountLoop) & ") " &
Projects(pbProjectCountLoop).FullName & vbCrLf
i = 1
For Each sp In ActiveProject.Subprojects
pbNames = pbNames & Str(pbProjectCountLoop) & "." & Str(i) & ")
" & sp.SourceProject.Name & vbCrLf
i = i + 1
Next sp

Next pbProjectCountLoop

pbMsg = "Global MarkMRT: These are the projects/subprojects to be used.
Do you want to continue ?" & vbCrLf & vbCrLf & pbNames 'Define message.
pbStyle = vbYesNo + vbCritical + vbDefaultButton2 'Define buttons.
pbTitle = "MarkMRT: Confirm OK to Proceed" 'Define title.

pbResponse = MsgBox(pbMsg, pbStyle, pbTitle)
If pbResponse = vbYes Then 'User chose Yes.
pbMyString = "Yes" 'Fall through and do the macro
Else 'User chose No.
pbMyString = "No" 'Exit the macro altogether
End
End If

'We are good to go.

SelectTaskColumn Column:="Flag1" 'Selects the MRT column ready to clear
it, but also makes sure that every task, embedded subprojects included, is
selected so that For Each will work correctly

EditClear 'Clear out the current settings for all MRT entries; they will
be recalculated from scratch every time

'Begin work loop:

Set pbTasks = ActiveSelection.Tasks

For Each pbTask In pbTasks 'Modified code from John - this is one way to
work on every single task, including those in embedded subprojects if at
least one column is selected and all tasks are expanded

If Not pbTask Is Nothing Then 'As long as we're not looking at a
blank or empty task...

If pbTask.Milestone = True Then 'Only do the next process if
this task is a milestone

pbTask.Flag1 = True 'Mark the task as an MRT (we want to
mark both Milestones and their attendant Predecessors)

If Not pbTask.PredecessorTasks Is Nothing Then 'If there are
Predecessors for this milestone...

Set pbPredecessor = pbTask.PredecessorTasks 'Get the
Predecessors

For Each pbItem In pbPredecessor 'Loop through the list
of Predecessors

pbItem.Flag1 = True 'Mark the task that is a
Predecessor of the Milestone as an MRT.

Next pbItem

End If

End If

End If

Next pbTask

'End work loop

'User may want to filter to show just the MRT=Yes

If MsgBox("Do you want to filter on MRT now?", vbYesNo, "MarkMRT
Request") = vbYes Then

FilterEdit Name:="MRT=Yes", TaskFilter:=True, Create:=True,
OverwriteExisting:=True, FieldName:="Flag1", Test:="equals", Value:="Yes",
ShowInMenu:=False, ShowSummaryTasks:=False
FilterApply Name:="MRT=Yes"

End If

End Sub

I've commented minimally to give some idea of what each section does, just
FYI.

I experimented a little further by adding several subprojects as embeds, and
the Project count seems to incorporate all the subprojects as projects, which
explains the value of the count, but not why the subprojects are being
classified as projects.

Grateful for any ideas.

Best,

Peter
 
J

Jan De Messemaeker

Hi AB,

Did some further testing because a memory from the past suddenly haunted me.
When you have a master with inserted projects, and nothing else open,
projects.count will yield 1.
Once however you address these projects individually in VBA (for instance, I
used subprojects(1).sourceproject), the project appears in the projects list
in VBE and behold, projects.count becomes 2.
I can't imagine why this is so (I gave up wondering why any software lab in
the world does things years ago, long before I knew about Microsoft) but
once you know it's like that you can adapt your code..
There must be an alternative for the activate instruction, and BTW wouldn't
on error resume next solve the problem?
Hope this helps,

--
Jan De Messemaeker
Microsoft Project Most Valuable Professional
+32 495 300 620
For availability check:
http://users.online.be/prom-ade/Calendar.pdf
 
A

Ancient Brit

Hi Jan

So it does appear to be a bug? I did wonder...

It puzzled me that the value appeared to "carry over" into what should have
been a fresh run of the macro, and since Application.Projects.Count is
read-only it can't be "fixed" by anything I can do (or think of doing).

I'm not sure that On Error Resume Next would solve the problem in this case,
(although I will try it, just to be sure) because the incorrect value in the
counter will never subsequently address the project correctly (it should
never exceed 1 and it already has) and I suspect will just end up trapped in
a loop that will eventually end, but not before I'm covered in cobwebs :)

I'm loth to create a kludge (test for Application.Projects.Count exceeding 1
and reset the variable pbProjectCount) but that may be my only option for now
- at least it's better than telling users not to re-run the macro :)

Thanks for your feedback - it always helps when I get confirmation that I'm
not totally insane :)

Best,

Peter
 
A

Ancient Brit

Hi Jan

Just a follow-up to the suggestion to use On Error Resume Next.

That has the same effect as commenting out the line that triggers the 1004
error (Projects(pbProjectCountLoop).Activate) - i.e., the first pass works
OK, subsequent passes treat all embedded subprojects as if they are also
projects.

That seems a little weird to me - that a subproject can be a project at the
same time (so essentially the parent inherits from the child, which I thought
violated object hierarchy) - but I'm not even remotely an expert so under the
MS Project Object Model it may be perfectly permissible for all I know.

I guess by removing the feedback to the user I could mask what's going on
but that just seems to be begging for trouble IMHO :)

Unless anyone else has any bright ideas I'll work on this some more and see
if I can find a way to resolve the issue, and post a follow-up if I do.

I did think I'd spotted one path to redemption when I noticed that there was
a Deactivate (whoopee!) but that turns out to be an event while Activate is a
method (d'oh!) and so there's no support for
Projects(pbProjectCountLoop).Deactivate. Poo.

Best,

Peter
 
A

Ancient Brit

A follow-up to the follow-up:

It seems that Projects().Activate is not the culprit - I simplified the code
(kept the same project, which contains four embedded subprojects, all
read-only), and the macro worked without problems. It can be run repeatedly
and works exactly as expected.

The core code is this:

Sub testing()

Dim ProjectPointer As Long, pbNames As String

For ProjectPointer = 1 To Projects.Count
Projects(ProjectPointer).Activate
pbNames = pbNames & Projects(ProjectPointer).FullName & vbCrLf & vbCrLf
Next ProjectPointer

MsgBox pbNames

End Sub

Where the error comes in is when the name of each subproject is retrieved. I
added some code to extract the name of each embedded subproject and
incorporate it into the string pbNames (the numbers simply allow me to keep
track of the projects):

Sub testing()

Dim ProjectPointer As Long, pbNames As String

For ProjectPointer = 1 To Projects.Count
Projects(ProjectPointer).Activate
pbNames = pbNames & Projects(ProjectPointer).FullName & vbCrLf & vbCrLf
i = 1
For Each SubProjectName In ActiveProject.Subprojects
pbNames = pbNames & Str(ProjectPointer) & "." & Str(i) & ") " &
SubProjectName.SourceProject.Name & vbCrLf
i = i + 1
Next SubProjectName
Next ProjectPointer

MsgBox pbNames

End Sub

The first pass through works OK; subsequent attempts to run the macro
generate the 1004 error.

I can't see why requesting the subproject name should change the project
count...

Best,

Peter
 
A

Ancient Brit

An interim result...

After much banging around in the garden shed, it begins to look as though
Sourceproject.Name is definitely bugged (or at least, is not behaving as I
would expect), but InsertedProjectSummary.Name doesn't seem to trigger the
error seen.

I have some verification to undertake (to make sure that both Names are
identical in all cases) and some regression testing to devise and run, but
it's looking promising.

Best,

Peter
 
A

Ancient Brit

InsertedProjectSummary.Name turns out to be something of a red herring. It
doesn't reflect the current file name, but appears to show the original name
before the file was renamed... Either way, it fails as a solution because
it's not completely right.

However, InsertedProjectSummary.Subproject does contain the correct file
name for the embedded subproject, albeit with the full path included. A bit
of exploring reveals that .Path also contains the same full information
(equivalent to Fullname, I guess). To make it clearer, revising the code
segment below gives:

i = 1
For Each SubProjectName In ActiveProject.Subprojects
pbNames = pbNames & Str(ProjectPointer) & "." & Str(i) & ") " &
SubProjectName.Path & vbCrLf
i = i + 1
Next SubProjectName

The next logical step is to extract just the file name portion of the full
path, which should be relatively straightforward (it's everything after the
rightmost backslash separator in the path, and there's more than one way of
extracting that substring).

So I'd consider this resolved. Thanks to Jan for having confirmed that there
is an oddity on behavior.

Best,

Peter
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top