Detect file and folder selection

I would like to be able to detect when a Windows Explorer folder or file is selected without having to "poll" for changes.

This could take either of 2 forms that occur to me:

1) Run a shell extension similar to a context menu or property
sheet handler, but immediately on file or folder selection.

2) Recieve a notification similar to what you get with the undocumented API "SHChangeNotifyRegister".  As far as I know
this function doesn't detect selection.

Any other methods are fine if they do the job.

Please note that I don't want to resort to using "desktop.ini" files since I would like to detect selection anywhere in the file system.

I would also like to retrieve the selected path/file name.
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

bhamiltoAuthor Commented:
Edited text of question.
The approach necessary for doing this, entails the creation of a ‘Notification Object’, which is a hidden kernel object that Explorer will use to notify your program when certain events have taken place, of which one is the notification of a file selection.  Along with this notification object, are three functions the Win32 SDK uses to work with such an object.  They are:


The primary job of the first function is to create the notification object and place it in a non-signal state.  The prototype of this function is:

HANDLE   FindFirstChangeNotification(LPCTSTR lpPathName,  BOOL bWatchSubtree,  DWORD dwNotifyFilter);

The first parameter is a pointer to a buffer containing the name of the directory (i.e. the pathname) Explorer will use to keep a watch on.  The second parameter specifies whether the path should include the sub-tree below.  The third parameter is used for the (various) flags that will trigger the object to inform your program that a change has occurred.  (This change notification depends on what flags you used.)  There are six such flags:







The second function’s primary job is to reset the notification object back to a non-signal state.  The reason for this is because when Explorer informs of a change, the object is switched from a non-signal state (when it was created) to that of a signal state.  Your program (specifically a thread within your program) gets the nod that a change has taken place and its job is to promptly inform the system that it (your program) is ready for another event, which it does by turning off the signal state and replacing it with the non-signal state.  Before this second function gets executed, this thread is in a ‘wait’ state (because it has not received a signal).  When the signal comes in, Explorer has already done its changes and informs the object of its completion.  This is when the object is then switched to a signaled state.  The ‘wait’ state then comes to an end, and the program must then inform the system that it’s ready for another event.  This, the program does by using the second function, resetting the notification object back to a state of non-activity (meaning non-signal).  The prototype of the second function is:

BOOL   FindNextChangeNotification(HANDLE  hChangeHandle);

The value of its parameter is the HANDLE  the first function returned when the object was created.

The job of the third function is to release the notification object and to stop watching out for changes.  The prototype of the third function is:

BOOL   FindCloseChangeNotification(HANDLE  hChangeHandle);

The value of its parameter is the HANDLE  the first function returned when the object was created.

Here are some sample codes:

HANDLE  SHInstallNotifier(HWND hwndParent,  LPCTSTR pszDir,  CUSTOMINFO& ci)
      DWORD  dwID = 0;
      g_bContinue = TRUE;

      ZeroMemory(&ci,  sizeof(CUSTOMINFO));
      ci.hwnd  =  hwndParent;
      lstrcpy(ci.pszDir,  pszDir);

      // Create a worker thread
      HANDLE  hThread  =  CreateThread(NULL,  0,  Notify,  &ci,  0,  & dwID);

       return  hThread;

