none
Can I get a uinque ID and last modificaiton time of the attachment in Contacts/Tasks/Events? RRS feed

  • Question

  • I would like to copy the item attachments to servers, the attachments may also be synced back to Outlook if it's updated.

    Is it possible to retrieve these two properties of the attachments?

    - Unique id of the attachment in the item
    - Last modification time

    VB.NET, e.g:
     For Each attachment In task.Attachments
         WriteLog("DisplayName:" + attachment.DisplayName)
         WriteLog("Unique ID:" + attachment.id)   <================ 
         WriteLog("Last Modificaiton:" + attachment.lastmodificationtime)   <================
     Next

    Thanks,

    Cowcow

                           
    Thursday, October 23, 2014 9:02 AM

Answers

  • Hello,

    You can use the DisplayName property of the Attachment class, a String representing the name, which does not need to be the actual file name, displayed below the icon representing the embedded attachment.

    But the Attachment class (nor low-level properties of the IAttach interface) doesn't provide the id or last modification time. Note, you can't modify the attachment on the fly - you will have to re-attach it or set the binary value using the low-level code (PR_ATTACH_DATA_BIN).

    However, you may rely on the attachment Size - I think it will be changed when the attachment is changed. To identify the attachment you may try to use the PR_RECORD_KEY property, DASL name is "http://schemas.microsoft.com/mapi/proptag/0x0FF90102".

    Thursday, October 23, 2014 9:27 AM
  • Oulook doesn't reflect any changes immediately. You need to re-open the Outlook item at least, i.e. re-open the inspector window.

    Be aware, the PropertyAccessor class has limitations - the max number of data that can be set/get is limited to 16 KB if I remember correctly. You need to use the OpenProperty method instead, for example:

    LPSTREAM pStreamFile, pStreamAtt;
    HRESULT hr;
    hr = OpenStreamOnFile (MAPIAllocateBuffer, MAPIFreeBuffer,
                           STGM_READ, "myfile.doc", NULL, &pStreamFile);
    if (HR_SUCCEEDED(hr))
    {
        // Open the destination stream in the attachment object
        hr = pAttach->OpenProperty (PR_ATTACH_DATA_BIN,
                                    &IID_IStream,
                                    0,
                                    MAPI_MODIFY | MAPI_CREATE,
                                    (LPUNKNOWN *)&pStreamAtt);
        if (HR_SUCCEEDED(hr))
        {
            STATSTG StatInfo;
            pStreamFile->Stat (&StatInfo, STATFLAG_NONAME);
            hResult = pStreamFile->CopyTo (pStreamAtt, StatInfo.cbSize,
                                           NULL, NULL);
            pStreamAtt->Release();
        }
        pStreamFile->Release();
    }

     You can read more about this on the Opening an Attachment  page in MSDN.


    Thursday, October 23, 2014 12:16 PM
  • As far as I know the PropertyAccessor methods are based on the GetProps/SetProps methods of the IMAPIProp interface that have their own limitations. To avoid them you need to use the OpenProperty method as shown above.
    Thursday, October 23, 2014 2:12 PM

