Hi,
I want to improve an outlook addin which is using mapi fields (a lot) and this is generating abnormal behaviors in outlook, so now I'm in doubt to quit all use of mapi fields fo User Properties but I need some recomendatios or comments about using "mapi fields vs user properties" (or viceversa).
Thanks,
Mauricio.

Outlook: MAPI fields versus User Properties
LAPM
.NET languages have no support for accessing MAPI properties in versions prior to Outlook 2007. Therefore, the UserProperties collection would be the supported approach.
What kind of behaviors are you seeing as abnormal
Bawaj
Hi.
Now I tried following your suggests but it did not solve the problem, the abnormal behavior continue :(
--------------------------------------------------------------
System.Runtime.InteropServices.Marshal.ReleaseComObject(lmsg)
lmsg = Nothing
GC.Collect()
---------------------------------------------------------------
So, if CDO 1.21 with .NET and Office2003 does not work (or generate abnormal behaviors) :
how could I do to persist metadata associated to a mail object (user properties are not an option because I don't have a mapi form associated with all mails)
thanks a lot for your support,
Mauricio.
Pockey
Ravel
Hi!
Now I tried to do this:
-------------------------------------------------------------------------
.NET code:
Public Sub SetCampoMAPI_Mejorado(ByRef Item As Outlook.MailItem, ByVal Campo As String, ByVal valor As String)
Dim lwrapMAPI As Object, lsEntryID As String, lsStoreID As String
Try
lsEntryID = Item.EntryID
lsStoreID = Item.Parent.StoreID
lwrapMAPI = CreateObject("prjWorkMAPI.clsWorkMAPI") 'I allready try with an interop of this DLL
lwrapMAPI.SetCampoMAPI(lsEntryID, lsStoreID, Campo, valor)
lwrapMAPI.Dispose()
System.Runtime.InteropServices.Marshal.ReleaseComObject(lwrapMAPI)
lwrapMAPI = Nothing
Catch ex As System.Exception
MsgBox(ex.Message & vbCrLf & ex.Source & vbCrLf & ex.StackTrace, MsgBoxStyle.Critical, "Atencion")
If Not lwrapMAPI Is Nothing Then
lwrapMAPI.Dispose()
System.Runtime.InteropServices.Marshal.ReleaseComObject(lwrapMAPI)
lwrapMAPI = Nothing
End If
End Try
GC.Collect()
GC.WaitForPendingFinalizers()
End Sub
------------------------------------------------------------------------
as you see, I made a VB6's dll which open a mapi session and modify or create a mapi field in a message. In this dll I'm doing early binding with CDO and set to nothing all objects.
------------------------------------------------------------------------
VB6 dll code:
Option Explicit
Private mSessionObj As MAPI.Session
Public Sub SetCampoMAPI(ByVal xsEntryID As String, ByVal xsStoreID As String, _
ByVal Campo As String, ByVal valor As String)
Dim lmsg As MAPI.Message
Dim loFields As MAPI.Fields, loField As MAPI.Field, lbExiste As Boolean
Dim lsTest As String
On Error GoTo ErrHand
Set lmsg = MSession.GetMessage(xsEntryID, xsStoreID)
Set loFields = lmsg.Fields
If loFields.Count > 0 Then
For Each loField In loFields
If UCase(Trim("" & loField.Name)) = UCase(Trim("" & Campo)) Then
loField.Value = valor
lbExiste = True
Exit For
End If
Next
End If
If Not lbExiste Then
loFields.Add Campo, vbString, valor
End If
lmsg.Update True, True
Set loFields = Nothing
Set lmsg = Nothing
Exit Sub
ErrHand:
Err.Raise Err.Number, "SetCampoMAPI" & Err.Source, Err.Description
End Sub
Public Function MSession() As MAPI.Session
If mSessionObj Is Nothing Then
Set mSessionObj = New MAPI.Session
mSessionObj.Logon "Outlook", "", False, False
MsgBox "Cree la sesion MAPI:" & mSessionObj.CurrentUser().Name
End If
Set MSession = mSessionObj
End Function
Public Sub Dispose()
If Not mSessionObj Is Nothing Then
mSessionObj.Logoff
Set mSessionObj = Nothing
End If
End Sub
------------------------------------------------------------------------
But the unwanted behavior still here :(
when I want to save a message which was in draft folder, the warning message appear ("...this message has been changed by another user or in another window...."), only when I set mapi fields of course.
reproduce this behavior is very simple, did you try
thanks for your help,
Mauricio.
inias
well, I just trying to do the same that I'm doing with .net 2003 but now I try to do it with VB6, here is the code (in red is my customized code):
---------------------------------------------------------------------------------------------------------
Option Explicit
Public FormDisplayed As Boolean
Public VBInstance As VBIDE.VBE
Dim mcbMenuCommandBar As Office.CommandBarControl
Dim mfrmAddIn As New frmAddIn
Public WithEvents MenuHandler As CommandBarEvents 'command bar event handler
Public WithEvents OLKApplication As Outlook.Application
Public WithEvents ColInspectors As Inspectors
Private mSessionObj As MAPI.Session
Sub Hide()
On Error Resume Next
FormDisplayed = False
mfrmAddIn.Hide
End Sub
Sub Show()
On Error Resume Next
If mfrmAddIn Is Nothing Then
Set mfrmAddIn = New frmAddIn
End If
Set mfrmAddIn.VBInstance = VBInstance
Set mfrmAddIn.Connect = Me
FormDisplayed = True
mfrmAddIn.Show
End Sub
'------------------------------------------------------
'this method adds the Add-In to VB
'------------------------------------------------------
Private Sub AddinInstance_OnConnection(ByVal Application As Object, ByVal ConnectMode As AddInDesignerObjects.ext_ConnectMode, ByVal AddInInst As Object, custom() As Variant)
On Error GoTo error_handler
'save the vb instance
'Set VBInstance = Application
Set OLKApplication = Application
Set ColInspectors = OLKApplication.Inspectors
' 'this is a good place to set a breakpoint and
' 'test various addin objects, properties and methods
' Debug.Print VBInstance.FullName
'
' If ConnectMode = ext_cm_External Then
' 'Used by the wizard toolbar to start this wizard
' Me.Show
' Else
' Set mcbMenuCommandBar = AddToAddInCommandBar("My AddIn")
' 'sink the event
' Set Me.MenuHandler = VBInstance.Events.CommandBarEvents(mcbMenuCommandBar)
' End If
'
' If ConnectMode = ext_cm_AfterStartup Then
' If GetSetting(App.Title, "Settings", "DisplayOnConnect", "0") = "1" Then
' 'set this to display the form on connect
' Me.Show
' End If
' End If
Exit Sub
error_handler:
MsgBox Err.Description
End Sub
'------------------------------------------------------
'this method removes the Add-In from VB
'------------------------------------------------------
Private Sub AddinInstance_OnDisconnection(ByVal RemoveMode As AddInDesignerObjects.ext_DisconnectMode, custom() As Variant)
On Error Resume Next
'delete the command bar entry
mcbMenuCommandBar.Delete
'shut down the Add-In
If FormDisplayed Then
SaveSetting App.Title, "Settings", "DisplayOnConnect", "1"
FormDisplayed = False
Else
SaveSetting App.Title, "Settings", "DisplayOnConnect", "0"
End If
Unload mfrmAddIn
Set mfrmAddIn = Nothing
End Sub
Private Sub IDTExtensibility_OnStartupComplete(custom() As Variant)
If GetSetting(App.Title, "Settings", "DisplayOnConnect", "0") = "1" Then
'set this to display the form on connect
Me.Show
End If
End Sub
'this event fires when the menu is clicked in the IDE
Private Sub MenuHandler_Click(ByVal CommandBarControl As Object, handled As Boolean, CancelDefault As Boolean)
Me.Show
End Sub
Function AddToAddInCommandBar(sCaption As String) As Office.CommandBarControl
Dim cbMenuCommandBar As Office.CommandBarControl 'command bar object
Dim cbMenu As Object
On Error GoTo AddToAddInCommandBarErr
'see if we can find the Add-Ins menu
Set cbMenu = VBInstance.CommandBars("Add-Ins")
If cbMenu Is Nothing Then
'not available so we fail
Exit Function
End If
'add it to the command bar
Set cbMenuCommandBar = cbMenu.Controls.Add(1)
'set the caption
cbMenuCommandBar.Caption = sCaption
Set AddToAddInCommandBar = cbMenuCommandBar
Exit Function
AddToAddInCommandBarErr:
End Function
Private Sub ColInspectors_NewInspector(ByVal Inspector As Outlook.Inspector)
Dim lMailItem As Outlook.MailItem
Set lMailItem = Inspector.CurrentItem
If Not lMailItem Is Nothing Then
SetCampoMAPI lMailItem.EntryID, lMailItem.Parent.StoreID, "Prueba", "MPV"
End If
Set lMailItem = Nothing
End Sub
Public Sub SetCampoMAPI(ByVal xsEntryID As String, ByVal xsStoreID As String, _
ByVal Campo As String, ByVal valor As String)
Dim lmsg As MAPI.Message
Dim loFields As MAPI.Fields, loField As MAPI.Field, lbExiste As Boolean
Dim lsTest As String
On Error GoTo ErrHand
Set lmsg = MSession.GetMessage(xsEntryID, xsStoreID)
Set loFields = lmsg.Fields
If loFields.Count > 0 Then
For Each loField In loFields
If UCase(Trim("" & loField.Name)) = UCase(Trim("" & Campo)) Then
loField.Value = valor
lbExiste = True
Exit For
End If
Next
End If
If Not lbExiste Then
loFields.Add Campo, vbString, valor
End If
lmsg.Update True, True
Set loFields = Nothing
Set lmsg = Nothing
Dispose
Exit Sub
ErrHand:
Err.Raise Err.Number, "SetCampoMAPI" & Err.Source, Err.Description
End Sub
Public Function MSession() As MAPI.Session
If mSessionObj Is Nothing Then
Set mSessionObj = New MAPI.Session
mSessionObj.Logon "Outlook", "", False, False
MsgBox "Cree la sesion MAPI:" & mSessionObj.CurrentUser().Name
End If
Set MSession = mSessionObj
End Function
Public Sub Dispose()
If Not mSessionObj Is Nothing Then
mSessionObj.Logoff
Set mSessionObj = Nothing
End If
End Sub
---------------------------------------------------------------------------------------------------------
and the result is exactly the same that I have with .net addin......... when I modify a mapi field and after I want to save the mail, I get the warning message.
I don't realise if are something wrong it that code, I think that I release all objects but abnormal behavior is still here :(
So, after all of this tests I assume that this behavior will happen allways that you want to change or add mapi fields in a mail item.
could you post the code that you used to test this behavior and didn't get the error
thanks a lot,
Mauricio.
katokay
Saurabh G
I think you need to set an object to Nothing before calling ReleaseComObject.
The availability of the UserProperties collection is not dependent on a custom form being associated with a message. That said, using UserProperties on messages can create problems for forwarded messages. Lower level third-party libraries like Outlook Redemption and MAPI33 can provide access to features that normally are available only with Extended MAPI. Another approach would be to use VB6 to create your own COM component using CDO 1.21 that your .NET application can call when it needs that functionality.
P.Johansson
Hi,
yes I get this warning in inbox folder too ("The item could not be saved because it has been changed by another user o in another window.Do you want to make a copy in the default folder for the item ").
but, did you trying do something like I'm doing (addin in .net 2003, calling a VB6 dll and using the MailItem variable in .net code which is in module level because I need events handling, to catch mail close for example)
I'm going to do some tests without event handling and without module level variables, later I'll tell you about this.
thanks for your patience,
Mauricio.
Puil
No, I didn't exactly replicate your setup, I just tested using some Outlook VBA code with CDO 1.21.
I'd first suggest using a piggyback logon to CDO and not using a profile logon. That could be part of the problem. I would logon as follows: mSessionObj.Logon "", "", False, False. Since Outlook is already running that lets CDO share the same session as Outlook.
I'd also not do everything you're doing in NewInspector. The object reference you can get in NewInspector is a pretty weak reference and I only use it for CurrentItem.Class, .MessageClass. I wait until Inspector.Activate fires before I try to manipulate any properties such as the Fields collection to make sure the item in the Inspector is fully instantiated.
Using Update(True, True) from a call from NewInspector might be part of the problem along with the other things I mentioned.
See if changing those things helps.
ron nash
No, I don't get that error in either VB6 or VBA code. Do you get it if the Message is saved elsewhere, other than Drafts
Do you have any open references to the Imsg item You're passing the EntryID and StoreID for Imsg, are you releasing any object references to that object before passing the ID strings
tenchyz
Does it work any better if you do this
iMsg = Nothing
GC.Collect()
GC.WaitForPendingFinalizers
Thymen
ok, I post one method of many which I'm using:
Public Shared Sub CampoOculto_Agregar(ByRef Item As Outlook.MailItem, ByVal Campo As String, ByVal valor As String)
Dim lmsg As MAPI.Message
Dim lsTest As String
If IsDate(Left(Item.BillingInformation, 10)) Then
SetCampoOm(Item.BillingInformation, Campo, valor)
Else
Dim larValor As Array = Array.CreateInstance(GetType(String), 1)
larValor(0) = valor
lmsg = MSession.GetMessage(Item.EntryID, Item.Parent.StoreId)
Try
lsTest = lmsg.Fields(Campo).Name
If TypeName(lmsg.Fields(Campo).Value) = "Object()" Then
lmsg.Fields(Campo).Value = larValor
ElseIf TypeName(lmsg.Fields(Campo).Value) = "String" Then
lmsg.Fields(Campo).Delete()
lmsg.Fields.Add(Campo, vbArray + vbString, larValor)
Else
MsgBox("error de tipo al actualizar campo: " & Campo)
End If
Catch ex As System.Exception
Try
'lFields = lmsg.Fields()
'lFields.Add(campo,vbArray + vbstring
lmsg.Fields.Add(Campo, vbArray + vbString, larValor)
Catch ex1 As System.Exception
MsgBox(ex1.Message)
End Try
End Try
lmsg.Update(True, True)
lmsg = Nothing
End If
What is wrong in this code (talking about work with MAPI fields, of course)
I really appreciate your help, thanks.
Mauricio.
adiash
if I set to nothing the object before calling ReleaseComObject, this method throw an error because object is nothing..., so I assume that set to nothing goes after ReleaseComObject.
I can't to use UserProperties without a custom form because I need persist the values on mail item on forward and reply. When user close Outlook and open it again I need the value on mail still there too.
So, now I will try to do something with redemption or mapi33 or else make my own vb6 dll.
thanks a lot again,
Mauricio.
PD: later I will post my tests result and maybe new questions ;)
IanG
Somethings like warnings when closing a mail saying: "The message has changed, do yo want to save...."
or if you save a message in drafts and later open it and make some changes, when yo want save it, a warning appear saying that a copy will be made in origin folder, so you have a copy in inbox too, later if yo close outlook , when you open it again and open the message in drafts folder the last changes does not appear, but in the copy in inbox the changes are.......
Behaviors like this happen in PCs which have my outlook addin installed, I assume that work with mapi fields are the problem because if I ommit set mapi fields this behaviors does not happen.
Thanks for your help,
Mauricio