mirror of
				https://github.com/noDRM/DeDRM_tools.git
				synced 2025-10-23 23:07:47 -04:00 
			
		
		
		
	
		
			
				
	
	
		
			211 lines
		
	
	
	
		
			6.3 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			211 lines
		
	
	
	
		
			6.3 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| #!/usr/bin/env python
 | |
| # -*- coding: utf-8 -*-
 | |
| # vim:ts=4:sw=4:softtabstop=4:smarttab:expandtab
 | |
| 
 | |
| # to work around tk_chooseDirectory not properly returning unicode paths on Windows
 | |
| # need to use a dialog that can be hacked up to actually return full unicode paths
 | |
| # originally based on AskFolder from EasyDialogs for Windows but modified to fix it
 | |
| # to actually use unicode for path
 | |
| 
 | |
| # The original license for EasyDialogs is as follows
 | |
| #
 | |
| # Copyright (c) 2003-2005 Jimmy Retzlaff
 | |
| #
 | |
| # Permission is hereby granted, free of charge, to any person obtaining a
 | |
| # copy of this software and associated documentation files (the "Software"),
 | |
| # to deal in the Software without restriction, including without limitation
 | |
| # the rights to use, copy, modify, merge, publish, distribute, sublicense,
 | |
| # and/or sell copies of the Software, and to permit persons to whom the
 | |
| # Software is furnished to do so, subject to the following conditions:
 | |
| # 
 | |
| # The above copyright notice and this permission notice shall be included in
 | |
| # all copies or substantial portions of the Software.
 | |
| # 
 | |
| # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | |
| # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | |
| # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 | |
| # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | |
| # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 | |
| # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 | |
| # DEALINGS IN THE SOFTWARE.
 | |
| 
 | |
| """
 | |
| AskFolder(...) -- Ask the user to select a folder Windows specific
 | |
| """
 | |
| 
 | |
| import os
 | |
| 
 | |
| import ctypes
 | |
| from ctypes import POINTER, byref, cdll, c_int, windll
 | |
| from ctypes.wintypes import LPCWSTR, LPWSTR
 | |
| import ctypes.wintypes as wintypes
 | |
| 
 | |
| 
 | |
| __all__ = ['AskFolder']
 | |
| 
 | |
| # Load required Windows DLLs
 | |
| ole32 = ctypes.windll.ole32
 | |
| shell32 = ctypes.windll.shell32
 | |
| user32 = ctypes.windll.user32
 | |
| 
 | |
| 
 | |
| # Windows Constants
 | |
| BFFM_INITIALIZED = 1
 | |
| BFFM_SETOKTEXT = 1129
 | |
| BFFM_SETSELECTIONA = 1126
 | |
| BFFM_SETSELECTIONW = 1127
 | |
| BIF_EDITBOX = 16
 | |
| BS_DEFPUSHBUTTON = 1
 | |
| CB_ADDSTRING = 323
 | |
| CB_GETCURSEL = 327
 | |
| CB_SETCURSEL = 334
 | |
| CDM_SETCONTROLTEXT = 1128
 | |
| EM_GETLINECOUNT = 186
 | |
| EM_GETMARGINS = 212
 | |
| EM_POSFROMCHAR = 214
 | |
| EM_SETSEL = 177
 | |
| GWL_STYLE = -16
 | |
| IDC_STATIC = -1
 | |
| IDCANCEL = 2
 | |
| IDNO = 7
 | |
| IDOK = 1
 | |
| IDYES = 6
 | |
| MAX_PATH = 260
 | |
| OFN_ALLOWMULTISELECT = 512
 | |
| OFN_ENABLEHOOK = 32
 | |
| OFN_ENABLESIZING = 8388608
 | |
| OFN_ENABLETEMPLATEHANDLE = 128
 | |
| OFN_EXPLORER = 524288
 | |
| OFN_OVERWRITEPROMPT = 2
 | |
| OPENFILENAME_SIZE_VERSION_400 = 76
 | |
| PBM_GETPOS = 1032
 | |
| PBM_SETMARQUEE = 1034
 | |
| PBM_SETPOS = 1026
 | |
| PBM_SETRANGE = 1025
 | |
| PBM_SETRANGE32 = 1030
 | |
| PBS_MARQUEE = 8
 | |
| PM_REMOVE = 1
 | |
| SW_HIDE = 0
 | |
| SW_SHOW = 5
 | |
| SW_SHOWNORMAL = 1
 | |
| SWP_NOACTIVATE = 16
 | |
| SWP_NOMOVE = 2
 | |
| SWP_NOSIZE = 1
 | |
| SWP_NOZORDER = 4
 | |
| VER_PLATFORM_WIN32_NT = 2
 | |
| WM_COMMAND = 273
 | |
| WM_GETTEXT = 13
 | |
| WM_GETTEXTLENGTH = 14
 | |
| WM_INITDIALOG = 272
 | |
| WM_NOTIFY = 78
 | |
| 
 | |
| # Windows function prototypes
 | |
| BrowseCallbackProc = ctypes.WINFUNCTYPE(ctypes.c_int, wintypes.HWND, ctypes.c_uint, wintypes.LPARAM, wintypes.LPARAM)
 | |
