Re: Init COM interfaces
 
* 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 ago!
So herewith, the most (well, OK, at least a very) inefficient way to output 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 arguments.
         }
         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_error( 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: failed" );
             result.resize( n );
             return result;
         }
         bool throwHRX( char const s[], HRESULT hr )
         {
             throw std::runtime_error( s + narrow( _com_error( 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 : nParameters, defaultParam() )
             , myNamedArgIds( 1 )
         {
             myParams.rgvarg             = &myArgValues[0];
             myParams.rgdispidNamedArgs  = &myNamedArgIds[0];
             myParams.cArgs              = nParameters;
             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,           // reserved
                 0,                  // locale id
                 static_cast<WORD>( callType ),
                 params.ptr(),
                 &returnValue,       // VARIANT FAR*  pVarResult
                 &exceptionInfo,     // EXCEPINFO FAR*  pExcepInfo
                 &erronousArgIndex
                 );
             (SUCCEEDED( hr )) || throwHRX( "OleAutomationObject: Invoke: ", hr );
             return returnValue;
         }
     public:
         OleAutomationObject( wchar_t const progId[], DWORD serverType = 
CLSCTX_ALL )
             : myDispatch( progId, 0, serverType )
         {
             using namespace detail;
             (myDispatch != 0) || throwX( "OleAutomationObject::<init> failed" );
         }
         DISPID dispIdOf( wchar_t const name[] ) const
         {
             using namespace detail;
             DISPID  dispId  = 0;
             HRESULT const hr = myDispatch->GetIDsOfNames(
                 IID_NULL,           // reserved
                 const_cast<wchar_t**>( &name ),
                 1,                  // count of names
                 0,                  // locale id
                 &dispId
                 );
             (SUCCEEDED( hr )) ||
                 throwHRX( "OleAutomationObject::dispIdOf: GetIDsOfNames: ", hr );
             return dispId;
         }
         _variant_t call( wchar_t const methodName[], DispatchParams& 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 pointers.  Silly.
             DispatchParams  params( 0 );
             return invokeAs( propertyGet, propertyName, params );
         }
         _bstr_t getAsBString( wchar_t const propertyName[] ) const
         {
             return get( propertyName );
         }
         std::wstring getAsStdString( wchar_t const propertyName[] ) const
         {
             return getAsBString( propertyName ).operator wchar_t const*();
         }
     };
}
#endif
</code>