Pass Outlook.MAPIFolder to C++ Dll

G

Gabi Fruhner

Hi,

I've written a C++ Dll to get and set body of a hidden message.

I pass a Outlook.MAPIFolder to C++

STDMETHODIMP CTools::GetAdminMessage(/*[in]*/ VARIANT pFolder, /*[in]*/ long
CanCreate, /*[in]*/ BSTR* Subject, /*[out,retval]*/ BSTR* result)
{

LPUNKNOWN lpUnknown;
LPMAPIFOLDER lpFolder;
...
...

lpUnknown = getMapiObject(pFolder.pdispVal);
if (!lpUnknown) return E_NOINTERFACE;

// OL 2000 return


// OL 20020 SUCCEEDED

lpUnknown->QueryInterface(IID_IMAPIFolder, (LPVOID*) &lpFolder);
if (!lpFolder) return E_NOINTERFACE;

hr = lpFolder->GetContentsTable(MAPI_ASSOCIATED, &lpTable);

...
...

}



// Example from Internet
LPUNKNOWN CTools::getMapiObject(LPDISPATCH disp)
{
DISPID rgDispId;
DISPPARAMS dispparams = {NULL, NULL, 0, 0};
VARIANT vaResult;
LPOLESTR pName = L"MAPIOBJECT";
VariantInit(&vaResult);

if
(SUCCEEDED(disp->GetIDsOfNames(IID_NULL,&pName,1,LOCALE_SYSTEM_DEFAULT,&rgDi
spId)))
if (SUCCEEDED(disp->Invoke(rgDispId, IID_NULL, 0, DISPATCH_PROPERTYGET,
&dispparams, &vaResult, NULL, NULL)))
if (vaResult.vt == VT_UNKNOWN)
{
return vaResult.punkVal;
}

return NULL;
}


and it works fine in OL 2002, but in OL 2000 'getMapiObject' fails.

I think it is, because Outlook.MAPIFolder.MAPIOBJECT is not supported in OL
2000.

Is there another way to pass a Outlook.MAPIFolder or is there an error in my
code ?

Some code would be helpful because this is my first C++ Dll and the smallest
problem is a big problem for me.

Thanks

Gabi
 
H

Henry Gusakovsky

MAPIOBJECT property is not supported in Outlook2000.

Use MAPILogonEx to obtain shared session.
From MAPIFolder obtain EntryID property
Convert into binary. For that you can use FBinFromHex function.

After that via IMAPISession->OpenEntry() you can obtain IMAPIFolder
interface

WBR
Henry
 
D

Dmitry Streblechenko \(MVP\)

Correct. MAPIFolder.MAPIOBJECT property was introduced in Outlook 2002.
You can use the folder entry id and store id to call
IMAPISession::OpenEntry. To retrieve IMAPISession, you can either call
MAPILogonEx or retrieve it from Namespace.MAPIOBJECT (2002 and up only).

Dmitry Streblechenko (MVP)
http://www.dimastr.com/
OutlookSpy - Outlook, CDO
and MAPI Developer Tool
 
G

Gabi Fruhner

Thanks Henry and Dmitry,

because I'm new to C++ and new to MAPI I have some problems to complete my
Dll and this is making me crazy

I think I have to pass StoreID ( as BSTR ? - Mainprog is VB ) too because
there are more Stores in profile.

After hours of googling without finding any examples for this problem I
think I have to give up.
A next problem is, that in my VB App I have to read 3 named properties and
my C++ property wrapper function does not support GetNameFromIDs yet.
I will try to remove my problems 5 more days and then I will throw my
notebook on the wall and I will go to swimming bath to enjoy last few days
of summer.

Gabi


Henry Gusakovsky said:
MAPIOBJECT property is not supported in Outlook2000.

Use MAPILogonEx to obtain shared session.
From MAPIFolder obtain EntryID property
Convert into binary. For that you can use FBinFromHex function.

After that via IMAPISession->OpenEntry() you can obtain IMAPIFolder
interface

WBR
Henry
Hi,

I've written a C++ Dll to get and set body of a hidden message.

I pass a Outlook.MAPIFolder to C++

