当前位置: 首页 >> 程序设计 >> 远程调用技术代码追踪(webservice)
 

远程调用技术代码追踪(webservice)

作者:      来源:http://blog.csdn.net/wu_yanan2003     发表时间:2007-02-27     浏览次数:      字号:    

 
//这里是最重要的地方:这个函数完成了。打包,传递,并返回服务器端结果。我们仔细研究一下。
 
function TRIO.Generic(CallID: Integer; Params: Pointer): Int64;
。。。。
MethMD := IntfMD.MDA[CallID]; //得到方法相应的属性。
FContext.SetMethodInfo(MethMD); // FContext 产生虚拟的表函数表格。
 
procedure TInvContext.SetMethodInfo(const MD: TIntfMethEntry);
begin
 SetLength(DataP, MD.ParamCount + 1);
 SetLength(Data, (MD.ParamCount + 1) * MAXINLINESIZE);
end;
 
if MethMd.CC <> ccSafeCall then
 begin
    if RetOnStack(MethMD.ResultInfo) then
    begin
      RetP := Pointer(PInteger(P)^);
      if MethMD.ResultInfo.Kind = tkVariant then
        IncPtr(P, sizeof(Pointer))
      else
        IncPtr(P, GetStackTypeSize(MethMD.ResultInfo, MethMD.CC));
      if MethMD.CC in [ccCdecl, ccStdCall] then
      begin
        IncPtr(P, sizeof(Pointer));   { Step over self }
      end;
    end else
      RetP := @Result;
    FContext.SetResultPointer(RetP);
 end;
//把相应的返回信息压入Fcontext中。
 
for J := 0 to MethMD.ParamCount - 1 do
 begin
    FContext.SetParamPointer(ParamIdx, P);
    with MethMD.Params[J] do
    begin
      if (Info.Kind = tkVariant) and
         (MethMD.CC in [ccCdecl, ccStdCall, ccSafeCall]) and
         not (pfVar in Flags) and
         not (pfOut in Flags) then
      begin
        IncPtr(P, sizeof(TVarData)); { NOTE: better would be to dword-align!! }
      end
      else if IsParamByRef(Flags, Info, MethMD.CC) then
        IncPtr(P, 4)
      else
        IncPtr(P, GetStackTypeSize(Info, MethMD.CC));
    end;
    Inc(ParamIdx, LeftRightOrder);
 end;
//把相应的参数压入Fcontext中。
//转换成XML封包,并写入流中,这里就是具体打包的地方:
大家看清楚了:
Req := FConverter.InvContextToMsg(IntfMD, MethNum, FContext, FHeadersOutBound);
现在来好好研究一下它是怎么转换成XML封包的。
function TOPToSoapDomConvert.InvContextToMsg(const IntfMD: TIntfMetaData; MethNum: Integer;
                                            Con: TInvContext; Headers: THeaderList): TStream;
 
MethMD := IntfMD.MDA[MethNum];
首先得到方法的动态信息。
XMLDoc := NewXMLDocument; 看看这句:
 
function TOPToSoapDomConvert.NewXMLDocument: IXMLDocument;
begin
 Result := XMLDoc.NewXMLDocument;
 Result.Options := Result.Options + [doNodeAutoIndent];
 Result.ParseOptions := Result.ParseOptions + [poPreserveWhiteSpace];
end;
 
function NewXMLDocument(Version: DOMString = '1.0'): IXMLDocument;
begin
 Result := TXMLDocument.Create(nil);
 Result.Active := True;
 if Version <> '' then
    Result.Version := Version;
end;
创建了一个TXMLDocument对象用于读写XML。
 
procedure TXMLDocument.SetActive(const Value: Boolean);
begin
 。。。。
      CheckDOM;
      FDOMDocument := DOMImplementation.createDocument('', '', nil);
      try
        LoadData;
      except
        ReleaseDoc(False);
        raise;
      end;
      DoAfterOpen;
    end
    else
    begin
      DoBeforeClose;
      ReleaseDoc;
      DoAfterClose;
    end;
 end;
