New menu on OL2003 doesn't work when Word is used to edit msg

  • Thread starter Thread starter Jim
  • Start date Start date
J

Jim

Hi,

I'm developing an addin for Outlook 2003 in C++. The addin dll will
add a new menu button on outlook item menu, this works if Word is not
involved. If I check "use Office word 2003 to edit email message" in
the tool->options->mail format, the menu can not be added.

I try to trace the issue and I found that Commandbars can not be got
through inspector. I'm trying to solve the problem with some code that
attempt to add the menu to Word's commandbar, but it failed at this
line in AttachMenu function:

hr = editWordDoc->get_CommandBars(&spCmdBars);

Any ideas on why this doesn't work? Is this the right way to add menu
to OL2003's new mail/view message window when Word is used?

The following codes are relevant codes:


//Invoke function can get the inspector of application
STDMETHODIMP CSecurityAddin::Invoke(DISPID dispidMember,REFIID
riid,LCID lcid, WORD wFlags,
DISPPARAMS* pDispParams, VARIANT*
pvarResult,
EXCEPINFO* pExcepInfo, UINT*
puArgErr)
{
HRESULT hr = S_OK;
if(dispidMember == 0xf001)
{
if(pDispParams == NULL)
{
return E_FAIL;
}
if(pDispParams->cArgs > 0)
{
//the only parameter is an Inspector*
IDispatchPtr pDisp(pDispParams->rgvarg[0].pdispVal);
CComQIPtr<_Inspector> spInspector(pDisp);

Outlook::OlObjectClass CurObjectCls;
spInspector->get_Class(&CurObjectCls);

CComQIPtr<IDispatch> spInspectorItem;
spInspector->get_CurrentItem(&spInspectorItem);
CComQIPtr<Outlook::_MailItem> spMailItem(spInspectorItem);
if(spMailItem == NULL)
{
return E_FAIL;
}
OlObjectClass type;
spMailItem->get_Class(&type);

if(type == olMail)
{
CMenu* pMenu = new CMenu();
if(!pMenu)
{
return E_OUTOFMEMORY;
}
pMenu->Init(m_spApp, spInspector);
m_vecPMenu.push_back(pMenu);
}
}
}
else
{
return E_FAIL;
}
return hr;
}

//Init menu
HRESULT CMenu::Init(CComQIPtr <Outlook::_Application> spApp,
CComQIPtr<Outlook::_Inspector> spInspector)
{
ATLASSERT(spApp);
ATLASSERT(spInspector);
LogFile("Start Init!");
m_spApp = spApp;
m_spInspector = spInspector;
if(FAILED(AttachMenu(m_spInspector)))
{
return E_FAIL;
}
LogFile("End Init!");
return S_OK;
}
//
HRESULT CMenu::AttachMenu(CComQIPtr<_Inspector> spInspector)
{
LogFile("Start AttachMenu!");
HRESULT hr = S_OK;
ATLASSERT(spInspector);
m_spInspector = spInspector;
CComPtr<Office::_CommandBars> spCmdBars;
hr = spInspector->get_CommandBars(&spCmdBars); //actually if the
option is checked, the function get the error code
OlEditorType editType;
spInspector->get_EditorType(&editType);
if(editType == olEditorWord)
{
LogFile("Using the word to edit email message!");
CComPtr<MSWord::_Document> editWordDoc;
hr = spInspector->get_WordEditor((IDispatch* *)&editWordDoc);

if(FAILED(hr))
{
LogFile("spInspector->get_WordEditor Failed!");
return hr;
}
ATLASSERT(editWordDoc);
CComPtr<MSWord::_Application> editWordApp;

hr = editWordDoc->get_Application(&editWordApp);
if(FAILED(hr))
{
LogFile("editWordDoc->get_Application Failed!");
return hr;
}
else
{
LogFile("Get_Application success");
}

ATLASSERT(editWordApp);
hr = editWordDoc->get_CommandBars(&spCmdBars);

if(FAILED(hr))
{
LogFile("editWordApp->get_CommandBars Failed!");
return hr;
}
MessageBox(NULL,"NULL","TRACE",NULL);
}
if(FAILED(hr))
{
LogFile("spInspector->get_CommandBars failed!");
return hr;
}
ATLASSERT(spCmdBars);
CComQIPtr<CommandBar> spTopMenu;
spTopMenu = spCmdBars->GetActiveMenuBar();
ATLASSERT(spTopMenu);

//... add item into the menu item and add item into the menu.
.............................
}
 
