MS Office Forum / Word / Programming / November 2007
Error if macro "Run", No error if single stepped! Help?
|
|
Thread rating:  |
Julian - 29 Nov 2007 20:38 GMT It was a reliable piece of code, and stuff around it has changed but the key point is that if I "Run" the macro (which copies from a bookmark in one doc and pastes the text into another) the pastespecial fails (empty clipboard), but if I single step through the code it all works perfectly (NB I have over-ridden the Ctrl-V keyboard shortcut for paste, but what should that have to do with it?).
I removed all the modules from Normal.dot and then re-imported them (not sure if I quit in-between though) but on this occasion it made no difference... have I missed a trick?
Ideas?
TIA
Julian
fumei - 29 Nov 2007 21:07 GMT "It was a reliable piece of code"....except we have no idea what that was/is.
"I have over-ridden the Ctrl-V keyboard shortcut for paste" - hmmm, which means you have overridden the actual command. You do not just override the shortcut, you override the command. I would say that this may have something to do with it.
Again, since we have no idea what you have done, it is virtually impossible to suggest anything.
>It was a reliable piece of code, and stuff around it has changed but the key >point is that if I "Run" the macro (which copies from a bookmark in one doc [quoted text clipped - 12 lines] > >Julian Julian - 29 Nov 2007 23:49 GMT The key diagnostic to me was that the code ran perfectly when single stepped but failed when run either by Alt-F8 from Word or as "Run" in the VBE... given which I thought the specifics probably irrelevant (but included some info just in case)
I also have my own event handling, but that is specifically disabled at the start of the macro...
I know that Word VBA can get corrupted and can sometimes behave oddly, but I think I eliminated that possibility by the remove/reimport.
However, allow me to clarify as per your questions
> "It was a reliable piece of code"....except we have no idea what that > was/is. I don't really know whether you wanted the actual code, I thought that might be a bit OTT but here's the key section...
this_doc = ActiveDocument.Name Documents.add DocumentType:=wdNewBlankDocument temp_doc = ActiveDocument.Name wd_total = 0 For i = 0 To UBound(bkmrk, 2) Documents(this_doc).Activate Documents(this_doc).Bookmarks(bkmrk(0, i)).Select Selection.Copy Documents(temp_doc).Activate On Error Resume Next ' if null copied, paste fails - there should never actually be a null source Selection.PasteSpecial DataType:=wdPasteText ' there are colons there, they're just thin in the Windows Mail newsreading font... On Error GoTo 0 bkmrk(1, i) = Documents(temp_doc).ComputeStatistics(wdStatisticWords) Selection.WholeStory Selection.Delete unit:=wdCharacter, count:=1 wd_total = wd_total + bkmrk(1, i) Next Documents(this_doc).Activate
overall, the macro iterates through a set of bookmarks spanning a single column in a number of tables, places the plain text in another document, counts the words, stores the results in the bookmark array and then later writes it out a a log file.
> "I have over-ridden the Ctrl-V keyboard shortcut for paste" - hmmm, which > means you have overridden the actual command. You do not just override > the > shortcut, you override the command. I would say that this may have > something > to do with it. Revised cut/copy/paste macros are all variants of the following, which serves to generate special journal entries according to where the action takes place I have only set new key-bindings - I was unaware that altering a keybinding causes the underlying command to get redirected too, especially when the command is not invoked by keystrokes. Can you confirm that's what you are saying?
Sub myCopy() If Selection.Type = wdNoSelection Or Selection.Type = wdSelectionIP Then Exit Sub If Not (Selection.Document.ActiveWindow.View.SplitSpecial = wdPaneRevisions And Selection.Document.ActiveWindow.ActivePane.index = 2) Then createCutCopyPasteEditPoint On Error Resume Next Selection.Copy If Err.Number <> 0 Then Application.StatusBar = "Copy Failed!" End If On Error GoTo 0 End If End Sub
If you have any ideas I'd love to hear them
Thanks
Julian
Jay Freedman - 30 Nov 2007 01:43 GMT Because you're passing your text through the Windows clipboard, you could have a timing problem, especially if the documents and/or the bits of text inside the bookmarks are fairly large.
A solution for this is to use two ranges, one in the document containing the bookmarks and the other in the temporary document, and assign the .FormattedText property of one to the .FormattedText property of the other. This accomplishes the same thing as a copy/paste without passing through the clipboard -- and probably without the problem.
The following snippet does the same thing as the code you showed, but without all the overhead (and with some considerable streamlining in other areas as well):
Dim this_doc As Document Dim temp_doc As Document Dim src_rg As Range Dim dest_rg As Range Dim wd_total As Long, i As Long Dim bkmrk(1, 2) As Variant ' some code to fill column 0 of bkmrk with bookmark names bkmrk(0, 0) = "bk1" bkmrk(0, 1) = "bk2" bkmrk(0, 2) = "bk3" Set this_doc = ActiveDocument Set temp_doc = Documents.Add wd_total = 0 For i = 0 To UBound(bkmrk, 2) Set src_rg = this_doc.Bookmarks(bkmrk(0, i)).Range Set dest_rg = temp_doc.Range ' This does a "copy/paste" without the clipboard; ' since it overwrites anything that's already there, ' you don't have to delete it when you're done. dest_rg.FormattedText = src_rg.FormattedText bkmrk(1, i) = dest_rg.ComputeStatistics(wdStatisticWords) wd_total = wd_total + bkmrk(1, i) Next i ' discard the temp_doc, which reactivates this_doc temp_doc.Close Savechanges:=wdDoNotSaveChanges
>The key diagnostic to me was that the code ran perfectly when single stepped >but failed when run either by Alt-F8 from Word or as "Run" in the VBE... [quoted text clipped - 78 lines] > >Julian -- Regards, Jay Freedman Microsoft Word MVP FAQ: http://word.mvps.org Email cannot be acknowledged; please post all follow-ups to the newsgroup so all may benefit.
Julian - 30 Nov 2007 08:48 GMT Jay - that was *really* useful - thanks.
> Because you're passing your text through the Windows clipboard, you > could have a timing problem, especially if the documents and/or the > bits of text inside the bookmarks are fairly large. I had *assumed* that copy would not return until it had completed... the document *is* karge (>750pp, ~6000 comments, ~19MB), and some of the bookmarks are large (18,000 words excluding associated comments and other text in adjacent columns) although the 1st bookmark on ~p3 which also fails is small ~240 words in a 10 row, 5 column table). A timing problem makes a great deal of sense.
> The following snippet does the same thing as the code you showed, but > without all the overhead (and with some considerable streamlining in > other areas as well): "Considerable streamlining" LOL! My bricks respond to gravity perfectly well thank you <g> [I'm supposed to be writing, not coding <g>, the supporting extensions to word I have written for commenting functionality, in-table outlining, journalling and other stuff do run to several thousand lines... and yes, I know it shouldn't all be in normal.dot but...]
However, back the problem and potential solution. I tried your code and found a couple of problems
1/ I said that the bookmarks span a column, but didn't make it clear that there are several columns... the range based FormattedText assignment takes all text between the bookmark ends not just that in the bookmarked column... which I think is why I did a select/copy/paste - bookmark ranges in tables mark table spanning end-endranges, but when selected, the range corresponds to the visually inspired expectation (i.e. that a bookmark in one column contains only what is in that column....)
2a The ComputerStatistics on the result completely kills Word (Word 2002)... seen from the VBE it just locked up, trying again and looking at Word and manually Ctrl-A selecting all the text that had appeared, I chose Tools...Word Count and after coming up with a count (incorrect, BTW) Word then attempted repagination and hung. The only suggestion I had for that was perhaps the presence of Unicode characters carried across from Col 1... 2b/ When I tried to test that hypothesis Word locked up on the FormattedText assignment, eating 50% of CPU time. I need to give it more thought and test data other than the real data... why it worked (as far as the range assignment) once and never since I have no idea either...
NB Col 1 of my table provides "outlining" capabilities with Unicode block triangles pointing right and down to indicate collapsed/expanded rows; Cols 3 & 4 are never both "visible" - either one or the other is set to a very small width and hidden text, and Col 4 may contain embedded images; Col 5 contains the text of interest with maybe 1-50+ potentially overlapping/intersecting (in scope) comments, which may contain hyperlinks (and possibly other stuff)
I think it might be easier/quicker just to try getting data from the clipboard through another object and waiting until that is successful before doing a paste - if it is a timing issue that approach could confirm and resolve at the same time... 'tis such things that lead to the atrophy of elegance...
Or is there some other way to avoid such timing issues - can one make VBA code sync rather than async?
Very grateful for your input though
Julian --
> Regards, > Jay Freedman > Microsoft Word MVP FAQ: http://word.mvps.org > Email cannot be acknowledged; please post all follow-ups to the newsgroup > so all may benefit. Julian - 30 Nov 2007 12:03 GMT Update...
Because the range of a bookmarked column spans all cells between the bookmark ends I went back to Selection.Copy. There are still issues of "elegance" insofar as in principle I ought to allow for bookmarks that contain no text... but since there's no way of testing that range directly I choose to assume pro tem that they are not empty.
Firstly I initialise the clipboard by finding and copying the first non-null word in the document and placing it on the clipboard, i.e. the clipboard is not empty and contains text different to the first bookmark text.
Then for each bookmark I use a data object and GetClipText to get the text - if no error fine, otherwise I set the receviving variable to "" (not interested in why there might be an error given the above!)
Then select the bookmark and copy...(with Stop on error...) turn off error trapping and loop on GetFromClipboard while err.number <> 0 (should also have an emergency get out, but I settled for DoEvents to allow me to Break into the loop...). Bookmark text (and only the text in that column) is now on the clipboard
When I can get from the clipboard I do so, and if the text return is not the same as previously (hence the initialisation) I know I did in fact successfully copy to the clipboard, so then I assign the text to the destination range and do the word count...
I can see however that if it were a timing issue this shouldn't have worked either... but it does, suggesting that perhaps it wasn't timing, that Copy is synchronous and that it was some other peculiarity...
Anyway, I can now count words again! Takes ~30s to work through the ~34 tables to completion - and the result is right. It's still a brick but at least it's falling straight down again.
But - if you do know of a better way to deal with a column range directly let me know!
Thanks for the input - just needed a little prod along...
Julian
PS Would it help if I painted wings on my bricks? <g>
Jay Freedman - 30 Nov 2007 16:49 GMT Winged bricks... hmmm... nice idea!
If your code works now, you may not want to mess with it. :-)
If you want to pursue improvements in performance, here are some suggestions. I would still look for a way to avoid the clipboard, because it's a cross-process call that will always be inefficient. In fact, you don't need to copy the text to a new document at all, because the Range object has the same ComputeStatistics method as the Document object has -- in fact, I used it in the code I posted before. So you can call it on any properly defined Range in the original document, and jettison the whole copying apparatus.
Now, you're correct about the miserable behavior of Ranges when dealing with table columns -- a Range extends from the starting point into the next cell to its right, to the end of the row, into the first cell of the next row, and so on until the end. There's no such thing as a Range that includes only a single column in a multicolumn table. So... treat the bookmark as a series of Range objects, each one covering only a single cell in the desired column. Iterate down the column, totaling the word counts as you go.
There are a couple of ways to do the iteration. Probably the simplest one is to find the starting and ending row numbers and just go through the cells in that series in a For...Next loop.
Dim bkRg As Range, subRg As Range Dim bkName As String Dim oTbl As Table Dim wdct As Long Dim ncol As Integer Dim nrowtop As Integer, nrowbot As Integer Dim nCurrRow As Integer
bkName = "bk2"
If Not ActiveDocument.Bookmarks.Exists(bkName) Or _ (Not ActiveDocument.Bookmarks(bkName).Range _ .Information(wdWithInTable)) Then Exit Sub End If
Set bkRg = ActiveDocument.Bookmarks(bkName).Range Set oTbl = bkRg.Tables(1) ' the table containing the bookmark ncol = bkRg.Information(wdStartOfRangeColumnNumber) nrowtop = bkRg.Information(wdStartOfRangeRowNumber) nrowbot = bkRg.Information(wdEndOfRangeRowNumber)
wdct = 0 For nCurrRow = nrowtop To nrowbot Set subRg = oTbl.Cell(nCurrRow, ncol).Range ' exclude the end-of-cell marker subRg.MoveEnd wdCharacter, -1 wdct = wdct + subRg.ComputeStatistics(wdStatisticWords) Next
MsgBox bkName & " contains " & wdct & " words"
 Signature Regards, Jay Freedman Microsoft Word MVP FAQ: http://word.mvps.org Email cannot be acknowledged; please post all follow-ups to the newsgroup so all may benefit.
> Update... > [quoted text clipped - 39 lines] > > PS Would it help if I painted wings on my bricks? <g> Julian - 30 Nov 2007 17:24 GMT Oh great! Thanks a bunch! There's nothing more annoying that *knowing* - not merely suspecting - there's a better way to do things but not really being able to justify the effort of putting something that works into even better shape <g> {"Let not the best be the enemy of the good")
Missed the fact that the computestatistics applies equally to ranges otherwise I would have already done the same myself... of course I would, wouldn't I...? Probably due to finding something that works and then stopping the search...
See http://berossus.blogspot.com/2007/07/not-last-place-you-look.html for related insights <g>
Nice work - very nice... expect to be bothered with more tricky Word VBA in due course!
Now... if we only used the same naming conventions I could just grab your code and...
Thanks for the help :)
Julian
|
|
|