end;
 
procedure TXMLDocument.CheckDOM;
begin
 if not Assigned(FDOMImplementation) then
    if Assigned(FDOMVendor) then
      FDOMImplementation := FDOMVendor.DOMImplementation
    else
      FDOMImplementation := GetDOM(DefaultDOMVendor);
end;
在TXMLDocument内部使用了Abstract Factory模式
Abstract Factory希望不用指定具体的类,但为了找到它们,在TXMLDocument是通过指定一个字符串,也就是我们点击DOMVendor时出现的哪几个字符串.
 
GetDOM函数如下:
Result := GetDOMVendor(VendorDesc).DOMImplementation;
 
//根据传递进去的名字,创建相应在的实例:
function GetDOMVendor(VendorDesc: string): TDOMVendor;
begin
 if VendorDesc = '' then
    VendorDesc := DefaultDOMVendor;
 if (VendorDesc = '') and (DOMVendorList.Count > 0) then
    Result := DOMVendorList[0]
 else
    Result := DOMVendorList.Find(VendorDesc);
 if not Assigned(Result) then
   raise Exception.CreateFmt(SNoMatchingDOMVendor, [VendorDesc]);
end;
 
最后取得一个IDOMImplementation,它有一个createDocument(….):IDOMDocument;函数,这个函数将返回一个IDOMDocument;接口让IXMLDoucment使用。
//由此可见,默认状态下是创建DOM,微软的XML解析器。
function DOMVendorList: TDOMVendorList;
begin
 if not Assigned(DOMVendors) then
    DOMVendors := TDOMVendorList.Create;
 Result := DOMVendors;
end;
function TDOMVendorList.GetVendors(Index: Integer): TDOMVendor;
begin
 Result := FVendors[Index];
end;
如果为空,就返回默认的。
function TMSDOMImplementationFactory.DOMImplementation: IDOMImplementation;
begin
 Result := TMSDOMImplementation.Create(nil);
end;
 
再返回到函数:
procedure TXMLDocument.SetActive(const Value: Boolean);
 
 FDOMDocument := DOMImplementation.createDocument('', '', nil);
继续:
function TMSDOMImplementation.createDocument(const namespaceURI,
 qualifiedName: DOMString; doctype: IDOMDocumentType): IDOMDocument;
begin
 Result := TMSDOMDocument.Create(MSXMLDOMDocumentCreate);
end;
 
在如果使用MSXML,接口对应的是TMSDOMDocument,TMSDOMDocument是实际上是调用MSXML技术,下面是调用MS COM的代码
 
function CreateDOMDocument: IXMLDOMDocument;
begin
 Result := TryObjectCreate([CLASS_DOMDocument40, CLASS_DOMDocument30,
    CLASS_DOMDocument26, msxml.CLASS_DOMDocument]) as IXMLDOMDocument;
 if not Assigned(Result) then
    raise DOMException.Create(SMSDOMNotInstalled);
end;
 
再返回到函数:
procedure TXMLDocument.SetActive(const Value: Boolean);
..
LoadData
 
//因为是新建的TXMLDocument,所以装内空数据,立即返回。
procedure TXMLDocument.LoadData;
const
 UnicodeEncodings: array[0..2] of string = ('UTF-16', 'UCS-2', 'UNICODE');
var
 Status: Boolean;
 ParseError: IDOMParseError;
 StringStream: TStringStream;
 Msg: string;
begin
 …
Status := True; { No load, just create empty doc. }
创建空的文档:
 
 if not Status then
 begin
    DocSource := xdsNone;
    ParseError := DOMDocument as IDOMParseError;
    with ParseError do
      Msg := Format('%s%s%s: %d%s%s', [Reason, SLineBreak, SLine,
        Line, SLineBreak, Copy(SrcText, 1, 40)]);
    raise EDOMParseError.Create(ParseError, Msg);
 end;
 SetModified(False);
end;
设置不能修改。因为空文档。
 
