delphidelphi-7msxmldelphi-5serverxmlhttp

MSXML2.ServerXMLHTTP late binding "send" method with BSTR fails with "the parameter is incorrect"


I'm having a VERY strange behavior with MSXML2.ServerXMLHTTP/MSXML2.XMLHTTP.3.0.
The problem is with the send method. which can accept BSTR/SAFEARRAY/XMLDOC object/IStream

This code works fine and worked for years (the usage of FServiceUrl, FReqXML naming is intentional):

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;

Now I needed to wrap this procedure into a simple class:

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;

Strangely, the above line xmlHttp.send(FReqXML); is raising an exception:

EOleException: "the parameter is incorrect"

Notice that FReqXML types are identical in both cases (WideString/BSTR)

A simple test:

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;

I simply cannot understand why this exception occurs!

If I explicitly "convert" FReqXML to WideString with VarToWideStr in TXMLHttpNet.PostRequest it works ok:

xmlHttp.send(VarToWideStr(FReqXML));

Or even strangely like this (!):

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

Question: What is going on here?
From what I can tell FReqXML is a WideString/BSTR in both cases.
Why is FReqXML parameter behaves differently in the two situations?


Solution

  • You're right that FReqXML is of the same type in both cases, but in the latter case, its memory is allocated in relation to the object's memory (heap). Depending on the Delphi version and the compiler settings, this may cause different behaviour of the memory used for the string than for local use only (stack). Which is why VarToWideStr does work (and oddly enough extra parentheses also apparently).

    Apart from that, I would very strongly recommend importing the MSXML2 type library and using that. It uses early binding, and that not only improves performance, it enabled code-completion in the code editor.

    You could use the Type Library importer to generate it, or use a copy I have here.

    Then, don't use OleVariantand CreateOleObject (which causes late binding), but use CoServerXMLHTTP.Create and the XMLHTTP interface type.