Property tags - what happens if... (Rename of user defined field)

  • Thread starter Thread starter Bert_Bert
  • Start date Start date
B

Bert_Bert

I would like to ask someone experienced - I think I can use UserProperties
ang Property tags somehow intuitively but still there is something that
inhibits me to imagine how to rename all the Custom fields "Name1" to "Name2".

Firstly, I think it fill not be possible to change the name of the existing
property and the only solution would be to find
oMailItem.Fields(poprtag) and to delete it somehow and to create some with
new name and copy the value, is it right ?

My question is, the old property disappears from the folder completely
including old Propertytag in the moment that I delete it from last items, is
it right ?

Or, it does never disappear ?

Or, Is it good to create a new folder and then move all the
"in-this-way-renamed" items to the new folder to get rid of the balast (old
named fields)?

And, what object would you recommend to use with Redemtion to "rename", even
by the deleting- adding new - method. - for 6000 items to run fast enough ?

Of course also Form has to be adapted to use new UserNames.

thank you
 
You cannot change the name of a UserProperty once it's created. You'd have
to delete it and create a new property with the name you want. You also
can't change a UserProperty data type once it's created.

If the UserProperty was created only in the items then deleting it from all
items with that property will completely remove it. If it was also added to
the folder fields then deleting it from all items won't be enough to
completely remove all traces of it.

Can I ask why you need to do all this and not just leave things as they are?

Whatever method you use will still involve getting each item in the folder
and deleting the properties and creating new ones. I don't think Redemption
would be significantly faster in that case than using the Outlook object
model. Whatever you use will take time for 6000 items.
 
If the UserProperty was created only in the items then deleting it from all
items with that property will completely remove it. If it was also added to
the folder fields then deleting it from all items won't be enough to
completely remove all traces of it.
Can I ask why you need to do all this and not just leave things as they are?
Whatever method you use will still involve getting each item in the folder
and deleting the properties and creating new ones. I don't think Redemption
would be significantly faster in that case than using the Outlook object
model. Whatever you use will take time for 6000 items.

Well, I am designing Language vocabulary flexible storage that would examine
you and store how successful you were back so that it examines you more often
from words you did not know.
Such a solution has advantage of synchronized personal knowledge that
evolves during the time with you.
The vocabulary and the schedules being in one folder.

What I need to do is, As I designed this solution I hd less experience than
now and I would like to do some meintenance of the sample vocabulary so that
it looks nicer.

Also, as I learned how to restrict with categores, I can remove my temp
field Categ2 that enabled me to filter and was duplicate and had to be copied
with the form so it was something I did not like at all.

I mean, I need this to make "Maintenance admin form" for me only, not for
the end user :-)
I am creating this kind of solution in my free time and dedicated a lot alot
of time so far and it works very quickly and I at least have some results
with redemption tahnks to your advices.

you can see a few screenshots at
http://filip.laburda.cz/zkouseni/zkouseni.html
the main advantage is, the store with vocabulary is very flexible to
categorize and is always up-to date with person that learns language


Do I understand it right, that with first item that exists in the store, the
store is aware of this fact and blocks the field from being deleted until I
remove the last item or, until I remove last occurence of the field, then
also PropertyTag that is unique for the store/perhaps folder?? can be
released ?

It is still great mystery for me :-)
 
If a user property is added only to individual items then deleting it from
each item where it exists will completely remove it. If it was also added to
the folder then even deleting every item in the folder won't remove it from
the folder fields. That would have to be done using a different API such as
Extended MAPI (C++ or Delhi only, no managed code) or CDO 1.21 or Redemption
(www.dimastr.com/redemption) to get at the folder fields.
 
I had big trouble in making bulk Property change using Redemption, CDO and
Outlook object model.

Firstly, CDO is quick and straightforwaard enough to create the bulk rename
script quickly, BUT, does not support Unicode so it forgets every foreigh
characters during the conversion.

Secondly, the Outlook object model is terribly slow (does not matter, I
could let him do it overnight) but, worse is, as it is working on items with
customized form, memory grows, grows, grows, after several hundred of items
it all crashes, wow!

Interesting point, if I remove form prom folder, there is no memory leak,
but the script stops working :-) because UserProperties is dependant on the
form published in the folder.


