import datetime import os import struct import sys import pythoncom import pywintypes import win32com.test.util import win32con import win32timezone from win32com.shell import shell from win32com.shell.shellcon import * from win32com.storagecon import * class ShellTester(win32com.test.util.TestCase): def testShellLink(self): desktop = str(shell.SHGetSpecialFolderPath(0, CSIDL_DESKTOP)) num = 0 shellLink = pythoncom.CoCreateInstance( shell.CLSID_ShellLink, None, pythoncom.CLSCTX_INPROC_SERVER, shell.IID_IShellLink, ) persistFile = shellLink.QueryInterface(pythoncom.IID_IPersistFile) names = [os.path.join(desktop, n) for n in os.listdir(desktop)] programs = str(shell.SHGetSpecialFolderPath(0, CSIDL_PROGRAMS)) names.extend([os.path.join(programs, n) for n in os.listdir(programs)]) for name in names: try: persistFile.Load(name, STGM_READ) except pythoncom.com_error: continue # Resolve is slow - avoid it for our tests. # shellLink.Resolve(0, shell.SLR_ANY_MATCH | shell.SLR_NO_UI) fname, findData = shellLink.GetPath(0) unc = shellLink.GetPath(shell.SLGP_UNCPRIORITY)[0] num += 1 if num == 0: # This isn't a fatal error, but is unlikely. print( "Could not find any links on your desktop or programs dir, which is unusual" ) def testShellFolder(self): sf = shell.SHGetDesktopFolder() names_1 = [] for i in sf: # Magically calls EnumObjects name = sf.GetDisplayNameOf(i, SHGDN_NORMAL) names_1.append(name) # And get the enumerator manually enum = sf.EnumObjects( 0, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS | SHCONTF_INCLUDEHIDDEN ) names_2 = [] for i in enum: name = sf.GetDisplayNameOf(i, SHGDN_NORMAL) names_2.append(name) names_1.sort() names_2.sort() self.assertEqual(names_1, names_2) class PIDLTester(win32com.test.util.TestCase): def _rtPIDL(self, pidl): pidl_str = shell.PIDLAsString(pidl) pidl_rt = shell.StringAsPIDL(pidl_str) self.assertEqual(pidl_rt, pidl) pidl_str_rt = shell.PIDLAsString(pidl_rt) self.assertEqual(pidl_str_rt, pidl_str) def _rtCIDA(self, parent, kids): cida = parent, kids cida_str = shell.CIDAAsString(cida) cida_rt = shell.StringAsCIDA(cida_str) self.assertEqual(cida, cida_rt) cida_str_rt = shell.CIDAAsString(cida_rt) self.assertEqual(cida_str_rt, cida_str) def testPIDL(self): # A PIDL of "\1" is: cb + pidl + cb expect = b"\03\00" + b"\1" + b"\0\0" self.assertEqual(shell.PIDLAsString([b"\1"]), expect) self._rtPIDL([b"\0"]) self._rtPIDL([b"\1", b"\2", b"\3"]) self._rtPIDL([b"\0" * 2048] * 2048) # PIDL must be a list self.assertRaises(TypeError, shell.PIDLAsString, "foo") def testCIDA(self): self._rtCIDA([b"\0"], [[b"\0"]]) self._rtCIDA([b"\1"], [[b"\2"]]) self._rtCIDA([b"\0"], [[b"\0"], [b"\1"], [b"\2"]]) def testBadShortPIDL(self): # A too-short child element: cb + pidl + cb pidl = b"\01\00" + b"\1" self.assertRaises(ValueError, shell.StringAsPIDL, pidl) # ack - tried to test too long PIDLs, but a len of 0xFFFF may not # always fail. class FILEGROUPDESCRIPTORTester(win32com.test.util.TestCase): def _getTestTimes(self): if issubclass(pywintypes.TimeType, datetime.datetime): ctime = win32timezone.now() # FILETIME only has ms precision... ctime = ctime.replace(microsecond=ctime.microsecond // 1000 * 1000) atime = ctime + datetime.timedelta(seconds=1) wtime = atime + datetime.timedelta(seconds=1) else: ctime = pywintypes.Time(11) atime = pywintypes.Time(12) wtime = pywintypes.Time(13) return ctime, atime, wtime def _testRT(self, fd): fgd_string = shell.FILEGROUPDESCRIPTORAsString([fd]) fd2 = shell.StringAsFILEGROUPDESCRIPTOR(fgd_string)[0] fd = fd.copy() fd2 = fd2.copy() # The returned objects *always* have dwFlags and cFileName. if "dwFlags" not in fd: del fd2["dwFlags"] if "cFileName" not in fd: self.assertEqual(fd2["cFileName"], "") del fd2["cFileName"] self.assertEqual(fd, fd2) def _testSimple(self, make_unicode): fgd = shell.FILEGROUPDESCRIPTORAsString([], make_unicode) header = struct.pack("i", 0) self.assertEqual(header, fgd[: len(header)]) self._testRT({}) d = {} fgd = shell.FILEGROUPDESCRIPTORAsString([d], make_unicode) header = struct.pack("i", 1) self.assertEqual(header, fgd[: len(header)]) self._testRT(d) def testSimpleBytes(self): self._testSimple(False) def testSimpleUnicode(self): self._testSimple(True) def testComplex(self): clsid = pywintypes.IID("{CD637886-DB8B-4b04-98B5-25731E1495BE}") ctime, atime, wtime = self._getTestTimes() d = { "cFileName": "foo.txt", "clsid": clsid, "sizel": (1, 2), "pointl": (3, 4), "dwFileAttributes": win32con.FILE_ATTRIBUTE_NORMAL, "ftCreationTime": ctime, "ftLastAccessTime": atime, "ftLastWriteTime": wtime, "nFileSize": sys.maxsize + 1, } self._testRT(d) def testUnicode(self): # exercise a bug fixed in build 210 - multiple unicode objects failed. ctime, atime, wtime = self._getTestTimes() d = [ { "cFileName": "foo.txt", "sizel": (1, 2), "pointl": (3, 4), "dwFileAttributes": win32con.FILE_ATTRIBUTE_NORMAL, "ftCreationTime": ctime, "ftLastAccessTime": atime, "ftLastWriteTime": wtime, "nFileSize": sys.maxsize + 1, }, { "cFileName": "foo2.txt", "sizel": (1, 2), "pointl": (3, 4), "dwFileAttributes": win32con.FILE_ATTRIBUTE_NORMAL, "ftCreationTime": ctime, "ftLastAccessTime": atime, "ftLastWriteTime": wtime, "nFileSize": sys.maxsize + 1, }, { "cFileName": "foo\xa9.txt", "sizel": (1, 2), "pointl": (3, 4), "dwFileAttributes": win32con.FILE_ATTRIBUTE_NORMAL, "ftCreationTime": ctime, "ftLastAccessTime": atime, "ftLastWriteTime": wtime, "nFileSize": sys.maxsize + 1, }, ] s = shell.FILEGROUPDESCRIPTORAsString(d, 1) d2 = shell.StringAsFILEGROUPDESCRIPTOR(s) # clobber 'dwFlags' - they are not expected to be identical for t in d2: del t["dwFlags"] self.assertEqual(d, d2) class FileOperationTester(win32com.test.util.TestCase): def setUp(self): import tempfile self.src_name = os.path.join(tempfile.gettempdir(), "pywin32_testshell") self.dest_name = os.path.join(tempfile.gettempdir(), "pywin32_testshell_dest") self.test_data = b"Hello from\0Python" f = open(self.src_name, "wb") f.write(self.test_data) f.close() try: os.unlink(self.dest_name) except OSError: pass def tearDown(self): for fname in (self.src_name, self.dest_name): if os.path.isfile(fname): os.unlink(fname) def testCopy(self): s = (0, FO_COPY, self.src_name, self.dest_name) # hwnd, # operation rc, aborted = shell.SHFileOperation(s) self.assertTrue(not aborted) self.assertEqual(0, rc) self.assertTrue(os.path.isfile(self.src_name)) self.assertTrue(os.path.isfile(self.dest_name)) def testRename(self): s = (0, FO_RENAME, self.src_name, self.dest_name) # hwnd, # operation rc, aborted = shell.SHFileOperation(s) self.assertTrue(not aborted) self.assertEqual(0, rc) self.assertTrue(os.path.isfile(self.dest_name)) self.assertTrue(not os.path.isfile(self.src_name)) def testMove(self): s = (0, FO_MOVE, self.src_name, self.dest_name) # hwnd, # operation rc, aborted = shell.SHFileOperation(s) self.assertTrue(not aborted) self.assertEqual(0, rc) self.assertTrue(os.path.isfile(self.dest_name)) self.assertTrue(not os.path.isfile(self.src_name)) def testDelete(self): s = ( 0, # hwnd, FO_DELETE, # operation self.src_name, None, FOF_NOCONFIRMATION, ) rc, aborted = shell.SHFileOperation(s) self.assertTrue(not aborted) self.assertEqual(0, rc) self.assertTrue(not os.path.isfile(self.src_name)) if __name__ == "__main__": win32com.test.util.testmain()