Mercurial and Git clients can push and pull from this alias URL to interact with this repository. You can change to which repository an alias points by going to the Aliases link on the project page.
#include "stdafx.h"#include "TortoiseUtils.h"#include "StringUtils.h"#include "Thgstatus.h"#include "Winstat.h"#include "InitStatus.h"#include "SysInfo.h"#include "ShellExt.h"#include "RegistryConfig.h"#include "TortoiseIconBitmap.h"#include "ThgVersion.h"#include "Msi.h"#include "CShellExtCMenu.h"// According to http://msdn.microsoft.com/en-us/library/bb776094%28VS.85%29.aspx// the help texts for the commands should be reasonably short (under 40 characters)staticconstMenuDescriptionCMenuMenuDescList[]={{"commit",L"Commit...",L"Commit changes in repository","menucommit.ico",0},{"init",L"Create Repository Here",L"Create a new repository","menucreaterepos.ico",0},{"clone",L"Clone...",L"Create clone here from source","menuclone.ico",0},{"shelve",L"Shelve Changes",L"Shelve or unshelve file changes","shelve.ico",0},{"status",L"View File Status",L"Repository status & changes","menushowchanged.ico",0},{"add",L"Add Files...",L"Add files to version control","menuadd.ico",0},{"revert",L"Revert Files...",L"Revert file changes","menurevert.ico",0},{"remove",L"Remove Files...",L"Remove files from version control","menudelete.ico",0},{"rename",L"Rename File...",L"Rename file or directory","general.ico",0},{"workbench",L"Workbench",L"View change history of repository","menulog.ico",0},{"log",L"Revision History",L"View change history of selected files","menulog.ico",0},{"synch",L"Synchronize",L"Synchronize with remote repository","menusynch.ico",0},{"serve",L"Web Server",L"Start web server for this repository","proxy.ico",0},{"update",L"Update...",L"Update working directory","menucheckout.ico",0},{"thgstatus",L"Update Icons",L"Update icons for this repository","refresh_overlays.ico",0},{"userconf",L"Global Settings",L"Configure user wide settings","settings_user.ico",0},{"repoconf",L"Repository Settings",L"Configure repository settings","settings_repo.ico",0}, {"about", L"About TortoiseHg",
L"Show About Dialog",
"menuabout.ico", 0},
+ {"annotate", L"Annotate Files",+ L"Changeset information per file line",+ "menublame.ico", 0}, {"vdiff", L"Visual Diff",
L"View changes using GUI diff tool",
"TortoiseMerge.ico", 0},
{"hgignore",L"Edit Ignore Filter",L"Edit repository ignore filter","ignore.ico",0},{"guess",L"Guess Renames",L"Detect renames and copies","detect_rename.ico",0},{"grep",L"Search History",L"Search file revisions for patterns","menurepobrowse.ico",0},{"forget",L"Forget Files...",L"Remove files from version control","menudelete.ico",0},{"shellconf",L"Explorer Extension Settings",L"Configure Explorer extension","settings_repo.ico",0},/* Add new items here */// template//{"", L"", L"", ".ico", 0},};staticconstchar*constRepoNoFilesMenu="commit status shelve vdiff sep"" add revert rename forget remove sep"" workbench update grep sep"" synch serve clone init thgstatus sep"" hgignore guess sep"" shellconf repoconf userconf sep"" about";static const char* const RepoFilesMenu =
"commit status vdiff sep"
" add revert rename forget remove sep"
- " log sep"
+ " log annotate sep"
" about"
;
staticconstchar*constNoRepoMenu="clone init shellconf userconf thgstatus sep"" workbench sep"" about";voidCShellExtCMenu::AddMenuList(UINTidCmd,conststd::string&name){TDEBUG_TRACE("AddMenuList: idCmd = "<<idCmd<<" name = "<<name);myMenuIdMap[idCmd]=myDescMap[name];}voidGetCMenuTranslation(conststd::string&lang,conststd::string&name,std::wstring&menuText,std::wstring&helpText){std::wstringsubkey=L"Software\\TortoiseHg\\CMenu\\";subkey+=_WCSTR(lang.c_str());subkey+=L"\\";subkey+=_WCSTR(name.c_str());TDEBUG_TRACEW(L"GetCMenuTranslation: "<<subkey);HKEYhkey=0;LONGrv=RegOpenKeyExW(HKEY_CURRENT_USER,subkey.c_str(),0,KEY_READ,&hkey);if(rv==ERROR_SUCCESS&&hkey){GetRegSZValueW(hkey,L"menuText",menuText);GetRegSZValueW(hkey,L"helpText",helpText);}else{TDEBUG_TRACEW(L"GetCMenuTranslation: RegOpenKeyExW(\""<<subkey<<"\") failed");}if(hkey)RegCloseKey(hkey);}voidCShellExtCMenu::InitMenuMaps(constMenuDescription*menuDescs,std::size_tsz){if(myDescMap.empty()){std::stringlang;GetRegistryConfig("CMenuLang",lang);for(std::size_ti=0;i<sz;i++){MenuDescriptionmd=menuDescs[i];if(md.name.empty()){TDEBUG_TRACE("**** InitMenuMaps: ignoring entry with empty name");break;}TDEBUG_TRACE("InitMenuMaps: adding "<<md.name);// Look for translation of menu and help textif(!lang.empty())GetCMenuTranslation(lang,md.name,md.menuText,md.helpText);myDescMap[md.name]=md;}}myMenuIdMap.clear();}voidInsertMenuItemWithIcon1(HMENUhMenu,UINTindexMenu,UINTidCmd,conststd::wstring&menuText,conststd::string&iconName){// MFT_STRING is obsolete and should not be used (replaced by MIIM_STRING// from Win2K onward)MENUITEMINFOWmi;memset(&mi,0,sizeof(mi));mi.cbSize=sizeof(mi);mi.fMask=MIIM_ID|MIIM_STRING;mi.dwTypeData=const_cast<wchar_t*>(menuText.c_str());mi.cch=static_cast<UINT>(menuText.length());mi.wID=idCmd;if(SysInfo::Instance().IsVistaOrLater()){HBITMAPhBmp=GetTortoiseIconBitmap(iconName);if(hBmp){mi.fMask|=MIIM_BITMAP;mi.hbmpItem=hBmp;}else{TDEBUG_TRACE(" ***** InsertMenuItemWithIcon1: can't find "+iconName);}}else{HICONh=GetTortoiseIcon(iconName);if(h){mi.fMask|=MIIM_BITMAP|MIIM_DATA;mi.dwItemData=(ULONG_PTR)h;mi.hbmpItem=HBMMENU_CALLBACK;}else{TDEBUG_TRACE(" ***** InsertMenuItemWithIcon1: can't find "+iconName);}}InsertMenuItemW(hMenu,indexMenu,TRUE,&mi);TDEBUG_TRACEW(L"InsertMenuItemWithIcon1(\""<<menuText<<L"\") finished");}voidInsertSubMenuItemWithIcon2(HMENUhMenu,HMENUhSubMenu,UINTindexMenu,UINTidCmd,conststd::wstring&menuText,conststd::string&iconName){// MFT_STRING is obsolete and should not be used (replaced by MIIM_STRING// from Win2K onward)MENUITEMINFOWmi;memset(&mi,0,sizeof(mi));mi.cbSize=sizeof(mi);mi.fMask=MIIM_SUBMENU|MIIM_ID|MIIM_STRING;mi.dwTypeData=const_cast<wchar_t*>(menuText.c_str());mi.cch=static_cast<UINT>(menuText.length());mi.wID=idCmd;mi.hSubMenu=hSubMenu;if(SysInfo::Instance().IsVistaOrLater()){HBITMAPhBmp=GetTortoiseIconBitmap(iconName);if(hBmp){mi.fMask|=MIIM_BITMAP;mi.hbmpItem=hBmp;}else{TDEBUG_TRACE(" ***** InsertSubMenuItemWithIcon2: can't find "+iconName);}}else{HICONh=GetTortoiseIcon(iconName);if(h){mi.fMask|=MIIM_BITMAP|MIIM_DATA;mi.dwItemData=(ULONG_PTR)h;mi.hbmpItem=HBMMENU_CALLBACK;}else{TDEBUG_TRACE(" ***** InsertSubMenuItemWithIcon2: can't find "+iconName);}}InsertMenuItemW(hMenu,indexMenu,TRUE,&mi);TDEBUG_TRACEW(L"InsertMenuItemWithIcon2(\""<<menuText<<L"\") finished");}voidCShellExtCMenu::InsertMenuItemByName(HMENUhMenu,conststd::string&name,UINTindexMenu,UINTidCmd,UINTidCmdFirst,conststd::wstring&prefix){MenuDescriptionMap::iteratoriter=myDescMap.find(name);if(iter==myDescMap.end()){TDEBUG_TRACE("***** InsertMenuItemByName: can't find menu info for "<<name);return;}MenuDescriptionmd=iter->second;AddMenuList(idCmd-idCmdFirst,name);InsertMenuItemWithIcon1(hMenu,indexMenu,idCmd,prefix+md.menuText,md.iconName);}conststd::wstringTortoiseHgMenuEntryString=L"TortoiseHg";intHasTortoiseMenu(HMENUhMenu,bool&hasmenu)// returns -1 on error, 0 otherwise{hasmenu=false;constintcount=::GetMenuItemCount(hMenu);if(count==-1){TDEBUG_TRACE("***** HasTortoiseMenu: GetMenuItemCount returned -1");return-1;}MENUITEMINFOWmii;for(inti=0;i<count;++i){memset(&mii,0,sizeof(MENUITEMINFOW));mii.cbSize=sizeof(MENUITEMINFOW);// first GetMenuItemInfoW call: get size of menu item stringmii.fMask=MIIM_STRING;BOOLres=::GetMenuItemInfoW(hMenu,i,true,&mii);if(res==0){TDEBUG_TRACE("HasTortoiseMenu: "<<"first GetMenuItemInfo returned 0");continue;}if(mii.dwTypeData!=MFT_STRING){// not a stringcontinue;}// allocate buffer for the stringstd::vector<wchar_t>text(mii.cch+1);// second GetMenuItemInfoW call: get string into buffermii.dwTypeData=&text[0];++mii.cch;// size of buffer is one more than length of stringres=::GetMenuItemInfoW(hMenu,i,true,&mii);if(res==0){TDEBUG_TRACE("HasTortoiseMenu: "<<"second GetMenuItemInfo returned 0");continue;}conststd::wstringmenuitemtext(&text[0]);//TDEBUG_TRACEW(L"HasTortoiseMenu: "// << L"menuitemtext is '" << menuitemtext << L"'");if(menuitemtext==TortoiseHgMenuEntryString){TDEBUG_TRACE("HasTortoiseMenu: FOUND TortoiseHg menu entry");hasmenu=true;return0;}}TDEBUG_TRACE("HasTortoiseMenu: TortoiseHg menu entry NOT found");return0;}voidCShellExtCMenu::TweakMenuForVista(HMENUhMenu){if(!SysInfo::Instance().IsVistaOrLater())return;MENUINFOMenuInfo={};MenuInfo.cbSize=sizeof(MenuInfo);MenuInfo.fMask=MIM_STYLE|MIM_APPLYTOSUBMENUS;MenuInfo.dwStyle=MNS_CHECKORBMP;SetMenuInfo(hMenu,&MenuInfo);}#define ResultFromShort(i) ResultFromScode(MAKE_SCODE(SEVERITY_SUCCESS, 0, (USHORT)(i)))// IContextMenuSTDMETHODIMPCShellExtCMenu::QueryContextMenu(HMENUhMenu,UINTindexMenu,UINTidCmdFirst,UINTidCmdLast,UINTuFlags){TDEBUG_TRACE("CShellExtCMenu::QueryContextMenu");UINTidCmd=idCmdFirst;BOOLbAppendItems=TRUE;if((uFlags&0x000F)==CMF_NORMAL)bAppendItems=TRUE;elseif(uFlags&CMF_VERBSONLY)bAppendItems=TRUE;elseif(uFlags&CMF_EXPLORE)bAppendItems=TRUE;elsebAppendItems=FALSE;if(!bAppendItems)returnS_OK;boolhasthgmenu=false;if(HasTortoiseMenu(hMenu,hasthgmenu)==0&&hasthgmenu){TDEBUG_TRACE("CShellExtCMenu::QueryContextMenu: "<<"TortoiseHg menu entry already in menu -> skipping");returnS_OK;}InitMenuMaps(CMenuMenuDescList,sizeof(CMenuMenuDescList)/sizeof(MenuDescription));typedefstd::vector<std::string>entriesT;typedefentriesT::const_iteratorentriesIter;std::stringpromoted_string="commit,workbench";// default value if key not foundGetRegistryConfig("PromotedItems",promoted_string);entriesTpromoted;Tokenize(promoted_string,promoted,",");// Select menu to showboolfileMenu=!myFiles.empty();boolisHgrepo=false;std::stringcwd;if(!myFolder.empty()){cwd=myFolder;}elseif(fileMenu){cwd=IsDirectory(myFiles[0])?myFiles[0]:DirName(myFiles[0]);}if(!cwd.empty()){// check if target directory is a Mercurial repositorystd::stringroot=GetHgRepoRoot(cwd);isHgrepo=!root.empty();if(myFiles.size()==1&&root==myFiles[0]){fileMenu=false;myFolder=cwd;myFiles.clear();}}if((uFlags&CMF_EXTENDEDVERBS)==0){// shift key is not downif(!isHgrepo){// we are not inside a repostd::stringcval;if(GetRegistryConfig("HideMenuOutsideRepo",cval)!=0&&cval=="1"){returnS_OK;// don't show thg cmenu entries}}}TDEBUG_TRACE("CShellExtCMenu::QueryContextMenu: isHgrepo = "<<isHgrepo<<", fileMenu = "<<fileMenu);/* We have three menu types: files-selected, no-files-selected, no-repo */constchar*entries_string=0;if(isHgrepo)if(fileMenu)entries_string=RepoFilesMenu;elseentries_string=RepoNoFilesMenu;elseentries_string=NoRepoMenu;// start building TortoiseHg menus and submenusInsertMenu(hMenu,indexMenu++,MF_SEPARATOR|MF_BYPOSITION,0,NULL);entriesTentries;Tokenize(entries_string,entries," ");for(entriesIteri=entries.begin();i!=entries.end();i++){std::stringname=*i;if(contains(promoted,name)){InsertMenuItemByName(hMenu,name,indexMenu++,idCmd++,idCmdFirst,L"Hg ");}}constHMENUhSubMenu=CreatePopupMenu();if(hSubMenu){UINTindexSubMenu=0;boolisSeparator=true;for(entriesIteri=entries.begin();i!=entries.end();i++){std::stringname=*i;if(name=="sep"){if(!isSeparator){InsertMenu(hSubMenu,indexSubMenu++,MF_SEPARATOR|MF_BYPOSITION,0,NULL);isSeparator=true;}}else{if(!contains(promoted,name)){InsertMenuItemByName(hSubMenu,name,indexSubMenu++,idCmd++,idCmdFirst,L"");isSeparator=false;}}}if(isSeparator&&indexSubMenu>0)RemoveMenu(hSubMenu,indexSubMenu-1,MF_BYPOSITION);TweakMenuForVista(hSubMenu);}TDEBUG_TRACE(" CShellExtCMenu::QueryContextMenu: adding main THG menu");InsertSubMenuItemWithIcon2(hMenu,hSubMenu,indexMenu++,idCmd++,TortoiseHgMenuEntryString,"hg.ico");InsertMenu(hMenu,indexMenu++,MF_SEPARATOR|MF_BYPOSITION,0,NULL);InitStatus::check();TweakMenuForVista(hMenu);returnResultFromShort(idCmd-idCmdFirst);}STDMETHODIMPCShellExtCMenu::InvokeCommand(LPCMINVOKECOMMANDINFOlpcmi){TDEBUG_TRACE("CShellExtCMenu::InvokeCommand");HRESULThr=E_INVALIDARG;if(!HIWORD(lpcmi->lpVerb)){UINTidCmd=LOWORD(lpcmi->lpVerb);TDEBUG_TRACE("CShellExtCMenu::InvokeCommand: idCmd = "<<idCmd);MenuIdCmdMap::iteratoriter=myMenuIdMap.find(idCmd);if(iter!=myMenuIdMap.end()){RunDialog(iter->second.name);hr=S_OK;}else{TDEBUG_TRACE("***** CShellExtCMenu::InvokeCommand: action not found for idCmd "<<idCmd);}}returnhr;}STDMETHODIMPCShellExtCMenu::GetCommandString(UINT_PTRidCmd,UINTuFlags,UINTFAR*reserved,LPSTRpszName,UINTcchMax){// see http://msdn.microsoft.com/en-us/library/bb776094%28VS.85%29.aspxHRESULTres=S_FALSE;constchar*psz="";constwchar_t*pszw=0;std::stringsflags="?";switch(uFlags){caseGCS_HELPTEXTW:
sflags="GCS_HELPTEXTW";break;caseGCS_HELPTEXTA:
sflags="GCS_HELPTEXTA";break;caseGCS_VALIDATEW:
sflags="GCS_VALIDATEW";break;caseGCS_VALIDATEA:
sflags="GCS_VALIDATEA";break;caseGCS_VERBW:
sflags="GCS_VERBW";break;caseGCS_VERBA:
sflags="GCS_VERBA";break;}TDEBUG_TRACE("CShellExtCMenu::GetCommandString: idCmd = "<<idCmd<<", uFlags = "<<uFlags<<" ("<<sflags<<")"<<", cchMax = "<<cchMax);MenuIdCmdMap::iteratoriter=myMenuIdMap.find(static_cast<UINT>(idCmd));if(iter==myMenuIdMap.end()){TDEBUG_TRACE("***** CShellExtCMenu::GetCommandString: idCmd not found");}else{TDEBUG_TRACE("CShellExtCMenu::GetCommandString: name = \""<<iter->second.name<<"\"");if(uFlags==GCS_HELPTEXTW){pszw=iter->second.helpText.c_str();res=S_OK;size_tsize=iter->second.helpText.size();if(size>=40){TDEBUG_TRACE("***** CShellExtCMenu::GetCommandString: warning:"<<" length of help text is "<<size<<", which is not reasonably short (<40)");}}elseif(uFlags==GCS_HELPTEXTA){// we don't provide ansi help textspsz="";res=S_OK;}elseif(uFlags==GCS_VERBW||uFlags==GCS_VERBA){#if 0 psz = iter->second.name.c_str();#else// bugfix: don't provide verbs ("rename" conflicted with rename of explorer)psz="";#endifres=S_OK;}elseif(uFlags==GCS_VALIDATEW||uFlags==GCS_VALIDATEA){res=S_OK;}}if(cchMax<1){TDEBUG_TRACE("CShellExtCMenu::GetCommandString: cchMax = "<<cchMax<<" (is <1)");returnres;}size_tsize=0;if(uFlags&GCS_UNICODE){wchar_t*constdest=reinterpret_cast<wchar_t*>(pszName);constwchar_t*constsrc=pszw?pszw:_WCSTR(psz);wcsncpy(dest,src,cchMax-1);*(dest+cchMax-1)=0;size=wcslen(src);TDEBUG_TRACEW(L"CShellExtCMenu::GetCommandString: res = "<<int(res)<<L", pszName (wide) = \""<<dest<<L"\"");}else{strncpy(pszName,psz,cchMax-1);*(pszName+cchMax-1)=0;size=strlen(psz);TDEBUG_TRACE("CShellExtCMenu::GetCommandString: res = "<<int(res)<<", pszName = \""<<psz<<"\"");}if(size>cchMax-1){TDEBUG_TRACE("***** CShellExtCMenu::GetCommandString: string was truncated: size = "<<size<<", cchMax = "<<cchMax);}returnres;}STDMETHODIMPCShellExtCMenu::HandleMenuMsg(UINTuMsg,WPARAMwParam,LPARAMlParam){LRESULTres;returnHandleMenuMsg2(uMsg,wParam,lParam,&res);}STDMETHODIMPCShellExtCMenu::HandleMenuMsg2(UINTuMsg,WPARAMwParam,LPARAMlParam,LRESULT*pResult){// A great tutorial on owner drawn menus in shell extension can be found// here: http://www.codeproject.com/shell/shellextguide7.aspLRESULTres;if(!pResult)pResult=&res;*pResult=FALSE;switch(uMsg){caseWM_MEASUREITEM:
{MEASUREITEMSTRUCT*lpmis=(MEASUREITEMSTRUCT*)lParam;if(lpmis==NULL)break;lpmis->itemWidth+=2;if(lpmis->itemHeight<16)lpmis->itemHeight=16;*pResult=TRUE;}break;caseWM_DRAWITEM:
{DRAWITEMSTRUCT*lpdis=(DRAWITEMSTRUCT*)lParam;if(!lpdis||(lpdis->CtlType!=ODT_MENU)||!lpdis->itemData)break;//not for a menuDrawIconEx(lpdis->hDC,lpdis->rcItem.left-16,lpdis->rcItem.top+(lpdis->rcItem.bottom-lpdis->rcItem.top-16)/2,(HICON)lpdis->itemData,16,16,0,0,DI_NORMAL);*pResult=TRUE;}break;default:returnS_OK;}returnS_OK;}voidCShellExtCMenu::RunDialog(conststd::string&cmd){std::stringdir=GetTHgProgRoot();if(dir.empty()){TDEBUG_TRACE("RunDialog: THG root is empty");return;}std::stringhgcmd=dir+"\\thgw.exe";WIN32_FIND_DATAAdata;HANDLEhfind=FindFirstFileA(hgcmd.c_str(),&data);if(hfind==INVALID_HANDLE_VALUE){hgcmd=dir+"\\hgtk.exe";hfind=FindFirstFileA(hgcmd.c_str(),&data);if(hfind==INVALID_HANDLE_VALUE)hgcmd=dir+"\\thg.cmd";elseFindClose(hfind);}elseFindClose(hfind);hgcmd=Quote(hgcmd)+" --nofork "+cmd;std::stringcwd;if(!myFolder.empty()){cwd=myFolder;}elseif(!myFiles.empty()){cwd=IsDirectory(myFiles[0])?myFiles[0]:DirName(myFiles[0]);}else{TDEBUG_TRACE("***** RunDialog: can't get cwd");return;}if(cmd=="thgstatus"){if(Thgstatus::remove(cwd)!=0){std::stringp=dir+"\\TortoiseHgOverlayServer.exe";LaunchCommand(Quote(p),dir);}InitStatus::check();return;}if(!myFiles.empty()){conststd::stringtempfile=GetTemporaryFile();if(tempfile.empty()){TDEBUG_TRACE("***** RunDialog: error: GetTemporaryFile returned empty string");return;}TDEBUG_TRACE("RunDialog: temp file = "<<tempfile);HANDLEtempfileHandle=CreateFileA(tempfile.c_str(),GENERIC_WRITE,FILE_SHARE_READ,0,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,0);if(tempfileHandle==INVALID_HANDLE_VALUE){TDEBUG_TRACE("***** RunDialog: error: failed to create file "<<tempfile);return;}typedefstd::vector<std::string>::size_typeST;for(STi=0;i<myFiles.size();i++){DWORDdwWritten;TDEBUG_TRACE("RunDialog: temp file adding "<<myFiles[i]);WriteFile(tempfileHandle,myFiles[i].c_str(),static_cast<DWORD>(myFiles[i].size()),&dwWritten,0);WriteFile(tempfileHandle,"\n",1,&dwWritten,0);}CloseHandle(tempfileHandle);hgcmd+=" --listfile "+Quote(tempfile);}LaunchCommand(hgcmd,cwd);InitStatus::check();}voidCShellExtCMenu::PrintDebugHeader(LPCITEMIDLISTpIDFolder,LPDATAOBJECTpDataObj){TDEBUG_TRACE("CShellExtCMenu::Initialize");// get installed MSI product id (for debugging purposes for now)#ifdef _M_X64constchar*shellexid="{D5D1E532-CDAD-4FFD-9695-757B8A29B4BA}";#elseconstchar*shellexid="{728E8840-5878-4EA7-918F-281C2697ABB1}";#endifstd::vector<char>product_id(50,0);UINTmsires=::MsiGetProductCodeA(shellexid,&product_id[0]);TDEBUG_TRACE("MSI shellexid: "<<shellexid);TDEBUG_TRACE("MSI msires: "<<msires);TDEBUG_TRACE("MSI installed product id: "<<&product_id[0]);DWORDbusize=300;std::vector<char>buf(busize,0);msires=::MsiGetProductInfoA(&product_id[0],INSTALLPROPERTY_INSTALLLOCATION,&buf[0],&busize);if(msires==ERROR_SUCCESS){TDEBUG_TRACE("MSI install location: "<<&buf[0]);}else{TDEBUG_TRACE("MSI install location: error "<<msires);}TDEBUG_TRACEW(L"---- TortoiseHg shell extension version "<<ThgVersion::get()<<L"----");TDEBUG_TRACE(" pIDFolder: "<<pIDFolder);TDEBUG_TRACE(" pDataObj: "<<pDataObj);}STDMETHODIMPCShellExtCMenu::Initialize(LPCITEMIDLISTpIDFolder,LPDATAOBJECTpDataObj,HKEYhRegKey){TCHARname[MAX_PATH+1];PrintDebugHeader(pIDFolder,pDataObj);myFolder.clear();myFiles.clear();if(pDataObj){FORMATETCfmt={CF_HDROP,NULL,DVASPECT_CONTENT,-1,TYMED_HGLOBAL};STGMEDIUMstg={TYMED_HGLOBAL};if(SUCCEEDED(pDataObj->GetData(&fmt,&stg))&&stg.hGlobal){HDROPhDrop=(HDROP)GlobalLock(stg.hGlobal);if(hDrop){UINTuNumFiles=DragQueryFile(hDrop,0xFFFFFFFF,NULL,0);TDEBUG_TRACE(" hDrop uNumFiles = "<<uNumFiles);for(UINTi=0;i<uNumFiles;++i){if(DragQueryFile(hDrop,i,name,MAX_PATH)>0){TDEBUG_TRACE(" DragQueryFile ["<<i<<"] = "<<name);myFiles.push_back(name);}}}else{TDEBUG_TRACE(" hDrop is NULL ");}GlobalUnlock(stg.hGlobal);if(stg.pUnkForRelease){IUnknown*relInterface=(IUnknown*)stg.pUnkForRelease;relInterface->Release();}}else{TDEBUG_TRACE(" pDataObj->GetData failed");}}// if a directory backgroundif(pIDFolder){SHGetPathFromIDList(pIDFolder,name);TDEBUG_TRACE(" Folder "<<name);myFolder=name;}// disable context menu if neither the folder nor the files// have been foundif(myFolder.empty()&&myFiles.empty()){TDEBUG_TRACE(" shell extension not available on this object");returnE_FAIL;}else{returnS_OK;}}CShellExtCMenu::CShellExtCMenu(constchardummy){m_cRef=0L;CShellExt::IncDllRef();}CShellExtCMenu::~CShellExtCMenu(){CShellExt::DecDllRef();}STDMETHODIMP_(ULONG)CShellExtCMenu::AddRef(){ThgCriticalSectioncs(CShellExt::GetCriticalSection());return++m_cRef;}STDMETHODIMP_(ULONG)CShellExtCMenu::Release(){ThgCriticalSectioncs(CShellExt::GetCriticalSection());if(--m_cRef)returnm_cRef;deletethis;return0L;}STDMETHODIMPCShellExtCMenu::QueryInterface(REFIIDriid,LPVOIDFAR*ppv){if(ppv==0)returnE_POINTER;*ppv=NULL;if(IsEqualIID(riid,IID_IShellExtInit)||IsEqualIID(riid,IID_IUnknown)){*ppv=(LPSHELLEXTINIT)this;}elseif(IsEqualIID(riid,IID_IContextMenu)){*ppv=(LPCONTEXTMENU)this;}elseif(IsEqualIID(riid,IID_IContextMenu2)){*ppv=(IContextMenu2*)this;}elseif(IsEqualIID(riid,IID_IContextMenu3)){*ppv=(IContextMenu3*)this;}if(*ppv){AddRef();returnS_OK;}returnE_NOINTERFACE;}
Attach a Trello Card
Add a tag
Your session has expired
You are no longer logged in. Please log in and try your request again.
Filter RSS Feed
This RSS feed URL allows you to see the contents of your current filter using any feed reader.
This link includes a special authentication token. If you share the URL with anyone else, they can see this RSS feed's activity. You can disable these tokens when needed.
Your current filter is unsaved; changing it won't affect this RSS feed.