Third: Redemption, it is Unicode, wow, it is quick, wow, it does not leak
memory, wow, but it does NOT work. >:-)

well as I declared
Dim up as Redemption.UserProperty
Set up=oMessage.UserProperties.Find(..., true) 'tried string, PropTag

I get Count 0, empty collection in debugger.

Strange behaviour however is, that when I first make
Set up_existing=oMessage.UserProperties.Add("myexistingpropertyname")

then o la la I can see instead of adding the value of my EXISTING value.

This way I finally made the bulk migration tool working somehow but withou
proper examples on the internet it was two days of really hard work - why the
objects are so non-intuitive ?
 
1. Instead of using the standard CDO property tags use the _W set of tags.
For example, for subject instead of using CdoPR_SUBJECT = (&H37001E) use
CdoPR_SUBJECT_W = (&H37001F).

2. The Outlook object model will be slower.

Crashes like that are usually because you did not release objects each pass
through the loop or were trying to use dot operators. For example instead of
using oMessage.UserProperties.Find() you should instantiate a UserProperties
collection and then set the specific UserProperty. Each dot operator adds an
internal object that isn't released until the procedure ends.

If using .NET code you might have to use Marshal.ReleaseComObject() on each
object to fully release it.

The same memory manangement would also apply with unmanaged code and with
CDO or Redemption code too.

3. Is oMessage an RDOMail object or what? It isn't an Outlook object is it?

The Outlook object model is the most intuitive and most documented of the 3
choices. CDO and Redemption are more for advanced users and since Redemption
is based on MAPI you really should have some knowledge of MAPI to make the
best use of Redemption.
 
1. Instead of using the standard CDO property tags use the _W set of tags.
For example, for subject instead of using CdoPR_SUBJECT = (&H37001E) use
CdoPR_SUBJECT_W = (&H37001F).

well I have several days and weeks of heavy testing and of course I used
also the unicode PropTag but with the same poor results, so no, as far as I
know and tested, it was not possible, neither documented from anyone who
would report successful use of unicode+cdo at internet in real life

2. The Outlook object model will be slower.
well, Redemption is also slow with UserProperties, but does not have the
terrible memory leaks
and usint the same prop tags as before in CDO gives me Unicode results

Regarding the mem leaks, I know I found KB article at microsoft, it is
confirmed and known problem for years, and workaround in some register as far
as I remember, but the fix also was not of any use, it was ineffective for me

Crashes like that are usually because you did not release objects each pass
through the loop or were trying to use dot operators. For example instead of

no, I would argue here, of coure I studied how to fix it for a long time and
am aware of these hints

I strictly release every object to Nothing and do not use .dot convention
But I could not find anything for Visual Basic that would explicxitly invoke
garbage collector

Maybe problem is that I pass oTaskItem object Byref to subprocedure, in the
end of subprocedure release all objects dependant on it, and in the end of
loop before Next Set oTaskItem = Nothing.

Well, you can do a little test yourself at 1000 items folder, switch on your
Task manager and watch memory while setting some Userproperties and Subject
and so on for every message that has associated Form with VBScript on it.

I will bet you will not be able to write a program in such a way that after
300+- items the loop crashes and memoory will be full. It is not 1 single
test, but painful years of hard experiences, not being able to get rid of
this problem, all Outlook version till 2003 have this bug (2007 not tested,
but believe also).
using oMessage.UserProperties.Find() you should instantiate a UserProperties
collection and then set the specific UserProperty. Each dot operator adds an
internal object that isn't released until the procedure ends.

If using .NET code you might have to use Marshal.ReleaseComObject() on each
object to fully release it.
well using .NET was very nice for me because of comfortable object oriented
modern language, but till the moment I debugged sussefully my app Outlook
addin and wanted to deploy it.
Then Deploy hell started for me and despite several pages of microsoft
official documents with exact steps I did not manage to make it work on
testing machines, perhaps because of access rights problems, and also created
the package of tens megabytes for just single piece of code is not my cup of
coffe so I got back to rigid VB6 (unmanaged).
I wait with managed code until they make deployment really work and not pain
:-)
3. Is oMessage an RDOMail object or what? It isn't an Outlook object is it?
oMessage I mean Redemption.RDOMail

