Re: Init COM interfaces
Wow, thanks Alf for the help.
but mine main problem was the following line of your code:
WordAppObject wordApp;
i.e. I didn't know the type of my COM (WordAppObject in you case).
Thanks for your concern and time,
Alex
On Apr 2, 4:09 pm, "Alf P. Steinbach" <al...@start.no> wrote:
* Alex:
The only documentation I have is some example in VB:
Dim oI As Object
oI = CreateObject("SomeCOM.SomeInterface")
oI.Init()
[snip]
> But this VB example doesn't give me any idea about this COM class
name. So my question is - do I have to ask this COM distributors for
some additional information - Interface Classes/Namespaces, GUIDs...?
Or something can be done just knowing that this COM object was
registered and ProgID is "SomeCOM.SomeInterface" ?
Well you have already solved the problem and got good advice.
But I was inspired by your question to do a bit of coding, it's so long ag=
o!
So herewith, the most (well, OK, at least a very) inefficient way to outpu=
t the
text "Microsoft Word". Perhaps this can be useful to someone else, even=
if the
functionality and error handling etc. is rather incomplete. And perhaps=
I or
others can learn something from comments about how to do this in an easier=
way
(of course not using type lib, since that's the point) or errors, whatever=
..
Cheers,
- Alf
<output comment="After a little waiting period... :-)">
Microsoft Word
</output>
<code filename="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 WordAppObject: 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:
WordAppObject(): alfs::OleAutomationObject( L"Word.Application"=
) {}
~WordAppObject() { quit(); }
std::wstring name() const { return getAsStdString( L"Name" ); }=
};
struct ComUsage
{
ComUsage()
{
(SUCCEEDED( CoInitialize(0) )) || throwX( "CoInitialize=
failed" );
}
~ComUsage() { CoUninitialize(); }
};
void cppMain()
{
ComUsage com;
WordAppObject wordApp;
std::wcout << wordApp.name() << std::endl;
}
int main()
{
try
{
cppMain();
return EXIT_SUCCESS;
}
catch( std::exception const& x )
{
std::cerr << "!" << x.what() << std::endl;
return EXIT_FAILURE;
}} // main
</code>
<code filename="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;
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;
}
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>