<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-1800518423097919889</id><updated>2011-12-03T06:13:47.576Z</updated><category term='String-Handling'/><category term='VBA'/><category term='Introduction'/><category term='Fuzzy-Matching'/><title type='text'>Excellerando</title><subtitle type='html'>A programmer's scrapbook devoted to Microsoft Excel and its embedded language, Visual Basic for Applications.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://excellerando.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1800518423097919889/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://excellerando.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Nigel Heffernan</name><uri>http://www.blogger.com/profile/08954578765691578714</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://1.bp.blogspot.com/_B9BAdln8o_A/SYY_TkYyu4I/AAAAAAAAAAs/z5CQ01NUtTI/S220/Cropped+Blog+Shot.JPG'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>9</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-1800518423097919889.post-9037826132066895412</id><published>2011-08-30T19:46:00.008+01:00</published><updated>2011-08-30T21:08:23.526+01:00</updated><title type='text'>Demising VBA: the caret and stick approach</title><content type='html'>&lt;P Align="justify"&gt;I haven't been posting much in the last year, because the work I'm doing is under contract and I don't own the source code... So I can't publish it here. I can't complain: everyone's tightened up the IP and disclosure rules in their contracts and workng quietly beats hell out of not working.&lt;br /&gt;&lt;br /&gt;So, in the absence of any actual content from me, here's a little gem from &lt;A Href="http://www.tushar-mehta.com/publish_train/xl_vba_cases/1016%20Office%202010%20VBA.shtml" alt="Link to the full article Tushar Mehta's site"&gt;Tushar Mehta, on VBA in Office 2010&lt;/A&gt;:&lt;/P&gt;&lt;br /&gt;&lt;cite src="http://www.tushar-mehta.com/publish_train/xl_vba_cases/1016%20Office%202010%20VBA.shtml"&gt;&lt;P Align="justify"&gt;To support this new data type, Microsoft also introduced the CLngLng function, the VarType constant vbLongLong, and the DefType statement DefLngLng.  The type declaration character is ^.  This can cause problems while typing VBA statements that use the exponentiation operator, which is also ^.&lt;/P&gt;&lt;/cite&gt;&lt;P Align="justify"&gt;&lt;br /&gt;Feel free to read the details... And remember to insert a space before indicating an exponent in your calculations.&lt;br /&gt;&lt;br /&gt;I wonder what else is out there, waiting to be discovered. I wonder, also, whether any other financial institution has made the transition to Office 2010, outside of a few 'early adopters' who amuse and entertain their IT staff with their ingenuity. We've only got about 50,000 regular users, worldwide - regular as in 'I use it every day in a critical part of my job', and probably twice that number of occasionals, so we're talking about a fair chunk of revenue for Microsoft here, and you'd think they'd make it easy for us to migrate.&lt;br /&gt;&lt;br /&gt;Actually, you know Microsoft: you know damn' well they've made it difficult.  &lt;br /&gt;&lt;br /&gt;Everything we've done in terms of macros and reports, all the way up to add-ins and  fully-developed applications, will need some testing - that's standard for all Office upgrades, even service patches - and we test the complex ones quite thoroughly. You'd think there might be tools, and scripts, and maybe even checklists and case studies. But no: Microsoft is unlike any other software vendor. And we start this job *knowing* that everything we've build that uses the application menubar is broken, by design, by Microsoft's insistence on imposing the new 'Ribbon Bar' with no concession whatsoever to supporting backward compatibility... I predict thet we'll be using Office 2003 well into 2012; and that there are major companies as big as us, or bigger, who'll be using it in 2014.&lt;br /&gt;&lt;br /&gt;Ultimately, Microsoft will kill off VBA and this is just another nail in the coffin; they are, if you will, putting the caret before the hearse.&lt;/P&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1800518423097919889-9037826132066895412?l=excellerando.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://excellerando.blogspot.com/feeds/9037826132066895412/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://excellerando.blogspot.com/2011/08/demising-vba-caret-and-stick-approach.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1800518423097919889/posts/default/9037826132066895412'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1800518423097919889/posts/default/9037826132066895412'/><link rel='alternate' type='text/html' href='http://excellerando.blogspot.com/2011/08/demising-vba-caret-and-stick-approach.html' title='Demising VBA: the caret and stick approach'/><author><name>Nigel Heffernan</name><uri>http://www.blogger.com/profile/08954578765691578714</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://1.bp.blogspot.com/_B9BAdln8o_A/SYY_TkYyu4I/AAAAAAAAAAs/z5CQ01NUtTI/S220/Cropped+Blog+Shot.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1800518423097919889.post-7335916728247102616</id><published>2010-03-01T21:14:00.010Z</published><updated>2010-03-02T15:05:09.877Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='VBA'/><category scheme='http://www.blogger.com/atom/ns#' term='Fuzzy-Matching'/><category scheme='http://www.blogger.com/atom/ns#' term='String-Handling'/><title type='text'>VLookup() with fuzzy-matching to get a 'closest match' result</title><content type='html'>&lt;P Align='justify'&gt;&lt;br /&gt;Ever had to look up a name or an address in a list that doesn't quite match, so the standard Excel 'VLookup()' and 'Match()' functions don't help you?&lt;br /&gt;&lt;/P&gt;Here's the solution:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_B9BAdln8o_A/S4w8o8tq44I/AAAAAAAAAB4/EAylSzldMqE/s1600-h/FuncArgs2.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 285px;" src="http://4.bp.blogspot.com/_B9BAdln8o_A/S4w8o8tq44I/AAAAAAAAAB4/EAylSzldMqE/s400/FuncArgs2.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5443792723774202754" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;P Align='justify'&gt;The answer is 'Fuzzy Matching', a process of applying rules and picking out a 'best fit'. In the case of text - words, addresses, alphanumeric codes like ISIN identifiers for shares, bonds and other financial instruments - the best approach is the Levenshtein Edit Distance algorithm, a measure of how many characters were changed or moved to get from one text to another; but I've gone for a simplified approach that adds up how much of text A is made up of recognisable fragments of text B. &lt;br /&gt;&lt;/P&gt;&lt;P Align='justify'&gt;It works surprisingly well, but there are some limitations. There's a more detailed discussion of this in the preceding post: feel free to offer some suggestions and comments there: what you're reading &lt;i&gt;here&lt;/i&gt; is the application of these abstract principles to spreadsheets. Click on the image: it'll &lt;i&gt;show&lt;/i&gt; you how the function is used.&lt;br /&gt;&lt;/P&gt;&lt;P Align='justify'&gt;What's missing is a version of &lt;b&gt;Match()&lt;/b&gt; (you can code that up for yourselves), and a dedicated 'FuzzyVLookupAddress()' function, tweaked to deal with the peculiar things that we do to postal addresses to make them extraordinarily difficult for computers (and spreadsheets!) to read. Instead, I've provided a crude &lt;b&gt;'NormaliseAddress'&lt;/b&gt; function, which standardises all those troublesome Aves, Avenues, Streets, Saints and St.'s. Apply it to the addresses in your list (and to the search term you're trying to look up) and let me know how you get on.&lt;br /&gt;&lt;/P&gt;&lt;P Align='justify'&gt;Enough witter: the code's below. It's been tested for cut-and-paste out of Blogger, but there's always a health warning: Blogger will munge the line breaks, and so will whatever you're using to view this post, especially if it's an RSS feed.&lt;br /&gt;&lt;/P&gt;&lt;br /&gt;&lt;br /&gt;&lt;font face="FixedSys, System, Terminal, Courier New"&gt;&lt;br /&gt;&lt;br /&gt;Option Explicit&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Public Function FuzzyVLookup(Lookup_Value As String, _&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Table_Array As Variant, _ &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Optional Col_Index_Num As Integer = 1, _&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Optional Compare As VbCompareMethod = vbTextCompare _ &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;) As Variant&lt;br /&gt;&lt;!--&lt;br /&gt;Attribute FuzzyVLookup.VB_Description = "Find the best match for a given string in column 1 of an array of data\r\nThis is functionally similar to VLookup, but it returns the best match, not the first exact match\r\nThis function is not case-sensitive, unless you specify 'Compare' as 0 or vbBinaryCompare\r\n\r\n' If your data quality is poor, you are advised to display the retrieved index value from column 1 and use the FuzzyMatchScore() function on this index value to reveal the fuzzy-matching 'score' and discard all results below a threshold value."&lt;br /&gt;--&gt;&lt;font color="Green"&gt; &lt;br /&gt;' Find the best match for a given string in column 1 of an array of data obtained from an Excel range&lt;br /&gt;' This is functionally similar to VLookup, but it returns the best match, not the first exact match&lt;br /&gt;' This function is not case-sensitive, unless you specify 'Compare' as 0 or vbBinaryCompare&lt;br /&gt;&lt;br /&gt;' If your data quality is poor, you are advised to display the retrieved index value from column 1&lt;br /&gt;' and use the FuzzyMatchScore() function on this index value to reveal the fuzzy-matching 'score' and&lt;br /&gt;' discard all results below a threshold value. Feel free to code up a 'threshold' parameter!&lt;br /&gt;&lt;br /&gt;' If you are looking up names and addresses, use the NormaliseAddress() function on your search term and&lt;br /&gt;' searched population to standardise abbreviations and word-order conventions used in British addresses.&lt;br /&gt;&lt;br /&gt;' THIS CODE IS IN THE PUBLIC DOMAIN&lt;/FONT&gt;&lt;br /&gt;&lt;br /&gt;Application.Volatile False&lt;br /&gt;&lt;br /&gt;Dim dblBestMatch As Double&lt;br /&gt;&lt;br /&gt;Dim iRowBest&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;As Integer&lt;br /&gt;Dim dblMatch&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;As Double&lt;br /&gt;Dim iRow&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;As Integer&lt;br /&gt;Dim strTest&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; As String&lt;br /&gt;Dim strInput&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;As String&lt;br /&gt;&lt;br /&gt;Dim iStartCol&amp;nbsp;&amp;nbsp; As Integer&lt;br /&gt;Dim iEndCol&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; As Integer&lt;br /&gt;Dim iOffset&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; As Integer&lt;br /&gt;&lt;br /&gt;If InStr(TypeName(Table_Array), "(") + InStr(1, TypeName(Table_Array), "Range", vbTextCompare) &lt; 1 Then&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color="Green"&gt; 'Table_Array is not an array &lt;/FONT&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; FuzzyVLookup = "#VALUE"&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Exit Function&lt;br /&gt;End If&lt;br /&gt;&lt;br /&gt;If InStr(1, TypeName(Table_Array), "Range", vbTextCompare) &gt; 0 Then&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Table_Array = Table_Array.Value&lt;br /&gt;End If&lt;br /&gt;&lt;font color="Green"&gt; &lt;br /&gt;' If you get a subscript-out-of-bounds error here, you're using a vector instead&lt;br /&gt;' of the 2-dimensional array that is the default 'Value' property of an Excel range.&lt;/FONT&gt;&lt;br /&gt;&lt;br /&gt;iStartCol = LBound(Table_Array, 2)&lt;br /&gt;iEndCol = UBound(Table_Array, 2)&lt;br /&gt;iOffset = 1 - iStartCol&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Col_Index_Num = Col_Index_Num - iOffset&lt;br /&gt;&lt;br /&gt;If Col_Index_Num &gt; iEndCol Or Col_Index_Num &lt; iStartCol Then&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color="Green"&gt; 'Out-of-bounds&lt;/FONT&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; FuzzyVLookup = "#VALUE"&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Exit Function&lt;br /&gt;End If&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;strInput = UCase(Lookup_Value)&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;iRowBest = -1&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;dblBestMatch = 0&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;For iRow = LBound(Table_Array, 1) To UBound(Table_Array, 1)&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;strTest = ""&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;strTest = Table_Array(iRow, iStartCol)&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;dblMatch = 0&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;dblMatch = FuzzyMatchScore(strInput, strTest, Compare)&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;If dblMatch = 1 Then ' Bail out on finding an exact match&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;iRowBest = iRow&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Exit For&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;End If&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;If dblMatch &gt; dblBestMatch Then&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;dblBestMatch = dblMatch&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;iRowBest = iRow&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;End If&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Next iRow&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;If iRowBest = -1 Then&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;FuzzyVLookup = "#NO MATCH"&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Exit Function&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;End If&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;FuzzyVLookup = Table_Array(iRowBest, Col_Index_Num)&lt;br /&gt;&lt;br /&gt;End Function&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;Public Function FuzzyHLookup(Lookup_Value As String, _ &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Table_Array As Variant, _ &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Optional Row_Index_Num As Integer = 1, _ &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Optional Compare As VbCompareMethod = vbTextCompare)&lt;br /&gt;&lt;font color="Green"&gt; &lt;br /&gt;' Find the best match for a given string in Row 1 of an array of data obtained from an Excel range&lt;br /&gt;' This is functionally similar to HLookup, but it returns the best match, not the first exact match&lt;br /&gt;' This function is not case-sensitive, unless you specify 'Compare' as vbTextBinary.&lt;br /&gt;&lt;br /&gt;' If your data quality is poor, you are advised to display the retrieved index value from row 1&lt;br /&gt;' and use the FuzzyMatchScore() function on this index value to reveal the fuzzy-matching 'score' and&lt;br /&gt;' discard all results below a threshold value. Feel free to code up a 'threshold' parameter!&lt;br /&gt;&lt;br /&gt;' If you are looking up names and addresses, use the NormaliseAddress() function on your search term and&lt;br /&gt;' searched population to standardise abbreviations and word-order conventions used in British addresses.&lt;br /&gt;&lt;br /&gt;' THIS CODE IS IN THE PUBLIC DOMAIN&lt;/FONT&gt;&lt;br /&gt;&lt;br /&gt;Application.Volatile False&lt;br /&gt;&lt;br /&gt;Dim dblBestMatch As Double&lt;br /&gt;&lt;br /&gt;Dim iColBest&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;As Integer&lt;br /&gt;Dim dblMatch&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;As Double&lt;br /&gt;Dim iCol&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;As Integer&lt;br /&gt;Dim strTest&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; As String&lt;br /&gt;Dim strInput&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;As String&lt;br /&gt;&lt;br /&gt;Dim iStartRow&amp;nbsp;&amp;nbsp; As Integer&lt;br /&gt;Dim iEndRow&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; As Integer&lt;br /&gt;Dim iOffset&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; As Integer&lt;br /&gt;&lt;br /&gt;If InStr(TypeName(Table_Array), "(") + InStr(1, TypeName(Table_Array), "Range", vbTextCompare) &lt; 1 Then&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color="Green"&gt; 'Table_Array is not an array &lt;/FONT&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; FuzzyHLookup = "#VALUE"&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Exit Function&lt;br /&gt;End If&lt;br /&gt;&lt;br /&gt;If InStr(1, TypeName(Table_Array), "Range", vbTextCompare) &gt; 0 Then&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Table_Array = Table_Array.Value&lt;br /&gt;End If&lt;br /&gt;&lt;font color="Green"&gt; &lt;br /&gt;' If you get a subscript-out-of-bounds error here, you're using a vector instead&lt;br /&gt;' of the 2-dimensional array that is the default 'Value' property of an Excel range.&lt;/FONT&gt;&lt;br /&gt;&lt;br /&gt;iStartRow = LBound(Table_Array, 1)&lt;br /&gt;iEndRow = UBound(Table_Array, 1)&lt;br /&gt;iOffset = 1 - iStartRow&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Row_Index_Num = Row_Index_Num - iOffset&lt;br /&gt;&lt;br /&gt;If Row_Index_Num &gt; iEndRow Or Row_Index_Num &lt; iStartRow Then&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color="Green"&gt; 'Out-of-bounds &lt;/FONT&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; FuzzyHLookup = "#VALUE"&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Exit Function&lt;br /&gt;End If&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;strInput = UCase(Lookup_Value)&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;iColBest = -1&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;dblBestMatch = 0&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;For iCol = LBound(Table_Array, 2) To UBound(Table_Array, 2)&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;strTest = ""&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;strTest = Table_Array(iStartRow, iCol)&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;dblMatch = 0&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;dblMatch = FuzzyMatchScore(strInput, strTest, Compare)&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;If dblMatch = 1 Then ' Bail out on finding an exact match&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;iColBest = iCol&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Exit For&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;End If&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;If dblMatch &gt; dblBestMatch Then&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;dblBestMatch = dblMatch&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;iColBest = iCol&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;End If&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Next iCol&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;If iColBest = -1 Then&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;FuzzyHLookup = "#NO MATCH"&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Exit Function&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;End If&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;FuzzyHLookup = Table_Array(Row_Index_Num, iColBest)&lt;br /&gt;&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Public Function FuzzyMatchScore(ByVal str1 As String, _ &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ByVal str2 As String, _ &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Optional Compare As VbCompareMethod = vbTextCompare _&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;) As Double&lt;br /&gt;&lt;font color="Green"&gt; &lt;br /&gt;' Returns an estimate of how closely word 1 matches word 2: this is best displayed as a percentage&lt;br /&gt;' This is calculated as the fraction of the longer string that is made up of recognisable fragments of the shorter string&lt;br /&gt;' There is no support for wildcards and regular expressions. Case-sensitivity is determined by the 'compare' parameter&lt;br /&gt;&lt;br /&gt;' THIS CODE IS IN THE PUBLIC DOMAIN&lt;/FONT&gt;&lt;br /&gt;&lt;br /&gt;Application.Volatile False&lt;br /&gt;&lt;br /&gt;Dim maxLen As Integer&lt;br /&gt;Dim minLen As Integer&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;If str1 = str2 Then&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;FuzzyMatchScore = 1#&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Exit Function&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;End If&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;If Len(str1) &gt; Len(str2) Then&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;maxLen = Len(str1)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;minLen = Len(str2)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Else&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;maxLen = Len(str2)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;minLen = Len(str1)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;End If&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;If Len(str1) = 0 Or Len(str2) = 0 Then&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;FuzzyMatchScore = 0#&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Else&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;FuzzyMatchScore = 0#&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;FuzzyMatchScore = SumOfCommonStrings(str1, str2, Compare) / maxLen&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;End If&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Public Function SumOfCommonStrings( _&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ByVal s1 As String, _&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ByVal s2 As String, _&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Optional Compare As VBA.VbCompareMethod = vbTextCompare, _&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Optional iScore As Integer = 0 _&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;) As Integer&lt;br /&gt;&lt;br /&gt;Application.Volatile False&lt;br /&gt;&lt;font color="Green"&gt;&lt;br /&gt;' N.Heffernan 06 June 2006 (somewhere over Newfoundland)&lt;br /&gt;' THIS CODE IS IN THE PUBLIC DOMAIN&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;' Function to measure how much of String 1 is made up of substrings found in String 2&lt;br /&gt;&lt;br /&gt;' This function uses a modified Longest Common String algorithm.&lt;br /&gt;' Simple LCS algorithms are unduly sensitive to single-letter&lt;br /&gt;' deletions/changes near the midpoint of the test words, eg:&lt;br /&gt;' Wednesday is obviously closer to WedXesday on an edit-distance&lt;br /&gt;' basis than it is to WednesXXX. So it would be better to score&lt;br /&gt;' the 'Wed' as well as the 'esday' and add up the total matched&lt;br /&gt;&lt;br /&gt;' Watch out for strings of differing lengths:&lt;br /&gt;'&lt;br /&gt;'&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;SumOfCommonStrings("Wednesday", "WednesXXXday")&lt;br /&gt;'&lt;br /&gt;' This scores the same as:&lt;br /&gt;'&lt;br /&gt;'&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; SumOfCommonStrings("Wednesday", "Wednesday")&lt;br /&gt;'&lt;br /&gt;' So make sure the calling function uses the length of the longest&lt;br /&gt;' string when calculating the degree of similarity from this score.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;' This is coded for clarity, not for performance.&lt;/FONT&gt;&lt;br /&gt;&lt;br /&gt;Dim arr() As Integer&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;' Scoring matrix&lt;br /&gt;Dim n As Integer&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;' length of s1&lt;br /&gt;Dim m As Integer&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;' length of s2&lt;br /&gt;Dim i As Integer&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;' start position in s1&lt;br /&gt;Dim j As Integer&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;' start position in s2&lt;br /&gt;Dim subs1 As String&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ' a substring of s1&lt;br /&gt;Dim len1 As Integer&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ' length of subs1&lt;br /&gt;&lt;br /&gt;Dim sBefore1&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;' documented in the code&lt;br /&gt;Dim sBefore2&lt;br /&gt;Dim sAfter1&lt;br /&gt;Dim sAfter2&lt;br /&gt;&lt;br /&gt;Dim s3 As String&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;SumOfCommonStrings = iScore&lt;br /&gt;&lt;br /&gt;n = Len(s1)&lt;br /&gt;m = Len(s2)&lt;br /&gt;&lt;br /&gt;If s1 = s2 Then&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;SumOfCommonStrings = n&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Exit Function&lt;br /&gt;End If&lt;br /&gt;&lt;br /&gt;If n = 0 Or m = 0 Then&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Exit Function&lt;br /&gt;End If&lt;br /&gt;&lt;br /&gt;&lt;font color="Green"&gt;'s1 should always be the shorter of the two strings:&lt;/FONT&gt;&lt;br /&gt;If n &gt; m Then&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;s3 = s2&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;s2 = s1&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;s1 = s3&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;n = Len(s1)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;m = Len(s2)&lt;br /&gt;End If&lt;br /&gt;&lt;br /&gt;n = Len(s1)&lt;br /&gt;m = Len(s2)&lt;br /&gt;&lt;br /&gt;&lt;font color="Green"&gt;' Special case: s1 is n exact substring of s2&lt;/FONT&gt;&lt;br /&gt;If InStr(1, s2, s1, Compare) Then&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;SumOfCommonStrings = n&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Exit Function&lt;br /&gt;End If&lt;br /&gt;&lt;br /&gt;For len1 = n To 1 Step -1&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;For i = 1 To n - len1 + 1&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;subs1 = Mid(s1, i, len1)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;j = 0&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;j = InStr(1, s2, subs1, Compare)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;If j &gt; 0 Then&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color="Green"&gt;' We've found a matching substring...&lt;/FONT&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;iScore = iScore + len1&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color="Green"&gt;' Now clip out this substring from s1 and s2...&lt;/FONT&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color="Green"&gt;' And search the fragments before and after this excision:&lt;/FONT&gt;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;If i &gt; 1 And j &gt; 1 Then&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;sBefore1 = left(s1, i - 1)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;sBefore2 = left(s2, j - 1)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;iScore = SumOfCommonStrings(sBefore1, _&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;sBefore2, _&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Compare, _&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;iScore)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;End If&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;If i + len1 &lt; n And j + len1 &lt; m Then&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;sAfter1 = right(s1, n + 1 - i - len1)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;sAfter2 = right(s2, m + 1 - j - len1)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;iScore = SumOfCommonStrings(sAfter1, _&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;sAfter2, _&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Compare, _&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;iScore)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;End If&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;SumOfCommonStrings = iScore&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Exit Function&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;End If&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Next&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Next&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Private Function Minimum(ByVal a As Integer, _&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ByVal b As Integer, _&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ByVal c As Integer) As Integer&lt;br /&gt;Dim min As Integer&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;min = a&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;If b &lt; min Then&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;min = b&lt;br /&gt;&amp;nbsp;&amp;nbsp;End If&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;If c &lt; min Then&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;min = c&lt;br /&gt;&amp;nbsp;&amp;nbsp;End If&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;Minimum = min&lt;br /&gt;&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Public Function NormaliseAddress(ByVal strAddress As String) As String&lt;br /&gt;Application.Volatile False &lt;font color="Green"&gt;&lt;br /&gt;' This function is intended to remove or standardise common phrases&lt;br /&gt;' and abbreviations used in British postal addresses, allowing the use&lt;br /&gt;' of string-comparison algorithms in lists of names and addresses.&lt;br /&gt;&lt;br /&gt;' Developers in other countries should review the word list used here,&lt;br /&gt;' as conventions probably differ in your local language or dialect.&lt;/FONT&gt;&lt;br /&gt;&lt;br /&gt;strAddress = " " &amp; UCase(strAddress) &amp; " "&lt;br /&gt;&lt;br /&gt;strAddress = Substitute(strAddress, ",", " ")&lt;br /&gt;strAddress = Substitute(strAddress, ".", " ")&lt;br /&gt;strAddress = Substitute(strAddress, "-", " ")&lt;br /&gt;strAddress = Substitute(strAddress, vbCrLf, " ")&lt;br /&gt;strAddress = Substitute(strAddress, " BLVD ", " BOULEVARD ")&lt;br /&gt;strAddress = Substitute(strAddress, " BVD ", " BOULEVARD ")&lt;br /&gt;strAddress = Substitute(strAddress, " AV ", " AVENUE ")&lt;br /&gt;strAddress = Substitute(strAddress, " AVE ", " AVENUE ")&lt;br /&gt;strAddress = Substitute(strAddress, " RD ", " ROAD ")&lt;br /&gt;strAddress = Substitute(strAddress, " WY ", " WAY ")&lt;br /&gt;strAddress = Substitute(strAddress, " EST ", " ESTATE ")&lt;br /&gt;strAddress = Substitute(strAddress, " PL ", " PLACE ")&lt;br /&gt;strAddress = Substitute(strAddress, " PK ", " PARK ")&lt;br /&gt;strAddress = Substitute(strAddress, " HSE ", " HOUSE ")&lt;br /&gt;strAddress = Substitute(strAddress, " H0 ", " HOUSE ")&lt;br /&gt;strAddress = Substitute(strAddress, " GDNS ", " GARDENS ")&lt;br /&gt;&lt;br /&gt;strAddress = Substitute(strAddress, "&amp;", "AND")&lt;br /&gt;strAddress = Substitute(strAddress, " LIMITED ", " LTD ")&lt;br /&gt;strAddress = Substitute(strAddress, " COMPANY ", " CO ")&lt;br /&gt;strAddress = Substitute(strAddress, " CORPORATION ", " CORP ")&lt;br /&gt;strAddress = Substitute(strAddress, " T/A ", " TA ")&lt;br /&gt;strAddress = Substitute(strAddress, " TRADING AS ", " TA ")&lt;br /&gt;&lt;font color="Green"&gt;&lt;br /&gt;' Common personal titles: these are often applied inconsistently or&lt;br /&gt;' omitted, and must therefore be removed. Specific applications may&lt;br /&gt;' require additional titles and their abbreviations - military rank,&lt;br /&gt;' academic titles and degrees, courtesy titles of the aristocracy,&lt;br /&gt;' knighthoods and honours (particularly for lists of civil servants)&lt;/FONT&gt;&lt;br /&gt;&lt;br /&gt;strAddress = Substitute(strAddress, " ESQ ", " ")&lt;br /&gt;strAddress = Substitute(strAddress, " MR ", " ")&lt;br /&gt;strAddress = Substitute(strAddress, " MRS ", " ")&lt;br /&gt;strAddress = Substitute(strAddress, " MISS ", " ")&lt;br /&gt;strAddress = Substitute(strAddress, " MS ", " ")&lt;br /&gt;strAddress = Substitute(strAddress, " MESSRS ", " ")&lt;br /&gt;strAddress = Substitute(strAddress, " SIR ", " ")&lt;br /&gt;strAddress = Substitute(strAddress, " OF ", " ")&lt;br /&gt;strAddress = Substitute(strAddress, " DR ", " ")&lt;br /&gt;strAddress = Substitute(strAddress, " OR ", " ")&lt;br /&gt;strAddress = Substitute(strAddress, " IN ", " ")&lt;br /&gt;strAddress = Substitute(strAddress, " THE ", " ")&lt;br /&gt;strAddress = Substitute(strAddress, " REVEREND ", " REV ")&lt;br /&gt;strAddress = Substitute(strAddress, " REVERENT ", " REV ")&lt;br /&gt;strAddress = Substitute(strAddress, " HONOURABLE ", " HON ")&lt;br /&gt;strAddress = Substitute(strAddress, " BROS ", " BROTHERS ")&lt;br /&gt;strAddress = Substitute(strAddress, " ASSOC ", " ASSOCIATION ")&lt;br /&gt;strAddress = Substitute(strAddress, " ASSN ", " ASSOCIATION ")&lt;br /&gt;&lt;font color="Green"&gt;&lt;br /&gt;' Standardising 'St.', 'St', and 'Street'. Note that there are over 40 English&lt;br /&gt;' towns and place names that contain or consist entirely of the word 'Street'.&lt;br /&gt;' In addition, 'St' is a common abbreviation for 'Saint' in addresses.&lt;br /&gt;&lt;br /&gt;' I have never seen a list of addresses where 'Street' and 'St' were used in a&lt;br /&gt;' consistent way, and the only workable solution is to delete them all:&lt;/FONT&gt;&lt;br /&gt;&lt;br /&gt;strAddress = Substitute(strAddress, " STREET ", " ")&lt;br /&gt;strAddress = Substitute(strAddress, " ST ", " ")&lt;br /&gt;strAddress = Substitute(strAddress, " STR ", " ")&lt;br /&gt;&lt;br /&gt;Do While InStr(strAddress, "&amp;nbsp;&amp;nbsp;") &gt; 0&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;strAddress = Substitute(strAddress, "&amp;nbsp;&amp;nbsp;", " ")&lt;br /&gt;Loop&lt;br /&gt;&lt;br /&gt;strAddress = Trim(strAddress)&lt;br /&gt;&lt;br /&gt;NormaliseAddress = strAddress&lt;br /&gt;&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Public Function StripChars(myString As String, ParamArray Exceptions()) As String&lt;br /&gt;&lt;font color="Green"&gt;&lt;br /&gt;' Strip out all non-alphanumeric characters from a string in a single pass&lt;br /&gt;' Exceptions parameters allow you to retain specific characters (eg: spaces)&lt;br /&gt;&lt;br /&gt;' THIS CODE IS IN THE PUBLIC DOMAIN&lt;/FONT&gt;&lt;br /&gt;&lt;br /&gt;Application.Volatile False&lt;br /&gt;&lt;br /&gt;Dim i As Integer&lt;br /&gt;Dim iLen As Integer&lt;br /&gt;Dim chrA As String * 1&lt;br /&gt;Dim intA As Integer&lt;br /&gt;Dim j As Integer&lt;br /&gt;Dim iStart As Integer&lt;br /&gt;Dim iEnd As Integer&lt;br /&gt;&lt;br /&gt;If Not IsEmpty(Exceptions()) Then&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;iStart = LBound(Exceptions)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;iEnd = UBound(Exceptions)&lt;br /&gt;End If&lt;br /&gt;&lt;br /&gt;iLen = Len(myString)&lt;br /&gt;&lt;br /&gt;For i = 1 To iLen&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;chrA = Mid(myString, i, 1)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;intA = Asc(chrA)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Select Case intA&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Case 48 To 57, 65 To 90, 97 To 122&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;StripChars = StripChars &amp; chrA&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Case Else&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;If Not IsEmpty(Exceptions()) Then&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;For j = iStart To iEnd&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;If chrA = Exceptions(j) Then&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;StripChars = StripChars &amp; chrA&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Exit For ' j&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;End If&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Next j&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;End If&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;End Select&lt;br /&gt;Next i&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Private Function Substitute(ByVal Text As String, _&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ByVal Old_Text As String, _&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ByVal New_Text As String, _&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Optional Instance As Long = 0, _&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Optional Compare As VbCompareMethod = vbTextCompare _&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;) As String&lt;br /&gt;&lt;br /&gt;&lt;font color="Green"&gt;&lt;br /&gt;' Replace all instances (or the nth instance ) of 'Old' text with 'New'&lt;br /&gt;' Unlike VB.Mid$ this method is not sensitive to length and can replace ALL instances&lt;br /&gt;' This is not exposed as a Public function because there is an Excel Worksheet function&lt;br /&gt;' called Substitute(). However, Workheet Functions have length constraints.&lt;br /&gt;&lt;br /&gt;' THIS CODE IS IN THE PUBLIC DOMAIN&lt;/FONT&gt;&lt;br /&gt;&lt;br /&gt;Dim iStart As Long&lt;br /&gt;Dim iEnd As Long&lt;br /&gt;Dim iLen As Long&lt;br /&gt;Dim iInstance As Long&lt;br /&gt;Dim strOut As String&lt;br /&gt;&lt;br /&gt;iLen = Len(Old_Text)&lt;br /&gt;&lt;br /&gt;If iLen = 0 Then&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Substitute = Text&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Exit Function&lt;br /&gt;End If&lt;br /&gt;&lt;br /&gt;iEnd = 0&lt;br /&gt;iStart = 1&lt;br /&gt;&lt;br /&gt;iEnd = InStr(iStart, Text, Old_Text, Compare)&lt;br /&gt;&lt;br /&gt;If iEnd = 0 Then&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Substitute = Text&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Exit Function&lt;br /&gt;End If&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;strOut = ""&lt;br /&gt;&lt;br /&gt;Do Until iEnd = 0&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;strOut = strOut &amp; Mid$(Text, iStart, iEnd - iStart)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;iInstance = iInstance + 1&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;If Instance = 0 Or Instance = iInstance Then&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;strOut = strOut &amp; New_Text&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Else&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;strOut = strOut &amp; Mid$(Text, iEnd, Len(Old_Text))&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;End If&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;iStart = iEnd + iLen&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;iEnd = InStr(iStart, Text, Old_Text, Compare)&lt;br /&gt;&lt;br /&gt;Loop&lt;br /&gt;&lt;br /&gt;iLen = Len(Text)&lt;br /&gt;strOut = strOut &amp; Mid$(Text, iStart, iLen - iEnd)&lt;br /&gt;&lt;br /&gt;Substitute = strOut&lt;br /&gt;&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;&lt;/FONT&gt;&lt;br /&gt;&lt;br /&gt;&lt;P Align='justify'&gt;&lt;br /&gt;This is something I coded up on an obscure personal blog a couple of years ago: I get one or two enquiries about it every year (mostly appreciative) so I've tidied it up, tested it more thoroughly, and released it into the wild on Excellerando.&lt;br /&gt;&lt;/P&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1800518423097919889-7335916728247102616?l=excellerando.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://excellerando.blogspot.com/feeds/7335916728247102616/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://excellerando.blogspot.com/2010/03/vlookup-with-fuzzy-matching-to-get.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1800518423097919889/posts/default/7335916728247102616'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1800518423097919889/posts/default/7335916728247102616'/><link rel='alternate' type='text/html' href='http://excellerando.blogspot.com/2010/03/vlookup-with-fuzzy-matching-to-get.html' title='VLookup() with fuzzy-matching to get a &apos;closest match&apos; result'/><author><name>Nigel Heffernan</name><uri>http://www.blogger.com/profile/08954578765691578714</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://1.bp.blogspot.com/_B9BAdln8o_A/SYY_TkYyu4I/AAAAAAAAAAs/z5CQ01NUtTI/S220/Cropped+Blog+Shot.JPG'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_B9BAdln8o_A/S4w8o8tq44I/AAAAAAAAAB4/EAylSzldMqE/s72-c/FuncArgs2.jpg' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1800518423097919889.post-7081468001749343711</id><published>2010-02-27T11:07:00.003Z</published><updated>2010-03-01T21:13:49.586Z</updated><title type='text'>String-Comparison in VBA: a modified Longest-Common-String approach</title><content type='html'>&lt;B&gt;Summary:&lt;/B&gt;&lt;p align="justify"&gt;I discuss the use of a sum-of-longest-common-strings algorithm to measure the degree of difference between strings. This is efficient in VBA, and can be used as a the basis as a closest-match alternative to VLookup and Match.&lt;br /&gt;&lt;/P&gt;&lt;br /&gt;&lt;B&gt;The Details...&lt;/B&gt;&lt;p align="justify"&gt;A couple of years ago, I looked at writing a fuzzy-matching version of VLookup, to return the closest match to a search string rather than the #NA() that comes back from the standard Excel function. I posted it in an obscure personal blog, and forgot about it. But I'll be posting it here, shortly, and &lt;i&gt;this&lt;/i&gt; post is the introduction to it, with an explanation of the principles and the core VBA function that drives the whole thing.&lt;br /&gt;&lt;/P&gt;&lt;p align="justify"&gt;Originally,I looked at using a Levenshtein 'Edit Distance' algorithm to compare and measure the degree of difference between strings. (Thanks are due to the inestimable Mr. Crowley for pointing me towards some basic C++ and theory-of-algorithms links). But field-testing showed that a simpler and faster approach was required - I needed something that gives consistent results on longer strings, like addresses and sentences, without the need for a separate scoring process that examines the word order.&lt;br /&gt;&lt;/P&gt;&lt;p align="justify"&gt;The simplest approach of all to comparing and scoring for similarity is searching for the longest common string. This has the obvious advantages of speed and simplicity, but it alse has a weak point: simple LCS algorithms are unduly sensitive to single-letter substitutions and deletions near the midpoint of the test word. For example, 'Wed&lt;b&gt;n&lt;/b&gt;esday' is obviously closer to 'Wed&lt;b&gt;X&lt;/b&gt;esday' on an edit-distance basis than it is to 'WednesXXX', but the latter has the longest common string despite having more substitutions; this suggests that it would be better to score the 'Wed' as well as the 'eday', adding up &lt;i&gt;all&lt;/i&gt; the matching substrings, instead of just measuring the longest one. &lt;br /&gt;&lt;/P&gt;&lt;p align="justify"&gt;It turns out that the recursive algorithm I'm using to do this has an embedded sequence-sensitivity; in theory, this is a complication and a pretty heavy hint that there's some error in my logic that I ought to investigate and remove. In practice, a degree of sequence-sensitivity works well when we compare two sentences or phrases: this 'error' is a pretty good proxy for compiling a secondary score based on similarities in their word order.&lt;br /&gt;&lt;/P&gt;&lt;p align="justify"&gt;Which goes to show that serendipidity comes from simplicity and, if you strip out the comments, this function is a commendably compact piece of code:&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;font face="FixedSys, System, Terminal, Courier New"&gt;&lt;br /&gt;Public Function SumOfCommonStrings( _&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ByVal s1 As String, _&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ByVal s2 As String, _&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Optional Compare As VBA.VbCompareMethod = vbTextCompare, _&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Optional iScore As Integer = 0 _&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;) As Integer&lt;br /&gt;&lt;br /&gt;Application.Volatile False&lt;br /&gt;&lt;font color="Green"&gt; &lt;br /&gt;' N.Heffernan 06 June 2006 (somewhere over Newfoundland)&lt;br /&gt;' THIS CODE IS IN THE PUBLIC DOMAIN&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;' Function to measure how much of String 1 is made up of substrings found in String 2&lt;br /&gt;&lt;br /&gt;' This function uses a modified Longest Common String algorithm.&lt;br /&gt;' Simple LCS algorithms are unduly sensitive to single-letter&lt;br /&gt;' deletions/changes near the midpoint of the test words, eg:&lt;br /&gt;' Wednesday is obviously closer to WedXesday on an edit-distance&lt;br /&gt;' basis than it is to WednesXXX. So would it be better to score&lt;br /&gt;' the 'Wed' as well as the 'eday' ?&lt;br /&gt;&lt;br /&gt;' Watch out for strings of differing lengths:&lt;br /&gt;'&lt;br /&gt;'&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;SumOfCommonStrings("Wednesday", "WednesXXXday")&lt;br /&gt;'&lt;br /&gt;' This scores the same as:&lt;br /&gt;'&lt;br /&gt;'&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; SumOfCommonStrings("Wednesday", "Wednesday")&lt;br /&gt;'&lt;br /&gt;' So make sure the calling function uses the length of the longest&lt;br /&gt;' string when calculating the degree of similarity from this score.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;' This is coded for clarity, not for performance. &lt;/FONT&gt;&lt;br /&gt;&lt;br /&gt;Dim arr() As Integer&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color="Green"&gt; ' Scoring matrix &lt;/FONT&gt;&lt;br /&gt;Dim n As Integer&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color="Green"&gt; ' length of s1 &lt;/FONT&gt;&lt;br /&gt;Dim m As Integer&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color="Green"&gt; ' length of s2 &lt;/FONT&gt;&lt;br /&gt;Dim i As Integer&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color="Green"&gt; ' start position in s1 &lt;/FONT&gt;&lt;br /&gt;Dim j As Integer&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color="Green"&gt; ' start position in s2 &lt;/FONT&gt;&lt;br /&gt;Dim subs1 As String&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font color="Green"&gt; ' a substring of s1 &lt;/FONT&gt;&lt;br /&gt;Dim len1 As Integer&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font color="Green"&gt; ' length of subs1 &lt;/FONT&gt;&lt;br /&gt;&lt;br /&gt;Dim sBefore1&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color="Green"&gt; ' documented in the code &lt;/FONT&gt;&lt;br /&gt;Dim sBefore2&lt;br /&gt;Dim sAfter1&lt;br /&gt;Dim sAfter2&lt;br /&gt;&lt;br /&gt;Dim s3 As String&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;SumOfCommonStrings = iScore&lt;br /&gt;&lt;br /&gt;n = Len(s1)&lt;br /&gt;m = Len(s2)&lt;br /&gt;&lt;br /&gt;If s1 = s2 Then&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;SumOfCommonStrings = n&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Exit Function&lt;br /&gt;End If&lt;br /&gt;&lt;br /&gt;If n = 0 Or m = 0 Then&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Exit Function&lt;br /&gt;End If&lt;br /&gt;&lt;font color="Green"&gt;&lt;br /&gt;'s1 should always be the shorter of the two strings: &lt;/FONT&gt;&lt;br /&gt;If n &gt; m Then&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;s3 = s2&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;s2 = s1&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;s1 = s3&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;n = Len(s1)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;m = Len(s2)&lt;br /&gt;End If&lt;br /&gt;&lt;br /&gt;n = Len(s1)&lt;br /&gt;m = Len(s2)&lt;br /&gt;&lt;br /&gt;&lt;font color="Green"&gt;' Special case: s1 is n exact substring of s2 &lt;/FONT&gt;&lt;br /&gt;If InStr(1, s2, s1, Compare) Then&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;SumOfCommonStrings = n&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Exit Function&lt;br /&gt;End If&lt;br /&gt;&lt;br /&gt;For len1 = n To 1 Step -1&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;For i = 1 To n - len1 + 1&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;subs1 = Mid(s1, i, len1)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;j = 0&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;j = InStr(1, s2, subs1, Compare)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;If j &gt; 0 Then&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font color="Green"&gt; ' We've found a matching substring...&lt;/FONT&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;iScore = iScore + len1&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;  &lt;font color="Green"&gt;  &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;' Reinstate this Debug.Print statement to monitor the function:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;' Debug.Print s1 &amp; " substring (len=" &amp; len1 &amp; ") " &amp; subs1 &amp; " in " &amp; s2 &amp; " Scores " &amp; len1&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;' Now clip out this substring from s1 and s2...&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;' However, we can't just concatenate the fragments before and&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;' after this deletion and restart: substrings that span this&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;' artificial join might give spurious matches. So we run the&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;' function on the separate 'before' and 'after' pieces. Note&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;' that running before1 vs before2 and after1 vs after2, without&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;' running before1 vs after2 and before2 vs after1, introduces&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;' a sequence bias. This may be undesirable, as the effect will&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;' be to discard match scores for transposed words in a sentence&lt;/FONT&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;If i &gt; 1 And j &gt; 1 Then&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;sBefore1 = left(s1, i - 1)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;sBefore2 = left(s2, j - 1)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;iScore = SumOfCommonStrings(sBefore1, _&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;sBefore2, _&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Compare, _&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;iScore)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;End If&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;If i + len1 &lt; n And j + len1 &lt; m Then&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;sAfter1 = right(s1, n + 1 - i - len1)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;sAfter2 = right(s2, m + 1 - j - len1)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;iScore = SumOfCommonStrings(sAfter1, _&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;sAfter2, _&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Compare, _&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;iScore)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;End If&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;SumOfCommonStrings = iScore&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color="Green"&gt;' No further recursion: don't double-count substrings of a matched substring!&lt;/FONT&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Exit Function&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color="Green"&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;'Reinstate this 'Else' block to monitor the function:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;'Else&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;' No action required.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;' Debug.Print s1 &amp; " substring (len=" &amp; len1 &amp; ") " &amp; subs1 &amp; " in " &amp; s2 &lt;/FONT&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;End If&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Next&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Next&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;End Function&lt;br /&gt;&lt;/font&gt;&lt;br /&gt;&lt;br /&gt; &lt;br /&gt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;p align="justify"&gt;&lt;br /&gt;There is room for improvement, and I suspect that the embedded sequence sensitivity is a drawback in some applications. Consider these two addresses:&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;The House of Cards,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;11 High Street,&lt;br /&gt;&lt;br /&gt;and&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;House of Cards, The&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;11 High Street&lt;br /&gt;&lt;br /&gt;They are clearly the same address, and this isn't even a typing error: moving 'The' to the end of the line (or titles like 'Mr' and 'Mrs') is accepted secretarial practice in lists that are sorted alphabetically. But my algorithm treats the transposed word 'The' as an insertion, applying a penalty without making any attempt to identify it as a transposition. In fact, it double-counts the transposition as two points of difference - deletion plus insertion - just like the unmodified Levenshtein edit-distance algorithm. So feel free to rewrite my code where it splits the test words into 'before' and 'after' fragments and resumes the search for matching substrings - but be warned, this is not as simple as you might think, and I don't see any obvious analogy with Damerau's extension of the Levenshtein algorithm. In practice the brutal excision of articles and titles from addresses is the most reliable approach.&lt;/P&gt;&lt;br /&gt;&lt;b&gt;A parting shot:&lt;/B&gt;&lt;br /&gt;&lt;p align="justify"&gt;I have a vague suspicion that this sum-of-longest-common-strings algorithm is functionally equivalent to the Levenshtein edit distance, but I lack the logical tools to attempt a formal proof. Would anyone care to offer some pointers? I think its time I moved beyond simple hacks and started putting this stuff on a firmer foundation.&lt;br /&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1800518423097919889-7081468001749343711?l=excellerando.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://excellerando.blogspot.com/feeds/7081468001749343711/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://excellerando.blogspot.com/2010/02/string-comparison-in-vba-modified.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1800518423097919889/posts/default/7081468001749343711'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1800518423097919889/posts/default/7081468001749343711'/><link rel='alternate' type='text/html' href='http://excellerando.blogspot.com/2010/02/string-comparison-in-vba-modified.html' title='String-Comparison in VBA: a modified Longest-Common-String approach'/><author><name>Nigel Heffernan</name><uri>http://www.blogger.com/profile/08954578765691578714</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://1.bp.blogspot.com/_B9BAdln8o_A/SYY_TkYyu4I/AAAAAAAAAAs/z5CQ01NUtTI/S220/Cropped+Blog+Shot.JPG'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1800518423097919889.post-6088396440688871748</id><published>2010-02-26T15:37:00.009Z</published><updated>2010-02-26T16:58:11.728Z</updated><title type='text'>Unprotecting a project using VBA</title><content type='html'>&lt;p&gt;&lt;/p&gt;&lt;p&gt;Ever tried to open another workbook call a macro in it from your VBA code?&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Easy, if the sub or function is declared 'public' at workbook level and is visible as a method of the workbook object. If it isn't (and, sometimes, even if it is) and the VB Project is locked, you'll need to go into the VBE editor and unlock it yourself.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;In short: manual intervention is required.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;For obvious reasons, there's no Project.Unprotect(sPassword) function: obvious, but not good,and definitely not convenient when you've been asked to re-run all the reports in a month of separate daily workbooks.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;We'll gloss over that your office should probably be handling the data and the daily reporting process in a more efficient way: sometimes you get this kind of job and the rest s up to you.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;We'll assume that you know the password and have the right to open and run these files... now what?&lt;br /&gt;&lt;/p&gt;&lt;p&gt;There's code out there to unlock a project using a truly horrible combination of SendKeys() strings. THIS code is marginally better, but not miraculously so: it works on identifying the windows and the handles of the controls, and sending Windows messages using the API functions.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Most of the time the messages work... More often, anyway, than Sendkeys does. And, as we're in a slightly better environment than a keystroke-passer, we can read the results and retry the messages when they fail.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Here's the function:&lt;br /&gt;&lt;br /&gt;&lt;b&gt;fUnlockProject(wbk As Excel.Workbook, strPwd As String) As Boolean&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;I'm assuming that you know how to open a workbook in VBA: if you can't, then this code sample probably isn't for you. Not only is at an advanced topic - API calls and window messages - but we're doing something that VBA really isn't designed to do.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;On top of that, Blogger's HTML editor (whatever RSS feed you're viewing the blog post in!) will have munged at least one of the line breaks and, while I've succeeded in getting thhe code below to copy-and-paste into a new VBA module, I suspect that some of you will get at least one syntax error when you try.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Finally: read the comments below the function header. There's stuff in there that you need to know about the return value, and a hint about passing the workbook object.&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;font face=Courier New&gt;&lt;SPAN style="color:#00007F"&gt;Option&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Explicit&lt;/SPAN&gt;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;Option&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Private&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Module&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#007F00"&gt;' Requires a reference to the library :&lt;/SPAN&gt;&lt;br&gt;&lt;SPAN style="color:#007F00"&gt;'&amp;#160;&amp;#160; Microsoft Visual Basic for Applications Extensibility (v5.3)&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Private&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Declare&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Function&lt;/SPAN&gt; SendMessage &lt;SPAN style="color:#00007F"&gt;Lib&lt;/SPAN&gt; "user32.dll" Alias "SendMessageA" ( _&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;ByVal&lt;/SPAN&gt; hWnd &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Long&lt;/SPAN&gt;, &lt;SPAN style="color:#00007F"&gt;ByVal&lt;/SPAN&gt; wMsg &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Long&lt;/SPAN&gt;, &lt;SPAN style="color:#00007F"&gt;ByVal&lt;/SPAN&gt; wParam &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Long&lt;/SPAN&gt;, &lt;SPAN style="color:#00007F"&gt;ByVal&lt;/SPAN&gt; lParam &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; Long _&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; ) &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Long&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Private&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Declare&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Function&lt;/SPAN&gt; SendMessageStr &lt;SPAN style="color:#00007F"&gt;Lib&lt;/SPAN&gt; "user32.dll" Alias "SendMessageA" ( _&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;ByVal&lt;/SPAN&gt; hWnd &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Long&lt;/SPAN&gt;, &lt;SPAN style="color:#00007F"&gt;ByVal&lt;/SPAN&gt; wMsg &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Long&lt;/SPAN&gt;, &lt;SPAN style="color:#00007F"&gt;ByVal&lt;/SPAN&gt; wParam &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Long&lt;/SPAN&gt;, &lt;SPAN style="color:#00007F"&gt;ByVal&lt;/SPAN&gt; lParam &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; String _&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; ) &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Long&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Private&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Declare&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Function&lt;/SPAN&gt; PostMessage &lt;SPAN style="color:#00007F"&gt;Lib&lt;/SPAN&gt; "user32.dll" Alias "PostMessageA" ( _&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;ByVal&lt;/SPAN&gt; hWnd &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Long&lt;/SPAN&gt;, &lt;SPAN style="color:#00007F"&gt;ByVal&lt;/SPAN&gt; wMsg &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Long&lt;/SPAN&gt;, &lt;SPAN style="color:#00007F"&gt;ByVal&lt;/SPAN&gt; wParam &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; Long, &lt;SPAN style="color:#00007F"&gt;ByVal&lt;/SPAN&gt; lParam &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Long&lt;/SPAN&gt; _&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;) &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Long&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#007F00"&gt;' SetText params for SendMessage and PostMessage:&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#007F00"&gt;' ms-help://MS.VSCC.v80/MS.MSDN.v80/MS.WIN32COM.v10.en/winui/winui/windowsuserinterface/windowing/windows/windowreference/windowmessages/wm_settext.htm&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#007F00"&gt;'&amp;#160;&amp;#160; wParam:&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; This parameter is not used.&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#007F00"&gt;'&amp;#160;&amp;#160; lParam:&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Pointer to a null-terminated string that is the window text.&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#007F00"&gt;'&amp;#160;&amp;#160; Return Value:&amp;#160;&amp;#160; The return value is TRUE if the text is set.&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#007F00"&gt;' API Window Message Constants are documented here:&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#007F00"&gt;' ms-help://MS.VSCC.v80/MS.MSDN.v80/MS.WIN32COM.v10.en/winui/winui/windowsuserinterface/windowing/windows/windowreference/windowmessages/wm_close.htm&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#007F00"&gt;' ms-help://MS.VSCC.v80/MS.MSDN.v80/MS.WIN32COM.v10.en/shellcc/platform/commctls/buttons/buttonreference/buttonmessages/bm_click.htm&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Private&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Declare&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Function&lt;/SPAN&gt; GetWindowTextApi &lt;SPAN style="color:#00007F"&gt;Lib&lt;/SPAN&gt; "user32.dll" Alias "GetWindowTextA" (&lt;SPAN style="color:#00007F"&gt;ByVal&lt;/SPAN&gt; hWnd &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Long&lt;/SPAN&gt;, &lt;SPAN style="color:#00007F"&gt;ByVal&lt;/SPAN&gt; lpString &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;String&lt;/SPAN&gt;, &lt;SPAN style="color:#00007F"&gt;ByVal&lt;/SPAN&gt; cch &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Long&lt;/SPAN&gt;) &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Long&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Private&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Declare&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Function&lt;/SPAN&gt; GetClassNameApi &lt;SPAN style="color:#00007F"&gt;Lib&lt;/SPAN&gt; "user32.dll" Alias "GetClassNameA" (&lt;SPAN style="color:#00007F"&gt;ByVal&lt;/SPAN&gt; hWnd &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Long&lt;/SPAN&gt;, &lt;SPAN style="color:#00007F"&gt;ByVal&lt;/SPAN&gt; lpClassName &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;String&lt;/SPAN&gt;, &lt;SPAN style="color:#00007F"&gt;ByVal&lt;/SPAN&gt; nMaxCount &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Long&lt;/SPAN&gt;) &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Long&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Private&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Const&lt;/SPAN&gt; WM_SETTEXT &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Long&lt;/SPAN&gt; = &amp;HC&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Private&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Const&lt;/SPAN&gt; WM_CLOSE &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Long&lt;/SPAN&gt; = &amp;H10&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Private&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Const&lt;/SPAN&gt; BM_CLICK = &amp;HF5&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Private&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Const&lt;/SPAN&gt; SW_HIDE = 0&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Private&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Const&lt;/SPAN&gt; BM_SETCHECK &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Long&lt;/SPAN&gt; = &amp;HF1&amp;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Private&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Const&lt;/SPAN&gt; BST_UNCHECKED = &amp;H0&amp;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Private&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Const&lt;/SPAN&gt; BST_CHECKED &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Long&lt;/SPAN&gt; = &amp;H1&amp;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Private&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Const&lt;/SPAN&gt; BST_INDETERMINATE = &amp;H2&amp;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Private&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Const&lt;/SPAN&gt; EM_REPLACESEL &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Long&lt;/SPAN&gt; = &amp;HC2&amp;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Private&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Const&lt;/SPAN&gt; HWND_TOPMOST &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Long&lt;/SPAN&gt; = -1&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Private&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Const&lt;/SPAN&gt; SWP_NOACTIVATE &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Long&lt;/SPAN&gt; = &amp;H10&amp;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Private&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Const&lt;/SPAN&gt; SWP_NOMOVE &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Long&lt;/SPAN&gt; = &amp;H2&amp;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Private&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Const&lt;/SPAN&gt; SWP_NOSIZE &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Long&lt;/SPAN&gt; = &amp;H1&amp;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Private&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Const&lt;/SPAN&gt; SWP_SHOWWINDOW &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Long&lt;/SPAN&gt; = &amp;H40&amp;&lt;br&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Private&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Const&lt;/SPAN&gt; TCM_SETCURFOCUS &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Long&lt;/SPAN&gt; = &amp;H1330&amp;&lt;br&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#007F00"&gt;' Default Dialog control IDs&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Private&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Const&lt;/SPAN&gt; IDOK &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; Long = 1&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Private&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Const&lt;/SPAN&gt; IDCANCEL &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; Long = 2&lt;br&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&lt;SPAN style="color:#007F00"&gt;'&amp;#160;&amp;#160;&amp;#160;&amp;#160;Private Declare Function ShowWindow Lib "user32" (ByVal hWnd As &lt;SPAN style="color:#00007F"&gt;Long&lt;/SPAN&gt;, &lt;SPAN style="color:#00007F"&gt;ByVal&lt;/SPAN&gt; nCmdShow As &lt;SPAN style="color:#00007F"&gt;Long&lt;/SPAN&gt;) As &lt;SPAN style="color:#00007F"&gt;Long&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Private&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Declare&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Function&lt;/SPAN&gt; SetFocus &lt;SPAN style="color:#00007F"&gt;Lib&lt;/SPAN&gt; "user32" (&lt;SPAN style="color:#00007F"&gt;ByVal&lt;/SPAN&gt; hWnd &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Long&lt;/SPAN&gt;) &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Long&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Private&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Declare&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Function&lt;/SPAN&gt; FindWindow &lt;SPAN style="color:#00007F"&gt;Lib&lt;/SPAN&gt; "user32.dll" Alias "FindWindowA" ( _&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;ByVal&lt;/SPAN&gt; lpClassName &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; String, &lt;SPAN style="color:#00007F"&gt;ByVal&lt;/SPAN&gt; lpWindowName &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;String&lt;/SPAN&gt; _&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;) &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Long&lt;/SPAN&gt;&lt;br&gt; &lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#007F00"&gt;' ms-help:'MS.VSCC.v80/MS.MSDN.v80/MS.WIN32COM.v10.en/winui/winui/windowsuserinterface/windowing/dialogboxes/dialogboxreference/dialogboxfunctions/getdlgitem.htm&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#007F00"&gt;' Retrieves the handle to a control in the specified dialog box.&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#007F00"&gt;' hDlg&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;: [in] Handle to the dialog box that contains the control.&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#007F00"&gt;' nIDDlgItem: [in] Specifies the identifier of the control to be retrieved.&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#007F00"&gt;' returns&amp;#160;&amp;#160; : The window handle of the specified control indicates success. NULL indicates failure due to an invalid dialog box handle or a nonexistent control.&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Private&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Declare&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Function&lt;/SPAN&gt; GetDlgItem &lt;SPAN style="color:#00007F"&gt;Lib&lt;/SPAN&gt; "user32.dll" (&lt;SPAN style="color:#00007F"&gt;ByVal&lt;/SPAN&gt; hDlg &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Long&lt;/SPAN&gt;, &lt;SPAN style="color:#00007F"&gt;ByVal&lt;/SPAN&gt; nIDDlgItem &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Long&lt;/SPAN&gt;) &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Long&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#007F00"&gt;' ms-help://MS.VSCC.v80/MS.MSDN.v80/MS.WIN32COM.v10.en/winui/winui/windowsuserinterface/windowing/windows/windowreference/windowfunctions/setforegroundwindow.htm&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#007F00"&gt;' If the window was brought to the foreground, the return value is nonzero.&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#007F00"&gt;' If the window was not brought to the foreground, the return value is zero.&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Private&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Declare&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Function&lt;/SPAN&gt; SetForegroundWindow &lt;SPAN style="color:#00007F"&gt;Lib&lt;/SPAN&gt; "user32.dll" (&lt;SPAN style="color:#00007F"&gt;ByVal&lt;/SPAN&gt; hWnd &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Long&lt;/SPAN&gt;) &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Long&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Private&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Declare&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Function&lt;/SPAN&gt; GetTickCount &lt;SPAN style="color:#00007F"&gt;Lib&lt;/SPAN&gt; "kernel32.dll" () &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Long&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Private&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Declare&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Sub&lt;/SPAN&gt; Sleep &lt;SPAN style="color:#00007F"&gt;Lib&lt;/SPAN&gt; "kernel32.dll" (&lt;SPAN style="color:#00007F"&gt;ByVal&lt;/SPAN&gt; dwMilliseconds &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Long&lt;/SPAN&gt;)&lt;br&gt;&lt;br&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Private&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Declare&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Function&lt;/SPAN&gt; CharLower &lt;SPAN style="color:#00007F"&gt;Lib&lt;/SPAN&gt; "user32.dll" Alias "CharLowerA" (&lt;SPAN style="color:#00007F"&gt;ByVal&lt;/SPAN&gt; lpsz &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;String&lt;/SPAN&gt;) &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;String&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Private&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Declare&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Function&lt;/SPAN&gt; CharUpper &lt;SPAN style="color:#00007F"&gt;Lib&lt;/SPAN&gt; "user32.dll" Alias "CharUpperA" (ByVal lpsz &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;String&lt;/SPAN&gt;) &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;String&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#007F00"&gt;' Password windows caption suffix&lt;/SPAN&gt;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;Private&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Const&lt;/SPAN&gt; DLG_PWD_CAP_SUFFIX &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;String&lt;/SPAN&gt; = " Password"&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#007F00"&gt;' Project properties dialog caption suffix&lt;/SPAN&gt;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;Private&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Const&lt;/SPAN&gt; DLG_PRJPROP_CAP_SUFFIX &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;String&lt;/SPAN&gt; = " - Project properties"&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#007F00"&gt;' Project properties dialog hWnd&lt;/SPAN&gt;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;Private&lt;/SPAN&gt; hWndProjectProperties &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; Long&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#007F00"&gt;' Caption of the dialog when a bad password is inserted&lt;/SPAN&gt;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;Private&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Const&lt;/SPAN&gt; DLG_BADPWD_CAP &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;String&lt;/SPAN&gt; = "Project Locked"&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#007F00"&gt;' Caption of the generic VBA error&lt;/SPAN&gt;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;Public&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Const&lt;/SPAN&gt; DLG_VBERROR_CAP &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;String&lt;/SPAN&gt; = "Microsoft Visual Basic"&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#007F00"&gt;' Dialog class&lt;/SPAN&gt;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;Private&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Const&lt;/SPAN&gt; DIALOG_CLS &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; String = "#32770"&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#007F00"&gt;' Password dialog textfield control ID&lt;/SPAN&gt;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;Private&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Const&lt;/SPAN&gt; PWD_DLG_EDIT_ID &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; Long = &amp;H155E&amp;&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#007F00"&gt;' Wait time for the windows search&lt;/SPAN&gt;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;Private&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Const&lt;/SPAN&gt; WAIT_TIME &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; Long = 500&lt;br&gt;&lt;SPAN style="color:#007F00"&gt;'&lt;/SPAN&gt;&lt;/FONT&gt;&lt;br /&gt;&lt;font face=Courier New&gt;&lt;SPAN style="color:#00007F"&gt;Public&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Function&lt;/SPAN&gt; fUnlockProject(wbk &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; Excel.Workbook, strPwd &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;String&lt;/SPAN&gt;) &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Boolean&lt;/SPAN&gt;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;On&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Error&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Resume&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Next&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#007F00"&gt;' Unlock a VB project using a known password.&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#007F00"&gt;' You are advised to pass a wbk parameter that's opened in another Excel Application session.&lt;/SPAN&gt;&lt;br&gt;&lt;SPAN style="color:#007F00"&gt;' This one will probably crash if you try it locally.&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#007F00"&gt;' Returns True if all the dialog boxes were closed (indicating that the app can be safely closed).&lt;/SPAN&gt;&lt;br&gt;&lt;SPAN style="color:#007F00"&gt;' To know if the document project was unlocked successfully, use the .VBProject.Protection property.&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#007F00"&gt;' This code works by manipulating the windows of the VBE password dialogue in VBA.&lt;/SPAN&gt;&lt;br&gt;&lt;SPAN style="color:#007F00"&gt;' It's a step above the widely-published 'SendKeys' code. But that's faint praise:&lt;/SPAN&gt;&lt;br&gt;&lt;SPAN style="color:#007F00"&gt;' it's messy, and you'll soon find out why I use all those 'GoTo ...iRetry' blocks.&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Dim&lt;/SPAN&gt; appExcel &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; Excel.Application&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Dim&lt;/SPAN&gt; vbpProject &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; VBIDE.VBProject&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Dim&lt;/SPAN&gt; vbEditor &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; VBIDE.VBE&lt;br&gt;&amp;#160;&amp;#160; &lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Dim&lt;/SPAN&gt; i &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Long&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Dim&lt;/SPAN&gt; lStart &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Long&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Dim&lt;/SPAN&gt; sPPDlgCaption &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;String&lt;/SPAN&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;SPAN style="color:#007F00"&gt;' Project Properties dialog caption&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Dim&lt;/SPAN&gt; hDlgProjectProps &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Long&lt;/SPAN&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#007F00"&gt;' Project Properties dialog handle&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Dim&lt;/SPAN&gt; sPwdDlgCaption &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;String&lt;/SPAN&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#007F00"&gt;' password dialog caption&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Dim&lt;/SPAN&gt; hDlgPassword &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Long&lt;/SPAN&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#007F00"&gt;' password dialog handle&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Dim&lt;/SPAN&gt; hPwdField &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Long&lt;/SPAN&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;SPAN style="color:#007F00"&gt;' password dialog textbox handle&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Dim&lt;/SPAN&gt; hDlgBadPassword &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Long&lt;/SPAN&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;SPAN style="color:#007F00"&gt;' a 'Bad Password' dialog handle&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Dim&lt;/SPAN&gt; iRetry &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Long&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#007F00"&gt;' Menu bar&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#007F00"&gt;'&amp;#160;&amp;#160;\ Tools (msoControlPopup, ID:30007)&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#007F00"&gt;'&amp;#160;&amp;#160;&amp;#160;&amp;#160; \ Properties of &lt;project_name&gt;... (msoControlButton, ID:2578)&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Dim&lt;/SPAN&gt; cbMenuBar &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; CommandBar&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Dim&lt;/SPAN&gt; cbpTools &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; CommandBarPopup&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Dim&lt;/SPAN&gt; cbbProperties &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; CommandBarButton&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Dim&lt;/SPAN&gt; bDialogsCleared &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Boolean&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;bDialogsCleared = &lt;SPAN style="color:#00007F"&gt;True&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#007F00"&gt;'Application.EnableCancelKey = xlDisabled&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Set&lt;/SPAN&gt; appExcel = wbk.Application&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Set&lt;/SPAN&gt; vbEditor = appExcel.VBE&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Set&lt;/SPAN&gt; vbpProject = wbk.VBProject&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#007F00"&gt;' show Visual Basic Editor?&lt;/SPAN&gt;&lt;br&gt;&lt;SPAN style="color:#007F00"&gt;'&amp;#160;&amp;#160;&amp;#160;&amp;#160;If appExcel.VBE.MainWindow.visible = True Then&lt;/SPAN&gt;&lt;br&gt;&lt;SPAN style="color:#007F00"&gt;'&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;appExcel.VBE.MainWindow.visible = False&lt;/SPAN&gt;&lt;br&gt;&lt;SPAN style="color:#007F00"&gt;'&amp;#160;&amp;#160;&amp;#160;&amp;#160;End If&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#007F00"&gt;' set the VBE active project&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Set&lt;/SPAN&gt; vbEditor.ActiveVBProject = vbpProject&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#007F00"&gt;' construct the password dialog caption&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;sPwdDlgCaption = vbpProject.Name &amp; DLG_PWD_CAP_SUFFIX&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#007F00"&gt;' construct the 'project properties' dialog caption&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;sPPDlgCaption = vbpProject.Name &amp; DLG_PRJPROP_CAP_SUFFIX&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;br&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#007F00"&gt;' Note that this could be structured as nested IF... THEN blocks, avoiding the use of 'GOTO'&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#007F00"&gt;' But 'drop-through or exit' is easier to follow when we use a 'go-back-and-retry' structure&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#007F00"&gt;' Try to acquire the menu bar&lt;/SPAN&gt;&lt;br&gt;iRetry = 0&lt;br&gt;RetryGetMenuBar:&lt;br&gt;iRetry = iRetry + 1&lt;br&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Not&lt;/SPAN&gt; fGetMenuBar(vbEditor, cbMenuBar) &lt;SPAN style="color:#00007F"&gt;Then&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#007F00"&gt;' Failed, retry 3 times&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Call&lt;/SPAN&gt; Sleep(32 * iRetry)&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt; iRetry &lt; 4 &lt;SPAN style="color:#00007F"&gt;Then&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;GoTo&lt;/SPAN&gt; RetryGetMenuBar&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Else&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;Debug.Print vbpProject.Name &amp; vbTab &amp; "fUnlockProject() - Menubar not found : " &amp; Err.Description&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;GoTo&lt;/SPAN&gt; ExitFunction&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt;&amp;#160;&amp;#160;&lt;SPAN style="color:#007F00"&gt;' menu bar successfully acquired&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&lt;SPAN style="color:#007F00"&gt;' try to find the 'Tools' menu&lt;/SPAN&gt;&lt;br&gt;iRetry = 0&lt;br&gt;RetryGetToolsMenu:&lt;br&gt;iRetry = iRetry + 1&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Set&lt;/SPAN&gt; cbpTools = cbMenuBar.FindControl(ID:="30007")&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt; (cbpTools &lt;SPAN style="color:#00007F"&gt;Is&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Nothing&lt;/SPAN&gt;) &lt;SPAN style="color:#00007F"&gt;Then&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#007F00"&gt;' Failed, retry 3 times&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Call&lt;/SPAN&gt; Sleep(32 * iRetry)&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt; iRetry &lt; 4 &lt;SPAN style="color:#00007F"&gt;Then&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;GoTo&lt;/SPAN&gt; RetryGetToolsMenu&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Else&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;Debug.Print vbpProject.Name &amp; vbTab &amp; "fUnlockProject() - Tools menu not found : " &amp; Err.Description&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;GoTo&lt;/SPAN&gt; ExitFunction&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;br&gt;&lt;SPAN style="color:#007F00"&gt;' try to get the 'project properties' menu item&lt;/SPAN&gt;&lt;br&gt;iRetry = 0&lt;br&gt;RetryGetProjProps:&lt;br&gt;iRetry = iRetry + 1&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Call&lt;/SPAN&gt; fGetPopupItem(cbpTools, "2578", cbbProperties)&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;CloseNamedDialog DLG_VBERROR_CAP&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt; (cbbProperties &lt;SPAN style="color:#00007F"&gt;Is&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Nothing&lt;/SPAN&gt;) &lt;SPAN style="color:#00007F"&gt;Then&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#007F00"&gt;'Failed, Retry 3 times&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Call&lt;/SPAN&gt; Sleep(32 * iRetry)&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt; iRetry &lt; 4 &lt;SPAN style="color:#00007F"&gt;Then&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;GoTo&lt;/SPAN&gt; RetryGetProjProps&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Else&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;Debug.Print vbpProject.Name &amp; vbTab &amp; "fUnlockProject() : Properties menu item not found."&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;GoTo&lt;/SPAN&gt; ExitFunction&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#007F00"&gt;' Execute the 'project properties' menu item action&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Call&lt;/SPAN&gt; cbbProperties.Execute&lt;br&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#007F00"&gt;' Test an unlikely outcome: the project properties window&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#007F00"&gt;' opened up straightaway, indicating there was no password:&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;hDlgProjectProps = 0&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;hDlgProjectProps = FindWindow(DIALOG_CLS, sPPDlgCaption)&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt; hDlgProjectProps &lt;&gt; 0 &lt;SPAN style="color:#00007F"&gt;Then&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;GoTo&lt;/SPAN&gt; ExitFunction&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;br&gt;&lt;SPAN style="color:#007F00"&gt;' Get the password dialog's window handle:&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;hDlgPassword = 0&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;hDlgPassword = FindWindow(DIALOG_CLS, sPwdDlgCaption)&lt;br&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;br&gt;&lt;SPAN style="color:#007F00"&gt;' Test the&amp;#160;&amp;#160;password dialog exists, retry if it does not:&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;iRetry = 0&lt;br&gt;RetryGetPwdDialog:&lt;br&gt;iRetry = iRetry + 1&lt;br&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt; hDlgPassword = 0 And iRetry &lt; 3 &lt;SPAN style="color:#00007F"&gt;Then&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#007F00"&gt;' Close any 'bad password' or VB Error windows&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;CloseNamedDialog DLG_VBERROR_CAP&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;CloseNamedDialog DLG_BADPWD_CAP&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#007F00"&gt;' Try getting the hWnd of the password dialog again:&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;hDlgPassword = FindWindow(DIALOG_CLS, sPwdDlgCaption)&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt; hDlgPassword = 0 &lt;SPAN style="color:#00007F"&gt;Then&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Call&lt;/SPAN&gt; Sleep(32 * iRetry)&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt; hDlgPassword = 0 &lt;SPAN style="color:#00007F"&gt;Then&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;GoTo&lt;/SPAN&gt; RetryGetPwdDialog&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt; hDlgPassword = 0 And iRetry &lt; 4 &lt;SPAN style="color:#00007F"&gt;Then&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;CloseNamedDialog DLG_VBERROR_CAP&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;CloseNamedDialog DLG_BADPWD_CAP&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#007F00"&gt;' Try reopening the dialog from the menu, then get the hwnd:&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Call&lt;/SPAN&gt; cbbProperties.Execute&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Call&lt;/SPAN&gt; Sleep(32 * iRetry)&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;hDlgPassword = (FindWindow(DIALOG_CLS, sPwdDlgCaption))&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt; hDlgPassword = 0 &lt;SPAN style="color:#00007F"&gt;Then&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Call&lt;/SPAN&gt; Sleep(32 * iRetry)&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt; hDlgPassword = 0 &lt;SPAN style="color:#00007F"&gt;Then&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;GoTo&lt;/SPAN&gt; RetryGetPwdDialog&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt; hDlgPassword = 0 &lt;SPAN style="color:#00007F"&gt;Then&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;Debug.Print vbpProject.Name &amp; vbTab &amp; "fUnlockProject(): cannot open the password dialog."&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;GoTo&lt;/SPAN&gt; ExitFunction&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/FONT&gt;&lt;br /&gt;&lt;font face=Courier New&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&lt;SPAN style="color:#007F00"&gt;' Get the password textbox&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;hPwdField = 0&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;hPwdField = GetDlgItem(hDlgPassword, PWD_DLG_EDIT_ID)&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&lt;SPAN style="color:#007F00"&gt;' Test the password textbox exists, retry if it does not:&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;br&gt;iRetry = 0&lt;br&gt;RetryGetPwdTextbox:&lt;br&gt;iRetry = iRetry + 1&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt; hPwdField = 0 And iRetry &lt; 4 &lt;SPAN style="color:#00007F"&gt;Then&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;CloseNamedDialog DLG_VBERROR_CAP&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;CloseNamedDialog DLG_BADPWD_CAP&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;hPwdField = GetDlgItem(hDlgPassword, PWD_DLG_EDIT_ID)&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt; hPwdField = 0 &lt;SPAN style="color:#00007F"&gt;Then&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Call&lt;/SPAN&gt; Sleep(32 * iRetry)&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt; hPwdField = 0 &lt;SPAN style="color:#00007F"&gt;Then&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;GoTo&lt;/SPAN&gt; RetryGetPwdTextbox&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt; hPwdField = 0 &lt;SPAN style="color:#00007F"&gt;Then&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;Debug.Print vbpProject.Name &amp; vbTab &amp; "fUnlockProject(): cannot find the password textbox."&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;bDialogsCleared = CloseWindow(hDlgPassword)&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;GoTo&lt;/SPAN&gt; ExitFunction&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&lt;SPAN style="color:#007F00"&gt;'Fill in the password text:&lt;/SPAN&gt;&lt;br&gt;iRetry = 0&lt;br&gt;RetrySetText:&lt;br&gt;iRetry = iRetry + 1&lt;br&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt; SendMessageStr(hPwdField, WM_SETTEXT, 0&amp;, strPwd) = 0 &lt;SPAN style="color:#00007F"&gt;Then&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#007F00"&gt;' zero return indicates a failed set-text operation&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Call&lt;/SPAN&gt; Sleep(32 * iRetry)&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Select&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Case&lt;/SPAN&gt; iRetry&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Case&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Is&lt;/SPAN&gt; &lt; 4&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;GoTo&lt;/SPAN&gt; RetrySetText&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Case&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Is&lt;/SPAN&gt; &lt; 5&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;CloseNamedDialog DLG_VBERROR_CAP&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;CloseNamedDialog DLG_BADPWD_CAP&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;hDlgPassword = (FindWindow(DIALOG_CLS, sPwdDlgCaption))&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;hPwdField = GetDlgItem(hDlgPassword, PWD_DLG_EDIT_ID)&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;GoTo&lt;/SPAN&gt; RetrySetText&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Case&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Is&lt;/SPAN&gt; &lt; 6&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;CloseNamedDialog DLG_VBERROR_CAP&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;CloseNamedDialog DLG_BADPWD_CAP&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;CloseWindow hDlgPassword&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;GoTo&lt;/SPAN&gt; RetryGetPwdDialog&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Case&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Else&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;Debug.Print vbpProject.Name &amp; vbTab &amp; "fUnlockProject() : Unable to enter password '" &amp; strPwd &amp; "' into the textbox."&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;bDialogsCleared = CloseWindow(hDlgPassword)&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;GoTo&lt;/SPAN&gt; ExitFunction&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Select&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&lt;SPAN style="color:#007F00"&gt;' Click the 'Ok' button&lt;/SPAN&gt;&lt;br&gt;iRetry = 0&lt;br&gt;RetryClickOK:&lt;br&gt;iRetry = iRetry + 1&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#007F00"&gt;' PostMessage returns the results of the 'click': nonzero indicates success&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt; PostMessage(GetDlgItem(hDlgPassword, IDOK), BM_CLICK, 0&amp;, 0&amp;) = 0 &lt;SPAN style="color:#00007F"&gt;Then&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Select&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Case&lt;/SPAN&gt; iRetry&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Case&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Is&lt;/SPAN&gt; &lt; 4&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Call&lt;/SPAN&gt; Sleep(32 * iRetry)&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;GoTo&lt;/SPAN&gt; RetryClickOK&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Case&lt;/SPAN&gt; 4&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;CloseNamedDialog DLG_BADPWD_CAP&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;CloseNamedDialog DLG_VBERROR_CAP&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Call&lt;/SPAN&gt; SetForegroundWindow(hDlgPassword)&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;GoTo&lt;/SPAN&gt; RetryClickOK&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Case&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Else&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;Debug.Print vbpProject.Name &amp; vbTab &amp; "fUnlockProject() : Unable to click 'OK' for this password."&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;bDialogsCleared = CloseWindow(hDlgPassword)&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;GoTo&lt;/SPAN&gt; ExitFunction&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Select&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt; &lt;SPAN style="color:#007F00"&gt;' fClickButton failed&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#007F00"&gt;' fClickButton returned true, telling us that control&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#007F00"&gt;' has returned to the OK button's parent dialog.&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#007F00"&gt;' However, that could also mean that the button wasn't clicked at all:&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;hDlgPassword = 0&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;hDlgPassword = FindWindow(DIALOG_CLS, sPwdDlgCaption)&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt; hDlgPassword &lt;&gt; 0 &lt;SPAN style="color:#00007F"&gt;Then&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Select&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Case&lt;/SPAN&gt; iRetry&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Case&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Is&lt;/SPAN&gt; &lt; 4&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Call&lt;/SPAN&gt; Sleep(32 * iRetry)&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;GoTo&lt;/SPAN&gt; RetryClickOK&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Case&lt;/SPAN&gt; 4&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;CloseNamedDialog DLG_BADPWD_CAP&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;CloseNamedDialog DLG_VBERROR_CAP&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Call&lt;/SPAN&gt; SetForegroundWindow(hDlgPassword)&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;GoTo&lt;/SPAN&gt; RetryClickOK&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Case&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Else&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;Debug.Print vbpProject.Name &amp; vbTab &amp; "fUnlockProject() : Unable to click 'OK' for this password."&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;bDialogsCleared = CloseWindow(hDlgPassword)&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;GoTo&lt;/SPAN&gt; ExitFunction&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Select&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;bDialogsCleared = &lt;SPAN style="color:#00007F"&gt;False&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#007F00"&gt;' Inspect the results of the click&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#007F00"&gt;' No retry block here: retrying Window-open operations, clicks and SetTexts is fine&lt;/SPAN&gt;&lt;br&gt;&lt;SPAN style="color:#007F00"&gt;' - or rather, a messy necessity - but the password itself either worked or failed.&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt; &lt;SPAN style="color:#007F00"&gt;' Two possible outcomes:&amp;#160;&amp;#160; 1 Password success opened a 'project properties' dialog&lt;/SPAN&gt;&lt;br&gt; &lt;SPAN style="color:#007F00"&gt;'&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;2 Password failure opened a 'bad password' dialog&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt; CloseNamedDialog(DLG_BADPWD_CAP) = 0 &lt;SPAN style="color:#00007F"&gt;Then&lt;/SPAN&gt;&amp;#160;&amp;#160;&lt;SPAN style="color:#007F00"&gt;' no 'bad password' dialog to close&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;hDlgProjectProps = 0&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;hDlgProjectProps = FindWindow(DIALOG_CLS, sPPDlgCaption)&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt; hDlgProjectProps = 0 &lt;SPAN style="color:#00007F"&gt;Then&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Call&lt;/SPAN&gt; Sleep(250)&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt; hDlgProjectProps &lt;&gt; 0 &lt;SPAN style="color:#00007F"&gt;Then&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#007F00"&gt;' Opened the 'Properties' screen, which means: PASSWORD SUCCESSFUL!&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;Debug.Print "PASSWORD: " &amp; strPwd &amp; vbTab &amp; wbk.FullName&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#007F00"&gt;'Close the project properties dialog: try the OK button first&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;bDialogsCleared = fClickButton(hDlgProjectProps, IDOK)&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt; &lt;SPAN style="color:#007F00"&gt;'successful password&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Else&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#007F00"&gt;' Bad password dialog detected &amp; closed... Our password Failed&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&lt;br&gt;ExitFunction:&lt;br&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;CloseNamedDialog DLG_BADPWD_CAP&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;CloseNamedDialog DLG_VBERROR_CAP&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;hDlgProjectProps = FindWindow(DIALOG_CLS, sPPDlgCaption)&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;bDialogsCleared = bDialogsCleared And CloseWindow(hDlgPassword) And CloseWindow(hDlgProjectProps)&lt;br&gt;&amp;#160;&amp;#160; &lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt; (bDialogsCleared) &lt;SPAN style="color:#00007F"&gt;Then&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#007F00"&gt;' all the dialog boxes were closed&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;fUnlockProject = &lt;SPAN style="color:#00007F"&gt;True&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Set&lt;/SPAN&gt; cbbProperties = &lt;SPAN style="color:#00007F"&gt;Nothing&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Set&lt;/SPAN&gt; cbpTools = &lt;SPAN style="color:#00007F"&gt;Nothing&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Set&lt;/SPAN&gt; cbMenuBar = &lt;SPAN style="color:#00007F"&gt;Nothing&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;vbEditor.MainWindow.Close&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Set&lt;/SPAN&gt; vbEditor = &lt;SPAN style="color:#00007F"&gt;Nothing&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Set&lt;/SPAN&gt; appExcel = &lt;SPAN style="color:#00007F"&gt;Nothing&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Function&lt;/SPAN&gt;&lt;/FONT&gt;&lt;br /&gt;&lt;font face=Courier New&gt;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;Private&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Function&lt;/SPAN&gt; fGetDialogHnd(sCaption, hDlg &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Long&lt;/SPAN&gt;) &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Boolean&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#007F00"&gt;' Get the handle of the dialog whose the caption is specified.&lt;/SPAN&gt;&lt;br&gt;&lt;SPAN style="color:#007F00"&gt;' Return True if the dialog was found.&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;hDlg = (FindWindow(DIALOG_CLS, sCaption))&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;fGetDialogHnd = (hDlg &lt;&gt; 0)&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Function&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;Private&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Function&lt;/SPAN&gt; fClickButton(hDlg &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Long&lt;/SPAN&gt;, lButtonID &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Long&lt;/SPAN&gt;) &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Boolean&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#007F00"&gt;' Programmatically click on a button in a command bar or menu,&amp;#160;&amp;#160;specified by ID&lt;/SPAN&gt;&lt;br&gt;&lt;SPAN style="color:#007F00"&gt;' Return False if the button owner was not activated or the 'click' failed&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Dim&lt;/SPAN&gt; hButton &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Long&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#007F00"&gt;' get the button handle&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;hButton = GetDlgItem(hDlg, lButtonID)&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#007F00"&gt;' active the dialog box (hDlg) and click on the button&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt; PostMessage(hButton, BM_CLICK, 0&amp;, 0&amp;) &lt;&gt; 0 &lt;SPAN style="color:#00007F"&gt;Then&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;fClickButton = &lt;SPAN style="color:#00007F"&gt;True&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Function&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;Private&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Function&lt;/SPAN&gt; fGetMenuBar(oContainer &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Object&lt;/SPAN&gt;, cb &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; CommandBar) &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Boolean&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#007F00"&gt;' Get the menu bar of the specified container:&lt;/SPAN&gt;&lt;br&gt;&lt;SPAN style="color:#007F00"&gt;' oContainer can be any object which has a CommandBars collection.&lt;/SPAN&gt;&lt;br&gt;&lt;SPAN style="color:#007F00"&gt;' Return True if the menu bar was found.&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Dim&lt;/SPAN&gt; i &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Long&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;On&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Error&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Resume&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Next&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;For&lt;/SPAN&gt; i = 1 &lt;SPAN style="color:#00007F"&gt;To&lt;/SPAN&gt; oContainer.CommandBars.Count&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Set&lt;/SPAN&gt; cb = oContainer.CommandBars(i)&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt; (cb.Type = msoBarTypeMenuBar) &lt;SPAN style="color:#00007F"&gt;Then&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;fGetMenuBar = &lt;SPAN style="color:#00007F"&gt;True&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Exit&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;For&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Next&lt;/SPAN&gt; i&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;On&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Error&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;GoTo&lt;/SPAN&gt; 0&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Function&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;Private&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Function&lt;/SPAN&gt; fGetPopupItem(cbp &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; CommandBarPopup, sControlID &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;String&lt;/SPAN&gt;, cbc &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; CommandBarControl) &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Boolean&lt;/SPAN&gt;&lt;br&gt;&lt;SPAN style="color:#007F00"&gt;' Get a control from a commandbar or menu, by specifying the control's ID&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Dim&lt;/SPAN&gt; i &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Long&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;For&lt;/SPAN&gt; i = 1 &lt;SPAN style="color:#00007F"&gt;To&lt;/SPAN&gt; cbp.Controls.Count&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Set&lt;/SPAN&gt; cbc = cbp.Controls(i)&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt; (cbc.ID = sControlID) &lt;SPAN style="color:#00007F"&gt;Then&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;fGetPopupItem = &lt;SPAN style="color:#00007F"&gt;True&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Exit&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;For&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Next&lt;/SPAN&gt; i&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Function&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;Private&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Function&lt;/SPAN&gt; TrimNulls(&lt;SPAN style="color:#00007F"&gt;ByVal&lt;/SPAN&gt; sString &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; String) &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; String&lt;br&gt;&lt;SPAN style="color:#007F00"&gt;' Trims trailing nulls&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;Dim&lt;/SPAN&gt; iPos &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Integer&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;iPos = InStr(sString, Chr$(0))&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Select&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Case&lt;/SPAN&gt; iPos&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Case&lt;/SPAN&gt; 0&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;TrimNulls = sString&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Case&lt;/SPAN&gt; 1&lt;br&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;TrimNulls = ""&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Case&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Else&lt;/SPAN&gt; &lt;SPAN style="color:#007F00"&gt;' iPos &gt; 1&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;TrimNulls = left$(sString, iPos - 1)&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Select&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Function&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;Private&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Function&lt;/SPAN&gt; fUCase(&lt;SPAN style="color:#00007F"&gt;ByVal&lt;/SPAN&gt; sString &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; String) &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; String&lt;br&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt; (Len(s&lt;SPAN style="color:#00007F"&gt;String&lt;/SPAN&gt;) &gt;= 2) &lt;SPAN style="color:#00007F"&gt;Then&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;fUCase = CharUpper(left$(s&lt;SPAN style="color:#00007F"&gt;String&lt;/SPAN&gt;, 1)) &amp; _&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; CharLower(right$(s&lt;SPAN style="color:#00007F"&gt;String&lt;/SPAN&gt;, Len(sString) - 1))&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Else&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;fUCase = s&lt;SPAN style="color:#00007F"&gt;String&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Function&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;Private&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Function&lt;/SPAN&gt; IsArrayEmpty(va &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Variant&lt;/SPAN&gt;) &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Boolean&lt;/SPAN&gt;&lt;br&gt;&lt;SPAN style="color:#007F00"&gt;' Incorporates fix from Torsten Rendelmann (MVPS - Hardcore VB)&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Dim&lt;/SPAN&gt; i &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Long&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;On&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Error&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Resume&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Next&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;i = &lt;SPAN style="color:#00007F"&gt;LBound&lt;/SPAN&gt;(va, 1)&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;IsArrayEmpty = (Err.Number &lt;&gt; 0)&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;On&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Error&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;GoTo&lt;/SPAN&gt; 0 &lt;SPAN style="color:#007F00"&gt;' Err.Clear&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Function&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;Private&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Function&lt;/SPAN&gt; CloseWindow(hWnd &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Long&lt;/SPAN&gt;) &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Boolean&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;Dim&lt;/SPAN&gt; iRetry &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Integer&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;CloseWindow = &lt;SPAN style="color:#00007F"&gt;False&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;RetryCloseWindow:&lt;br&gt;iRetry = iRetry + 1&lt;br&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt; SendMessage(hWnd, WM_CLOSE, 0&amp;, 0&amp;) = 0&amp; &lt;SPAN style="color:#00007F"&gt;Then&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;CloseWindow = &lt;SPAN style="color:#00007F"&gt;True&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Else&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;CloseWindow = &lt;SPAN style="color:#00007F"&gt;False&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;CloseNamedDialog DLG_VBERROR_CAP&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Call&lt;/SPAN&gt; Sleep(32 * iRetry)&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt; iRetry &lt; 4 &lt;SPAN style="color:#00007F"&gt;Then&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;GoTo&lt;/SPAN&gt; RetryCloseWindow&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Function&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;Public&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Function&lt;/SPAN&gt; CloseNamedDialog(sDialogCaption &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;String&lt;/SPAN&gt;) &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Long&lt;/SPAN&gt;&lt;br&gt;&lt;SPAN style="color:#007F00"&gt;'Returns window handle of last-closed window&lt;/SPAN&gt;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;On&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Error&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Resume&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Next&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;Dim&lt;/SPAN&gt; iCount &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Integer&lt;/SPAN&gt;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;Dim&lt;/SPAN&gt; hwnDialog &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Long&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;Err.Clear&lt;br&gt;&lt;br&gt;CloseNamedDialog = 1&lt;br&gt;&lt;br&gt;hwnDialog = FindWindow(DIALOG_CLS, sDialogCaption)&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;Do&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Until&lt;/SPAN&gt; hwnDialog = 0&lt;br&gt;iCount = iCount + 1&lt;br&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;SendMessage hwnDialog, WM_CLOSE, 0&amp;, 0&amp;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;CloseNamedDialog = hwnDialog&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;hwnDialog = FindWindow(DIALOG_CLS, sDialogCaption)&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt; iCount &gt; 1 &lt;SPAN style="color:#00007F"&gt;Then&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;Sleep 10 * iCount&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;SetFocus hwnDialog&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt; iCount &gt; 3 &lt;SPAN style="color:#00007F"&gt;Then&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#007F00"&gt;' something's stopping us closing the window&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Exit&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Do&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;Loop&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Function&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;Public&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Sub&lt;/SPAN&gt; CloseGenericError()&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;On&lt;/SPAN&gt; Error &lt;SPAN style="color:#00007F"&gt;Resume&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Next&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;CloseNamedDialog DLG_VBERROR_CAP&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;Application.OnTime EarliestTime:=Now() + (1# / 24# / 1200#), Procedure:="CloseGeneric&lt;SPAN style="color:#00007F"&gt;Error&lt;/SPAN&gt;"&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Sub&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;Private&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Function&lt;/SPAN&gt; ClickButton(hWndOwner &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Long&lt;/SPAN&gt;, hWndButton &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Long&lt;/SPAN&gt;) &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Boolean&lt;/SPAN&gt;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;On&lt;/SPAN&gt; Error &lt;SPAN style="color:#00007F"&gt;Resume&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Next&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;SetForegroundWindow hWndOwner&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;SetFocus hWndButton&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;PostMessage hWndButton, BM_CLICK, 0&amp;, 0&amp;&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Function&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;Private&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Function&lt;/SPAN&gt; GetWindowText(&lt;SPAN style="color:#00007F"&gt;ByVal&lt;/SPAN&gt; hWnd &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Long&lt;/SPAN&gt;) &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; String&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;Dim&lt;/SPAN&gt; sBuffer &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; String&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;Dim&lt;/SPAN&gt; lBufferLen &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Long&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;sBuffer = String$(512, 0)&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;lBufferLen = GetWindowTextApi(hWnd, sBuffer, Len(sBuffer))&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;GetWindowText = left$(sBuffer, lBufferLen)&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Function&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;Private&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Function&lt;/SPAN&gt; GetClassName(&lt;SPAN style="color:#00007F"&gt;ByVal&lt;/SPAN&gt; hWnd &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Long&lt;/SPAN&gt;) &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; String&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;Dim&lt;/SPAN&gt; sBuffer &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; String&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;Dim&lt;/SPAN&gt; lBufferLen &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Long&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;sBuffer = String$(512, 0)&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;lBufferLen = GetClassNameApi(hWnd, sBuffer, Len(sBuffer))&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;GetClassName = left$(sBuffer, lBufferLen)&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Function&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;&lt;/FONT&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1800518423097919889-6088396440688871748?l=excellerando.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://excellerando.blogspot.com/feeds/6088396440688871748/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://excellerando.blogspot.com/2010/02/unprotecting-project-using-vba.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1800518423097919889/posts/default/6088396440688871748'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1800518423097919889/posts/default/6088396440688871748'/><link rel='alternate' type='text/html' href='http://excellerando.blogspot.com/2010/02/unprotecting-project-using-vba.html' title='Unprotecting a project using VBA'/><author><name>Nigel Heffernan</name><uri>http://www.blogger.com/profile/08954578765691578714</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://1.bp.blogspot.com/_B9BAdln8o_A/SYY_TkYyu4I/AAAAAAAAAAs/z5CQ01NUtTI/S220/Cropped+Blog+Shot.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1800518423097919889.post-2462796448728466786</id><published>2009-12-02T23:01:00.003Z</published><updated>2009-12-03T18:55:47.685Z</updated><title type='text'>A VBA function to force calculation of a cell's precedents</title><content type='html'>&lt;P Align='justify'&gt;Here's some code I hope you don't need: a targeted 'recalculate' function.&lt;/P&gt;&lt;P Align='justify'&gt; Most Excel developers don't get huge workbooks that take twenty minutes to recalculate... It's our job to stop this kind of thing, right? But if you do, how do you get just one bit of the monster to calculate - the bit you're trying to debug, or explain the strange results in - when there's a long, long chain of dependencies on market data sources and external math libraries? The one thing you don't want to do is recalculate the whole workbook, but recalculating the cell with the F2 key is useless because it doesn't go right down the  'precedents' (Microsoft's term for the chain of cells and ranges that feed into your cell), no matter what you read in the documentation.&lt;/P&gt;&lt;a href="http://2.bp.blogspot.com/_B9BAdln8o_A/SxgEXA4DLsI/AAAAAAAAABg/V8CvFWEenu8/s1600-h/TraceDependants.JPG"&gt;&lt;img style="float:right; margin:0 0 10px 10px;cursor:pointer; cursor:hand;width: 266px; height: 320px;" src="http://2.bp.blogspot.com/_B9BAdln8o_A/SxgEXA4DLsI/AAAAAAAAABg/V8CvFWEenu8/s320/TraceDependants.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5411079745704242882" /&gt;&lt;/a&gt;&lt;P Align='justify'&gt;So I started writing a tool to record the chain of precedents, and found that really complex spreadsheets could produce so much dependency data that the text output was impossible to assimilate. What I found out &lt;i&gt;next&lt;/i&gt; was that presenting this mass of data in a structured way breaks down because there are no tools that can represent cross-linkage without turning into a visual spaghetti, and the only good tool for representing the mess as a branching structure - the treeview control - is unstable in Excel at the best of times and blows up if there's more than 16 layers of recursion or more than 255 subnodes in any given node. &lt;/P&gt;&lt;P Align='justify'&gt;But the end result of this failed project was a tool that could explore the precedents, list them in a collection and, having discovered all the sources leading into a cell, &lt;b&gt;back it's way out of the dependency chain while only calculating each cell once&lt;/b&gt;. That's efficient - not as quick as Excel's internal dependency chain, but it's often quicker than recalculating an over-complicated workbook. And it works a treat when Excel's dependency tree is broken, or blocked by named ranges, indirect references, and third-party libraries which place range pointers in a cell instead of range addresses. &lt;br /&gt;&lt;/P&gt;&lt;P Align='justify'&gt;Feel free to post your code if you get a visualisation tool to work! Also, please let me know if you can think of a way of identifying homogeneous blocks of formulae and enumerating them in one go, instead of repeating the search on cell after cell. It's not that it can't be done, but I can't see a way of doing it reliably and &lt;i&gt;quickly&lt;/i&gt; enough to use on thousands of formulae.&lt;/P&gt;&lt;P Align='justify'&gt;Anyway, here's the code, complete with a snippet for putting it into an add-in and populating the popup 'cell' menu with a button that calls the function. As always, beware of spurious line breaks and syntax errors introduced by the Blogger platform's automatic formatting.&lt;/P&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;font face=Courier New&gt;&lt;SPAN style="color:#00007F"&gt;Option&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Explicit&lt;/SPAN&gt;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;Option&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Private&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Module&lt;/SPAN&gt;&lt;br&gt;&lt;br /&gt;&lt;SPAN style="color:#00007F"&gt;Private&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Sub&lt;/SPAN&gt; CalculatePrecedents(rngCalc &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; Excel.Range, &lt;SPAN style="color:#00007F"&gt;Optional&lt;/SPAN&gt; bVerbose &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Boolean&lt;/SPAN&gt; = &lt;SPAN style="color:#00007F"&gt;False&lt;/SPAN&gt;)&lt;br /&gt;&lt;br /&gt;&lt;SPAN style="color:#007F00"&gt;' Recursive function to force calculation of a dependency chain&lt;/SPAN&gt;&lt;br /&gt;&lt;SPAN style="color:#007F00"&gt;' with additional coding to prevent searching any range twice&lt;/SPAN&gt;&lt;br /&gt;&lt;br /&gt;&lt;SPAN style="color:#00007F"&gt;On&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Error&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Resume&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Next&lt;/SPAN&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;SPAN style="color:#00007F"&gt;Static&lt;/SPAN&gt; iRecurse &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Long&lt;/SPAN&gt;&lt;br /&gt;&lt;SPAN style="color:#00007F"&gt;Static&lt;/SPAN&gt; colRanges &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; Scripting.Dictionary&lt;br /&gt;&lt;SPAN style="color:#00007F"&gt;Static&lt;/SPAN&gt; colWorkbooks &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; Scripting.Dictionary&lt;br /&gt;&lt;SPAN style="color:#00007F"&gt;Static&lt;/SPAN&gt; xlPriorCalcSetting &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; XlCalculation&lt;br /&gt;&lt;SPAN style="color:#00007F"&gt;Static&lt;/SPAN&gt; iSearched &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Long&lt;/SPAN&gt;&lt;br /&gt;&lt;SPAN style="color:#00007F"&gt;Static&lt;/SPAN&gt; iCalculated &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Long&lt;/SPAN&gt;&lt;br /&gt;&lt;SPAN style="color:#00007F"&gt;Static&lt;/SPAN&gt; arrNames() &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;String&lt;/SPAN&gt;&lt;br /&gt;&lt;SPAN style="color:#00007F"&gt;Static&lt;/SPAN&gt; iCountNames &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Long&lt;/SPAN&gt;&lt;br /&gt;&lt;SPAN style="color:#00007F"&gt;Static&lt;/SPAN&gt; sWorkbookName &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;String&lt;/SPAN&gt;&lt;br /&gt;&lt;br /&gt;&lt;SPAN style="color:#00007F"&gt;Dim&lt;/SPAN&gt; iCountPrecedents &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Long&lt;/SPAN&gt;&lt;br /&gt;&lt;SPAN style="color:#00007F"&gt;Dim&lt;/SPAN&gt; rPrecedent &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; Excel.Range&lt;br /&gt;&lt;SPAN style="color:#00007F"&gt;Dim&lt;/SPAN&gt; rCell &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; Excel.Range&lt;br /&gt;&lt;SPAN style="color:#00007F"&gt;Dim&lt;/SPAN&gt; myName &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; Excel.Name&lt;br /&gt;&lt;SPAN style="color:#00007F"&gt;Dim&lt;/SPAN&gt; strName &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;String&lt;/SPAN&gt;&lt;br /&gt;&lt;SPAN style="color:#00007F"&gt;Dim&lt;/SPAN&gt; strAddress &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;String&lt;/SPAN&gt;&lt;br /&gt;&lt;SPAN style="color:#00007F"&gt;Dim&lt;/SPAN&gt; strFormula &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;String&lt;/SPAN&gt;&lt;br /&gt;&lt;SPAN style="color:#00007F"&gt;Dim&lt;/SPAN&gt; iLen &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Long&lt;/SPAN&gt;&lt;br /&gt;&lt;SPAN style="color:#00007F"&gt;Dim&lt;/SPAN&gt; i &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Integer&lt;/SPAN&gt;&lt;br /&gt;&lt;SPAN style="color:#00007F"&gt;Dim&lt;/SPAN&gt; iMatch &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Integer&lt;/SPAN&gt;&lt;br /&gt;&lt;SPAN style="color:#00007F"&gt;Dim&lt;/SPAN&gt; iNextChar &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Integer&lt;/SPAN&gt;&lt;br /&gt;&lt;SPAN style="color:#00007F"&gt;Dim&lt;/SPAN&gt; iPrevChar &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Integer&lt;/SPAN&gt;&lt;br /&gt;&lt;SPAN style="color:#00007F"&gt;Dim&lt;/SPAN&gt; boolIsName &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Boolean&lt;/SPAN&gt;&lt;br /&gt;&lt;br /&gt;&lt;SPAN style="color:#007F00"&gt;' Do we need new collections for the searched formulae and calculated ranges?&lt;/SPAN&gt;&lt;br /&gt;&lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt; iRecurse = 0 &lt;SPAN style="color:#00007F"&gt;Or&lt;/SPAN&gt; rngCalc.Worksheet.Parent.Name &lt;&gt; sWorkbookName &lt;SPAN style="color:#00007F"&gt;Then&lt;/SPAN&gt;&lt;br /&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt; colWorkbooks &lt;SPAN style="color:#00007F"&gt;Is&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Nothing&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Then&lt;/SPAN&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Set&lt;/SPAN&gt; colWorkbooks = &lt;SPAN style="color:#00007F"&gt;New&lt;/SPAN&gt; Scripting.Dictionary&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#007F00"&gt;' save sets for current workbook&lt;/SPAN&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Not&lt;/SPAN&gt; (colWorkbooks.Exists("Ranges: " &amp; sWorkbookName) &lt;SPAN style="color:#00007F"&gt;Or&lt;/SPAN&gt; colRanges &lt;SPAN style="color:#00007F"&gt;Is&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Nothing&lt;/SPAN&gt;) &lt;SPAN style="color:#00007F"&gt;Then&lt;/SPAN&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;colWorkbooks.Add "Ranges: " &amp; sWorkbookName, colRanges&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#007F00"&gt;' retrieve sets for newly-discovered workbook&lt;/SPAN&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;sWorkbookName = rngCalc.Worksheet.Parent.Name&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt; colWorkbooks.Exists("Ranges: " &amp; sWorkbookName) &lt;SPAN style="color:#00007F"&gt;Then&lt;/SPAN&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Set&lt;/SPAN&gt; colRanges = colWorkbooks("Ranges: " &amp; sWorkbookName)&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Else&lt;/SPAN&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Set&lt;/SPAN&gt; colRanges = &lt;SPAN style="color:#00007F"&gt;Nothing&lt;/SPAN&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt;&lt;br /&gt;&amp;#160;&amp;#160;&lt;br /&gt;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt;&lt;br /&gt;&lt;br /&gt;&lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt; colRanges &lt;SPAN style="color:#00007F"&gt;Is&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Nothing&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Or&lt;/SPAN&gt; iRecurse = 0 &lt;SPAN style="color:#00007F"&gt;Then&lt;/SPAN&gt;&lt;br /&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;xlPriorCalcSetting = Application.Calculation&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#007F00"&gt;' Initialise the collection that prevents checking the same range twice:&lt;/SPAN&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Set&lt;/SPAN&gt; colRanges = &lt;SPAN style="color:#00007F"&gt;New&lt;/SPAN&gt; Scripting.Dictionary&lt;br /&gt;&amp;#160;&amp;#160; &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#007F00"&gt;' initialise and populate the array of names: this is used for a fast&lt;/SPAN&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#007F00"&gt;' search to see if a named range is referenced in a formula - a test&lt;/SPAN&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#007F00"&gt;' that isn't reliably executed by Excel's native 'precedents' function&lt;/SPAN&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;iCountNames = rngCalc.Worksheet.Parent.Names.Count&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br /&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;Application.StatusBar = "Trace precedents: collating named range addresses in " &amp; sWorkbookName &amp; "..."&lt;br /&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt; bVerbose = &lt;SPAN style="color:#00007F"&gt;True&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Then&lt;/SPAN&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;Debug.Print "Trace precedents: collating named range addresses in " &amp; sWorkbookName &amp; "..."&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt;&lt;br /&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt; iCountNames &gt; 0 &lt;SPAN style="color:#00007F"&gt;Then&lt;/SPAN&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;ReDim&lt;/SPAN&gt; arrNames(1 &lt;SPAN style="color:#00007F"&gt;To&lt;/SPAN&gt; iCountNames)&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;For&lt;/SPAN&gt; i = 1 &lt;SPAN style="color:#00007F"&gt;To&lt;/SPAN&gt; iCountNames&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;strName = ""&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;strName = rngCalc.Worksheet.Parent.Names(i).NameLocal&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt; InStr(1, strName, "!") &gt; 0 &lt;SPAN style="color:#00007F"&gt;Then&lt;/SPAN&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;strName = left(strName, InStr(1, strName, "!") - 1)&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;arrNames(i) = strName&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Next&lt;/SPAN&gt; i&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#007F00"&gt;' Sort in descending order: looking for the longest names first allows us&lt;/SPAN&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#007F00"&gt;' to prevent a match on 'ABCDE' being masked by finding 'BCD'&lt;/SPAN&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;BubbleSortOnLen arrNames, xlDescending&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt; &lt;SPAN style="color:#007F00"&gt;'&amp;#160;&amp;#160;iCountNames &gt; 0&lt;/SPAN&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;Application.StatusBar = "Trace precedents: analysing first cell..."&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt; bVerbose = &lt;SPAN style="color:#00007F"&gt;True&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Then&lt;/SPAN&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;Debug.Print "Trace precedents: analysing first cell... '" &amp; rngCalc.Worksheet.Name &amp; "'!" &amp; rngCalc.Address&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br /&gt;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;SPAN style="color:#007F00"&gt;' Check for ranges we've searched before.&lt;/SPAN&gt;&lt;br /&gt;&lt;br /&gt;&lt;SPAN style="color:#007F00"&gt;' First check: it might be a single cell; if so, is it part of an array we've already analysed?&lt;/SPAN&gt;&lt;br /&gt;&lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt; rngCalc.Cells.Count = 1 &lt;SPAN style="color:#00007F"&gt;Then&lt;/SPAN&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt; rngCalc.HasArray &lt;SPAN style="color:#00007F"&gt;Then&lt;/SPAN&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt; colRanges.Exists("'" &amp; rngCalc.Worksheet.Name &amp; "'!" &amp; rngCalc.CurrentArray) Then&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;SPAN style="color:#00007F"&gt;GoTo&lt;/SPAN&gt; ExitSub&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Else&lt;/SPAN&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;colRanges.Add "'" &amp; rngCalc.Worksheet.Name &amp; "'!" &amp; rngCalc.CurrentArray, "Recursion " &amp; CStr(iRecurse) &amp; vbTab &amp; "'" &amp; rngCalc.Worksheet.Name &amp; "'!" &amp; rngCalc.AddressLocal &amp; vbTab &amp; "{" &amp; rngCalc.Formula &amp; "}"&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt;&lt;br /&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#007F00"&gt;' Exit if there's no formula; there can be no precedents&lt;/SPAN&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#007F00"&gt;' Note that we had to check it wan't an array beforehand&lt;/SPAN&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Not&lt;/SPAN&gt; (IsNull(rngCalc.HasFormula) &lt;SPAN style="color:#00007F"&gt;Or&lt;/SPAN&gt; (rngCalc.HasFormula = &lt;SPAN style="color:#00007F"&gt;True&lt;/SPAN&gt;)) &lt;SPAN style="color:#00007F"&gt;Then&lt;/SPAN&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;GoTo&lt;/SPAN&gt; ExitSub&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br /&gt;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt;&amp;#160;&amp;#160;&lt;SPAN style="color:#007F00"&gt;' rngCalc.Cells.Count = 1&lt;/SPAN&gt;&lt;br /&gt;&lt;br /&gt;&lt;SPAN style="color:#007F00"&gt;' Check that we haven't searched this range already - there's an overhead doing this, but it's better than repeated search and calculation&lt;/SPAN&gt;&lt;br /&gt;&lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt; colRanges.Exists("'" &amp; rngCalc.Worksheet.Name &amp; "'!" &amp; rngCalc.AddressLocal) Then&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;GoTo&lt;/SPAN&gt; ExitSub&lt;br /&gt;&lt;SPAN style="color:#00007F"&gt;Else&lt;/SPAN&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;colRanges.Add "'" &amp; rngCalc.Worksheet.Name &amp; "'!" &amp; rngCalc.AddressLocal, "Recursion " &amp; CStr(iRecurse) &amp; vbTab &amp; "'" &amp; rngCalc.Worksheet.Name &amp; "'!" &amp; rngCalc.AddressLocal&lt;br /&gt;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;SPAN style="color:#007F00"&gt;' Keep track of recursion: this tells us when the search has been completed&lt;/SPAN&gt;&lt;br /&gt;&lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt; iRecurse &lt; 0 &lt;SPAN style="color:#00007F"&gt;Then&lt;/SPAN&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;iRecurse = 0&lt;br /&gt;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt;&lt;br /&gt;&lt;br /&gt;&lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt; iSearched Mod 10 = 0 &lt;SPAN style="color:#00007F"&gt;Then&lt;/SPAN&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;Application.StatusBar = "Trace precedents: searched " &amp; Format(iSearched, "#,##0") &amp; "&amp;#160;&amp;#160;&amp;#160;&amp;#160;Calculated " &amp; Format(iCalculated, "#,##0") &amp; "&amp;#160;&amp;#160;&amp;#160;&amp;#160;Recursion level " &amp; iRecurse &amp; "&amp;#160;&amp;#160;&amp;#160;&amp;#160;Cell '" &amp; rngCalc.Worksheet.Name &amp; "'!" &amp; rngCalc.Address&lt;br /&gt;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt;&lt;br /&gt;&lt;br /&gt;&lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt; bVerbose = &lt;SPAN style="color:#00007F"&gt;True&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Then&lt;/SPAN&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;Debug.Print "Trace precedents - search " &amp; iSearched &amp; ":" &amp; vbTab &amp; " Precedents of " &amp; vbTab &amp; "'" &amp; rngCalc.Worksheet.Name &amp; "'!" &amp; rngCalc.AddressLocal &amp; vbTab &amp; " Formula: " &amp; rngCalc.Formula &amp; vbTab &amp; " at recursion level " &amp; iRecurse&lt;br /&gt;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt;&lt;br /&gt;&lt;br /&gt;&lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt; rngCalc.Cells.Count = 1 &lt;SPAN style="color:#00007F"&gt;Then&lt;/SPAN&gt;&lt;br /&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;str&lt;SPAN style="color:#00007F"&gt;For&lt;/SPAN&gt;mula = ""&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;strFormula = LTrim(rngCalc.Formula)&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#007F00"&gt;' Check for named ranges in the formula: these are not&lt;/SPAN&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#007F00"&gt;' recognized as reliably as "A1" specified addresses&lt;/SPAN&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#007F00"&gt;' and will therefore not be recognised as precedents&lt;/SPAN&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;For i = 1 &lt;SPAN style="color:#00007F"&gt;To&lt;/SPAN&gt; iCountNames &lt;SPAN style="color:#00007F"&gt;Step&lt;/SPAN&gt; 1&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;strName = ""&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;strName = arrNames(i)&lt;br /&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;iMatch = InStr(1, strFormula, strName, vbTextCompare)&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt; iMatch &gt; 0 &lt;SPAN style="color:#00007F"&gt;Then&lt;/SPAN&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;boolIsName = &lt;SPAN style="color:#00007F"&gt;True&lt;/SPAN&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#007F00"&gt;' A name like "res" might well be a substring of another name, or of a&lt;/SPAN&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#007F00"&gt;' function name. So we must establish that the string we've found isn't&lt;/SPAN&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#007F00"&gt;' just a match for a named range: it's got to be in use as an address.&lt;/SPAN&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;iLen = Len(strName)&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;iPrevChar = 0&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;iNextChar = 0&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt; iMatch + iLen = Len(strFormula) &lt;SPAN style="color:#00007F"&gt;Then&lt;/SPAN&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;iNextChar = 0&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Else&lt;/SPAN&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;iNextChar = iMatch + iLen + 1&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Select&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Case&lt;/SPAN&gt; Mid(strFormula, iNextChar, 1)&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Case&lt;/SPAN&gt; "(", Chr(34), ".", "!", "a" &lt;SPAN style="color:#00007F"&gt;To&lt;/SPAN&gt; "z", "A" &lt;SPAN style="color:#00007F"&gt;To&lt;/SPAN&gt; "Z", 0 &lt;SPAN style="color:#00007F"&gt;To&lt;/SPAN&gt; 9&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#007F00"&gt;'strName definitely isn't a named range&lt;/SPAN&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;boolIsName = &lt;SPAN style="color:#00007F"&gt;False&lt;/SPAN&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Case&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Else&lt;/SPAN&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#007F00"&gt;' no action... move to next test&lt;/SPAN&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Select&lt;/SPAN&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt; iMatch &gt; 1 &lt;SPAN style="color:#00007F"&gt;Then&lt;/SPAN&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;iPrevChar = iMatch - 1&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Select&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Case&lt;/SPAN&gt; Mid(str&lt;SPAN style="color:#00007F"&gt;For&lt;/SPAN&gt;mula, iPrevChar, 1)&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Case&lt;/SPAN&gt; Chr(34), ".", "!", "a" &lt;SPAN style="color:#00007F"&gt;To&lt;/SPAN&gt; "z", "A" &lt;SPAN style="color:#00007F"&gt;To&lt;/SPAN&gt; "Z", 0 &lt;SPAN style="color:#00007F"&gt;To&lt;/SPAN&gt; 9&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#007F00"&gt;'strName definitely isn't a named range&lt;/SPAN&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;boolIsName = &lt;SPAN style="color:#00007F"&gt;False&lt;/SPAN&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Case&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Else&lt;/SPAN&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#007F00"&gt;' no action... move to next test&lt;/SPAN&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Select&lt;/SPAN&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt; boolIsName &lt;SPAN style="color:#00007F"&gt;Then&lt;/SPAN&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;iSearched = iSearched + 1&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;iRecurse = iRecurse + 1&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;CalculatePrecedents rngCalc.Worksheet.Parent.Names(strName).RefersToRange, bVerbose&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;iRecurse = iRecurse - 1&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#007F00"&gt;' Strip the matched name out of our formula string, so we only analyse it once:&lt;/SPAN&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;strFormula = Application.WorksheetFunction.Substitute(str&lt;SPAN style="color:#00007F"&gt;For&lt;/SPAN&gt;mula, strName, "")&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt; &lt;SPAN style="color:#007F00"&gt;'boolIsName&lt;/SPAN&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Next&lt;/SPAN&gt; i&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;iCountPrecedents = 0&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;iCountPrecedents = rngCalc.DirectPrecedents.Count&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt; iCountPrecedents &gt; 0 &lt;SPAN style="color:#00007F"&gt;Then&lt;/SPAN&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;For &lt;SPAN style="color:#00007F"&gt;Each&lt;/SPAN&gt; rPrecedent &lt;SPAN style="color:#00007F"&gt;In&lt;/SPAN&gt; rngCalc.DirectPrecedents&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;iSearched = iSearched + 1&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;iRecurse = iRecurse + 1&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;CalculatePrecedents rPrecedent, bVerbose&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;iRecurse = iRecurse - 1&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Next&lt;/SPAN&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt; &lt;SPAN style="color:#007F00"&gt;' .DirectPrecedents.Count = 0&lt;/SPAN&gt;&lt;br /&gt;&lt;br /&gt;&lt;SPAN style="color:#00007F"&gt;Else&lt;/SPAN&gt;&lt;br /&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#007F00"&gt;' unless it's an array formula, search each cell&lt;/SPAN&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt; IsNull(rngCalc.FormulaArray) &lt;SPAN style="color:#00007F"&gt;Then&lt;/SPAN&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;For&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Each&lt;/SPAN&gt; rCell &lt;SPAN style="color:#00007F"&gt;In&lt;/SPAN&gt; rngCalc.SpecialCells(xlCellTypeFormulas)&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt; rCell.HasFormula &lt;SPAN style="color:#00007F"&gt;Then&lt;/SPAN&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;iSearched = iSearched + 1&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;iRecurse = iRecurse + 1&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;CalculatePrecedents rCell, bVerbose&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;iRecurse = iRecurse - 1&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Next&lt;/SPAN&gt; rCell&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Else&lt;/SPAN&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#007F00"&gt;' for an array, run the precedents of the entire range:&lt;/SPAN&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;For &lt;SPAN style="color:#00007F"&gt;Each&lt;/SPAN&gt; rPrecedent &lt;SPAN style="color:#00007F"&gt;In&lt;/SPAN&gt; rngCalc.DirectPrecedents&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;iSearched = iSearched + 1&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;iRecurse = iRecurse + 1&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;CalculatePrecedents rPrecedent, bVerbose&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;iRecurse = iRecurse - 1&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Next&lt;/SPAN&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt; &lt;SPAN style="color:#007F00"&gt;' cells.count = 1&lt;/SPAN&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;iCalculated = iCalculated + 1&lt;br /&gt;&lt;br /&gt;&lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt; bVerbose = &lt;SPAN style="color:#00007F"&gt;True&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Then&lt;/SPAN&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;Debug.Print "Calculating cell " &amp; iCalculated &amp; " (recursion layer " &amp; iRecurse &amp; "): " &amp; "'" &amp; rngCalc.Worksheet.Name &amp; "'!" &amp; rngCalc.AddressLocal &amp; vbTab &amp; vbTab &amp; rngCalc.Formula&lt;br /&gt;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt;&lt;br /&gt;&lt;br /&gt;&lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt; bVerbose = &lt;SPAN style="color:#00007F"&gt;True&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Then&lt;/SPAN&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;Debug.Print vbTab &amp; "Trace precedents - Calculation " &amp; iCalculated &amp; ":" &amp; vbTab &amp; "'" &amp; rngCalc.Worksheet.Name &amp; "'!" &amp; rngCalc.AddressLocal &amp; vbTab &amp; " &lt;SPAN style="color:#00007F"&gt;For&lt;/SPAN&gt;mula: "; vbTab &amp; rngCalc.&lt;SPAN style="color:#00007F"&gt;For&lt;/SPAN&gt;mula &amp; " at recursion level " &amp; iRecurse&lt;br /&gt;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt;&lt;br /&gt;&lt;br /&gt;rngCalc.Calculate&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;ExitSub:&lt;br /&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt; iRecurse &lt; 0 &lt;SPAN style="color:#00007F"&gt;Then&lt;/SPAN&gt;&amp;#160;&amp;#160;&lt;SPAN style="color:#007F00"&gt;' this is redundant in production code, but it'll save you grief in development&lt;/SPAN&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;iRecurse = 0&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt; iRecurse = 0 &lt;SPAN style="color:#00007F"&gt;Then&lt;/SPAN&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt; bVerbose = &lt;SPAN style="color:#00007F"&gt;True&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Then&lt;/SPAN&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;Application.StatusBar = "Trace precedents searched " &amp; &lt;SPAN style="color:#00007F"&gt;For&lt;/SPAN&gt;mat(iSearched, "#,##0") &amp; "&amp;#160;&amp;#160;&amp;#160;&amp;#160;Calculated " &amp; &lt;SPAN style="color:#00007F"&gt;For&lt;/SPAN&gt;mat(iCalculated, "#,##0") &amp; "&amp;#160;&amp;#160;&amp;#160;&amp;#160;Recursion returned to " &amp; iRecurse&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;Erase arrNames&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;Application.StatusBar = &lt;SPAN style="color:#00007F"&gt;False&lt;/SPAN&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;iSearched = 0&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;iCalculated = 0&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Set&lt;/SPAN&gt; colRanges = &lt;SPAN style="color:#00007F"&gt;Nothing&lt;/SPAN&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;Application.Calculation = xlPriorCalcSetting&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Sub&lt;/SPAN&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;SPAN style="color:#00007F"&gt;Private&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Sub&lt;/SPAN&gt; BubbleSortOnLen(&lt;SPAN style="color:#00007F"&gt;ByRef&lt;/SPAN&gt; arrStrings() &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;String&lt;/SPAN&gt;, &lt;SPAN style="color:#00007F"&gt;Optional&lt;/SPAN&gt; SortOrder &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; Excel.XlSortOrder = xlAscending)&lt;br /&gt;&lt;SPAN style="color:#007F00"&gt;' Modified Bubble Sort: sort an array of strings by length&lt;/SPAN&gt;&lt;br /&gt;&lt;br /&gt;&lt;SPAN style="color:#00007F"&gt;Dim&lt;/SPAN&gt; iFirst&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Integer&lt;/SPAN&gt;&lt;br /&gt;&lt;SPAN style="color:#00007F"&gt;Dim&lt;/SPAN&gt; iLast&amp;#160;&amp;#160; &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Integer&lt;/SPAN&gt;&lt;br /&gt;&lt;SPAN style="color:#00007F"&gt;Dim&lt;/SPAN&gt; i&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Integer&lt;/SPAN&gt;&lt;br /&gt;&lt;SPAN style="color:#00007F"&gt;Dim&lt;/SPAN&gt; j&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Integer&lt;/SPAN&gt;&lt;br /&gt;&lt;SPAN style="color:#00007F"&gt;Dim&lt;/SPAN&gt; sTemp&amp;#160;&amp;#160; &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; String&lt;br /&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;iFirst = &lt;SPAN style="color:#00007F"&gt;LBound&lt;/SPAN&gt;(arrStrings)&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;iLast = &lt;SPAN style="color:#00007F"&gt;UBound&lt;/SPAN&gt;(arrStrings)&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt; SortOrder = xlAscending &lt;SPAN style="color:#00007F"&gt;Then&lt;/SPAN&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;For i = iFirst &lt;SPAN style="color:#00007F"&gt;To&lt;/SPAN&gt; iLast - 1&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;For j = i + 1 &lt;SPAN style="color:#00007F"&gt;To&lt;/SPAN&gt; iLast&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt; Len(arrStrings(i)) &gt; Len(arrStrings(j)) &lt;SPAN style="color:#00007F"&gt;Then&lt;/SPAN&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;sTemp = arrStrings(j)&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;arrStrings(j) = arrStrings(i)&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;arrStrings(i) = sTemp&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Next&lt;/SPAN&gt; j&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Next&lt;/SPAN&gt; i&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Else&lt;/SPAN&gt;&amp;#160;&amp;#160; &lt;SPAN style="color:#007F00"&gt;' SortOrder = xlDescending&lt;/SPAN&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;For i = iFirst &lt;SPAN style="color:#00007F"&gt;To&lt;/SPAN&gt; iLast - 1&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;For j = i + 1 &lt;SPAN style="color:#00007F"&gt;To&lt;/SPAN&gt; iLast&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt; Len(arrStrings(i)) &lt; Len(arrStrings(j)) &lt;SPAN style="color:#00007F"&gt;Then&lt;/SPAN&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;sTemp = arrStrings(j)&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;arrStrings(j) = arrStrings(i)&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;arrStrings(i) = sTemp&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Next&lt;/SPAN&gt; j&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Next&lt;/SPAN&gt; i&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt; &lt;SPAN style="color:#007F00"&gt;' sortorder&lt;/SPAN&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;br /&gt;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Sub&lt;/SPAN&gt;&lt;br /&gt; &lt;br /&gt;&lt;br /&gt;&lt;SPAN style="color:#00007F"&gt;Public&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Sub&lt;/SPAN&gt; CalculateSelection()&lt;br /&gt;&lt;SPAN style="color:#007F00"&gt;' Called from a button in a menubar or popup&lt;/SPAN&gt;&lt;br /&gt;&lt;br /&gt;&lt;SPAN style="color:#00007F"&gt;On&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Error&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Resume&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Next&lt;/SPAN&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;Selection.Calculate&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br /&gt;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Sub&lt;/SPAN&gt;&lt;br /&gt;&lt;br /&gt;&lt;SPAN style="color:#00007F"&gt;Public&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Sub&lt;/SPAN&gt; GetPrecedents()&lt;br /&gt;&lt;SPAN style="color:#007F00"&gt;' Called from a button in a menubar or popup&lt;/SPAN&gt;&lt;br /&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;CalculatePrecedents Selection, &lt;SPAN style="color:#00007F"&gt;False&lt;/SPAN&gt;&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br /&gt;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Sub&lt;/SPAN&gt;&lt;/FONT&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;P Align='justify'&gt;&lt;br /&gt;And here's the boilerplate code that puts Calculate Precedents into an add-in's 'Workbook' object module and adds our function to the right-click popup menu for an Excel worksheet:&lt;br /&gt;&lt;/P&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;font face=Courier New&gt;&lt;SPAN style="color:#00007F"&gt;Option&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Explicit&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;Private&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Sub&lt;/SPAN&gt; Workbook_AddinInstall()&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;Dim&lt;/SPAN&gt; objCbtn &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; Office.CommandBarButton&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;Dim&lt;/SPAN&gt; objCbtn2 &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; Office.CommandBarButton&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;Dim&lt;/SPAN&gt; objCbar &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; Office.CommandBar&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;With&lt;/SPAN&gt; Application.CommandBars("Cell")&lt;br&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Set&lt;/SPAN&gt; objCbtn = .FindControl(, , "Calculate Precedents", , &lt;SPAN style="color:#00007F"&gt;True&lt;/SPAN&gt;)&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Do&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Until&lt;/SPAN&gt; objCbtn &lt;SPAN style="color:#00007F"&gt;Is&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Nothing&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;objCbtn.Delete&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Set&lt;/SPAN&gt; objCbtn = .FindControl(, , "Calculate Precedents", , &lt;SPAN style="color:#00007F"&gt;True&lt;/SPAN&gt;)&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Loop&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Set&lt;/SPAN&gt; objCbtn = .Controls.Add(msoControlButton, , , , &lt;SPAN style="color:#00007F"&gt;True&lt;/SPAN&gt;)&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;br&gt;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;With&lt;/SPAN&gt;&amp;#160;&amp;#160;&lt;SPAN style="color:#007F00"&gt;'Application.CommandBars("Cell")&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;With&lt;/SPAN&gt; objCbtn&lt;br&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;.BeginGroup = &lt;SPAN style="color:#00007F"&gt;True&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;.Caption = "Calculate Precedents"&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;.DescriptionText = "Locate all precedents and calculate recursively"&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;.OnAction = "GetPrecedents"&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;.Tag = "Calculate Precedents"&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;.TooltipText = "Locate all precedents and calculate recursively"&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;.FaceId = 452&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;With&lt;/SPAN&gt; &lt;SPAN style="color:#007F00"&gt;'objCbtn&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;Set&lt;/SPAN&gt; objCbtn = &lt;SPAN style="color:#00007F"&gt;Nothing&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;With&lt;/SPAN&gt; Application.CommandBars("Cell")&lt;br&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Set&lt;/SPAN&gt; objCbtn = .FindControl(, , "Calculate Selection", , &lt;SPAN style="color:#00007F"&gt;True&lt;/SPAN&gt;)&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Do&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Until&lt;/SPAN&gt; objCbtn &lt;SPAN style="color:#00007F"&gt;Is&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Nothing&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;objCbtn.Delete&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Set&lt;/SPAN&gt; objCbtn = .FindControl(, , "Calculate Selection", , &lt;SPAN style="color:#00007F"&gt;True&lt;/SPAN&gt;)&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Loop&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Set&lt;/SPAN&gt; objCbtn = .Controls.Add(msoControlButton, , , , &lt;SPAN style="color:#00007F"&gt;True&lt;/SPAN&gt;)&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;br&gt;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;With&lt;/SPAN&gt;&amp;#160;&amp;#160;&lt;SPAN style="color:#007F00"&gt;'Application.CommandBars("Cell")&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;With&lt;/SPAN&gt; objCbtn&lt;br&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;.Caption = "Calculate Selection"&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;.OnAction = "CalculateSelection"&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;.Tag = "Calculate Selection"&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;.TooltipText = "Calculate the selected range"&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;.FaceId = 346&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;With&lt;/SPAN&gt; &lt;SPAN style="color:#007F00"&gt;'objCbtn&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;Set&lt;/SPAN&gt; objCbtn = &lt;SPAN style="color:#00007F"&gt;Nothing&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Sub&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;Private&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Sub&lt;/SPAN&gt; Workbook_AddinUninstall()&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;Dim&lt;/SPAN&gt; objCbtn &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; Office.CommandBarButton&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;With&lt;/SPAN&gt; Application.CommandBars("Cell")&lt;br&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Set&lt;/SPAN&gt; objCbtn = .FindControl(, , "Calculate Precedents", , &lt;SPAN style="color:#00007F"&gt;True&lt;/SPAN&gt;)&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Not&lt;/SPAN&gt; objCbtn &lt;SPAN style="color:#00007F"&gt;Is&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Nothing&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Then&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;objCbtn.Delete&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Set&lt;/SPAN&gt; objCbtn = .FindControl(, , "Calculate Selection", , &lt;SPAN style="color:#00007F"&gt;True&lt;/SPAN&gt;)&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Not&lt;/SPAN&gt; objCbtn &lt;SPAN style="color:#00007F"&gt;Is&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Nothing&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Then&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;objCbtn.Delete&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;With&lt;/SPAN&gt;&amp;#160;&amp;#160;&lt;SPAN style="color:#007F00"&gt;'Application.CommandBars("Cell")&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;Set&lt;/SPAN&gt; objCbtn = &lt;SPAN style="color:#00007F"&gt;Nothing&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Sub&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;Private&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Sub&lt;/SPAN&gt; Workbook_BeforeClose(Cancel &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Boolean&lt;/SPAN&gt;)&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;Call&lt;/SPAN&gt; Workbook_AddinUninstall&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Sub&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;Private&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Sub&lt;/SPAN&gt; Workbook_Open()&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;Call&lt;/SPAN&gt; Workbook_AddinInstall&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Sub&lt;/SPAN&gt;&lt;br&gt;&lt;/FONT&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1800518423097919889-2462796448728466786?l=excellerando.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://excellerando.blogspot.com/feeds/2462796448728466786/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://excellerando.blogspot.com/2009/12/vba-function-to-force-calculation-of.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1800518423097919889/posts/default/2462796448728466786'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1800518423097919889/posts/default/2462796448728466786'/><link rel='alternate' type='text/html' href='http://excellerando.blogspot.com/2009/12/vba-function-to-force-calculation-of.html' title='A VBA function to force calculation of a cell&apos;s precedents'/><author><name>Nigel Heffernan</name><uri>http://www.blogger.com/profile/08954578765691578714</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://1.bp.blogspot.com/_B9BAdln8o_A/SYY_TkYyu4I/AAAAAAAAAAs/z5CQ01NUtTI/S220/Cropped+Blog+Shot.JPG'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_B9BAdln8o_A/SxgEXA4DLsI/AAAAAAAAABg/V8CvFWEenu8/s72-c/TraceDependants.JPG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1800518423097919889.post-5486687487728191800</id><published>2009-12-01T15:22:00.002Z</published><updated>2009-12-01T15:59:50.586Z</updated><title type='text'>Who owns that file? Using WMI to identify the owner of a file</title><content type='html'>&lt;P Align='justify'&gt;&lt;br /&gt;Every now and again, I have the job of archiving vast numbers of workbooks: a penance for failing to move the users on from using Excel for primary data storage and saving down each day's valuations in a separate sheet.&lt;br /&gt;&lt;/P&gt;&lt;br /&gt;&lt;P Align='justify'&gt;&lt;br /&gt;As you can imagine, this gets tedious, and it needs automating... Any fool can write a script to delete, zip or move files around, and many fools have done so: few were so damned by their actions in a past life as to be doomed to &lt;i&gt;notify the file owners by email&lt;/i&gt;.&lt;br /&gt;&lt;/P&gt;&lt;br /&gt;&lt;P Align='justify'&gt;&lt;br /&gt;&lt;B&gt;But who owns the file?&lt;/B&gt;&lt;br /&gt;&lt;/P&gt;&lt;br /&gt;&lt;P Align='justify'&gt;&lt;br /&gt;Every now and again, Windows shows that a simple question can be made to have an absurdly difficult answer, and finding the owner of a named file is one of the worst I've come across. The API calls have been analysed and explained by Emmet Gray:&lt;br /&gt;&lt;BR /&gt;&lt;BR /&gt;&lt;br /&gt;http://www.emmet-gray.com/Articles/GetOwner.htm&lt;br /&gt;&lt;BR /&gt;&lt;BR /&gt;&lt;br /&gt;You are welcome to read it and try out the code: it is a remarkable feat of analysis and simplification in the face of the wilfully illogical and obscure and, despite being pared down and superbly documented, it is a truly intimidating piece of API coding. You cannot extract the Security Descriptor of a file in less than a hundred lines of code and, when you've got it, you will rapidly realise that opening up and interrogating a file's Security Descriptor for the SID of the user only leads to an even deeper travail in extracting a human-readable user name. I do not believe that it can be done in less than a thousand lines of code and I would question whether it can be done reproducibly and reliably - let lone clearly - which is to say that it probably shouldn't be done in VBA.&lt;br /&gt;&lt;/P&gt;&lt;br /&gt;&lt;P Align='justify'&gt;&lt;br /&gt;But I've still got the job of digging out the user names for all the files I'm archiving. The code snippet below uses WMI - Windows Management Information - a truly horrible API released (but not documented) by Microsoft for systems administrators. If WMI is an improvement, I shudder to think what they had to do before it existed, and I am astonished that the haven't all turned into the BOFH (Look it up. But not at work). But it is at least &lt;i&gt;short&lt;/i&gt;. All it is, is a 'Get Owner' function and a small Scripting wrapper that searches a folder and lists the files...&lt;br /&gt;&lt;/P&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;BLOCKQUOTE&gt;&lt;br /&gt;&lt;font face=Courier New&gt;&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;Private&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Function&lt;/SPAN&gt; GetFileOwner(strFile &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;String&lt;/SPAN&gt;, &lt;SPAN style="color:#00007F"&gt;Optional&lt;/SPAN&gt; WithDomainName &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Boolean&lt;/SPAN&gt; = &lt;SPAN style="color:#00007F"&gt;False&lt;/SPAN&gt;) &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;String&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#007F00"&gt;' Returns the owner of a file or folder, or a comma-delimited list if there are multiple owners.&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#007F00"&gt;' Usage:&lt;/SPAN&gt;&lt;br&gt;&lt;SPAN style="color:#007F00"&gt;'&amp;#160;&amp;#160;&amp;#160;&amp;#160; Debug.Print GetFileOwner("H:\Personal\MyFile.txt")&lt;/SPAN&gt;&lt;br&gt;&lt;SPAN style="color:#007F00"&gt;'&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; heffernann&lt;/SPAN&gt;&lt;br&gt;&lt;SPAN style="color:#007F00"&gt;'&lt;/SPAN&gt;&lt;br&gt;&lt;SPAN style="color:#007F00"&gt;'&amp;#160;&amp;#160;&amp;#160;&amp;#160; Debug.Print GetFileOwner("H:\Personal\MyFile.txt", TRUE)&lt;/SPAN&gt;&lt;br&gt;&lt;SPAN style="color:#007F00"&gt;'&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; OLYMPUS\heffernann&lt;/SPAN&gt;&lt;br&gt;&lt;SPAN style="color:#007F00"&gt;'&lt;/SPAN&gt;&lt;br&gt;&lt;SPAN style="color:#007F00"&gt;'&amp;#160;&amp;#160;&amp;#160;&amp;#160; Debug.Print GetFileOwner("\\OLYMPUS\Users\heffernann\Personal\MyFile.txt", TRUE)&lt;/SPAN&gt;&lt;br&gt;&lt;SPAN style="color:#007F00"&gt;'&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; [returns nothing, see below]&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#007F00"&gt;' This works with local drives and mapped drives, but fully-qualified network paths do not work.&lt;/SPAN&gt;&lt;br&gt;&lt;SPAN style="color:#007F00"&gt;' According to the documentation, WMI will return an error when the file owner is a user who has&lt;/SPAN&gt;&lt;br&gt;&lt;SPAN style="color:#007F00"&gt;' been purged from the system. However, all that happens here is that we get an empty collection&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#007F00"&gt;' Author: Nigel Heffernan&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#007F00"&gt;' The underlying technology is WMI (Windows Management Information).&lt;/SPAN&gt;&lt;br&gt;&lt;SPAN style="color:#007F00"&gt;' The WMI documentation is very poor, even by the standards of MSDN.&lt;/SPAN&gt;&lt;br&gt;&lt;SPAN style="color:#007F00"&gt;' However, Microsoft's 'Hey! Scripting Guy!' site has usable information:&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#007F00"&gt;'&amp;#160;&amp;#160; http://www.microsoft.com/technet/scriptcenter/resources/qanda/oct04/hey1007.mspx&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;Static&lt;/SPAN&gt; objWMIService &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Object&lt;/SPAN&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#007F00"&gt;' Persistent object: this is called repeatedly,&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#007F00"&gt;' so you may prefer to declare it at module level&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#007F00"&gt;' and instantiate/dismiss it explicitly&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;Dim&lt;/SPAN&gt; colItems &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Object&lt;/SPAN&gt;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;Dim&lt;/SPAN&gt; objItem &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Object&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;Dim&lt;/SPAN&gt; strComputer &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;String&lt;/SPAN&gt;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;Dim&lt;/SPAN&gt; strWMI_Query &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;String&lt;/SPAN&gt;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;Dim&lt;/SPAN&gt; strOwner &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;String&lt;/SPAN&gt;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;Dim&lt;/SPAN&gt; strOutput &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;String&lt;/SPAN&gt;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;Dim&lt;/SPAN&gt; iCount &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Integer&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;Const&lt;/SPAN&gt; wbemFlagReturnImmediately &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Long&lt;/SPAN&gt; = 16&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;Const&lt;/SPAN&gt; wbemFlagForwardOnly &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Long&lt;/SPAN&gt; = 32&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;Dim&lt;/SPAN&gt; IFlags &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Long&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;IFlags = wbemFlagReturnImmediately + wbemFlagForwardOnly&lt;br&gt;&lt;br&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;strComputer = "."&amp;#160;&amp;#160; &lt;SPAN style="color:#007F00"&gt;' WMI notation for 'This machine'&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#007F00"&gt;' WMI script sometimes works if remote machine names are specified&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#007F00"&gt;' but you'll need to specify the local path when looking up files&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;strWMI_Query = ""&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;strWMI_Query = strWMI_Query &amp; "ASSOCIATORS OF "&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;strWMI_Query = strWMI_Query &amp; "{Win32_LogicalFileSecuritySetting='" &amp; strFile &amp; "'}"&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;strWMI_Query = strWMI_Query &amp; " WHERE AssocClass=Win32_LogicalFileOwner ResultRole=Owner"&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#007F00"&gt;' WMI Association classes can be instantiated directly, but the syntax is arcane.&lt;/SPAN&gt;&lt;br&gt;&lt;SPAN style="color:#007F00"&gt;' Querying the WMI data service is simpler, if you can find a pre-existing query template&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt; objWMIService &lt;SPAN style="color:#00007F"&gt;Is&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Nothing&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Then&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Set&lt;/SPAN&gt; objWMIService = GetObject("winmgmts:" &amp; "{impersonationLevel=impersonate}!\\" &amp; strComputer &amp; "\root\cimv2")&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#007F00"&gt;' ExecQuery is relatively easy to do, but rather slow&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Set&lt;/SPAN&gt; colItems = objWMIService.ExecQuery(strWMI_Query, , IFlags)&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#007F00"&gt;' AssociatorsOf is faster, and is documented here: http://msdn.microsoft.com/en-us/library/aa393858(VS.85).aspx&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#007F00"&gt;'Set colItems = objWMIService.AssociatorsOf("winmgmts:" &amp; "{impersonationLevel=impersonate}!\\" &amp; strComputer &amp; "\root\cimv2", "Win32_LogicalFileOwner", "SWbemObjectEx", "Owner", , , , , , IFlags)&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;strOutput = ""&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;iCount = 0&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;On&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Error&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Resume&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Next&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;For&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Each&lt;/SPAN&gt; objItem &lt;SPAN style="color:#00007F"&gt;In&lt;/SPAN&gt; colItems&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;strOwner = ""&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt; WithDomainName &lt;SPAN style="color:#00007F"&gt;Then&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;strOwner = objItem.ReferencedDomainName &amp; "\" &amp; objItem.AccountName&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Else&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;strOwner = objItem.AccountName &amp; ","&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;strOutput = strOutput &amp; strOwner&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Next&lt;/SPAN&gt; objItem&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&lt;SPAN style="color:#007F00"&gt;'Trim trailing comma:&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;strOutput = Trim(strOutput)&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt; Len(strOutput) &gt; 0 &lt;SPAN style="color:#00007F"&gt;Then&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;strOutput = Left(strOutput, Len(strOutput) - 1)&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;GetFileOwner = strOutput&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Function&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;Public&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Sub&lt;/SPAN&gt; RecurseFolder(strFolder &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;String&lt;/SPAN&gt;, &lt;SPAN style="color:#00007F"&gt;Optional&lt;/SPAN&gt; RecursionLevel &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Integer&lt;/SPAN&gt; = 0, &lt;SPAN style="color:#00007F"&gt;Optional&lt;/SPAN&gt; minDateLastModified &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; Date = 0, &lt;SPAN style="color:#00007F"&gt;Optional&lt;/SPAN&gt; minSize &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Double&lt;/SPAN&gt; = 0)&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#007F00"&gt;' Recursive Subroutine to enumerate the contents of an NT folder.&lt;/SPAN&gt;&lt;br&gt;&lt;SPAN style="color:#007F00"&gt;' Writes the results to a log file&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#007F00"&gt;' Subfolders are enumerated by a recursive call&lt;/SPAN&gt;&lt;br&gt;&lt;SPAN style="color:#007F00"&gt;' For use in Excel VBA: can be converted to VBScript&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#007F00"&gt;' REQUIRES module-level declarations:&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#007F00"&gt;'&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; objLogStream (Scripting.TextStream)&lt;/SPAN&gt;&lt;br&gt;&lt;SPAN style="color:#007F00"&gt;'&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; objFSO (Scripting.FileSystemObject)&lt;/SPAN&gt;&lt;br&gt;&lt;SPAN style="color:#007F00"&gt;'&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; LogfileName&amp;#160;&amp;#160;(string)&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#007F00"&gt;' REQUIRES Subroutines and Functions:&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#007F00"&gt;'&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; GetFileOwner&lt;/SPAN&gt;&lt;br&gt;&lt;SPAN style="color:#007F00"&gt;'&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Logfile&lt;/SPAN&gt;&lt;br&gt;&lt;SPAN style="color:#007F00"&gt;'&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; CloseLogFile&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#007F00"&gt;' VBA Declarations:&lt;/SPAN&gt;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;Dim&lt;/SPAN&gt; objFolder &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; Folder&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;Dim&lt;/SPAN&gt; objSubFolder &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; Folder&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;Dim&lt;/SPAN&gt; objFile&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; File&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;Dim&lt;/SPAN&gt; strFile&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;String&lt;/SPAN&gt;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;Dim&lt;/SPAN&gt; strMessage&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;String&lt;/SPAN&gt;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;Dim&lt;/SPAN&gt; strOwner&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;String&lt;/SPAN&gt;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;Dim&lt;/SPAN&gt; strSize&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;String&lt;/SPAN&gt;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;Dim&lt;/SPAN&gt; lngCountLog &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Long&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt; objFSO &lt;SPAN style="color:#00007F"&gt;Is&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Nothing&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Then&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Set&lt;/SPAN&gt; objFSO = &lt;SPAN style="color:#00007F"&gt;New&lt;/SPAN&gt; FileSystemObject&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;Set&lt;/SPAN&gt; objFolder = objFSO.GetFolder(strFolder)&lt;br&gt;&lt;br&gt;&lt;br&gt;Application.StatusBar = "Searching folders: " &amp; RecursionLevel &amp; " layers: " &amp; strFolder&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#007F00"&gt;' Use this if you're reporting progress on a worksheet (requires named range as shown):&lt;/SPAN&gt;&lt;br&gt;ThisWorkbook.Names("CurrentFolder").RefersToRange.Value = strFolder&lt;br&gt;&lt;br&gt;strOwner = GetFileOwner(objFolder.Path)&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;On&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Error&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Resume&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Next&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;strMessage = ""&lt;br&gt;strMessage = strMessage &amp; "FOLDER" &amp; vbTab &amp; objFolder.name &amp; vbTab &amp; 0 &amp; vbTab &amp; objFolder.DateLastModified &amp; vbTab &amp; objFolder.DateLastAccessed &amp; vbTab &amp; strOwner &amp; vbTab &amp; objFolder.Path &amp; vbTab &amp; RecursionLevel&lt;br&gt;Logfile strMessage&lt;br&gt;&lt;br&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;lngCountLog = 0&lt;br&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;For&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Each&lt;/SPAN&gt; objFile &lt;SPAN style="color:#00007F"&gt;In&lt;/SPAN&gt; objFolder.Files&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;strFile = objFile.Path&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt; objFile.DateLastModified &gt;= minDateLastModified &lt;SPAN style="color:#00007F"&gt;Then&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt; objFile.Size &gt;= minSize &lt;SPAN style="color:#00007F"&gt;Then&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;strOwner = ""&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;strOwner = GetFileOwner(objFile.Path)&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;strMessage = ""&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;strMessage = strMessage &amp; "FILE" &amp; vbTab &amp; objFile.name &amp; vbTab &amp; objFile.Size &amp; vbTab &amp; objFile.DateLastModified &amp; vbTab &amp; objFile.DateLastAccessed &amp; vbTab &amp; strOwner &amp; vbTab &amp; objFolder.Path &amp; vbTab &amp; RecursionLevel&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;Logfile strMessage&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;lngCountLog = lngCountLog + 1&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt;&amp;#160;&amp;#160;&lt;SPAN style="color:#007F00"&gt;'objFile.Size &gt; minSize Then&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt; &lt;SPAN style="color:#007F00"&gt;' objFile.DateLastModified &gt; minDateLastModified&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Next&lt;/SPAN&gt; objFile&lt;br&gt;&lt;br&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#007F00"&gt;' Use these f you're reporting progress on a worksheet (requires named ranges as shown):&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;ThisWorkbook.Names("CurrentCount").RefersToRange.Value = ThisWorkbook.Names("CurrentCount").RefersToRange.Value + objFolder.Files.Count&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;ThisWorkbook.Names("CurrentCountLogged").RefersToRange.Value = ThisWorkbook.Names("CurrentCountLogged").RefersToRange.Value + lngCountLog&lt;br&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;For&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Each&lt;/SPAN&gt; objSubFolder &lt;SPAN style="color:#00007F"&gt;In&lt;/SPAN&gt; objFolder.SubFolders&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;RecursionLevel = RecursionLevel + 1&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;RecurseFolder objSubFolder.Path, RecursionLevel, minDateLastModified, minSize&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;RecursionLevel = RecursionLevel - 1&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Next&lt;/SPAN&gt; obj&lt;SPAN style="color:#00007F"&gt;Sub&lt;/SPAN&gt;Folder&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Sub&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;Public&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Sub&lt;/SPAN&gt; Logfile(strMessage)&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#007F00"&gt;' Stream a message to a log file&lt;/SPAN&gt;&lt;br&gt;&lt;SPAN style="color:#007F00"&gt;' Opens the file if required.&lt;/SPAN&gt;&lt;br&gt;&lt;SPAN style="color:#007F00"&gt;' You are advised to close the file explicitly when your process has completed: use CloseLogFile for this&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#007F00"&gt;' REQUIRES module-level declarations:&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#007F00"&gt;'&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; objLogStream (Scripting.TextStream)&lt;/SPAN&gt;&lt;br&gt;&lt;SPAN style="color:#007F00"&gt;'&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; objFSO (Scripting.FileSystemObject)&lt;/SPAN&gt;&lt;br&gt;&lt;SPAN style="color:#007F00"&gt;'&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; LogfileName&amp;#160;&amp;#160;(string)&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;Dim&lt;/SPAN&gt; strHeader &lt;SPAN style="color:#00007F"&gt;As&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;String&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt; objLogStream &lt;SPAN style="color:#00007F"&gt;Is&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Nothing&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Then&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Set&lt;/SPAN&gt; objLogStream = objFSO.OpenTextFile(LogfileName, ForWriting, &lt;SPAN style="color:#00007F"&gt;True&lt;/SPAN&gt;)&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;strHeader = "Type" &amp; vbTab &amp; "Filename" &amp; vbTab &amp; "Size" &amp; vbTab &amp; "DateLastModified" &amp; vbTab &amp; "DateLastAccessed" &amp; vbTab &amp; "Owner" &amp; vbTab &amp; "ParentFolder" &amp; vbTab &amp; "PathDepth"&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;objLogStream.WriteLine strHeader&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;objLogStream.WriteLine strMessage&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Sub&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;Public&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Sub&lt;/SPAN&gt; CloseLogFile()&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt; objLogStream &lt;SPAN style="color:#00007F"&gt;Is&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Nothing&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Then&lt;/SPAN&gt;&lt;br&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;SPAN style="color:#00007F"&gt;Exit&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;Sub&lt;/SPAN&gt;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; &lt;SPAN style="color:#00007F"&gt;If&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;objLogStream.Close&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;Set&lt;/SPAN&gt; objLogStream = &lt;SPAN style="color:#00007F"&gt;Nothing&lt;/SPAN&gt;&lt;br&gt;&lt;br&gt;&lt;SPAN style="color:#00007F"&gt;End&lt;/SPAN&gt; Sub&lt;br&gt;&lt;br&gt;&lt;/FONT&gt;&lt;br /&gt;&lt;br /&gt;&lt;/BLOCKQUOTE&gt;&lt;br /&gt;&lt;br /&gt;&lt;P Align='justify'&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;P Align='justify'&gt;&lt;br /&gt;Feel free to try out the code - and do, please, feel free to tell me how you got on. Oh, and watch out for line breaks imposed by Blogger's atomatic formatting.&lt;br /&gt;&lt;/P&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1800518423097919889-5486687487728191800?l=excellerando.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://excellerando.blogspot.com/feeds/5486687487728191800/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://excellerando.blogspot.com/2009/12/who-owns-that-file-using-wmi-to.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1800518423097919889/posts/default/5486687487728191800'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1800518423097919889/posts/default/5486687487728191800'/><link rel='alternate' type='text/html' href='http://excellerando.blogspot.com/2009/12/who-owns-that-file-using-wmi-to.html' title='Who owns that file? Using WMI to identify the owner of a file'/><author><name>Nigel Heffernan</name><uri>http://www.blogger.com/profile/08954578765691578714</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://1.bp.blogspot.com/_B9BAdln8o_A/SYY_TkYyu4I/AAAAAAAAAAs/z5CQ01NUtTI/S220/Cropped+Blog+Shot.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1800518423097919889.post-6690202136956839921</id><published>2009-02-04T02:32:00.008Z</published><updated>2009-02-04T02:44:16.234Z</updated><title type='text'>Detecting an array variant in Excel VBA</title><content type='html'>&lt;BR /&gt;This will return 0 for scalar variables and a positive integer for arrays:&lt;br /&gt;&lt;BR /&gt;&lt;br /&gt;&lt;BR /&gt;&lt;span style="font-family:FIXEDSYS,SYSTEM,TERMINAL;"&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 0, 153);"&gt;InStr&lt;/span&gt;(&lt;span style="color: rgb(51, 0, 153);"&gt;TypeName&lt;/span&gt;(varTest), "()")&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;BR /&gt;&lt;br /&gt;&lt;BR /&gt;The return values cast to Boolean TRUE or FALSE and can be used directly in an &lt;span style="font-family:FIXEDSYS,SYSTEM,TERMINAL;"&gt;IF... THEN&lt;/span&gt; clause.&lt;br /&gt;&lt;BR /&gt;&lt;br /&gt;&lt;BR /&gt;Kludgy, but effective. Note that this detects empty arrays: their typename isn't "empty", it is &lt;span style="font-family:FIXEDSYS,SYSTEM,TERMINAL;"&gt;Empty()&lt;/span&gt;&lt;br /&gt;&lt;BR /&gt;&lt;br /&gt;&lt;BR /&gt;The correct approach is to use the native VBA function VarType(), which reads the numeric type constant. An integer is VarType 2 (vbInteger) and the vbArray constant (8192) is used in a bitwise operation to give 8192 for an array of integers: [vbInteger OR vbArray]&lt;br /&gt;&lt;BR /&gt;&lt;br /&gt;&lt;BR /&gt;The 'correct' approach fails when you try to wrap this logic in a function, for reasons stated in the comments...&lt;br /&gt;&lt;span style="font-family:FIXEDSYS,SYSTEM,TERMINAL;"&gt;&lt;br /&gt;&lt;BR /&gt;&lt;br /&gt;&lt;BR /&gt;&lt;span style="color: rgb(51, 0, 153);"&gt;Public Function&lt;/span&gt; VariantIsArray(varTest &lt;span style="color: rgb(51, 0, 153);"&gt;As Variant&lt;/span&gt;) &lt;span style="color: rgb(51, 0, 153);"&gt;As Boolean&lt;/span&gt;&lt;br /&gt;&lt;BR /&gt;&lt;span style="color:green;"&gt;&lt;br /&gt;&lt;BR /&gt;' Return TRUE if varTest is array&lt;br /&gt;&lt;BR /&gt;' FALSE for User-defined types&lt;br /&gt;&lt;BR /&gt;&lt;br /&gt;&lt;BR /&gt;' Note that all ranges of two or more cells are cast to an array variant&lt;br /&gt;&lt;BR /&gt;' even when you omit the '.Value' property. All object types that expose&lt;br /&gt;&lt;BR /&gt;' a default property will pass it into our function's parameter, instead&lt;br /&gt;&lt;BR /&gt;' of a reference to the object itself. There can be no reliable and self&lt;br /&gt;&lt;BR /&gt;' -contained IsArray() function in VBA,  because you have to run a prior&lt;br /&gt;&lt;BR /&gt;' test using IsObject() in the calling function.&lt;br /&gt;&lt;BR /&gt;&lt;br /&gt;&lt;BR /&gt;&lt;br /&gt;&lt;BR /&gt;' What, you read the documentation and believed that IsArray() works? Try&lt;br /&gt;&lt;BR /&gt;' it on an array of objects, a single-member array, and an empty variant.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;BR /&gt;&lt;br /&gt;&lt;BR /&gt;    VariantIsArray = &lt;span style="color: rgb(51, 0, 153);"&gt;VarType&lt;/span&gt;(varTest)&lt;span style="color: rgb(51, 0, 153);"&gt; And vbArray&lt;/span&gt;&lt;br /&gt;&lt;BR /&gt;&lt;br /&gt;&lt;BR /&gt;&lt;span style="color: rgb(51, 0, 153);"&gt;End Function&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;BR /&gt;&lt;br /&gt;&lt;BR /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1800518423097919889-6690202136956839921?l=excellerando.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://excellerando.blogspot.com/feeds/6690202136956839921/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://excellerando.blogspot.com/2009/02/detecting-array-variant-in-excel-vba.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1800518423097919889/posts/default/6690202136956839921'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1800518423097919889/posts/default/6690202136956839921'/><link rel='alternate' type='text/html' href='http://excellerando.blogspot.com/2009/02/detecting-array-variant-in-excel-vba.html' title='Detecting an array variant in Excel VBA'/><author><name>Nigel Heffernan</name><uri>http://www.blogger.com/profile/08954578765691578714</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://1.bp.blogspot.com/_B9BAdln8o_A/SYY_TkYyu4I/AAAAAAAAAAs/z5CQ01NUtTI/S220/Cropped+Blog+Shot.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1800518423097919889.post-7080584788601231814</id><published>2009-01-30T23:25:00.016Z</published><updated>2009-02-04T04:08:52.807Z</updated><title type='text'>Using Microsoft Excel to feed batches of files to a command-line utility</title><content type='html'>&lt;h3&gt;Overview:&lt;br /&gt;&lt;/h3&gt;&lt;p align="justify"&gt;This is a kind of Swiss Army Knife: whenever I need to process batches of files, I pull out this simple application and tweak the code. I don't recommend it as production code - there are far better ways of doing this on a server - but ad-hoc jobs are the daily bread of a desktop developer. You could write it as a script - and a sysadmin would do exactly that - but Excel was the tool to hand when I realised that I had to do this job every week or so.&lt;/p&gt;&lt;br /&gt;&lt;h3&gt;Highlights for novice VBA coders:&lt;br /&gt;&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Looping through the files in a folder using &lt;b&gt;VBA.FileSystem.Dir()&lt;/b&gt;&lt;/li&gt;&lt;li&gt;Selecting and opening folders with the &lt;b&gt;Office.FileDialog&lt;/b&gt; Object&lt;/li&gt;&lt;li&gt;Using the Windows Scripting Host Object Model  -  &lt;b&gt;wshom.ocx&lt;/b&gt;:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;The File System Object  -  &lt;b&gt;IWshRuntimeLibrary.FileSystemObject&lt;/b&gt;&lt;/li&gt; &lt;li&gt;The Execution Object  -  &lt;b&gt;IWshRuntimeLibrary.WshExec&lt;/b&gt;&lt;/li&gt; &lt;li&gt;The Shell Object  -  &lt;b&gt;IWshRuntimeLibrary.WshShell&lt;/b&gt;&lt;/li&gt; &lt;/ul&gt;&lt;/li&gt;&lt;li&gt;Reading STDIO, the standard input/output stream of a command-line executable&lt;/li&gt;&lt;li&gt;Reading and logging STERR, the error message stream of a command-line executable.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;The background to this...&lt;/h3&gt;&lt;p align="justify"&gt;Processing batches of files... Don't we just love the daily grind of the COBOL era? Except that in the real world, almost every trading and invoicing system has some kind of back-end audit and reconciliation function, separated from the end-to-end streams of XML that you hope are running smoothly in the foreground. These audit systems tend to run on FTP file drops from counterparties - brokers, custodians, banks providing prime brokerage services etc - and they form part of every company's overnight processing.&lt;/p&gt;&lt;br /&gt;&lt;p align="justify"&gt;Mostly, we don't see any of this ('We' as in developers and users: sysadmins see a &lt;i&gt;lot&lt;/i&gt; of it). But every now and again, you'll be asked for a one-off job of loading or reprocessing a bunch of files where the regular process has failed, or was never written because someone in the Back Office only does it once a year.&lt;/p&gt;&lt;p align="justify"&gt;The worst of these jobs consist of feeding files into a command-line executable; this particular example involves decrypting them with pgp.exe - and no, I didn't choose to do it that way, but getting a pgp add-in and transferring the keyring was just too much work. The short version is, every single file in a daily batch of 27 needs a long and fiddly command-line with five parameters, and I've automated the process with a cuddly point-and-click interface.&lt;br /&gt;&lt;/p&gt;&lt;p align="justify"&gt;You can adapt this code to work with any command-line executable, even the good old DOS &lt;b&gt;COPY&lt;/b&gt; command if you feel that the exercise will be good for you. Ambitious students can implement a drag-and drop, using controls available in MSForms.2 - please put the code into a comment when you do, so we can all see how you did it: the drag-and-drop events don't &lt;i&gt;quite&lt;/i&gt; do what you expect in Excel!&lt;/p&gt;&lt;br /&gt;&lt;h3&gt;Here's a picture of a spreadsheet used as a form:&lt;br /&gt;&lt;/h3&gt;&lt;center&gt;&lt;br /&gt;&lt;img src="http://pics.livejournal.com/hairyears/pic/000aqyqk" alt="The sheet or userform looks like this" title="The sheet or userform looks like this" width="534" height="348" /&gt;&lt;br /&gt;&lt;/center&gt;&lt;br /&gt;&lt;h3&gt;The VBA code behind the one and only worksheet:&lt;br /&gt;&lt;/h3&gt;&lt;br /&gt;&lt;p align="justify"&gt;Feel free to put it in your own userform instead of a worksheet. Also: watch out when you copy-and-paste. I've tested this, but there's always a possibility that Blogger has reformatted a line break or inserted HTML that breaks the VBA syntax.&lt;/p&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;&lt;nobr&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 0);font-family:Courier New;font-size:85%;"  &gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;Option Explicit&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;hr  style="font-size:78%;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 128, 0);"&gt;' This is a simple batch-processing appl&lt;wbr&gt;ication: a wrapper for a command-line&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 128, 0);"&gt;' programme that processes all the fi&lt;wbr&gt;les in a folder. The example applicatio&lt;wbr&gt;n&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 128, 0);"&gt;' is for batch decryption using pgp.exe,&lt;wbr&gt; but this can be adapted to almost a&lt;wbr&gt;ny&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 128, 0);"&gt;' command-line application, script or sh&lt;wbr&gt;ell command.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 128, 0);"&gt;' This was built into a worksheet; if yo&lt;wbr&gt;u prefer, you can put all this code&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 128, 0);"&gt;' into a userform. But watch out for t&lt;wbr&gt;he dependency on named ranges; you'll&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 128, 0);"&gt;' need to recode all this to use Textbox&lt;wbr&gt;es or Win32 common-dialog controls.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 128, 0);"&gt;' The following components are assumed t&lt;wbr&gt;o exist and are mandatory:&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 128, 0);"&gt;&lt;br /&gt;' Excel Named Ranges:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 128, 0);"&gt;'       SourceFolder&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 128, 0);"&gt;'       TargetFolder&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 128, 0);"&gt;' The following components are optional b&lt;wbr&gt;ut the code is difficult to understand&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 128, 0);"&gt;' if they are not included:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 128, 0);"&gt;' MSForms2 CommandButton Objects:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 128, 0);"&gt;'   cmdGo&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 128, 0);"&gt;'   cmdGetSourceFolder&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 128, 0);"&gt;'   cmdGetTargetFolder&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 128, 0);"&gt;'   cmdOpenSource&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 128, 0);"&gt;'   cmdOpenTarget&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 128, 0);"&gt;' In order to use this specific example,&lt;wbr&gt; you will need pgp.exe and an RSA keyrin&lt;wbr&gt;g.&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 128, 0);"&gt;' DOS 'copy' would work just as well: th&lt;wbr&gt;e minimum features are that it has Comma&lt;wbr&gt;nd-&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 128, 0);"&gt;' Line parameters for a source file and a&lt;wbr&gt;n output file.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;Private Sub&lt;/span&gt; cmdGo_Click()&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 128, 0);"&gt;' The Big Button Marked 'GO'&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 128, 0);"&gt;' This launches the batch process.&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 128, 0);"&gt;' Runs the command-line utility on ev&lt;wbr&gt;ery matching file in the source folder.&lt;wbr&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 128, 0);"&gt;' Creates a log file.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;On Error GoTo&lt;/span&gt; ErrSub&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;Const&lt;/span&gt; FILE_PATTERN  &lt;span style="color: rgb(0, 0, 128);"&gt;As String&lt;/span&gt; = "*.pgp"&lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;Const&lt;/span&gt; LOG_FILE      &lt;span style="color: rgb(0, 0, 128);"&gt;As String&lt;/span&gt; = "LogFile.txt"&lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;Const&lt;/span&gt; ERROR_FILE    &lt;span style="color: rgb(0, 0, 128);"&gt;As String&lt;/span&gt; = "Error.txt"&lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;Const&lt;/span&gt; KEYRING_NAME  &lt;span style="color: rgb(0, 0, 128);"&gt;As String&lt;/span&gt; = ".PRIVATE3"&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;Dim&lt;/span&gt; strCmd &lt;span style="color: rgb(0, 0, 128);"&gt;As String&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;Dim&lt;/span&gt; strFile &lt;span style="color: rgb(0, 0, 128);"&gt;As String&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;Dim&lt;/span&gt; strFolder_Target &lt;span style="color: rgb(0, 0, 128);"&gt;As String&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;Dim&lt;/span&gt; strFolder_Source &lt;span style="color: rgb(0, 0, 128);"&gt;As String&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;Dim&lt;/span&gt; iResult &lt;span style="color: rgb(0, 0, 128);"&gt;As Integer&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;Dim&lt;/span&gt; iFile  &lt;span style="color: rgb(0, 0, 128);"&gt;As Integer&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;Dim&lt;/span&gt; iFileCount &lt;span style="color: rgb(0, 0, 128);"&gt;As Integer&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;Dim&lt;/span&gt; strFileTarget &lt;span style="color: rgb(0, 0, 128);"&gt;As String&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;Dim&lt;/span&gt; boolError &lt;span style="color: rgb(0, 0, 128);"&gt;As Boolean&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 128, 0);"&gt;' Help on the Windows Scripting host is a&lt;wbr&gt;vailable here:&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 128, 0);"&gt;' http://msdn2.microsoft.com/en-us/libra&lt;wbr&gt;ry/98591fh7.aspx&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 128, 0);"&gt;' Windows Script Host Object Model&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 128, 0);"&gt;' C:\WINDOWS\system32\wshom.ocx&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;Dim&lt;/span&gt; objFSO &lt;span style="color: rgb(0, 0, 128);"&gt;As&lt;/span&gt; IWshRuntimeLibrary.FileSystemObject&lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;Dim&lt;/span&gt; oxLogFile &lt;span style="color: rgb(0, 0, 128);"&gt;As&lt;/span&gt; IWshRuntimeLibrary.TextStream&lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;Dim&lt;/span&gt; objExec &lt;span style="color: rgb(0, 0, 128);"&gt;As&lt;/span&gt; IWshRuntimeLibrary.WshExec&lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;Dim&lt;/span&gt; objShell &lt;span style="color: rgb(0, 0, 128);"&gt;As&lt;/span&gt; IWshRuntimeLibrary.WshShell&lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;Dim&lt;/span&gt; objNetwork &lt;span style="color: rgb(0, 0, 128);"&gt;As&lt;/span&gt; IWshRuntimeLibrary.WshNetwork&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 128, 0);"&gt;' Read the user-specified folder path&lt;wbr&gt;s:&lt;/span&gt;&lt;br /&gt;strFolder_Target = ThisWorkbook.Names("T&lt;wbr&gt;argetFolder").RefersToRange.Value&lt;br /&gt;strFolder_Target = Trim(strFolder_Target)&lt;wbr&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;If&lt;/span&gt; Right(strFolder_Target, 1) &amp;lt;&amp;gt; "\" &lt;span style="color: rgb(0, 0, 128);"&gt;Then&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  strFolder_Target = strFolder_Target &lt;wbr&gt;&amp;amp; "\"&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;End If&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 128, 0);"&gt;'If the folder does not exist, create it:&lt;wbr&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;If&lt;/span&gt; Len(Dir(strFolder_Target, vbDirectory))&lt;wbr&gt; &amp;lt; 1 &lt;span style="color: rgb(0, 0, 128);"&gt;Then&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;     MkDir strFolder_Target&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;End If&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;strFolder_Source = ThisWorkbook.Names("S&lt;wbr&gt;ourceFolder").RefersToRange.Value&lt;br /&gt;strFolder_Source = Trim(strFolder_Source)&lt;wbr&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;If&lt;/span&gt; Right(strFolder_Source, 1) &amp;lt;&amp;gt; "\" &lt;span style="color: rgb(0, 0, 128);"&gt;Then&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;     strFolder_Source = strFolder_Source &lt;wbr&gt;&amp;amp; "\"&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;End If&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 128, 0);"&gt;' Create File system objects:&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;Set&lt;/span&gt; objNetwork = &lt;span style="color: rgb(0, 0, 128);"&gt;New&lt;/span&gt; IWshRuntimeLibrary.WshNetwork&lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;Set&lt;/span&gt; objShell = &lt;span style="color: rgb(0, 0, 128);"&gt;New&lt;/span&gt; IWshRuntimeLibrary.WshShell&lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;Set&lt;/span&gt; objFSO = &lt;span style="color: rgb(0, 0, 128);"&gt;New&lt;/span&gt; IWshRuntimeLibrary.FileSystemObject&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 128, 0);"&gt;' Create a log file:&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;Set&lt;/span&gt; oxLogFile = objFSO.OpenTextFile(strFold&lt;wbr&gt;er_Target &amp;amp; "LogFile.txt", ForWriting, &lt;span style="color: rgb(0, 0, 128);"&gt;True&lt;/span&gt;, TristateUseDefault)&lt;br /&gt;&lt;br /&gt;oxLogFile.WriteLine Now() &amp;amp; vbTab &amp;amp; "STA&lt;wbr&gt;RT FOLDER" &amp;amp; vbTab &amp;amp; strFolder_Source&lt;br /&gt;&lt;br /&gt;iFileCount = objFSO.GetFolder(strFolder_&lt;wbr&gt;Source).Files.Count&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 128, 0);"&gt;' Select the first of the source files f&lt;wbr&gt;or your command-line app.&lt;/span&gt;&lt;br /&gt;strFile = Dir(strFolder_Source &amp;amp; FILE_PA&lt;wbr&gt;TTERN)  &lt;span style="color: rgb(0, 128, 0);"&gt;' Yes, it seems odd to use Dir() when th&lt;wbr&gt;ere's a file&lt;/span&gt;&lt;br /&gt;                                            &lt;wbr&gt;        &lt;span style="color: rgb(0, 128, 0);"&gt;' system object, but it enumerates fi&lt;wbr&gt;les with wildcards&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;If&lt;/span&gt; objFSO.FileExists(strFolder_Target &amp;amp; ER&lt;wbr&gt;ROR_FILE) &lt;span style="color: rgb(0, 0, 128);"&gt;Then&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;      objFSO.DeleteFile strFolder_Target &amp;amp;&lt;wbr&gt; ERROR_FILE, &lt;span style="color: rgb(0, 0, 128);"&gt;True&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;End If&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 128, 0);"&gt;'Start loop, processing every matching f&lt;wbr&gt;ile in the folder...&lt;/span&gt;&lt;br /&gt;boolError = &lt;span style="color: rgb(0, 0, 128);"&gt;False&lt;/span&gt;&lt;br /&gt;iFile = 1&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;Do While&lt;/span&gt; Len(strFile) &amp;gt; 1&lt;br /&gt;&lt;br /&gt;  Application.StatusBar = "Rea&lt;wbr&gt;ding file " &amp;amp; iFile &amp;amp; " of " &amp;amp; iFileCoun&lt;wbr&gt;t&lt;br /&gt;&lt;br /&gt;  oxLogFile.WriteLine Now() &amp;amp; vbTa&lt;wbr&gt;b &amp;amp; "START FILE" &amp;amp; vbTab &amp;amp; Chr(34) &amp;amp; str&lt;wbr&gt;Folder_Source &amp;amp; strFile &amp;amp; Chr(34)&lt;br /&gt;&lt;br /&gt;  strFileTarget = ""&lt;br /&gt;  strFileTarget = strFolder_Ta&lt;wbr&gt;rget &amp;amp; Left(strFile, Len(strFile) - 4)&lt;br /&gt;&lt;br /&gt;        &lt;span style="color: rgb(0, 0, 128);"&gt;If&lt;/span&gt; objFSO.FileExists(strFileTarget) &lt;span style="color: rgb(0, 0, 128);"&gt;Then&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;                &lt;span style="color: rgb(0, 0, 128);"&gt;On Error Resume Next&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;                objFSO.DeleteFile strFileTar&lt;wbr&gt;get, &lt;span style="color: rgb(0, 0, 128);"&gt;True&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span style="color: rgb(0, 0, 128);"&gt;End If&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span style="color: rgb(0, 0, 128);"&gt;If&lt;/span&gt; objFSO.FileExists(strFileTarget) &lt;span style="color: rgb(0, 0, 128);"&gt;Then&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;      strFileTarget = strFolder_Ta&lt;wbr&gt;rget &amp;amp; "Copy_of_ &amp;amp; Left(strFile, Len(str&lt;wbr&gt;File) - 4)"&lt;br /&gt;&lt;br /&gt;        &lt;span style="color: rgb(0, 0, 128);"&gt;End If&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span style="color: rgb(0, 128, 0);"&gt;' Concatenate your command-line: use c&lt;wbr&gt;hr(34) instead of playing with nested qu&lt;wbr&gt;ote marks!&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;         strCmd = ""&lt;br /&gt;   strCmd = strCmd &amp;amp; "pgp.exe -v &lt;wbr&gt;"&lt;br /&gt;   strCmd = strCmd &amp;amp; "--decrypt &lt;wbr&gt;"&lt;br /&gt;   strCmd = strCmd &amp;amp; Chr(34) &amp;amp; strF&lt;wbr&gt;older_Source &amp;amp; strFile &amp;amp; Chr(34)&lt;br /&gt;         strCmd = strCmd &amp;amp; " --output &lt;wbr&gt;"&lt;br /&gt;   strCmd = strCmd &amp;amp; Chr(34) &amp;amp; strF&lt;wbr&gt;ileTarget &amp;amp; Chr(34)&lt;br /&gt;   strCmd = strCmd &amp;amp; " --passph&lt;wbr&gt;rase "&lt;br /&gt;   strCmd = strCmd &amp;amp; Chr(34) &amp;amp; KEYR&lt;wbr&gt;ING_NAME &amp;amp; Chr(34)&lt;br /&gt;&lt;br /&gt;         iResult = 0&lt;br /&gt;         iResult = objShell.Run(strCm&lt;wbr&gt;d, 0, &lt;span style="color: rgb(0, 0, 128);"&gt;True&lt;/span&gt;)&lt;br /&gt;&lt;br /&gt;         &lt;span style="color: rgb(0, 0, 128);"&gt;If&lt;/span&gt; iResult &amp;lt;&amp;gt; 0 &lt;span style="color: rgb(0, 0, 128);"&gt;Then&lt;/span&gt;  &lt;span style="color: rgb(0, 128, 0);"&gt;'Failed run: retry, with logging. ObjExe&lt;wbr&gt;c can see the message stream&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;       oxLogFile.WriteLine "" &amp;amp; vbT&lt;wbr&gt;ab &amp;amp; "RETRY FILE" &amp;amp; vbTab &amp;amp; "FAILED WITH E&lt;wbr&gt;RROR " &amp;amp; iResult &amp;amp; vbTab &amp;amp; strCmd&lt;br /&gt;&lt;br /&gt;       &lt;span style="color: rgb(0, 0, 128);"&gt;Set&lt;/span&gt; objExec = objShell.Exec(strCmd)&lt;br /&gt;&lt;br /&gt;                 &lt;span style="color: rgb(0, 0, 128);"&gt;Do While&lt;/span&gt; objExec.Status &amp;lt;= WshRunning&lt;br /&gt;&lt;br /&gt;                         &lt;span style="color: rgb(0, 0, 128);"&gt;Do Until&lt;/span&gt; objExec.StdOut.AtEndOfStream&lt;br /&gt;&lt;br /&gt;                                 oxLogFile.WriteLine &lt;wbr&gt;"" &amp;amp; vbTab &amp;amp; "MESSAGE" &amp;amp; vbTab &amp;amp; obj&lt;wbr&gt;Exec.StdOut.ReadLine&lt;br /&gt;&lt;br /&gt;                         &lt;span style="color: rgb(0, 0, 128);"&gt;Loop&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;                  &lt;span style="color: rgb(0, 0, 128);"&gt;Loop&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span style="color: rgb(0, 128, 0);"&gt;' No, this isn't redundant.&lt;/span&gt;&lt;br /&gt;                  &lt;span style="color: rgb(0, 0, 128);"&gt;Do Until&lt;/span&gt; objExec.StdOut.AtEndOfStream&lt;br /&gt;&lt;br /&gt;                          oxLogFile.WriteLine "" &amp;amp;&lt;wbr&gt; vbTab &amp;amp; "MESSAGE" &amp;amp; vbTab &amp;amp; objExec.Std&lt;wbr&gt;Out.ReadLine&lt;br /&gt;&lt;br /&gt;        &lt;span style="color: rgb(0, 0, 128);"&gt;Loop&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;                  &lt;span style="color: rgb(0, 0, 128);"&gt;Do Until&lt;/span&gt; objExec.StdErr.AtEndOfStream&lt;br /&gt;&lt;br /&gt;                          boolError = &lt;span style="color: rgb(0, 0, 128);"&gt;True&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;                          oxLogFile.WriteLine "" &amp;amp;&lt;wbr&gt; vbTab &amp;amp; "ERROR MESSAGE" &amp;amp; vbTab &amp;amp; objEx&lt;wbr&gt;ec.StdErr.ReadLine&lt;br /&gt;&lt;br /&gt;        &lt;span style="color: rgb(0, 0, 128);"&gt;Loop&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;   &lt;span style="color: rgb(0, 0, 128);"&gt;End If&lt;/span&gt; &lt;span style="color: rgb(0, 128, 0);"&gt;'iretry &amp;lt;&amp;gt; 0&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;   &lt;span style="color: rgb(0, 0, 128);"&gt;Set&lt;/span&gt; objExec = &lt;span style="color: rgb(0, 0, 128);"&gt;Nothing&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;         oxLogFile.WriteLine Now() &amp;amp; vbTa&lt;wbr&gt;b &amp;amp; "END FILE" &amp;amp; vbTab &amp;amp; Chr(34) &amp;amp; strFi&lt;wbr&gt;leTarget &amp;amp; Chr(34)&lt;br /&gt;&lt;br /&gt;   strFile = Dir&lt;br /&gt;   iFile = iFile + 1&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;Loop&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;oxLogFile.WriteLine Now() &amp;amp; vbTab &amp;amp; "END F&lt;wbr&gt;OLDER" &amp;amp; vbTab &amp;amp; objNetwork.ComputerName &lt;wbr&gt;&amp;amp; vbTab &amp;amp; objNetwork.UserName&lt;br /&gt;oxLogFile.Close&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 128, 0);"&gt;' If the error flag is TRUE, rename the l&lt;wbr&gt;ogfile as the error file.&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;If&lt;/span&gt; boolError &lt;span style="color: rgb(0, 0, 128);"&gt;Then&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;     objFSO.CopyFile strFolder_Target &amp;amp; L&lt;wbr&gt;OG_FILE, strFolder_Target &amp;amp; ERROR_FILE, &lt;wbr&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;True&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;End If&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;ExitSub:&lt;br /&gt;&lt;br /&gt;  Application.StatusBar = &lt;span style="color: rgb(0, 0, 128);"&gt;False&lt;/span&gt;&lt;br /&gt;  Application.Cursor = xlDefault&lt;br /&gt;  &lt;span style="color: rgb(0, 0, 128);"&gt;Set&lt;/span&gt; oxLogFile = &lt;span style="color: rgb(0, 0, 128);"&gt;Nothing&lt;/span&gt;&lt;br /&gt;  &lt;span style="color: rgb(0, 0, 128);"&gt;Set&lt;/span&gt; objExec = &lt;span style="color: rgb(0, 0, 128);"&gt;Nothing&lt;/span&gt;&lt;br /&gt;  &lt;span style="color: rgb(0, 0, 128);"&gt;Set&lt;/span&gt; objFSO = &lt;span style="color: rgb(0, 0, 128);"&gt;Nothing&lt;/span&gt;&lt;br /&gt;  &lt;span style="color: rgb(0, 0, 128);"&gt;Set&lt;/span&gt; objShell = &lt;span style="color: rgb(0, 0, 128);"&gt;Nothing&lt;/span&gt;&lt;br /&gt;  &lt;span style="color: rgb(0, 0, 128);"&gt;Set&lt;/span&gt; objNetwork = &lt;span style="color: rgb(0, 0, 128);"&gt;Nothing&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: rgb(0, 0, 128);"&gt;Exit Sub&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;ErrSub:&lt;br /&gt;&lt;br /&gt;     &lt;span style="color: rgb(0, 0, 128);"&gt;Resume&lt;/span&gt; ExitSub&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;End Sub&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;hr  style="font-size:78%;"&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;Private Sub&lt;/span&gt; cmdGetSourceFolder_Click()&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 128, 0);"&gt;' Open a file dialogue enabling the u&lt;wbr&gt;ser to create or select a folder.&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 128, 0);"&gt;' Populates the SourceFolder named ra&lt;wbr&gt;nge if successful&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 128, 0);"&gt;' Recommended icon for this button is th&lt;wbr&gt;e 'folder search' magnifying glass&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;Dim&lt;/span&gt; strFolder_Source &lt;span style="color: rgb(0, 0, 128);"&gt;As String&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;Dim&lt;/span&gt; objFD &lt;span style="color: rgb(0, 0, 128);"&gt;As&lt;/span&gt; FileDialog&lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;Dim&lt;/span&gt; vrtSelectedItem &lt;span style="color: rgb(0, 0, 128);"&gt;As Variant&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;Set&lt;/span&gt; objFD = Application.FileDialog(msoFileD&lt;wbr&gt;ialogFolderPicker)&lt;br /&gt;&lt;br /&gt;strFolder_Source = ThisWorkbook.Names("S&lt;wbr&gt;ourceFolder").RefersToRange.Value&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;With&lt;/span&gt; objFD&lt;br /&gt;&lt;br /&gt;     .AllowMultiSelect = &lt;span style="color: rgb(0, 0, 128);"&gt;False&lt;/span&gt;&lt;br /&gt;   .InitialFileName = strFolder_Sou&lt;wbr&gt;rce&lt;br /&gt;   .Title = "Specify the source folder.&lt;wbr&gt;.."&lt;br /&gt;   .InitialView = msoFileDialogViewDeta&lt;wbr&gt;ils&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;    If&lt;/span&gt; .Show = -1 &lt;span style="color: rgb(0, 0, 128);"&gt;Then&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;           &lt;span style="color: rgb(0, 0, 128);"&gt;If&lt;/span&gt; .SelectedItems.Count &amp;gt; 0 &lt;span style="color: rgb(0, 0, 128);"&gt;Then&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;                    strFolder_Source = ""&lt;br /&gt;          strFolder_Source = .Selected&lt;wbr&gt;Items(1)&lt;br /&gt;&lt;br /&gt;                    &lt;span style="color: rgb(0, 0, 128);"&gt;If&lt;/span&gt; strFolder_Source &amp;lt;&amp;gt; "" &lt;span style="color: rgb(0, 0, 128);"&gt;Then&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;              ThisWorkbook.Names("Sour&lt;wbr&gt;ceFolder").RefersToRange.Value = strFold&lt;wbr&gt;er_Source&lt;br /&gt;&lt;br /&gt;          &lt;span style="color: rgb(0, 0, 128);"&gt;End If&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;           &lt;span style="color: rgb(0, 0, 128);"&gt;End If&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: rgb(0, 0, 128);"&gt;End If&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;End With&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;End Sub&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;hr  style="font-size:78%;"&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;Private Sub&lt;/span&gt; cmdGetTargetFolder_Click()&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 128, 0);"&gt;' Open a file dialogue enabling the u&lt;wbr&gt;ser to create or select a folder.&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 128, 0);"&gt;' Populates the TargetFolder named ra&lt;wbr&gt;nge if successful&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 128, 0);"&gt;' Recommended icon for this button is th&lt;wbr&gt;e 'folder search' magnifying glass&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;Dim&lt;/span&gt; strFolder_Target &lt;span style="color: rgb(0, 0, 128);"&gt;As String&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;Dim&lt;/span&gt; objFD &lt;span style="color: rgb(0, 0, 128);"&gt;As&lt;/span&gt; FileDialog&lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;Dim&lt;/span&gt; vrtSelectedItem &lt;span style="color: rgb(0, 0, 128);"&gt;As Variant&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;Set&lt;/span&gt; objFD = Application.FileDialog(msoFileD&lt;wbr&gt;ialogFolderPicker)&lt;br /&gt;&lt;br /&gt;strFolder_Target = ThisWorkbook.Names("T&lt;wbr&gt;argetFolder").RefersToRange.Value&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;With&lt;/span&gt; objFD&lt;br /&gt;&lt;br /&gt;    .AllowMultiSelect = &lt;span style="color: rgb(0, 0, 128);"&gt;False&lt;/span&gt;&lt;br /&gt;  .InitialFileName = strFolder_Tar&lt;wbr&gt;get&lt;br /&gt;  .Title = "Specify the Target folder.&lt;wbr&gt;.."&lt;br /&gt;  .InitialView = msoFileDialogViewDeta&lt;wbr&gt;ils&lt;br /&gt;&lt;br /&gt;     &lt;span style="color: rgb(0, 0, 128);"&gt;If&lt;/span&gt; .Show = -1 &lt;span style="color: rgb(0, 0, 128);"&gt;Then&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;             &lt;span style="color: rgb(0, 0, 128);"&gt;If&lt;/span&gt; .SelectedItems.Count &amp;gt; 0 &lt;span style="color: rgb(0, 0, 128);"&gt;Then&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;                     strFolder_Target = ""&lt;br /&gt;           strFolder_Target = .Selected&lt;wbr&gt;Items(1)&lt;br /&gt;&lt;br /&gt;           &lt;span style="color: rgb(0, 0, 128);"&gt;If&lt;/span&gt; strFolder_Target &amp;lt;&amp;gt; "" &lt;span style="color: rgb(0, 0, 128);"&gt;Then&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;                             ThisWorkbook.Names("Targ&lt;wbr&gt;etFolder").RefersToRange.Value = strFold&lt;wbr&gt;er_Target&lt;br /&gt;&lt;br /&gt;           &lt;span style="color: rgb(0, 0, 128);"&gt;End If&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;             &lt;span style="color: rgb(0, 0, 128);"&gt;End If&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;     &lt;span style="color: rgb(0, 0, 128);"&gt;End If&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;End With&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;End Sub&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;hr  style="font-size:78%;"&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;Private Sub&lt;/span&gt; cmdOpenSource_Click()&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 128, 0);"&gt;' Reads the SourceFolder named range.&lt;wbr&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 128, 0);"&gt;' Opens a Windows Explorer window displa&lt;wbr&gt;ying the folder and its contents.&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 128, 0);"&gt;' Recommended icon for this button is th&lt;wbr&gt;e standard Windows 'Open Folder'&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;On Error Resume Next&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;Dim&lt;/span&gt; strCmd &lt;span style="color: rgb(0, 0, 128);"&gt;As String&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;Dim&lt;/span&gt; strFile &lt;span style="color: rgb(0, 0, 128);"&gt;As String&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;Dim&lt;/span&gt; strFolder_Source &lt;span style="color: rgb(0, 0, 128);"&gt;As String&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  strFolder_Source = ThisWorkbook.Names("S&lt;wbr&gt;ourceFolder").RefersToRange.Value&lt;br /&gt;&lt;br /&gt;  strCmd = "Explorer " &amp;amp; Chr(34) &amp;amp; strFold&lt;wbr&gt;er_Source &amp;amp; Chr(34)&lt;br /&gt;&lt;br /&gt;  Shell strCmd, vbNormalFocus&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;End Sub&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;hr  style="font-size:78%;"&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;Private Sub&lt;/span&gt; cmdOpenTarget_Click()&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 128, 0);"&gt;' Reads the TargetFolder named range.&lt;wbr&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 128, 0);"&gt;' Opens a Windows Explorer window displa&lt;wbr&gt;ying the folder and its contents.&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 128, 0);"&gt;' Recommended icon for this button is th&lt;wbr&gt;e standard Windows 'Open Folder'&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;On Error Resume Next&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;Dim&lt;/span&gt; strCmd &lt;span style="color: rgb(0, 0, 128);"&gt;As String&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;Dim&lt;/span&gt; strFile &lt;span style="color: rgb(0, 0, 128);"&gt;As String&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;Dim&lt;/span&gt; strFolder_Target &lt;span style="color: rgb(0, 0, 128);"&gt;As String&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  strFolder_Target = ThisWorkbook.Names("T&lt;wbr&gt;argetFolder").RefersToRange.Value&lt;br /&gt;&lt;br /&gt;  strCmd = "Explorer " &amp;amp; Chr(34) &amp;amp; strFold&lt;wbr&gt;er_Target &amp;amp; Chr(34)&lt;br /&gt;&lt;br /&gt;  Shell strCmd, vbNormalFocus&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;End Sub&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;hr  style="font-size:78%;"&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;Private Sub&lt;/span&gt; RedoAllFolders()&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 128, 0);"&gt;' Redo EVERY folder&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 128, 0);"&gt;' Start with the parent folders specifie&lt;wbr&gt;d in source and target&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 128, 0);"&gt;' WARNING - this overwrites everything i&lt;wbr&gt;n the target folders.&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 128, 0);"&gt;' It is inadvisable to provide the us&lt;wbr&gt;ers with this function -&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 128, 0);"&gt;' leave it for administrators doing larg&lt;wbr&gt;e one-off batches&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;Dim&lt;/span&gt; strFile &lt;span style="color: rgb(0, 0, 128);"&gt;As String&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;Dim&lt;/span&gt; strFolder_Target &lt;span style="color: rgb(0, 0, 128);"&gt;As String&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;Dim&lt;/span&gt; strFolder_Source &lt;span style="color: rgb(0, 0, 128);"&gt;As String&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 128, 0);"&gt;' Help on the Windows Scripting host is a&lt;wbr&gt;vailable here:&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 128, 0);"&gt;' http://msdn2.microsoft.com/en-us/libra&lt;wbr&gt;ry/98591fh7.aspx&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 128, 0);"&gt;' Windows Script Host Object Model&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 128, 0);"&gt;' C:\WINDOWS\system32\wshom.ocx&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;Dim&lt;/span&gt; objFSO &lt;span style="color: rgb(0, 0, 128);"&gt;As&lt;/span&gt; IWshRuntimeLibrary.FileSystemObject&lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;Dim&lt;/span&gt; objSourceFolder &lt;span style="color: rgb(0, 0, 128);"&gt;As&lt;/span&gt; IWshRuntimeLibrary.Folder&lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;Dim&lt;/span&gt; objSourceParentFolder &lt;span style="color: rgb(0, 0, 128);"&gt;As&lt;/span&gt; IWshRuntimeLibrary.Folder&lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;Dim&lt;/span&gt; objTargetFolder &lt;span style="color: rgb(0, 0, 128);"&gt;As&lt;/span&gt; IWshRuntimeLibrary.Folder&lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;Dim&lt;/span&gt; objTargetParentFolder &lt;span style="color: rgb(0, 0, 128);"&gt;As&lt;/span&gt; IWshRuntimeLibrary.Folder&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;Set&lt;/span&gt; objFSO = &lt;span style="color: rgb(0, 0, 128);"&gt;New&lt;/span&gt; IWshRuntimeLibrary.FileSystemObject&lt;br /&gt;&lt;br /&gt;strFolder_Target = ThisWorkbook.Names("T&lt;wbr&gt;argetFolder").RefersToRange.Value&lt;br /&gt;strFolder_Target = Trim(strFolder_Target)&lt;wbr&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;If&lt;/span&gt; Right(strFolder_Target, 1) &amp;lt;&amp;gt; "\" &lt;span style="color: rgb(0, 0, 128);"&gt;Then&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;     strFolder_Target = strFolder_Target &lt;wbr&gt;&amp;amp; "\"&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;End If&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 128, 0);"&gt;'If the folder does not exist, create it:&lt;wbr&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;If Not&lt;/span&gt; objFSO.FolderExists(strFolder_Targe&lt;wbr&gt;t) &lt;span style="color: rgb(0, 0, 128);"&gt;Then&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;     MkDir strFolder_Target&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;End If&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;If Not&lt;/span&gt; objFSO.FolderExists(strFolder_Targe&lt;wbr&gt;t) &lt;span style="color: rgb(0, 0, 128);"&gt;Then&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  MsgBox "Target folder does not e&lt;wbr&gt;xist and cannot be created: " &amp;amp; vbCrLf &amp;amp;&lt;wbr&gt; vbCrLf &amp;amp; strFolder_Target, vbCritical, &lt;wbr&gt;"No target folder..."&lt;br /&gt;  &lt;span style="color: rgb(0, 0, 128);"&gt;GoTo&lt;/span&gt; ExitSub&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;End If&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;Set&lt;/span&gt; objTargetParentFolder = objFSO.GetFolde&lt;wbr&gt;r(strFolder_Target)&lt;br /&gt;&lt;br /&gt;strFolder_Source = ThisWorkbook.Names("S&lt;wbr&gt;ourceFolder").RefersToRange.Value&lt;br /&gt;strFolder_Source = Trim(strFolder_Source)&lt;wbr&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;If&lt;/span&gt; Right(strFolder_Source, 1) &amp;lt;&amp;gt; "\" &lt;span style="color: rgb(0, 0, 128);"&gt;Then&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  strFolder_Source = strFolder_Source &lt;wbr&gt;&amp;amp; "\"&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;End If&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;If Not&lt;/span&gt; objFSO.FolderExists(strFolder_Sourc&lt;wbr&gt;e) &lt;span style="color: rgb(0, 0, 128);"&gt;Then&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  MsgBox "The source folder does not e&lt;wbr&gt;xist: " &amp;amp; vbCrLf &amp;amp; vbCrLf &amp;amp; strFolder_Ta&lt;wbr&gt;rget, vbCritical, "No target folder..."&lt;br /&gt;  &lt;span style="color: rgb(0, 0, 128);"&gt;GoTo&lt;/span&gt; ExitSub&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;End If&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Application.Cursor = xlWait&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;Set&lt;/span&gt; objSourceParentFolder = objFSO.GetFolde&lt;wbr&gt;r(strFolder_Source)&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;For Each&lt;/span&gt; objSourceFolder &lt;span style="color: rgb(0, 0, 128);"&gt;In&lt;/span&gt; objSourceParentFolder.SubFolders&lt;br /&gt;&lt;br /&gt;     ThisWorkbook.Names("SourceFolder").R&lt;wbr&gt;efersToRange.Value = objSourceFolder.Pat&lt;wbr&gt;h&lt;br /&gt;&lt;br /&gt;     strFolder_Target = objFSO.BuildP&lt;wbr&gt;ath(objTargetParentFolder.Path, objSourc&lt;wbr&gt;eFolder.Name)&lt;br /&gt;&lt;br /&gt;     ThisWorkbook.Names("TargetFolder").R&lt;wbr&gt;efersToRange.Value = strFolder_Target&lt;br /&gt;&lt;br /&gt;     cmdGo_Click&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;Next&lt;/span&gt; objSourceFolder&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;ExitSub:&lt;br /&gt;&lt;br /&gt;    Application.Cursor = xlDefault&lt;br /&gt;  &lt;span style="color: rgb(0, 0, 128);"&gt;Set&lt;/span&gt; objSourceParentFolder = &lt;span style="color: rgb(0, 0, 128);"&gt;Nothing&lt;/span&gt;&lt;br /&gt;  &lt;span style="color: rgb(0, 0, 128);"&gt;Set&lt;/span&gt; objSourceFolder = &lt;span style="color: rgb(0, 0, 128);"&gt;Nothing&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: rgb(0, 0, 128);"&gt;Set&lt;/span&gt; objFSO = &lt;span style="color: rgb(0, 0, 128);"&gt;Nothing&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span style="color: rgb(0, 0, 128);"&gt;Exit Sub&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;ErrSub:&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: rgb(0, 0, 128);"&gt;Resume&lt;/span&gt; ExitSub&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;End Sub&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/nobr&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;A few observations...&lt;/h3&gt;&lt;br /&gt;&lt;p align="justify"&gt;Are there better ways of doing this? Yes, definitely. There are scripting mavens out there who could can tap out a three-line shell script that'll do the lot in seconds... But I used the tools I had to hand; you're probably not the wizard you thought you were, and will find out after an hour of fruitless debugging; and unfamiliar command-line executables with finnicky switches need to be wrapped in a way that allows you to see, clearly and plainly, exactly what it is that you're doing. Note, also, that the error-logger writes out the command line, verbatim - a habit I would urge all novice developers to adopt today, because knowing what your application &lt;i&gt;did&lt;/i&gt; is the key to effective testing.&lt;/p&gt;&lt;p align="justify"&gt;I've used a separate logfile in this application but, this being Excel, I might've done better to write it all out onto a worksheet. I mean, it's already open and running, why not use it? Hindsight's a wonderful thing.&lt;br /&gt;&lt;/p&gt;Meanwhile, feel free to offer examples of other tasks that &lt;i&gt;you&lt;/i&gt; wrapped up in Excel.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1800518423097919889-7080584788601231814?l=excellerando.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://excellerando.blogspot.com/feeds/7080584788601231814/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://excellerando.blogspot.com/2009/01/using-microsoft-excel-to-feed-batches.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1800518423097919889/posts/default/7080584788601231814'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1800518423097919889/posts/default/7080584788601231814'/><link rel='alternate' type='text/html' href='http://excellerando.blogspot.com/2009/01/using-microsoft-excel-to-feed-batches.html' title='Using Microsoft Excel to feed batches of files to a command-line utility'/><author><name>Nigel Heffernan</name><uri>http://www.blogger.com/profile/08954578765691578714</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://1.bp.blogspot.com/_B9BAdln8o_A/SYY_TkYyu4I/AAAAAAAAAAs/z5CQ01NUtTI/S220/Cropped+Blog+Shot.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1800518423097919889.post-3903114455278113472</id><published>2009-01-30T22:50:00.005Z</published><updated>2010-03-02T16:57:18.581Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='Introduction'/><title type='text'>Introduction to Excellerando</title><content type='html'>&lt;div style="text-align: justify;"&gt;&lt;br /&gt;Welcome to Excellerando, a blog devoted to arcane VBA-Geekery, mostly in Microsoft Excel. &lt;br /&gt;&lt;BR /&gt;I don't claim to be a definitive source on the subject (that would be the book &lt;A Href="http://www.amazon.com/Professional-Excel-Development-Applications-Addison-Wesley/dp/0321262506" Title="Link to the definitive book on developing applications in Excel"&gt;Professional Excel Development&lt;/A&gt; by &lt;A Href="http://www.oaltd.co.uk/Default.htm"&gt;Stephen Bullen&lt;/A&gt;, &lt;A Href="http://www.appspro.com/About/AboutAppsPro.htm"&gt;Rob Bovey&lt;/A&gt; and &lt;A Href="http://www.oaltd.co.uk/MVP/MVPPage.asp#JohnGreen"&gt;John Green&lt;/A&gt;). Instead, you'll get odd code scraps, fixes to uncommon problems, and usable code that saves reinventing the wheel. &lt;br /&gt;&lt;BR /&gt;Much of it will have a financial and banking perspective, because that's what I've spent the last ten years doing for a living: bashing out spreadsheets and add-ins for traders, analysts, risk managers and anyone else who asks in banks and hedge funds.&lt;br /&gt;&lt;BR /&gt;Comments are welcome; questions will be answered - eventually - but your first port of call for any Excel question should be &lt;A Href="http://groups.google.com/group/microsoft.public.excel.programming/topics?lnk"&gt;the Usenet boards&lt;/A&gt; or &lt;A Href="http://www.google.com/custom?hl=en&amp;client=google-coop&amp;cof=AH%3Aleft%3BCX%3ADDoE%2520Site%2520Search%3BL%3Ahttp%3A%2F%2Fwww.google.com%2Fcoop%2Fintl%2Fen%2Fimages%2Fcustom_search_sm.gif%3BLH%3A65%3BLP%3A1%3BVLC%3A%23551a8b%3BGFNT%3A%23666666%3BDIV%3A%23cccccc%3B&amp;adkw=AELymgWAM5WjZFJ6gkBcnefBZtgTgZTIbX8Zb2utpX-lSkmV8iyUMtDdJRFl7kYkMekD7hskvlCrhjNQKkVVFL12oOdycYhCIAjLVXtXkL8CIS-L1kBQLKhd0y9D0ynSZ4V-_obaKYiM&amp;q=Merged+Cells&amp;btnG=Search&amp;cx=010399408046709365196%3Apaywkt7xixs" Title"Google Site Search Example"&gt;a quick search&lt;/A&gt; through &lt;A Href ="http://www.dailydoseofexcel.com/"&gt;Daily Dose of Excel&lt;/A&gt;, a blog that you really should be reading every day if you're programming with Excel for a living.&lt;br /&gt;&lt;BR /&gt;Meanwhile, sit back, relax, and reflect upon the knowledge that the worst job you've ever been asked to do in Excel has surely been done already by someone else, and the source code's out there. Or, quite possibly, here.&lt;br /&gt;&lt;BR /&gt;&lt;BR /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1800518423097919889-3903114455278113472?l=excellerando.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://excellerando.blogspot.com/feeds/3903114455278113472/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://excellerando.blogspot.com/2009/01/introduction-to-excellerando.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1800518423097919889/posts/default/3903114455278113472'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1800518423097919889/posts/default/3903114455278113472'/><link rel='alternate' type='text/html' href='http://excellerando.blogspot.com/2009/01/introduction-to-excellerando.html' title='Introduction to Excellerando'/><author><name>Nigel Heffernan</name><uri>http://www.blogger.com/profile/08954578765691578714</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://1.bp.blogspot.com/_B9BAdln8o_A/SYY_TkYyu4I/AAAAAAAAAAs/z5CQ01NUtTI/S220/Cropped+Blog+Shot.JPG'/></author><thr:total>0</thr:total></entry></feed>
