Re: Calling COM functions using IDispatch->Invoke(...
Thanks Sven and Alf
I just didn't put all the code, but I'm calling
delete [] dispparams.rgvarg;
As well as
pIDispatch->Release();
Unfotunatelly assigning of named params to NULL
dispparams.rgdispidNamedArgs = NULL;
didn't help
EXCEPINFO parameter says:
"Failed to initialize SomeCOM library"
Alf,
I tried to implement your class,
But it also fails, could you please check out what I'm doing wrong:
SomeCOMObject pComObj; //of course I've changed in the constructor
//PROG ID
alfs::DispatchParams dp( 2 );
DISPPARAMS* pDispParam = dp.ptr();
pDispParam->cArgs = 2;
pDispParam->cNamedArgs = 0;
DISPID dispidNamed = DISPATCH_METHOD;
pDispParam->rgdispidNamedArgs = &dispidNamed;
//or
pDispParam->rgdispidNamedArgs = NULL
//as Sven suggested
pDispParam->rgvarg = new VARIANTARG[ 2 ];
pDispParam->rgvarg[ 0 ].vt = VT_ERROR;
pDispParam->rgvarg[ 0 ].lVal = DISP_E_PARAMNOTFOUND;
pDispParam->rgvarg[ 1 ].vt = VT_BSTR;
pDispParam->rgvarg[ 1 ].bstrVal = SysAllocString( L"C:\\Program Files\
\... " );
pComObj.call( L"Start", dp );
//here comes an exception
//if I keep breaking I'm getting in
//string.cpp
MRTIMP2 void __cdecl _String_base::_Xlen()
{ // report a length_error
_THROW_NCEE(length_error, "string too long");
}
I've debugged your code, in invokeAs(..),
right before calling Invoke(=85) line
DISPID const dispId = dispIdOf( name );
return valid value, but Invoke doesn't work
Maybe indeed I have to do something extra to initialize this COM
library. The only thing I've done - imported corresponding tlb.exe.
Thanks to both of you,
Alex
On Apr 22, 11:47 am, "Alf P. Steinbach" <al...@start.no> wrote:
* Alex:
I've got to call some COM server functions. It appears, that the on=
ly
way I can do it =96 using IDispatch. After I've imported type libra=
ry I
can see the prototypes for some functions. For example:
HRESULT Start( _bstr_t Path, const _variant_t & Param );
Here is my code:
HRESULT hr=1;
IDispatch *pIDispatch = NULL;
CLSID clsid;
CLSIDFromProgID(L" SomeCOM.SomeInterface ", &clsid);
hr = CoInitialize(NULL);
if( SUCCEEDED(hr) )
(
hr = CoCreateInstance( clsid,
NULL, CLSCTX_LOCAL_SERVER,
IID_IDispatch,
(void**)&pIDispatch
);
if( SUCCEEDED(hr) )
{
DISPID dispid;
OLECHAR FAR* szMemberName = L"Start";
hr = pIDispatch->GetIDsOfNames(IID_NULL, &szMemberName, 1,
LOCALE_SYSTEM_DEFAULT, &dispid);
if( SUCCEEDED(hr) )
{
VARIANT varResult;
DISPID dispidNamed = DISPATCH_METHOD;
EXCEPINFO excep;
UINT uArgErr;
DISPPARAMS dispparams;
dispparams.cNamedArgs = 0;
dispparams.cArgs = 2;
dispparams.rgdispidNamedArgs = &dispidNamed;
dispparams.rgvarg = new VARIANTARG[2];
dispparams.rgvarg[0].vt = VT_ERROR;
dispparams.rgvarg[0].lVal = DISP_E_PARAMNOTFOUND;
dispparams.rgvarg[1].vt = VT_BSTR;
dispparams.rgvarg[1].bstrVal = SysAllocString(L=94SomePath=
=94);
hr = pIDispatch->Invoke( dispid, IID_NULL,
LOCALE_SYSTEM_DE=
FAULT,
DISPATCH_METHOD,
&dispparams,
&varResult,
&excep,
&uArgErr
);
if( SUCCEEDED(hr) )
{
//invoke succeeded
..........
}
else
{
//invoke failed
// I'm getting in here =
..
}
}
}
And I'm always getting invoke failed.
GetLatestError() returns 0.
If I'm using Alf's P. Steinbach code, which he very kindly supplied =
in
my previous post, for some wrapper class for IDispatch, calling of
this method also fails, but I'm able to get some strange error,
something like =93=85String is too long=85=94
So is possible to tell me what I'm doing wrong? Am I setting
"dispparams" incorrectly?
Don't know. Looks OK, including the backwards indexing. But then, it=
isn't
always necessary to know what the problem is in order to fix it! :-)
By the way in VB it works just fine as
Dim oI As Object
oI = CreateObject("SomeCOM.SomeInterface")
oI. Start(=93SomePath=94)
But I'm using STL library for handling of the data, so I really would
like to be able to call this COM functions directly from my C++
application.
Happily I hadn't yet thrown away the code I posted last time (it's an
all-purpose VC project I use for examples in e.g. Usenet postings), and wi=
th a
little added functionality -- destructor and an "addParam" function =
in
DispatchParameters class, I think it deals with your current problem.
Before blindly using this, though, see the comment in ~DispatchParameters.=
Sorry about the linebreaks if they're broken in the Usenet posting.
<code file="OleAutomationObject.hpp">
#ifndef OLE_AUTOMATION_OBJECT
#define OLE_AUTOMATION_OBJECT
#include "wrapper/windows_h.h"
#include <ole2.h> // IDispatch
#include <comdef.h> // _com_ptr_t, _variant_t, _=
bstr_t
#include <vector>
#include <stdexcept>
#include <string>
namespace alfs
{
namespace detail
{
// Exception helper, should really be in a file of its =
own:
bool throwX( char const s[] ) { throw std::runtime_erro=
r( s ); }
std::string narrow( wchar_t const wide[] )
{
std::string result( 2*wcslen(wide), '\0' );
size_t const n = wcstombs( &result[0], wide, =
result.size() );
(n != size_t(-1)) || throwX( "alfs::narrow: f=
ailed" );
result.resize( n );
return result;
}
bool throwHRX( char const s[], HRESULT hr )
{
throw std::runtime_error( s + narrow( _com_erro=
r( hr
).ErrorMessage() ) );
}
_COM_SMARTPTR_TYPEDEF( IDispatch, __uuidof(IDispatch) )=
; // IDispatchPtr
} // namespace detail
class DispatchParams
{
private:
std::vector<VARIANTARG> myArgValues;
std::vector<DISPID> myNamedArgIds;
DISPPARAMS myParams;
DispatchParams( DispatchParams const& ); =
// No such.
DispatchParams& operator=( DispatchParams const& ); /=
/ No such.
public:
static VARIANTARG defaultParam()
{
VARIANTARG v = {};
v.vt = VT_ERROR;
v.scode = DISP_E_PARAMNOTFOUND;
return v;
}
DispatchParams( int nParameters )
: myArgValues( nParameters == 0? 1 : nParam=
eters, defaultParam() )
, myNamedArgIds( 1 )
{
myParams.rgvarg = &my=
ArgValues[0];
myParams.rgdispidNamedArgs = &myNamedArgId=
s[0];
myParams.cArgs = n=
Parameters;
myParams.cNamedArgs = 0;
}
~DispatchParams()
{
// Not really sure if this should be done or is=
callee's
responsibility,
// and I'm too lazy to check that just for a Us=
enet posting!
Anyway, it
// seems to work.
for( size_t i = 0; i < myArgValues.size();=
++i )
{
::VariantClear( &myArgValues[i] );
}
}
void setParam( size_t i, std::wstring const& s )
{
_variant_t v( s.c_str() );
myArgValues.at( (myArgValues.size() - 1) - i ) =
= v.Detach();
}
DISPPARAMS* ptr() { return &myParams; }
};
class OleAutomationObject
{
private:
detail::IDispatchPtr myDispatch;
enum CallTypeEnum
{
methodCall = DISPATCH_METHOD,
propertyGet = DISPATCH_PROPERTYGET,
propertyPut = DISPATCH_PROPERTYPUT,
propertyPutRef = DISPATCH_PROPERTYPUTREF
};
_variant_t invokeAs(
CallTypeEnum callType,
wchar_t const name[],
DispatchParams& params
) const
{
using namespace detail;
EXCEPINFO exceptionInfo =
= {};
_variant_t returnValue;
unsigned erronousArgIndex =
= 0;
DISPID const dispId = dispIdOf( name );
HRESULT const hr = myDispatch->Invoke(
dispId,
IID_NULL, // reserv=
ed
0, /=
/ locale id
static_cast<WORD>( callType ),
params.ptr(),
&returnValue, // VARIANT FA=
R* pVarResult
&exceptionInfo, // EXCEPINFO FA=
R* pExcepInfo
&erronousArgIndex
);
(SUCCEEDED( hr )) || throwHRX( "OleAutomationOb=
ject: Invoke: ", hr );
return returnValue;
}
public:
OleAutomationObject( wchar_t const progId[], DWORD serv=
erType =
CLSCTX_ALL )
: myDispatch( progId, 0, serverType )
{
using namespace detail;
(myDispatch != 0) || throwX( "OleAutomationOb=
ject::<init> failed" );
}
DISPID dispIdOf( wchar_t const name[] ) const
{
using namespace detail;
DISPID dispId = 0;
HRESULT const hr = myDispatch->GetIDsOfNames(=
IID_NULL, // reserv=
ed
const_cast<wchar_t**>( &name ),
1, /=
/ count of names
0, /=
/ locale id
&dispId
);
(SUCCEEDED( hr )) ||
throwHRX( "OleAutomationObject::dispIdO=
f: GetIDsOfNames: ", hr );
return dispId;
}
_variant_t call( wchar_t const methodName[], DispatchPa=
rams& params )
{
return invokeAs( methodCall, methodName, params=
);
}
_variant_t call( wchar_t const methodName[], int nArgs =
)
{
DispatchParams params( nArgs );
return call( methodName, params );
}
_variant_t get( wchar_t const propertyName[] ) const
{
// E.g. WordApp.Name requires non-zero arg poin=
ters. Silly.
DispatchParams params( 0 );
return invokeAs( propertyGet, propertyName, par=
ams );
}
_bstr_t getAsBString( wchar_t const propertyName[] ) co=
nst
{
return get( propertyName );
}
std::wstring getAsStdString( wchar_t const propertyName=
[] ) const
{
return getAsBString( propertyName ).operator wc=
har_t const*();
}
};
}
#endif
</code>
<code file="main.cpp">
#include <cassert>
#include <iostream>
#include <ostream>
#include <stdexcept>
#include <string>
#include "OleAutomationObject.hpp"
bool throwX( char const s[] ) { throw std::runtime_error( s ); }
class WshShell: public alfs::OleAutomationObject
{
private:
void quit()
{
try
{
call( L"Quit", 3 ); // 3 defaulted argu=
ments.
}
catch( std::exception const& )
{
assert( "Word application object failed to quit=
" && 0 );
std::abort();
}
}
public:
WshShell(): alfs::OleAutomationObject( L"WScript.Shell" ) {}
long run( std::wstring const& path )
{
alfs::DispatchParams params( 3 );
params.setParam( 0, path );
return call( L"Run", params );
}
};
struct ComUsage
{
ComUsage()
{
...
read more =BB- Hide quoted text -
- Show quoted text -