3

我对MSXML2.ServerXMLHTTP/有一个非常奇怪的行为MSXML2.XMLHTTP.3.0
问题出在send方法上。哪个可以接受BSTR//对象SAFEARRAY/XMLDOCIStream

这段代码运行良好并且工作了多年FServiceUrl, FReqXML命名的使用是有意的)

procedure PostRequest(const FServiceUrl, FReqXML: WideString);
var
  xmlHttp: OleVariant;
begin
  xmlHttp := CreateOleObject('MSXML2.ServerXMLHTTP.6.0');
  xmlHttp.Open('POST', FServiceUrl, False);
  // VarType(FReqXML) -> BSTR
  xmlHttp.send(FReqXML); 
end;

现在我需要将此过程包装到一个简单的类中:

type
  TXMLHttpNet = class
  private
    FServiceUrl: WideString;
    FReqXML: WideString;        
  public
    constructor Create(const AServiceUrl, AReqXML: WideString);
    procedure PostRequest;
  end;

constructor TXMLHttpNet.Create(const AServiceUrl, AReqXML: WideString);
begin
  FServiceUrl := AServiceUrl;
  FReqXML := AReqXML;
end;

procedure TXMLHttpNet.PostRequest; // Problem is in this call
var
  xmlHttp: OleVariant;
begin
  xmlHttp := CreateOleObject('MSXML2.ServerXMLHTTP.6.0');
  xmlHttp.Open('POST', FServiceUrl, False);
  // VarType(FReqXML) -> BSTR
  xmlHttp.send(FReqXML); // EOleException: "the parameter is incorrect"
end;

奇怪的xmlHttp.send(FReqXML);是,上面一行引发了一个异常:

EOleException:“参数不正确”

请注意,FReqXML两种情况下的类型都是相同的 ( WideString/BSTR)

一个简单的测试:

uses ComObj;

procedure TForm1.Button1Click(Sender: TObject);
var
  Request: TXMLHttpNet;
begin
  // simple procedure
  PostRequest('http://www.gmail.com', 'foo'); // OK!
  // via object method
  Request := TXMLHttpNet.Create('http://www.gmail.com', 'foo'); 
  Request.PostRequest; // EOleException: "the parameter is incorrect"
  Request.Free;
end;

我简直无法理解为什么会发生这个异常!

如果我明确地“转换”FReqXMLWideStringwith VarToWideStrinTXMLHttpNet.PostRequest它可以正常工作:

xmlHttp.send(VarToWideStr(FReqXML));

甚至奇怪的是这样(!):

xmlHttp.send((FReqXML)); // note the double Brackets

问题:这里发生了什么?
据我所知FReqXMLWideString/BSTR在这两种情况下都是。
为什么FReqXML参数在两种情况下的行为不同?

4

1 回答 1

1

你是对的,FReqXML在这两种情况下都是相同的类型,但在后一种情况下,它的内存是相对于对象的内存(堆)分配的。根据 Delphi 版本和编译器设置,这可能会导致用于字符串的内存行为与仅用于本地使用(堆栈)的行为不同。这就是为什么VarToWideStr有效(奇怪的是,额外的括号也很明显)。

除此之外,我强烈建议导入 MSXML2 类型库并使用它。它使用早期绑定,这不仅提高了性能,而且在代码编辑器中启用了代码完成功能。

您可以使用类型库导入器来生成它,或者使用我这里的副本。

然后,不要使用OleVariantand CreateOleObject(这会导致后期绑定),而是使用CoServerXMLHTTP.CreateXMLHTTP接口类型。

于 2014-10-16T09:56:41.717 回答