STDMETHODIMP CTools::GetAdminMessage(/*[in]*/ VARIANT pFolder, /*[in]*/ long
CanCreate, /*[in]*/ BSTR* Subject, /*[out,retval]*/ BSTR* result)
{

LPUNKNOWN lpUnknown;
LPMAPIFOLDER lpFolder;
...
...

lpUnknown = getMapiObject(pFolder.pdispVal);
if (!lpUnknown) return E_NOINTERFACE;

// OL 2000 return


// OL 20020 SUCCEEDED

lpUnknown->QueryInterface(IID_IMAPIFolder, (LPVOID*) &lpFolder);
if (!lpFolder) return E_NOINTERFACE;

hr = lpFolder->GetContentsTable(MAPI_ASSOCIATED, &lpTable);

...
...

}



// Example from Internet
LPUNKNOWN CTools::getMapiObject(LPDISPATCH disp)
{
DISPID rgDispId;
DISPPARAMS dispparams = {NULL, NULL, 0, 0};
VARIANT vaResult;
LPOLESTR pName = L"MAPIOBJECT";
VariantInit(&vaResult);

if
(SUCCEEDED(disp->GetIDsOfNames(IID_NULL,&pName,1,LOCALE_SYSTEM_DEFAULT,&rgDi
spId)))
if (SUCCEEDED(disp->Invoke(rgDispId, IID_NULL, 0, DISPATCH_PROPERTYGET,
&dispparams, &vaResult, NULL, NULL)))
if (vaResult.vt == VT_UNKNOWN)
{
return vaResult.punkVal;
}

return NULL;
}


and it works fine in OL 2002, but in OL 2000 'getMapiObject' fails.

I think it is, because Outlook.MAPIFolder.MAPIOBJECT is not supported in OL
2000.

Is there another way to pass a Outlook.MAPIFolder or is there an error
in
my
code ?

Some code would be helpful because this is my first C++ Dll and the smallest
problem is a big problem for me.

Thanks

Gabi
 
D

Dmitry Streblechenko \(MVP\)

You don't need to pass the store id if Outlook has already touched the store
in the current MAPI session.
Do you convert the entry ids from hex to binary?

Dmitry Streblechenko (MVP)
http://www.dimastr.com/
OutlookSpy - Outlook, CDO
and MAPI Developer Tool


Gabi Fruhner said:
Thanks Henry and Dmitry,

because I'm new to C++ and new to MAPI I have some problems to complete my
Dll and this is making me crazy

I think I have to pass StoreID ( as BSTR ? - Mainprog is VB ) too because
there are more Stores in profile.

After hours of googling without finding any examples for this problem I
think I have to give up.
A next problem is, that in my VB App I have to read 3 named properties and
my C++ property wrapper function does not support GetNameFromIDs yet.
I will try to remove my problems 5 more days and then I will throw my
notebook on the wall and I will go to swimming bath to enjoy last few days
of summer.

Gabi


Henry Gusakovsky said:
MAPIOBJECT property is not supported in Outlook2000.

Use MAPILogonEx to obtain shared session.
From MAPIFolder obtain EntryID property
Convert into binary. For that you can use FBinFromHex function.

After that via IMAPISession->OpenEntry() you can obtain IMAPIFolder
interface

WBR
Henry
Hi,

I've written a C++ Dll to get and set body of a hidden message.

I pass a Outlook.MAPIFolder to C++

STDMETHODIMP CTools::GetAdminMessage(/*[in]*/ VARIANT pFolder,
/*[in]*/
long
CanCreate, /*[in]*/ BSTR* Subject, /*[out,retval]*/ BSTR* result)
{

LPUNKNOWN lpUnknown;
LPMAPIFOLDER lpFolder;
...
...

lpUnknown = getMapiObject(pFolder.pdispVal);
if (!lpUnknown) return E_NOINTERFACE;

// OL 2000 return


// OL 20020 SUCCEEDED

lpUnknown->QueryInterface(IID_IMAPIFolder, (LPVOID*) &lpFolder);
if (!lpFolder) return E_NOINTERFACE;

hr = lpFolder->GetContentsTable(MAPI_ASSOCIATED, &lpTable);

...
...

}



