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.