Watch, Follow, &
Connect with Us
Public Report
Report From: Delphi-BCB/Database/DataSnap    [ Add a report in this area ]  
Report #:  78752   Status: Open
Encounter "Invalid Pointer Operation" when access DataSnap service via in-process
Project:  Delphi Build #:  14.0.3513.24210
Version:    14.0 Submitted By:   Chee Yang Chau
Report Type:  Basic functionality failure Date Reported:  10/18/2009 8:33:58 AM
Severity:    Commonly encountered problem Last Updated: 3/20/2012 2:24:39 AM
Platform:    All platforms Internal Tracking #:   277617
Resolution: None (Resolution Comments) Resolved in Build: : None
Duplicate of:  None
Voting and Rating
Overall Rating: No Ratings Yet
0.00 out of 5
Total Votes: None
Description
To create a in-process DataSnap application, we may assign TSQLConnection.Driver to the name of a local TDSServer instance.  However, we will encounter "invalid pointer operation" exception.

One of the cause of the problem has filed in QC#78666 (Title: Mismatched in datapacket with DSUtil.StreamToDataPacket)

In addition to the reported QC#78666, there is another problem.  An in-process DataSnap create an instance of TDSServerCommand.  A method of TDSServerCommand create TDBXNoOpRow instance:

function TDSServerCommand.CreateParameterRow: TDBXRow;
begin
  Result := TDBXNoOpRow.Create(FDbxContext);
end;

Most of the methods in TDBXNoOpRow is not implemented.  There are 2 methods in class TDBXNoOpRow, GetStream and SetStream are used in subsequence operations.  This is the reason that cause the exception.

After fix TDBXNoOpRow problem, the data packet will transport to ClientDataSet successfully.  However, you may encounter another "invalid pointer operation" expcetion.  The problem is due to the following 2 methods:

1. procedure TDBXStreamValue.SetValue
2. function TDBXLookAheadStreamReader.ConvertToMemoryStream: TStream;

TDBXLookAheadStreamReader.ConvertToMemoryStream return a managed FStream object to TDBXStreamValue.SetValue.  This stream object become another managed object of TDBXStreamValue.  It turns out that a Stream object managed by two objects and the exception raised when these 2 objects attempt to free the Stream object.

procedure TDBXStreamValue.SetValue(const Value: TDBXValue);
begin
  if Value.IsNull then
    SetNull
  else
  begin
    SetStream(Value.GetStream(False), True);
  end;
end;

function TDBXLookAheadStreamReader.ConvertToMemoryStream: TStream;
...
begin
  if FStream = nil then
    Result := nil
  else
  begin
    Count := Size;
    if not (FStream is TMemoryStream) then
    begin
      ...
      StreamTemp := FStream;
      FStream := Stream;
      FreeAndNil(StreamTemp);
    end;
    FStream.Seek(0, soFromBeginning);
    FHasLookAheadByte := false;

    Result := FStream;
  end;
end;


Steps to Reproduce:
1. Attempt to fix QC#78666 by modify the DBX source code.

2. Run the following code:

var Q: TSQLConnection;
    D: TDSServer;
    C: TDSServerClass;
    P: TServerProvider;
    N: TDSProviderConnection;
begin
  P := TServerProvider.Create(nil);
  D := TDSServer.Create(nil);
  C := TDSServerClass.Create(nil);
  Q := TSQLConnection.Create(nil);
  N := TDSProviderConnection.Create(nil);
  try
    C.Server := D;
    C.OnGetClass := OnGetClass;

    D.Start;

    Q.DriverName := 'DSServer';
    Q.LoginPrompt := False;
    Q.Open;

    N.SQLConnection := Q;
    N.ServerClassName := 'TServerProvider';
    N.Connected := True;

    ClientDataSet1.RemoteServer := N;
    ClientDataSet1.ProviderName := 'DataSetProvider1';
    ClientDataSet1.Open;

    ShowMessage(IntToStr(ClientDataSet1.RecordCount));
  finally
    N.Free;
    Q.Free;
    C.Free;
    D.Free;
    P.Free;
  end;

3. You may also run a demo project from attachment.
Workarounds
Refer to http://chee-yang.blogspot.com/2009/10/datasnap-in-process-iappserver.html
Attachment
QC78752.zip
Comments

Markus Humm at 11/18/2009 4:09:37 AM -
Marked as "needs attention"

Server Response from: ETNACODE01