My application based on a VS 2010 isolated shell hangs when I implement the VS Find and Replace dialog (aka IVsFindTarget) within our custom editor pane (It’s an usual document window related a node of the hierarchy tree).
The bug occurs when more than one document is opened, we choose the "Look in: All Open documents" option and we perform a Replace All on a specific string (for example Find "1" and Replace All "11").
VS keeps looping infinitely between the Find and Replace for both opened documents so my "1" becomes "11" and when it returns to the initial documents the "11" becomes "1111" and so on and so on.
In our EditorPane, we implemented 3 members ofIVsFindTarget interface that notifies us that a search was requested by the VS Find&Replace dialog. This EditorPane is not text based (It’s a graphical editor) so it does only implement following interface:IVsPersistDocData, IPersistFileFormat, IVsToolboxUser, IVsToolboxActiveUserHook, IOleCommandTarget, IVsFindTarget, IVsWindowFrameNotify3.
Here is the implementation so far (please note the exception handling has been removed for better readability):
intIVsFindTarget.Find(string pszSearch,
uint grfOptions,
int fResetStartPoint,
IVsFindHelper pHelper,
outuint pResult )
{
pResult = (int)__VSFINDRESULT.VSFR_NotFound;
try
{
var farView = _editorViewasIWbFindAndReplace;
if (farView != null)
{
if (_findContext ==null)
_findContext = newWbFindAndReplaceContext(pHelper, pszSearch, grfOptions);
else
{
_findContext.VsHelper = pHelper;
_findContext.PatternSearch = pszSearch;
_findContext.SearchOptions = grfOptions;
}
var findResult = farView.FindAndReplace(_findContext, fResetStartPoint >= 1);
switch (findResult)
{
caseWbFindResult.Cancel:
pResult = (int)(__VSFINDRESULT.VSFR_NotFound |__VSFINDRESULT.VSFR_AndInterrupt);
break;
caseWbFindResult.Error:
pResult = (int)__VSFINDRESULT.VSFR_Error;
break;
caseWbFindResult.Found:
pResult = (int)__VSFINDRESULT.VSFR_Found;
break;
caseWbFindResult.EndOfDocument:
pResult = (int)__VSFINDRESULT.VSFR_EndOfDoc;
break;
caseWbFindResult.NotFound:
pResult = (int)__VSFINDRESULT.VSFR_EndOfSearch;
break;
default:
break;
}
}
returnVSConstants.S_OK;
}
intIVsFindTarget.Replace(string pszSearch,
string pszReplace,
uint grfOptions,
int fResetStartPoint,
IVsFindHelper pHelper,
outint pfReplaced)
{
pfReplaced = 0;
var farView = _editorViewasIWbFindAndReplace;
if (farView != null)
{
if (_replaceContext ==null)
_replaceContext = newWbFindAndReplaceContext(pHelper, pszSearch, pszReplace, grfOptions);
else
{
_replaceContext.VsHelper = pHelper;
_replaceContext.PatternSearch = pszSearch;
_replaceContext.SearchOptions = grfOptions;
_replaceContext.ReplacePattern = pszReplace;
}
var findResult = farView.FindAndReplace(_replaceContext, fResetStartPoint >= 1);
switch (findResult)
{
caseWbFindResult.Found:
pfReplaced = 1;
break;
caseWbFindResult.Error: // Passtghoug
caseWbFindResult.Cancel: // Passtghoug
caseWbFindResult.NotFound: // Passtghoug
caseWbFindResult.EndOfDocument: // Passtghoug
default:
break;
}
}
returnVSConstants.S_OK;
}
intIVsFindTarget.GetCapabilities(bool[] pfImage,uint[] pgrfOptions)
{
// We do NOT support IVsTextImage
if (pfImage != null&& pfImage.Length> 0)
pfImage[0] = false;
if (pgrfOptions != null&& pgrfOptions.Length> 0)
{
pgrfOptions[0] = (uint)__VSFINDOPTIONS.FR_None;
var farView = _editorViewasIWbFindAndReplace;
if (farView !=null&& farView.IsSupported())
{
// Scope supported
pgrfOptions[0] |= (uint)__VSFINDOPTIONS.FR_Document;
// Options supported
pgrfOptions[0] |= (uint)__VSFINDOPTIONS.FR_MatchCase;
pgrfOptions[0] |= (uint)__VSFINDOPTIONS.FR_WholeWord;
pgrfOptions[0] |= (uint)__VSFINDOPTIONS.FR_Plain;
pgrfOptions[0] |= (uint)__VSFINDOPTIONS.FR_Wildcard;
pgrfOptions[0] |= (uint)__VSFINDOPTIONS.FR_RegExpr;
// Action supported
pgrfOptions[0] |= (uint)__VSFINDOPTIONS.FR_Find;
pgrfOptions[0] |= (uint)__VSFINDOPTIONS.FR_FindAll;
pgrfOptions[0] |= (uint)__VSFINDOPTIONS.FR_Replace;
pgrfOptions[0] |= (uint)__VSFINDOPTIONS.FR_ReplaceAll;
}
}
returnVSConstants.S_OK;
}
intIVsFindTarget.GetProperty(uint propid,outobject pvar)
{
pvar = null;
var ret = VSConstants.S_OK;
switch ((__VSFTPROPID)propid)
{
case__VSFTPROPID.VSFTPROPID_IsFindInFilesForegroundOnly:
pvar = true;
break;
case__VSFTPROPID.VSFTPROPID_IsDiskFile:
pvar = false; // No file
break;
case__VSFTPROPID.VSFTPROPID_WindowFrame:
// Return the Window frame
pvar = GetService(typeof(SVsWindowFrame));
break;
case__VSFTPROPID.VSFTPROPID_InitialPattern:
case__VSFTPROPID.VSFTPROPID_InitialPatternAggressive:
// Return the selected text
var farView = _editorViewasIWbFindAndReplace;
if (farView != null)
pvar = farView.GetInitialPattern();
break;
case__VSFTPROPID.VSFTPROPID_BlockName:
case__VSFTPROPID.VSFTPROPID_DocName:
pvar = _documentMoniker;
break;
default:
ret = VSConstants.E_NOTIMPL;
break;
}
return ret;
}
My object "WbFindAndReplaceContext.FindText" will eventually invoke the following using the IVsFindHelper object:
VsHelper.FindInText( PatternSearch,
null,
SearchOptions,
(int)(__VSFINDBUFFERFLAGS.VSFB_StartOfLine | __VSFINDBUFFERFLAGS.VSFB_EndOfLine),
(uint)bufferArray.Length,
bufferArray,
out indexPatternFound,
out lengthPatternfound,
out computedTextForReplace,
out found );
It seems that the bug occurs because VS is not capable of tagging the documents which have already been searched and thus loops infinitely.
Is it our responsibility to tell VS to stop the search after all documents have been parsed or is there a flag we're not listening to in order to tell it to stop ?