Newbie get_CurrentItem() question

  • Thread starter Thread starter Gabriel
  • Start date Start date
G

Gabriel

Hello,

I am still brand new to ATL/COM add-in development so I assume there is an
obvious answer to this. I'm using VC++ 6 and the add-in is for Outlook 2003.

I am attempting to add the body of the currently selected message to a new
message I create. The new message creation/sending part works fine, but I get
a fatal error every time I use the get_CurrentItem() method. Here's the
relevant code (I got almost all of this from tutorials):

CComPtr <Outlook::_MailItem> mailPtr;

m_spApp->CreateItem(Outlook::olMailItem, (IDispatch**)&mailPtr);





CComPtr<Outlook::_Inspector> spInspector;

hr = m_spApp->ActiveInspector(&spInspector);

if (FAILED(hr)){

MessageBox(NULL,"Error retrieving inspector","Inspector",MB_OK);

return;

}





CComPtr<IDispatch> spCurrentItem;

CComPtr<Outlook::_MailItem> mailPtr2;



spInspector->get_CurrentItem(&spCurrentItem);

Any input is greatly appreciated. Let me know if you need any more info.
 
Hi Gabriel,
I am attempting to add the body of the currently selected message to a new
message I create. The new message creation/sending part works fine, but I
get
a fatal error every time I use the get_CurrentItem() method. Here's the
relevant code (I got almost all of this from tutorials):

CComPtr <Outlook::_MailItem> mailPtr;
m_spApp->CreateItem(Outlook::olMailItem, (IDispatch**)&mailPtr);

Did you try to create the new item *after* retrieving the current item,
just to make sure the CreateItem does not set a new CurrentItem
CComPtr<Outlook::_Inspector> spInspector;
hr = m_spApp->ActiveInspector(&spInspector);

Are you sure that spInspector != NULL?
CComPtr<IDispatch> spCurrentItem;
CComPtr<Outlook::_MailItem> mailPtr2;

spInspector->get_CurrentItem(&spCurrentItem);

Does the call fail or crash?
Can you call any other method on the inspector?
 
Hi Sven,


SvenC said:
Are you sure that spInspector != NULL?

That was it. I erroneously made the assumption that since hr wasn't failing,
spInspector was getting set. Which leads me to my next question. I think I'm
confusing the Inspector object and the Selection object. If I have one or
more messages in my inbox selected, I'd access them with
ActiveExplorer->Selection, correct? I tried this instead (with extra checks
to see where things went awry):

CComPtr <Outlook::_Explorer> spExplorer;



m_spApp->ActiveExplorer(&spExplorer);

if (spExplorer == NULL){

MessageBox(NULL,"Explorer not set","No Explorer",MB_OK);

}



CComPtr <Outlook::Selection> spSelection;

spExplorer->get_Selection(&spSelection);

if (spSelection == NULL){

MessageBox(NULL,"Selection not set","No Selection",MB_OK);

}



VARIANT v;

v.intVal = 1;

CComPtr<IDispatch> mailPtr2;

spSelection->Item(v,&mailPtr2);

if (mailPtr2 == NULL){

MessageBox(NULL,"mailPtr2 not set","No MailPtr2",MB_OK);

}

When run, it displays the "mailPtr2 not set" message box. Thanks for your
help!

-Gabriel
 
Hi Gabriel,
I think I'm confusing the Inspector object and the Selection object.

Inspector gives you access to a single item shown by Outlook in its
own window.
If I have one or more messages in my inbox selected, I'd access
them with ActiveExplorer->Selection, correct?
Yes.

CComPtr <Outlook::Selection> spSelection;
spExplorer->get_Selection(&spSelection);

if (spSelection == NULL){
MessageBox(NULL,"Selection not set","No Selection",MB_OK);
}

VARIANT v;
v.intVal = 1;

You must set the type of the variant.
v.vt == VT_I4.

Alternatively you can use a variant class like CComVariant
which has assignment overloads which set the type
automatically.

CComVariant v = 1L; // use L to indicate long constant
CComPtr<IDispatch> mailPtr2;
spSelection->Item(v,&mailPtr2);

Get the returned HRESULT as well. I expect that you should
get E_INVALIDARG when passing an incorrect VARIANT.
 
Thanks again, Sven!

I actually caught the VARIANT issue. The HRESULT returned from
spSelection->Item() doesn't fail and mailPtr2 is set now, however I run into
issues when calling mailPtr2's methods. I DID change the declaration to
CComPtr<Outlook::_MailItem> from CComPtr<IDispatch> because I couldn't figure
out how to convert between the two afterward. Here's what I'm currently
working with:

CComVariant nItem = 1L;

CComPtr<Outlook::_MailItem> mailPtr2;

hr = spSelection->Item(nItem,(IDispatch**)&mailPtr2);

if (FAILED(hr)){

char buf[30];

sprintf(buf,"HResult: %d",hr);

MessageBox(NULL,buf,"HResult",MB_OK);

}



if (mailPtr2 == NULL){

MessageBox(NULL,"mailPtr2 not set","No MailPtr2",MB_OK);

}



OlObjectClass cls;

mailPtr2->get_Class(&cls);

char buf[30];

sprintf(buf, "mailPtr2's class is: %d",cls);

MessageBox(NULL,buf,"Class",MB_OK);




CComPtr <Outlook::_MailItem> mailPtr;

m_spApp->CreateItem(Outlook::olMailItem, (IDispatch**)&mailPtr);



long size = 0;

mailPtr2->get_Size(&size);

sprintf(buf,"mailPtr2 Size: %d",size);

MessageBox(NULL,buf,"Size", MB_OK);

BSTR vSubject = ::SysAllocString(OLESTR("test"));

BSTR vBody = ::SysAllocStringLen(NULL,size);

get_Class() seems to work fine (returns 43, which I looked up in the
ITypeLib Viewer as being olMail). get_Size() doesn't set size though, and
get_Body() crashes Outlook. Any ideas?

-Gabriel
 
Hi Gabriel,
I DID change the declaration to
CComPtr<Outlook::_MailItem> from CComPtr<IDispatch> because I couldn't
figure
out how to convert between.

Use QueryInterface to "cast" between two COM interfaces:

CComPtr said:
CComVariant nItem = 1L;
CComPtr<Outlook::_MailItem> mailPtr2;
hr = spSelection->Item(nItem, &disp);

if(disp != NULL)
hr = disp->QueryInterface(&mailPtr2);

Also be sure to release the smart pointers before
you use their address operator to assign a new
object to them. So if you did another:

hr = spSelection->Item(nItem, &disp);

you would leak the first interface pointer.
This would be the correct way:

disp = NULL;
hr = spSelection->Item(nItem, &disp);
long size = 0;
mailPtr2->get_Size(&size);
get_Size() doesn't set size though

What is the value of size? Please retry with the
mailPtr2 retrieved through QueryInterface
BSTR vSubject = ::SysAllocString(OLESTR("test"));
BSTR vBody = ::SysAllocStringLen(NULL,size);

If you use hungarian notation you should use helpful
prefixes. v for BSTRs is confusing, looks more like VARIANT.

Why do you allocate them at all? Are they relevant for
your problem?
get_Body() crashes Outlook. Any ideas?

how do you call it?
 
Hi Sven,

Thanks so much, I just needed to use QueryInterface to cast between the two
interfaces. Works like a charm now. I'll also implement your other "pointers"
to avoid issues in the future.

Thanks again. You've gotten me well on my way!

-Gabriel
 
Back
Top