# -*- coding: UTF8 -*-"""winshell - convenience functions to access Windows shell functionalityCertain aspects of the Windows user interface are grouped byMicrosoft as Shell functions. These include the Desktop, shortcuticons, special folders(such as My Documents) and a few other things.These are mostly available via the shell module of the win32allextensions, but whenever I need to use them, I've forgotten thevarious constants and so on.Several of the shell items have two variants: personal and common,or User and All Users. These refer to systems with profiles in use:anything from NT upwards, and 9x with Profiles turned on. Whererelevant, the Personal/User version refers to that owned by thelogged-on user and visible only to that user; the Common/All Usersversion refers to that maintained by an Administrator and visibleto all users of the system.Copyright Tim Golden <winshell@timgolden.me.uk> 25th November 2003 - 2012Licensed under the(GPL-compatible) MIT License:http://www.opensource.org/licenses/mit-license.php"""__VERSION__='0.6.4'importos,sysimportdatetimeimporttempfileimportwin32confromwin32comimportstorageconfromwin32com.shellimportshell,shellconimportwin32apiimportwin32clipboardimportwin32timezoneimportpythoncomimportpywintypes## version compaibility workaround#try:basestringexceptNameError:basestring=strtry:unicodeexceptNameError:unicode=str## Constants & calculated types#_desktop_folder=shell.SHGetDesktopFolder()PyIShellFolder=type(_desktop_folder)## Exceptions#classx_winshell(Exception):passclassx_recycle_bin(x_winshell):passclassx_not_found_in_recycle_bin(x_recycle_bin):pass## Stolen from winsys#defwrapped(fn,*args,**kwargs):returnfn(*args,**kwargs)classUnset(object):passUNSET=Unset()defindented(text,level,indent=2):"""Take a multiline text and indent it as a block"""return"\n".join("%s%s"%(level*indent*" ",s)forsintext.splitlines())defdumped(text,level,indent=2):"""Put curly brackets round an indented text"""returnindented("{\n%s\n}"%indented(text,level+1,indent)or"None",level,indent)+"\n"defdumped_list(l,level,indent=2):returndumped("\n".join(unicode(i)foriinl),level,indent)defdumped_dict(d,level,indent=2):returndumped("\n".join("%s => %r"%(k,v)for(k,v)ind.items()),level,indent)defdumped_flags(f,lookups,level,indent=2):returndumped("\n".join(lookups.names_from_value(f))or"None",level,indent)defdatetime_from_pytime(pytime):ifisinstance(pytime,datetime.datetime):returnpytimeelse:returndatetime.datetime.fromtimestamp(int(pytime))## Given a namespace(eg a module) and a pattern(eg "FMTID_%s")# allow a value from within that space to be specified by name# or by value.#deffrom_constants(namespace,pattern,factory):pattern=pattern.lower()def_from_constants(value):try:returnfactory(value)except(ValueError,TypeError):fornameindir(namespace):ifname.lower()==pattern%value.lower():returngetattr(namespace,name)classWinshellObject(object):def__str__(self):returnself.as_string()def__repr__(self):return"<%s: %s>"%(self.__class__.__name__,self)defas_string(self):raiseNotImplementedErrordefdumped(self):raiseNotImplementedErrordefdump(self,level=0):sys.stdout.write(self.dumped(level=level))## This was originally a workaround when Win9x didn't implement SHGetFolderPath.# Now it's just a convenience which supplies the default parameters.#defget_path(folder_id):returnshell.SHGetFolderPath(0,folder_id,None,0)defget_folder_by_name(name):name=name.upper()ifnotname.startswith("CSIDL"):name="CSIDL_"+nametry:returnget_path(getattr(shellcon,name))exceptAttributeError:raisex_winshell("No such CSIDL constant %s"%name)deffolder(folder):ifisinstance(folder,int):returnget_path(folder)else:returnget_folder_by_name(unicode(folder))
[docs]defdesktop(common=0):"What folder is equivalent to the current desktop?"returnget_path((shellcon.CSIDL_DESKTOP,shellcon.CSIDL_COMMON_DESKTOPDIRECTORY)[common])
defcommon_desktop():## Only here because already used in code#returndesktop(common=1)
deffavourites(common=0):"What folder holds the Explorer favourites shortcuts?"returnget_path((shellcon.CSIDL_FAVORITES,shellcon.CSIDL_COMMON_FAVORITES)[common])bookmarks=favourites
[docs]defstart_menu(common=0):"What folder holds the Start Menu shortcuts?"returnget_path((shellcon.CSIDL_STARTMENU,shellcon.CSIDL_COMMON_STARTMENU)[common])
[docs]defprograms(common=0):"What folder holds the Programs shortcuts(from the Start Menu)?"returnget_path((shellcon.CSIDL_PROGRAMS,shellcon.CSIDL_COMMON_PROGRAMS)[common])
[docs]defstartup(common=0):"What folder holds the Startup shortcuts(from the Start Menu)?"returnget_path((shellcon.CSIDL_STARTUP,shellcon.CSIDL_COMMON_STARTUP)[common])
defpersonal_folder():"What folder holds the My Documents files?"returnget_path(shellcon.CSIDL_PERSONAL)my_documents=personal_folder
[docs]defrecent():"What folder holds the Documents shortcuts(from the Start Menu)?"returnget_path(shellcon.CSIDL_RECENT)
[docs]defsendto():"What folder holds the SendTo shortcuts(from the Context Menu)?"returnget_path(shellcon.CSIDL_SENDTO)
## Internally abstracted function to handle one of several shell-based file manipulation# routines. Not all the possible parameters are covered which might be passed to the# underlying SHFileOperation API call, but only those which seemed useful to me at# the time.#def_file_operation(operation,source_path,target_path=None,allow_undo=True,no_confirm=False,rename_on_collision=True,silent=False,extra_flags=0,hWnd=None):flags=extra_flags## At present the Python wrapper around SHFileOperation doesn't# allow lists of files. Hopefully it will at some point, so# take account of it here.# If you pass this shell function a "/"-separated path with# a wildcard, eg c:/temp/*.tmp, it gets confused. It's ok# with a backslash, so convert here.#source_path=source_pathor""ifisinstance(source_path,basestring):source_path=os.path.abspath(source_path)else:source_path="\0".join(os.path.abspath(i)foriinsource_path)target_path=target_pathor""ifisinstance(target_path,basestring):target_path=os.path.abspath(target_path)else:target_path="\0".join(os.path.abspath(i)foriintarget_path)flags|=shellcon.FOF_MULTIDESTFILESflags|=shellcon.FOF_WANTMAPPINGHANDLEifallow_undo:flags|=shellcon.FOF_ALLOWUNDOifno_confirm:flags|=shellcon.FOF_NOCONFIRMATIONifrename_on_collision:flags|=shellcon.FOF_RENAMEONCOLLISIONifsilent:flags|=shellcon.FOF_SILENTflags|=extra_flagsresult,n_aborted,mapping=shell.SHFileOperation((hWndor0,operation,source_path,target_path,flags,None,None))ifresult!=0:raisex_winshell(result)elifn_aborted:raisex_winshell("%d operations were aborted by the user"%n_aborted)returndict(mapping)defcopy_file(source_path,target_path,allow_undo=True,no_confirm=False,rename_on_collision=True,silent=False,extra_flags=0,hWnd=None):"""Perform a shell-based file copy. Copying in this way allows the possibility of undo, auto-renaming, and showing the "flying file" animation during the copy. The default options allow for undo, don't automatically clobber on a name clash, automatically rename on collision and display the animation. """return_file_operation(shellcon.FO_COPY,source_path,target_path,allow_undo,no_confirm,rename_on_collision,silent,extra_flags,hWnd)defmove_file(source_path,target_path,allow_undo=True,no_confirm=False,rename_on_collision=True,silent=False,extra_flags=0,hWnd=None):"""Perform a shell-based file move. Moving in this way allows the possibility of undo, auto-renaming, and showing the "flying file" animation during the copy. The default options allow for undo, don't automatically clobber on a name clash, automatically rename on collision and display the animation. """return_file_operation(shellcon.FO_MOVE,source_path,target_path,allow_undo,no_confirm,rename_on_collision,silent,extra_flags,hWnd)defrename_file(source_path,target_path,allow_undo=True,no_confirm=False,rename_on_collision=True,silent=False,extra_flags=0,hWnd=None):"""Perform a shell-based file rename. Renaming in this way allows the possibility of undo, auto-renaming, and showing the "flying file" animation during the copy. The default options allow for undo, don't automatically clobber on a name clash, automatically rename on collision and display the animation. """return_file_operation(shellcon.FO_RENAME,source_path,target_path,allow_undo,no_confirm,rename_on_collision,silent,extra_flags,hWnd)defdelete_file(source_path,allow_undo=True,no_confirm=False,silent=False,extra_flags=0,hWnd=None):"""Perform a shell-based file delete. Deleting in this way uses the system recycle bin, allows the possibility of undo, and showing the "flying file" animation during the delete. The default options allow for undo, don't automatically clobber on a name clash and display the animation. """return_file_operation(shellcon.FO_DELETE,source_path,None,allow_undo,no_confirm,False,silent,extra_flags,hWnd)classShortcut(WinshellObject):show_states={"normal":win32con.SW_SHOWNORMAL,"max":win32con.SW_SHOWMAXIMIZED,"min":win32con.SW_SHOWMINNOACTIVE}def__init__(self,lnk_filepath=None,**kwargs):self._shell_link=wrapped(pythoncom.CoCreateInstance,shell.CLSID_ShellLink,None,pythoncom.CLSCTX_INPROC_SERVER,shell.IID_IShellLink)self.lnk_filepath=lnk_filepathifself.lnk_filepathandos.path.exists(self.lnk_filepath):wrapped(self._shell_link.QueryInterface,pythoncom.IID_IPersistFile).Load(self.lnk_filepath)fork,vinkwargs.items():setattr(self,k,v)defas_string(self):return"%s -> %s"%(self.lnk_filepathor"-unsaved-",self.pathor"-no-target-")defdumped(self,level=0):output=[]output.append(self.as_string())output.append("")forattribute,valueinsorted(vars(self.__class__).items()):ifnotattribute.startswith("_")andisinstance(value,property):output.append("%s: %s"%(attribute,getattr(self,attribute)))returndumped("\n".join(output),level)@classmethoddeffrom_lnk(cls,lnk_filepath):returncls(lnk_filepath)@classmethoddeffrom_target(cls,target_filepath,lnk_filepath=UNSET,**kwargs):target_filepath=os.path.abspath(target_filepath)iflnk_filepathisUNSET:lnk_filepath=os.path.join(os.getcwd(),os.path.basename(target_filepath)+".lnk")returncls(lnk_filepath,path=target_filepath,**kwargs)def__enter__(self):returnselfdef__exit__(self,exc_type,exc_val,exc_tb):ifexc_typeisNone:self.write()def_get_arguments(self):returnself._shell_link.GetArguments()def_set_arguments(self,arguments):self._shell_link.SetArguments(arguments)arguments=property(_get_arguments,_set_arguments)def_get_description(self):returnself._shell_link.GetDescription()def_set_description(self,description):self._shell_link.SetDescription(description)description=property(_get_description,_set_description)def_get_hotkey(self):returnself._shell_link.GetHotkey()def_set_hotkey(self,hotkey):self._shell_link.SetHotkey(hotkey)hotkey=property(_get_hotkey,_set_hotkey)def_get_icon_location(self):path,index=self._shell_link.GetIconLocation()returnpath,indexdef_set_icon_location(self,icon_location):self._shell_link.SetIconLocation(*icon_location)icon_location=property(_get_icon_location,_set_icon_location)def_get_path(self):lnk_filepath,data=self._shell_link.GetPath(shell.SLGP_UNCPRIORITY)returnlnk_filepathdef_set_path(self,path):self._shell_link.SetPath(path)path=property(_get_path,_set_path)def_get_show_cmd(self):show_cmd=self._shell_link.GetShowCmd()fork,vinself.show_states.items():ifv==show_cmd:returnkelse:returnNonedef_set_show_cmd(self,show_cmd):try:show_cmd=int(show_cmd)exceptValueError:show_cmd=self.show_states[show_cmd]self._shell_link.SetShowCmd(show_cmd)show_cmd=property(_get_show_cmd,_set_show_cmd)def_get_working_directory(self):returnself._shell_link.GetWorkingDirectory()def_set_working_directory(self,working_directory):self._shell_link.SetWorkingDirectory(working_directory)working_directory=property(_get_working_directory,_set_working_directory)defwrite(self,lnk_filepath=None):ifnotlnk_filepath:lnk_filepath=self.lnk_filepathiflnk_filepathisNone:raisex_shell(errmsg="Must specify a lnk_filepath for an unsaved shortcut")ipersistfile=wrapped(self._shell_link.QueryInterface,pythoncom.IID_IPersistFile).Save(lnk_filepath,lnk_filepath==self.lnk_filepath)self.lnk_filepath=lnk_filepathreturnselfdefshortcut(source=UNSET):ifsourceisNone:returnNoneelifsourceisUNSET:returnShortcut()elifisinstance(source,Shortcut):returnsourceelifsource.endswith(".lnk"):returnShortcut.from_lnk(source)else:returnShortcut.from_target(source)## Constants for structured storage## These come from ObjIdl.hFMTID_USER_DEFINED_PROPERTIES="{F29F85E0-4FF9-1068-AB91-08002B27B3D9}"FMTID_CUSTOM_DEFINED_PROPERTIES="{D5CDD505-2E9C-101B-9397-08002B2CF9AE}"PIDSI_TITLE=0x00000002PIDSI_SUBJECT=0x00000003PIDSI_AUTHOR=0x00000004PIDSI_CREATE_DTM=0x0000000cPIDSI_KEYWORDS=0x00000005PIDSI_COMMENTS=0x00000006PIDSI_TEMPLATE=0x00000007PIDSI_LASTAUTHOR=0x00000008PIDSI_REVNUMBER=0x00000009PIDSI_EDITTIME=0x0000000aPIDSI_LASTPRINTED=0x0000000bPIDSI_LASTSAVE_DTM=0x0000000dPIDSI_PAGECOUNT=0x0000000ePIDSI_WORDCOUNT=0x0000000fPIDSI_CHARCOUNT=0x00000010PIDSI_THUMBNAIL=0x00000011PIDSI_APPNAME=0x00000012PROPERTIES=(PIDSI_TITLE,PIDSI_SUBJECT,PIDSI_AUTHOR,PIDSI_CREATE_DTM,PIDSI_KEYWORDS,PIDSI_COMMENTS,PIDSI_TEMPLATE,PIDSI_LASTAUTHOR,PIDSI_EDITTIME,PIDSI_LASTPRINTED,PIDSI_LASTSAVE_DTM,PIDSI_PAGECOUNT,PIDSI_WORDCOUNT,PIDSI_CHARCOUNT,PIDSI_APPNAME)## This was taken from someone else's example, but I can't find where.# If you know, please tell me so I can give due credit.#defstructured_storage(filename):"""Pick out info from MS documents with embedded structured storage(typically MS Word docs etc.) Returns a dictionary of information found """ifnotpythoncom.StgIsStorageFile(filename):return{}flags=storagecon.STGM_READ|storagecon.STGM_SHARE_EXCLUSIVEstorage=pythoncom.StgOpenStorage(filename,None,flags)try:properties_storage=storage.QueryInterface(pythoncom.IID_IPropertySetStorage)exceptpythoncom.com_error:return{}property_sheet=properties_storage.Open(FMTID_USER_DEFINED_PROPERTIES)try:data=property_sheet.ReadMultiple(PROPERTIES)finally:property_sheet=Nonetitle,subject,author,created_on,keywords,comments,template_used, \
updated_by,edited_on,printed_on,saved_on, \
n_pages,n_words,n_characters, \
application=dataresult={}iftitle:result['title']=titleifsubject:result['subject']=subjectifauthor:result['author']=authorifcreated_on:result['created_on']=created_onifkeywords:result['keywords']=keywordsifcomments:result['comments']=commentsiftemplate_used:result['template_used']=template_usedifupdated_by:result['updated_by']=updated_byifedited_on:result['edited_on']=edited_onifprinted_on:result['printed_on']=printed_onifsaved_on:result['saved_on']=saved_onifn_pages:result['n_pages']=n_pagesifn_words:result['n_words']=n_wordsifn_characters:result['n_characters']=n_charactersifapplication:result['application']=applicationreturnresultclassShellItem(WinshellObject):def__init__(self,parent,rpidl):## parent is a PyIShellFolder object(or something similar)# rpidl is a PyIDL object(basically: a list of SHITEMs)#assertparentisNoneorisinstance(parent,ShellFolder),"parent is %r"%parentself.parent=parentself.rpidl=rpidlifparentisNone:self.pidl=[]else:self.pidl=self.parent.pidl+[rpidl]@classmethoddeffrom_pidl(cls,pidl,parent_obj=None):ifparent_objisNone:## pidl is absolute#parent_obj=_desktop.BindToObject(pidl[:-1],None,shell.IID_IShellFolder)rpidl=pidl[-1:]else:## pidl is relative#rpidl=pidlreturncls(parent_obj,rpidl)@classmethoddeffrom_path(cls,path):_,pidl,flags=_desktop.ParseDisplayName(0,None,path,shellcon.SFGAO_FOLDER)ifflags&shellcon.SFGAO_FOLDER:returnShellFolder.from_pidl(pidl)else:returnShellItem.from_pidl(pidl)def_ifolder2(self):returnself.parent._folder.QueryInterface(shell.IID_IShellFolder2)def_ifolder2(self):returnself.parent._folder.QueryInterface(shell.IID_IShellFolder2)defas_string(self):returnself.filename()defdumped(self,level=0):output=[]output.append(self.as_string())output.append("")output.append(dumped_list(self.attributes(),level))returndumped("\n".join(output),level)defattributes(self):prefix="SFGAO_"results=set()all_attributes=self.parent._folder.GetAttributesOf([self.rpidl],-1)forattrindir(shellcon):ifattr.startswith(prefix):ifall_attributes&getattr(shellcon,attr):results.add(attr[len(prefix):].lower())returnresultsdefattribute(self,attributes):try:attribute=int(attributes)exceptValueError:attribute=getattr(shellcon,"SFGAO_"+attributes.upper())exceptTypeError:attribute=0forainattributes:try:attribute=attribute|aexceptTypeError:attribute=attribute|getattr(shellcon,"SFGAO_"+a.upper())returnbool(self.parent._folder.GetAttributesOf([self.rpidl],attribute)&attribute)defdetails(self,fmtid_name):returndict((pid_name,self.detail(fmtid_name,pid_name))forpid_nameinDETAILS[fmtid_name])defdetail(self,fmtid,pid):try:fmtid=pywintypes.IID(fmtid)exceptpywintypes.com_error:fmtid=_fmtids[fmtid]try:pid=int(pid)except(ValueError,TypeError):pid=_pids[pid]ifself.parent:folder=self.parent._folderelse:folder=self._folderfolder2=folder.QueryInterface(shell.IID_IShellFolder2)returnfolder2.GetDetailsEx(self.rpidl,(fmtid,pid))deffilename(self):returnself.name(shellcon.SHGDN_FORPARSING)defname(self,type=shellcon.SHGDN_NORMAL):returnself.parent._folder.GetDisplayNameOf(self.rpidl,type)defstat(self):stream=self.parent._folder.BindToStorage(self.rpidl,None,pythoncom.IID_IStream)returnmake_storage_stat(stream.Stat())defdetails(self,fmtid_name):returndict((pid_name,self.detail(fmtid_name,pid_name))forpid_nameinDETAILS[fmtid_name])defdetail(self,fmtid,pid):try:fmtid=pywintypes.IID(fmtid)exceptpywintypes.com_error:fmtid=_fmtid_from_name(fmtid)try:pid=int(pid)except(ValueError,TypeError):pid=_pid_from_name(pid)ifself.parent:folder=self.parent._folderelse:folder=self._folderfolder2=folder.QueryInterface(shell.IID_IShellFolder2)returnfolder2.GetDetailsEx(self.rpidl,(fmtid,pid))classShellFolder(ShellItem):def__init__(self,parent,rpidl):ShellItem.__init__(self,parent,rpidl)ifparent:self._folder=self.parent._folder.BindToObject(self.rpidl,None,shell.IID_IShellFolder)else:self._folder=Nonedef__getitem__(self,item):returnself.get_child(item)deffolders(self,flags=0):enum=self._folder.EnumObjects(0,flags|shellcon.SHCONTF_FOLDERS)ifenum:whileTrue:pidls=enum.Next(1)ifpidls:forpidlinpidls:yieldself.folder_factory(pidl)else:breakdefitems(self,flags=0):enum=self._folder.EnumObjects(0,flags|shellcon.SHCONTF_NONFOLDERS)ifenum:whileTrue:rpidls=enum.Next(1)ifrpidls:forrpidlinrpidls:yieldself.item_factory(rpidl)else:breakdefenumerate(self,flags=0):forfolderinself.folders(flags):yieldfolderforiteminself.items(flags):yielditem__iter__=enumeratedefwalk(self,flags=0):folders=list(self.folders(flags))items=list(self.items(flags))yieldself,folders,itemsforfolderinfolders:forresultinfolder.walk(flags):yieldresultdeffolder_factory(self,rpidl):returnShellFolder(self,rpidl)defitem_factory(self,rpidl):returnShellItem(self,rpidl)defget_child(self,name,hWnd=None):n_eaten,rpidl,attributes=self._folder.ParseDisplayName(hWnd,None,name,shellcon.SFGAO_FOLDER)ifattributes&shellcon.SFGAO_FOLDER:returnself.folder_factory(rpidl)else:returnself.item_factory(rpidl)classShellRecycledItem(ShellItem):PID_DISPLACED_FROM=2# Location that file was deleted from.PID_DISPLACED_DATE=3# Date that the file was deleted.defas_string(self):return"%s recycled at %s"%(self.original_filename(),self.recycle_date())deforiginal_filename(self):returnos.path.join(self.detail(shell.FMTID_Displaced,self.PID_DISPLACED_FROM),self.name(shellcon.SHGDN_INFOLDER))defrecycle_date(self):returndatetime_from_pytime(self.detail(shell.FMTID_Displaced,self.PID_DISPLACED_DATE))defreal_filename(self):returnself.parent._folder.GetDisplayNameOf(self.rpidl,shellcon.SHGDN_FORPARSING)defundelete(self):original_filename=self.original_filename()tempdir=tempfile.mkdtemp()try:temp_filepath=os.path.join(tempdir,os.path.basename(original_filename))## Move the undelete file into a working directory, ensuring that# the original filename is retained, regardless of the temporary# filename used in the Recycle Bin. Then move that file into the# original directory, allowing rename on collision. This ensures# that the final, possiby renamed, filename will be related to# the original name and not to the temporary recycled name.#move_file(self.real_filename(),temp_filepath,allow_undo=False,no_confirm=True,rename_on_collision=True,silent=True)remapping=move_file(temp_filepath,original_filename,allow_undo=False,no_confirm=True,rename_on_collision=True,silent=False)fork,vinremapping.items():ifk.lower()==original_filename.lower():returnvelse:returnoriginal_filenamefinally:delete_file(tempdir,allow_undo=False,no_confirm=True,silent=True)defcontents(self,buffer_size=8192):istream=self.parent._folder.BindToStorage(self.rpidl,None,pythoncom.IID_IStream)whileTrue:contents=istream.Read(buffer_size)ifcontents:yieldcontentselse:breakclassShellRecycleBin(ShellFolder):"""Wrap the shell object which represents the union of all the recycle bins on this system. """def__init__(self):ShellFolder.__init__(self,ShellDesktop(),shell.SHGetSpecialFolderLocation(0,shellcon.CSIDL_BITBUCKET))def__len__(self):_,n_items=shell.SHQueryRecycleBin(None)returnn_itemsdefget_size(self):size,_=shell.SHQueryRecycleBin(None)returnsizedefitem_factory(self,rpidl):returnShellRecycledItem(self,rpidl)folder_factory=item_factory@staticmethoddefempty(confirm=True,show_progress=True,sound=True):flags=0ifnotconfirm:flags|=shellcon.SHERB_NOCONFIRMATIONifnotshow_progress:flags|=shellcon.SHERB_NOPROGRESSUIifnotsound:flags|=shellcon.SHERB_NOSOUNDshell.SHEmptyRecycleBin(None,None,flags)defundelete(self,original_filepath):"""Restore the most recent version of a filepath, returning the filepath it was restored to(as rename-on-collision will apply if a file already exists at that path). """candidates=self.versions(original_filepath)ifnotcandidates:raisex_not_found_in_recycle_bin("%s not found in the Recycle Bin"%original_filepath)## NB Can't use max(key=...) until Python 2.6+#newest=sorted(candidates,key=lambdaentry:entry.recycle_date())[-1]returnnewest.undelete()defversions(self,original_filepath):original_filepath=original_filepath.lower()return[entryforentryinselfifentry.original_filename().lower()==original_filepath]defrecycle_bin():"""Return an object representing all the recycle bins on the system. """returnShellRecycleBin()defundelete(filepath):returnrecycle_bin().undelete(filepath)classShellDesktop(ShellFolder):def__init__(self):ShellFolder.__init__(self,None,[])self._folder=_desktop_folderdefname(self,type=shellcon.SHGDN_NORMAL):returnself._folder.GetDisplayNameOf(self.rpidl,type)defshell_object(shell_object=UNSET):ifshell_objectisNone:returnNoneelifshell_objectisUNSET:returnShellDesktop()elifisinstance(shell_object,ShellItem):returnshell_objectelse:returnShellDesktop().get_child(shell_object)classClipboard(object):def__init__(self,hWnd=None):self.hWnd=hWndself._is_owned=Falsedef__enter__(self):self.open()returnselfdef__exit__(self,exc_type,exc_val,exc_tb):self.close()def__getitem__(self,item):self._check_ownership()returnwin32clipboard.GetClipboardData(self._to_format(item))def__setitem__(self,item,value):self._check_ownership()win32clipboard.SetClipboardData(self._to_format(item),value)def__iter__(self):self._check_ownership()forformatinself._enum_formats():yieldformat,self[format]@staticmethoddef_to_format(item):ifisinstance(item,basestring):try:returngetattr(win32clipboard,item.upper())exceptAttributeError:returngetattr(win32clipboard,"CF_%s"%item.upper())else:returnitemdef_check_ownership(self):ifnotself._is_owned:raiseRuntimeError("Unable to access clipboard without owning it")def_enum_formats(self):self._check_ownership()format=0whileTrue:format=win32clipboard.EnumClipboardFormats(format)ifformat==0:breakyieldformatdefopen(self):win32clipboard.OpenClipboard(self.hWnd)self._is_owned=Truedefclose(self):self._is_owned=Falsewin32clipboard.CloseClipboard()defclear(self):self._check_ownership()win32clipboard.EmptyClipboard()defformats(self):returnself._enum_formats()defformat_name(self,format):forattrindir(win32clipboard):ifattr.startswith("CF_")andgetattr(win32clipboard,attr)==format:returnattrelse:returnwin32clipboard.GetClipboardFormatName(format)defset_text(self,utext):self._check_ownership()self["unicodetext"]=unicode(utext)self["text"]=unicode(utext).encode("mbcs")defget_text(self,format="unicodetext"):returnself[format]def_text_from_clipboard(self):self.open()try:returnself.get_text()finally:self.close()def_text_to_clipboard(self,utext):self.open()try:returnself.set_text(utext)finally:self.close()text=property(_text_from_clipboard,_text_to_clipboard)clipboard=Clipboard()## Legacy functions, retained for backwards compatibility#defCreateShortcut(Path,Target,Arguments="",StartIn="",Icon=("",0),Description=""):"""Create a Windows shortcut: Path - As what file should the shortcut be created? Target - What command should the desktop use? Arguments - What arguments should be supplied to the command? StartIn - What folder should the command start in? Icon -(filename, index) What icon should be used for the shortcut? Description - What description should the shortcut be given? eg CreateShortcut( Path=os.path.join(desktop(), "PythonI.lnk"), Target=r"c:\python\python.exe", Icon=(r"c:\python\python.exe", 0), Description="Python Interpreter" ) """lnk=shortcut(Target)lnk.arguments=Argumentslnk.working_directory=StartInlnk.icon_location=Iconlnk.description=Descriptionlnk.write(Path)if__name__=='__main__':try:raw_inputexceptNameError:raw_input=inputtry:print('Desktop =>',desktop())print('Common Desktop =>',desktop(1))print('Application Data =>',application_data())print('Common Application Data =>',application_data(1))print('Bookmarks =>',bookmarks())print('Common Bookmarks =>',bookmarks(1))print('Start Menu =>',start_menu())print('Common Start Menu =>',start_menu(1))print('Programs =>',programs())print('Common Programs =>',programs(1))print('Startup =>',startup())print('Common Startup =>',startup(1))print('My Documents =>',my_documents())print('Recent =>',recent())print('SendTo =>',sendto())finally:raw_input("Press enter...")