Board index » cppbuilder » Shell popup menu
Antreas7
CBuilder Developer |
Antreas7
CBuilder Developer |
Shell popup menu2005-06-21 09:54:52 AM cppbuilder97 Is there a way to find out the items that windows explorer would use displaying the popup menu for a specific file or folder? |
Remy Lebeau (TeamB)
CBuilder Developer |
2005-06-21 10:55:25 AM
Re:Shell popup menu
"Antreas7" < XXXX@XXXXX.COM >wrote in message
QuoteIs there a way to find out the items that windows explorer the IContextMenu interface for that. You have to first retreive the IShellFolder interface for the folder/file's parent folder. You can use SHGetDesktopFolder(), IShellFolder::ParseDisplayName(), and IShellFolder::BindToObject() for that. Once you have the parent folder's IShellFolder interface, you can then call IShellFolder::GetUIObjectOf() to get the IContentMenu interface, and then finally call IContentMenu::QueryContextMenu(). Gambit |
qyte
CBuilder Developer |
2005-06-22 07:10:10 PM
Re:Shell popup menu
Remy Lebeau (TeamB) wrote:
QuoteThe only way to do that is to actually create a blank menu, pass it to REFIID riid parameter is required in two of the above functions. could you post a reply of some code? let's say for the folder "C:\\windows"? {smallsort} |
qyte
CBuilder Developer |
2005-06-22 08:41:27 PM
Re:Shell popup menu
To be more specific i built the following test project...
void __fastcall TForm1::Button1Click(TObject *Sender) { if(OpenDialog1->Execute()) Label1->Caption=OpenDialog1->FileName; else Label1->Caption=""; } void __fastcall TForm1::Button2Click(TObject *Sender) { PopupMenu->Items->Clear(); if(Label1->Caption.IsEmpty()) return; unsigned long eaten=Label1->Caption.WideCharBufSize(); wchar_t *buf=new wchar_t[eaten]; Label1->Caption.WideChar(buf,eaten); IShellFolder *shl; ITEMIDLIST *item; if(SHGetDesktopFolder(&shl)!=NOERROR) { ShowMessage("Desktop error"); return; } if(shl->ParseDisplayName(NULL,NULL,buf,&eaten,&item,NULL)!=NOERROR) { ShowMessage("Parse error"); return; } if(item==NULL) { ShowMessage("item failure"); return; } void *intface; if(shl->BindToObject(item,NULL,IID_IContextMenu,&intface)!=NOERROR) { ShowMessage("Bind error"); return; } shl=(IShellFolder*)intface; if(shl->GetUIObjectOf(NULL,1,(const ITEMIDLIST **)&item,IID_IContextMenu,0,&intface)!=NOERROR) { ShowMessage("GetUI error"); return; } IContextMenu *menu; menu=(IContextMenu*)intface; eaten=menu->QueryContextMenu(PopupMenu->Handle,0,1,50,0); Label1->Caption=eaten; PopupMenu->Popup(10,10); } there is always a bind error. Can you show me what i should do to see the popup menu??? what am i doing wrong? |
Remy Lebeau (TeamB)
CBuilder Developer |
2005-06-23 04:20:13 AM
Re:Shell popup menu
"qyte" < XXXX@XXXXX.COM >wrote in message
QuoteI cannot seem to find what it is i have to pass where the REFIID Quotecould you post a reply of some code? if( pidl == NULL ) return NULL; int cb = pidl->mkid.cb; if( cb == 0 ) return NULL; pidl = (LPITEMIDLIST) (((LPBYTE) pidl) + cb); return (pidl->mkid.cb == 0) ? NULL : (LPITEMIDLIST) pidl; } UINT GetSize(LPCITEMIDLIST pidl) { UINT cbTotal = 0; if( pidl != NULL ) { cbTotal += sizeof(pidl->mkid.cb); while( pidl != NULL ) { cbTotal += pidl->mkid.cb; pidl = GetNextItemID(pidl); } } return cbTotal; } LPITEMIDLIST MakeCopy(LPCITEMIDLIST pidl) { LPITEMIDLIST pidlTemp = (LPITEMIDLIST) pidl; UINT cb = GetSize(pidl); LPITEMIDLIST pidlRet = (LPITEMIDLIST) CoTaskMemAlloc(cb); if( pidlRet != NULL ) CopyMemory(pidlRet, pidl, cb); return pidlRet; } LPITEMIDLIST GetChildID(LPITEMIDLIST pidl) { LPITEMIDLIST pidlRet = NULL; if( pidl != NULL ) { if( pidl->mkid.cb ) { LPITEMIDLIST pidlNext = pidl; while( pidlNext ) { pidl = pidlNext; pidlNext = GetNextItemID(pidl); } pidlRet = MakeCopy(pidl); if( pidlRet == NULL ) return NULL; pidl->mkid.cb = 0; } return pidlRet; } { IShellFolder *Desktop = NULL; if( SUCCEEDED(SHGetDesktopFolder(&Desktop)) ) { LPITEMIDLIST pidl = NULL; ULONG ulEaten = 0; WideString Path = Label1->Caption; if( SUCCEEDED(Desktop->ParseDisplayName(NULL, NULL, Path, &ulEaten, &pidl, NULL)) ) { LPITEMIDLIST pidlChild = GetChildID(pidl); if( pidlChild != NULL ) { IShellFolder *ParentFolder = NULL; if( SUCCEEDED(Desktop->BindToObject(pidl, NULL, IID_IShellFolder, (LPVOID*)&ParentFolder)) ) { IContextMenu *menu = NULL; if( SUCCEEDED(ParentFolder->GetUIObjectOf(NULL, 1, (LPCITEMIDLIST*)&pidlChild, IID_IContextMenu, NULL, (LPVOID*)&menu)) ) { Label1->Caption = menu->QueryContextMenu(PopupMenu->Handle, 0, 1, 100, CMF_NORMAL); menu->Release(); PopupMenu->Popup(10, 10); } } ParentFolder->Release(); } } CoTaskFreeMem(pidl); } Desktop->Release(); } Gambit |
Remy Lebeau (TeamB)
CBuilder Developer |
2005-06-23 04:20:15 AM
Re:Shell popup menu
"qyte" < XXXX@XXXXX.COM >wrote in message
QuoteTo be more specific i built the following test project... ITEMIDLIST that ParseDisplayName() returns), you are also not using BindToObject() correctly. For one thing, you requested it to return IContextMenu and then are casting the returned pointer to IShellFolder instead. That is completely wrong. Also, you did not heed what I told you earlier: "You have to first retreive the IShellFolder interface for the folder/file's ***parent*** folder." That is a very important step that you are completely ignoring. Please see my other reply. Gambit |
qyte
CBuilder Developer |
2005-06-23 09:42:31 AM
Re:Shell popup menu
i have made the following project based on your reply.
LPITEMIDLIST GetNextItemID(LPCITEMIDLIST pidl) { if( pidl == NULL ) return NULL; int cb = pidl->mkid.cb; if( cb == 0 ) return NULL; pidl = (LPITEMIDLIST) (((LPBYTE) pidl) + cb); return (pidl->mkid.cb == 0) ? NULL : (LPITEMIDLIST) pidl; } UINT GetSize(LPCITEMIDLIST pidl) { UINT cbTotal = 0; if( pidl != NULL ) { cbTotal += sizeof(pidl->mkid.cb); while( pidl != NULL ) { cbTotal += pidl->mkid.cb; pidl = GetNextItemID(pidl); } } return cbTotal; } LPITEMIDLIST MakeCopy(LPCITEMIDLIST pidl) { LPITEMIDLIST pidlTemp = (LPITEMIDLIST) pidl; UINT cb = GetSize(pidl); LPITEMIDLIST pidlRet = (LPITEMIDLIST) CoTaskMemAlloc(cb); if( pidlRet != NULL ) CopyMemory(pidlRet, pidl, cb); return pidlRet; } LPITEMIDLIST GetChildID(LPITEMIDLIST pidl) { LPITEMIDLIST pidlRet = NULL; if( pidl != NULL ) { if( pidl->mkid.cb ) { LPITEMIDLIST pidlNext = pidl; while( pidlNext ) { pidl = pidlNext; pidlNext = GetNextItemID(pidl); } pidlRet = MakeCopy(pidl); if( pidlRet == NULL ) return NULL; pidl->mkid.cb = 0; } } return pidlRet; } void __fastcall TForm1::Button1Click(TObject *Sender) { if(OpenDialog1->Execute()) Label1->Caption=OpenDialog1->FileName; else Label1->Caption=""; } void __fastcall TForm1::Button2Click(TObject *Sender) { if(Label1->Caption.IsEmpty()) return; IShellFolder *Desktop = NULL; if( SUCCEEDED(SHGetDesktopFolder(&Desktop)) ) { LPITEMIDLIST pidl = NULL; ULONG ulEaten = 0; WideString Path = Label1->Caption; if( SUCCEEDED(Desktop->ParseDisplayName(NULL, NULL, Path,&ulEaten, &pidl, NULL)) ) { LPITEMIDLIST pidlChild = GetChildID(pidl); if( pidlChild != NULL ) { IShellFolder *ParentFolder = NULL; if( SUCCEEDED(Desktop->BindToObject(pidl, NULL,IID_IShellFolder, (LPVOID*)&ParentFolder)) ) { IContextMenu *menu = NULL; if( SUCCEEDED(ParentFolder->GetUIObjectOf(NULL, 1,(LPCITEMIDLIST*)&pidlChild, IID_IContextMenu, NULL, (LPVOID*)&menu)) ) { Label1->Caption =menu->QueryContextMenu(PopupMenu->Handle, 0, 1, 100, CMF_NORMAL); menu->Release(); PopupMenu->Popup(10, 10); } } ParentFolder->Release(); } } CoTaskMemFree(pidl); } Desktop->Release(); } the problem is that the popupmenu doesn't get any item in it at all. there must be something wrong inside your code. the Label1 after i run button 2 takes the value 114. is it right??? |
Remy Lebeau (TeamB)
CBuilder Developer |
2005-06-23 10:39:35 AM
Re:Shell popup menu
"qyte" < XXXX@XXXXX.COM >wrote in message
Quotei have made the following project based on your reply. Quotethe problem is that the popupmenu doesn't get any item in it at all. Quotethe Label1 after i run button 2 takes the value 114. Your menu does not get displayed because you are using a TPopupMenu with no TMenuItem objects in it. If you use the Win32 API CreatePopupMenu() and TrackPopupMenu() functions, you will see that the code I gave does actually work. Gambit |
Antreas7
CBuilder Developer |
2005-06-24 05:24:14 AM
Re:Shell popup menu
Remy Lebeau (TeamB) wrote:
Quote"qyte" < XXXX@XXXXX.COM >wrote in message the popup menu. How can i add the events on these items? |
Remy Lebeau (TeamB)
CBuilder Developer |
2005-06-24 07:02:54 AM
Re:Shell popup menu
"Antreas7" < XXXX@XXXXX.COM >wrote in message
QuoteI used these function as you did and the popup menu worked fine. QuoteHow can i add the events on these items? the menu items. You can then intercept that message, pull out the ID of the menu that was clicked on, and then call the IContextMenu's InvokeCommand() method to perform the action for the clicked menu item. Gambit |
qyte
CBuilder Developer |
2005-06-24 06:31:30 PM
Re:Shell popup menu
Remy Lebeau (TeamB) wrote:
Quote"Antreas7" < XXXX@XXXXX.COM >wrote in message void ConstructMenu(HMENU Popup, TMenuItem *item) { for(int i=0;i<GetMenuItemCount(Popup);i++) { TMenuItem *additem=new TMenuItem(Form1); char buf[200]; GetMenuString(Popup,i,buf,200,MF_BYPOSITION); additem->Caption=buf; if(additem->Caption=="") additem->Caption="-"; additem->OnClick=Form1->ExClick; /*MENUITEMINFO inf; inf.cbSize=sizeof(MENUITEMINFO); inf.fMask=MIIM_TYPE; if(GetMenuItemInfo(Popup,i,true,&inf) && (inf.fType & MFT_BITMAP)) additem->Bitmap->Handle=(void*)LOWORD(inf.dwTypeData);*/ item->Add(additem); HMENU Sub=GetSubMenu(Popup,i); if(Sub) ConstructMenu(Sub,additem); } } As you can see i add the found items to my own popup menu. I have faced two problems. first i cannot find out how to retrieve the icon displayed left of a popupmenu item. look at the code inside the /**/ and tell me what is wrong with that? everything else works fine. apart from that the other problem is located somewhere inside your code. For some reason although the popupmenu gets the right items the subitems are not found. for example in the Open with item the is only one subitem "Open with" again. that happens in the send to as well. Another problem is that sometimes the invoke command does not function. like when i click on copy or cut. but it works great on open, delete, properties etc. Apart from that can you tell me if the code will need a lot variations in case i have multiselected items? what will i have to put as path in such a case? |