Я использую C ++ для автоматизации Microsoft Word 2010. Когда пользователь закрывает приложение, и моя программа хочет использовать ранее полученный интерфейс IDispatch, программа падает (необработанное исключение). Код Simular VBA в Excel выдает ошибку «Ошибка 462: удаленный сервер не существует». Как я могу определить, что приложение закрыто пользователем, как это делает Excel.
#ifdef __NO_PRECOMPILED_HEADERS__
#include "generic/platformdefs.h"
#endif
#include "test_word.h"
/*
* Include the right atlbase.h (depends on the compiler)
*/
#include "compat/which_atlbase.h"
static OLECHAR FAR *VISIBLE =
{
OLESTR( "Visible" )
} ;
static OLECHAR FAR *QUIT =
{
OLESTR( "quit" )
} ;
static void
VarSetBool( VARIANT *v , BOOL value )
{
V_VT( v ) = VT_BOOL ;
V_BOOL( v ) = value ? VARIANT_TRUE : VARIANT_FALSE ;
}
static void
DispatchPropertyPut
(
CComPtr<IDispatch> dispatch ,
OLECHAR FAR *property ,
VARIANT *value
)
{
HRESULT status ;
DISPID dispid ,
propertyput ;
DISPPARAMS parameters ;
UINT n_argument_error;
VARIANT result ;
/*
* Get the dispatch id of the method and arguments to invoke
*/
status = dispatch->GetIDsOfNames( IID_NULL ,
&property ,
1 ,
LOCALE_USER_DEFAULT ,
&dispid ) ;
if( !SUCCEEDED( status ) )
{
throw( 1 ) ;
}
/*
* Initialize result
*/
VariantInit( &result ) ;
/*
* need to be able to take the address of this
*/
propertyput = DISPID_PROPERTYPUT ;
/*
* Setup the parameters
*/
parameters.cNamedArgs = 1 ;
parameters.rgdispidNamedArgs = &propertyput ;
parameters.cArgs = 1 ;
parameters.rgvarg = value ;
/*
* Get the object
*/
status = dispatch->Invoke( dispid ,
IID_NULL,
LOCALE_USER_DEFAULT,
DISPATCH_PROPERTYPUT ,
¶meters ,
&result ,
0,
&n_argument_error ) ;
/*
* Cleanup result if any
*/
VariantClear( &result ) ;
/*
* Success ?
*/
if( !SUCCEEDED( status ) )
{
throw( 2 ) ;
}
}
static void
DispatchInvoke
(
CComPtr<IDispatch> dispatch ,
OLECHAR FAR *method
)
{
DISPID dispid ;
HRESULT status ;
DISPPARAMS parameters ;
status = dispatch->GetIDsOfNames( IID_NULL ,
&method ,
1 ,
LOCALE_USER_DEFAULT ,
&dispid ) ;
if( !SUCCEEDED( status ) )
{
throw( 3 ) ;
}
parameters.cNamedArgs = 0 ;
parameters.rgdispidNamedArgs = 0 ;
parameters.cArgs = 0 ;
parameters.rgvarg = 0 ;
status = dispatch->Invoke( dispid ,
IID_NULL,
LOCALE_USER_DEFAULT,
DISPATCH_METHOD ,
¶meters ,
0 ,
0 ,
0 ) ;
if( !SUCCEEDED( status ) )
{
throw( 4 ) ;
}
}
void
test_word( int argc , char *argv[] , void *data )
{
CComPtr<IDispatch> word ;
VARIANT v ;
HRESULT hr ;
OleInitialize( NULL ) ;
try
{
/*
* The metrowerks compiler doesn't handle __uuidof()
*/
# ifdef __MWERKS__
hr = word.CoCreateInstance( OLESTR( "Word.Application" ) ,
IID_IDispatch ,
0 ,
CLSCTX_SERVER ) ;
# else
hr = word.CoCreateInstance( OLESTR( "Word.Application" ) ,
0 ,
CLSCTX_SERVER ) ;
# endif
if( !SUCCEEDED( hr ) )
{
throw( 6 ) ;
}
VariantInit( &v ) ;
VarSetBool( &v , TRUE ) ;
DispatchPropertyPut( word , VISIBLE , &v ) ;
DispatchInvoke( word , QUIT ) ;
VarSetBool( &v , FALSE ) ;
/*
* This will crash the application
*/
DispatchPropertyPut( word , VISIBLE , &v ) ;
}
catch( int where )
{
fprintf( stderr , "Exception caught %d\n" , where ) ;
}
word.Release() ;
OleUninitialize() ;
}
Макрос Excel vba выглядит следующим образом:
Sub test_word()
Dim word As Object
Set word = CreateObject("word.application")
word.Visible = True
word.quit()
'
' Quit the word application before the next statement
' and you will get Error 462: The remote server does not exist
'
word.Visible = False
Set word = Nothing
End Sub