I don't use C++ but I regularly add UI to WordMail items in Outlook 2003.
There are some restrictions on where you can add UI, but it works as long as
you wait for the first Inspector.Activate() event to add your UI. If you try
to add the UI in the NewInspector() event handler it will fail.

I get the Inspector.CommandBars collection and if it's WordMail I create a
new toolbar (CommandBar) and add my UI to that. If it's the Outlook editor I
can add the UI to the existing toolbars (like Standard) or to the menus
(Menu Bar) or to a new toolbar.




Jim said:
Hi,

I'm developing an addin for Outlook 2003 in C++. The addin dll will
add a new menu button on outlook item menu, this works if Word is not
involved. If I check "use Office word 2003 to edit email message" in
the tool->options->mail format, the menu can not be added.

I try to trace the issue and I found that Commandbars can not be got
through inspector. I'm trying to solve the problem with some code that
attempt to add the menu to Word's commandbar, but it failed at this
line in AttachMenu function:

hr = editWordDoc->get_CommandBars(&spCmdBars);

Any ideas on why this doesn't work? Is this the right way to add menu
to OL2003's new mail/view message window when Word is used?

The following codes are relevant codes:


//Invoke function can get the inspector of application
STDMETHODIMP CSecurityAddin::Invoke(DISPID dispidMember,REFIID
riid,LCID lcid, WORD wFlags,
DISPPARAMS* pDispParams, VARIANT*
pvarResult,
EXCEPINFO* pExcepInfo, UINT*
puArgErr)
{
HRESULT hr = S_OK;
if(dispidMember == 0xf001)
{
if(pDispParams == NULL)
{
return E_FAIL;
}
if(pDispParams->cArgs > 0)
{
//the only parameter is an Inspector*
IDispatchPtr pDisp(pDispParams->rgvarg[0].pdispVal);
CComQIPtr<_Inspector> spInspector(pDisp);

Outlook::OlObjectClass CurObjectCls;
spInspector->get_Class(&CurObjectCls);

CComQIPtr<IDispatch> spInspectorItem;
spInspector->get_CurrentItem(&spInspectorItem);
CComQIPtr<Outlook::_MailItem> spMailItem(spInspectorItem);
if(spMailItem == NULL)
{
return E_FAIL;
}
OlObjectClass type;
spMailItem->get_Class(&type);

if(type == olMail)
{
CMenu* pMenu = new CMenu();
if(!pMenu)
{
return E_OUTOFMEMORY;
}
pMenu->Init(m_spApp, spInspector);
m_vecPMenu.push_back(pMenu);
}
}
}
else
{
return E_FAIL;
}
return hr;
}

