Platform SDK: Exchange 2000 Server |
[This is preliminary documentation and subject to change.]
The IDataSource interface defines methods and properties used to provide access to content in other objects or in the Microsoft Exchange 2000 Web Store.
Properties
Name | Type | Description |
---|---|---|
ActiveConnection | [Visual Basic,VBScript] ADODB.Connection [C++,IDL] _Connection* |
Returns the active ADO Connection object if applicable. |
IsDirty | [Visual Basic,VBScript] Boolean [C++,IDL] VARIANT_BOOL |
Specifies whether the local data has been changed since the last data source binding or call to Save. |
Source | [Visual Basic,VBScript] Object [C++,IDL] IUnknown* |
Returns the interface on the currently bound object. |
SourceClass | [Visual Basic,VBScript] String [C++,IDL] BSTR |
Returns the string identifier of the interface used to open the object. |
SourceURL | [Visual Basic,VBScript] String [C++,IDL] BSTR |
Returns the URL of the currently bound object if applicable. |
Methods
Name | Description |
---|---|
Open | Binds to and opens the existing item specified by URL. |
OpenObject | Binds to and opens the specified object. |
Save | Saves the current data into the currently bound data source |
SaveTo | Binds to and saves data into the item specified by URL. |
SaveToContainer | Binds to and saves data into a new item in the folder specified by URL. The item name is a generated globally unique identifier (GUID). |
SaveToObject | Binds to and saves data into the specified object. |
Objects expose implementations of the IDataSource interface to facilitate easy access to content (data) in other CDO, ADO and Active Directory objects, and items in the Microsoft Exchange 2000 Web Store. For example, the Message object exposes an implementation of the IDataSource interface.
There are two aspects associated with using the IDataSource interface on objects:
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 would of course be lost if the changes are not saved.
This reference only lists the loose semantic definition and 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.
Sub SaveEmbeddedPartsToFolder(iMsg As CDO.Message, URL As String) Dim iMsgB As New Message Dim iDsrcB As CDO.IDataSource Dim iFldr As New Folder Dim iDsrcFldr As CDO.IDataSource Dim Conn As ADODB.Connection Dim iBp As IBodyPart Dim iBps As IBodyParts Dim ContType As String Set iDsrcFldr = iFldr iDsrcFldr.Open URL Set Conn = iDsrcFldr.ActiveConnection Set iDsrcB = iMsgB Set iBp = iMsg 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 Debug.Print "Saved message has URL " & iDsrcB.SourceURL ElseIf ContType = "application/octet-stream" Then Dim Rec As New Record Dim Flds As ADODB.Fields Dim Fld As ADODB.Field Dim Stm1 As Stream Dim Stm2 As Stream '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 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 Debug.Print "Saved app/oct stream a URL " & FolderURL & "uniquename.x" End If Next iBp End Sub
HRESULT SaveEmbeddedPartsToFolder( IMessage* pMsgIn, BSTR FolderURL ) { /* Assume these headers: * * #import <msado15.dll> no_namespace raw_interfaces_only * #import <cdoex.dll> no_namespace raw_interfaces_only * #include <iostream.h> * */ if(pMsgIn == NULL) return E_INVALIDARG; IDataSourcePtr iDsrc; IBodyPart* pBp = NULL; IBodyPart* pBp2 = NULL; IBodyParts* pBps = NULL; _Connection* pConn = NULL; _Stream* pStm = NULL; _Stream* pStm2 = NULL; _Record* pRec = NULL; Fields* pFlds = NULL; Field* pFld = NULL; long i = 0; long count = 0; // for optional params _variant_t varOpt(DISP_E_PARAMNOTFOUND,VT_ERROR); HRESULT hr = S_OK; /* * use this object to extract embedded messags */ IMessagePtr Msg(__uuidof(Message)); iDsrc = Msg; /* * Use Folder to open specified/passed URL */ IFolder* pFldr = NULL; IDataSource* pDsrcFldr = NULL; _bstr_t bstrEmpty(""); hr = CoCreateInstance(__uuidof(Folder), NULL, CLSCTX_INPROC_SERVER, __uuidof(IDataSource), reinterpret_cast<void**>(&pDsrcFldr)); hr = pDsrcFldr->Open( _bstr_t(FolderURL), NULL, (ConnectModeEnum)NULL, adFailIfNotExists, adOpenSource, bstrEmpty, bstrEmpty ); if(FAILED(hr)) { cerr << "Error opening folder:" << _bstr_t(FolderURL) << endl; goto exit; } hr = pDsrcFldr->get_ActiveConnection(&pConn); /* ** Loop through passed Message, looking for embedded messages * and attachments ** (error checking removed for clarity) */ hr = pMsgIn->QueryInterface(__uuidof(IBodyPart),reinterpret_cast<void**>(&pBp)); /* * fetch all bodyparts below message to scan for application/octet-stream * and embedded messages message/rfc822 * (won't find "related" parts in MHTML formmatted messages) */ hr = pBp->get_BodyParts(&pBps); hr = pBp->Release(); pBp = NULL; pBps->get_Count(&count); for(i=1;i<=count;i++) { pBps->get_Item(i,&pBp); BSTR MediaType; pBp->get_ContentMediaType(&MediaType); if(_bstr_t(MediaType) == _bstr_t("message/rfc822")){ cout << "Found an embedded message...saving" << endl; /* * Extract Embedded Message * (clears previous message out) */ hr = iDsrc->raw_OpenObject(pBp,_bstr_t("IBodyPart")); if(FAILED(hr)) { cerr << "Failed to extract message!" << endl; goto exit; } /* * Save to some folder in a private Web Store * such as file://backofficestorage/domain.microsoft.com/store/scanattachments/" * (the file name will be like {GUID}.eml */ /* * Use available ActiveConnection in pConn * to save the Message to the container (folder) */ hr = iDsrc->raw_SaveToContainer( _bstr_t(FolderURL), pConn, adModeReadWrite, adCreateOverwrite, (RecordOpenOptionsEnum) NULL, NULL, NULL ); if(FAILED(hr)) { cerr << "Error saving message to folder:" << _bstr_t(FolderURL) << endl; goto exit; } pBp->Release(); pBp = NULL; BSTR srcURL; hr = iDsrc->get_SourceURL(&srcURL); if(FAILED(hr)) { cerr << "Failed getting source URL " << endl; goto exit; } cout << "Saved embedded message at " << _bstr_t(srcURL) << endl; SysFreeString(srcURL); } else if(_bstr_t(MediaType) == _bstr_t("application/msword")) { cout << "Found an application/msword body part" << endl; hr = CoCreateInstance( __uuidof(Record), NULL, CLSCTX_INPROC_SERVER, __uuidof(_Record), reinterpret_cast<void**>(&pRec)); _bstr_t newURL = _bstr_t(FolderURL) + _bstr_t("savedwordfile.doc"); hr = pRec->raw_Open( _variant_t(newURL), varOpt, adModeReadWrite, adCreateOverwrite, (RecordOpenOptionsEnum) adOpenSource, NULL, NULL ); if(FAILED(hr)) { cerr << "Failed to create Record for new item" << endl; goto exit; } hr = pRec->get_Fields(&pFlds); hr = pFlds->get_Item(_variant_t((long)adDefaultStream),&pFld); if(FAILED(hr)) { cerr << "failed to get Default Stream Field for Record" << endl; goto exit; } pFlds->Release(); VARIANT varVal; VariantInit(&varVal); hr = pFld->get_Value(&varVal); pFld->Release(); IDispatch* pDisp = NULL; if( varVal.vt == VT_DISPATCH) { pDisp = varVal.pdispVal; hr = pDisp->QueryInterface(__uuidof(_Stream),reinterpret_cast<void**>(&pStm)); pDisp->Release(); } else { cerr << "Value is not a stream object" << endl; goto exit; } hr = pBp->raw_GetDecodedContentStream(&pStm2); if(FAILED(hr)) { cerr << "failed to get stream for bodypart" << endl; goto exit; } hr = pStm->put_Type(adTypeBinary); hr = pStm2->CopyTo(pStm,-1); if(FAILED(hr)) { cerr << "failed to copy stream" << endl; cout << hex << hr << endl; goto exit; } pStm->Flush(); pStm->Close(); pRec->Close(); pRec->Release(); pStm2->Release(); pStm2 = NULL; pStm->Release(); pStm = NULL; } } exit: if(pDsrcFldr) pDsrcFldr->Release(); if(pBp) pBp->Release(); if(pBps) pBps->Release(); return hr; }
Sub SaveEmbeddedPartsToFolder(iMsg, URL) Const adModeRead = 1 Const adModeReadWrite = 3 Const adCreateOverwrite = 67108864 Dim iMsgB Set iMsgB = CreateObject("CDO.Message") Dim iDsrcB Dim iFldr Dim iDsrcFldr Dim Conn Dim iBp Dim iBps Dim ContType Set iDsrcFldr = iFldr iDsrcFldr.Open URL Set Conn = iDsrcFldr.ActiveConnection Set iDsrcB = iMsgB Set iBp = iMsg 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 End If Next End Sub