// Classic Shell (c) 2009-2017, Ivo Beltchev // Open-Shell (c) 2017-2018, The Open-Shell Team // Confidential information of Ivo Beltchev. Not for disclosure or distribution without prior written consent from the author // ExplorerBand.cpp : Implementation of CExplorerBand #include "stdafx.h" #include "ExplorerBand.h" #include "resource.h" #include "ExplorerBHO.h" #include "ResourceHelper.h" #include "SettingsUI.h" #include "Settings.h" #include "SettingsParser.h" #include "Translations.h" #include "dllmain.h" #include "SettingsUIHelper.h" #include "FNVHash.h" #include #include #include /////////////////////////////////////////////////////////////////////////////// // CBandWindow - the parent window of the toolbar static struct { const wchar_t *name; int id; } g_StdCommands[]={ {L"up",CBandWindow::ID_GOUP}, {L"cut",CBandWindow::ID_CUT}, {L"copy",CBandWindow::ID_COPY}, {L"paste",CBandWindow::ID_PASTE}, {L"paste_shortcut",CBandWindow::ID_PASTE_SHORTCUT}, {L"delete",CBandWindow::ID_DELETE}, {L"properties",CBandWindow::ID_PROPERTIES}, {L"email",CBandWindow::ID_EMAIL}, {L"settings",CBandWindow::ID_SETTINGS}, {L"moveto",CBandWindow::ID_MOVETO}, {L"copyto",CBandWindow::ID_COPYTO}, {L"undo",CBandWindow::ID_UNDO}, {L"redo",CBandWindow::ID_REDO}, {L"selectall",CBandWindow::ID_SELECTALL}, {L"deselect",CBandWindow::ID_DESELECT}, {L"invertselection",CBandWindow::ID_INVERT}, {L"back",CBandWindow::ID_GOBACK}, {L"forward",CBandWindow::ID_GOFORWARD}, {L"refresh",CBandWindow::ID_REFRESH}, {L"stop",CBandWindow::ID_STOP}, {L"rename",CBandWindow::ID_RENAME}, {L"newfolder",CBandWindow::ID_NEWFOLDER}, {L"zipfolder",CBandWindow::ID_ZIPFOLDER}, {L"nav_pane",CBandWindow::ID_NAVPANE}, {L"details_pane",CBandWindow::ID_DETAILSPANE}, {L"preview_pane",CBandWindow::ID_PREVIEWPANE}, {L"mapdrive",CBandWindow::ID_MAP_DRIVE}, {L"disconnect",CBandWindow::ID_DISCONNECT}, {L"customizefolder",CBandWindow::ID_CUSTOMIZEFOLDER}, {L"folderoptions",CBandWindow::ID_FOLDEROPTIONS}, {L"viewtiles",CBandWindow::ID_VIEW_TILES}, {L"viewdetails",CBandWindow::ID_VIEW_DETAILS}, {L"viewlist",CBandWindow::ID_VIEW_LIST}, {L"viewcontent",CBandWindow::ID_VIEW_CONTENT}, {L"viewicons_small",CBandWindow::ID_VIEW_ICONS1}, {L"viewicons_medium",CBandWindow::ID_VIEW_ICONS2}, {L"viewicons_large",CBandWindow::ID_VIEW_ICONS3}, {L"viewicons_extralarge",CBandWindow::ID_VIEW_ICONS4}, {L"show_extensions",CBandWindow::ID_SHOW_EXTENSIONS}, {L"hidden_files",CBandWindow::ID_HIDDEN_FILES}, {L"system_files",CBandWindow::ID_SYSTEM_FILES}, }; static GUID SID_FrameManager={0x31e4fa78,0x02b4,0x419f,{0x94,0x30,0x7b,0x75,0x85,0x23,0x7c,0x77}}; static GUID SID_PerBrowserPropertyBag={0xa3b24a0a,0x7b68,0x448d,{0x99,0x79,0xc7,0x00,0x05,0x9c,0x3a,0xd1}}; const wchar_t *g_NavPaneVisible=L"PageSpaceControlSizer_Visible"; const wchar_t *g_DetailsPaneVisible=L"PreviewPaneSizer_Visible"; const wchar_t *g_DetailsPaneEnabled=L"PreviewPaneSizer_Loaded"; const wchar_t *g_PreviewPaneVisible=L"ReadingPaneSizer_Visible"; const wchar_t *g_PreviewPaneEnabled=L"ReadingPaneSizer_Loaded"; const wchar_t *g_ComboPaneEnabled=L"DetailsContainerSizer_Loaded"; typedef HRESULT (__stdcall *tBagWrite)( IPropertyBag *pThis, LPCOLESTR pszPropName, VARIANT *pVar ); static volatile tBagWrite g_OldBagWrite; void CBandWindow::ParseToolbarItem( const wchar_t *name, StdToolbarItem &item ) { wchar_t text[256]; Sprintf(text,_countof(text),L"%s.Command",name); const wchar_t *str=m_Parser.FindSetting(text); item.id=ID_CUSTOM; if (str) { for (int i=0;i<_countof(g_StdCommands);i++) if (_wcsicmp(str,g_StdCommands[i].name)==0) { item.id=g_StdCommands[i].id; break; } } if (item.id==ID_CUSTOM) { item.command=str; item.regName=name; } Sprintf(text,_countof(text),L"%s.Link",name); item.link=m_Parser.FindSetting(text); if (item.link) { const wchar_t *c=wcschr(item.link,'|'); if (c) { for (c++;*c==' ';) c++; item.link=c; } } Sprintf(text,_countof(text),L"%s.Icon",name); item.iconPath=m_Parser.FindSetting(text); Sprintf(text,_countof(text),L"%s.IconDisabled",name); item.iconPathD=m_Parser.FindSetting(text); Sprintf(text,_countof(text),L"%s.Label",name); str=m_Parser.FindSetting(text); if (str) { if (str[0]=='$') item.label=FindTranslation(str+1,NULL); else item.label=str; } Sprintf(text,_countof(text),L"%s.Tip",name); str=m_Parser.FindSetting(text); if (str) { if (str[0]=='$') item.tip=FindTranslation(str+1,NULL); else item.tip=str; } } void CBandWindow::ParseToolbar( void ) { m_Items.clear(); CString setting=GetSettingString(L"ToolbarItems"); m_Parser.LoadText(setting,setting.GetLength()); m_Parser.ParseText(); std::vector items; m_Parser.ParseTree(L"Items",items); m_Items.resize(items.size()); for (int i=0;i<(int)items.size();i++) { const wchar_t *name=items[i].name; StdToolbarItem &item=m_Items[i]; { // can't use memset here because item is not a POD (there is a CString inside) item.id=0; item.tip=NULL; item.label=NULL; item.command=NULL; item.link=NULL; item.iconPath=NULL; item.iconPathD=NULL; item.submenu=NULL; item.menuIcon=NULL; item.menuIconD=NULL; item.bIconLoaded=false; item.bDisabled=false; item.bChecked=false; } // handle special names if (!*name) { item.id=ID_LAST; continue; } if (_wcsicmp(name,L"SEPARATOR")==0) { item.id=ID_SEPARATOR; continue; } ParseToolbarItem(name,item); int idx=items[i].children; if (idx>=0) item.submenu=&m_Items[idx]; } if (m_Items.size()==1) { m_Items.resize(2); m_Items[1]=m_Items[0]; m_Items[0].id=ID_SETTINGS; m_Items[0].tip=FindTranslation(L"$Toolbar.Settings",NULL); m_Items[0].command=L"settings"; m_Items[0].iconPath=L",1"; } } LRESULT CALLBACK CBandWindow::ToolbarSubclassProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData ) { if (uMsg==WM_SETTINGCHANGE) { // HACK: Looks like WM_SETTINGCHANGE breaks the toolbar if it contains a split dropdown button (most likely something to do with metrics or themes) // So we delete all buttons and post a message recreate them int count=(int)SendMessage(hWnd,TB_BUTTONCOUNT,0,0); CBandWindow *pThis=(CBandWindow*)uIdSubclass; if (count>0) { for (int i=count-1;i>=0;i--) { TBBUTTON button; SendMessage(hWnd,TB_GETBUTTON,i,(LPARAM)&button); pThis->m_Buttons[i].fsState=button.fsState; SendMessage(hWnd,TB_DELETEBUTTON,i,0); } ::PostMessage((HWND)dwRefData,CBandWindow::BWM_UPDATEBUTTONS,0,0); } // Also refresh the buttons when the folder settings change if (pThis->HasFolderSettings()) ::PostMessage((HWND)dwRefData,CBandWindow::BWM_UPDATETOOLBAR,0,0); } if (uMsg==WM_PAINT) { CBandWindow *pThis=(CBandWindow*)uIdSubclass; if (!pThis->m_pBrowserBag && pThis->HasPanes()) pThis->UpdateBag(); } return DefSubclassProc(hWnd,uMsg,wParam,lParam); } LRESULT CBandWindow::OnCreate( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled ) { ParseToolbar(); bool bLabels=false; bool bList=GetSettingBool(L"ToolbarListMode"); int mainCount=0; // number of the main items for (std::vector::const_iterator it=m_Items.begin();it->id!=ID_LAST;++it,mainCount++) if (it->label) bLabels=true; // create the toolbar if (bLabels && !bList) m_Toolbar=CreateWindow(TOOLBARCLASSNAME,L"",WS_CHILD|TBSTYLE_TOOLTIPS|TBSTYLE_FLAT|CCS_NODIVIDER|CCS_NOPARENTALIGN|CCS_NORESIZE,0,0,10,10,m_hWnd,(HMENU)101,g_Instance,NULL); else m_Toolbar=CreateWindow(TOOLBARCLASSNAME,L"",WS_CHILD|TBSTYLE_TOOLTIPS|TBSTYLE_FLAT|TBSTYLE_LIST|CCS_NODIVIDER|CCS_NOPARENTALIGN|CCS_NORESIZE,0,0,10,10,m_hWnd,(HMENU)101,g_Instance,NULL); m_Toolbar.SendMessage(TB_SETEXTENDEDSTYLE,0,TBSTYLE_EX_MIXEDBUTTONS|TBSTYLE_EX_DRAWDDARROWS|TBSTYLE_EX_HIDECLIPPEDBUTTONS); m_Toolbar.SendMessage(TB_BUTTONSTRUCTSIZE,sizeof(TBBUTTON)); m_Toolbar.SendMessage(TB_SETMAXTEXTROWS,1); SetWindowSubclass(m_Toolbar,ToolbarSubclassProc,(UINT_PTR)this,(DWORD_PTR)m_hWnd); int iconSize=GetSettingInt(GetSettingBool(L"UseBigButtons")?L"LargeIconSize":L"SmallIconSize"); if (iconSize<8) iconSize=8; else if (iconSize>128) iconSize=128; m_MenuIconSize=GetSettingInt(L"MenuIconSize"); if (m_MenuIconSize<=0) m_MenuIconSize=0; else if (m_MenuIconSize<8) m_MenuIconSize=8; if (m_MenuIconSize>32) m_MenuIconSize=32; m_ImgEnabled=ImageList_Create(iconSize,iconSize,ILC_COLOR32|ILC_MASK|(IsLanguageRTL()?ILC_MIRROR:0),0,mainCount); m_ImgDisabled=ImageList_Create(iconSize,iconSize,ILC_COLOR32|ILC_MASK|(IsLanguageRTL()?ILC_MIRROR:0),0,mainCount); HMODULE hShell32=GetModuleHandle(L"Shell32.dll"); std::vector modules; bool bSame=GetSettingBool(L"SameSizeButtons"); // create buttons m_Buttons.resize(mainCount); for (int i=0;i pFactory; if (SUCCEEDED(SHCreateItemFromIDList(pidl,IID_IShellItemImageFactory,(void**)&pFactory)) && pFactory) { SIZE size={iconSize,iconSize}; if (FAILED(pFactory->GetImage(size,SIIGBF_ICONONLY,&hBitmap))) hBitmap=NULL; } } } if (!hIcon && !hBitmap && !bNoIcon) hIcon=(HICON)LoadImage(hShell32,MAKEINTRESOURCE(1),IMAGE_ICON,iconSize,iconSize,LR_DEFAULTCOLOR); if (hIcon) { button.iBitmap=ImageList_AddIcon(m_ImgEnabled,hIcon); HICON hIcon2=item.iconPathD?LoadIcon(iconSize,item.iconPathD,modules):NULL; if (!hIcon2) hIcon2=CreateDisabledIcon(hIcon,iconSize); int idx=ImageList_AddIcon(m_ImgDisabled,hIcon2); Assert(button.iBitmap==idx); DestroyIcon(hIcon); DestroyIcon(hIcon2); } else if (hBitmap) { button.iBitmap=ImageList_AddMasked(m_ImgEnabled,hBitmap,CLR_NONE); int idx=ImageList_AddMasked(m_ImgDisabled,hBitmap,CLR_NONE); Assert(button.iBitmap==idx); DeleteObject(hBitmap); } button.fsState=(item.id!=ID_SETTINGS || GetSettingBool(L"EnableSettings"))?TBSTATE_ENABLED:0; button.fsStyle=BTNS_BUTTON|BTNS_NOPREFIX; if (!bSame) button.fsStyle|=BTNS_AUTOSIZE; if (item.label) { button.fsStyle|=BTNS_SHOWTEXT; button.iString=(INT_PTR)item.label; } bool bFolder=false; if (item.link) { wchar_t path[_MAX_PATH]; Strcpy(path,_countof(path),item.link); DoEnvironmentSubst(path,_countof(path)); CAbsolutePidl pidl; SFGAOF flags=0; if (SUCCEEDED(ShParseDisplayName(path,&pidl,SFGAO_FOLDER,&flags))) { if (flags&SFGAO_FOLDER) bFolder=true; } } if (item.submenu || bFolder) button.fsStyle|=(item.id::const_iterator it=modules.begin();it!=modules.end();++it) FreeLibrary(*it); // add buttons HIMAGELIST old=(HIMAGELIST)m_Toolbar.SendMessage(TB_SETIMAGELIST,0,(LPARAM)m_ImgEnabled); if (old) ImageList_Destroy(old); old=(HIMAGELIST)m_Toolbar.SendMessage(TB_SETDISABLEDIMAGELIST,0,(LPARAM)m_ImgDisabled); if (old) ImageList_Destroy(old); if (!m_Buttons.empty()) m_Toolbar.SendMessage(TB_ADDBUTTONS,(WPARAM)m_Buttons.size(),(LPARAM)&m_Buttons[0]); SendMessage(WM_CLEAR); return 0; } LRESULT CBandWindow::OnDestroy( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled ) { if (m_ImgEnabled) ImageList_Destroy(m_ImgEnabled); m_ImgEnabled=NULL; if (m_ImgDisabled) ImageList_Destroy(m_ImgDisabled); m_ImgDisabled=NULL; for (std::vector::iterator it=m_Items.begin();it!=m_Items.end();++it) { if (it->menuIcon) DeleteObject(it->menuIcon); if (it->menuIconD) DeleteObject(it->menuIconD); } m_Items.clear(); bHandled=FALSE; return 0; } LRESULT CBandWindow::OnUpdateUI( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled ) { // update the state of the custom buttons based on the registry settings CRegKey regSettings; if (regSettings.Open(HKEY_CURRENT_USER,GetSettingsRegPath())==ERROR_SUCCESS) { bool bMain=true; for (int idx=0;idx<(int)m_Items.size();idx++) { if (m_Items[idx].id==ID_LAST) bMain=false; if (!m_Items[idx].regName.IsEmpty()) { DWORD val; if (regSettings.QueryDWORDValue(m_Items[idx].regName,val)!=ERROR_SUCCESS) val=0; bool bDisabled=(val&1)!=0; bool bChecked=(val&2)!=0; if (bMain) { if (bDisabled!=m_Items[idx].bDisabled) m_Toolbar.SendMessage(TB_ENABLEBUTTON,idx+1,bDisabled?0:1); if (bChecked!=m_Items[idx].bChecked) m_Toolbar.SendMessage(TB_CHECKBUTTON,idx+1,bChecked?1:0); } m_Items[idx].bDisabled=bDisabled; m_Items[idx].bChecked=bChecked; } } } return 0; } void CBandWindow::SendEmail( void ) { const IID CLSID_SendMail={0x9E56BE60,0xC50F,0x11CF,{0x9A,0x2C,0x00,0xA0,0xC9,0x0A,0x90,0xCE}}; CComPtr pView; if (FAILED(m_pBrowser->QueryActiveShellView(&pView))) return; // check if there is anything selected CComQIPtr pView2=pView; int count; if (pView2 && SUCCEEDED(pView2->ItemCount(SVGIO_SELECTION,&count)) && count==0) return; // get the data object CComPtr pDataObj; if (FAILED(pView->GetItemObject(SVGIO_SELECTION,IID_IDataObject,(void**)&pDataObj))) return; CComQIPtr pAsync=pDataObj; if (pAsync) pAsync->SetAsyncMode(FALSE); // drop into the SendMail handler CComPtr pDropTarget; if (SUCCEEDED(CoCreateInstance(CLSID_SendMail,NULL,CLSCTX_ALL,IID_IDropTarget,(void **)&pDropTarget))) { POINTL pt={0,0}; DWORD dwEffect=DROPEFFECT_COPY; pDropTarget->DragEnter(pDataObj,MK_LBUTTON,pt,&dwEffect); pDropTarget->Drop(pDataObj,0,pt,&dwEffect); } } class CSendToZipHelper: public CComObjectRootEx, public IServiceProvider { public: BEGIN_COM_MAP(CSendToZipHelper) COM_INTERFACE_ENTRY_IID( IID_IServiceProvider, IServiceProvider ) END_COM_MAP() // from IServiceProvider virtual HRESULT STDMETHODCALLTYPE QueryService( REFGUID guidService, REFIID riid, void **ppvObject ); CComPtr m_pFolderView; }; HRESULT CSendToZipHelper::QueryService( REFGUID guidService, REFIID riid, void **ppvObject ) { if (guidService==SID_SNewMenuClient) { return m_pFolderView->QueryInterface(riid,ppvObject); } return E_NOINTERFACE; } void CBandWindow::SendToZip( void ) { const IID CLSID_SendToZip={0x888DCA60, 0xFC0A, 0x11CF, {0x8F, 0x0F, 0x00, 0xC0, 0x4F, 0xD7, 0xD0, 0x62}}; CComPtr pView; if (FAILED(m_pBrowser->QueryActiveShellView(&pView))) return; // check if there is anything selected CComQIPtr pView2=pView; CComPtr pFolder; if (FAILED(pView2->GetFolder(IID_IShellFolder,(void**)&pFolder)) || !pFolder) return; int count; if (pView2 && SUCCEEDED(pView2->ItemCount(SVGIO_SELECTION,&count)) && count==0) return; // get the data object CComPtr pDataObj; if (FAILED(pView->GetItemObject(SVGIO_SELECTION,IID_IDataObject,(void**)&pDataObj))) return; CComQIPtr pAsync=pDataObj; if (pAsync) pAsync->SetAsyncMode(FALSE); // drop into the SendMail handler CComPtr pDropTarget; if (SUCCEEDED(CoCreateInstance(CLSID_SendToZip,NULL,CLSCTX_ALL,IID_IDropTarget,(void **)&pDropTarget))) { CComQIPtr pDropWithSite=pDropTarget; if (pDropWithSite) { CComObject *pHelper; if (SUCCEEDED(CComObject::CreateInstance(&pHelper))) { pHelper->m_pFolderView=pView2; pDropWithSite->SetSite(pHelper); } else delete pHelper; } POINTL pt={0,0}; DWORD dwEffect=DROPEFFECT_COPY; pDropTarget->DragEnter(pDataObj,MK_LBUTTON,pt,&dwEffect); pDropTarget->Drop(pDataObj,0,pt,&dwEffect); } } static bool GetPidlPath( PIDLIST_ABSOLUTE pidl, wchar_t *path ) { path[0]=0; if (SHGetPathFromIDList(pidl,path) && *path) return true; if (GetWinVersion()>=WIN_VER_WIN7) { // maybe it is a library - try the default save folder CComPtr pShellItem; if (SUCCEEDED(SHCreateItemFromIDList(pidl,IID_IShellItem,(void**)&pShellItem))) { CComPtr pLibrary; if (SUCCEEDED(pLibrary.CoCreateInstance(CLSID_ShellLibrary)) && SUCCEEDED(pLibrary->LoadLibraryFromItem(pShellItem,STGM_READ))) { pShellItem=NULL; if (SUCCEEDED(pLibrary->GetDefaultSaveFolder(DSFT_DETECT,IID_IShellItem,(void**)&pShellItem)) && pShellItem) { CComString pPath; if (SUCCEEDED(pShellItem->GetDisplayName(SIGDN_FILESYSPATH,&pPath))) { Strcpy(path,_MAX_PATH,pPath); return true; } } } } } return false; } void CBandWindow::NewFolder( void ) { CComPtr pView; if (FAILED(m_pBrowser->QueryActiveShellView(&pView))) return; CComQIPtr pView2=pView; if (!pView2) return; { // check if this is a filesystem folder (InvokeCommand may crash for non-folders) CComPtr pFolder; CAbsolutePidl pidl; if (FAILED(pView2->GetFolder(IID_IPersistFolder2,(void**)&pFolder)) || FAILED(pFolder->GetCurFolder(&pidl))) return; wchar_t path[_MAX_PATH]; bool bFolder=GetPidlPath(pidl,path); // it is a folder if it has a path if (!bFolder) return; } CComPtr pFolder; if (FAILED(pView2->GetFolder(IID_IShellFolder,(void**)&pFolder)) || !pFolder) return; std::vector items; { // remember the old folders CComPtr pEnum; if (pFolder->EnumObjects(NULL,SHCONTF_FOLDERS,&pEnum)!=S_OK) pEnum=NULL; PITEMID_CHILD child; while (pEnum && pEnum->Next(1,&child,NULL)==S_OK) { STRRET str; if (SUCCEEDED(pFolder->GetDisplayNameOf(child,SHGDN_INFOLDER|SHGDN_FORPARSING,&str))) { CComString pName; StrRetToStr(&str,child,&pName); items.push_back(CalcFNVHash(pName)); } ILFree(child); } } CComPtr pMenu; HMENU menu=CreatePopupMenu(); bool bRename=false; if (SUCCEEDED(pFolder->CreateViewObject(m_hWnd,IID_IContextMenu,(void**)&pMenu))) { if (SUCCEEDED(pMenu->QueryContextMenu(menu,0,1,32767,CMF_NORMAL))) { CMINVOKECOMMANDINFOEX info={sizeof(info),CMIC_MASK_UNICODE}; info.lpVerb="NewFolder"; info.lpVerbW=L"NewFolder"; info.nShow=SW_SHOWNORMAL; info.fMask|=CMIC_MASK_NOASYNC; info.hwnd=GetAncestor(m_hWnd,GA_ROOT); // Note: InvokeCommand crashes if the item is "Computer". I don't know if this is a bug in Explorer // or I am not supposed to give unsupported verbs to InvokeCommand. Unfortunately there is no way to // check if "NewFolder" is a supported verb. It is not present in the menu no matter what I give to // QueryContextMenu. So we verify if this is a filesystem folder, cross fingers and hope for the best if (SUCCEEDED(pMenu->InvokeCommand((CMINVOKECOMMANDINFO*)&info))) bRename=true; } } DestroyMenu(menu); if (bRename) { // look for a new folder and rename it CComPtr pEnum; if (pFolder->EnumObjects(NULL,SHCONTF_FOLDERS,&pEnum)!=S_OK) pEnum=NULL; PITEMID_CHILD child; while (pEnum && pEnum->Next(1,&child,NULL)==S_OK) { STRRET str; if (SUCCEEDED(pFolder->GetDisplayNameOf(child,SHGDN_INFOLDER|SHGDN_FORPARSING,&str))) { CComString pName; StrRetToStr(&str,child,&pName); unsigned int hash=CalcFNVHash(pName); if (std::find(items.begin(),items.end(),hash)==items.end()) { // found the new folder pView->SelectItem(child,SVSI_SELECT|SVSI_EDIT|SVSI_DESELECTOTHERS|SVSI_ENSUREVISIBLE|SVSI_FOCUSED); break; } } ILFree(child); } } } void CBandWindow::ExecuteCommandFile( const wchar_t *pText ) { wchar_t command[256]; pText=GetToken(pText,command,_countof(command),L" \t\r\n"); if (_wcsicmp(command,L"open")==0) { // navigate to the given folder wchar_t path[_MAX_PATH]; GetToken(pText,path,_countof(path),L" \t\r\n"); CAbsolutePidl pidl; if (m_pBrowser && SUCCEEDED(ShParseDisplayName(path,&pidl,0,NULL))) { UINT flags=(GetKeyState(VK_CONTROL)<0?SBSP_NEWBROWSER:SBSP_SAMEBROWSER); m_pBrowser->BrowseObject(pidl,flags|SBSP_ABSOLUTE); } } else if (_wcsicmp(command,L"refresh")==0) { // refresh Explorer SendShellTabCommand(41504); } else if (_wcsicmp(command,L"select")==0) { // select the given files, deselect all others std::vector selected; wchar_t path[_MAX_PATH]; while (*pText) { pText=GetToken(pText,path,_countof(path),L"\t\r\n"); wchar_t *fname=PathFindFileName(path); CharUpper(fname); // trim leading spaces while (*fname==' ') fname++; // trim trailing spaces wchar_t *end=fname+Strlen(fname); while (end>fname && end[-1]==' ') end--; *end=0; if (*fname) selected.push_back(CalcFNVHash(fname)); } CComPtr pView; if (SUCCEEDED(m_pBrowser->QueryActiveShellView(&pView))) { CComQIPtr pView2=pView; if (!pView2) return; CComPtr pFolder; if (FAILED(pView2->GetFolder(IID_IShellFolder,(void**)&pFolder)) || !pFolder) return; CComPtr pEnum; if (SUCCEEDED(pView2->Items(SVGIO_ALLVIEW,IID_IEnumIDList,(void**)&pEnum)) && pEnum) { PITEMID_CHILD child; bool bFirst=true; while (pEnum->Next(1,&child,NULL)==S_OK) { STRRET str; if (SUCCEEDED(pFolder->GetDisplayNameOf(child,SHGDN_FORPARSING|SHGDN_INFOLDER,&str))) { CComString pName; StrRetToStr(&str,child,&pName); pName.MakeUpper(); unsigned int hash=CalcFNVHash(pName); UINT flags=SVSI_DESELECT; if (std::find(selected.begin(),selected.end(),hash)!=selected.end()) { // the file is in the list flags=SVSI_SELECT; if (bFirst) { flags|=SVSI_ENSUREVISIBLE|SVSI_FOCUSED; bFirst=false; } } pView->SelectItem(child,flags); } ILFree(child); } } } } } void CBandWindow::SendShellTabCommand( int command ) { // sends a command to the ShellTabWindowClass window for (CWindow parent=GetParent();parent.m_hWnd;parent=parent.GetParent()) { // find a parent window with class ShellTabWindowClass wchar_t name[256]; GetClassName(parent.m_hWnd,name,_countof(name)); if (_wcsicmp(name,L"ShellTabWindowClass")==0) { parent.SendMessage(WM_COMMAND,command); break; } } } void CBandWindow::ExecuteCustomCommand( const wchar_t *pCommand ) { wchar_t buf[2048]; Strcpy(buf,_countof(buf),pCommand); // expand environment variables DoEnvironmentSubst(buf,_countof(buf)); wchar_t *pBuf=buf; bool bArg1=wcsstr(buf,L"%1")!=NULL; bool bArg2=wcsstr(buf,L"%2")!=NULL; bool bArg3=wcsstr(buf,L"%3")!=NULL; bool bArg4=wcsstr(buf,L"%4")!=NULL; bool bArg5=wcsstr(buf,L"%5")!=NULL; wchar_t path[_MAX_PATH]; wchar_t file[_MAX_PATH]; wchar_t input[_MAX_PATH]; wchar_t output[_MAX_PATH]; wchar_t temp[_MAX_PATH]; path[0]=file[0]=input[0]=output[0]=temp[0]=0; CComPtr pView; if (SUCCEEDED(m_pBrowser->QueryActiveShellView(&pView))) { CComPtr pFolder; CAbsolutePidl pidl; CComQIPtr pView2=pView; if (pView2 && SUCCEEDED(pView2->GetFolder(IID_IPersistFolder2,(void**)&pFolder)) && SUCCEEDED(pFolder->GetCurFolder(&pidl))) { // get current path GetPidlPath(pidl,path); if (bArg2) { CComPtr pEnum; int count; // if only one file is selected get the file name (%2) if (SUCCEEDED(pView2->ItemCount(SVGIO_SELECTION,&count)) && count==1 && SUCCEEDED(pView2->Items(SVGIO_SELECTION,IID_IEnumIDList,(void**)&pEnum)) && pEnum) { PITEMID_CHILD child; if (pEnum->Next(1,&child,NULL)==S_OK) { CAbsolutePidl full; full.Attach(ILCombine(pidl,child)); SHGetPathFromIDList(full,file); ILFree(child); } } } if (bArg3 || bArg4) { GetTempPath(_countof(temp),temp); if (GetTempFileName(temp,L"cei",0,input)) { // create a text file with the selected files FILE *f; if (_wfopen_s(&f,input,L"wb")==0 && f) { CComPtr pEnum; if (SUCCEEDED(pView2->Items(SVGIO_SELECTION,IID_IEnumIDList,(void**)&pEnum)) && pEnum) { PITEMID_CHILD child; while (pEnum->Next(1,&child,NULL)==S_OK) { wchar_t fname[_MAX_PATH]; CAbsolutePidl full; full.Attach(ILCombine(pidl,child)); SHGetPathFromIDList(full,fname); ILFree(child); if (bArg3) { char fnameA[_MAX_PATH]; WcsToMbs(fnameA,_countof(fnameA),fname); fprintf_s(f,"%s\r\n",fnameA); } else { fwprintf_s(f,L"%s\r\n",fname); } } } fclose(f); } else { input[0]=0; bArg3=false; bArg4=false; } } else { input[0]=0; bArg3=false; bArg4=false; } } } if (bArg5) { if (!temp[0]) GetTempPath(_countof(temp),temp); if (GetTempFileName(temp,L"ceo",0,output)) { FILE *f; if (_wfopen_s(&f,output,L"wb")==0 && f) { fclose(f); } else { output[0]=0; bArg5=false; } } else { output[0]=0; bArg5=false; } } if (bArg1 || bArg2 || bArg3 || bArg4 || bArg5) { // expand %1, %2, %3, %4, %5 DWORD_PTR args[100]={(DWORD_PTR)path,(DWORD_PTR)file,(DWORD_PTR)input,(DWORD_PTR)input,(DWORD_PTR)output}; FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_ARGUMENT_ARRAY|FORMAT_MESSAGE_FROM_STRING,buf,0,0,(LPWSTR)&pBuf,0,(va_list*)args); } wchar_t exe[_MAX_PATH]; const wchar_t *params=SeparateArguments(pBuf,exe); if (_wcsicmp(exe,L"open")==0) { CAbsolutePidl pidl; if (m_pBrowser && SUCCEEDED(ShParseDisplayName((LPWSTR)params,&pidl,0,NULL))) { UINT flags=(GetKeyState(VK_CONTROL)<0?SBSP_NEWBROWSER:SBSP_SAMEBROWSER); m_pBrowser->BrowseObject(pidl,flags|SBSP_ABSOLUTE); } } else if (_wcsicmp(exe,L"sortby")==0) { CComQIPtr pView2=pView; if (pView2) ViewByProperty(pView2,params,false); } else if (_wcsicmp(exe,L"groupby")==0) { CComQIPtr pView2=pView; if (pView2) ViewByProperty(pView2,params,true); } else if (bArg3 || bArg4 || bArg5) { // create a process instead of using ShellExecute STARTUPINFO startupInfo={sizeof(startupInfo)}; PROCESS_INFORMATION processInfo; memset(&processInfo,0,sizeof(processInfo)); DWORD flags=CREATE_NO_WINDOW; if (CreateProcess(exe,pBuf,NULL,NULL,TRUE,flags,NULL,*path?path:NULL,&startupInfo,&processInfo)) { CloseHandle(processInfo.hThread); if (bArg5) { // wait for the process to finish so we can parse the output file WaitForSingleObject(processInfo.hProcess,INFINITE); } CloseHandle(processInfo.hProcess); } if (bArg5) { // process output FILE *f; if (_wfopen_s(&f,output,L"rb")==0 && f) { // load output file fseek(f,0,SEEK_END); int size=ftell(f); fseek(f,0,SEEK_SET); std::vector text(size+2); if (fread(&text[0],1,size,f)!=size) text.clear(); fclose(f); if (!text.empty()) { text[size]=0; text[size+1]=0; std::vector textW; if (size>=2 && text[0]==0xFF && text[1]==0xFE) ExecuteCommandFile((wchar_t*)&text[2]); else { int len=MbsToWcs(NULL,0,(char*)&text[0]); textW.resize(len+1); MbsToWcs(&textW[0],len+1,(char*)&text[0]); ExecuteCommandFile(&textW[0]); } } } DeleteFile(output); } } else { // simply execute ShellExecute(NULL,NULL,exe,params,path,SW_SHOWNORMAL); } if (pBuf!=buf) LocalFree(pBuf); } } void CBandWindow::ViewByProperty( IFolderView2 *pView, const wchar_t *pProperty, bool bGroup ) { SORTCOLUMN column={0}; column.direction=SORT_ASCENDING; if (pProperty) { if (pProperty[0]=='-') { column.direction=SORT_DESCENDING; pProperty++; } if (_wcsicmp(pProperty,L"name")==0) column.propkey=PKEY_ItemNameDisplay; else if (_wcsicmp(pProperty,L"type")==0) column.propkey=PKEY_ItemTypeText; else if (_wcsicmp(pProperty,L"size")==0) column.propkey=PKEY_Size; else if (_wcsicmp(pProperty,L"date")==0) column.propkey=PKEY_DateModified; else { wchar_t token[256]; pProperty=GetToken(pProperty,token,_countof(token),L" ,"); if (IIDFromString(token,&column.propkey.fmtid)!=S_OK) return; pProperty=GetToken(pProperty,token,_countof(token),L" ,"); column.propkey.pid=_wtol(token); } } if (bGroup) { PROPERTYKEY prop; BOOL ascending; if (pProperty && SUCCEEDED(pView->GetGroupBy(&prop,&ascending))) { if (prop==column.propkey && ascending) column.direction=SORT_DESCENDING; } pView->SetGroupBy(column.propkey,column.direction==SORT_ASCENDING); } else { int count; if (pProperty && SUCCEEDED(pView->GetSortColumnCount(&count)) && count>0) { std::vector columns(count); if (SUCCEEDED(pView->GetSortColumns(&columns[0],count))) { if (columns[0].propkey==column.propkey) column.direction=-columns[0].direction; } } pView->SetSortColumns(&column,1); } } LRESULT CBandWindow::OnUpdateButtons( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled ) { if (!m_Buttons.empty() && m_Toolbar.SendMessage(TB_BUTTONCOUNT)==0) m_Toolbar.SendMessage(TB_ADDBUTTONS,(WPARAM)m_Buttons.size(),(LPARAM)&m_Buttons[0]); return 0; } LRESULT CBandWindow::OnUpdateToolbar( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled ) { UpdateToolbar(); return 0; } static BOOL CALLBACK RefreshExplorerWindows( HWND hwnd, LPARAM lParam ) { wchar_t className[256]; if (GetClassName(hwnd,className,_countof(className))) { if (_wcsicmp(className,L"CabinetWClass")==0 || _wcsicmp(className,L"Progman")==0) PostMessage(hwnd,WM_COMMAND,41504,0); // post refresh command } return TRUE; } static bool ToggleExplorerSetting( const wchar_t *setting, DWORD off, DWORD on ) { CRegKey regKey; if (regKey.Open(HKEY_CURRENT_USER,L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced",KEY_READ|KEY_WRITE|KEY_WOW64_64KEY)==ERROR_SUCCESS) { DWORD val=off; if (regKey.QueryDWORDValue(setting,val)!=ERROR_SUCCESS) val=off; regKey.SetDWORDValue(setting,val==on?off:on); EnumWindows(RefreshExplorerWindows,0); return val==off; } return false; } // Executes a cut/copy/paste/delete command LRESULT CBandWindow::OnCommand( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled ) { int idx=LOWORD(wParam)-1; int id=m_Items[idx].id; if (id>=ID_CUSTOM) { if (m_Items[idx].command) { ExecuteCustomCommand(m_Items[idx].command); } else if (m_Items[idx].link) { wchar_t path[_MAX_PATH]; Strcpy(path,_countof(path),m_Items[idx].link); DoEnvironmentSubst(path,_countof(path)); CAbsolutePidl pidl; if (m_pBrowser && SUCCEEDED(ShParseDisplayName(path,&pidl,0,NULL))) { UINT flags=(GetKeyState(VK_CONTROL)<0?SBSP_NEWBROWSER:SBSP_SAMEBROWSER); m_pBrowser->BrowseObject(pidl,flags|SBSP_ABSOLUTE); } } return TRUE; } if (id==ID_SETTINGS) { #ifndef BUILD_SETUP if (GetKeyState(VK_SHIFT)<0) *(int*)0=0; // force a crash if Shift is pressed. Makes it easy to restart explorer.exe #endif EditSettings(); return TRUE; } if (id==ID_GOUP || id==ID_GOBACK || id==ID_GOFORWARD) { if (m_pBrowser) { UINT flags=(GetKeyState(VK_CONTROL)<0?SBSP_NEWBROWSER:SBSP_SAMEBROWSER); if (id==ID_GOUP) m_pBrowser->BrowseObject(NULL,flags|SBSP_PARENT); if (id==ID_GOBACK) m_pBrowser->BrowseObject(NULL,flags|SBSP_NAVIGATEBACK); if (id==ID_GOFORWARD) m_pBrowser->BrowseObject(NULL,flags|SBSP_NAVIGATEFORWARD); } return TRUE; } if (id==ID_EMAIL) { SendEmail(); return TRUE; } if (id==ID_RENAME) { CComPtr pView; if (SUCCEEDED(m_pBrowser->QueryActiveShellView(&pView))) { CComQIPtr pView2=pView; if (pView2) pView2->DoRename(); } return TRUE; } if (id==ID_NEWFOLDER) { NewFolder(); return TRUE; } if (id==ID_ZIPFOLDER) { SendToZip(); return TRUE; } if (id==ID_NAVPANE) { if (m_pBrowserBag) { VARIANT val={VT_EMPTY}; bool bNavPane=SUCCEEDED(m_pBrowserBag->Read(g_NavPaneVisible,&val,NULL)) && val.vt==VT_BOOL && val.boolVal; VariantClear(&val); val.vt=VT_BOOL; val.boolVal=bNavPane?VARIANT_FALSE:VARIANT_TRUE; m_pBrowserBag->Write(g_NavPaneVisible,&val); } return TRUE; } if (id==ID_DETAILSPANE) { if (m_pBrowserBag) { VARIANT val={VT_EMPTY}; bool bNavPane=SUCCEEDED(m_pBrowserBag->Read(g_DetailsPaneVisible,&val,NULL)) && val.vt==VT_BOOL && val.boolVal; VariantClear(&val); val.vt=VT_BOOL; val.boolVal=bNavPane?VARIANT_FALSE:VARIANT_TRUE; m_pBrowserBag->Write(g_DetailsPaneVisible,&val); } return TRUE; } if (id==ID_PREVIEWPANE) { if (m_pBrowserBag) { VARIANT val={VT_EMPTY}; bool bNavPane=SUCCEEDED(m_pBrowserBag->Read(g_PreviewPaneVisible,&val,NULL)) && val.vt==VT_BOOL && val.boolVal; VariantClear(&val); val.vt=VT_BOOL; val.boolVal=bNavPane?VARIANT_FALSE:VARIANT_TRUE; m_pBrowserBag->Write(g_PreviewPaneVisible,&val); } return TRUE; } if (id==ID_SHOW_EXTENSIONS) { CheckButton(ID_SHOW_EXTENSIONS,ToggleExplorerSetting(L"HideFileExt",1,0)); return TRUE; } if (id==ID_HIDDEN_FILES) { CheckButton(ID_HIDDEN_FILES,ToggleExplorerSetting(L"Hidden",2,1)); return TRUE; } if (id==ID_SYSTEM_FILES) { CheckButton(ID_SYSTEM_FILES,ToggleExplorerSetting(L"ShowSuperHidden",0,1)); return TRUE; } // check if the focus is on the tree side or on the list side CWindow focus=GetFocus(); wchar_t name[256]; GetClassName(focus,name,_countof(name)); CWindow parent=focus.GetParent(); if (_wcsicmp(name,WC_TREEVIEW)==0) { // send these commands to the parent of the tree view if (id==ID_CUT) parent.SendMessage(WM_COMMAND,41025); if (id==ID_COPY) parent.SendMessage(WM_COMMAND,41026); if (id==ID_PASTE) parent.SendMessage(WM_COMMAND,41027); if (id==ID_DELETE) parent.SendMessage(WM_COMMAND,40995); if (id==ID_PROPERTIES) ShowTreeProperties(focus.m_hWnd); } else { GetClassName(parent,name,_countof(name)); if (_wcsicmp(name,L"SHELLDLL_DefView")==0) { // send these commands to the SHELLDLL_DefView window if (id==ID_CUT) { parent.SendMessage(WM_COMMAND,28696); focus.InvalidateRect(NULL); } if (id==ID_COPY) parent.SendMessage(WM_COMMAND,28697); if (id==ID_PASTE) parent.SendMessage(WM_COMMAND,28698); if (id==ID_DELETE) parent.SendMessage(WM_COMMAND,28689); if (id==ID_PROPERTIES) parent.SendMessage(WM_COMMAND,28691); if (id==ID_COPYTO) parent.SendMessage(WM_COMMAND,28702); if (id==ID_MOVETO) parent.SendMessage(WM_COMMAND,28703); } } if (id==ID_UNDO) SendShellTabCommand(28699); if (id==ID_REDO) SendShellTabCommand(28704); if (id==ID_PASTE_SHORTCUT) parent.SendMessage(WM_COMMAND,28700); if (id==ID_MAP_DRIVE) SendShellTabCommand(41089); if (id==ID_DISCONNECT) SendShellTabCommand(41090); if (id==ID_CUSTOMIZEFOLDER) SendShellTabCommand(28722); if (id==ID_FOLDEROPTIONS) SendShellTabCommand(41251); if (id==ID_VIEW_TILES) SendShellTabCommand(28748); if (id==ID_VIEW_DETAILS) SendShellTabCommand(28747); if (id==ID_VIEW_LIST) SendShellTabCommand(28753); if (id==ID_VIEW_CONTENT) SendShellTabCommand(28754); if (id==ID_VIEW_ICONS1) SendShellTabCommand(28752); if (id==ID_VIEW_ICONS2) SendShellTabCommand(28750); if (id==ID_VIEW_ICONS3) SendShellTabCommand(28751); if (id==ID_VIEW_ICONS4) SendShellTabCommand(28749); if (id==ID_SELECTALL || id==ID_INVERT || id==ID_DESELECT) { // handle selection commands the hard way (instead of sending commands with SendShellTabCommand). // some folders don't support selection and they crash if they get selection commands CComPtr pView; if (FAILED(m_pBrowser->QueryActiveShellView(&pView))) return TRUE; CComQIPtr pView2=pView; if (!pView2) return TRUE; // ID_DESELECT if (id==ID_DESELECT) { pView2->SelectItem(-1,SVSI_DESELECTOTHERS); return TRUE; } int count; if (FAILED(pView2->ItemCount(SVGIO_ALLVIEW,&count))) return TRUE; // ID_SELECTALL if (id==ID_SELECTALL) { for (int i=0;iSelectItem(i,SVSI_SELECT); return TRUE; } // ID_INVERT // we can't use IFolderView2::GetSelectedItem to enumerate the selected items. there is a bug in it on Windows 7. when called // with 0 or 1 it returns 0 for the next item, causing an infinite loop. we have to use Item + GetSelectionState instead. // it allocates a PIDLs, so it is not ideal, but what can you do. stupid bugs for (int i=0;iItem(i,&child)) && child) { DWORD state; if (SUCCEEDED(pView2->GetSelectionState(child,&state))) pView2->SelectItem(i,(state&SVSI_SELECT)?SVSI_DESELECT:SVSI_SELECT); ILFree(child); } } return TRUE; } if (id==ID_REFRESH) SendShellTabCommand(41504); if (id==ID_STOP && m_pWebBrowser) m_pWebBrowser->Stop(); return TRUE; } LRESULT CBandWindow::OnRClick( int idCtrl, LPNMHDR pnmh, BOOL& bHandled ) { NMMOUSE *pInfo=(NMMOUSE*)pnmh; POINT pt=pInfo->pt; { RECT rc; int count=(int)m_Toolbar.SendMessage(TB_BUTTONCOUNT); m_Toolbar.SendMessage(TB_GETITEMRECT,count-1,(LPARAM)&rc); if (pt.x>rc.right) return 0; } m_Toolbar.ClientToScreen(&pt); ShowSettingsMenu(m_hWnd,pt.x,pt.y); return 1; } LRESULT CBandWindow::OnGetInfoTip( int idCtrl, LPNMHDR pnmh, BOOL& bHandled ) { NMTBGETINFOTIP *pTip=(NMTBGETINFOTIP*)pnmh; const StdToolbarItem &item=m_Items[pTip->lParam]; if (item.tip && _wcsicmp(item.tip,L"none")!=0) { // show the tip for the standard item Strcpy(pTip->pszText,pTip->cchTextMax,item.tip); } return 0; } // Callback for IShellMenu. Executes the selected command class CMenuCallback: public IShellMenuCallback { public: CMenuCallback( IShellBrowser *pBrowser ) { m_bExecuted=false; m_pBrowser=pBrowser; } virtual HRESULT STDMETHODCALLTYPE QueryInterface( REFIID riid, void **ppvObject ); virtual ULONG STDMETHODCALLTYPE AddRef( void ) { return 1; } virtual ULONG STDMETHODCALLTYPE Release( void ) { return 1; } STDMETHOD(CallbackSM)( LPSMDATA psmd, UINT uMsg, WPARAM wParam, LPARAM lParam ); private: bool m_bExecuted; IShellBrowser *m_pBrowser; }; HRESULT STDMETHODCALLTYPE CMenuCallback::QueryInterface( REFIID riid, void **ppvObject ) { if (riid==IID_IUnknown || riid==IID_IShellMenuCallback) { *ppvObject=this; return S_OK; } else { *ppvObject=NULL; return E_NOINTERFACE; } } HRESULT STDMETHODCALLTYPE CMenuCallback::CallbackSM( LPSMDATA psmd, UINT uMsg, WPARAM wParam, LPARAM lParam ) { switch(uMsg) { case SMC_GETINFO: { SMINFO *pSmInfo=(SMINFO*)lParam; if (pSmInfo->dwMask&SMIM_FLAGS) pSmInfo->dwFlags|=SMIF_DROPCASCADE|SMIF_TRACKPOPUP; if (pSmInfo->dwMask&SMIM_ICON) pSmInfo->iIcon=-1; } return S_OK; case SMC_SFEXEC: { if (m_bExecuted) return S_OK; m_bExecuted=true; SFGAOF flags=SFGAO_FOLDER|SFGAO_LINK; if (SUCCEEDED(psmd->psf->GetAttributesOf(1,&psmd->pidlItem,&flags))) { CAbsolutePidl pidl; if (flags&SFGAO_LINK) { flags=0; // resolve link CComPtr pLink; if (SUCCEEDED(psmd->psf->GetUIObjectOf(NULL,1,&psmd->pidlItem,IID_IShellLink,NULL,(void**)&pLink)) && pLink) pLink->GetIDList(&pidl); if (pidl) { CComPtr pFolder; PCUITEMID_CHILD child; SHBindToParent(pidl,IID_IShellFolder,(void**)&pFolder,&child); SFGAOF flags2=SFGAO_FOLDER; if (pFolder && SUCCEEDED(pFolder->GetAttributesOf(1,&child,&flags2)) && (flags2&SFGAO_FOLDER)) flags=SFGAO_FOLDER; else pidl.Clear(); } } if (!pidl) pidl.Attach(ILCombine(psmd->pidlFolder,psmd->pidlItem)); if (flags&SFGAO_FOLDER) { // navigate to folder if (m_pBrowser) { UINT flags=(GetKeyState(VK_CONTROL)<0?SBSP_NEWBROWSER:SBSP_SAMEBROWSER); m_pBrowser->BrowseObject(pidl,flags); } } else { // execute file SHELLEXECUTEINFO execute={sizeof(execute),SEE_MASK_IDLIST|SEE_MASK_FLAG_LOG_USAGE}; execute.lpIDList=pidl; execute.nShow=SW_SHOWNORMAL; ShellExecuteEx(&execute); } } return S_OK; } case SMC_PROMOTE: case SMC_EXITMENU: case SMC_GETSFINFO: case SMC_SFSELECTITEM: case SMC_REFRESH: case SMC_DEMOTE: case SMC_DEFAULTICON: case SMC_NEWITEM: case SMC_CHEVRONEXPAND: case SMC_DISPLAYCHEVRONTIP: case SMC_SETSFOBJECT: case SMC_SHCHANGENOTIFY: case SMC_CHEVRONGETTIP: case SMC_SFDDRESTRICTED: return S_OK; default: return S_FALSE; } } LRESULT CBandWindow::OnDropDown( int idCtrl, LPNMHDR pnmh, BOOL& bHandled ) { NMTOOLBAR *pButton=(NMTOOLBAR*)pnmh; int idx=0; const StdToolbarItem *pItem=NULL; for (std::vector::const_iterator it=m_Items.begin();it->id!=ID_LAST;++it,idx++) { RECT rc; if (m_Toolbar.SendMessage(TB_GETITEMRECT,idx,(LPARAM)&rc) && memcmp(&rc,&pButton->rcButton,sizeof(RECT))==0) { pItem=&*it; break; } } if (pItem && (pItem->submenu || pItem->link)) { if (pItem->submenu) { TPMPARAMS params={sizeof(params),pButton->rcButton}; m_Toolbar.ClientToScreen(¶ms.rcExclude); // must not use MapWindowPoints because it produces wrong results in RTL cases HMENU menu=CreateDropMenu(pItem->submenu); int res=TrackPopupMenuEx(menu,TPM_RETURNCMD|TPM_VERTICAL,params.rcExclude.left,params.rcExclude.bottom,m_hWnd,¶ms); DestroyMenu(menu); if (res>0) PostMessage(WM_COMMAND,res); } else if (pItem->link) { TPMPARAMS params={sizeof(params),pButton->rcButton}; m_Toolbar.MapWindowPoints(NULL,¶ms.rcExclude); // must use MapWindowPoints to handle RTL correctly CAbsolutePidl pidl; CComPtr pFolder; wchar_t buf[1024]; Strcpy(buf,_countof(buf),pItem->link); DoEnvironmentSubst(buf,_countof(buf)); if (SUCCEEDED(ShParseDisplayName(buf,&pidl,0,NULL))) SHBindToObject(NULL,pidl,NULL,IID_IShellFolder,(void **)&pFolder); if (pFolder) { HRESULT hr; CComPtr pMenu; CoCreateInstance(CLSID_TrackShellMenu,NULL,CLSCTX_INPROC_SERVER,IID_ITrackShellMenu,(void**)&pMenu); if (pMenu) { CMenuCallback callback(m_pBrowser); hr=pMenu->Initialize(&callback,-1,ANCESTORDEFAULT,SMINIT_TOPLEVEL|SMINIT_VERTICAL|SMINIT_RESTRICT_DRAGDROP); if (SUCCEEDED(hr)) { CRegKey cRegOrder; CComString pFavs; SHGetKnownFolderPath(FOLDERID_Favorites,0,NULL,&pFavs); if (pFavs && SUCCEEDED(SHGetPathFromIDList(pidl,buf))) { // must compare strings and not pidls. sometimes pidls can be different but point to the same folder pFavs.MakeUpper(); CharUpper(buf); if (wcscmp(pFavs,buf)==0) cRegOrder.Open(HKEY_CURRENT_USER,_T("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\MenuOrder\\Favorites")); } hr=pMenu->SetShellFolder(pFolder,pidl,cRegOrder.m_hKey,SMSET_BOTTOM|0x00000008); // SMSET_USEBKICONEXTRACTION=0x00000008 if (SUCCEEDED(hr)) { cRegOrder.Detach(); POINTL ptl={params.rcExclude.left,params.rcExclude.bottom}; RECTL rcl={params.rcExclude.left,params.rcExclude.top,params.rcExclude.right,params.rcExclude.bottom}; pMenu->Popup(GetAncestor(m_hWnd,GA_ROOT),&ptl,&rcl,MPPF_SETFOCUS|MPPF_BOTTOM); } } } } } // remove the next mouse click if it is on the same button MSG msg; RECT rc=pButton->rcButton; m_Toolbar.ClientToScreen(&rc); if (PeekMessage(&msg,NULL,WM_LBUTTONDOWN,WM_LBUTTONDBLCLK,PM_NOREMOVE) && PtInRect(&rc,msg.pt)) PeekMessage(&msg,NULL,WM_LBUTTONDOWN,WM_LBUTTONDBLCLK,PM_REMOVE); } return TBDDRET_DEFAULT; } LRESULT CBandWindow::OnChevron( int idCtrl, LPNMHDR pnmh, BOOL& bHandled ) { NMREBARCHEVRON *pChevron=(NMREBARCHEVRON*)pnmh; REBARBANDINFO info={sizeof(info),RBBIM_CHILD}; if (::SendMessage(pnmh->hwndFrom,RB_GETBANDINFO,pChevron->uBand,(LPARAM)&info) && info.hwndChild==m_Toolbar.m_hWnd) { RECT clientRect; m_Toolbar.GetClientRect(&clientRect); int idx=0; for (std::vector::const_iterator it=m_Items.begin();it->id!=ID_LAST;++it,idx++) { RECT rc; m_Toolbar.SendMessage(TB_GETITEMRECT,idx,(LPARAM)&rc); if (rc.right>clientRect.right) break; } while (m_Items[idx].id==ID_SEPARATOR) idx++; if (m_Items[idx].id==ID_LAST) return 1; HMENU menu=CreateDropMenu(&m_Items[idx]); TPMPARAMS params={sizeof(params),pChevron->rc}; // use ClientToScreen instead of MapWindowPoints because it works better in RTL mode ::ClientToScreen(pnmh->hwndFrom,(POINT*)¶ms.rcExclude); ::ClientToScreen(pnmh->hwndFrom,((POINT*)¶ms.rcExclude)+1); int res=TrackPopupMenuEx(menu,TPM_RETURNCMD|TPM_VERTICAL,params.rcExclude.left,params.rcExclude.bottom,m_hWnd,¶ms); DestroyMenu(menu); if (res>0) PostMessage(WM_COMMAND,res); // remove the next mouse click if it is on the chevron MSG msg; if (PeekMessage(&msg,NULL,WM_LBUTTONDOWN,WM_LBUTTONDBLCLK,PM_NOREMOVE) && PtInRect(¶ms.rcExclude,msg.pt)) PeekMessage(&msg,NULL,WM_LBUTTONDOWN,WM_LBUTTONDBLCLK,PM_REMOVE); return 1; } return 0; } HMENU CBandWindow::CreateDropMenu( const StdToolbarItem *pItem ) { HMODULE hShell32=GetModuleHandle(L"Shell32.dll"); std::vector modules; HMENU menu=CreateDropMenuRec(pItem,modules,hShell32); for (std::vector::const_iterator it=modules.begin();it!=modules.end();++it) FreeLibrary(*it); MENUINFO info={sizeof(info),MIM_STYLE,MNS_CHECKORBMP}; SetMenuInfo(menu,&info); return menu; } HMENU CBandWindow::CreateDropMenuRec( const StdToolbarItem *pItem, std::vector &modules, HMODULE hShell32 ) { HMENU menu=CreatePopupMenu(); for (int idx=0;pItem->id!=ID_LAST;pItem++,idx++) { if (pItem->id==ID_SEPARATOR) { AppendMenu(menu,MF_SEPARATOR,0,0); continue; } const wchar_t *name=pItem->label; if (!name && pItem->tip && _wcsicmp(pItem->tip,L"none")!=0) name=pItem->tip; if (!pItem->bIconLoaded) { pItem->bIconLoaded=true; if (m_MenuIconSize>0) { if (pItem->iconPath) { if (_wcsicmp(pItem->iconPath,L"NONE")!=0) { HICON hIcon=LoadIcon(m_MenuIconSize,pItem->iconPath,modules); if (!hIcon) hIcon=(HICON)LoadImage(hShell32,MAKEINTRESOURCE(1),IMAGE_ICON,m_MenuIconSize,m_MenuIconSize,LR_DEFAULTCOLOR); if (hIcon) { HICON hIcon2=pItem->iconPathD?LoadIcon(m_MenuIconSize,pItem->iconPathD,modules):NULL; if (!hIcon2) hIcon2=CreateDisabledIcon(hIcon,m_MenuIconSize); pItem->menuIcon=BitmapFromIcon(hIcon,m_MenuIconSize,NULL,true); pItem->menuIconD=BitmapFromIcon(hIcon2,m_MenuIconSize,NULL,true); } } } else if (pItem->link) { HICON hIcon=NULL; CAbsolutePidl pidl; wchar_t path[_MAX_PATH]; Strcpy(path,_countof(path),pItem->link); DoEnvironmentSubst(path,_countof(path)); if (SUCCEEDED(ShParseDisplayName(path,&pidl,0,NULL))) { if (!name) { CComString pName; if (SUCCEEDED(SHGetNameFromIDList(pidl,SIGDN_PARENTRELATIVEEDITING,&pName)) && pName) { pItem->menuText=pName; } } hIcon=LoadIcon(m_MenuIconSize,pidl); } if (hIcon) { HICON hIcon2=pItem->iconPathD?LoadIcon(m_MenuIconSize,pItem->iconPathD,modules):NULL; if (!hIcon2) hIcon2=CreateDisabledIcon(hIcon,m_MenuIconSize); pItem->menuIcon=BitmapFromIcon(hIcon,m_MenuIconSize,NULL,true); pItem->menuIconD=BitmapFromIcon(hIcon2,m_MenuIconSize,NULL,true); } } } } if (!name) name=pItem->menuText; if (pItem->submenu) { HMENU menu2=CreateDropMenu(pItem->submenu); AppendMenu(menu,MF_POPUP,(UINT_PTR)menu2,name); } else { int cmd=(int)(pItem-&m_Items[0]+1); AppendMenu(menu,MF_STRING,cmd,name); } if (pItem->menuIcon) { MENUITEMINFO mii={sizeof(mii)}; mii.fMask=MIIM_BITMAP; mii.hbmpItem=pItem->bDisabled?pItem->menuIconD:pItem->menuIcon; SetMenuItemInfo(menu,idx,TRUE,&mii); } if (pItem->bDisabled) EnableMenuItem(menu,idx,MF_BYPOSITION|MF_GRAYED); if (pItem->bChecked) CheckMenuItem(menu,idx,MF_BYPOSITION|MF_CHECKED); } return menu; } void CBandWindow::UpdateToolbar( void ) { // disable the Up button if we are at the top level bool bDesktop=false; bool bNavPane=true; bool bDisableNavPane=false; bool bDetailsPane=true; bool bDisableDetailsPane=false; bool bPreviewPane=true; bool bDisablePreviewPane=false; if (m_pBrowser) { CComPtr pView; m_pBrowser->QueryActiveShellView(&pView); if (pView) { CComQIPtr pView2=pView; if (pView2) { CComPtr pFolder; pView2->GetFolder(IID_IPersistFolder2,(void**)&pFolder); if (pFolder) { CAbsolutePidl pidl; if (SUCCEEDED(pFolder->GetCurFolder(&pidl)) && pidl) { if (ILIsEmpty(pidl)) bDesktop=true; // only the top level has empty PIDL } } if (m_pBrowserBag) { if (GetWinVersion()>=WIN_VER_WIN8) { VARIANT val={VT_EMPTY}; if (SUCCEEDED(m_pBrowserBag->Read(g_ComboPaneEnabled,&val,NULL)) && val.vt==VT_BOOL && !val.boolVal) { bDisableDetailsPane=true; bDetailsPane=false; bDisablePreviewPane=true; bPreviewPane=false; } VariantClear(&val); } else { VARIANT val={VT_EMPTY}; if (SUCCEEDED(m_pBrowserBag->Read(g_DetailsPaneEnabled,&val,NULL)) && val.vt==VT_BOOL && !val.boolVal) { bDisableDetailsPane=true; bDetailsPane=false; } VariantClear(&val); if (SUCCEEDED(m_pBrowserBag->Read(g_PreviewPaneEnabled,&val,NULL)) && val.vt==VT_BOOL && !val.boolVal) { bDisablePreviewPane=true; bPreviewPane=false; } VariantClear(&val); } CComPtr pVisibility; if (SUCCEEDED(pView2->GetFolder(IID_IExplorerPaneVisibility,(void**)&pVisibility)) && pVisibility) { EXPLORERPANESTATE state=0; if (SUCCEEDED(pVisibility->GetPaneState(EP_NavPane,&state))) { bDisableNavPane=(state&EPS_FORCE)!=0; if (bDisableNavPane) bNavPane=!(state&EPS_DEFAULT_OFF); } if (!bDisableDetailsPane) { state=0; if (SUCCEEDED(pVisibility->GetPaneState(EP_DetailsPane,&state))) { bDisableDetailsPane=(state&EPS_FORCE)!=0; if (bDisableDetailsPane) bDetailsPane=!(state&EPS_DEFAULT_OFF); } } if (!bDisablePreviewPane) { state=0; if (SUCCEEDED(pVisibility->GetPaneState(EP_PreviewPane,&state))) { bDisablePreviewPane=(state&EPS_FORCE)!=0; if (bDisablePreviewPane) bPreviewPane=!(state&EPS_DEFAULT_OFF); } } } } } } if (m_pBrowserBag) { if (!bDisableNavPane) { VARIANT val={VT_EMPTY}; bNavPane=SUCCEEDED(m_pBrowserBag->Read(g_NavPaneVisible,&val,NULL)) && val.vt==VT_BOOL && val.boolVal; VariantClear(&val); } if (!bDisableDetailsPane) { VARIANT val={VT_EMPTY}; bDetailsPane=SUCCEEDED(m_pBrowserBag->Read(g_DetailsPaneVisible,&val,NULL)) && val.vt==VT_BOOL && val.boolVal; VariantClear(&val); } if (!bDisablePreviewPane) { VARIANT val={VT_EMPTY}; bPreviewPane=SUCCEEDED(m_pBrowserBag->Read(g_PreviewPaneVisible,&val,NULL)) && val.vt==VT_BOOL && val.boolVal; VariantClear(&val); } } } EnableButton(ID_GOUP,!bDesktop); if (m_pBrowserBag) { EnableButton(ID_NAVPANE,!bDisableNavPane); CheckButton(ID_NAVPANE,bNavPane); EnableButton(ID_DETAILSPANE,!bDisableDetailsPane); CheckButton(ID_DETAILSPANE,bDetailsPane); EnableButton(ID_PREVIEWPANE,!bDisablePreviewPane); CheckButton(ID_PREVIEWPANE,bPreviewPane); } if (HasFolderSettings()) UpdateFolderSettings(); } void CBandWindow::UpdateFolderSettings( void ) { bool bExtensions=false, bHidden=false, bSystem=false; CRegKey regKey; if (regKey.Open(HKEY_CURRENT_USER,L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced",KEY_READ|KEY_WOW64_64KEY)==ERROR_SUCCESS) { DWORD val; if (regKey.QueryDWORDValue(L"HideFileExt",val)==ERROR_SUCCESS) bExtensions=(val!=1); if (regKey.QueryDWORDValue(L"Hidden",val)==ERROR_SUCCESS) bHidden=(val==1); if (regKey.QueryDWORDValue(L"ShowSuperHidden",val)==ERROR_SUCCESS) bSystem=(val==1); } CheckButton(ID_SHOW_EXTENSIONS,bExtensions); CheckButton(ID_HIDDEN_FILES,bHidden); CheckButton(ID_SYSTEM_FILES,bSystem); } void CBandWindow::EnableButton( int cmd, bool bEnable ) { bool bMain=true; bool bDisabled=!bEnable; for (int idx=0;idx<(int)m_Items.size();idx++) { if (m_Items[idx].id==ID_LAST) bMain=false; if (m_Items[idx].id==cmd && m_Items[idx].bDisabled!=bDisabled) { m_Items[idx].bDisabled=bDisabled; if (bMain) m_Toolbar.SendMessage(TB_ENABLEBUTTON,idx+1,bDisabled?0:1); } } } void CBandWindow::CheckButton( int cmd, bool bCheck ) { bool bMain=true; for (int idx=0;idx<(int)m_Items.size();idx++) { if (m_Items[idx].id==ID_LAST) bMain=false; if (m_Items[idx].id==cmd && m_Items[idx].bChecked!=bCheck) { m_Items[idx].bChecked=bCheck; if (bMain) m_Toolbar.SendMessage(TB_CHECKBUTTON,idx+1,bCheck?1:0); } } } bool CBandWindow::HasPanes( void ) const { for (int idx=0;idx<(int)m_Items.size();idx++) { if (m_Items[idx].id==ID_NAVPANE || m_Items[idx].id==ID_DETAILSPANE || m_Items[idx].id==ID_PREVIEWPANE) return true; } return false; } bool CBandWindow::HasFolderSettings( void ) const { for (int idx=0;idx<(int)m_Items.size();idx++) { if (m_Items[idx].id==ID_SHOW_EXTENSIONS || m_Items[idx].id==ID_HIDDEN_FILES || m_Items[idx].id==ID_SYSTEM_FILES) return true; } return false; } void CBandWindow::UpdateBag( void ) { if (!m_pBrowserBag) { CComPtr pFrame; IUnknown_QueryService(m_pBrowser,SID_FrameManager,IID_IUnknown,(void**)&pFrame); IUnknown_QueryService(pFrame,SID_PerBrowserPropertyBag,IID_IPropertyBag,(void**)&m_pBrowserBag); if (m_pBrowserBag) { void **vtbl=*(void***)m_pBrowserBag.p+4; if (InterlockedCompareExchangePointer((void**)&g_OldBagWrite,*vtbl,0)==0) { DWORD oldProtect; VirtualProtect(vtbl,sizeof(void*),PAGE_READWRITE,&oldProtect); *vtbl=BagWriteHook; VirtualProtect(vtbl,sizeof(void*),oldProtect,&oldProtect); // prevent the DLL from being unloaded after we mess with the vtable, otherwise bad things happen HMODULE q; GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,(const wchar_t*)g_Instance,&q); } } } PostMessage(BWM_UPDATETOOLBAR); } HRESULT __stdcall CBandWindow::BagWriteHook( IPropertyBag *pThis, LPCOLESTR pszPropName, VARIANT *pVar ) { if (_wcsicmp(pszPropName,g_NavPaneVisible)==0 || _wcsicmp(pszPropName,g_DetailsPaneVisible)==0 || _wcsicmp(pszPropName,g_PreviewPaneVisible)==0 || _wcsicmp(pszPropName,g_DetailsPaneEnabled)==0 || _wcsicmp(pszPropName,g_PreviewPaneEnabled)==0 || _wcsicmp(pszPropName,g_ComboPaneEnabled)==0 ) { TlsData *pData=GetTlsData(); if (pData && pData->band) pData->band->m_BandWindow.PostMessage(BWM_UPDATETOOLBAR); } return g_OldBagWrite(pThis,pszPropName,pVar); } void CBandWindow::Clear( void ) { m_TreeParent=NULL; m_pBrowser=NULL; m_pWebBrowser=NULL; m_pBrowserBag=NULL; } void CBandWindow::SetBrowsers( IShellBrowser *pBrowser, IWebBrowser2 *pWebBrowser ) { m_pBrowser=pBrowser; m_pWebBrowser=pWebBrowser; m_pBrowserBag=NULL; } /////////////////////////////////////////////////////////////////////////////// // CExplorerBand - adds a toolbar band to Windows Explorer with 2 buttons - "Up" and "Settings" CExplorerBand::CExplorerBand( void ) { m_bSubclassRebar=GetWinVersion()>=WIN_VER_WIN7; m_bSubclassedRebar=false; m_TopWindow=NULL; } // Subclasses the rebar control on Windows 7. Makes sure the RBBS_BREAK style is properly set. Windows 7 has a bug // that forces RBBS_BREAK for every rebar band LRESULT CALLBACK CExplorerBand::RebarSubclassProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData ) { if (uMsg==RB_SETBANDINFO && ((CExplorerBand*)uIdSubclass)->m_bHandleSetInfo) { REBARBANDINFO *pInfo=(REBARBANDINFO*)lParam; if ((pInfo->hwndChild==(HWND)dwRefData) && (pInfo->fMask&RBBIM_STYLE)) { if (((CExplorerBand*)uIdSubclass)->m_bBandNewLine) pInfo->fStyle|=RBBS_BREAK; else pInfo->fStyle&=~RBBS_BREAK; } } if (uMsg==WM_CLEAR) ((CExplorerBand*)uIdSubclass)->m_bHandleSetInfo=false; if (uMsg==RB_DELETEBAND) { int n=(int)SendMessage(hWnd,RB_GETBANDCOUNT,0,0); CExplorerBand *pThis=(CExplorerBand*)uIdSubclass; for (int i=0;im_bHandleSetInfo; pThis->m_bHandleSetInfo=false; SendMessage(hWnd,RB_SETBANDINFO,i,(LPARAM)&info); pThis->m_bHandleSetInfo=old; } return res; } } } return DefSubclassProc(hWnd,uMsg,wParam,lParam); } // Subclasses the rebar's parent to catch RBN_CHEVRONPUSHED LRESULT CALLBACK CExplorerBand::ParentSubclassProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData ) { if (uMsg==WM_NOTIFY && ((NMHDR*)lParam)->code==RBN_CHEVRONPUSHED) { if (SendMessage((HWND)dwRefData,uMsg,wParam,lParam)) return 0; } return DefSubclassProc(hWnd,uMsg,wParam,lParam); } // IDeskBand STDMETHODIMP CExplorerBand::GetBandInfo( DWORD dwBandID, DWORD dwViewMode, DESKBANDINFO* pdbi ) { // initializes the band if (!m_bSubclassedRebar) { HWND rebar=GetParent(m_BandWindow.GetToolbar()); wchar_t className[256]; GetClassName(rebar,className,_countof(className)); if (_wcsicmp(className,REBARCLASSNAME)==0) { if (m_bSubclassRebar) { CRegKey regSettings; m_bBandNewLine=false; if (regSettings.Open(HKEY_CURRENT_USER,GetSettingsRegPath())==ERROR_SUCCESS) { DWORD NewLine; if (regSettings.QueryDWORDValue(L"NewLine",NewLine)==ERROR_SUCCESS) m_bBandNewLine=NewLine!=0; } SetWindowSubclass(rebar,RebarSubclassProc,(UINT_PTR)this,(DWORD_PTR)m_BandWindow.GetToolbar()); } SetWindowSubclass(GetParent(rebar),ParentSubclassProc,(UINT_PTR)this,(DWORD_PTR)m_BandWindow.m_hWnd); m_bSubclassedRebar=true; } } RECT rc; SendMessage(m_BandWindow.GetToolbar(),TB_GETITEMRECT,0,(LPARAM)&rc); int minSize=rc.right; int count=(int)SendMessage(m_BandWindow.GetToolbar(),TB_BUTTONCOUNT,0,0); SendMessage(m_BandWindow.GetToolbar(),TB_GETITEMRECT,count-1,(LPARAM)&rc); bool bChevron=GetSettingBool(L"ResizeableToolbar"); if (pdbi) { if (pdbi->dwMask&DBIM_MINSIZE) { pdbi->ptMinSize.x=bChevron?minSize:rc.right; pdbi->ptMinSize.y=rc.bottom; } if (pdbi->dwMask&DBIM_MAXSIZE) { pdbi->ptMaxSize.x=0; // ignored pdbi->ptMaxSize.y=-1; // unlimited } if (pdbi->dwMask&DBIM_INTEGRAL) { pdbi->ptIntegral.x=0; // not sizeable pdbi->ptIntegral.y=0; // not sizeable } if (pdbi->dwMask&DBIM_ACTUAL) { pdbi->ptActual.x=rc.right; pdbi->ptActual.y=rc.bottom; } if (pdbi->dwMask&DBIM_TITLE) { *pdbi->wszTitle=0; // no title } if (pdbi->dwMask&DBIM_BKCOLOR) { //Use the default background color by removing this flag. pdbi->dwMask&=~DBIM_BKCOLOR; } if (pdbi->dwMask&DBIM_MODEFLAGS) { if (bChevron) pdbi->dwModeFlags|=DBIMF_USECHEVRON; } } return S_OK; } // IOleWindow STDMETHODIMP CExplorerBand::GetWindow( HWND* phwnd ) { if (!phwnd) return E_INVALIDARG; *phwnd=m_BandWindow.GetToolbar(); return S_OK; } STDMETHODIMP CExplorerBand::ContextSensitiveHelp( BOOL fEnterMode ) { return S_OK; } // IDockingWindow STDMETHODIMP CExplorerBand::CloseDW( unsigned long dwReserved ) { ShowDW(FALSE); return S_OK; } STDMETHODIMP CExplorerBand::ResizeBorderDW( const RECT* prcBorder, IUnknown* punkToolbarSite, BOOL fReserved ) { // Not used by any band object. return E_NOTIMPL; } STDMETHODIMP CExplorerBand::ShowDW( BOOL fShow ) { if (m_bSubclassRebar && m_bSubclassedRebar) { // on Windows 7 get the current RBBS_BREAK state and save it in the registry to be restored later HWND rebar=GetParent(m_BandWindow.GetToolbar()); m_bHandleSetInfo=true; if (!fShow) { int n=(int)SendMessage(rebar,RB_GETBANDCOUNT,0,0); for (int i=0;i::SetSite(pUnkSite); if (m_BandWindow.IsWindow()) m_BandWindow.DestroyWindow(); m_BandWindow.Clear(); if (m_bSubclassedRebar) { HWND hwnd=GetParent(m_BandWindow.GetToolbar()); if (m_bSubclassRebar) RemoveWindowSubclass(hwnd,RebarSubclassProc,(UINT_PTR)this); RemoveWindowSubclass(GetParent(hwnd),ParentSubclassProc,(UINT_PTR)this); } m_bSubclassedRebar=false; m_bHandleSetInfo=true; if (m_pWebBrowser && m_dwEventCookie!=0xFEFEFEFE) DispEventUnadvise(m_pWebBrowser,&DIID_DWebBrowserEvents2); m_pWebBrowser=NULL; //If punkSite is not NULL, a new site is being set. if (pUnkSite) { // hook GetTlsData()->band=this; //Get the parent window. HWND hWndParent=NULL; CComQIPtr pOleWindow=pUnkSite; if (pOleWindow) pOleWindow->GetWindow(&hWndParent); if (!IsWindow(hWndParent)) return E_FAIL; m_TopWindow=GetAncestor(hWndParent,GA_ROOT); if (!GetProp(m_TopWindow,g_LoadedSettingsAtom)) { SetProp(m_TopWindow,g_LoadedSettingsAtom,(HANDLE)1); LoadSettings(); } m_BandWindow.Create(hWndParent,NULL,NULL,WS_CHILD); if (!m_BandWindow.IsWindow()) return E_FAIL; CComQIPtr pProvider=pUnkSite; if (pProvider) { CComPtr pBrowser; pProvider->QueryService(SID_SShellBrowser,IID_IShellBrowser,(void**)&pBrowser); // listen for web browser notifications. we only care about DISPID_NAVIGATECOMPLETE2 and DISPID_ONQUIT pProvider->QueryService(SID_SWebBrowserApp,IID_IWebBrowser2,(void**)&m_pWebBrowser); if (m_pWebBrowser) { if (m_dwEventCookie==0xFEFEFEFE) // ATL's event cookie is 0xFEFEFEFE when the sink is not advised DispEventAdvise(m_pWebBrowser,&DIID_DWebBrowserEvents2); } m_BandWindow.SetBrowsers(pBrowser,m_pWebBrowser); } } else { // unhook GetTlsData()->band=NULL; if (m_TopWindow) RemoveProp(m_TopWindow,g_LoadedSettingsAtom); m_TopWindow=NULL; } return S_OK; } STDMETHODIMP CExplorerBand::OnNavigateComplete( IDispatch *pDisp, VARIANT *URL ) { // this is called when the current folder changes. disable the Up button if this is the desktop folder m_BandWindow.UpdateToolbar(); return S_OK; } STDMETHODIMP CExplorerBand::OnCommandStateChange( long Command, VARIANT_BOOL Enable ) { if (Command==CSC_NAVIGATEFORWARD) { m_BandWindow.EnableButton(CBandWindow::ID_GOFORWARD,Enable?true:false); } if (Command==CSC_NAVIGATEBACK) { m_BandWindow.EnableButton(CBandWindow::ID_GOBACK,Enable?true:false); } return S_OK; } STDMETHODIMP CExplorerBand::OnQuit( void ) { if (m_pWebBrowser && m_dwEventCookie!=0xFEFEFEFE) // ATL's event cookie is 0xFEFEFEFE, when the sink is not advised return DispEventUnadvise(m_pWebBrowser,&DIID_DWebBrowserEvents2); return S_OK; }