TChromium/DCEF3 вызывает ошибку "Нарушение доступа" при использовании SOAP с Delphi7

У меня есть 32-битная сборка приложения с Delphi 7, и это приложение использует TChromium (Delphi Chromium Embeded, ветвь dcef3-2378) для отображения веб-страниц. В этом приложении я использую сервис SOAP для проверки номера НДС на ec.europe.eu, и это приложение дает мне доступ к Viloation.

Мой проект состоит из трех блоков:

Project1.dpr - project.
VatCheck.pas - automatically build from WSDL
Unit1.пас - form with button

Ошибка "AV" находится в этой строке в "Unit1.pas":

outp := WS.checkVat(inp);

Все нормально, когда я комментирую эту строку в "Project1.dpr":

if not CefLoadLibDefault then Exit;

Ниже приведен полный исходный код.

program Project1;

uses
  ceflib,
  Forms,
  Unit1 in 'Unit1.pas' {Form1},
  VatCheck in 'VatCheck.pas';

{$R *.res}

begin
   CefSingleProcess := False;
   if not CefLoadLibDefault then Exit;
   //
   Application.Initialize;
   Application.CreateForm(TForm1, Form1);
   Application.Run;
end.



unit VatCheck;

interface

uses InvokeRegistry, SOAPHTTPClient, Types, XSBuiltIns;

const
  IS_UNQL = $0008;


type

  checkVat             = class;                 {"urn:ec.europa.eu:taxud:vies:services:checkVat:types"[Cplx] }
  checkVatResponse     = class;                 {"urn:ec.europa.eu:taxud:vies:services:checkVat:types"[Cplx] }

  // ************************************************************************ //
  // XML       : checkVat, 
  // Namespace : urn:ec.europa.eu:taxud:vies:services:checkVat:types
  // ************************************************************************ //
  checkVat = class(TRemotable)
  private
    FcountryCode: WideString;
    FvatNumber: WideString;
  published
    property countryCode: WideString  Index (IS_UNQL) read FcountryCode write FcountryCode;
    property vatNumber:   WideString  Index (IS_UNQL) read FvatNumber write FvatNumber;
  end;



  // ************************************************************************ //
  // XML       : checkVatResponse, 
  // Namespace : urn:ec.europa.eu:taxud:vies:services:checkVat:types
  // ************************************************************************ //
  checkVatResponse = class(TRemotable)
  private
    FcountryCode: WideString;
    FvatNumber: WideString;
    FrequestDate: TXSDate;
    Fvalid: Boolean;
    Fname_: WideString;
    Faddress: WideString;
  public
    destructor Destroy; override;
  published
    property countryCode: WideString  Index (IS_UNQL) read FcountryCode write FcountryCode;
    property vatNumber:   WideString  Index (IS_UNQL) read FvatNumber write FvatNumber;
    property requestDate: TXSDate     Index (IS_UNQL) read FrequestDate write FrequestDate;
    property valid:       Boolean     Index (IS_UNQL) read Fvalid write Fvalid;
    property name_:       WideString  Index (IS_UNQL) read Fname_ write Fname_;
    property address:     WideString  Index (IS_UNQL) read Faddress write Faddress;
  end;


  checkVatPortType = interface(IInvokable)
  ['{FF7DB705-D388-D555-FDCA-58B0F7D33A5F}']

    // Cannot unwrap:
    //     - The input part is not a complex type
    //     - The output part is not a complex type
    function  checkVat(const parameters: checkVat): checkVatResponse; stdcall;
  end;

function GetcheckVatPortType(UseWSDL: Boolean=System.False; Addr: string=''; HTTPRIO: THTTPRIO = nil): checkVatPortType;


implementation
uses SysUtils;

function GetcheckVatPortType(UseWSDL: Boolean; Addr: string; HTTPRIO: THTTPRIO): checkVatPortType;
const
  defWSDL = 'http://ec.europa.eu/taxation_customs/vies/checkVatService.wsdl';
  defURL  = 'http://ec.europa.eu/taxation_customs/vies/services/checkVatService';
  defSvc  = 'checkVatService';
  defPrt  = 'checkVatPort';
var
  RIO: THTTPRIO;
begin
  Result := nil;
  if (Addr = '') then
  begin
    if UseWSDL then
      Addr := defWSDL
    else
      Addr := defURL;
  end;
  if HTTPRIO = nil then
    RIO := THTTPRIO.Create(nil)
  else
    RIO := HTTPRIO;
  try
    Result := (RIO as checkVatPortType);
    if UseWSDL then
    begin
      RIO.WSDLLocation := Addr;
      RIO.Service := defSvc;
      RIO.Port := defPrt;
    end else
      RIO.URL := Addr;
  finally
    if (Result = nil) and (HTTPRIO = nil) then
      RIO.Free;
  end;
end;


destructor checkVatResponse.Destroy;
begin
  FreeAndNil(FrequestDate);
  inherited Destroy;
end;

initialization
  InvRegistry.RegisterInterface(TypeInfo(checkVatPortType), 'urn:ec.europa.eu:taxud:vies:services:checkVat', 'UTF-8');
  InvRegistry.RegisterDefaultSOAPAction(TypeInfo(checkVatPortType), '');
  InvRegistry.RegisterInvokeOptions(TypeInfo(checkVatPortType), ioDocument);
  InvRegistry.RegisterInvokeOptions(TypeInfo(checkVatPortType), ioLiteral);
  InvRegistry.RegisterExternalParamName(TypeInfo(checkVatPortType), 'checkVat', 'parameters1', 'parameters');
  RemClassRegistry.RegisterXSClass(checkVat, 'urn:ec.europa.eu:taxud:vies:services:checkVat:types', 'checkVat');
  RemClassRegistry.RegisterXSClass(checkVatResponse, 'urn:ec.europa.eu:taxud:vies:services:checkVat:types', 'checkVatResponse');
  RemClassRegistry.RegisterExternalPropName(TypeInfo(checkVatResponse), 'name_', 'name');

end.


unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Label1: TLabel;
    editCountry: TEdit;
    Label2: TLabel;
    editVAT: TEdit;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation
uses VatCheck, XSBuiltIns;

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var
   WS: checkVatPortType;
   inp: checkVat;
   outp: checkVatResponse;
begin
   WS := GetcheckVatPortType;
   inp := checkVat.Create;
   try
      inp.countryCode := editCountry.Text;
      inp.vatNumber   := editVAT.Text;
      try
         outp := WS.checkVat(inp);
      except
         on E: Exception do begin
            ShowMessage('Error: ' + E.Message);
            Exit;
         end{on};
      end{try};
      if outp.valid then ShowMessage(outp.name_ + #13#10 + outp.address)
      else ShowMessage(outp.countryCode + outp.vatNumber + ' is invalid VAT number.')
   finally
      inp.Free;
      outp.Free
   end;
end;

end.

Заранее спасибо!

1 ответ

Решение

Благодаря ответу Криса Торнтона я смог найти решение своей проблемы.

Проблема в том, что Delphi 7 не поддерживает DEP, а компоненты на основе RIO выделяют память для исполняемого кода, не помечая его как исполняемый, чтобы поддерживать DEP.

Крис также предоставил решение: перестроить код с помощью библиотек SOAP Delphi 2007.

Другие вопросы по тегам