|
29 | 29 | import re as _re |
30 | 30 | import shutil as _shutil |
31 | 31 | import stat |
| 32 | +from ctypes import byref, c_wchar_p, c_void_p, POINTER, Structure, windll, \ |
| 33 | + wintypes |
| 34 | +from uuid import UUID |
32 | 35 |
|
33 | 36 | from .bolt import GPath, deprint, Path, decode, struct_unpack |
34 | 37 | from .exception import BoltError, CancelError, SkipError, AccessDeniedError, \ |
@@ -124,21 +127,21 @@ def clear_read_only(filepath): # copied from bolt |
124 | 127 |
|
125 | 128 | def get_personal_path(): |
126 | 129 | if shell and shellcon: |
127 | | - path = _getShellPath(shellcon.CSIDL_PERSONAL) |
128 | | - sErrorInfo = _(u"Folder path extracted from win32com.shell.") |
| 130 | + personal_path = get_known_path(FOLDERID.Documents) |
| 131 | + error_info = _(u'Folder path retrieved via SHGetKnownFolderPath') |
129 | 132 | else: |
130 | | - path = _getShellPath('Personal') |
131 | | - sErrorInfo = __get_error_info() |
132 | | - return GPath(path), sErrorInfo |
| 133 | + personal_path = _getShellPath('Personal') |
| 134 | + error_info = __get_error_info() |
| 135 | + return GPath(personal_path), error_info |
133 | 136 |
|
134 | 137 | def get_local_app_data_path(): |
135 | 138 | if shell and shellcon: |
136 | | - path = _getShellPath(shellcon.CSIDL_LOCAL_APPDATA) |
137 | | - sErrorInfo = _(u"Folder path extracted from win32com.shell.") |
| 139 | + local_path = get_known_path(FOLDERID.LocalAppData) |
| 140 | + error_info = _(u'Folder path retrieved via SHGetKnownFolderPath') |
138 | 141 | else: |
139 | | - path = _getShellPath('Local AppData') |
140 | | - sErrorInfo = __get_error_info() |
141 | | - return GPath(path), sErrorInfo |
| 142 | + local_path = _getShellPath('Local AppData') |
| 143 | + error_info = __get_error_info() |
| 144 | + return GPath(local_path), error_info |
142 | 145 |
|
143 | 146 | def __get_error_info(): |
144 | 147 | try: |
@@ -768,3 +771,152 @@ def getJava(): |
768 | 771 | # So javaw.exe would actually be in Windows\SysWOW64 |
769 | 772 | java = win.join(u'syswow64', u'javaw.exe') |
770 | 773 | return java |
| 774 | + |
| 775 | +# TODO(inf) Maybe move to windows.py? Circular dependency though... |
| 776 | +# All code starting from the 'BEGIN MIT-LICENSED PART' comment and until the |
| 777 | +# 'END MIT-LICENSED PART' comment is based on |
| 778 | +# https://gist.github.com/mkropat/7550097 by Michael Kropat |
| 779 | +# Modifications made for py3 compatibility and to conform to our code style |
| 780 | +# BEGIN MIT-LICENSED PART ===================================================== |
| 781 | +# http://msdn.microsoft.com/en-us/library/windows/desktop/aa373931.aspx |
| 782 | +class GUID(Structure): |
| 783 | + _fields_ = [ |
| 784 | + ("Data1", wintypes.DWORD), |
| 785 | + ("Data2", wintypes.WORD), |
| 786 | + ("Data3", wintypes.WORD), |
| 787 | + ("Data4", wintypes.BYTE * 8) |
| 788 | + ] |
| 789 | + |
| 790 | + def __init__(self, uuid_): |
| 791 | + super(GUID, self).__init__() |
| 792 | + self.Data1, self.Data2, self.Data3, self.Data4[0], self.Data4[1], \ |
| 793 | + rest = uuid_.fields |
| 794 | + for i in range(2, 8): |
| 795 | + self.Data4[i] = rest>>(8 - i - 1)*8 & 0xff |
| 796 | + |
| 797 | +# http://msdn.microsoft.com/en-us/library/windows/desktop/dd378457.aspx |
| 798 | +class FOLDERID(object): |
| 799 | + AccountPictures = UUID('{008ca0b1-55b4-4c56-b8a8-4de4b299d3be}') |
| 800 | + AdminTools = UUID('{724EF170-A42D-4FEF-9F26-B60E846FBA4F}') |
| 801 | + ApplicationShortcuts = UUID('{A3918781-E5F2-4890-B3D9-A7E54332328C}') |
| 802 | + CameraRoll = UUID('{AB5FB87B-7CE2-4F83-915D-550846C9537B}') |
| 803 | + CDBurning = UUID('{9E52AB10-F80D-49DF-ACB8-4330F5687855}') |
| 804 | + CommonAdminTools = UUID('{D0384E7D-BAC3-4797-8F14-CBA229B392B5}') |
| 805 | + CommonOEMLinks = UUID('{C1BAE2D0-10DF-4334-BEDD-7AA20B227A9D}') |
| 806 | + CommonPrograms = UUID('{0139D44E-6AFE-49F2-8690-3DAFCAE6FFB8}') |
| 807 | + CommonStartMenu = UUID('{A4115719-D62E-491D-AA7C-E74B8BE3B067}') |
| 808 | + CommonStartup = UUID('{82A5EA35-D9CD-47C5-9629-E15D2F714E6E}') |
| 809 | + CommonTemplates = UUID('{B94237E7-57AC-4347-9151-B08C6C32D1F7}') |
| 810 | + Contacts = UUID('{56784854-C6CB-462b-8169-88E350ACB882}') |
| 811 | + Cookies = UUID('{2B0F765D-C0E9-4171-908E-08A611B84FF6}') |
| 812 | + Desktop = UUID('{B4BFCC3A-DB2C-424C-B029-7FE99A87C641}') |
| 813 | + DeviceMetadataStore = UUID('{5CE4A5E9-E4EB-479D-B89F-130C02886155}') |
| 814 | + Documents = UUID('{FDD39AD0-238F-46AF-ADB4-6C85480369C7}') |
| 815 | + DocumentsLibrary = UUID('{7B0DB17D-9CD2-4A93-9733-46CC89022E7C}') |
| 816 | + Downloads = UUID('{374DE290-123F-4565-9164-39C4925E467B}') |
| 817 | + Favorites = UUID('{1777F761-68AD-4D8A-87BD-30B759FA33DD}') |
| 818 | + Fonts = UUID('{FD228CB7-AE11-4AE3-864C-16F3910AB8FE}') |
| 819 | + GameTasks = UUID('{054FAE61-4DD8-4787-80B6-090220C4B700}') |
| 820 | + History = UUID('{D9DC8A3B-B784-432E-A781-5A1130A75963}') |
| 821 | + ImplicitAppShortcuts = UUID('{BCB5256F-79F6-4CEE-B725-DC34E402FD46}') |
| 822 | + InternetCache = UUID('{352481E8-33BE-4251-BA85-6007CAEDCF9D}') |
| 823 | + Libraries = UUID('{1B3EA5DC-B587-4786-B4EF-BD1DC332AEAE}') |
| 824 | + Links = UUID('{bfb9d5e0-c6a9-404c-b2b2-ae6db6af4968}') |
| 825 | + LocalAppData = UUID('{F1B32785-6FBA-4FCF-9D55-7B8E7F157091}') |
| 826 | + LocalAppDataLow = UUID('{A520A1A4-1780-4FF6-BD18-167343C5AF16}') |
| 827 | + LocalizedResourcesDir = UUID('{2A00375E-224C-49DE-B8D1-440DF7EF3DDC}') |
| 828 | + Music = UUID('{4BD8D571-6D19-48D3-BE97-422220080E43}') |
| 829 | + MusicLibrary = UUID('{2112AB0A-C86A-4FFE-A368-0DE96E47012E}') |
| 830 | + NetHood = UUID('{C5ABBF53-E17F-4121-8900-86626FC2C973}') |
| 831 | + OriginalImages = UUID('{2C36C0AA-5812-4b87-BFD0-4CD0DFB19B39}') |
| 832 | + PhotoAlbums = UUID('{69D2CF90-FC33-4FB7-9A0C-EBB0F0FCB43C}') |
| 833 | + PicturesLibrary = UUID('{A990AE9F-A03B-4E80-94BC-9912D7504104}') |
| 834 | + Pictures = UUID('{33E28130-4E1E-4676-835A-98395C3BC3BB}') |
| 835 | + Playlists = UUID('{DE92C1C7-837F-4F69-A3BB-86E631204A23}') |
| 836 | + PrintHood = UUID('{9274BD8D-CFD1-41C3-B35E-B13F55A758F4}') |
| 837 | + Profile = UUID('{5E6C858F-0E22-4760-9AFE-EA3317B67173}') |
| 838 | + ProgramData = UUID('{62AB5D82-FDC1-4DC3-A9DD-070D1D495D97}') |
| 839 | + ProgramFiles = UUID('{905e63b6-c1bf-494e-b29c-65b732d3d21a}') |
| 840 | + ProgramFilesX64 = UUID('{6D809377-6AF0-444b-8957-A3773F02200E}') |
| 841 | + ProgramFilesX86 = UUID('{7C5A40EF-A0FB-4BFC-874A-C0F2E0B9FA8E}') |
| 842 | + ProgramFilesCommon = UUID('{F7F1ED05-9F6D-47A2-AAAE-29D317C6F066}') |
| 843 | + ProgramFilesCommonX64 = UUID('{6365D5A7-0F0D-45E5-87F6-0DA56B6A4F7D}') |
| 844 | + ProgramFilesCommonX86 = UUID('{DE974D24-D9C6-4D3E-BF91-F4455120B917}') |
| 845 | + Programs = UUID('{A77F5D77-2E2B-44C3-A6A2-ABA601054A51}') |
| 846 | + Public = UUID('{DFDF76A2-C82A-4D63-906A-5644AC457385}') |
| 847 | + PublicDesktop = UUID('{C4AA340D-F20F-4863-AFEF-F87EF2E6BA25}') |
| 848 | + PublicDocuments = UUID('{ED4824AF-DCE4-45A8-81E2-FC7965083634}') |
| 849 | + PublicDownloads = UUID('{3D644C9B-1FB8-4f30-9B45-F670235F79C0}') |
| 850 | + PublicGameTasks = UUID('{DEBF2536-E1A8-4c59-B6A2-414586476AEA}') |
| 851 | + PublicLibraries = UUID('{48DAF80B-E6CF-4F4E-B800-0E69D84EE384}') |
| 852 | + PublicMusic = UUID('{3214FAB5-9757-4298-BB61-92A9DEAA44FF}') |
| 853 | + PublicPictures = UUID('{B6EBFB86-6907-413C-9AF7-4FC2ABF07CC5}') |
| 854 | + PublicRingtones = UUID('{E555AB60-153B-4D17-9F04-A5FE99FC15EC}') |
| 855 | + PublicUserTiles = UUID('{0482af6c-08f1-4c34-8c90-e17ec98b1e17}') |
| 856 | + PublicVideos = UUID('{2400183A-6185-49FB-A2D8-4A392A602BA3}') |
| 857 | + QuickLaunch = UUID('{52a4f021-7b75-48a9-9f6b-4b87a210bc8f}') |
| 858 | + Recent = UUID('{AE50C081-EBD2-438A-8655-8A092E34987A}') |
| 859 | + RecordedTVLibrary = UUID('{1A6FDBA2-F42D-4358-A798-B74D745926C5}') |
| 860 | + ResourceDir = UUID('{8AD10C31-2ADB-4296-A8F7-E4701232C972}') |
| 861 | + Ringtones = UUID('{C870044B-F49E-4126-A9C3-B52A1FF411E8}') |
| 862 | + RoamingAppData = UUID('{3EB685DB-65F9-4CF6-A03A-E3EF65729F3D}') |
| 863 | + RoamedTileImages = UUID('{AAA8D5A5-F1D6-4259-BAA8-78E7EF60835E}') |
| 864 | + RoamingTiles = UUID('{00BCFC5A-ED94-4e48-96A1-3F6217F21990}') |
| 865 | + SampleMusic = UUID('{B250C668-F57D-4EE1-A63C-290EE7D1AA1F}') |
| 866 | + SamplePictures = UUID('{C4900540-2379-4C75-844B-64E6FAF8716B}') |
| 867 | + SamplePlaylists = UUID('{15CA69B3-30EE-49C1-ACE1-6B5EC372AFB5}') |
| 868 | + SampleVideos = UUID('{859EAD94-2E85-48AD-A71A-0969CB56A6CD}') |
| 869 | + SavedGames = UUID('{4C5C32FF-BB9D-43b0-B5B4-2D72E54EAAA4}') |
| 870 | + SavedSearches = UUID('{7d1d3a04-debb-4115-95cf-2f29da2920da}') |
| 871 | + Screenshots = UUID('{b7bede81-df94-4682-a7d8-57a52620b86f}') |
| 872 | + SearchHistory = UUID('{0D4C3DB6-03A3-462F-A0E6-08924C41B5D4}') |
| 873 | + SearchTemplates = UUID('{7E636BFE-DFA9-4D5E-B456-D7B39851D8A9}') |
| 874 | + SendTo = UUID('{8983036C-27C0-404B-8F08-102D10DCFD74}') |
| 875 | + SidebarDefaultParts = UUID('{7B396E54-9EC5-4300-BE0A-2482EBAE1A26}') |
| 876 | + SidebarParts = UUID('{A75D362E-50FC-4fb7-AC2C-A8BEAA314493}') |
| 877 | + SkyDrive = UUID('{A52BBA46-E9E1-435f-B3D9-28DAA648C0F6}') |
| 878 | + SkyDriveCameraRoll = UUID('{767E6811-49CB-4273-87C2-20F355E1085B}') |
| 879 | + SkyDriveDocuments = UUID('{24D89E24-2F19-4534-9DDE-6A6671FBB8FE}') |
| 880 | + SkyDrivePictures = UUID('{339719B5-8C47-4894-94C2-D8F77ADD44A6}') |
| 881 | + StartMenu = UUID('{625B53C3-AB48-4EC1-BA1F-A1EF4146FC19}') |
| 882 | + Startup = UUID('{B97D20BB-F46A-4C97-BA10-5E3608430854}') |
| 883 | + System = UUID('{1AC14E77-02E7-4E5D-B744-2EB1AE5198B7}') |
| 884 | + SystemX86 = UUID('{D65231B0-B2F1-4857-A4CE-A8E7C6EA7D27}') |
| 885 | + Templates = UUID('{A63293E8-664E-48DB-A079-DF759E0509F7}') |
| 886 | + UserPinned = UUID('{9E3995AB-1F9C-4F13-B827-48B24B6C7174}') |
| 887 | + UserProfiles = UUID('{0762D272-C50A-4BB0-A382-697DCD729B80}') |
| 888 | + UserProgramFiles = UUID('{5CD7AEE2-2219-4A67-B85D-6C9CE15660CB}') |
| 889 | + UserProgramFilesCommon = UUID('{BCBD3057-CA5C-4622-B42D-BC56DB0AE516}') |
| 890 | + Videos = UUID('{18989B1D-99B5-455B-841C-AB7C74E4DDFC}') |
| 891 | + VideosLibrary = UUID('{491E922F-5643-4AF4-A7EB-4E7A138D8174}') |
| 892 | + Windows = UUID('{F38BF404-1D43-42F2-9305-67DE0B28FC23}') |
| 893 | + |
| 894 | +# http://msdn.microsoft.com/en-us/library/windows/desktop/bb762188.aspx |
| 895 | +class UserHandle(object): |
| 896 | + current = wintypes.HANDLE(0) |
| 897 | + common = wintypes.HANDLE(-1) |
| 898 | + |
| 899 | +# http://msdn.microsoft.com/en-us/library/windows/desktop/ms680722.aspx |
| 900 | +_CoTaskMemFree = windll.ole32.CoTaskMemFree |
| 901 | +_CoTaskMemFree.restype= None |
| 902 | +_CoTaskMemFree.argtypes = [c_void_p] |
| 903 | + |
| 904 | +# http://msdn.microsoft.com/en-us/library/windows/desktop/bb762188.aspx |
| 905 | +# http://web.archive.org/web/20111025090317/http://www.themacaque.com/?p=954 |
| 906 | +_SHGetKnownFolderPath = windll.shell32.SHGetKnownFolderPath |
| 907 | +_SHGetKnownFolderPath.argtypes = [ |
| 908 | + POINTER(GUID), wintypes.DWORD, wintypes.HANDLE, POINTER(c_wchar_p) |
| 909 | +] |
| 910 | + |
| 911 | +def get_known_path(known_folder_id, user_handle=UserHandle.current): |
| 912 | + kf_id = GUID(known_folder_id) |
| 913 | + pPath = c_wchar_p() |
| 914 | + S_OK = 0 |
| 915 | + if _SHGetKnownFolderPath(byref(kf_id), 0, user_handle, |
| 916 | + byref(pPath)) != S_OK: |
| 917 | + raise RuntimeError(u"Failed to retrieve known folder path '%r'" % |
| 918 | + known_folder_id) |
| 919 | + path = pPath.value |
| 920 | + _CoTaskMemFree(pPath) |
| 921 | + return path |
| 922 | +# END MIT-LICENSED PART ======================================================= |
0 commit comments