M
Mel Green
Hi there,
I've seem to run into an interesting problem with an Add-In that I
originally wrote for Excel 2003 and below, and then tried to run with Excel
2007. The Add-In is written in ATL C++ and uses the IDispatchImpl and
IDispEventSimpleImpl interfaces to communicate events with Excel.
While the Add-In works perfectly for Excel 2000-2003, excel will crash with
an error AFTER Excel unloads the GUI and all the Add-Ins. During the time
that Excel is open my Add-In works great. I've tried to debug the code to
find out what is happening, but there are no exceptions thrown anywhere in my
code. I can go all the way to the point where Excel calls my
OnDisconnection() and subsequently OnBeginShutdown() functions at which point
I return S_OK. It is then, if I walk through some of the assembly code in
Excel I get to a point where a NULL reference exception is encountered.
The only thing my Add-In does is create a new Command Bar and adds a button
to it. By the process of commenting out all of the code inside my functions
and then slowly enabling some I've found that the code that is somehow
causing this problem is the code that creates my Command Bar.
The code I use to create the command bar is fired in the OnStartupComplete()
event of the IDispatch interface and does this:
<---------------------------------------------------------------------------
//Members used to insert the button(s)
CCommandBars oCommandBars;
//Setup the application
CApplication spApp(m_pApplication);
//Get the collection of command bars
oCommandBars = spApp.get_CommandBars();
//Now add a new toolband to which we'll add a button
CComVariant vName("MyBar");
CComVariant vEmpty(DISP_E_PARAMNOTFOUND, VT_ERROR);
CComVariant vVisible(VARIANT_TRUE);
CComQIPtr<Office::CommandBar> oMyBar;
//Loop through the collection of command bars and see if our bar
//already exists
BSTR tmp;
for(int i = 1; i < oCommandBars.get_Count(); i++)
{
CComVariant vIndex(i);
oEFileBar = oCommandBars.get_Item(vIndex);
oEFileBar->get_Name(&tmp);
if(strcmp(ConvertBSTRToString(tmp), "MyBar"))
{
oMyBar.Detach();
}
else
break;
}
//free the string
::SysFreeString(tmp);
//If we didn't find the bar already there, create it
if(!oMyBar)
{
//position it below all toolbands
//MsoBarPosition::msoBarTop = 1
CComVariant vPos(1);
CComVariant vTemp(VARIANT_TRUE); //menu is temporary
//Add a new toolband through Add method
//vMenuTemp holds an unspecified parameter
oMyBar = oCommandBars.Add( vName, vPos, vEmpty, vTemp );
}
------------------------------------------------------------------------------->
Instead of using the regular ATL convention of
ComQIPtr<Office::CommandBars>, I used a MFC class creator for COM interfaces
to create these wrapper classes (CCommandBars and CApplication) to make the
code simpler. This has worked fine for me.
I've seem to run into an interesting problem with an Add-In that I
originally wrote for Excel 2003 and below, and then tried to run with Excel
2007. The Add-In is written in ATL C++ and uses the IDispatchImpl and
IDispEventSimpleImpl interfaces to communicate events with Excel.
While the Add-In works perfectly for Excel 2000-2003, excel will crash with
an error AFTER Excel unloads the GUI and all the Add-Ins. During the time
that Excel is open my Add-In works great. I've tried to debug the code to
find out what is happening, but there are no exceptions thrown anywhere in my
code. I can go all the way to the point where Excel calls my
OnDisconnection() and subsequently OnBeginShutdown() functions at which point
I return S_OK. It is then, if I walk through some of the assembly code in
Excel I get to a point where a NULL reference exception is encountered.
The only thing my Add-In does is create a new Command Bar and adds a button
to it. By the process of commenting out all of the code inside my functions
and then slowly enabling some I've found that the code that is somehow
causing this problem is the code that creates my Command Bar.
The code I use to create the command bar is fired in the OnStartupComplete()
event of the IDispatch interface and does this:
<---------------------------------------------------------------------------
//Members used to insert the button(s)
CCommandBars oCommandBars;
//Setup the application
CApplication spApp(m_pApplication);
//Get the collection of command bars
oCommandBars = spApp.get_CommandBars();
//Now add a new toolband to which we'll add a button
CComVariant vName("MyBar");
CComVariant vEmpty(DISP_E_PARAMNOTFOUND, VT_ERROR);
CComVariant vVisible(VARIANT_TRUE);
CComQIPtr<Office::CommandBar> oMyBar;
//Loop through the collection of command bars and see if our bar
//already exists
BSTR tmp;
for(int i = 1; i < oCommandBars.get_Count(); i++)
{
CComVariant vIndex(i);
oEFileBar = oCommandBars.get_Item(vIndex);
oEFileBar->get_Name(&tmp);
if(strcmp(ConvertBSTRToString(tmp), "MyBar"))
{
oMyBar.Detach();
}
else
break;
}
//free the string
::SysFreeString(tmp);
//If we didn't find the bar already there, create it
if(!oMyBar)
{
//position it below all toolbands
//MsoBarPosition::msoBarTop = 1
CComVariant vPos(1);
CComVariant vTemp(VARIANT_TRUE); //menu is temporary
//Add a new toolband through Add method
//vMenuTemp holds an unspecified parameter
oMyBar = oCommandBars.Add( vName, vPos, vEmpty, vTemp );
}
------------------------------------------------------------------------------->
Instead of using the regular ATL convention of
ComQIPtr<Office::CommandBars>, I used a MFC class creator for COM interfaces
to create these wrapper classes (CCommandBars and CApplication) to make the
code simpler. This has worked fine for me.