//Init menu
HRESULT CMenu::Init(CComQIPtr <Outlook::_Application> spApp,
CComQIPtr<Outlook::_Inspector> spInspector)
{
ATLASSERT(spApp);
ATLASSERT(spInspector);
LogFile("Start Init!");
m_spApp = spApp;
m_spInspector = spInspector;
if(FAILED(AttachMenu(m_spInspector)))
{
return E_FAIL;
}
LogFile("End Init!");
return S_OK;
}
//
HRESULT CMenu::AttachMenu(CComQIPtr<_Inspector> spInspector)
{
LogFile("Start AttachMenu!");
HRESULT hr = S_OK;
ATLASSERT(spInspector);
m_spInspector = spInspector;
CComPtr<Office::_CommandBars> spCmdBars;
hr = spInspector->get_CommandBars(&spCmdBars); //actually if the
option is checked, the function get the error code
OlEditorType editType;
spInspector->get_EditorType(&editType);
if(editType == olEditorWord)
{
LogFile("Using the word to edit email message!");
CComPtr<MSWord::_Document> editWordDoc;
hr = spInspector->get_WordEditor((IDispatch* *)&editWordDoc);

if(FAILED(hr))
{
LogFile("spInspector->get_WordEditor Failed!");
return hr;
}
ATLASSERT(editWordDoc);
CComPtr<MSWord::_Application> editWordApp;

hr = editWordDoc->get_Application(&editWordApp);
if(FAILED(hr))
{
LogFile("editWordDoc->get_Application Failed!");
return hr;
}
else
{
LogFile("Get_Application success");
}

ATLASSERT(editWordApp);
hr = editWordDoc->get_CommandBars(&spCmdBars);

if(FAILED(hr))
{
LogFile("editWordApp->get_CommandBars Failed!");
return hr;
}
MessageBox(NULL,"NULL","TRACE",NULL);
}
if(FAILED(hr))
{
LogFile("spInspector->get_CommandBars failed!");
return hr;
}
ATLASSERT(spCmdBars);
CComQIPtr<CommandBar> spTopMenu;
spTopMenu = spCmdBars->GetActiveMenuBar();
ATLASSERT(spTopMenu);

//... add item into the menu item and add item into the menu.
............................
}
 
I just skimmed that article but I saw a couple of things I wouldn't agree
with. For example he assumes that Tools is the 6th item in the Menu Bar
CommandBar. That's not always the case, some other code could have added a
control before Tools, shifting its index. You can't just assume positioning
like that and expect it to work on anything other than a virgin
installation. I also don't like using ActiveMenuBar, at least without
further testing, I've seen lots of problems with that approach.

You definitely need to handle NewInspector(), but the Inspector object
reference passed to you in NewInspector() is what's known as a weak object
reference. That means it doesn't necessarily have all the expected
properties available at that time. One of those properties that's often
missing or not fully initialized yet is Inspector.CommandBars. The only
properties you really should use in NewInspector() are some of the
properties of Inspector.CurrentItem, such as .Class and .MessageClass, used
to decide if you want to handle that Inspector.

Once the first Inspector.Activate() event fires you do have a fully
instantiated Inspector and then you can always retrieve the CommandBars
collection. One reason something like Inspector.CommandBars may not be
available to you in NewInspector() is that the event fires after the
Inspector is created but before its visible. WordMail takes extra time to
become fully available compared to an Outlook editor item, all the item data
must be passed to the subclassed msword.exe in Outlook 2003 and that takes
extra time.




Hi, Slovak

Thanks for the info, I based on my code on
http://www.codeproject.com/KB/COM/outlookaddin.aspx,
if you check the update on April 02,2003, you can see Amit Dey
recommend handling the new inspector event, is he wrong or is this
problem specific to OL2003?

Thanks

Jim
 
Hi, Slovak

Thanks for your evaluation of the code, I'm working on an approach
based on your suggestion. I took a look at the sample codes on your
website, do you mind if I use them as a guide? I'm looking at the
inspector wrapper code at http://www.slovaktech.com/code_samples.htm#InspectorWrapper:
It has some code on create menus and tries to use different method if
Word is used as editor. However, it doesn't seem to handle the
activate event, and although it checks if Word is used by setting
m_blnWord, but this is never used elsewhere in the code. Also the
CreateMenus method only creates the menu but didn't seem to attache
the menu to the command bar. I wonder if there's a more complete
sample of the inspector wrapper?

Thanks

Jim
 
That's a shell of an Inspector wrapper, it doesn't do any of the heavy
lifting of actually doing anything useful with the menu (or even create it
for WordMail), and work best the way it creates UI with the Outlook editor
and earlier versions of Outlook 2003 and earlier.

Things changed later on, that sample really needs updating and filling in
for more recent best practices. When I put that sample online it was the
first Inspector wrapper sample available.

You can use any of my samples as a basis for your code.
 
Back
Top