|
Hi,
Great article. I prefer OE for email but it's spam filtering is worthless. I'm looking for articles like this to get me started on writing OE plugins so that I can make my own. Thanks.
But, how do you implement drag/drop of messages? I've previously written an OE app which processed messages but the user has to drag-n-drop the messages to a folder and then the files to the app. I would like to allow them to drag-n-drop the messages staright from OE to the app.
Thanks a lot.
--
Synetech
|
|
|
|
|
thanks for your a very use full app
i would like to load all messages programmatically from my mailbox yahoo;
as I do with menu item "receive&send" email in outlook,
is-it possible ? Witch interface to invoke ?
sorry for my bad english,
tanks so much.
-- modified at 1:04 Wednesday 19th July, 2006
|
|
|
|
|
This is a great artical, probably the best artical I found so far related to outlook express.
I'd like to add a menu to outlook express. Any suggestions?
Thanks.
--Yajun
|
|
|
|
|
Hi,
You have to run your code inside OE process. See PGP example to know how it can be achieved.
I have never added an additional menu in OE 6, I know that it can be done in OE 5 because PGP did it.
Regards,
Pablo Yabo.
|
|
|
|
|
Hi Yajun,
You can reference here if you haven't done yet.
Best regards,
soricere_vn
|
|
|
|
|
Is there an efficient method of determining if a email message contains any attachments?
According to the documentation dwFlags in the MESSAGEPROPS specifies the state of the message. One of the states is IMF_ATTACHMENTS - Indicates that the message has attachments. Unfortunately every message dwFlags is zero?
Thanks in advance.
Danny
|
|
|
|
|
Hi,
You can use IMimeMessage::GetAttachments to list all body handles that are attachments.
Regards,
Pablo Yabo.
|
|
|
|
|
Hi Pablo,
Yes but I am trying to obtain this information efficiently.
Basically I would like to list all the messages in a folder. Similar to Outlook Express it would be nice to indicate in the email has any attachments. I don't need any details of the attachments, only if some exists.
Thanks,
Danny
|
|
|
|
|
We need to automate the outlook express 6 for reading folders etc. We could not get any good article than yours. The article is very good.
how can this be carried out using Visual Basic 6.0? Can we reference your code from VB?
any help on this is appreciated.
kram
|
|
|
|
|
I'm not and expert of VB. I think that you can use it only if you know internals. I know someone that made it work with VB but I didn't see that code.
The problem is that you have to force VB to use the VTable that is in the header file because the typelibrary is not registered.
Pablo
|
|
|
|
|
Hi,
I'm currently programming a win32 service and need to retrieve local user(s) OE folders and message.
But when I execute your code from within my service it only retrieve System's user folders (default OE folders). Is there a way to specify that we want to access another user's folders. Please give me hints or tell me I can't do it !
Thanks a lot.
|
|
|
|
|
Hi,
The problem using this code from a service is that OE data is owned by each user and your service should be running as SYSTEM user and it's not related to any user and you cannot choose the user using OE API.
Regards,
Pablo Yabo.
|
|
|
|
|
Ok, that was what i thought.
So, there isn't any way to choose the user with this API.
Thank for your reply !
|
|
|
|
|
I think you can try to use another interface - IMessageStore. You can initialize it using the absolute path (in terms of file system) to the folder which contains the .dbx files. For example (on my machine) it is "C:\Documents and Settings\Alexey\Local Settings\Application Data\Identities\{<some_guid>}\Microsoft\Outlook Express". After proper initialization you will have access to whole tree of OE's folders located in this file folder.
You can get the instance using simple call of CoCreateInstance:
IMessageStore* p_store = NULL;
...
HRESULT hr = ::CoCreateInstance(CLSID_MessageStore,NULL,CLSCTX_INPROC_SERVER,IID_IMessageStore,(void**)&store );
if (FAILED(hr) || (p_store == NULL)) return E_FAIL;
hr = p_store->Initialize(sz_path_to_dbx_folder);
...
Then you can use member functions:
EnumChildren - to enumerate folders,
OpenFolder - to open folder,
OpenSpecialFolder... and so on.
They works very like the ones from IStoreNamespace (actually these members of IStoreNamespace delegate their calls to IMessageStore). If you see, for example, OpenFolder (in difference with such member from IStoreNamespace) returns the pointer to IMessageFolder, instead of IStoreFolder - and also wait for parameter IMessageServer.
Actually you can use IMessageFolder as more general version of IStoreFolder.
hm... I think I can summ the knowledge of internal OE structures into standalone article here on CodeProject, how you think? :->
Below is the necessary declarations (they are non-official - so, it may contain misstypes; be careful!)
<br />
DEFINE_GUID(CLSID_MessageStore, 0x101A8FB9, 0xF1B9, 0x11d1, 0x9A, 0x56, 0x0, 0xC0, 0x4F, 0xA3, 0x09, 0xD4);<br />
<br />
DEFINE_GUID(IID_IMessageStore, 0xE883FC75, 0xEC08, 0x11D1, 0x9A, 0x53, 0x0, 0xC0, 0x4F, 0xA3, 0x09, 0xD4);<br />
<br />
struct tagMESSAGEINFO;<br />
typedef tagMESSAGEINFO MESSAGEINFO, __RPC_FAR *LPMESSAGEINFO;<br />
<br />
struct tagFINDINFO;<br />
struct tagGETCOUNTTYPE;<br />
struct tagAPPLYCHILDRENTYPE;<br />
struct tagMARK_TYPE;<br />
struct tagFOLDERSORTINFO;<br />
struct tagGETNEXTTYPE;<br />
struct tagROWMESSAGETYPE;<br />
struct tagRELATIVEROWTYPE;<br />
struct tagFINDNEXTFLAGS;<br />
struct tagFOLDER_OPTIONS;<br />
<br />
interface IListSelector;<br />
interface IMessageServer;<br />
interface IMessageTableNotify;<br />
<br />
typedef DWORD MESSAGEID__;<br />
typedef unsigned long FOLDERID__;<br />
typedef DWORD tagADJUSTFLAGS;<br />
<br />
interface IStoreCallback : public IUnknown<br />
{<br />
};<br />
<br />
struct HLOCK__;<br />
struct tagTABLEINDEX;<br />
struct tagRESULTLIST;<br />
struct tagFOLDERINFO;<br />
struct HROWSET__;<br />
struct HTRANSACTION__;<br />
typedef unsigned short ushort;<br />
typedef unsigned char uchar;<br />
<br />
interface IDatabaseNotify;<br />
interface IDatabaseProgress;<br />
interface IDatabase;<br />
interface IEnumerateFolders;<br />
interface IImnAccount;<br />
<br />
interface IMessageFolder;<br />
<br />
interface IMessageStore : public IUnknown<br />
{<br />
virtual HRESULT STDMETHODCALLTYPE Lock(HLOCK__ * *);<br />
virtual HRESULT STDMETHODCALLTYPE Unlock(HLOCK__ * *);<br />
virtual HRESULT STDMETHODCALLTYPE InsertRecord(void *);<br />
virtual HRESULT STDMETHODCALLTYPE UpdateRecord(void *);<br />
virtual HRESULT STDMETHODCALLTYPE DeleteRecord(void *);<br />
virtual HRESULT STDMETHODCALLTYPE FindRecord(unsigned long,unsigned long,void *,unsigned long *);<br />
virtual HRESULT STDMETHODCALLTYPE GetRowOrdinal(unsigned long,void *,unsigned long *);<br />
virtual HRESULT STDMETHODCALLTYPE FreeRecord(void *);<br />
virtual HRESULT STDMETHODCALLTYPE GetUserData(void *,unsigned long);<br />
virtual HRESULT STDMETHODCALLTYPE SetUserData(void *,unsigned long);<br />
virtual HRESULT STDMETHODCALLTYPE GetRecordCount(unsigned long,unsigned long *);<br />
virtual HRESULT STDMETHODCALLTYPE GetIndexInfo(unsigned long,char * *,struct tagTABLEINDEX *);<br />
virtual HRESULT STDMETHODCALLTYPE ModifyIndex(unsigned long,char const *,struct tagTABLEINDEX const *);<br />
virtual HRESULT STDMETHODCALLTYPE DeleteIndex(unsigned long);<br />
virtual HRESULT STDMETHODCALLTYPE CreateRowset(unsigned long,unsigned long,struct HROWSET__ * *);<br />
virtual HRESULT STDMETHODCALLTYPE SeekRowset(struct HROWSET__ *,enum tagSEEKROWSETTYPE,long,unsigned long *);<br />
virtual HRESULT STDMETHODCALLTYPE QueryRowset(struct HROWSET__ *,long,void * *,unsigned long *);<br />
virtual HRESULT STDMETHODCALLTYPE CloseRowset(struct HROWSET__ * *);<br />
virtual HRESULT STDMETHODCALLTYPE CreateStream(unsigned long *);<br />
virtual HRESULT STDMETHODCALLTYPE DeleteStream(unsigned long);<br />
virtual HRESULT STDMETHODCALLTYPE CopyStream(struct IDatabase *,unsigned long,unsigned long *);<br />
virtual HRESULT STDMETHODCALLTYPE OpenStream(enum tagACCESSTYPE,unsigned long,struct IStream * *);<br />
virtual HRESULT STDMETHODCALLTYPE ChangeStreamLock(struct IStream *,enum tagACCESSTYPE);<br />
virtual HRESULT STDMETHODCALLTYPE RegisterNotify(unsigned long,unsigned long,unsigned long,IDatabaseNotify *);<br />
virtual HRESULT STDMETHODCALLTYPE DispatchNotify(struct IDatabaseNotify *);<br />
virtual HRESULT STDMETHODCALLTYPE SuspendNotify(struct IDatabaseNotify *);<br />
virtual HRESULT STDMETHODCALLTYPE ResumeNotify(struct IDatabaseNotify *);<br />
virtual HRESULT STDMETHODCALLTYPE UnregisterNotify(struct IDatabaseNotify *);<br />
virtual HRESULT STDMETHODCALLTYPE LockNotify(unsigned long,struct HLOCK__ * *);<br />
virtual HRESULT STDMETHODCALLTYPE UnlockNotify(struct HLOCK__ * *);<br />
virtual HRESULT STDMETHODCALLTYPE GetTransaction(struct HTRANSACTION__ * *,enum tagTRANSACTIONTYPE *,void *,void *,unsigned long *,struct tagORDINALLIST *);<br />
virtual HRESULT STDMETHODCALLTYPE MoveFileA(unsigned short const *);<br />
virtual HRESULT STDMETHODCALLTYPE SetSize(unsigned long);<br />
virtual HRESULT STDMETHODCALLTYPE Repair(void);<br />
virtual HRESULT STDMETHODCALLTYPE Compact(struct IDatabaseProgress *,unsigned long);<br />
virtual HRESULT STDMETHODCALLTYPE HeapAllocate(unsigned long,unsigned long,void * *);<br />
virtual HRESULT STDMETHODCALLTYPE HeapFree(void *);<br />
virtual HRESULT STDMETHODCALLTYPE GenerateId(unsigned long *);<br />
virtual HRESULT STDMETHODCALLTYPE GetClientCount(unsigned long *);<br />
virtual HRESULT STDMETHODCALLTYPE GetFile(unsigned short * *);<br />
virtual HRESULT STDMETHODCALLTYPE GetSize(unsigned long *,unsigned long *,unsigned long *,unsigned long *);<br />
virtual HRESULT STDMETHODCALLTYPE Initialize(LPCSTR pszPath);<br />
virtual HRESULT STDMETHODCALLTYPE Validate(unsigned long);<br />
virtual HRESULT STDMETHODCALLTYPE GetDirectory(int,LPSTR lpString1,int iMaxLength);<br />
virtual HRESULT STDMETHODCALLTYPE Synchronize(FOLDERID__ *,unsigned long,struct IStoreCallback *);<br />
virtual HRESULT STDMETHODCALLTYPE FindServerId(char const *,FOLDERID__ * *);<br />
virtual HRESULT STDMETHODCALLTYPE CreateServer(IImnAccount *,ULONG,FOLDERID__ * *);<br />
virtual HRESULT STDMETHODCALLTYPE CreateFolder(ULONG,tagFOLDERINFO *,IStoreCallback *);<br />
virtual HRESULT STDMETHODCALLTYPE OpenSpecialFolder(FOLDERID__ *,IMessageServer *,uchar,IMessageFolder**);<br />
virtual HRESULT STDMETHODCALLTYPE OpenFolder(FOLDERID__ *,IMessageServer *,ULONG,IMessageFolder**);<br />
virtual HRESULT STDMETHODCALLTYPE MoveFolder(FOLDERID__ *,FOLDERID__ *,ULONG,IStoreCallback *);<br />
virtual HRESULT STDMETHODCALLTYPE RenameFolder(FOLDERID__ *,char const *,ULONG,IStoreCallback *);<br />
virtual HRESULT STDMETHODCALLTYPE DeleteFolder(FOLDERID__ *,ULONG,IStoreCallback *);<br />
virtual HRESULT STDMETHODCALLTYPE GetFolderInfo(FOLDERID__ *,tagFOLDERINFO *);<br />
virtual HRESULT STDMETHODCALLTYPE GetSpecialFolderInfo(FOLDERID__ *,uchar,tagFOLDERINFO *);<br />
virtual HRESULT STDMETHODCALLTYPE SubscribeToFolder(FOLDERID__ *,int,IStoreCallback *);<br />
virtual HRESULT STDMETHODCALLTYPE HrSetNoSecUICallback(ULONG,long (*)(ULONG));<br />
virtual HRESULT STDMETHODCALLTYPE UpdateFolderCounts(FOLDERID__ *,long,long,long,long);<br />
virtual HRESULT STDMETHODCALLTYPE EnumChildren(FOLDERID__ *,int,IEnumerateFolders **);<br />
virtual HRESULT STDMETHODCALLTYPE GetAdvise(ULONG *,ULONG *,IAdviseSink * *);<br />
};<br />
<br />
interface IMessageFolder : public IUnknown<br />
{<br />
virtual HRESULT STDMETHODCALLTYPE Lock(HLOCK__ * *);<br />
virtual HRESULT STDMETHODCALLTYPE Unlock(HLOCK__ * *);<br />
virtual HRESULT STDMETHODCALLTYPE InsertRecord(void *);<br />
virtual HRESULT STDMETHODCALLTYPE UpdateRecord(void *);<br />
virtual HRESULT STDMETHODCALLTYPE DeleteRecord(void *);<br />
virtual HRESULT STDMETHODCALLTYPE FindRecord(ULONG,ULONG,void *,ULONG *);<br />
virtual HRESULT STDMETHODCALLTYPE GetRowOrdinal(ULONG,void *,ULONG *);<br />
virtual HRESULT STDMETHODCALLTYPE FreeRecord(void *);<br />
virtual HRESULT STDMETHODCALLTYPE GetUserData(void *,ULONG);<br />
virtual HRESULT STDMETHODCALLTYPE SetUserData(void *,ULONG);<br />
virtual HRESULT STDMETHODCALLTYPE GetRecordCount(ULONG,ULONG *);<br />
virtual HRESULT STDMETHODCALLTYPE GetIndexInfo(ULONG,char * *,tagTABLEINDEX *);<br />
virtual HRESULT STDMETHODCALLTYPE ModifyIndex(ULONG,char const *,tagTABLEINDEX const *);<br />
virtual HRESULT STDMETHODCALLTYPE DeleteIndex(ULONG);<br />
virtual HRESULT STDMETHODCALLTYPE CreateRowset(ULONG,ULONG,HROWSET__ * *);<br />
virtual HRESULT STDMETHODCALLTYPE SeekRowset(HROWSET__ *,tagSEEKROWSETTYPE,long,ULONG *);<br />
virtual HRESULT STDMETHODCALLTYPE QueryRowset(HROWSET__ *,long,void * *,ULONG *);<br />
virtual HRESULT STDMETHODCALLTYPE CloseRowset(HROWSET__ * *);<br />
virtual HRESULT STDMETHODCALLTYPE CreateStream(ULONG *);<br />
virtual HRESULT STDMETHODCALLTYPE DeleteStream(ULONG);<br />
virtual HRESULT STDMETHODCALLTYPE CopyStream(IDatabase *,ULONG,ULONG *);<br />
virtual HRESULT STDMETHODCALLTYPE OpenStream(tagACCESSTYPE,ULONG,IStream * *);<br />
virtual HRESULT STDMETHODCALLTYPE ChangeStreamLock(IStream *,tagACCESSTYPE);<br />
virtual HRESULT STDMETHODCALLTYPE RegisterNotify(ULONG,ULONG,ULONG,IDatabaseNotify *);<br />
virtual HRESULT STDMETHODCALLTYPE DispatchNotify(IDatabaseNotify *);<br />
virtual HRESULT STDMETHODCALLTYPE SuspendNotify(IDatabaseNotify *);<br />
virtual HRESULT STDMETHODCALLTYPE ResumeNotify(IDatabaseNotify *);<br />
virtual HRESULT STDMETHODCALLTYPE UnregisterNotify(IDatabaseNotify *);<br />
virtual HRESULT STDMETHODCALLTYPE LockNotify(ULONG,HLOCK__ * *);<br />
virtual HRESULT STDMETHODCALLTYPE UnlockNotify(HLOCK__ * *);<br />
virtual HRESULT STDMETHODCALLTYPE GetTransaction(HTRANSACTION__ * *,tagTRANSACTIONTYPE *,void *,void *,ULONG *,tagORDINALLIST *);<br />
virtual HRESULT STDMETHODCALLTYPE MoveFileA(ushort const *);<br />
virtual HRESULT STDMETHODCALLTYPE SetSize(ULONG);<br />
virtual HRESULT STDMETHODCALLTYPE Repair(void);<br />
virtual HRESULT STDMETHODCALLTYPE Compact(IDatabaseProgress *,ULONG);<br />
virtual HRESULT STDMETHODCALLTYPE HeapAllocate(ULONG,ULONG,void * *);<br />
virtual HRESULT STDMETHODCALLTYPE HeapFree(void *);<br />
virtual HRESULT STDMETHODCALLTYPE GenerateId(ULONG *);<br />
virtual HRESULT STDMETHODCALLTYPE GetClientCount(ULONG *);<br />
virtual HRESULT STDMETHODCALLTYPE GetFile(ushort * *);<br />
virtual HRESULT STDMETHODCALLTYPE GetSize(ULONG *,ULONG *,ULONG *,ULONG *);<br />
virtual HRESULT STDMETHODCALLTYPE Initialize(IMessageStore *,IMessageServer *,ULONG,FOLDERID__ *);<br />
virtual HRESULT STDMETHODCALLTYPE ContextSensitiveHelp(int);<br />
virtual HRESULT STDMETHODCALLTYPE UpdateRegistry(int);<br />
virtual HRESULT STDMETHODCALLTYPE GetFolderId(FOLDERID__ * *);<br />
virtual HRESULT STDMETHODCALLTYPE GetMessageFolderId(MESSAGEID__ *,FOLDERID__ * *);<br />
virtual HRESULT STDMETHODCALLTYPE GetAdvise(ULONG *,ULONG *,IAdviseSink * *);<br />
virtual HRESULT STDMETHODCALLTYPE OpenMessage(MESSAGEID__ *,ULONG,IMimeMessage * *,IStoreCallback *);<br />
virtual HRESULT STDMETHODCALLTYPE SaveMessage(MESSAGEID__ * *,ULONG,ULONG,IStream *,IMimeMessage *,IStoreCallback *);<br />
virtual HRESULT STDMETHODCALLTYPE HrSetNoSecUICallback(ULONG,long (*)(ULONG));<br />
virtual HRESULT STDMETHODCALLTYPE SetMessageFlags(tagMESSAGEIDLIST *,tagADJUSTFLAGS *,tagRESULTLIST *,IStoreCallback *);<br />
virtual HRESULT STDMETHODCALLTYPE CopyMessages(IMessageFolder *,ULONG,tagMESSAGEIDLIST *,tagADJUSTFLAGS *,tagRESULTLIST *,IStoreCallback *);<br />
virtual HRESULT STDMETHODCALLTYPE DeleteMessages(ULONG,tagMESSAGEIDLIST *,tagRESULTLIST *,IStoreCallback *);<br />
virtual HRESULT STDMETHODCALLTYPE ResetFolderCounts(ULONG,ULONG,ULONG,ULONG);<br />
virtual HRESULT STDMETHODCALLTYPE IsWatched(char const *,char const *);<br />
virtual HRESULT STDMETHODCALLTYPE GetDatabase(IDatabase * *);<br />
virtual HRESULT STDMETHODCALLTYPE ConnectionRelease(void);<br />
virtual HRESULT STDMETHODCALLTYPE ConnectionRelease1(void);<br />
virtual HRESULT STDMETHODCALLTYPE ContextSensitiveHelp1(int);<br />
};<br />
|
|
|
|
|
Hi,
Thanks for given declaration, it very helpful
for me.
Have you any idea about clsid and IID for IMessageList
in Windows Mail for Windows Vista?
|
|
|
|
|
Hi Pablo, great article
I want to extract the attachments from the e-mails and for this I'm using IMimeBody interface. Until here no problem I was able to extract them successfully.
The problems occurs when I'm using the UNICODE version of my program. I'm not able to get the filenames correctly. Do I have to use the UNICODE version of the interface IMimeBody - IMimeBodyW? If so do you in which header is declared? It seems that is not in the mimeole.h. Or do I have to find a newer version of this header.
Thanks,
|
|
|
|
|
Sorry, I am not Pablo...
Which filenames you are not able to get correctly? I didn't find any filenames in methods of IMimeBody, except the one in "SaveToFile" method.
I don't think that any IMimeBodyW exists - since this is COM-interface, not the WIN API function which can be substituted with different acronyms conditionally from the UNICODE macro definition.
Here you have only one IMimeBody with it's own IID. And it gives you the data encoded according different RFC docs, not according your current unicode settings. So, I think you just ought to use such things as MultiByteToWideChar (or OLE macro for it - a2w)
|
|
|
|
|
Hi there,
thanks for your reply
Here is the link for description of IMimeBodyW
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/outlookexpress/oe/reference/ifaces/imimebodyw/imimebodyw.asp
It has method that is getting the name of the body, in this case the attachment -
LPSTR pString;
pMimeBody->GetDisplayName( &pString );
The thing is the parameter of GetDisplayName is a pointer to LPSTR and I need a LPWSTR. Anyway I will try with A2W to see if the chars will be converted
Thanks
|
|
|
|
|
This is a great article.
Can anybody give me an idea to get the selected message Id to get all the information for the e-mail selected in Inbox or any other folder selected.
Thanks in advance.
Advaitha P
|
|
|
|
|
The interaction with user is totally another issue - and I think this is the very reason why Pablo's OEAPI exists.
Internally OE doesn't use IStoreNamespace and IStoreFolder, but instead it uses IMessageFolder and IMessageTable. The last one represents the view for list of messages you currently see on the screen - and using it's method GetSelectedRows you can get the list of selected/focused messages. All works perfectly with one exception - the instance of IMessageTable which contains information you need is own by OE itself, and you can't access it easy way from the outside.
The most popular method to get such info is so-called "mirroring". You must instantiate the copy of IMessageFolder (you can do it using CoCreateInstance with CLSID {233A9692-667E-11D1-9DFB-006097D50408} and IID {DE89B950-A597-11D1-9E46-006097D50408}) - then get from it the copy of IMessageTable. Then you must get from the registry the sort order of columns which OE itself uses to display the list - and finally you must hook all events which can change this sort order (for example, clicking on headers of listview and etc.). By this you will have your own copy of IMessageTable sinchronyzed with one which OE uses in this very moment - and by hooking selected elements from displayed messagelist you can actually get the MessageIDs corresponded to them.
This method is very stupid and require a mass of low-level coding, but it works.
The declarations of IMessageFolder and IMessageTable interfaces you can get from msoe.dll using debugging symbols from MS, and debugger - just search for "vftable" for IMessageFolder and IMessageTable and write your own header file.
|
|
|
|
|
On the way of continuing my previous post.
As you can imagine, the main problem of accessing current message list (selection, focuses) is isolation of the instance of IMessageTable which contains the data we needs.
Though the "mirroring" method of tracking this data is working, it is not so plain and easy in realization because of the mass of coding.
Another way - and I believe, it is much better for this purpose - is interface hooking.
Suppose that your application is already placed in the address space of OE. The OE itself is located in the library msoe.dll (msimn.exe is actually only loader of msoe). So, if you instantiate from your application any class which is realized in msoe, the COM will not load the second copy of msoe into the memory, but simple redirect your call to the existing instance.
And now - see how it works:
1. Instantiate IMessageFolder (using CoCreateInstance).
2. from the interface's pointer, get the address of vftable.
3. VirtualProtect at least second entry of vftable for read/write.
4. Prepare your own AddRef function using c-prototype with first parameter (which is pointer to 'this'). The function must store 'this' parameter, and then call original AddRef (and let it return it's value).
5. Patch the second entry of vftable with address of your AddRef, and restore original virtualprotect mode.
6. Release your instance of IMessageFolder.
Now you have patched the vftable of IMessageFolder with your own 'AddRef' function - so, since this interface is located in msoe, which also contains many other working objects, your releasing will not cause msoe to unload. And as a result, your hook will live and any future using of this interface will firstly invoke this your interface hook (since AddRef is essentially important part of COM) - and give you the pointer to their class ('this').
(Note, that I am describe you the simple model without any little details - actually you may want to hook also Release method and track the lifetime of your traced interfaces)
Now you will always have the weak (i.e., not "addrefed") pointer to the latest instance of IMessageFolder. And since this interface is used exclusively by OE, this pointer is the actual pointer to active messagelist.
- so, now you don't need any hooks, tracks, "mirroring" and etc. Just take this latest stored value of real IMessageFolder and get your data directly from it.
-- modified at 12:26 Thursday 6th April, 2006
|
|
|
|
|
How to create IMessageTable from IMessageFolder? IMessageFolder can be Created by using CoCreateInstance, but how to create IMessageTable?
|
|
|
|
|
AFAIK there is no easy way. IMessageFolder is the 'generic' IStoreFolder (i.e., it reprepents _any_ folder in OE, not only those in local storage, but also IMAP, NNTP and another server-based folders).
IMessageTable is simple set of 'rows' you see in OE's tree. It works together with IMessageList interface and can be gеt from it using method GetMessageTable. IMessageTable may work also with 'composite' rows - collapsed and expanded subtrees of connected messages.
However... why do you need to transform IMessageFolder to IMessageTable? Is it not enough metnods in IMessageFolder itself? Or you have a specific task especially for IMessageTable? If you work with selected messages it is more comfortable just to get the list of selected\highlighted messageids, and then work with them using any interface which may work - including IMessageFolder.
IMessageList->GetSelected - you will get list of messages
IMessageTable->GetMessageIdList - with previous list will "expand" all collapsed rows into set of messageids
then
IMessageTable->GetRowFolderId - for a message will give the folderid of it. So, you will know all message's 'coordinates': folderid and messageid.
then
IMessageStore->OpenFolder - with your folderid will make the IMessageFolder of the folder you interested in,
and finally -
IMessageFolder->CopyMessage, DeleteMessage and so on...
|
|
|
|
|
thanks for your answer rapidly.I had misreaded your means,Now the new question is I don't know IMessageList CLSID and IDD,Please tell me them or how to get them.
|
|
|
|
|
Look inside resources of msoe.dll. It is included in "reginst" section:
These values I've found there:
// {233A9692-667E-11D1-9DFB-006097D50408}
DEFINE_GUID(CLSID_MessageList, 0x233A9692, 0x667E, 0x11D1, 0x9D, 0xFB, 0x0, 0x60, 0x97, 0xD5, 0x04, 0x08);
// {DE89B950-A597-11D1-9E46-006097D50408}
DEFINE_GUID(IID_IMessageList, 0xDE89B950, 0xA597, 0x11D1, 0x9E, 0x46, 0x0, 0x60, 0x97, 0xD5, 0x04, 0x08);
|
|
|
|
|