Greetings, problems with setting a bookmarked textbox value...it's protected?

S

Shell

Hi all,

I've been writing code in various environments, in varying
application, for a wide range of customers, for about 35 years now and
I'm still learning new stuff. ;) This week I'm helping a friend
create a Word document template (Word 97) that stores a bunch of
answers to questions in the registry (Using SaveSetting and
GetSetting). In this document, as a part of the startup processing
(AutoNew), I want to load the stored values back into the bookmarked
places where they belong. The problem is I'm getting a error saying
the location is protected. From what I understand of this, yes it is!
I've protected the document so the body cannot be modified...but I
want to be able to enter text/values into those places where I've
defined fields (such as Textboxes, Checkboxes...et al)

Here's the code I have so far, the error comes from this line:

BkMrkRng.Text = RegVal

<code>
Option Explicit
Private BkMrk As Bookmark, BkMrkRng As Range

Sub AutoNew()
Dim sBMName As String, S1 As String, S2 As String, RegVal As String

For Each BkMrk In ActiveDocument.Bookmarks
sBMName = BkMrk.Name
S1 = Mid(sBMName, 1, Len(sBMName) - 1)
S2 = Mid(sBMName, Len(sBMName))
RegVal = GetSetting("MBD", S1, S2, vbNullString)
If RegVal <> vbNullString Then
Set BkMrkRng = ActiveDocument.Bookmarks(sBMName).Range
BkMrkRng.Text = RegVal
ActiveDocument.Bookmarks.Add sBMName, BkMrkRng
End If
Next BkMrk
End Sub
</code>

Hints: I've used the bookmark name, split into 2 strings, to name the
Section and Key for the SaveSetting function so I can easily retrieve
the values. I've learned that by setting the text value of a bookmark
it clears the bookmark itself, therefore making it necessary to Add
the bookmark back in after setting the text value.

Thanks for any help,
Shell (Yes, this is my real name)
 
J

Jay Freedman

At the beginning of the code, put in

If ActiveDocument.ProtectionType <> wdNoProtection Then
ActiveDocument.Unprotect
End If

and at the end put in

ActiveDocument.Protect Type:=wdAllowOnlyFormFields, NoReset:=True

Also, a bit of unsolicited advice: The registry isn't a suitable place
to store data for specific documents.

- They're available only on that one computer; if the document is
moved to another computer, the values won't be found.

- The registry is already a bloated monster on most PCs; it was never
intended for storing large chunks of text. Performance of the whole PC
is likely to suffer as the registry grows.

A better choice is to create document variables, members of the
ActiveDocument.Variables collection. These values are stored in the
document file when it's saved. They can be created and deleted only by
macro code, but they can be displayed in the body of the document by
{DocVariable} fields.
 
S

Shell

In response to the post:
At the beginning of the code, put in

If ActiveDocument.ProtectionType <> wdNoProtection Then
ActiveDocument.Unprotect
End If

and at the end put in

ActiveDocument.Protect Type:=wdAllowOnlyFormFields, NoReset:=True

Also, a bit of unsolicited advice: The registry isn't a suitable place
to store data for specific documents.

- They're available only on that one computer; if the document is
moved to another computer, the values won't be found.

- The registry is already a bloated monster on most PCs; it was never
intended for storing large chunks of text. Performance of the whole PC
is likely to suffer as the registry grows.

A better choice is to create document variables, members of the
ActiveDocument.Variables collection. These values are stored in the
document file when it's saved. They can be created and deleted only by
macro code, but they can be displayed in the body of the document by
{DocVariable} fields.

That sounds good. Would I be able to reference them from another
document? The reason I'm storing the vlues in the registry is so I
can get to them easily from other documents...there will be 4-5 other
documents that I'll plug the values into when they are opened.

Thanks for the quick reply,
Shell
 
S

Shell

In response to the post:
and I replied:

Maybe I responded too soon :) Now I'm getting a completely
unintelligable error...at least the doc is unprotected now (thanks).

Runtime error '5148:
The number must be between :: <----this is a box in the message

The error occurs on the same line as before:

BkMrkRng.Text = RegVal

Also, I've noticed the text is preceeded with the value "FORMTEXT "
which seems to be plugged in there by Word for some reason :/

I've been programming in VB6 for the last 5-6 years and I'm getting
pretty good at finding the methods/properties/events of those
controls...but this Word stuff seems to be like trying to see through
mud. I do not understand how you can tell, from the collection of
bookmarks, what type of form field it is the bookmark is referring to,
textbox, checkbox or dropdownbox.

Shell
 
J

Jay Freedman

This is in response to both of your most recent replies...

1. About storing things in document variables or in the registry: Your
concern is correct, the document variables of one document aren't available
to another document; but the registry still isn't a good choice. There's a
third alternative, a separate file on the disk, which you can read and write
with the System.PrivateProfileString property. The VBA help has a good
example of how to use it. That file will be available to any open document
on the same PC.

