IDataSource Interface

Topic Last Modified: 2006-06-29

The IDataSource interface defines methods and properties that are used to provide access to content in other objects or in the Exchange store.

CLSID

CD000029-8B95-11D1-82DB-00C04FB1625D

Extends

IDispatch

Type Library

Microsoft CDO for Exchange 2000 Library

DLL Implemented In

CDOEX.DLL

Member Summary

The following table lists the properties of the IDataSource interface.

Name Description

ActiveConnection

Returns the currently active Microsoft® ActiveX® Data Objects (ADO) Connection object.

IsDirty

Specifies whether or not the local data has been altered since the last save to the currently bound data source.

Source

The reference to the currently bound object.

SourceClass

The name of the interface used to bind the currently bound object.

SourceURL

The URL of the currently bound item within the Active Directory® directory service or the Exchange store.

The following table lists the methods of the IDataSource interface.

Name Description

Open

Binds to and opens data from the existing item specified by the URL.

OpenObject

Binds to and opens data from the specified object.

Save

Saves data into the currently bound data source.

SaveTo

Binds to and saves data into the item with the specified URL.

SaveToContainer

Binds to and saves data into a new item in the folder/container specified by URL. The item name is a generated globally unique identifier (GUID).

SaveToObject

Binds to and saves data into the specified object.

Remarks

Objects expose implementations of the IDataSource interface to facilitate easy access to content (data) in other Collaboration Data Objects (CDO), ADO and Active Directory objects, and items in the Exchange store. For example, the Message object exposes an implementation of the IDataSource interface.

Two aspects are associated with using the IDataSource interface on objects:

  • Binding. Certain methods create an association, or linkage between the target item or object and the binding object. For example, when you use the Open method, you bind to a resource in the Exchange store or Active Directory. This binding (association) remains active until the object is subsequently rebound, unbound, or destroyed. While bound, various operations such as Save or IsDirty act on (or in relation to) the currently bound resource or object.
  • Directional Transfer of Data. Methods on the IDataSource are verbs that imply a direction of data flow. After binding to an object, these operations are then carried out. For example, the OpenObject method first binds the specified object, and then retrieves the serialized content contained within the bound object into the opening object. The process is analogous for the Open method. The SaveToObject, SaveTo, and SaveToContainer methods first bind to the specified object or resource, and then transfer local content into the target.

Opening other objects and resources is completely analogous to using Microsoft? Word to open its .doc files: when you "Open" a .doc file, the file is "bound" and the contents copied into the opening application. Subsequent "Save" commands overwrite the file contents with the local copy of data. When another file is opened or the user chooses Save As, the application rebinds to the new file and the appropriate data transfer occurs, either to or from the acting application. Save commands now act on the newly bound file. When a user closes the application, local data changes may not have been saved into the currently bound file. A dialog appears, "Do you wish to save the changes you have made to file?" Changes will be lost if they are not saved.

This reference only lists the loose semantic definition and Component Object Model (COM) interface binary signature required for an implementation of the IDataSource interface. For specific information about a particular implementation, see the corresponding COM class reference page.

Examples

[Visual Basic]

' Reference to Microsoft CDO for Exchange 2000 Library
' Reference to Microsoft ActiveX Data Objects 2.5 Library

