add skeleton for variant type support
[pywinlite.git] / storage.py
blobe07f13cb359657175981d1a802ec4c14e9544704
1 #Copyright (c) 2009 Vincent Povirk
3 #Permission is hereby granted, free of charge, to any person
4 #obtaining a copy of this software and associated documentation
5 #files (the "Software"), to deal in the Software without
6 #restriction, including without limitation the rights to use,
7 #copy, modify, merge, publish, distribute, sublicense, and/or sell
8 #copies of the Software, and to permit persons to whom the
9 #Software is furnished to do so, subject to the following
10 #conditions:
12 #The above copyright notice and this permission notice shall be
13 #included in all copies or substantial portions of the Software.
15 #THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 #EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17 #OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 #NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19 #HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20 #WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 #FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 #OTHER DEALINGS IN THE SOFTWARE.
24 # structured storage
26 from ctypes import POINTER, windll, c_void_p, Structure, byref, cast, create_string_buffer, c_uint32, Union, addressof
27 from winlitecfg import get_aw_symbols
28 from windef import HRESULT, DWORD, LPCWSTR, LPVOID, GUID, LPCOLESTR, ULONG, PULONG, LPOLESTR, ULARGE_INTEGER, FILETIME, CLSID, S_OK, REFCLSID, LARGE_INTEGER, UINT, USHORT, REFIID, LPCTSTR, FMTID, REFFMTID, WORD, LPSTR, LONG
29 from winliteutils import get_symbols
30 from winlitecom import IUnknown
32 class SNB(object):
33 @classmethod
34 def from_param(cls, arg):
35 if arg == None:
36 return c_void_p(0)
37 else:
38 # TODO
39 raise NotImplemented
41 try:
42 _bytes = bytes
43 except NameError:
44 _bytes = str
46 class ISequentialStream(IUnknown):
47 com_methods = [('Read', HRESULT, LPVOID, ULONG, PULONG),
48 #RemoteRead = Read
49 ('Write', HRESULT, LPVOID, ULONG, PULONG),
50 #RemoteWrite = Write
53 iid = GUID("0c733a30-2a1c-11ce-ade5-00aa0044773d")
55 def read(self, size=None):
56 if size:
57 result = create_string_buffer(size)
58 bytesread = ULONG()
59 self.Read(cast(result, LPVOID), size, byref(bytesread))
60 return result.raw[0:bytesread.value]
61 else:
62 blocks = []
63 result = create_string_buffer(1024)
64 bytesread = ULONG(1024)
65 while bytesread.value == 1024:
66 self.Read(cast(result, LPVOID), 1024, byref(bytesread))
67 block = result.raw[0:bytesread.value]
68 blocks.append(block)
69 return _bytes().join(blocks)
71 STGTY_STORAGE = 1
72 STGTY_STREAM = 2
73 STGTY_LOCKBYTES = 3
74 STGTY_PROPERTY = 4
76 class STATSTG(Structure):
77 _fields_ = [('pwcsName', LPOLESTR),
78 ('type', DWORD),
79 ('cbSize', ULARGE_INTEGER),
80 ('mtime', FILETIME),
81 ('ctime', FILETIME),
82 ('atime', FILETIME),
83 ('grfMode', DWORD),
84 ('grfLocksSupported', DWORD),
85 ('clsid', CLSID),
86 ('grfStateBits', DWORD),
87 ('reserved', DWORD),
90 owns_name = False
92 def __del__(self):
93 if self.owns_name:
94 _ole32.CoTaskMemFree(cast(self.pwcsName, c_void_p))
95 self.owns_name = False
97 STREAM_SEEK_SET = 0
98 STREAM_SEEK_CUR = 1
99 STREAM_SEEK_END = 2
101 class IStream(ISequentialStream):
102 iid = GUID("0000000c-0000-0000-C000-000000000046")
104 def stat(self, mode):
105 result = STATSTG()
106 self.Stat(byref(result), mode)
107 result.owns_name = True
108 return result
110 def seek(self, offset, origin):
111 result = ULARGE_INTEGER()
112 self.Seek(offset, origin, byref(result))
113 return result.value
115 IStream.set_methods([('Seek', HRESULT, LARGE_INTEGER, DWORD, POINTER(ULARGE_INTEGER)),
116 #RemoteSeek = Seek
117 ('SetSize', HRESULT, ULARGE_INTEGER),
118 ('CopyTo', HRESULT, IStream, ULARGE_INTEGER, ULARGE_INTEGER, ULARGE_INTEGER),
119 #RemoteCopyTo = CopyTo
120 ('Commit', HRESULT, DWORD),
121 ('Revert', HRESULT),
122 ('LockRegion', HRESULT, ULARGE_INTEGER, ULARGE_INTEGER, DWORD),
123 ('UnlockRegion', HRESULT, ULARGE_INTEGER, ULARGE_INTEGER, DWORD),
124 ('Stat', HRESULT, POINTER(STATSTG), DWORD),
125 ('Clone', HRESULT, IStream.outparam),
128 LPSTREAM = IStream
130 class IEnumSTATSTG(IUnknown):
131 iid = GUID("0000000d-0000-0000-C000-000000000046")
133 def __iter__(self):
134 return self
136 def __next__(self):
137 result = STATSTG()
138 numreturned = ULONG()
139 if self.Next(1, byref(result), byref(numreturned)) == S_OK and numreturned.value == 1:
140 result.owns_name = True
141 return result
142 else:
143 raise StopIteration
145 next = __next__
148 IEnumSTATSTG.set_methods([('Next', HRESULT, ULONG, POINTER(STATSTG), POINTER(ULONG)),
149 ('Skip', HRESULT, ULONG),
150 ('Reset', HRESULT),
151 ('Clone', HRESULT, IEnumSTATSTG.outparam),
154 STATFLAG_DEFAULT = 0
155 STATFLAG_NONAME = 1
156 STATFLAG_NOOPEN = 2
158 class IStorage(IUnknown):
159 iid = GUID("0000000b-0000-0000-C000-000000000046")
161 def __iter__(self):
162 result = IEnumSTATSTG.outparam()
163 self.EnumElements(0, None, 0, result)
164 return iter(result.get())
166 def stat(self, mode):
167 result = STATSTG()
168 self.Stat(byref(result), mode)
169 result.owns_name = True
170 return result
172 def open_storage(self, name, mode):
173 result = IStorage.outparam()
174 self.OpenStorage(name, None, mode, None, 0, result)
175 return result.get()
177 def open_stream(self, name, mode):
178 result = IStream.outparam()
179 self.OpenStream(name, None, mode, 0, result)
180 return result.get()
182 def create_stream(self, name, mode):
183 result = IStream.outparam()
184 self.CreateStream(name, mode, 0, 0, result)
185 return result.get()
187 IStorage.set_methods([('CreateStream', HRESULT, LPCOLESTR, DWORD, DWORD, DWORD, IStream.outparam),
188 ('OpenStream', HRESULT, LPCOLESTR, LPVOID, DWORD, DWORD, IStream.outparam),
189 #RemoteOpenStream = OpenStream
190 ('CreateStorage', HRESULT, LPCOLESTR, DWORD, DWORD, DWORD, IStorage.outparam),
191 ('OpenStorage', HRESULT, LPCOLESTR, IStorage, DWORD, SNB, DWORD, IStorage.outparam),
192 ('CopyTo', HRESULT, DWORD, POINTER(GUID), SNB, IStorage),
193 ('MoveElementTo', HRESULT, LPCOLESTR, IStorage, LPCOLESTR, DWORD),
194 ('Commit', HRESULT, DWORD),
195 ('Revert', HRESULT),
196 ('EnumElements', HRESULT, DWORD, LPVOID, DWORD, IEnumSTATSTG.outparam),
197 #RemoteEnumElements = EnumElements
198 ('DestroyElement', HRESULT, LPCOLESTR),
199 ('RenameElement', HRESULT, LPCOLESTR, LPCOLESTR),
200 ('SetElementTimes', HRESULT, LPCOLESTR, POINTER(FILETIME), POINTER(FILETIME), POINTER(FILETIME)),
201 ('SetClass', HRESULT, REFCLSID),
202 ('SetStateBits', HRESULT, DWORD, DWORD),
203 ('Stat', HRESULT, POINTER(STATSTG), DWORD),
206 STGM_DIRECT = 0x0
207 STGM_FAILIFTHERE = 0x0
208 STGM_READ = 0x0
209 STGM_WRITE = 0x1
210 STGM_READWRITE = 0x2
211 STGM_SHARE_EXCLUSIVE = 0x10
212 STGM_SHARE_DENY_WRITE = 0x20
213 STGM_SHARE_DENY_READ = 0x30
214 STGM_SHARE_DENY_NONE = 0x40
215 STGM_CREATE = 0x1000
216 STGM_TRANSACTED = 0x10000
217 STGM_CONVERT = 0x20000
218 STGM_PRIORITY = 0x40000
219 STGM_NOSCRATCH = 0x100000
220 STGM_NOSNAPSHOT = 0x200000
221 STGM_DIRECT_SWMR = 0x400000
222 STGM_DELETEONRELEASE = 0x4000000
223 STGM_SIMPLE = 0x8000000
225 STGFMT = UINT
226 STGFMT_STORAGE = 0
227 STGFMT_FILE = 3
228 STGFMT_ANY = 4
229 STGFMT_DOCFILE = 5
231 PROPID = ULONG
233 PRSPEC_INVALID = 0xffffffff
234 PRSPEC_LPWSTR = 0
235 PRSPEC_PROPID = 1
237 class PROPSPEC(Structure):
238 class U(Union):
239 _fields_ = [('propid', PROPID),
240 ('lpwstr', LPOLESTR),
242 _fields_ = [('ulKind', ULONG),
243 ('u', U),
246 VARTYPE = USHORT
248 VT_I4 = 3
249 VT_LPSTR = 30
250 VT_FILETIME = 64
252 def _get_propvar_i4(value):
253 return cast(addressof(value), POINTER(LONG)).contents.value
255 def _get_propvar_lpstr(value):
256 return cast(addressof(value), POINTER(LPSTR)).contents.value
258 def _get_propvar_filetime(value):
259 return cast(addressof(value), POINTER(FILETIME)).contents
261 _propvar_getters = {
262 VT_I4: _get_propvar_i4,
263 VT_LPSTR: _get_propvar_lpstr,
264 VT_FILETIME: _get_propvar_filetime,
267 class _PROPVAR_VALUE(Structure):
268 _fields_ = [('cElems', ULONG),
269 ('pElems', LPVOID),
272 class PROPVARIANT(Structure):
273 _fields_ = [('vt', VARTYPE),
274 ('wReserved1', WORD),
275 ('wReserved2', WORD),
276 ('wReserved3', WORD),
277 ('value', _PROPVAR_VALUE), # to avoid the huge union, cast a pointer to this field
280 def get_value(self):
281 try:
282 getter = _propvar_getters[self.vt]
283 except KeyError:
284 return None
285 else:
286 return getter(self.value)
288 class STATPROPSTG(Structure):
289 _fields_ = [('lpwstrName', LPOLESTR),
290 ('propid', PROPID),
291 ('vt', VARTYPE),
294 class IEnumSTATPROPSTG(IUnknown):
295 iid = GUID("00000139-0000-0000-C000-000000000046")
297 def __iter__(self):
298 return self
300 def __next__(self):
301 result = STATPROPSTG()
302 numfetched = ULONG()
303 if self.Next(1, byref(result), byref(numfetched)) == S_OK:
304 return result
305 else:
306 raise StopIteration
308 IEnumSTATPROPSTG.set_methods([('Next', HRESULT, ULONG, POINTER(STATPROPSTG), POINTER(ULONG)),
309 #RemoteNext = Next
310 ('Skip', HRESULT, ULONG),
311 ('Reset', HRESULT),
312 ('Clone', HRESULT, IEnumSTATPROPSTG.outparam),
315 class STATPROPSETSTG(Structure):
316 _fields_ = [('fmtid', FMTID),
317 ('clsid', CLSID),
318 ('grfFlags', DWORD),
319 ('mtime', FILETIME),
320 ('ctime', FILETIME),
321 ('atime', FILETIME),
322 ('dwOSVersion', DWORD),
325 class IPropertyStorage(IUnknown):
326 iid = GUID("00000138-0000-0000-C000-000000000046")
328 def __iter__(self):
329 result = IEnumSTATPROPSTG.outparam()
330 self.Enum(result)
331 return result.get()
333 def read_id(self, propid):
334 spec = PROPSPEC()
335 spec.ulKind = PRSPEC_PROPID
336 spec.u.propid = propid
337 result = PROPVARIANT()
338 self.ReadMultiple(1, byref(spec), byref(result))
339 return result
341 com_methods = [('ReadMultiple', HRESULT, ULONG, POINTER(PROPSPEC), POINTER(PROPVARIANT)),
342 ('WriteMultiple', HRESULT, ULONG, POINTER(PROPSPEC), POINTER(PROPVARIANT), PROPID),
343 ('DeleteMultiple', HRESULT, ULONG, POINTER(PROPSPEC)),
344 ('ReadPropertyNames', HRESULT, ULONG, POINTER(PROPID), POINTER(LPOLESTR)),
345 ('WritePropertyNames', HRESULT, ULONG, POINTER(PROPID), POINTER(LPOLESTR)),
346 ('DeletePropertyNames', HRESULT, ULONG, POINTER(PROPID)),
347 ('Commit', HRESULT, DWORD),
348 ('Revert', HRESULT),
349 ('Enum', HRESULT, IEnumSTATPROPSTG.outparam),
350 ('SetTimes', HRESULT, POINTER(FILETIME), POINTER(FILETIME), POINTER(FILETIME)),
351 ('SetClass', HRESULT, REFCLSID),
352 ('Stat', HRESULT, POINTER(STATPROPSETSTG)),
355 class IEnumSTATPROPSETSTG(IUnknown):
356 iid = GUID("0000013B-0000-0000-C000-000000000046")
358 def __iter__(self):
359 return self
361 def __next__(self):
362 result = STATPROPSETSTG()
363 numfetched = ULONG()
364 if self.Next(1, byref(result), byref(numfetched)) == S_OK:
365 return result
366 else:
367 raise StopIteration
369 next = __next__
371 IEnumSTATPROPSETSTG.set_methods([('Next', HRESULT, ULONG, POINTER(STATPROPSETSTG), POINTER(ULONG)),
372 #RemoteNext = Next
373 ('Skip', HRESULT, ULONG),
374 ('Reset', HRESULT),
375 ('Clone', HRESULT, IEnumSTATPROPSETSTG.outparam),
378 class IPropertySetStorage(IUnknown):
379 iid = GUID("0000013A-0000-0000-C000-000000000046")
381 def __iter__(self):
382 result = IEnumSTATPROPSETSTG.outparam()
383 self.Enum(result)
384 return result.get()
386 com_methods = [('Create', HRESULT, REFFMTID, POINTER(CLSID), DWORD, DWORD, IPropertyStorage.outparam),
387 ('Open', HRESULT, REFFMTID, DWORD, IPropertyStorage.outparam),
388 ('Delete', HRESULT, REFFMTID),
389 ('Enum', HRESULT, IEnumSTATPROPSETSTG.outparam),
392 class STGOPTIONS(Structure):
393 _fields_ = [('usVersion', USHORT),
394 ('reserved', USHORT),
395 ('ulSectorSize', ULONG),
396 ('pwcsTemplateFile', LPCWSTR),
399 _ole32 = windll.ole32
401 get_symbols(globals(), _ole32, ['ReadClassStg', 'StgCreateStorageEx', 'StgIsStorageFile', 'StgOpenStorage'])
403 ReadClassStg.restype = HRESULT
404 ReadClassStg.argtypes = [IStorage, POINTER(CLSID)]
406 StgCreateStorageEx.restype = HRESULT
407 StgCreateStorageEx.argtypes = [LPCWSTR, DWORD, STGFMT, DWORD, POINTER(STGOPTIONS), LPVOID, REFIID, POINTER(LPVOID)]
409 StgIsStorageFile.restype = HRESULT
410 StgIsStorageFile.argtypes = [LPCWSTR]
412 StgOpenStorage.restype = HRESULT
413 StgOpenStorage.argtypes = [LPCWSTR, IStorage, DWORD, SNB, DWORD, IStorage.outparam]
415 def is_storage_file(filename):
416 try:
417 return StgIsStorageFile(filename) == S_OK
418 except WindowsError:
419 return False
421 def open_storage(filename, mode):
422 result = IStorage.outparam()
423 StgOpenStorage(filename, None, mode, None, 0, result)
424 return result.get()
426 _shlwapi = windll.shlwapi
428 get_aw_symbols(globals(), _shlwapi, ['SHCreateStreamOnFile'])
430 SHCreateStreamOnFile.argtypes = [LPCTSTR, DWORD, IStream.outparam]
431 SHCreateStreamOnFile.restype = HRESULT
433 def file_stream(filename, mode):
434 result = IStream.outparam()
435 SHCreateStreamOnFile(filename, mode, result)
436 return result.get()