For once a question from me

I'm writing a file search algorithm that searches every physical fixed drive and every network drive including all subdirectories for a filename. Although there is a shell function that brings up the file search box of Explorer, there seems to be no function to do this programmatically, neither in the shell nor in the file I/O functions.

The problem I have is: the function that searches the directory tree could either be recursive (shiver) or use some kind of loop and an array to simulate the recursion.
The tree-nature of directories requires two loops: one that walks into the depth of the tree and another that walks the directory siblings. The sibling-walker is the inner loop. The problem is that I can't use continue or break (or something like that) from within the inner loop to act on the outer loop. As I don't want to have cryptic continue flags the only way that seems left to me is using goto (*shiver again*).
Here's my code (MFC, but a lot of API access).
CList is a templated linked list. CStringList is equivalent to a specialization of CList for CString.
CFileFind is a class that encapsulates the API WIN32_FIND_DATA, FindFirstFile and FindNextFile.
Code:
bool CJBStarterApp::SearchTree(const CString & strInitDir,
	const CString & strFilename, CString & strOut)
{
	// Uses a freaky goto to avoid recursiveness.
	// Makes you wonder...
	CStringList lsStack;
	CList<CFileFind *, CFileFind *> lpffStack;
	CFileFind *pCurrentFF = NULL;
	CString strCurDir(strInitDir);
recur:
	pCurrentFF = new CFileFind();
	::SetCurrentDirectory(strCurDir);
	if(pCurrentFF->FindFile(strFilename))
	{
		pCurrentFF->FindNextFile();
		strOut = pCurrentFF->GetFilePath();
		// Unroll stack and return
		delete pCurrentFF;
		while(!lpffStack.IsEmpty())
			delete lpffStack.RemoveHead();
		return true;
	}
	pCurrentFF->FindFile();
	while(pCurrentFF->FindNextFile())
	{
		if(pCurrentFF->IsDirectory())
		{
			lpffStack.AddHead(pCurrentFF);
			lsStack.AddHead(strCurDir);
			strCurDir = pCurrentFF->GetFilePath();
			goto recur;
cont:
			delete pCurrentFF;
			pCurrentFF = lpffStack.RemoveHead();
			strCurDir = lsStack.RemoveHead();
			::SetCurrentDirectory(strCurDir);
		}
	}
	if(lpffStack.IsEmpty())
		return false;
	goto cont;
}
I believe it should work (haven't tried yet), but I'm not sure and that's a bad sign. If I'm not able to follow program flow right after I've written the app then this can't be good.

I welcome any ideas on restructuring this code to make it more readable. I welcome any reference to an API function that does this even more.

Thanks in advance.