继续返回到
function NewXMLDocument(Version: DOMString = '1.0'): IXMLDocument;
begin
 if Version <> '' then
    Result.Version := Version;
end;
procedure TXMLDocument.SetVersion(const Value: DOMString);
begin
 SetPrologValue(Value, xpVersion);
end;
procedure TXMLDocument.SetPrologValue(const Value: Variant;
….
    PrologNode := GetPrologNode;
    PrologAttrs := InternalSetPrologValue(PrologNode, Value, PrologItem);
    NewPrologNode := CreateNode('xml', ntProcessingInstr, PrologAttrs);
    if Assigned(PrologNode) then
      Node.ChildNodes.ReplaceNode(PrologNode, NewPrologNode)
    else
      ChildNodes.Insert(0, NewPrologNode);
 end;
 
 
NewPrologNode := CreateNode('xml', ntProcessingInstr, PrologAttrs);
这句调用了:
function TXMLDocument.CreateNode(const NameOrData: DOMString;
 NodeType: TNodeType = ntElement; const AddlData: DOMString = ''): IXMLNode;
begin
 Result := TXMLNode.Create(CreateDOMNode(FDOMDocument, NameOrData,
    NodeType, AddlData), nil, Self);
end;
 
 
在返回到这个函数中:
function TOPToSoapDomConvert.InvContextToMsg(const IntfMD: TIntfMetaData; MethNum: Integer;
                                             Con: TInvContext; Headers: THeaderList): TStream;
BodyNode := Envelope.MakeBody(EnvNode);
 
if not (soLiteralParams in Options) then
 begin
    SoapMethNS := GetSoapNS(IntfMD);
    ExtMethName := InvRegistry.GetMethExternalName(IntfMD.Info, MethMD.Name)
 
;;;;;
 
//创建一个SOAP的body:
function TSoapEnvelope.MakeBody(ParentNode: IXMLNode): IXMLNode;
begin
   Result := ParentNode.AddChild(SSoapNameSpacePre + ':' + SSoapBody, SSoapNameSpace);
end;
 
 
SoapMethNS := GetSoapNS(IntfMD); 返回:'urn:MyFirstWSIntf-IMyFirstWS'
ExtMethName := InvRegistry.GetMethExternalName(IntfMD.Info, MethMD.Name);
得到调用方法名。剩下的部分就是把参数打包。生成SOAP的源文件。然后写到内存流中。
 
 
再回到函数中:InvContextToMsg
 Result := TMemoryStream.Create();
 DOMToStream(XMLDoc, Result);
把内存块的数据,转化成XML。
具体的函数如下:
procedure TOPToSoapDomConvert.DOMToStream(const XMLDoc: IXMLDocument; Stream: TStream);
var
 XMLWString: WideString;
 StrStr: TStringStream;
begin
 
   if (FEncoding = '') or (soUTF8EncodeXML in Options) then
 begin
    XMLDoc.SaveToXML(XMLWString);
    StrStr := TStringStream.Create(UTF8Encode(XMLWString));
    try
      Stream.CopyFrom(StrStr, 0);
    finally
      StrStr.Free;
    end;
 end else
    XMLDoc.SaveToStream(Stream);
end;
我们跟踪之后StrStr的结果如下:
 
'<?xml version="1.0"?>'#$D#$A'<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/">'#$D#$A' <SOAP-ENV:Body SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">'#$D#$A'    <NS1:GetObj xmlns:NS1="urn:MyFirstWSIntf-IMyFirstWS">'#$D#$A'      <a xsi:type="xsd:int">3</a>'#$D#$A'      <b xsi:type="xsd:int">4</b>'#$D#$A'    </NS1:GetObj>'#$D#$A' </SOAP-ENV:Body>'#$D#$A'</SOAP-ENV:Envelope>'#$D#$A
 
 
转化后继续调用Generic函数:
。。。。
FWebNode.BeforeExecute(IntfMD, MethMD, MethNum-3, nil);
 
if (BindingType = btMIME) then
begin
。。。
FWebNode.BeforeExecute(IntfMD, MethMD, MethNum-3, nil);
 
THTTPReqResp.BeforeExecute
。。。。。
MethName := InvRegistry.GetMethExternalName(IntfMD.Info, MethMD.Name);
FSoapAction := InvRegistry.GetActionURIOfInfo(IntfMD.Info, MethName, MethodIndex);
得到方法名和FsoapAction
FBindingType := btSOAP
 
DoBeforeExecute // TRIO.
if Assigned(FOnBeforeExecute) then
退出:
 
继续:
Resp := GetResponseStream(RespBindingType);
 
 
 
继续返回到TRIO.Generic函数中执行:
try
   FWebNode.Execute(Req, Resp);
比较重要的部分:
 
这个函数就是THTTPReqResp向IIS发出请求。并返回信息:
 
procedure THTTPReqResp.Execute(const Request: TStream; Response: TStream);
begin
 …
    Context := Send(Request);
    try
      try
        Receive(Context, Response);
        Exit;
      except
        on Ex: ESOAPHTTPException do
        begin
          Connect(False);
          if not CanRetry or not IsErrorStatusCode(Ex.StatusCode) then
            raise;
          { Trigger UDDI Lookup }
          LookUpUDDI := True;
          PrevError := Ex.Message;
        end;
        else
        begin
          Connect(False);
          raise;
        end;
      end;
    finally
      if Context <> 0 then
        InternetCloseHandle(Pointer(Context));
    end;
 end;
{$ENDIF}
end;
 
现在看看Send函数,看看到底如何发送数据给WEB服务器的。
function THTTPReqResp.Send(const ASrc: TStream): Integer;
var
 Request: HINTERNET;
 RetVal, Flags: DWord;
 P: Pointer;
 ActionHeader: string;
 ContentHeader: string;
 BuffSize, Len: Integer;
 INBuffer: INTERNET_BUFFERS;
 Buffer: TMemoryStream;
 StrStr: TStringStream;
begin
 { Connect }
 Connect(True);
 
 Flags := INTERNET_FLAG_KEEP_CONNECTION or INTERNET_FLAG_NO_CACHE_WRITE;
 if FURLScheme = INTERNET_SCHEME_HTTPS then
 begin
    Flags := Flags or INTERNET_FLAG_SECURE;
    if (soIgnoreInvalidCerts in InvokeOptions) then
      Flags := Flags or (INTERNET_FLAG_IGNORE_CERT_CN_INVALID or
                         INTERNET_FLAG_IGNORE_CERT_DATE_INVALID);
 end;
 
 Request := nil;
 try
    Request := HttpOpenRequest(FInetConnect, 'POST', PChar(FURLSite), nil,
                               nil, nil, Flags, 0{Integer(Self)});
    Check(not Assigned(Request));
 
    { Timeouts }
    if FConnectTimeout > 0 then
      Check(InternetSetOption(Request, INTERNET_OPTION_CONNECT_TIMEOUT, Pointer(@FConnectTimeout), SizeOf(FConnectTimeout)));
    if FSendTimeout > 0 then
      Check(InternetSetOption(Request, INTERNET_OPTION_SEND_TIMEOUT, Pointer(@FSendTimeout), SizeOf(FSendTimeout)));
    if FReceiveTimeout > 0 then
      Check(InternetSetOption(Request, INTERNET_OPTION_RECEIVE_TIMEOUT, Pointer(@FReceiveTimeout), SizeOf(FReceiveTimeout)));
 
    { Setup packet based on Content-Type/Binding }
    if FBindingType = btMIME then
    begin
      ContentHeader := Format(ContentHeaderMIME, [FMimeBoundary]);
      ContentHeader := Format(ContentTypeTemplate, [ContentHeader]);
      HttpAddRequestHeaders(Request, PChar(MIMEVersion), Length(MIMEVersion), HTTP_ADDREQ_FLAG_ADD);
 
      { SOAPAction header }
      { NOTE: It's not really clear whether this should be sent in the case
              of MIME Binding. Investigate interoperability ?? }
      if not (soNoSOAPActionHeader in FInvokeOptions) then
      begin
        ActionHeader:= GetSOAPActionHeader;
        HttpAddRequestHeaders(Request, PChar(ActionHeader), Length(ActionHeader), HTTP_ADDREQ_FLAG_ADD);
      end;
 
    end else { Assume btSOAP }
    begin
      { SOAPAction header }
      if not (soNoSOAPActionHeader in FInvokeOptions) then
      begin
        ActionHeader:= GetSOAPActionHeader;
        HttpAddRequestHeaders(Request, PChar(ActionHeader), Length(ActionHeader), HTTP_ADDREQ_FLAG_ADD);
      end;
 
      if UseUTF8InHeader then
        ContentHeader := Format(ContentTypeTemplate, [ContentTypeUTF8])
      else
        ContentHeader := Format(ContentTypeTemplate, [ContentTypeNoUTF8]);
    end;
 
    { Content-Type }
    HttpAddRequestHeaders(Request, PChar(ContentHeader), Length(ContentHeader), HTTP_ADDREQ_FLAG_ADD);
 
    { Before we pump data, see if user wants to handle something - like set Basic-Auth data?? }
    if Assigned(FOnBeforePost) then
      FOnBeforePost(Self, Request);
 
    ASrc.Position := 0;
    BuffSize := ASrc.Size;
    if BuffSize > FMaxSinglePostSize then
    begin
      Buffer := TMemoryStream.Create;
      try
        Buffer.SetSize(FMaxSinglePostSize);
 
        { Init Input Buffer }
        INBuffer.dwStructSize := SizeOf(INBuffer);
        INBuffer.Next := nil;
        INBuffer.lpcszHeader := nil;
        INBuffer.dwHeadersLength := 0;
        INBuffer.dwHeadersTotal := 0;
        INBuffer.lpvBuffer := nil;
        INBuffer.dwBufferLength := 0;
        INBuffer.dwBufferTotal := BuffSize;
        INBuffer.dwOffsetLow := 0;
        INBuffer.dwOffsetHigh := 0;
 
        { Start POST }
        Check(not HttpSendRequestEx(Request, @INBuffer, nil,
                                    HSR_INITIATE or HSR_SYNC, 0));
        try
          while True do
          begin
            { Calc length of data to send }
            Len := BuffSize - ASrc.Position;
            if Len > FMaxSinglePostSize then
              Len := FMaxSinglePostSize;
            { Bail out if zip.. }
            if Len = 0 then
              break;
            { Read data in buffer and write out}
            Len := ASrc.Read(Buffer.Memory^, Len);
            if Len = 0 then
              raise ESOAPHTTPException.Create(SInvalidHTTPRequest);
 
            Check(not InternetWriteFile(Request, @Buffer.Memory^, Len, RetVal));
 
            RetVal := InternetErrorDlg(GetDesktopWindow(), Request, GetLastError,
              FLAGS_ERROR_UI_FILTER_FOR_ERRORS or FLAGS_ERROR_UI_FLAGS_CHANGE_OPTIONS or
              FLAGS_ERROR_UI_FLAGS_GENERATE_DATA, P);
            case RetVal of
              ERROR_SUCCESS: ;
              ERROR_CANCELLED: SysUtils.Abort;
              ERROR_INTERNET_FORCE_RETRY: {Retry the operation};
            end;
 
            { Posting Data Event }
            if Assigned(FOnPostingData) then
              FOnPostingData(ASrc.Position, BuffSize);
          end;
        finally
          Check(not HttpEndRequest(Request, nil, 0, 0));
        end;
      finally
        Buffer.Free;
      end;
    end else
    begin
      StrStr := TStringStream.Create('');
      try
        StrStr.CopyFrom(ASrc, 0);
        while True do
        begin
          Check(not HttpSendRequest(Request, nil, 0, @StrStr.DataString[1], Length(StrStr.DataString)));
          RetVal := InternetErrorDlg(GetDesktopWindow(), Request, GetLastError,
            FLAGS_ERROR_UI_FILTER_FOR_ERRORS or FLAGS_ERROR_UI_FLAGS_CHANGE_OPTIONS or
            FLAGS_ERROR_UI_FLAGS_GENERATE_DATA, P);
          case RetVal of
            ERROR_SUCCESS: break;
            ERROR_CANCELLED: SysUtils.Abort;
            ERROR_INTERNET_FORCE_RETRY: {Retry the operation};
          end;
        end;
      finally
        StrStr.Free;
      end;
    end;
 except
    if (Request <> nil) then
      InternetCloseHandle(Request);
    Connect(False);
    raise;
 end;
 Result := Integer(Request);
end;
 
 
 
function THTTPReqResp.Send(const ASrc: TStream): Integer;
先调用了:
procedure THTTPReqResp.Connect(Value: Boolean);
……
if InternetAttemptConnect(0) <> ERROR_SUCCESS then
      SysUtils.Abort;
这个函数可以说非常简单,只是尝试计算机连接到网络。
 
FInetRoot := InternetOpen(PChar(FAgent), AccessType, PChar(FProxy), PChar(FProxyByPass), 0);
创建HINTERNET句柄,并初始化WinInet的API函数:
 
Check(not Assigned(FInetRoot));
    try
      FInetConnect := InternetConnect(FInetRoot, PChar(FURLHost), FURLPort, PChar(FUserName),
        PChar(FPassword), INTERNET_SERVICE_HTTP, 0, Cardinal(Self));
    //创建一个特定的会话:
      Check(not Assigned(FInetConnect));
      FConnected := True;
    except
      InternetCloseHandle(FInetRoot);
      FInetRoot := nil;
      raise;
    end;
这里已经创建了一个会话:
继续返回function THTTPReqResp.Send(const ASrc: TStream): Integer;函数之中:
。。。。
Request := HttpOpenRequest(FInetConnect, 'POST', PChar(FURLSite), nil,
                               nil, nil, Flags, 0{Integer(Self)});
Check(not Assigned(Request));。
打开一个HTTP的请求。向WEB服务器提出请求:
。。
if not (soNoSOAPActionHeader in FInvokeOptions) then
      begin
        ActionHeader:= GetSOAPActionHeader;
        HttpAddRequestHeaders(Request, PChar(ActionHeader), Length(ActionHeader), HTTP_ADDREQ_FLAG_ADD);
end;
。。。
为请求添加一个或多个标头。可以看到标点的信息为:
'SOAPAction: "urn:MyFirstWSIntf-IMyFirstWS#GetObj"'
 
 
HttpAddRequestHeaders(Request, PChar(ContentHeader), Length(ContentHeader), HTTP_ADDREQ_FLAG_ADD);
继续加入标头'Content-Type: text/xml'信息:
 
      StrStr := TStringStream.Create('');
      try
        StrStr.CopyFrom(ASrc, 0);
        while True do
        begin
          Check(not HttpSendRequest(Request, nil, 0, @StrStr.DataString[1], Length(StrStr.DataString)));
建立到internet 的连接,并将请求发送到指定的站点。
这句执行完后的图如下(用工具跟踪的结果):
 
看看前面的soap生成的字符 StrStr的结果如下,发现后半部分是一样的。
 
继续
function THTTPReqResp.Execute(const Request: TStream): TStream;
Receive(Context, Response);
 
 
procedure THTTPReqResp.Receive(Context: Integer; Resp: TStream; IsGet: Boolean);
var
 Size, Downloaded, Status, Len, Index: DWord;
 S: string;
begin
 
 ..
//获取请求信息:
 HttpQueryInfo(Pointer(Context), HTTP_QUERY_CONTENT_TYPE, @FContentType[1], Size, Index);
 
 repeat
    Check(not InternetQueryDataAvailable(Pointer(Context), Size, 0, 0));
    if Size > 0 then
    begin
      SetLength(S, Size);
Check(not InternetReadFile(Pointer(Context), @S[1], Size, Downloaded));
//下载数据:
      Resp.Write(S[1], Size);
 
      { Receiving Data event }
      if Assigned(FOnReceivingData) then
        FOnReceivingData(Size, Downloaded)
    end;
 until Size = 0;
 
S的结果如下和刚才跟踪器里的是一模一样的:
'<?xml version="1.0"?>'#$D#$A'<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/">'#$D#$A' <SOAP-ENV:Body SOAP-ENC:encodingStyle="http://schemas.xmlsoap.org/soap/envelope/">'#$D#$A'    <NS1:GetObjResponse xmlns:NS1="urn:MyFirstWSIntf-IMyFirstWS">'#$D#$A'      <return xsi:type="xsd:string">12</return>'#$D#$A'    </NS1:GetObjResponse>'#$D#$A' </SOAP-ENV:Body>'#$D#$A'</SOAP-ENV:Envelope>'#$D#$A
 
最后关闭HTTP会话句柄:
 InternetCloseHandle(Pointer(Context));
 
在返回function TRIO.Generic(CallID: Integer; Params: Pointer): Int64;函数中继续查看:
 
RespXML := Resp;
返回信息的内存流
FConverter.ProcessResponse(RespXML, IntfMD, MethMD, FContext, FHeadersInbound);
 
再次把SOAP封包转换成PASCEL调用:
procedure TOPToSoapDomConvert.ProcessResponse(const Resp: TStream;
                                              const IntfMD: TIntfMetaData;
                                              const MD: TIntfMethEntry;
                                              Context: TInvContext;
                                              Headers: THeaderList);
var
 XMLDoc: IXMLDocument;
begin
 XMLDoc := NewXMLDocument;
 XMLDoc.Encoding := FEncoding;
 Resp.Position := 0;
 XMLDoc.LoadFromStream(Resp);
 ProcessResponse(XMLDoc, IntfMD, MD, Context, Headers);
end;
 
procedure TOPToSoapDomConvert.ProcessResponse(const XMLDoc: IXMLDocument;
                                              const IntfMD: TIntfMetaData;
                                              const MD: TIntfMethEntry;
                                              Context: TInvContext;
                                              Headers: THeaderList);
var
 ProcessSuccess(RespNode, IntfMD, MD, Context);
 
ProcessSuccess函数如下:
….
 for I := 0 to RespNode.childNodes.Count - 1 do
    begin
      Node := RespNode.childNodes[I];
      { Skip non-valid nodes }
      if Node.NodeType <> ntElement then
        continue;
   
// 处理返回值:
      if I = RetIndex then
      begin
        InvData := InvContext.GetResultPointer;
        ByRef := IsParamByRef([pfOut], MD.ResultInfo, MD.CC);
        ConvertSoapToNativeData(InvData, MD.ResultInfo, InvContext, RespNode, Node, True, ByRef, 1);
 
 
ConvertSoapToNativeData(InvData, MD.ResultInfo, InvContext, RespNode, Node, True, ByRef, 1);
把SOAP的结果,写入返回区地址空间。
 

[1] [2] [3]

责任编辑 webmaster

 
 
 
 
 
评论更多>>
 
 
 
发表
 
姓名: QQ:
性别: MSN:
E-mail: 主页:
评分: 1 2 3 4 5
评论内容:
验证码:
  
  • 请遵守《互联网电子公告服务管理规定》及中华人民共和国其他各项有关法律法规。
  • 严禁发表危害国家安全、损害国家利益、破坏民族团结、破坏国家宗教政策、破坏社会稳定、侮辱、诽谤、教唆、淫秽等内容的评论 。
  • 用户需对自己在使用本站服务过程中的行为承担法律责任(直接或间接导致的)。
  • 本站管理员有权保留或删除评论内容。
  • 评论内容只代表网友个人观点,与本网站立场无关。
  •