yes, RDOMail or I also tested RDOTaskItem
I also tested late binding declaring all as object but the same problem
is based on MAPI you really should have some knowledge of MAPI to make the
best use of Redemption.
well I look with OutlookSpy to Properties have and some intuitive feeling
however I do not understand why .UserProperties on Item that I securely
know contains "customprop" is empty and has count of properties zero.
i.e. Why I firstly have to ADD the field to see existing value in it.
 
Not to be too abstract: example od code taking rdoMail and using Outlook
Object model for each single Redemtion object to set the properties.
It is not too fast way of doing it I admit, but it HAS memory leaks:

'Private Function SubAkce_Rename(ByRef oMail As redemption.RDOMail, txtOld
As String, txtNew As String, tt As Long)
'
' If Len(Trim(txtOld)) = 0 Or Len(Trim(txtNew)) = 0 Or IsEmpty(tt) Or tt
= -1 Then Exit Function
'
' Dim nsp As Outlook.NameSpace
' Set nsp = Application.GetNamespace("MAPI")
' Dim pol As Outlook.TaskItem
' Set pol = nsp.GetItemFromID(oMail.EntryID)
' Dim upold As Outlook.UserProperty, upnew As Outlook.UserProperty
'
' Set upold = pol.UserProperties(txtOld)
'
' If upold Is Nothing Then Exit Function
' If IsEmpty(upold.Value) Then Exit Function
'
' Set upnew = pol.UserProperties.Add(txtNew, upold.Type, True)
' upnew.Value = upold.Value
'
' pol.Save
'
' Set up2 = Nothing
' Set up1 = Nothing
' Set pol = Nothing
' Set nsp = Nothing
'End Function
 
.....but why this strange method is the only one that can "find" existing
Property to copy value from ???
(the loop is above and passes the individual oMail objects to our Function)

Private Function SubAkce_Rename(ByRef oMail As redemption.RDOMail, txtOld As
String, txtNew As String, tt As Long)

If Len(Trim(txtOld)) = 0 Or Len(Trim(txtNew)) = 0 Or IsEmpty(tt) Or tt =
-1 Then Exit Function

Dim ups As redemption.RDOUserProperties
Set ups = oMail.UserProperties

Dim upold As redemption.RDOUserProperty, upnew As
redemption.RDOUserProperty
Set upold = ups.Add(txtOld, tt, True)

If upold Is Nothing Then Exit Function
If IsEmpty(upold.Value) Then Exit Function

Set upnew = ups.Add(txtNew, upold.Type, True)


upnew.Value = upold.Value

'...a smažeme staré
upold.Value = Empty
Set upold = Nothing

oMail.Save

Set upnew = Nothing
Set upold = Nothing
Set ups = Nothing

End Function
 
I see you using dot operators in your code so what you say just isn't so.

Set oUserProp = item.UserProperties("myProp") uses dot operators, they're
just implied. To not use dot operators you would Set colUserProps =
item.UserProperties, then set a UserProperty object from the UserProperties
collection.

I also have used VB6 for many years in writing many Outlook addins and have
yet to run into horrible memory leaks or crashes because of lots of items in
folders, and I'm talking about thousands of items in folders. So either my
experience is completely different than yours or you are doing something
wrong in releasing items and objects. And there is no garbage collector for
VB6 as there is in managed code.

If a user property is added as a custom field in a form there may be no
Count for UserProperties and the UserProperties named property as seen in
OutlookSpy may not even be there at all. However there probably will be a
MAPI named property of that name and type. Things are not always consistent
or even logical when you use custom properties in custom forms, one of many
reasons why forms aren't robust solutions.
 
' dot operator added objects
Set upold = pol.UserProperties(txtOld)
Set upnew = pol.UserProperties.Add(txtNew, upold.Type, True)

If you hit Exit Function you never set your objects to Nothing. I have no
idea what up2 and up1 are, but you don't set upold or upnew to Nothing.

To avoid dot operator added objects use something like this:

Dim props As Outlook.UserProperties

Then you can set props to pol.UserProperties and use props when you set
upold and upnew. Then you can also explicitly release props by setting it to
Nothing.
 
Set oUserProp = item.UserProperties("myProp") uses dot operators, they're
just implied. To not use dot operators you would Set colUserProps =
item.UserProperties, then set a UserProperty object from the UserProperties
collection.

