| 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