[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