' Note: It is recommended that all input parameters be validated when they are
' first obtained from the user or user interface.
Function MoveItems(folderUrl1 As String, folderUrl2 As String)

    ' Items must be in same store for this routine to work.
    Dim Item As New CDO.Item
    Dim Fldr As New CDO.Folder
    Dim Msg As New CDO.message
    Dim CalMsg As New CDO.CalendarMessage
    Dim iAppt  As New CDO.Appointment
    Dim Per As New CDO.Person

    Dim Rec As New ADODB.Record
    Dim Rec2 As New ADODB.Record
    Dim Rs  As New ADODB.Recordset
    Dim Conn As New ADODB.Connection

    Conn.Provider = "ExOLEDb.DataSource"
    Conn.Open folderUrl1

    Rec.Open folderUrl1, Conn
    ' Error check here

    ' This is very expensive for very large folders!
    Set Rs = Rec.GetChildren
    While Not Rs.EOF
        Rec2.Open Rs, Conn, adModeReadWrite, adFailIfNotExists
        Select Case Rec2.Fields("DAV:contentclass")
            Case "urn:content-classes:message":
                Debug.Print "Message"
                Msg.DataSource.OpenObject Rec2, "_Record"
                Debug.Print "To: " & Msg.To
                Debug.Print "From:: " & Msg.From
                Debug.Print "Subject: " & Msg.Subject
                Debug.Print vbCrLf & Msg.TextBody
                Debug.Print vbCrLf & Msg.Attachments.Count & " Attachments"
                Msg.DataSource.SaveToContainer folderUrl2, Conn, adModeReadWrite, adCreateNonCollection
                Rec2.DeleteRecord
                Rec2.Close

            Case "urn:content-classes:document":
                Debug.Print "Document"
                Item.DataSource.OpenObject Rec2, "_Record"
                Debug.Print Item.DisplayName
                Debug.Print Item.CreationDate
                Debug.Print Item.ContentClass

                ' This step MIME-encodes the document in the new location.
                ' Item.DataSource.SaveToContainer folderUrl2, Conn, adModeReadWrite, adCreateNonCollection
                Item.DataSource.SaveTo folderUrl2 & "/" & Item.DisplayName, Conn, adModeReadWrite, adCreateNonCollection
                Rec2.DeleteRecord
                Rec2.Close

            Case "urn:content-classes:folder":
                Debug.Print "Folder"
                Fldr.DataSource.OpenObject Rec2, "_Record"
                Debug.Print Fldr.DisplayName
                Debug.Print Fldr.ContentClass
                Debug.Print "Email address: " & Fldr.EmailAddress

                ' Must recurse here
                Dim strOrigFolder As String
                strOrigFolder = Fldr.DataSource.SourceURL
                Fldr.DataSource.SaveTo folderUrl2 & "/" & Fldr.DisplayName, Conn, adModeReadWrite, adCreateCollection
                MoveItems strOrigFolder, Fldr.DataSource.SourceURL
                Rec2.DeleteRecord
                Rec2.Close

            Case "urn:content-classes:calendarmessage":
                Debug.Print "CalendarMessage"
                CalMsg.DataSource.OpenObject Rec2, "_Record"
                Debug.Print "To: " & CalMsg.message.To
                Debug.Print "From:: " & CalMsg.message.From
                Debug.Print "Subject: " & CalMsg.message.Subject
                Debug.Print vbCrLf & CalMsg.message.TextBody
                Debug.Print vbCrLf & CalMsg.CalendarParts.Count & " Calendar-related body parts."
                Debug.Print vbCrLf & CalMsg.message.Attachments.Count & " Attachments."
                CalMsg.DataSource.SaveToContainer folderUrl2, Conn, adModeReadWrite, adCreateNonCollection
                Rec2.DeleteRecord
                Rec2.Close

            Case "urn:content-classes:person":
                Debug.Print "Contact Item"
                Per.DataSource.OpenObject Rec2, "_Record"
                Debug.Print Per.FirstName
                Debug.Print Per.LastName
                Debug.Print Per.Company
                Debug.Print Per.Email
                Per.DataSource.SaveToContainer folderUrl2, Conn, adModeReadWrite, adCreateNonCollection
                Rec2.DeleteRecord
                Rec2.Close

        End Select

        If Rec2.State = adStateOpen Then
            Rec2.Close
        End If
        Rs.MoveNext
    Wend

' Clean up.
Conn.Close
Rec.Close
Rec2.Close
Rs.Close

Set Conn = Nothing
Set Rec = Nothing
Set Rec2 = Nothing
Set Rs = Nothing

End Function

[C++,IDL]


// You must have the following paths in your
// INCLUDE path.
// %CommonProgramFiles%\system\ado
// %CommonProgramFiles%\microsoft shared\cdo

#ifndef _CORE_EXAMPLE_HEADERS_INCLUDED
#define _CORE_EXAMPLE_HEADERS_INCLUDED
#import <msado15.dll> no_namespace
#import <cdoex.dll> no_namespace
#include <iostream.h>
#endif

#define BUFLEN  40

