Консольное приложение C ++ Builder, которое вызывает веб-сервис (привет мир) - PullRequest
2 голосов
/ 21 февраля 2012

Я пытаюсь написать пример "Hello World", используя C ++ Builder. Это мой первый проект, поэтому я, вероятно, допустил простую ошибку.

Я хочу создать консольное приложение, которое вызывает веб-сервис калькулятора.

Я открываю C ++ Builder 2007 и создаю консольное приложение. Появляется файл cpp с именем File1.cpp. Вот это содержание:

//---------------------------------------------------------------------------
#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;
}
//---------------------------------------------------------------------------

Кроме того, я добавил мыльный прокси в New-> Other-> WebService-> WSDL Importer. Использование WSDL http://www.dneonline.com/calculator.asmx?WSDL

Это действие добавлено 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

Когда я запускаю приложение, оно вызывает исключение при вызове GetCalculatorSoap () -> Add (1,2):

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

Отладка, похоже, что GetCalculatorSoap () выполняется нормально, но перед вызовом метода Add возникает исключение ...

Есть идеи, что не так? Спасибо!

1 Ответ

4 голосов
/ 22 февраля 2012

Сообщение об ошибке сообщает вам, в чем проблема - CoInitialize не был вызван. (На самом деле, вместо этого лучше звонить CoInitializeEx, но любой из них будет работать.)

В вашем SOAP-коде используются методы COM, поэтому сначала нужно инициализировать COM. Это делается для каждого потока.

Вы можете исправить это, вызвав CoInitialize(NULL); 'в начале вашей функции main. Не забудьте также позвонить CoUnitialize(); в конце main.

В Delphi CoInitialize/CoUninitialize объявлены в ActiveX единице. В C ++ Builder он, кажется, находится в OBJBASE.H (быстрый поиск нашел его там, и это также то, что указано в документации MSDN .

(Если вы привыкли писать приложения на основе форм VCL, вы раньше этого не видели; VCL автоматически инициализирует для вас COM. Вы видите это сейчас, потому что пишете консольное приложение.)

...