2. About the error: This requires some background. In Word there are plain
bookmarks, which you manage in the Insert > Bookmark dialog; and there are
bookmarks associated with form fields, which you see in the fields'
Properties dialog. If you simply cycle through the ActiveDocument.Bookmarks
collection, you'll get both kinds, but you can't treat them the same. The
error you see comes from trying to treat a form-field bookmark like a plain
bookmark, just assigning text to its range. But since the value you picked
up from the registry is the whole field including the field markers, VBA
complains. (The 'FORMTEXT' is part of the field code, which you can see when
you select the field in an unprotected document and press Shift+F9.)

The right way to go about this is to declare a FormField object, and then
cycle through the ActiveDocument.FormFields collection (Dim oFld As
FormField; For Each oFld In ActiveDocument.FormFields ...). One advantage of
this is that the code in this loop will never see any of the plain
bookmarks. A second advantage is that a FormField object has a property
named Type, and you can use an If statement or a Select Case statement to do
different things depending on whether its value is wdFieldFormTextInput (a
text box), wdFieldFormCheckBox, or wdFieldFormDropDown.

The value you should be storing, wherever you put it, should not be the
..Range.Text of some bookmark, but instead the .Value property of the
FormField object. For a textbox this will be the text in the box; for a
checkbox it will be either True or False; and for a dropdown it will be the
index (not the text!) of the selected item. When you retrieve the value from
storage, assign it back to the .Value property of the corresponding
FormField object.

I can sympathize with your frustration! The core of VBA is similar to VB,
but probably 80% of the things you need to know in VBA are the details of
the Word/Office object model and not just the programming principles. It
takes a while to get the hang of these things.
 
S

Shell

In response to the post:
This is in response to both of your most recent replies...

I really appreciate your help on this...you've been both extremely
helpful and patient. Because of your help I now have about 20% of the
code I had before...now you can help me to make what remains work ;)

How can I tell what FormField has triggered an Entry or Exit Module?
I've tried to use the Selection.FormField(1).Name in both an Entry and
Exit Module, but neither collection contains ANY members. I can see
that focus moves from the field when the Exit Mod is being
processed...so where can I find which one triggered the event?

Shell
 
J

Jay Freedman

In response to the post:


I really appreciate your help on this...you've been both extremely
helpful and patient. Because of your help I now have about 20% of the
code I had before...now you can help me to make what remains work ;)

How can I tell what FormField has triggered an Entry or Exit Module?
I've tried to use the Selection.FormField(1).Name in both an Entry and
Exit Module, but neither collection contains ANY members. I can see
that focus moves from the field when the Exit Mod is being
processed...so where can I find which one triggered the event?

Shell

If your typing of 'Selection.FormField(1).Name' is literally what you
have in your code, you're missing the 's' in 'FormFields'.

If it isn't a typo, then I'll guess that the field you're exiting from
is a text box -- those don't follow the rules (bug? who knows?). See
this page for an explanation of what you need to do:
http://www.word.mvps.org/FAQs/TblsFldsFms/GetCurFmFldName.htm

That code goes in the exit macro of a field (or more likely, the same
macro called as the exit macro of several fields), and it returns the
name of the field you're exiting from.

Another page that has code you can study is
http://www.word.mvps.org/FAQs/TblsFldsFms/ValidateFFields.htm.
 
S

Shell

In response to the post:
If your typing of 'Selection.FormField(1).Name' is literally what you
have in your code, you're missing the 's' in 'FormFields'.

If it isn't a typo, then I'll guess that the field you're exiting from
is a text box -- those don't follow the rules (bug? who knows?). See
this page for an explanation of what you need to do:
http://www.word.mvps.org/FAQs/TblsFldsFms/GetCurFmFldName.htm

That code goes in the exit macro of a field (or more likely, the same
macro called as the exit macro of several fields), and it returns the
name of the field you're exiting from.

Another page that has code you can study is
http://www.word.mvps.org/FAQs/TblsFldsFms/ValidateFFields.htm.


Hehehe, ok what can I say? Microsoft is not known for it's stability
or consistencies of procedure. What I typed before was a typo and
what you resonded with resolved the problem. Another thing I noticed
was that once I had the name of the bookmark, I was still not able to
reference it with the name...I had to use the workaround even there.
Maybe the index doesn't like string variables containing the bookmark
name...whatever, I was able to work around it with your much
appreciated help.

Another thing I noticed, although this is not a problem that has
stopped development, is that ActiveDocument.Path doesn't return
anything...it's blank. I've found a work around (patch really) where
I store the Application.Path in a Main entry program (in VB6), then
use that path in the Word macro. I have a few more things to work
into it...like a document name in the SaveAs dialog (I have the
article for that one), and directing the SaveAs to my program
directory instead of MyDocuments.

For now, I have a nice quiet weekend to enjoy, and some birthday cake
to eat (my neice is turning 11) With a classic "Doc" Sevrenson bow
and wave, you have a good one too.

Shell
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top