// Note: It is recommended that all input parameters be validated when they are
// first obtained from the user or user interface.
void SaveEmbeddedPartsToFolder( IMessagePtr pMsgIn, bstr_t folderURL ) {

   if(pMsgIn == NULL)
      throw _com_error(E_INVALIDARG);

   IDataSourcePtr   iDsrc;
   IDataSourcePtr  iDsrcItem;
   IItemPtr      iItem(__uuidof(Item));
   IBodyPartPtr   pBp;
   IBodyPartPtr   pBp2;
   IBodyPartsPtr   pBps;
   _ConnectionPtr   pConn(__uuidof(Connection));
   _StreamPtr      pStm;
   _StreamPtr      pStm2;
   _RecordPtr      pRec;
   FieldsPtr      pFlds;
   FieldPtr      pFld;
   long         i   =   0;
   long         nbp   =   0;

   // For optional parameters
   _variant_t      varOpt(DISP_E_PARAMNOTFOUND,VT_ERROR);


   // Use this object to extract embedded messages.

   pConn->Provider = "ExOLEDB.DataSource";
   try {
      pConn->Open(folderURL,bstr_t(),bstr_t(),-1);
   }
   catch(_com_error e) {
      throw e;
   }

   IMessagePtr Msg(__uuidof(Message));
   iDsrc = Msg;
   pBp  = pMsgIn;


   // Fetch all bodyparts below the message to scan for
   // application/octet-stream and embedded messages message/rfc822
   // (won't find "related" parts in MHTML formatted messages)

   pBps = pBp->BodyParts;
   nbp = pBps->Count;
   for(i=1;i<=nbp;i++) {

      pBp = pBps->Item[i];
      bstr_t MediaType;

      MediaType = pBp->ContentMediaType;
      if(MediaType == _bstr_t("message/rfc822")){

         cout << "Found an embedded message...saving" << endl;

         //  Extract Embedded Message
         //  (clears out the previous message)
         try {
            iDsrc->OpenObject(pBp,_bstr_t("IBodyPart"));
         }
         catch(_com_error e) {
            cerr << "Error opening message/rfc822 body part" << endl;
            throw e;
         }

         try {
            iDsrc->SaveToContainer(
                     folderURL,
                     pConn,
                     adModeReadWrite,
                     adCreateNonCollection,
                     (RecordOpenOptionsEnum) NULL,
                     bstr_t(),
                     bstr_t()
                     );
         }
         catch(_com_error e) {
            cerr << "Error saving item to container" << endl;
            throw e;
         }

         pConn = iDsrc->ActiveConnection;

         bstr_t srcURL;
         srcURL = iDsrc->SourceURL;
         cout << "Saved embedded message at " << _bstr_t(srcURL) << endl;
      }
      else if(MediaType == _bstr_t("application/msword")) {
         cout << "Found an application/msword body part" << endl;


         // Can't use SaveToContainer here.
         // The file will get MIME encoded.
         // Use SaveTo instead.

         GUID g;
         if(FAILED(CoCreateGuid(&g))) {
            cerr << "Error creating GUID" << endl;
            throw _com_error(E_FAIL);
         }
         wchar_t buf[BUFLEN];
         memset((void*)(wchar_t*)buf,0,BUFLEN);
         if( StringFromGUID2(g,(wchar_t*)buf,BUFLEN) == 0 ) {
            cerr << "Error getting string from GUID?" << endl;
            throw _com_error(E_UNEXPECTED);
         }
         cout << "Word file name: " << bstr_t(buf) << ".doc " << endl;
         try {
            iDsrcItem = iItem;
            iItem->Fields->Item["DAV:contentclass"]->Value = variant_t("urn:content-classes:document");
            iItem->Fields->Update();
            iDsrcItem->SaveTo(
                        folderURL + bstr_t(buf) + bstr_t(".doc"),
                        _variant_t((IDispatch*)pConn, true),
                        adModeReadWrite,
                        adCreateNonCollection,
                        adOpenSource,
                        bstr_t(),
                        bstr_t()
                        );
            pStm = iItem->GetStream();
            pStm2 = pBp->GetDecodedContentStream();
            pStm2->CopyTo(pStm,-1);
            pStm->Flush();

            // Must call save here for item. Stream is not committed to the
            // store until Save() is called.
            iDsrcItem->Save();

    // clean up.
    pConn->Close();
    pStm->Close();
    pStm2->Close();
    pRec->Close();

         }
         catch(_com_error e) {
            cerr << "Error saving word file to folder " << folderURL << endl;
            throw e;
         }
      }
   }
}

[VBScript]

' Type information must have been imported into the script engine,
' for example:
' <reference object="adodb.record"/>
' <reference object="cdo.message"/>
' elements in
' a Windows Script Host (.wsf) file.

Sub SaveEmbeddedPartsToFolder(iMsg, URL)

    Dim iMsgB
    Set iMsgB = CreateObject("CDO.Message")
    Dim iDsrcB
    Dim iFldr
    Dim iDsrcFldr
    Dim Conn
    Dim iBp
    Dim iBps
    Dim ContType

    Set Conn = CreateObject("ADODB.Connection")
    Conn.Provider = "ExOLEDB.DataSource"
    Conn.Open URL

    Set iDsrcFldr = iFldr
    iDsrcFldr.Open URL, Conn

    Set iDsrcB = iMsgB.DataSource

    Set iBp = iMsg.BodyPart
    Set iBps = iBp.BodyParts

    For Each iBp In iBps
        ContType = iBp.ContentMediaType
        If ContType = "message/rfc822" Then

            iDsrcB.OpenObject iBp, "IBodyPart"
            iDsrcB.SaveToContainer FolderURL, Conn, adModeReadWrite, adCreateOverwrite

        ElseIf ContType = "application/octet-stream" Then

            Dim Rec
            Set Rec = CreateObject("ADODB.Record")
            Dim Flds
            Dim Fld
            Dim Stm1
            Dim Stm2

            ' Get some unique name based on message ID, etc.
            Rec.Open FolderURL & "uniquename.x", Conn, adModeReadWrite, adCreateOverwrite
            Set Flds = Rec.Fields
            ' Get Stream for resource which is accessed using -1 in Fields collection.
            Set Fld = Flds.Item(-1)
            Set Stm1 = Fld.Value

            ' Get Decoded BodyPart stream.
            Set Stm2 = iBp.GetDecodedContentStream
            ' Copy bodypart stream to resource stream
            Stm2.CopyTo Stm1

            ' Commit
            Stm1.Flush
            Stm1.Close
            Rec.Close
    Stm2.Close

    Stm1 = Nothing
    Stm2 = Nothing
    Rec = Nothing

        End If

    Conn.Close
    Set Conn = Nothing
End Sub