ok, this example was wrong since I admit I did another and another tests and
I became crazy testing all combinations
you are right this was using dot convention, but the following does not and
after 500 items it exhausts Outlook 2003SP3 totally. I believe all object
here are released correctly and do not use dot convention.

It is simple procedure to import from Excel sheet to Outlook and uses
..UserProperties - this is maybe the catch why for you it has worked and for
me it does not. Pole_zahlavi() contains array of Fields names, Pole_radka
contains arary of values() I want to "import".

Function ZanesDoPolozky_OutlookOM(ByRef fld As Outlook.MAPIFolder, ByRef
Pole_zahlavi() As String, ByRef Pole_radka() As String, trida As String)
Dim zpr As Outlook.TaskItem
Dim j As Long, strNazevPole As String, hod As String

Dim KWords() As String
Dim itms As Outlook.Items
Set itms = fld.Items
Set zpr = itms.Add(trida)
For j = 0 To UBound(Pole_zahlavi)
strNazevPole = Pole_zahlavi(j)
hod = Pole_radka(j)

Select Case strNazevPole
Case "Category" ' Pokud to není uživatelsky definované pole, má
výjimku
'KWords = Split(hod, ";")
zpr.Categories = hod
Case "Lekce"
KWords = Split(hod, ";")
Call HodnotaDoPole_OutlookOM(zpr, "Lekce", naplnPole(KWords))
Case Else ' Veškerá ostatní uživatelská pole
If Len(Trim(hod)) > 0 Then Call
HodnotaDoPole_OutlookOM(zpr, strNazevPole, hod)
End Select
Next j
Call AktualizujSubjekt_OutlookOM(zpr)

zpr.Save
Set zpr = Nothing
Set itms = Nothing
End Function

Function HodnotaDoPole_OutlookOM(ByRef zpr As Outlook.TaskItem, ByVal
strNazevPole As String, ByVal Hodnota As Variant)
Dim upr As Outlook.UserProperties
Set upr = zpr.UserProperties
upr(strNazevPole).Value = Hodnota
Set upr = Nothing
End Function



I will maybe try to remember the id of the folder and set nsp=Nothing and
Create ne Namespace everytime I add one item, that seems crazy from the
programming point of view, but I really do not know after the years of
struggling how to use Outlook object model e.g. to import large number of
items normally without crashing or without calling 200 by 200 by 200 ietms
manually with Outlook killing in between manually.

This KB article
http://support.microsoft.com/kb/239658
is about Outlook98 but I experienced it is related so far to all the later
versions.

Sometimes I suspect Microsoft that this issue is introduced for years on
intention just not to allow bulk operations with VB.

Also please note I import items that are NOT standard Tasks, but customized
items with forms withs VBScript on it. Maybe this also is the problem.


MAPI named property of that name and type. Things are not always consistent
or even logical when you use custom properties in custom forms, one of many

regarding this, ok, I do not mind I cannot see my Custom properties using
Redemption UserPropeties, but as far as I cannot use Outlook (mem leaks),
cannot use CDO (non-unicode), cannot use Redemption (not visible as you just
told me) so please do you have some tip HOW should I access user defined
fields visible in my customized form in ANY correct way ? It will be a great
mystery diclosure for me :-)

Ken, thanks very musch for the replies
 
Ken, thanks to having to formulate my reply to you, I realized what could be
wrong I found the culprit of memory leaks.

It is VBScript at the custom form, because is runs even when the item is not
visually open, i.e. during import.

Firstly I tried to remove the whole VBS from form, and voilá ! work fast and
without leaks. Then I experimented a bit and found a culprit Sub called from

Sub Item_CustomPropertyChange(ByVal Name)

Then I removed dot convention and released objects explicitly and now
problem is gone !!!!!
Thank you very much for the hints.

If you happen to know some other way how to access UserProperties() via
Redemption, that are invisible through Retention's .UserProperty that would
be perhaps best solution, since as far as I understand it does not run the
Form VBS at all.
 
OK, that makes sense that the form code would run in that case. I'd probably
add something to the form code to check for an Inspector for the item to
verify that the item was actually opened for display if that's the only time
you want the form code to run. Otherwise you pretty much have to do what
you're doing.
 
Back
Top