Search code examples
c++c++buildervclole

Borland C++ - using OLE to open RTF file using Word


I'm new with Embarcadero C++Builder, VCL and OLE. What I'm trying to do is open an RTF file using OLE, but I'm getting an exception:

Bad variable type

when executing this line:

wordDoc = wordDoc.OleFunction( "open", file );

I'm not sure how to fix this. Here is my code:

//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop
#include <tchar.h>

#include <System.hpp>
#include <oleauto.h>
#include <sysvari.h>
//---------------------------------------------------------------------------
int WINAPI _tWinMain(HINSTANCE, HINSTANCE, LPTSTR, int)
{
    try
    {
        Application->Initialize();

        UnicodeString file( "C:\\TempFiles\\Test.rtf" );

        Variant wordApp = Variant::CreateObject( "word.application" );
        wordApp.OlePropertySet( "Visible", Variant( false ) );

        Variant wordDoc = wordApp.OlePropertyGet( "documents" );
        wordDoc = wordDoc.OleFunction( "open", file );

        //Application->MainFormOnTaskBar = true;
        //Application->Run();
    }
    catch (Exception &exception)
    {
        Application->ShowException(&exception);
    }
    catch (...)
    {
        try
        {
            throw Exception("");
        }
        catch (Exception &exception)
        {
            Application->ShowException(&exception);
        }
    }
    return 0;
}
//---------------------------------------------------------------------------

Solution

  • The problem is that you are passing a UnicodeString in the 2nd parameter of Variant::OleFunction() when calling Word's Open() function.

    Internally, OleFunction() converts the input parameters to Variant values (rather than OleVariant), and then passes them as-is to IDispatch::Invoke().

    Variant is compatible with OLE only when it holds OLE-compatible data. UnicodeString is specific to Delphi/C++Builder and unknown to OLE, so it is not OLE-compatible.

    When a Variant is assigned a UnicodeString value, its VType field is set to varUString (0x0102), and its payload is a pointer to the UnicodeString's internal data with its refCnt field incremented (the Variant will decrement the refCnt when destroyed).

    OLE is complaining about that unsupported VType value when your UnicodeString-turned-Variant is passed to IDispatch::Invoke().

    To fix the error, you need to instead pass a WideString to OleFunction(). WideString is a wrapper for an OLE BSTR string. When a Variant is assigned a WideString value, its VType field is set to varOleStr (0x0008, aka VT_BSTR in OLE), and its payload is a proper BSTR pointer that is a copy of the WideString data (the Variant will free the BSTR when destroyed).

    So, you need to either:

    • change your file variable to WideString:

      WideString file( L"C:\\TempFiles\\Test.rtf" );
      
    • keep your file variable as UnicodeString, but convert it to WideString when passing it to OleFunction():

      wordDoc = wordDoc.OleFunction( L"open", WideString(file) );