Eduard
Eduard

Reputation: 674

C++ Builder console application that calls a webservice (hello world)

I am trying write a "Hello World" example using C++Builder. This is my first project so I have probably made a simple mistake.

I want to create a console application that calls a calculator web service.

I open C++Builder 2007 and I create a Console Application. A cpp file called File1.cpp appears. Here it is the content:

//---------------------------------------------------------------------------
#include <iostream.h>
#include <vcl.h>
#pragma hdrstop
#include "calculator.h"

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

#pragma argsused
int main(int argc, char* argv[])
{
    double a, b;

    cout << "Enter the values to sum\n";
    cout << "A: ";
    cin >> a;
    cout << "B: ";
    cin >> b;

    cout << "\nA+B:";
    cout << GetCalculatorSoap()->Add(1,2);

    cout << "\n\nPress any key to continue...";
    getchar();

    return 0;
}
//---------------------------------------------------------------------------

Additionally I added the soap proxy going into New->Other->WebService->WSDL Importer. Using the WSDL http://www.dneonline.com/calculator.asmx?WSDL

This action added calculator.cpp:

// ************************************************************************ //
// The types declared in this file were generated from data read from the
// WSDL File described below:
// WSDL     : http://www.dneonline.com/calculator.asmx?WSDL
//  >Import : http://www.dneonline.com/calculator.asmx?WSDL:0
// Encoding : utf-8
// Version  : 1.0
// (21/02/2012 19:48:31 - - $Rev: 10138 $)
// ************************************************************************ //

#include <vcl.h>
#pragma hdrstop

#if !defined(calculatorH)
#include "calculator.h"
#endif  

namespace NS_calculator {

_di_CalculatorSoap GetCalculatorSoap(bool useWSDL, 
  AnsiString addr, THTTPRIO* HTTPRIO)
{
  static const char* defWSDL= "http://www.dneonline.com/calculator.asmx?WSDL";
  static const char* defURL = "http://www.dneonline.com/calculator.asmx";
  static const char* defSvc = "Calculator";
  static const char* defPrt = "CalculatorSoap";
  if (addr=="")
    addr = useWSDL ? defWSDL : defURL;
  THTTPRIO* rio = HTTPRIO ? HTTPRIO : new THTTPRIO(0);
  if (useWSDL) {
    rio->WSDLLocation = addr;
    rio->Service = defSvc;
    rio->Port = defPrt;
  } else {
    rio->URL = addr;
  }
  _di_CalculatorSoap service;
  rio->QueryInterface(service);
  if (!service && !HTTPRIO)
    delete rio;
  return service;
}


// ************************************************************************ //
// This routine registers the interfaces and types exposed by the WebService.
// ************************************************************************ //
static void RegTypes()
{
  /* CalculatorSoap */
  InvRegistry()->RegisterInterface(__interfaceTypeinfo(CalculatorSoap),             
     L"http://tempuri.org/", L"utf-8");
  InvRegistry()->RegisterDefaultSOAPAction(__interfaceTypeinfo(CalculatorSoap), 
     L"http://tempuri.org/%operationName%");
  InvRegistry()->RegisterInvokeOptions(__interfaceTypeinfo(CalculatorSoap), 
     ioDocument);
}
#pragma startup RegTypes 32

};     // NS_calculator

When I run the application it raises an exception when calling GetCalculatorSoap()->Add(1,2):

---------------------------
Debugger Exception Notification
---------------------------
Project Test.exe raised exception class EOleSysError 
  with message 'CoInitialize has not been called'.
---------------------------
Break   Continue   Help   
---------------------------

Debugging it seems the GetCalculatorSoap() executes ok, but just before calling the Add method the exception is thrown...

Any ideas what is wrong? Thanks!

Upvotes: 3

Views: 4419

Answers (1)

Ken White
Ken White

Reputation: 125689

The error message tells you what the problem is - CoInitialize has not been called. (Actually, it's preferable to call CoInitializeEx instead, but either will work.)

Your SOAP code is using COM methods, and therefore COM has to be initialized first. This is done on a per-thread basis.

You can fix it by calling CoInitialize(NULL);' at the beginning of your main function. Don't forget to call CoUnitialize(); at the end of main as well.

In Delphi, CoInitialize/CoUninitialize are declared in the ActiveX unit. In C++Builder, it seems to be in OBJBASE.H (a quick search found it there, and that's also what's indicated in the MSDN documentation.

(If you're used to writing VCL form based apps, you won't have seen this before; the VCL initializes COM for you automatically. You're seeing it now because you're writing a console app.)

Upvotes: 5

Related Questions