Page 2 of 2

Posted: 2007 Sep 03, 11:27
by nikos
thanks for the code Jim. It looks like you are adding a few extra keys like PerceivedType etc which must be vista only -- i can't find HKCR\FileSystemAssociations in XP

my hunch is that the type of menu commands and duplicates depend on the selection. If say you have selected a *.h and a *.cpp file, then you'll get some "duplicates" called OpenWithMSDEV but each belongs to a different filetype, so it is technically correct albeit lame!

I don't get crashes but some funny first chance exceptions errors in kernel32.dll on account of "invalid handles" when the IContextMenu is released. It looks like the magic number is 17: If i pass 17 registry keys or less to CDefFolderMenu_Create2 then all is fine, from 18 and up (ie more and diverse file types) I start getting these exceptions which can cause a crash too

this is regardless of using my "fake"/subclassed folder or not so it looks like a problem with CDefFolderMenu_Create2 which i'll report to m$ and see what they'll come up with

Posted: 2008 Mar 08, 21:30
by TiKu
Is it really necessary to hook the desktop's IShellFolder and provide a custom data object? I just started to implement cross-namespace context menus, but so far I didn't came across the situation that the data object provided by the desktop doesn't contain correct CF_HDROP data. On the other hand I did not yet test on anything other than Windows XP SP2.

I plan to use SHCreateDefaultContextMenu on Vista, because according to the docs you can let this API search for the correct registry keys itself. Do you have any experience with it?

BTW, many thanks Jim and Nikos for sharing all these information.

Posted: 2008 Mar 09, 02:04
by TiKu
I took RegMon and checked which parts of the registry Explorer is accessing when I right-click a *.bas file and a *.txt file out of different folders in the search pane (XP SP2).

Case 1) The *.bas file is focused. The following keys were accessed (I picked the important ones):
  1. HKCR\.bas
  2. HKCR\VisualBasic.Module
  3. HKCR\VisualBasic.Module\CurVer
  4. HKCR\SystemFileAssociations\.bas  <- not existing
  5. HKCR\SystemFileAssociations\application  <- not existing
  6. HKCR\*
  7. HKCR\AllFileSystemObjects
  8. --- I think at this point CDefFolderMenu_Create2 is called ---
  9. HKCR\.txt
  10. HKCR\txtfile
  11. HKCR\txtfile\CurVer
  12. HKCR\txtfile\shell and subkeys
  13. HKCR\SystemFileAssociations\.txt
  14. HKCR\.txt\PerceivedType
  15. HKCR\SystemFileAssociations\text
  16. HKCR\SystemFileAssociations\text\shell and subkeys
Those keys, whose shellex\ContextMenuHandlers subkeys were accessed by CDefFolderMenu_Create2, are highlighted green.
My code, which is just Jims code translated to C++, accesses these keys:
  1. HKCR\.bas
  2. HKCR\VisualBasic.Module
  3. HKCR\VisualBasic.Module\CurVer
  4. HKCR\SystemFileAssociations\.bas  <- not existing
  5. HKCR\*
  6. HKCR\AllFileSystemObjects
  7. --- at this point CDefFolderMenu_Create2 is called ---
  8. HKCR\SystemFileAssociations\.bas  <- not existing
  9. HKCR\SystemFileAssociations\application  <- not existing
  10. NOTE: For the *.txt file no key seems to be accessed.
Case 2) The same test with the *.txt file being focused.
  1. HKCR\.txt
  2. HKCR\txtfile
  3. HKCR\txtfile\CurVer
  4. HKCR\SystemFileAssociations\.txt  <- not existing
  5. HKCR\.txt\PerceivedType  <- fallback to extension key
  6. HKCR\SystemFileAssociations\text
  7. HKCR\*
  8. HKCR\AllFileSystemObjects
  9. --- I think at this point CDefFolderMenu_Create2 is called ---
  10. NOTE: For the *.bas file no key seems to be accessed.
My/Jims code:
  1. HKCR\.txt
  2. HKCR\txtfile
  3. HKCR\txtfile\CurVer
  4. HKCR\SystemFileAssociations\.txt
  5. HKCR\*
  6. HKCR\AllFileSystemObjects
  7. --- at this point CDefFolderMenu_Create2 is called ---
  8. HKCR\.txt\PerceivedType
  9. HKCR\SystemFileAssociations\text
  10. NOTE: For the *.bas file no key seems to be accessed.