// Example from Internet
LPUNKNOWN CTools::getMapiObject(LPDISPATCH disp)
{
DISPID rgDispId;
DISPPARAMS dispparams = {NULL, NULL, 0, 0};
VARIANT vaResult;
LPOLESTR pName = L"MAPIOBJECT";
VariantInit(&vaResult);

if
(SUCCEEDED(disp->GetIDsOfNames(IID_NULL,&pName,1,LOCALE_SYSTEM_DEFAULT,&rgDi
 
H

Henry Gusakovsky

use code like this

//using ATL that's easier to demonstrate
LPUNKNOWN CTools::getMapiObject(LPDISPATCH disp)
{
LPUNKNOWN lpResult = NULL;
HRESULT hResult = S_OK;
CComVariant vEntryID;
CComVariant vStoreEntryID;
CComDispatchDriver pFolder(disp);

hResult = pFolder.GetPropertyByName( L"EntryID", &vEntryID );
if ( FAILED( hResult ) )
return NULL;
bstr_t bstrEntryID(vEntryID.bstrVal, TRUE);

hResult = pFolder.GetPropertyByName( L"StoreID", &vStoreEntryID );
if ( FAILED( hResult ) )
return NULL;
bstr_t bstrStoreEntryID(vStoreEntryID.bstrVal, TRUE);

SBinary sbEntryID = {0};
sbEntryID.cb = strlen((LPCSTR)bstrEntryID)/2;
sbEntryID.lpb = new BYTE[sbEntryID.cb];

hResult = ScBinFromHexBounded((LPSTR)bstrEntryID, sbEntryID.lpb,
sbEntryID.cb);
//check result

SBinary sbStoreEntryID = {0};
sbStoreEntryID.cb = strlen((LPCSTR)bstrStoreEntryID)/2;
sbStoreEntryID.lpb = new BYTE[sbStoreEntryID.cb];

hResult = ScBinFromHexBounded((LPSTR)bstrStoreEntryID, sbStoreEntryID.lpb,
sbStoreEntryID.cb);

if(SUCCEEDED(hResult))
{
LPMAPISESSION lpSession = NULL;
//obtain shared session
hResult = MAPILogonEx(
0, // Handle to the window
NULL, // Profile name
NULL, // Password
0, // Flags
&lpSession);
if(SUCCEEDED(hResult))
{
LPMDB lpStore = NULL;
//we need to open MsgStore because without this lpSession->OpenEntry
//returns MAPI_E_UNKNOWN_ENTRYID
hResult = lpSession->OpenMsgStore(
0,
sbStoreEntryID.cb,
(LPENTRYID)sbStoreEntryID.lpb,
NULL,
MAPI_BEST_ACCESS,
&lpStore);
if(SUCCEEDED(hResult))
{
ULONG ulObjectType = 0;
hResult = lpStore->OpenEntry(
sbEntryID.cb,
(LPENTRYID)sbEntryID.lpb,
NULL, //default interface returned. IMAPIFolder in case of folder
MAPI_BEST_ACCESS,
&ulObjectType,
(LPUNKNOWN*)&lpResult);
if(SUCCEEDED(hResult))
{
if(MAPI_FOLDER != ulObjectType)
{
lpResult->Release();
lpResult = NULL;
} // if
} // if

lpStore->Release();
} // if

lpSession->Release();
} // if
} // if

delete [] sbEntryID.lpb;
return lpResult;
}


WBR
Henry

Gabi Fruhner said:
Thanks Henry and Dmitry,

because I'm new to C++ and new to MAPI I have some problems to complete my
Dll and this is making me crazy

I think I have to pass StoreID ( as BSTR ? - Mainprog is VB ) too because
there are more Stores in profile.

After hours of googling without finding any examples for this problem I
think I have to give up.
A next problem is, that in my VB App I have to read 3 named properties and
my C++ property wrapper function does not support GetNameFromIDs yet.
I will try to remove my problems 5 more days and then I will throw my
notebook on the wall and I will go to swimming bath to enjoy last few days
of summer.

Gabi


Henry Gusakovsky said:
MAPIOBJECT property is not supported in Outlook2000.

Use MAPILogonEx to obtain shared session.
From MAPIFolder obtain EntryID property
Convert into binary. For that you can use FBinFromHex function.

After that via IMAPISession->OpenEntry() you can obtain IMAPIFolder
interface

WBR
Henry
Hi,

I've written a C++ Dll to get and set body of a hidden message.

I pass a Outlook.MAPIFolder to C++

STDMETHODIMP CTools::GetAdminMessage(/*[in]*/ VARIANT pFolder,
/*[in]*/
long
CanCreate, /*[in]*/ BSTR* Subject, /*[out,retval]*/ BSTR* result)
{

LPUNKNOWN lpUnknown;
LPMAPIFOLDER lpFolder;
...
...

lpUnknown = getMapiObject(pFolder.pdispVal);
if (!lpUnknown) return E_NOINTERFACE;

// OL 2000 return


// OL 20020 SUCCEEDED

lpUnknown->QueryInterface(IID_IMAPIFolder, (LPVOID*) &lpFolder);
if (!lpFolder) return E_NOINTERFACE;

hr = lpFolder->GetContentsTable(MAPI_ASSOCIATED, &lpTable);

...
...

}



// Example from Internet
LPUNKNOWN CTools::getMapiObject(LPDISPATCH disp)
{
DISPID rgDispId;
DISPPARAMS dispparams = {NULL, NULL, 0, 0};
VARIANT vaResult;
LPOLESTR pName = L"MAPIOBJECT";
VariantInit(&vaResult);

if
(SUCCEEDED(disp->GetIDsOfNames(IID_NULL,&pName,1,LOCALE_SYSTEM_DEFAULT,&rgDi
 
G

Gabi Fruhner

Thanks Dmitry and Henry,

after 2 sleepless nights I nearly solved it.
Propwrapper can now return Named Properties too and GetAdminMessage works
with OpenMsgStore and OpenEntry, but only with OL 2002.

And thats my last question:
Why return code after OpenEntry in OL 2000.

....
....
lpID = LPSTRFromBSTR(*bstrStoreID);
cbEID = strlen(lpID)/2;

MAPIAllocateBuffer(cbEID, (void **)&pbEID);
FBinFromHex(lpID,(LPBYTE)pbEID);

hr = lpMAPISession->OpenMsgStore(0, cbEID, pbEID, NULL, MAPI_BEST_ACCESS,
&lpStore);

MAPIFreeBuffer(pbEID);
FREEMEM(lpID);

if (FAILED(hr)) return hr;

lpID = LPSTRFromBSTR(*bstrFolderID);
cbEID = strlen(lpID)/2;

MAPIAllocateBuffer(cbEID, (void **)&pbEID);
FBinFromHex(lpID,(LPBYTE)pbEID);

hr = lpStore->OpenEntry(cbEID, pbEID, 0, MAPI_BEST_ACCESS, 0, &lpUnknown);

lpStore->Release();
MAPIFreeBuffer(pbEID);
FREEMEM(lpID);

if (FAILED(hr)) return hr; // OL 2000 returns
....
....

I use OpenMsgStore, because OOM and CDO (CDO only for tests) in VB App have
problems to get folder/messages/items if StoreID is not passed.

Should Dll be Unicode ?

Thanks again

Gabi


Gabi Fruhner said:
Thanks Henry and Dmitry,

because I'm new to C++ and new to MAPI I have some problems to complete my
Dll and this is making me crazy

I think I have to pass StoreID ( as BSTR ? - Mainprog is VB ) too because
there are more Stores in profile.

After hours of googling without finding any examples for this problem I
think I have to give up.
A next problem is, that in my VB App I have to read 3 named properties and
my C++ property wrapper function does not support GetNameFromIDs yet.
I will try to remove my problems 5 more days and then I will throw my
notebook on the wall and I will go to swimming bath to enjoy last few days
of summer.

Gabi


Henry Gusakovsky said:
MAPIOBJECT property is not supported in Outlook2000.

Use MAPILogonEx to obtain shared session.
From MAPIFolder obtain EntryID property
Convert into binary. For that you can use FBinFromHex function.

After that via IMAPISession->OpenEntry() you can obtain IMAPIFolder
interface

WBR
Henry
Hi,

I've written a C++ Dll to get and set body of a hidden message.

I pass a Outlook.MAPIFolder to C++

STDMETHODIMP CTools::GetAdminMessage(/*[in]*/ VARIANT pFolder,
/*[in]*/
long
CanCreate, /*[in]*/ BSTR* Subject, /*[out,retval]*/ BSTR* result)
{

LPUNKNOWN lpUnknown;
LPMAPIFOLDER lpFolder;
...
...

lpUnknown = getMapiObject(pFolder.pdispVal);
if (!lpUnknown) return E_NOINTERFACE;

// OL 2000 return


// OL 20020 SUCCEEDED

lpUnknown->QueryInterface(IID_IMAPIFolder, (LPVOID*) &lpFolder);
if (!lpFolder) return E_NOINTERFACE;

hr = lpFolder->GetContentsTable(MAPI_ASSOCIATED, &lpTable);

...
...

}



// Example from Internet
LPUNKNOWN CTools::getMapiObject(LPDISPATCH disp)
{
DISPID rgDispId;
DISPPARAMS dispparams = {NULL, NULL, 0, 0};
VARIANT vaResult;
LPOLESTR pName = L"MAPIOBJECT";
VariantInit(&vaResult);

if
(SUCCEEDED(disp->GetIDsOfNames(IID_NULL,&pName,1,LOCALE_SYSTEM_DEFAULT,&rgDi
 
G

Gabi Fruhner

Found it

hr = lpStore->OpenEntry(cbEID, pbEID, 0, MAPI_BEST_ACCESS, 0, &lpUnknown);

must be

ULONG ulObjType

hr = lpStore->OpenEntry(cbEID, pbEID, 0, MAPI_BEST_ACCESS, &ulObjType,
(LPUNKNOWN*)&lpFolder);


Thanks

Gabi

Gabi Fruhner said:
Thanks Dmitry and Henry,

after 2 sleepless nights I nearly solved it.
Propwrapper can now return Named Properties too and GetAdminMessage works
with OpenMsgStore and OpenEntry, but only with OL 2002.

And thats my last question:
Why return code after OpenEntry in OL 2000.

...
...
lpID = LPSTRFromBSTR(*bstrStoreID);
cbEID = strlen(lpID)/2;

MAPIAllocateBuffer(cbEID, (void **)&pbEID);
FBinFromHex(lpID,(LPBYTE)pbEID);

hr = lpMAPISession->OpenMsgStore(0, cbEID, pbEID, NULL, MAPI_BEST_ACCESS,
&lpStore);

MAPIFreeBuffer(pbEID);
FREEMEM(lpID);

if (FAILED(hr)) return hr;

lpID = LPSTRFromBSTR(*bstrFolderID);
cbEID = strlen(lpID)/2;

MAPIAllocateBuffer(cbEID, (void **)&pbEID);
FBinFromHex(lpID,(LPBYTE)pbEID);

hr = lpStore->OpenEntry(cbEID, pbEID, 0, MAPI_BEST_ACCESS, 0, &lpUnknown);

lpStore->Release();
MAPIFreeBuffer(pbEID);
FREEMEM(lpID);

if (FAILED(hr)) return hr; // OL 2000 returns
...
...

I use OpenMsgStore, because OOM and CDO (CDO only for tests) in VB App have
problems to get folder/messages/items if StoreID is not passed.

Should Dll be Unicode ?

Thanks again

Gabi


Gabi Fruhner said:
Thanks Henry and Dmitry,

because I'm new to C++ and new to MAPI I have some problems to complete my
Dll and this is making me crazy

I think I have to pass StoreID ( as BSTR ? - Mainprog is VB ) too because
there are more Stores in profile.

After hours of googling without finding any examples for this problem I
think I have to give up.
A next problem is, that in my VB App I have to read 3 named properties and
my C++ property wrapper function does not support GetNameFromIDs yet.
I will try to remove my problems 5 more days and then I will throw my
notebook on the wall and I will go to swimming bath to enjoy last few days
of summer.

Gabi


Henry Gusakovsky said:
MAPIOBJECT property is not supported in Outlook2000.

Use MAPILogonEx to obtain shared session.
From MAPIFolder obtain EntryID property
Convert into binary. For that you can use FBinFromHex function.

After that via IMAPISession->OpenEntry() you can obtain IMAPIFolder
interface

WBR
Henry

Hi,

I've written a C++ Dll to get and set body of a hidden message.

I pass a Outlook.MAPIFolder to C++

STDMETHODIMP CTools::GetAdminMessage(/*[in]*/ VARIANT pFolder, /*[in]*/
long
CanCreate, /*[in]*/ BSTR* Subject, /*[out,retval]*/ BSTR* result)
{

LPUNKNOWN lpUnknown;
LPMAPIFOLDER lpFolder;
...
...

lpUnknown = getMapiObject(pFolder.pdispVal);
if (!lpUnknown) return E_NOINTERFACE;

// OL 2000 return


// OL 20020 SUCCEEDED

lpUnknown->QueryInterface(IID_IMAPIFolder, (LPVOID*) &lpFolder);
if (!lpFolder) return E_NOINTERFACE;

hr = lpFolder->GetContentsTable(MAPI_ASSOCIATED, &lpTable);

...
...

}



// Example from Internet
LPUNKNOWN CTools::getMapiObject(LPDISPATCH disp)
{
DISPID rgDispId;
DISPPARAMS dispparams = {NULL, NULL, 0, 0};
VARIANT vaResult;
LPOLESTR pName = L"MAPIOBJECT";
VariantInit(&vaResult);

if
(SUCCEEDED(disp->GetIDsOfNames(IID_NULL,&pName,1,LOCALE_SYSTEM_DEFAULT,&rgDi supported
in error
in
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top