How can I control which parts of the shell namespace the INamespaceWalk::Walk operation will walk into?


The INamespace­Walk::Walk method initiates a depth-first traversal of the shell namespace, subject to constraints controlled by the various parameters (such as maximum search depth). If you pass an object which implements the INamespace­Walk­CB interface, you can monitor the progress of the namespace walk and also influence how it proceeds.

The Enter­Folder method is called when the namespace walk finds an object in the shell namespace with the SFGAO_FOLDER attribute. You can perform whatever actions you wish in response to this callout, and you can provide limited feedback to the namespace walk operation:

  • Return S_OK to allow the namespace walk to recurse into the folder. The folder is eligible to be reported by INamespace­Walk::Get­ID­Array­Result.
  • Return S_FALSE to prevent the namespace walk from recursing into the folder. The folder is eligible to be reported by INamespace­Walk::Get­ID­Array­Result.
  • Return a COM error HRESULT to abandon the namespace walk operation. The error code you return will be the return value of the INamespace­Walk::Walk method.

The Found­Item method is called when the namespace walk finds an object in the shell namespace without the SFGAO_FOLDER attribute. Again, you can perform whatever actions you wish in response to this callout, and you can provide limited feedback to the namespace walk operation:

  • Return S_OK to allow the namespace walk to continue. The item will be reported by INamespace­Walk::Get­ID­Array­Result.
  • Return a COM error HRESULT to abandon the namespace walk operation. The error code you return will be the return value of the INamespace­Walk::Walk method.

Note that "allow the namespace walk to recurse into the folder" and "eligible to be reported by INamespace­Walk::Get­ID­Array­Result" are both conditional upon how the namespace walk is configured. For example, if recursing into the folder would exceed the recursion depth, then recursion won't occur even if you say "Sure, go ahead" in your Enter­Folder handler.

The Leave­Folder method is called when the namespace walk has finished enumerating the contents of a folder. It is the counterpart to Enter­Folder. This is your chance to perform any cleanup or other actions. (For example, if you are counting the number of items in each folder, this tells you that the enumeration of a folder is complete, and you can save the totals to wherever you intend to save them.) The return value here does not affect the namespace walk.

Let's go with the table again:

Operation S_OK S_FALSE COM error
Enter­Folder
Allow recursion
Allow reporting
Continue
Block recursion
Allow reporting
Continue
Block recursion
Block reporting
Abandon
Found­Item
Allow reporting
Continue
Not allowed
Block reporting
Abandon
Leave­Folder Continue Not allowed Continue

The boxes marked "Not allowed" indicate that returning S_FALSE is not allowed for those methods.

Exercise 1: A customer had the following question. Maybe you can answer it.

We are using INamespace­Walk::Walk, and we're passing the NSWF_TRAVERSE_STREAM_JUNCTIONS flag so that it recurses into CAB folders, but it's also recursing into ZIP folders. How can we stop it from recursing into ZIP folders?

Exercise 2: Suppose you want to process at most the first 100 files. How would you stop the namespace walk operation after 100 files have been processed?

Comments (6)

  1. Antonio Rodríguez says:

    Exercise 1: in the EnterFunction method, detect wether the item is a ZIP folder, and in that case, return S_FALSE. Otherwise, return S_OK.

    Exercise 2: create a counter and initialize it to zero. In every call to FoundItem, increment the counter. If the counter goes over 100, return a COM error. Otherwise, return S_OK.

  2. Ray Koopa says:

    Sounds like the walk methods I implemented once in a .NET node hierarchy for a game engine. I feel like I’ve done something right for once after reading this!

    1. Martin Bonner says:

      Ideally FoundItem and LeaveFolder should also treat S_FALSE as “stop searching, successfully” (You can always implement that with a customer error code that means “gave up early for some reason”, but that’s really the sort of thing S_FALSE is for.)

      1. Antonio Rodríguez says:

        IIRC, COM error codes are based, for historical reasons, on old Win16 error codes, which themselves were based on DOS codes, which include some sort of “aborted by the user” code. But I’m too lazy to look up that O:-) . If it’s true, you can use it in the case you mention.

        1. Joshua says:

          I just set a global boolean that means ignore that error.

          1. Antonio Rodríguez says:

            Given that you are already using an object to control the recursion, and that the object must be created before calling the INamespace­Walk::Walk method (and thus, should be destroyed after returning), I think it’s better to put that flag in the control object. CS courses teach not to use global variables under any circumstances. I think you should use them only for global configuration and for singular objects (like the ones representing your application or your main window). Or, as Raymond says it, don’t use a global resource to solve a local problem.

Skip to main content