So I think Jims code should be slightly modified.
1) If the file extension belongs to a file class (e. g. txtfile), the extension key (.txt) should NOT be passed to CDefFolderMenu_Create2.
2) The PerceivedType thing should be done before calling CDefFolderMenu_Create2 and the key should be passed. "application" might be a fallback perceived type. (I wonder why CDefFolderMenu_Create2 doesn't seem to try reading HKCR\.bas\PerceivedType)

I implemented both modifications and now I get exactly the same context menus like in search pane. Well, almost - the "rename" verb is missing for some reason.
Now let's hope the code also works for other combinations than *.bas/*.txt. ;)

Posted: 2008 Mar 09, 07:01
by nikos
the problem is that bug when you supply 16+ registry keys, so you should be striving to make the keys you need less, not more!

regarding the CF_HDROP, i also sometimes saw it filled by the desktop's folder but try combining something from c:\ and something from d:\ !

Posted: 2008 Mar 09, 10:35
by TiKu
nikos wrote:the problem is that bug when you supply 16+ registry keys, so you should be striving to make the keys you need less, not more!
Actually this limit can't even be reached. As Jim said, only the filetype of the focused item is relevant, not all filetypes. E. g. if you have selected the following files:
  • Readme.txt
  • stdafx.h
  • Logfile.log
  • Prices.pdf
and Readme.txt is the one you right-click, then you must pass the following keys to CDefFolderMenu_Create2 (you can verify this with RegMon and Windows Explorer):
  1. HKCR\txtfile
  2. HKCR\SystemFileAssociations\text
  3. HKCR\*
  4. HKCR\AllFileSystemObjects
That's far away from the limit of 16. Actually 6 is the maximum you'll reach.
nikos wrote:regarding the CF_HDROP, i also sometimes saw it filled by the desktop's folder but try combining something from c:\ and something from d:\ !
Works for me, but I'll check on Windows 2000. I'll have to hook IShellFolder anyway, because GetAttributesOf doesn't handle full pIDLs well (that's the reason why I don't get the "rename" menu item).

Posted: 2008 Mar 09, 20:18
by JimKueneman
Thanks for digging into this more TiKu.  I will update my components.

Also you must add CMF_CANRENAME to the flags for QueryContextMenu to get the Rename.  You then need to see if the Verb is 'rename' and you are responsible for the rename, don't call InvokeCommand with this verb.

Jim

Posted: 2008 Mar 10, 00:24
by TiKu
I'm currently testing on Vista. So far SHCreateDefaultContextMenu seems to work as expected. I set the punkAssociationInfo, cKeys and aKeys members of DEFCONTEXTMENU to 0 and it looks like the API really does the ugly registry stuff itself.

BTW, currently I'm not hooking the desktop's IShellFolder. The problem with the rename verb turned out to have another reason.
In Debug mode of my app I'll verify that the IDataObject provided by the desktop contains correct CF_HDROP data and throw an assertion if it does not. If I ever come across the situation that the CF_HDROP data is not right, I'll activate the hooking, but so far it seems to be unnecessary.

Posted: 2008 Mar 10, 00:30
by JimKueneman
In Debug mode of my app I'll verify that the IDataObject provided by the desktop contains correct CF_HDROP data and throw an assertion if it does not. If I ever come across the situation that the CF_HDROP data is not right, I'll activate the hooking, but so far it seems to be unnecessary.
Make sure you try what nikos mentioned.  Get a file from two different volumes and make sure that works as well.  That is one place is use to fail (I have not revisited this since Vista I was working on XP, Win2k and Win98).

Jim

Posted: 2008 Mar 10, 01:14
by TiKu
Strange... This afternoon I did test it with 2 files from different drives and it worked. Now, on another machine but also with XP SP2, it fails and the hook is required.

Jim, earlier in this thread you mentioned you had to override GetAttributesOf() because of SFGAO_CANMOVE and SFGAO_CANCOPY. Have you still implemented it this way or turned it out to be unnecessary meanwhile?

Posted: 2008 Mar 10, 02:18
by JimKueneman
That was a long time ago in "Jim Time"... :lol:

Ok, I looked at my code and yes I am still validating Copy and Cut manually in my proxy IShellFolder.  Not sure if it is still necessary.

Wow, there is a lot of code that I don't remember doing in that file....

Jim

Posted: 2008 Mar 10, 14:39
by TiKu
:lol:

To make the TortoiseSVN context menu extension and SHMultiFileProperties happy, you also must add CFSTR_SHELLIDLIST data to the IDataObject returned in GetUIObjectOf.

Looks like everything is working now. :D Only the Send To sub menu seems to cause my IDataObject implementation run into an infinite loop.

Posted: 2011 Mar 28, 21:55
by joshcomley
Hi there,

I know this is an old thread, but being able to do what you achieve (context menu on files from multiple folders).

Do you guys know of any C# adaptation of your solution?

I'm really struggling with the C++... it's been 10 years since I was there!

Many thanks,
Josh

Posted: 2011 Mar 29, 06:32
by nikos
sorry, my C# is worse than your C++

Re: blog: riddles in programming

Posted: 2021 Aug 23, 07:44
by DavidXanatos
nikos wrote: 2007 Jul 08, 08:46 here's the comment area for today's blog entry found at:
http://www.zabkat.com/blog/08Jul07.htm
Could you may be please provide an actually working example code?

as the comments says "... This is easier said than done but if you have an explorer type of application you most probably have such a class already. " and well I don't as I'm using a Qt based file system browser and want only to add the native windows menu, I'm quite far away and unexperienced with all that windows shell stuff.

Cheers
David X.

Re: blog: riddles in programming

Posted: 2021 Aug 23, 08:49
by nikos
have a look at SHCreateDataObject API. If you search for it in github i'm sure you'll find samples