[python-win32] Help with IPropertyStorage and IPropertySetStorage
COM Interfaces
Christopher Ramos
christopher.ramos7 at verizon.net
Mon Jun 16 23:38:26 EDT 2003
Hello,
Does anyone have any experience with the IPropertyStorage and
IPropertySetStorage COM interfaces from Python? I am trying to write a
Python script to set custom defined properties on a Microsoft Word document
and I am having some problems.
Using some sample code from Hammond & Robinson's "Python Programming on
Win32", a little help from Google, and some poking with a sharp stick I have
been able to get my script to read both the user defined properties and
custom properties from a Microsoft Word document. My script can even
programmatically change existing and create new custom properties that can
be read back using the same script.
The problem is that the custom properties do not show up in the Custom
properties tab on the Word document and are not accessible as document
properties inside the document. If I change the value of an existing custom
property that I created via the custom properties UI in Word it disappears
from the list of custom properties. Interestingly enough, if I try to define
that custom property again in Word the Add button changes to Modify.
At this point I suspect that my problem is that my Custom Properties are
getting stored in Unicode when the U.S. English version of Word wants them
to be in ANSI. This is just a guess based on some debugging code that I put
in my script.
I could be doing a number of other things wrong as well. I am no COM expert.
Anyone got any ideas?
------------------------------------------
Details:
Here is the output from my pilfered script.
E:\script>e:\Python22\python dump2.py foo.doc
udp= ((None, 4, 30),)
(property id)4 = d
udp= ((None, 6, 30),)
(property id)6 = d
udp= ((None, 5, 30),)
(property id)5 = d
udp= ((None, 3, 30),)
(property id)3 = d
udp= ((None, 2, 30),)
(property id)2 = d
cdp = ((u'CustomProperty1', 2, 30),) property_value = ('CustomValue1',)
(property_name)CustomProperty1 = CustomValue1
cdp = ((u'CustomProperty2', 3, 30),) property_value = ('CustomValue2',)
(property_name)CustomProperty2 = CustomValue2
cdp = ((u'CustomProperty3', 4, 30),) property_value = ('CustomValue3',)
(property_name)CustomProperty3 = CustomValue3
cdp = ((u'CustomProperty4', 5, 8),) property_value = (u'CustomValue4',)
(property_name)CustomProperty4 = CustomValue4
I ran it on a word doc with three custom properties defined via Word. They
are CustomProperty1, CustomProperty2, CustomProperty3. The script defines
CustomProperty4.
Here is the output of my script. I believe that the 8 and the 30 refer to
type information. The PROPVARIANT's VARTYPE? Here are the values I am
guessing that these correspond to.
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/stg/stg/pro
pvariant.asp
VT_BSTR 8 bstrVal
Pointer to a null-terminated Unicode string. The string is
immediately preceded by a DWORD
representing the byte count, but bstrVal points past this DWORD to
the first character of the
string. BSTRs must be allocated and freed using the Automation
SysAllocString and SysFreeString calls.
VT_LPSTR 30 pszVal
Pointer to a null-terminated ANSI string in the system default code
page.
Here is the script.
-----
import pythoncom
from win32com import storagecon
FMTID_UserDefinedProperties = "{F29F85E0-4FF9-1068-AB91-08002B27B3D9}"
FMTID_CustomDefinedProperties = "{D5CDD505-2E9C-101B-9397-08002B2CF9AE}"
def read_custom_properties(filename):
if not pythoncom.StgIsStorageFile(filename):
print "the file is not a storage file!"
return
flags = storagecon.STGM_READWRITE | storagecon.STGM_SHARE_EXCLUSIVE
stg = pythoncom.StgOpenStorage(filename, None, flags)
try:
property_set_storage =
stg.QueryInterface(pythoncom.IID_IPropertySetStorage)
except pythoncom.com_error:
print "No summary information os available"
return
user_defined_property_set =
property_set_storage.Open(FMTID_UserDefinedProperties,flags)
custom_defined_property_set =
property_set_storage.Open(FMTID_CustomDefinedProperties,flags)
udps_enum = user_defined_property_set.Enum()
cdps_enum = custom_defined_property_set.Enum()
udp = udps_enum.Next(1)
while udp:
print 'udp=',udp
property_name = udp[0]
property_value =
user_defined_property_set.ReadMultiple((property_name[1],))
if property_name[0] == None:
print "(property id)%s = %s" % (property_name[1],
property_value[0])
else:
print "(property_name)%s = %s" % (property_name[0],
property_value[0])
udp = udps_enum.Next(1)
print
cdp = cdps_enum.Next(1)
while cdp:
property_name = cdp[0]
property_value =
custom_defined_property_set.ReadMultiple((property_name[1],))
print 'cdp = ', cdp, 'property_value = ',property_value
if property_name[0] == None:
print "(property id)%s = %s" % (property_name[1],
property_value[0])
else:
print "(property_name)%s = %s" % (property_name[0],
property_value[0])
cdp = cdps_enum.Next(1)
print
return
def write_custom_properties(filename):
if not pythoncom.StgIsStorageFile(filename):
print "the file is not a storage file!"
return
flags = storagecon.STGM_READWRITE | storagecon.STGM_SHARE_EXCLUSIVE
stg = pythoncom.StgOpenStorage(filename, None, flags)
try:
property_set_storage =
stg.QueryInterface(pythoncom.IID_IPropertySetStorage)
except pythoncom.com_error:
print "No summary information os available"
return
custom_defined_property_set =
property_set_storage.Open(FMTID_CustomDefinedProperties,flags)
names = ('CustomProperty4',)
values = ('CustomValue4',)
custom_defined_property_set.WriteMultiple(names,values)
## This commit is just here as a hack
custom_defined_property_set.Commit(0x8)
return
if __name__ == '__main__':
import sys
if len(sys.argv) < 2:
print "Please specify a filename"
else:
write_custom_properties(sys.argv[1])
read_custom_properties(sys.argv[1])
More information about the Python-win32
mailing list