#include "plugin.h" #include #include #include "Resource.h" #include "Reg.cpp" #include "MenuDlg.h" #include "FarMenu.h" #include "Pidl.h" #include "shlguid.h" #include "olethread.h" #include "farkeys.hpp" #include "HMenu.h" #include #define BOUNDS( x ) (sizeof( (x) ) / sizeof( (x)[0] )) void __stdcall _com_issue_error(HRESULT) throw(_com_error) { assert(0); } CPlugin::CPlugin(void) { Init(); } void CPlugin::Init() { m_pMalloc=NULL; m_bOldFARorInitErr=true; NULL_HWND=NULL; REG_Key=_T("\\RightClick"); REG_WaitToContinue=_T("WaitToContinue"); REG_UseGUI=_T("UseGUI"); REG_DelUsingFar=_T("DelUsingFar"); REG_ClearSel=_T("ClearSelection"); REG_Silent=_T("Silent"); REG_Helptext=_T("Helptext"); REG_DifferentOnly=_T("DifferentOnly"); REG_GuiPos=_T("GuiPos"); auto_sz::SetOem(); } CPlugin::~CPlugin(void) { } int CPlugin::GetMinFarVersion() { return MAKEFARVERSION(1, 70, MIN_FAR_BUILD); } void CPlugin::SetStartupInfo(const PluginStartupInfo *Info) { Init(); const size_t nMinSize=offsetof(PluginStartupInfo, AdvControl) +sizeof(PluginStartupInfo::AdvControl); if (Info->StructSizeFSF; lstrcpy(g_PluginRootKey, Info->RootKey); lstrcat(g_PluginRootKey, REG_Key); ReadRegValues(); OSVERSIONINFO osvi; osvi.dwOSVersionInfoSize=sizeof(osvi); if (!GetVersionEx(&osvi)) return; if (osvi.dwPlatformId==VER_PLATFORM_WIN32_WINDOWS) { m_bWin9x=true; m_bWin95=(osvi.dwMajorVersion==4 && !osvi.dwMinorVersion); m_bWin98=(osvi.dwMajorVersion==4 && osvi.dwMinorVersion<0x5a); m_bWinME=((osvi.dwMajorVersion>4) || (osvi.dwMajorVersion==4 && osvi.dwMinorVersion>=0x5a)); } m_bWinNT=(4==osvi.dwMajorVersion && 0==osvi.dwMinorVersion && VER_PLATFORM_WIN32_NT==osvi.dwPlatformId); m_bWin2K=(5==osvi.dwMajorVersion && 0==osvi.dwMinorVersion && VER_PLATFORM_WIN32_NT==osvi.dwPlatformId); m_bOldFARorInitErr=false; } void CPlugin::ReadRegValues() { m_WaitToContinue=GetRegKey(HKEY_CURRENT_USER, "", REG_WaitToContinue, 1); m_UseGUI=GetRegKey(HKEY_CURRENT_USER, "", REG_UseGUI, 2); m_DelUsingFar=GetRegKey(HKEY_CURRENT_USER, "", REG_DelUsingFar, 0); m_ClearSel=GetRegKey(HKEY_CURRENT_USER, "", REG_ClearSel, 1); m_Silent=GetRegKey(HKEY_CURRENT_USER, "", REG_Silent, 0); m_enHelptext=(EAdditionalStr)GetRegKey(HKEY_CURRENT_USER, "", REG_Helptext, 0); m_DifferentOnly=GetRegKey(HKEY_CURRENT_USER, "", REG_DifferentOnly, 0); m_GuiPos=GetRegKey(HKEY_CURRENT_USER, "", REG_GuiPos, 1); } void CPlugin::GetPluginInfo(PluginInfo *Info) { if (m_bOldFARorInitErr) return; m_PluginMenuString=GetMsg(LNG_TITLE); m_PluginConfigString=GetMsg(LNG_TITLE); Info->StructSize=sizeof(*Info); Info->Flags=PF_FULLCMDLINE; Info->DiskMenuStringsNumber=0; Info->PluginMenuStrings=&m_PluginMenuString; Info->PluginMenuStringsNumber=1; Info->PluginConfigStrings=&m_PluginConfigString; Info->PluginConfigStringsNumber=1; Info->CommandPrefix=PFX_RCLK _T(":") PFX_RCLK_TXT _T(":") PFX_RCLK_GUI _T(":") PFX_RCLK_CMD _T(":") PFX_RCLK_ITEM; } LPCTSTR g_szTopicMain=_T("Main"); LPCTSTR g_szTopicConfig=_T("Config"); LPCTSTR g_szTopicChooseMenuType=_T("ChooseMenuType"); LPCTSTR g_szTopicContextMenu=_T("ContextMenu"); LPCTSTR g_szTopicMyComp=_T("MyComp"); LPCTSTR g_szTopicError0=_T("Error0"); LPCTSTR g_szTopicError1=_T("Error1"); LPCTSTR g_szTopicError2=_T("Error2"); LPCTSTR g_szTopicClose=_T("Close"); LPCTSTR CPlugin::GetMsg(int nMsgId) { return PluginStartupInfo::GetMsg(ModuleNumber, nMsgId); } int CPlugin::Menu(int nX, int nY, int nMaxHeight, DWORD nFlags , LPCTSTR szTitle, LPCTSTR szBottom, LPCTSTR szHelpTopic , const int* pnBreakKeys, int* pnBreakCode , const FarMenuItem* pItems, int nItemsNumber) { return PluginStartupInfo::Menu(ModuleNumber, nX, nY, nMaxHeight, nFlags , szTitle, szBottom, szHelpTopic, pnBreakKeys, pnBreakCode , pItems, nItemsNumber); } int CPlugin::DialogEx(int X1, int Y1, int X2, int Y2, LPCTSTR szHelpTopic , FarDialogItem* pItem, int nItemsNumber, DWORD nReserved, DWORD nFlags , FARWINDOWPROC DlgProc, long pParam) { return PluginStartupInfo::DialogEx(ModuleNumber, X1, Y1, X2, Y2, szHelpTopic , pItem, nItemsNumber, nReserved, nFlags, DlgProc, pParam); } int CPlugin::Message(DWORD nFlags, LPCTSTR szHelpTopic, const LPCTSTR* pItems , int nItemsNumber, int nButtonsNumber) { if (m_Silent) return -1; return PluginStartupInfo::Message(ModuleNumber, nFlags, szHelpTopic, pItems , nItemsNumber, nButtonsNumber); } int CPlugin::Control(int nCommand, void* pParam) { return PluginStartupInfo::Control(INVALID_HANDLE_VALUE, nCommand, pParam); } int CPlugin::AdvControl(int nCommand, void *pParam) { return PluginStartupInfo::AdvControl(ModuleNumber, nCommand, pParam); } long WINAPI CPlugin::CfgDlgProcStatic(HANDLE hDlg, int Msg, int Param1, long Param2) { static CPlugin* pThis=NULL; if (DN_INITDIALOG==Msg) { pThis=reinterpret_cast(Param2); } if (pThis) pThis->CfgDlgProc(hDlg, Msg, Param1, Param2); return thePlug.DefDlgProc(hDlg,Msg,Param1,Param2); } void CPlugin::CfgDlgProc(HANDLE hDlg, int Msg, int Param1, long Param2) { if (DN_INITDIALOG==Msg) { SendDlgMessage(hDlg, DM_ENABLE, m_nShowMessId , 0==SendDlgMessage(hDlg, DM_GETCHECK, m_nSilentId, 0)); SendDlgMessage(hDlg, DM_ENABLE, m_nDifferentId , 0==SendDlgMessage(hDlg, DM_GETCHECK, m_nDifferentId-3, 0)); } if (DN_BTNCLICK==Msg && m_nSilentId==Param1) { SendDlgMessage(hDlg, DM_ENABLE, m_nShowMessId, 0==Param2); } if (DN_BTNCLICK==Msg && Param1>=m_nDifferentId-2 && Param1(this))) { return 0; } m_WaitToContinue=DlgItems[1].Selected; m_UseGUI=DlgItems[2].Selected; m_DelUsingFar=DlgItems[3].Selected; m_ClearSel=DlgItems[4].Selected; m_Silent=DlgItems[5].Selected; if (DlgItems[7].Selected) m_enHelptext=AS_NONE; if (DlgItems[8].Selected) m_enHelptext=AS_HELPTEXT; if (DlgItems[9].Selected) m_enHelptext=AS_VERB; m_DifferentOnly=DlgItems[10].Selected; if (DlgItems[12].Selected) m_GuiPos=0; if (DlgItems[13].Selected) m_GuiPos=1; SetRegKey(HKEY_CURRENT_USER, "", REG_WaitToContinue, m_WaitToContinue); SetRegKey(HKEY_CURRENT_USER, "", REG_UseGUI, m_UseGUI); SetRegKey(HKEY_CURRENT_USER, "", REG_DelUsingFar, m_DelUsingFar); SetRegKey(HKEY_CURRENT_USER, "", REG_ClearSel, m_ClearSel); SetRegKey(HKEY_CURRENT_USER, "", REG_Silent, m_Silent); SetRegKey(HKEY_CURRENT_USER, "", REG_Helptext, m_enHelptext); SetRegKey(HKEY_CURRENT_USER, "", REG_DifferentOnly, m_DifferentOnly); SetRegKey(HKEY_CURRENT_USER, "", REG_GuiPos, m_GuiPos); return 1; } void CPlugin::ExitFAR() { OleThread::Stop(); } HANDLE CPlugin::OpenPlugin(int nOpenFrom, int nItem) { LPCTSTR MsgItems[2]={GetMsg(LNG_TITLE)}; bool bSuccess=false; SetFileApisToANSI(); switch (OleThread::OpenPlugin(nOpenFrom, nItem)) { case DOMNU_ERR_DIFFERENT_FOLDERS: { MsgItems[1]=GetMsg(LNG_ERR_DIFFERENT_FOLDERS); Message(FMSG_WARNING|FMSG_MB_OK, g_szTopicError0, MsgItems , BOUNDS(MsgItems), 0); } break; case DOMNU_ERR_SHOW: { MsgItems[1]=GetMsg(LNG_ERR_SHOW); Message(FMSG_WARNING|FMSG_MB_OK, g_szTopicError1, MsgItems , BOUNDS(MsgItems), 0); } break; case DOMNU_ERR_INVOKE: { MsgItems[1]=GetMsg(LNG_ERR_INVOKE); Message(FMSG_WARNING|FMSG_MB_OK, g_szTopicError2, MsgItems , BOUNDS(MsgItems), 0); } break; case DOMNU_OK: if (m_WaitToContinue) { MsgItems[1]=GetMsg(LNG_CLOSE); Message(FMSG_MB_OK, g_szTopicClose, MsgItems, BOUNDS(MsgItems), 0); } bSuccess=true; break; case DOMENU_CANCELLED: break; default: assert(0); } SetFileApisToOEM(); if (bSuccess) { if (m_ClearSel && !Control(FCTL_UPDATEPANEL, NULL)) { assert(0); } } return INVALID_HANDLE_VALUE; } CPlugin::EDoMenu CPlugin::OpenPluginBkg(int nOpenFrom, int nItem) { LPTSTR szCmdLine=NULL; if (OPEN_COMMANDLINE==nOpenFrom) { LPCTSTR sz=reinterpret_cast(nItem); size_t nLen=512; do { delete[] szCmdLine; nLen*=2; szCmdLine=new TCHAR[nLen]; } while (m_fsf.ExpandEnvironmentStr(sz, szCmdLine, nLen)>=nLen-1); } EDoMenu enDoMenu=DoMenu(szCmdLine); delete[] szCmdLine; return enDoMenu; } CPlugin::EDoMenu CPlugin::DoMenu(LPTSTR szCmdLine) { IShellFolderPtr pDesktop; if (FAILED(SHGetDesktopFolder(&pDesktop))) return DOMNU_ERR_SHOW; m_pDesktop=pDesktop; if (!m_pMalloc) return DOMNU_ERR_SHOW; if (szCmdLine) { int UseGUISav=m_UseGUI; LPTSTR szParams=NULL; EAutoItem enAutoItem=AI_NONE; if (0==m_fsf.LStrnicmp(szCmdLine, PFX_RCLK _T(":"), BOUNDS(PFX_RCLK))) { szParams=szCmdLine+BOUNDS(PFX_RCLK); } else if (0==m_fsf.LStrnicmp(szCmdLine, PFX_RCLK_TXT _T(":"), BOUNDS(PFX_RCLK_TXT))) { szParams=szCmdLine+BOUNDS(PFX_RCLK_TXT); m_UseGUI=0; } else if (0==m_fsf.LStrnicmp(szCmdLine, PFX_RCLK_GUI _T(":"), BOUNDS(PFX_RCLK_GUI))) { szParams=szCmdLine+BOUNDS(PFX_RCLK_GUI); m_UseGUI=1; } else if (0==m_fsf.LStrnicmp(szCmdLine, PFX_RCLK_CMD _T(":"), BOUNDS(PFX_RCLK_CMD))) { szParams=szCmdLine+BOUNDS(PFX_RCLK_CMD); m_UseGUI=0; enAutoItem=AI_VERB; } else if (0==m_fsf.LStrnicmp(szCmdLine, PFX_RCLK_ITEM _T(":"), BOUNDS(PFX_RCLK_ITEM))) { szParams=szCmdLine+BOUNDS(PFX_RCLK_ITEM); m_UseGUI=0; enAutoItem=AI_ITEM; } if (szParams) { EDoMenu enDoMenu=MenuForPanelOrCmdLine(szParams, enAutoItem); m_UseGUI=UseGUISav; return enDoMenu; } } CFarMenu oMainMenu(g_szTopicMain); oMainMenu.AddItem(GetMsg(LNG_CONTEXT_MENU)); oMainMenu.AddItem(GetMsg(LNG_SELECT_DRIVE)); int nSelItem=0; while (1) { EDoMenu enDoMenu; nSelItem=oMainMenu.Show(GetMsg(LNG_TITLE), nSelItem, m_GuiPos==0); switch (nSelItem) { case 0: enDoMenu=MenuForPanelOrCmdLine(); if (DOMENU_BACK!=enDoMenu) return enDoMenu; break; case 1: enDoMenu=SelectDrive(); if (DOMENU_BACK!=enDoMenu) return enDoMenu; break; default: return DOMENU_CANCELLED; } } } CPlugin::EDoMenu CPlugin::SelectDrive() { CPidl oPidlMyComp(m_pMalloc); if (FAILED(SHGetSpecialFolderLocation(NULL_HWND, CSIDL_DRIVES, &oPidlMyComp))) { return DOMNU_ERR_SHOW; } auto_sz szMenuTitle; STRRET sr={STRRET_CSTR}; if (SUCCEEDED(m_pDesktop->GetDisplayNameOf(oPidlMyComp, SHGDN_NORMAL, &sr))) { szMenuTitle=auto_sz(sr, oPidlMyComp); } IShellFolderPtr pMyComputer; if (FAILED(m_pDesktop->BindToObject(oPidlMyComp, NULL, IID_IShellFolder , reinterpret_cast(&pMyComputer)))) { return DOMNU_ERR_SHOW; } IEnumIDListPtr pEnum; if (FAILED(pMyComputer->EnumObjects(NULL_HWND, SHCONTF_FOLDERS |SHCONTF_NONFOLDERS|SHCONTF_INCLUDEHIDDEN, &pEnum))) { return DOMNU_ERR_SHOW; } CFarMenu oDrivesMenu(g_szTopicMyComp); LPITEMIDLIST piid; ULONG nFetched; CPidl oPiids(m_pMalloc); unsigned nLastDrivePos=0; while (SUCCEEDED(pEnum->Next(1, &piid, &nFetched)) && nFetched) { sr.uType=STRRET_CSTR; if (FAILED(pMyComputer->GetDisplayNameOf(piid, SHGDN_NORMAL, &sr))) { assert(0); continue; } ULONG nAttr=SFGAO_FILESYSTEM; if (FAILED(pMyComputer->GetAttributesOf(1, (LPCITEMIDLIST*)&piid, &nAttr))) { assert(0); } auto_sz szMenuItem(sr, piid); if (SFGAO_FILESYSTEM==nAttr) { oDrivesMenu.InsertItem(nLastDrivePos, szMenuItem, false); oPiids.Insert(nLastDrivePos, piid); ++nLastDrivePos; } else { oDrivesMenu.AddItem(szMenuItem, false); oPiids.Add(piid); } } int nItem=oDrivesMenu.Show(szMenuTitle, 0, m_GuiPos==0); switch (nItem) { case CFarMenu::SHOW_CANCEL: return DOMENU_CANCELLED; case CFarMenu::SHOW_BACK: return DOMENU_BACK; } LPCTSTR sz=oDrivesMenu[nItem]; return DoMenu(pMyComputer, oPiids.GetArray()+nItem, &sz, 0, 1); } CPlugin::EDoMenu CPlugin::MenuForPanelOrCmdLine(LPTSTR szCmdLine/*=NULL*/ , EAutoItem enAutoItem/*=AI_NONE*/) { EDoMenu enRet=DOMNU_ERR_SHOW; LPCTSTR* pParams=NULL; LPCTSTR* pFiles=NULL; LPCTSTR szCommand=NULL; auto_sz strCommand; do { unsigned nFiles=0, nFolders=0; auto_sz strCurDir; bool bGetFromPanel=true; if (szCmdLine && GetFilesFromParams(szCmdLine, &pParams , &nFiles, &nFolders, &strCurDir, enAutoItem!=AI_NONE)) { assert(pParams); pFiles=pParams; if (enAutoItem==AI_NONE) { bGetFromPanel=false; } else { strCommand=pParams[0]; strCommand.Oem2Ansi(); szCommand=strCommand; pFiles=pParams+1; if (nFiles+nFolders>0) { bGetFromPanel=false; } else { delete[] pParams; pParams=NULL; } } } if (bGetFromPanel) { if (!GetFilesFromPanel(&pParams, &nFiles, &nFolders, &strCurDir)) { break; } assert(pParams); assert(nFiles+nFolders); pFiles=pParams; } auto_sz strFilesDir; bool bMenuAssigned=false; bool bDifferentFolders=false; unsigned i; for (i=0; iParseDisplayName(NULL_HWND, NULL, strFilesDir, &nCount , &oDirPidl, NULL))) { enRet=DOMNU_ERR_SHOW; break; } IShellFolderPtr pCurFolder; if (FAILED(m_pDesktop->BindToObject(oDirPidl, NULL, IID_IShellFolder , reinterpret_cast(&pCurFolder)))) { enRet=DOMNU_ERR_SHOW; break; } CPidl oPidl(m_pMalloc); for (i=0; iParseDisplayName(NULL_HWND, NULL, szFile , &nCount, &pidl, NULL))) { enRet=DOMNU_ERR_SHOW; break; } oPidl.Add(pidl); } if (oPidl.Count()==nFolders+nFiles) { enRet=DoMenu(pCurFolder, oPidl.GetArray(), pFiles, nFiles , nFolders, szCommand, enAutoItem); } } while (0); delete[] pParams; return enRet; } bool CPlugin::GetFilesFromParams(LPTSTR szCmdLine , LPCTSTR** ppFiles , unsigned* pnFiles , unsigned* pnFolders , auto_sz* pstrCurDir , bool bSkipFirst) { PanelInfo pi; if (!Control(FCTL_GETPANELINFO, &pi)) return false; *pstrCurDir=auto_sz(pi.CurDir, lstrlen(pi.CurDir)+1); if (pstrCurDir->Len()) m_fsf.AddEndSlash(*pstrCurDir); unsigned nCnt=ParseParams(szCmdLine); if (!nCnt) return false; *ppFiles=new LPCTSTR[nCnt]; ParseParams(szCmdLine, *ppFiles); for (unsigned i=bSkipFirst?1:0; iTrunc(szFName-pstrCurDir->operator LPCTSTR()); } else { if (pstrCurDir->Len()) m_fsf.AddEndSlash(*pstrCurDir); *ppFiles=new LPCTSTR[pi.SelectedItemsNumber]; int i; for (i=0; iGetUIObjectOf(NULL_HWND, nFolders+nFiles, pPiids , IID_IContextMenu, 0, reinterpret_cast(&pCMenu1)))) { return DOMNU_ERR_SHOW; } LPCONTEXTMENU pPreferredMenu=pCMenu1; IContextMenu2Ptr pCMenu2(pCMenu1); if (pCMenu2) { pPreferredMenu=pCMenu2; } IContextMenu3Ptr pCMenu3(pCMenu1); if (pCMenu3) { pPreferredMenu=pCMenu3; } // Решение дурацкой проблемы с падением в 2000 на paste if (m_bWin2K) pCMenu1.Detach(); CHMenu oHMenu; if (!oHMenu) return DOMNU_ERR_SHOW; enum {EMENU_CMF_EXTENDEDVERBS=0x00000100}; // rarely used verbs if (!pPreferredMenu || FAILED(pPreferredMenu->QueryContextMenu(oHMenu , 0, MENUID_CMDOFFSET, 0x7FFF, CMF_CANRENAME|EMENU_CMF_EXTENDEDVERBS))) { return DOMNU_ERR_SHOW; } int nCmd=0; if (szCommand) { for (int i=0; i=MENUID_CMDOFFSET) { int nId=nCmd-MENUID_CMDOFFSET; CHAR szVerb[100]; if (FAILED(pPreferredMenu->GetCommandString(nId, GCS_VERBA, NULL, szVerb , BOUNDS(szVerb)))) { szVerb[0]=_T('\0'); } if (lstrcmpA(szVerb, "rename")==0) { DWORD dwKey=KEY_F6; KeySequence Key={0, 1, &dwKey}; AdvControl(ACTL_POSTKEYSEQUENCE, &Key); return DOMENU_CANCELLED; } if (m_DelUsingFar && lstrcmpA(szVerb, "delete")==0) { DWORD dwKey=KEY_F8; if (GetKeyState(VK_LSHIFT)&0x8000 || GetKeyState(VK_RSHIFT)&0x8000) { dwKey=KEY_SHIFTDEL; } else if (GetKeyState(VK_LMENU)&0x8000 || GetKeyState(VK_RMENU)&0x8000) { dwKey=KEY_ALTDEL; } KeySequence Key={0, 1, &dwKey}; AdvControl(ACTL_POSTKEYSEQUENCE, &Key); return DOMENU_CANCELLED; } else { CMINVOKECOMMANDINFO cmici; cmici.cbSize = sizeof(cmici); cmici.fMask = 0; cmici.hwnd = NULL_HWND; cmici.lpVerb = MAKEINTRESOURCE(nId); cmici.lpParameters = NULL; cmici.lpDirectory = NULL; cmici.nShow = SW_SHOWNORMAL; cmici.dwHotKey = 0; cmici.hIcon = NULL; if (FAILED(pPreferredMenu->InvokeCommand(&cmici))) { // return DOMNU_ERR_INVOKE; // Иногда здесь возвращается ошибка даже в // нормальных ситуациях. // Например, если занести это в реестр //[HKEY_CLASSES_ROOT\AllFileSystemObjects\shellex\ContextMenuHandlers\Copy To] //@="{C2FBB630-2971-11D1-A18C-00C04FD75D13}" //[HKEY_CLASSES_ROOT\AllFileSystemObjects\shellex\ContextMenuHandlers\Move To] //@="{C2FBB631-2971-11D1-A18C-00C04FD75D13}" // , а потом вызвать один из добавившихся пунктов // и нажать Esc. } // Эта функция решает проблему, когда // после помещения файла в буфер и выхода из FARа // буфер портился. // проблема точно проявлялась на Build950 и XP if (FAILED(OleFlushClipboard())) { // иногда бывает E_FAIL //assert(0); } } } return DOMNU_OK; } bool CPlugin::ShowGuiMenu(HMENU hMenu , LPCONTEXTMENU pMenu1 , LPCONTEXTMENU2 pMenu2 , LPCONTEXTMENU3 pMenu3 , int* pnCmd) { SMenuDlgParam DlgParam; DlgParam.pMenu1=pMenu1; DlgParam.pMenu2=pMenu2; DlgParam.pMenu3=pMenu3; POINT pt={0}; if (!GetCursorPos(&pt)) { assert(0); } HWND hFarWnd=(HWND)AdvControl(ACTL_GETFARHWND, 0); if (m_GuiPos==1) { RECT rc; if (GetWindowRect(hFarWnd, &rc)) { pt.x=(rc.left+rc.right)>>1; pt.y=(rc.bottom+rc.top)>>1; } else { assert(0); } } // Не устанавливаем родительское окно hFarWnd, т.к. // окно мелькает если консольных окон несколько HWND hWnd=CreateDialogParam(m_hModule, MAKEINTRESOURCE(IDD_NULL), NULL , (DLGPROC)MenuDlgProc, (LPARAM)&DlgParam); assert(hWnd); if (!hWnd) return false; RECT rc; if (!GetWindowRect(hWnd, &rc) || !SetWindowPos(hWnd, HWND_TOPMOST, pt.x-(rc.right-rc.left)/2 , pt.y-(rc.bottom-rc.top)/2 , 0, 0, SWP_NOSIZE)) { assert(0); } *pnCmd=TrackPopupMenu(hMenu, TPM_LEFTALIGN | TPM_RETURNCMD | TPM_RIGHTBUTTON , pt.x, pt.y, 0, hWnd, NULL); if (!DestroyWindow(hWnd)) { assert(0); } return true; } bool CPlugin::GetAdditionalString(IContextMenu* pContextMenu, UINT nID , EAdditionalStr enAdditionalString , auto_sz* pstr, BOOL bToOEM/*=TRUE*/) { UINT nType; switch (enAdditionalString) { case AS_HELPTEXT: nType=m_bWin9x?GCS_HELPTEXTA:GCS_HELPTEXTW; break; case AS_VERB: nType=m_bWin9x?GCS_VERBA:GCS_VERBW; break; default: return false; } WCHAR szwAddInfo[200]=L"\0"; if (FAILED(pContextMenu->GetCommandString(nID, nType, NULL , reinterpret_cast(szwAddInfo), BOUNDS(szwAddInfo)))) { return false; } if (m_bWin9x) { *pstr=reinterpret_cast(szwAddInfo); if (bToOEM) pstr->Ansi2Oem(); } else { *pstr=szwAddInfo; } if (AS_HELPTEXT==enAdditionalString) pstr->RemoveTrailing(_T('.')); return !pstr->IsEmpty(); } bool CPlugin::ShowTextMenu(HMENU hMenu , LPCONTEXTMENU pPreferredMenu , LPCONTEXTMENU2 pMenu2 , LPCONTEXTMENU3 pMenu3 , int* pnCmd , LPCTSTR szTitle , LPSHELLFOLDER pCurFolder , LPCITEMIDLIST* ppiid , unsigned nPiidCnt) { int nItems=GetMenuItemCount(hMenu); if (nItems<1) return false; CFarMenu oFarMenu(g_szTopicContextMenu, nItems); for (int i=0; iGetUIObjectOf( NULL_HWND , nPiidCnt , ppiid , IID_IDataObject , NULL , reinterpret_cast(&pDataObject)))) { return false; } POINTL pt={0}; DWORD nEffect=DROPEFFECT_COPY; if (FAILED(pDropTarget->DragEnter(pDataObject, MK_LBUTTON , pt, &nEffect))) { return false; } if (FAILED(pDropTarget->Drop(pDataObject, MK_LBUTTON , pt, &nEffect))) { return false; } } } else { // generic submenu selected if (pMenu3) { if (NOERROR!=pMenu3->HandleMenuMsg(WM_INITMENUPOPUP , (WPARAM)mii.hSubMenu, nItem)) { } } else if (pMenu2) { if (NOERROR!=pMenu2->HandleMenuMsg(WM_INITMENUPOPUP , (WPARAM)mii.hSubMenu, nItem)) { } } bShowMenuRes=ShowTextMenu(mii.hSubMenu, pPreferredMenu, pMenu2 , pMenu3, pnCmd, szTitle, pCurFolder, ppiid, nPiidCnt); } if (!bShowMenuRes) { return false; } else if (*pnCmd!=MENUID_CANCELLED && *pnCmd!=MENUID_BACK) { return true; } } else { assert(0==(mii.fState&MFS_DISABLED)); *pnCmd=mii.wID; return true; } } } bool CPlugin::ShowFolder(LPSHELLFOLDER pParentFolder, LPCITEMIDLIST piid , int* pnCmd, LPCTSTR szTitle, LPDROPTARGET* ppDropTarget) { IShellFolderPtr pFolder; if (FAILED(pParentFolder->BindToObject(piid, NULL, IID_IShellFolder , reinterpret_cast(&pFolder)))) { return false; } IEnumIDListPtr pEnum; if (FAILED(pFolder->EnumObjects(NULL_HWND, SHCONTF_FOLDERS|SHCONTF_NONFOLDERS |SHCONTF_INCLUDEHIDDEN, &pEnum))) { return false; } CFarMenu oFarMenu; if (!m_pMalloc) return false; CPidl oFolderPiids(m_pMalloc); LPITEMIDLIST piidItem; ULONG nFetched; while (SUCCEEDED(pEnum->Next(1, &piidItem, &nFetched)) && nFetched) { STRRET sr; sr.uType=STRRET_CSTR; if (FAILED(pFolder->GetDisplayNameOf(piidItem, SHGDN_NORMAL, &sr))) { assert(0); continue; } ULONG nAttr=SFGAO_FOLDER; if (FAILED(pFolder->GetAttributesOf(1, (LPCITEMIDLIST*)&piidItem, &nAttr))) { assert(0); continue; } oFolderPiids.Add(piidItem); auto_sz szMenuItem(sr, piidItem); oFarMenu.AddItem(szMenuItem, 0!=(nAttr&SFGAO_FOLDER)); } for(int nItem=0;;) { nItem=oFarMenu.Show(szTitle, nItem, m_GuiPos==0); switch (nItem) { case CFarMenu::SHOW_CANCEL: case CFarMenu::SHOW_BACK: *pnCmd=MENUID_CANCELLED; return true; } ULONG nAttr=SFGAO_FOLDER; LPCITEMIDLIST pSelPiid=oFolderPiids.GetAt(nItem); if (FAILED(pFolder->GetAttributesOf(1, &pSelPiid, &nAttr))) { return false; } if (nAttr&SFGAO_FOLDER) { if (!ShowFolder(pFolder, pSelPiid, pnCmd, szTitle, ppDropTarget)) { return false; } if (MENUID_CANCELLED!=*pnCmd) break; } else { if (FAILED(pFolder->GetUIObjectOf( NULL_HWND , 1 , &pSelPiid , IID_IDropTarget , NULL , (LPVOID*)ppDropTarget))) { return false; } *pnCmd=MENUID_SENDTO_DONE; break; } } return true; }