| 
 | |
| # Windows types
 | |
| LPCTSTR = ctypes.c_char_p
 | |
| LPTSTR = ctypes.c_char_p
 | |
| LPVOID = ctypes.c_voidp
 | |
| TCHAR = ctypes.c_char
 | |
| 
 | |
| class BROWSEINFO(ctypes.Structure):
 | |
|     _fields_ = [
 | |
|                 ("hwndOwner", wintypes.HWND),
 | |
|                 ("pidlRoot", LPVOID),
 | |
|                 ("pszDisplayName", LPTSTR),
 | |
|                 ("lpszTitle", LPCTSTR),
 | |
|                 ("ulFlags", ctypes.c_uint),
 | |
|                 ("lpfn", BrowseCallbackProc),
 | |
|                 ("lParam", wintypes.LPARAM),
 | |
|                 ("iImage", ctypes.c_int)
 | |
|                ]
 | |
| 
 | |
| 
 | |
| # Utilities
 | |
| def CenterWindow(hwnd):
 | |
|     desktopRect = GetWindowRect(user32.GetDesktopWindow())
 | |
|     myRect = GetWindowRect(hwnd)
 | |
|     x = width(desktopRect) // 2 - width(myRect) // 2
 | |
|     y = height(desktopRect) // 2 - height(myRect) // 2
 | |
|     user32.SetWindowPos(hwnd, 0,
 | |
|                         desktopRect.left + x,
 | |
|                         desktopRect.top + y,
 | |
|                         0, 0,
 | |
|                         SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER
 | |
|                        )
 | |
| 
 | |
| 
 | |
| def GetWindowRect(hwnd):
 | |
|     rect = wintypes.RECT()
 | |
|     user32.GetWindowRect(hwnd, ctypes.byref(rect))
 | |
|     return rect
 | |
| 
 | |
| def width(rect):
 | |
|     return rect.right-rect.left
 | |
| 
 | |
| def height(rect):
 | |
|     return rect.bottom-rect.top
 | |
| 
 | |
| 
 | |
| def AskFolder(
 | |
|         message=None,
 | |
|         version=None,
 | |
|         defaultLocation=None,
 | |
|         location=None,
 | |
|         windowTitle=None,
 | |
|         actionButtonLabel=None,
 | |
|         cancelButtonLabel=None,
 | |
|         multiple=None):
 | |
|     """Display a dialog asking the user for select a folder.
 | |
|        modified to use unicode strings as much as possible
 | |
|        returns unicode path
 | |
|     """
 | |
| 
 | |
|     def BrowseCallback(hwnd, uMsg, lParam, lpData):
 | |
|         if uMsg == BFFM_INITIALIZED:
 | |
|             if actionButtonLabel:
 | |
|                 label = unicode(actionButtonLabel, errors='replace')
 | |
|                 user32.SendMessageW(hwnd, BFFM_SETOKTEXT, 0, label)
 | |
|             if cancelButtonLabel:
 | |
|                 label = unicode(cancelButtonLabel, errors='replace')
 | |
|                 cancelButton = user32.GetDlgItem(hwnd, IDCANCEL)
 | |
|                 if cancelButton:
 | |
|                     user32.SetWindowTextW(cancelButton, label)
 | |
|             if windowTitle:
 | |
|                 title = unicode(windowTitle, erros='replace')
 | |
|                 user32.SetWindowTextW(hwnd, title)
 | |
|             if defaultLocation:
 | |
|                 user32.SendMessageW(hwnd, BFFM_SETSELECTIONW, 1, defaultLocation.replace('/', '\\'))
 | |
|             if location:
 | |
|                 x, y = location
 | |
|                 desktopRect = wintypes.RECT()
 | |
|                 user32.GetWindowRect(0, ctypes.byref(desktopRect))
 | |
|                 user32.SetWindowPos(hwnd, 0,
 | |
|                                   desktopRect.left + x,
 | |
|                                   desktopRect.top + y, 0, 0,
 | |
|                                   SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER)
 | |
|             else:
 | |
|                 CenterWindow(hwnd)
 | |
|         return 0
 | |
| 
 | |
|     # This next line is needed to prevent gc of the callback
 | |
|     callback = BrowseCallbackProc(BrowseCallback)
 | |
| 
 | |
|     browseInfo = BROWSEINFO()
 | |
|     browseInfo.pszDisplayName = ctypes.c_char_p('\0' * (MAX_PATH+1))
 | |
|     browseInfo.lpszTitle = message
 | |
|     browseInfo.lpfn = callback
 | |
| 
 | |
|     pidl = shell32.SHBrowseForFolder(ctypes.byref(browseInfo))
 | |
|     if not pidl:
 | |
|         result = None
 | |
|     else:
 | |
|         path = LPCWSTR(u" " * (MAX_PATH+1))
 | |
|         shell32.SHGetPathFromIDListW(pidl, path)
 | |
|         ole32.CoTaskMemFree(pidl)
 | |
|         result = path.value
 | |
|     return result
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | 
