11

The problem

I'm having some trouble setting document properties using VBA in Word 2010.

I have a document containing several Heading 1 sections and I use a macro to extract a selected section (along with it's contents) and paste it to a new document.

This part works fine, but at the end I need to set several document properties, but none of them are being set.

I'm trying to set both built-in and custom properties, but for the purpose of this question I'd like to set title, subject and, category.

I've created a function to set the properties I desire (as below), and VBA is throwing no error (even when I remove error handling in the function).

Does anybody know what I am doing wrong?


How the function should work

Here is a brief summary of what the function should do, but the full function is below should you find it easier to check that -

  1. Check to see if the property already exists
    • It does and it is a default property
      • Set the default property
      • Set the PropertyTypeUsed variable to default
    • it does and it is a custom property
      • Set the custom property
      • Set the PropertyTypeUsed variable to custom
    • It does not exist at all
      • Create a new custom property
      • Set the custom property
      • Set the PropertyTypeUsed variable to custom
  2. Check whether or not a value has successfully been set
    • A default property should have been set
      • Was the property set successfully?
    • A custom property should have been set
      • Was the property set successfully?
  3. Return the result

The function I believe is causing the issue

Function UpdateDocumentProperty(ByRef doc As Document, _
                                ByVal propertyName As String, _
                                ByVal propertyValue As Variant, _
                                Optional ByVal propertyType As Office.MsoDocProperties = 4)
                                
    '** Set the result to 'False' by default '*
    Dim result As Boolean
    result = False
    
    '** A property to hold whether or not the property used is default or custom *'
    Dim propertyTypeUsed As String

    '** Check to see if the document property already exists *'
    If PropertyExists(doc, propertyName) Then                           ' A default property exists, so use that
        doc.BuiltInDocumentProperties(propertyName).value = propertyValue
        propertyTypeUsed = "default"
    ElseIf PropertyExists(doc, propertyName, "custom") Then             ' A custom property exists, so use that
        doc.CustomDocumentProperties(propertyName).value = propertyValue
        propertyTypeUsed = "custom"
    Else                                                                ' No property exists, so create a custom property
        doc.CustomDocumentProperties.Add _
            name:=propertyName, _
            LinkToContent:=False, _
            Type:=propertyType, _
            value:=propertyValue
        propertyTypeUsed = "custom"
    End If
    
    '** Check whether or not the value has actually been set *'
    On Error Resume Next
    If propertyTypeUsed = "default" Then
        result = (doc.BuiltInDocumentProperties(propertyName).value = propertyValue)
    ElseIf propertyTypeUsed = "custom" Then
        result = (doc.CustomDocumentProperties(propertyName).value = propertyValue)
    End If
    On Error GoTo 0

    UpdateDocumentProperty = result
    
End Function

Full project code

The full code for this project can be found in two Paste Bins -

I'm not sure if it's possible to get the code for actually creating the form (short of exporting it, but I have no where to put it), but in any case it's very simple -

  1. The form - frmChooseDocument
  2. The label - lblChooseDocument (Which New Starter document would you like to export?)
  3. The combobox - comChooseDocument
  4. The cancel button - btnCancel
  5. The OK button - btnOK (Initially disabled)

In reality I'm using the document that houses this code as a 'master' document for new startes, containing detailed instructions on how to use variouse applications.

The code itself looks for Heading 1 formatted text within the document and adds them to the combobox in the form, allowing the user to select a section to export. A new document is then created and saved as a PDF.


Update

As suggested in the comments, I have checked that the type of value being set matches that of the value being passed to the function and it does.

In the case of all 3 properties described above, both the value that I am passing and the property as stored against the document are of type string.

I've added a couple of lines to output the type and value where I am setting the result and all looks well, but obviously it is not!

Debug.Print "My value:        (" & TypeName(propertyValue) & ")" & propertyValue
Debug.Print "Stored property: (" & TypeName(doc.BuiltInDocumentProperties(propertyName).value) & ")" & doc.BuiltInDocumentProperties(propertyName).value

Here is the output -

My value:        (String)New Starter Guide - Novell
Stored property: (String)New Starter Guide - Novell
My value:        (String)New starter guide
Stored property: (String)New starter guide
My value:        (String)new starters, guide, help
Stored property: (String)new starters, guide, help
Community
  • 1
  • 1
David Gard
  • 11,225
  • 36
  • 115
  • 227
  • 9
    Man, I wish all SO questions looked like this. – RubberDuck Jan 16 '15 at 14:48
  • The problem is that it's returning False, right? I got that same result when I tried to set a Boolean. It was comparing True to -1 and calling it no match. Instead of setting it to True, I set it to -1. Still False. Now it's comparing -1 to "-1". Check the TypeName of propertyvalue and of doc.CustomeDocumentProperties(properyName).value and see if they're the same. With things like Title, Subject, and Category, I can't imagine they'd be different, but it's a start. – Dick Kusleika Jan 16 '15 at 15:14
  • It is indeed returning false in every instance, but it's also not actually setting the property (which is done before checking if it was successful or not). I'll look in to your other comments now... Thanks. – David Gard Jan 16 '15 at 15:42
  • @DickKusleika - Apologies, the properties are now being set (I guess another error was preventing that earlier, didn't realised that I'd fixed it), however `false` is still being returned. I've updated my question in reference to your comments and would be greatful for any further thoughts you may have. Thanks. – David Gard Jan 16 '15 at 15:58
  • According to MSDN, the DocumentProperties collection (including `Item`) is read-only: http://msdn.microsoft.com/en-us/library/office/ff861126(v=office.15).aspx You can only `Add` but this would only work with CustomProperties. – Jason Faulkner Jan 16 '15 at 16:09
  • @David Gard it's working for me, but I don't see how you're calling UpdateDocumentProperty so maybe there's something there. Instead of checking the TypeName, check the Len() of both and make sure there aren't any non printable characters. Both of these returned true `Debug.Print UpdateDocumentProperty(ActiveDocument, "Title", "New Starter Guide - Novell", msoPropertyTypeString)` and `Debug.Print UpdateDocumentProperty(ActiveDocument, "testprop", "1")` – Dick Kusleika Jan 16 '15 at 17:36
  • It is working for me. Have you tried it on an empty document, to exclude other possible error sources? – ignotus Jan 19 '15 at 07:55
  • @ignotus - The code I have creates a brand new document and attempts to set the document properties on that. In just a moment I'll upload the entire script to a Paste Bin and link to it... – David Gard Jan 19 '15 at 15:10
  • @DickKusleika - Thanks for the tip, but the length of the results of `Len()` also match. I myself am starting to wonder if the problem is actually with the function that calls `UpdateDocumentProperty()`. Full code is now linked to in my question, any other tips would be apprciated. Thanks. – David Gard Jan 19 '15 at 15:45
  • 3
    @DavidGard In Function SetProperties, give result an initial value of True – ignotus Jan 19 '15 at 15:45
  • AHHHHH!!!! How did I miss that?! Thank you, that was indeed the problem. Rather than give an initial value of `True` I actually check to ensure that the returned value is `True` (just a personal preference), but that does the trick. Thanks for taking the time to look, and I'll accept that answer if you would be so kind as to post it :) – David Gard Jan 19 '15 at 15:57

2 Answers2

2

I managed to set my word document title by saving the document after changing the property. I set the "Saved" property to false first to make sure that Word registers the change in state.

Function ChangeDocumentProperty(doc As Document, sProperty As String, sNewValue As String)

    Debug.Print "Initial Property, Value: " & sProperty & ", " & doc.BuiltInDocumentProperties(sProperty)

    doc.BuiltInDocumentProperties(sProperty) = sNewValue

    doc.Saved = False
    doc.Save

    ChangeDocumentProperty = (doc.Saved = True And doc.BuiltInDocumentProperties(sProperty) = sNewValue)

    Debug.Print "Final Property, Value: " & sProperty & ", " & doc.BuiltInDocumentProperties(sProperty)

End Function

Immediate Window:

? ThisDocument.ChangeDocumentProperty(ThisDocument, "Title", "Report Definitions")
Initial Property, Value: Title, Report Glossary
Final Property, Value: Title, Report Definitions
True
TehJake
  • 121
  • 9
  • Apologies, I've re-read the above and now feel I've missed the point completely. I thought the issue was that the document properties were not being changed. Please ignore my post if it's irrelevant! – TehJake Apr 21 '15 at 15:23
1

Permanent object properties cannot be set by functions. In other words, VBA does not allow functions to have side effects that persist after the function is finished running.

Re-write the function as a Sub and it should work.

tpkaplan
  • 182
  • 8