All replies

  • Hello,

    You can use the DisplayName property of the Attachment class, a String representing the name, which does not need to be the actual file name, displayed below the icon representing the embedded attachment.

    But the Attachment class (nor low-level properties of the IAttach interface) doesn't provide the id or last modification time. Note, you can't modify the attachment on the fly - you will have to re-attach it or set the binary value using the low-level code (PR_ATTACH_DATA_BIN).

    However, you may rely on the attachment Size - I think it will be changed when the attachment is changed. To identify the attachment you may try to use the PR_RECORD_KEY property, DASL name is "http://schemas.microsoft.com/mapi/proptag/0x0FF90102".

    Thursday, October 23, 2014 9:27 AM
  • Thank you.

    The  PR_RECORD_KEY property works. I only need to convert it to string (e.g: Convert.ToBase64String(data))

    However, I also tried PR_ATTACH_DATA_BIN. But it weird.

    I can update the attachment, but I cannot see the update in the task until I restart Outlook. Is there any idea why?

    Here is the sample:

    With task
           
                    Dim accessor As Outlook.PropertyAccessor = Nothing
                    Dim tmpFile = "C:\temp\trace_file.log"
        
                    attachments = .Attachments
                    For Each attachment In attachments
                      
                        accessor = attachment.PropertyAccessor

                        Dim content() As Byte = accessor.GetProperty(PR_ATTACH_DATA_BIN)
                        Dim data As String = System.Text.Encoding.Unicode.GetString(content)
                        data = "y" + data

                        accessor.SetProperty(PR_ATTACH_DATA_BIN, System.Text.Encoding.Unicode.GetBytes(data))


                        Marshal.ReleaseComObject(accessor)
                        accessor = Nothing
                        Marshal.ReleaseComObject(attachment)
                        attachment = Nothing
                    Next

                    .Save()

                End With

                Marshal.ReleaseComObject(attachments)
                attachments = Nothing
                Marshal.ReleaseComObject(task)
                task = Nothing

    Thursday, October 23, 2014 10:49 AM
  • Oulook doesn't reflect any changes immediately. You need to re-open the Outlook item at least, i.e. re-open the inspector window.

    Be aware, the PropertyAccessor class has limitations - the max number of data that can be set/get is limited to 16 KB if I remember correctly. You need to use the OpenProperty method instead, for example:

    LPSTREAM pStreamFile, pStreamAtt;
    HRESULT hr;
    hr = OpenStreamOnFile (MAPIAllocateBuffer, MAPIFreeBuffer,
                           STGM_READ, "myfile.doc", NULL, &pStreamFile);
    if (HR_SUCCEEDED(hr))
    {
        // Open the destination stream in the attachment object
        hr = pAttach->OpenProperty (PR_ATTACH_DATA_BIN,
                                    &IID_IStream,
                                    0,
                                    MAPI_MODIFY | MAPI_CREATE,
                                    (LPUNKNOWN *)&pStreamAtt);
        if (HR_SUCCEEDED(hr))
        {
            STATSTG StatInfo;
            pStreamFile->Stat (&StatInfo, STATFLAG_NONAME);
            hResult = pStreamFile->CopyTo (pStreamAtt, StatInfo.cbSize,
                                           NULL, NULL);
            pStreamAtt->Release();
        }
        pStreamFile->Release();
    }

     You can read more about this on the Opening an Attachment  page in MSDN.


    Thursday, October 23, 2014 12:16 PM
  • Outlook 2007 has a PropertyAccessor limitation for reading a property of 8K. You can write more than that but you can't read it back using PropertyAccessor. Outlook 2010 removed that limitation, now the limit would be the MAPI limit on properties, if applicable.

    Ken Slovak MVP - Outlook

    Thursday, October 23, 2014 1:47 PM
    Moderator
  • Attachments are not addressable on the MAPI level, they can be identified only on their parent item level by the PR_ATTACH_NUM property, which can change every time the item is opened.

    You can read the PR_LAST_MODIFICATION_TIME property (DASL name http://schemas.microsoft.com/mapi/proptag/0x30080040) from the attachment using Attachment.PropertyAccessor.GetProperty.

    Take a look at the attachment with MFCMAPI or OutlookSpy to check if you can see anything that you can use to identify the attachment.


    Dmitry Streblechenko (MVP)
    http://www.dimastr.com/redemption
    Redemption - what the Outlook
    Object Model should have been
    Version 5.5 is now available!


    Thursday, October 23, 2014 1:56 PM
  • As far as I know the PropertyAccessor methods are based on the GetProps/SetProps methods of the IMAPIProp interface that have their own limitations. To avoid them you need to use the OpenProperty method as shown above.
    Thursday, October 23, 2014 2:12 PM
  • For the OpenProperty , I couldn't find any VB.NET sample on the internet. Does it mean it only available in C++?

    Thanks,

    Cowcow

    Friday, October 24, 2014 6:44 AM
  • Nope. You can call the OpenProperty from any language. It is up to you what programming language is to choose. However, Microsoft doesn't recommend calling Extended MAPI functions from a managed code. It is not supported. But it works.

    Also you may consider using any third-party wrapper around Extended MAPI (for example, Redemption).

    Friday, October 24, 2014 10:35 AM