读写 Outlook Express 中的消息






4.94/5 (42投票s)
2004年12月28日
2分钟阅读

868959

5323
本文旨在提供 IStoreNamespace
/ IStoreFolder
的示例。
目录
引言
该应用程序具有以下功能:
- 列出本地文件夹。
- 创建/重命名/删除本地文件夹。
- 列出本地文件夹中的消息。
- 获取消息属性。
- 获取消息源代码。
- 创建/复制/移动/删除消息。
- 将消息标记为已读或未读。
- 列出主体属性或头部信息。
- 获取/设置属性值。
- 导航主体结构。
- 获取/设置主体内容。
- 插入主体。
- 列出/添加/删除附件。
使用此代码
此代码编写的目的是提供 IStoreFolder
/ IStoreNamespace
类的初始示例。随后,添加了 IMimeMessage
/ IMimeMessageTree
/ IMimeBody
/ IMimePropertySet
的示例到应用程序中。本文的目的是通过一个完整的示例来记录所有这些接口,以展示如何访问 Outlook Express 存储。
在初始对话框中,列出了主身份的所有本地文件夹,以便用户修改它们。在消息对话框中,您将看到所选文件夹中的所有消息。可以在此处识别消息源和其他操作。在“主体”对话框中,您将能够查看消息结构并修改它。
关注点
列出本地文件夹
// add all the folders to the list box recursively void CDemoDlg::AddFolders(STOREFOLDERID dwFolderId) { FOLDERPROPS props; HENUMSTORE hEnum; int nIndex; hEnum = NULL; // set the size of the structure // or the function return error props.cbSize = sizeof(FOLDERPROPS); HRESULT hr = m_pStoreNamespace->GetFirstSubFolder(dwFolderId, &props, &hEnum); while(SUCCEEDED(hr) && hr != S_FALSE && hEnum != NULL) { nIndex = m_listFolder.AddString(props.szName); if(nIndex != LB_ERR && nIndex != LB_ERRSPACE) { // set the folder id as the data of the item m_listFolder.SetItemData(nIndex, props.dwFolderId); // add children of this folder too AddFolders(props.dwFolderId); } hr = m_pStoreNamespace->GetNextSubFolder(hEnum, &props); } // close the enum if(hEnum) { m_pStoreNamespace->GetSubFolderClose(hEnum); } }
列出文件夹中的消息
//List messages of folder and add //all 'Subject' and 'From' to the list box MESSAGEPROPS msgProps; HENUMSTORE hEnumMsg; CString item; int nIndex; hEnumMsg = NULL; // set the size of the structure // or the function return error msgProps.cbSize = sizeof(MESSAGEPROPS); // as we want the subject and other // staff we get all the properties. // you can use MSGPROPS_FAST as first parameter // to get only a few properties of the message. HRESULT hr = m_pStoreFolder->GetFirstMessage(0, 0, MESSAGEID_FIRST, &msgProps, &hEnumMsg); while(SUCCEEDED(hr) && hr != S_FALSE) { item = msgProps.pszDisplayFrom; item += _T(" "); item += msgProps.pszNormalSubject; // message subject and from is displayed in the list box. // data of each item is the message id. nIndex = m_listMsg.AddString(item); if(nIndex != LB_ERR && nIndex != LB_ERRSPACE) { m_listMsg.SetItemData(nIndex, msgProps.dwMessageId); } // free the message properties // as they are allocated by IStoreFolder. m_pStoreFolder->FreeMessageProps(&msgProps); hr = m_pStoreFolder->GetNextMessage(hEnumMsg, 0, &msgProps); } // close the enum if(hEnumMsg) { m_pStoreFolder->GetMessageClose(hEnumMsg); }
显示消息的源代码
// this function displays the source // of the selected message in the list box void CMsgDlg::OnView() { ULONG ulReaded = 0; int nIndex; STOREFOLDERID dwSelMsg; HRESULT hr; IStream *pTextStream; char buffer[4096]; // Get selected folder id nIndex = m_listMsg.GetCurSel(); if(nIndex == LB_ERR) { MessageBox(_T("Select a message first."), _T("Demo Error")); return; } dwSelMsg = m_listMsg.GetItemData(nIndex); // create a IStream from the message hr = m_pStoreFolder->OpenMessage(dwSelMsg, IID_IStream, (VOID **) &pTextStream); if(FAILED(hr)) { MessageBox(_T("Error opening message."), _T("Demo Error")); return; } CMsgSrcDlg msgSrcDlg; // read all the message do { hr = pTextStream->Read(buffer, sizeof(buffer)-1, &ulReaded); if(FAILED(hr)) { MessageBox(_T("Error reading message."), _T("Demo Error")); } else { buffer[ulReaded] = 0; msgSrcDlg.AddMessageSource(buffer); } } while(SUCCEEDED(hr) && ulReaded != 0); if(SUCCEEDED(hr)) { // display message msgSrcDlg.DoModal(); } pTextStream->Release(); }
在文件夹中创建消息
IStream *newMail = NULL; MESSAGEID msgId; HRESULT hr; ULONG len; CString msgSource; // Set msgSource to contain // the source of the new message ... // Create the IStream to write the new message // this function returns the id of the new message hr = m_pFolder->CreateStream(0, 0, &newMail, &msgId); if(FAILED(hr)) { MessageBox(_T("Cannot Create Stream."), _T("Demo Error")); return; } // write message source in the IStream hr = newMail->Write((const char *) msgSource, msgSource.GetLength(), &len); if(FAILED(hr)) { MessageBox(_T("Cannot Write message."), _T("Demo Error")); newMail->Release(); return; } // Commit the IStream in the folder // and use the returned msgId hr = m_pFolder->CommitStream(0, 0, 0, newMail, msgId, NULL); if(FAILED(hr)) { MessageBox(_T("Cannot Commit Stream."), _T("Demo Error")); newMail->Release(); return; } // release the IStream newMail->Release();
列出主体属性
// add property names to the combo box // first get IMimeMessage interface // using IStoreFolder and the message id. hr = pFolder->OpenMessage(msgId, IID_IMimeMessage, (LPVOID*) &m_pMimeMsg); if(FAILED(hr)) { OutputDebugString("CMessageTreeDlg::" "SetMessage: OpenMessage.\n"); return; } // get root body of the message. hr = m_pMimeMsg->GetBody(IBL_ROOT, 0, &m_hCurBody); if(FAILED(hr)) { OutputDebugString("OEMessage::SetMessage:" " Cannot get root body.\n"); return; } ... // bind the body to the IMimePropertySet interface. hr = m_pMimeMsg->BindToObject(m_hCurBody, IID_IMimePropertySet, (LPVOID *) &m_pPropertySet); if(FAILED(hr)) { OutputDebugString("OEMessage::UpdateBodyInfo:" " BindToObject IID_IMimePropertySet.\n"); return; } ... IMimeEnumProperties *pEnum = NULL; ENUMPROPERTY eProp = {0}; ULONG cFetched; HRESULT hr; m_propNames.ResetContent(); // enum properties of the body. hr = m_pPropertySet->EnumProps(0, &pEnum); if(FAILED(hr)) { OutputDebugString("OEMessage::" "FillCombo: EnumProps.\n"); return; } hr = pEnum->Next(1, &eProp, &cFetched); while(SUCCEEDED(hr) && hr != S_FALSE) { m_propNames.AddString(eProp.pszName); hr = m_pAllocator->FreeEnumPropertyArray(1, &eProp, FALSE); if(FAILED(hr)) { OutputDebugString("OEMessage::FillCombo:" " FreeEnumPropertyArray.\n"); } hr = pEnum->Next(1, &eProp, &cFetched); } if(pEnum) { pEnum->Release(); }
列出附件
ULONG attachCount, i, j; HBODY *bodyAttachs = NULL; HRESULT hr; IMimeBody *pMimeBody; LPSTR display; int nItem; m_attachs.ResetContent(); hr = m_pMimeMsg->GetAttachments(&attachCount, &bodyAttachs); if(FAILED(hr)) { MessageBox(_T("Cannot get attachments:") _T(" GetAttachments."), _T("Demo Error"), MB_OK); return; } // keep only bodies of type IBT_ATTACHMENT. for(i=0; i<attachCount;) { hr = m_pMimeMsg->IsBodyType(bodyAttachs[i], IBT_ATTACHMENT); if(hr != S_OK) { for(j=i+1; j<attachCount; j++) { bodyAttachs[j-1] = bodyAttachs[j]; } attachCount--; } else { // for the attachments, get display // name of the body to add to the listbox. hr = m_pMimeMsg->BindToObject(bodyAttachs[i], IID_IMimeBody, (LPVOID *) &pMimeBody); if(SUCCEEDED(hr)) { hr = pMimeBody->GetDisplayName(&display); if(SUCCEEDED(hr)) { nItem = m_attachs.AddString(display); m_attachs.SetItemData(nItem, (DWORD) bodyAttachs[i]); CoTaskMemFree(display); } } i++; } } if(bodyAttachs) { CoTaskMemFree(bodyAttachs); }
获取主体内容
while(1) { // just to save code! // bind body handle to a IMimeBody interface. hr = m_pMimeMsg->BindToObject(m_hCurBody, IID_IMimeBody, (LPVOID *) &pMimeBody); if(FAILED(hr)) { OutputDebugString("CMessageTreeDlg::" "UpdateBodyInfo: BindToObject\n"); break; } ... encType = IET_BINARY; m_isTextBody = FALSE; m_cntType = GetContentType(m_hCurBody); // if the body is a 'text' treat as a text. // Otherwise, read it as a buffer char // by char. if(m_cntType.Find(_T("text")) == 0) { encType = IET_UNICODE; m_isTextBody = TRUE; } ... m_bodyContent = _T(""); // Get body as a stream hr = pMimeBody->GetData(IET_UNICODE, &pBodyStream); if(FAILED(hr)) { OutputDebugString("OEMessage::GetBodyText: GetData\n"); break; } // if it is a text when we read it it comes unicode. if(encType == IET_UNICODE) { // for text bodies do { // Read the IStream into our buffer hr = pBodyStream->Read(lpszwBody, sizeof(lpszwBody)-sizeof(WCHAR), &ulRead); if(FAILED(hr)) { OutputDebugString("OEMessage::GetBodyText: Read\n"); } else if(ulRead != 0) { // Null terminate it lpszwBody[ulRead/2] = '\0'; m_bodyContent += (WCHAR *) lpszwBody; } } while(ulRead != 0); } else { do { // Read the IStream into our buffer. // It can be binary so it could // be displayed truncated. hr = pBodyStream->Read(lpszBody, sizeof(lpszBody)-sizeof(char), &ulRead); if(FAILED(hr)) { OutputDebugString("OEMessage::GetBodyText: Read\n"); } else if(ulRead != 0) { // Null terminate it lpszBody[ulRead] = '\0'; m_bodyContent += lpszBody; } } while(ulRead != 0); } pBodyStream->Release(); break; } if(pMimeBody) { pMimeBody->Release(); }
设置主体内容
HRESULT hr; ULONG ulLength, ulWritten; BSTR bstr = NULL; IStream *pStream = NULL; IMimeBody *pMimeBody = NULL; PROPVARIANT propValue; UpdateData(TRUE); while(1) { // Create a new stream to write in the new body hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream); if(FAILED(hr)) { MessageBox(_T("Cannot set content:" ) _T(" CreateStreamOnHGlobal."), _T("Demo Error"), MB_OK); break; } // compute the new body length + the // zero that terminates the string ulLength = m_bodyContent.GetLength() + 1; // there are better ways // to do it but this is the easiest bstr = m_bodyContent.AllocSysString(); // write in the new body hr = pStream->Write((LPWSTR) bstr, ulLength * sizeof(WCHAR), &ulWritten); if(FAILED(hr)) { MessageBox(_T("Cannot set content: Write."), _T("Demo Error"), MB_OK); break; } // Commit the stream hr = pStream->Commit(STGC_DEFAULT); if(FAILED(hr)) { MessageBox(_T("Cannot set content: Commit."), _T("Demo Error"), MB_OK); break; } // bind body handle to IMimeBody interface hr = m_pMimeMsg->BindToObject(m_hCurBody, IID_IMimeBody, (LPVOID *) &pMimeBody); if(FAILED(hr)) { MessageBox(_T("Cannot set content:") _T(" Commit."), _T("Demo Error"), MB_OK); break; } CString priCon, secCon; propValue.vt = VT_LPSTR; // get content-type property to save the body hr = m_pMimeMsg->GetBodyProp(m_hCurBody, PIDTOSTR(PID_HDR_CNTTYPE), 0, &propValue); if(FAILED(hr) || hr == S_FALSE) { MessageBox(_T("Cannot set content:") _T(" GetBodyProp."), _T("Demo Error"), MB_OK); break; } // this property has the format // of 'primaryType/secondaryType' char *sep = strchr(propValue.pszVal, '/'); if(sep == NULL) { MessageBox(_T("Cannot set content:") _T("Content Type error."), _T("Demo Error"), MB_OK); PropVariantClear(&propValue); break; } secCon = sep+1; *sep = 0; priCon = propValue.pszVal; PropVariantClear(&propValue); // save the data in this new stream // into the body using // the save conent-type it had before hr = pMimeBody->SetData(IET_UNICODE, priCon, secCon, IID_IStream, pStream); if(FAILED(hr)) { MessageBox(_T("Cannot set content: SetData."), _T("Demo Error"), MB_OK); break; } break; } if(bstr) { ::SysFreeString(bstr); } if(pMimeBody) { pMimeBody->Release(); } if(pStream) { pStream->Release(); }
许可证
您可以自由使用此代码,但请保留文件顶部的版权声明。
历史
- 2004年12月28日 - 首次发布:
IStoreFolder
/IStoreNamespace
。 - 2006年3月25日 - 更新:
IMimeMessage
/IMimeMessageTree
/IMimePropertySet
/IMimeBody
。