DWORD   Notify(LPVOID  lpv)
       CUSTOMINFO  ci;
       ci.hwnd  =  static_cast<LPCUSTOMINFO>(lpv)->hwnd;
        lstrcpy(ci.pszDir,  static_cast<LPCUSTOMINFO>(lpv)->pszDir);

        HANDLE  hNotify  =  FindFirstChangeNotification(ci.pszDir,  TRUE,
                               FILE_NOTIFY_CHANGE_FILE_NAME  |

        if(hNotify  ==  INVALID_HANDLE_VALUE)
               return  0;

               WaitForSingleObject(hNotify,  INFINITE);

          return  1;

CUSTOMINFO is a structure defined as:

        HWND   hwnd;
        TCHAR   pszDir[MAX_PATH];


What I have done here, is to give you something of an approach regarding what it is you want to do, can be done.  Exactly the way you wish to implement your ideas must reflect your design and strategy.

If you have any further questions, don’t hesitate.
You might also want to take a look at the SHGetFileInfo API.  It uses a SHFILEINFO structure defined as:

typedef struct _SHFILEINFO{
    HICON hIcon;
    int   iIcon;
    DWORD dwAttributes;
    TCHAR szDisplayName[MAX_PATH];
    TCHAR szTypeName[80];

The SHGetFileInfo API has the following prototype:

DWORD_PTR  SHGetFileInfo(LPCTSTR pszPath, DWORD dwFileAttributes,
SHFILEINFO *psfi, UINT cbFileInfo, UINT uFlags);

The flag you might want to use in the last parameter of the function is, SHGFI_DISPLAYNAME.

Using that flag, this function retrieves the display name for the file.  The name is copied to the 'szDisplayName' member of the structure specified in 'psfi'.

This is yet another way you can go if you think my earlier suggestion might be too complicated (etc.).

If you have any question, don't hesitate!
Cloud Class® Course: C++ 11 Fundamentals

This course will introduce you to C++ 11 and teach you about syntax fundamentals.

bhamiltoAuthor Commented:
To try - Re: FindFirstChangeNotification etc.

Essentially this is the same as the undocumented API SHChangeNotifyRegister which I mentioned above.  It allows for notification of all shell changes detected by SHGetFileInfo.  As far as I am aware it can only detect changes to files or folders (like the examples you gave above).  I don't think it is capable of notifying for a simple selection.  Am I missing something?

I thought about this a bit since I posted the question, and can probably use the "IconHandler" shell extension to detect a file selection.  Unfortunately this shellex does not work for folders so I only have half the answer.

Thanks - Bob Hamilton
>> I don't think it is capable of notifying for a
>> simple selection.  Am I missing something?
No, you are not missing anything, that is correct.

I think you are going to have a very hard time making this work.  You may need to reconsider your design.  What in particular are you hopping to acheive?
You might want to take a look at SHBrowseForFolder and SetWinEventHook.

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
bhamiltoAuthor Commented:

SetWinEventHook looks interesting.  I have never heard of it, but I guess it's too new (or newly documented!!).

I've downloaded the accessability SDK and some tech articles from MS but it looks like a lot to wade through.  As we all know, a few good examples is worth a 1000 pages of MS documentation, but there appears to be very little in the way of specific examples.  Do you know of any beyond the pitiful collection in the MSDN?

bhamiltoAuthor Commented:

My initial use of this capability is to replace a "kluge" I'm currently using to get the selected Explorer path/file and use as a parameter in my app.  The app runs in the background and doesn't have a window showing so I can't use drag/drop. I don't want to use a context menu method because they take too long.   For this purpose I don't need instant notification, but the only ways I have come up with to get the path/file is to simulate a copy or a right click context menu operation, either of which takes too long, especially on slow machines.

I tried using the IconHandler shellex for files and this will do the job quite nicely.  

I still need an equivalent capability for detecting folder selections.  For my initial purpose I don't need instant notification of a folder selection, simply a cleaner and faster way of accessing the selected data.  However I have another app in mind where instant notification is key so I'd like o kill 2 birds with one stone if I can.

What I meant was what is the ultimate goal you wish to achieve.  Perhaps there is a way to reach it without having information about the selected file/folder.
bhamiltoAuthor Commented:

Oleacc.dll is a goldmine!

Not only does it do everything I want, but a whole lot more for the future.  

I remember seeing something about "Active Accessibility" in the MSDN newsletter but nothing suggested the power that this 150K beauty provides (given the over-all "Accessibility" slant I probably didn't even read the article).

Post an answer and you get the points.  I wouldn't normally give an "A" on "You might want to take a look at ..." but this one is worth it.

Many thanks - Bob Hamilton
The reason for posting my comment in the form of, "You might want to take a look at ...", is because if it engendered some interest on your side, then I would go into more detail with it, as oppose to going into detail with it first and finding out later that you're not interested.  Make sense?  I'm a quick learner!!
bhamilto, you should have the option to accept a comment as an anwer.  There should be a link to do so at the top of each comment.  You can just select the one for Try's "you might want to take a look at..." comment.
bhamiltoAuthor Commented:

I have no problem with your approach.  

It's just that a lot of people get so many comments like that (without elaboration) that they either ignore them or check them out so quickly that they may miss what they are looking for.  I almost did that with SetWinEventHook (paricularly since all references to it were in the context of "Active Accessibility") but something caught my eye.  A bit of elaboration can save a lot of time and seems like "better value for points".

Thanks again.

PS  nietod - I never noticed the "accept answer" before.  It used to be common for people to have to ask for an answer.  It is a useful feature because there is nothing I hate more than someone (a few "someones" typically) jumping in with an answer (usually wrong or irreelevent" and knocking your question onto the back burner.

Thanks all - Bob Hamilton
Your point is well taken, and as I said, "I'm  a quick learner"!
bhamiltoAuthor Commented:

You seem to have a good knowledge of some fairly "obscure" areas of the Win API.  

You haven't filled in a user profile so I don't know your areas of expertise.  You don't happen to be a COM expert by any chance?

Regards - Bob Hamilton
I know enough to hold my own and be dangerous.
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today

From novice to tech pro — start learning today.