0

我在 Delphi 中看到了很多 DataSnap 示例,但在 C++ Builder 中却很少,并且还没有弄清楚如何指定应将 TStream 返回给调用客户端。

我正在使用一个简单的配置,类似于我看到的教程。一个示例服务器方法是:

    System::UnicodeString GetData(int PatientID, int& count, TStream* stream);

我从我的客户那里调用该方法没有问题。因为 count 作为引用传递,所以 DataSnap 服务器知道将其发送回客户端。Generate Client Classes,在客户端的 TSQLConnection 上,连接到服务器,生成如下:

System::UnicodeString __fastcall TServerMethods1Client::GetData(int PatientID, int &count, TStream* stream)
{
  if (FGetDataCommand == NULL)
  {
    FGetDataCommand = FDBXConnection->CreateCommand();
    FGetDataCommand->CommandType = TDBXCommandTypes_DSServerMethod;
    FGetDataCommand->Text = "TServerMethods1.GetData";
    FGetDataCommand->Prepare();
  }
  FGetDataCommand->Parameters->Parameter[0]->Value->SetInt32(PatientID);
  FGetDataCommand->Parameters->Parameter[1]->Value->SetInt32(count);
  FGetDataCommand->Parameters->Parameter[2]->Value->SetStream(stream, FInstanceOwner);
  FGetDataCommand->ExecuteUpdate();
  count = FGetDataCommand->Parameters->Parameter[1]->Value->GetInt32();
  System::UnicodeString result = FGetDataCommand->Parameters->Parameter[3]->Value->GetWideString();
  return result;
}

可以看到生成的代码是从返回的参数中设置计数,表示服务器正在发回。但是,流只发送到服务器,而不是在客户端上设置。

在 Delphi 中,我会使用 var 来指示应该将引用传回给调用者。但是,在 TStream 上使用引用也不起作用。

对于这个定义:

    System::UnicodeString GetData(int PatientID, int& count, TStream& stream);

我得到这个生成的代码:

System::UnicodeString __fastcall TServerMethods1Client::GetData(int PatientID, int &count, TStream* &stream)
{
  if (FGetDataCommand == NULL)
  {
    FGetDataCommand = FDBXConnection->CreateCommand();
    FGetDataCommand->CommandType = TDBXCommandTypes_DSServerMethod;
    FGetDataCommand->Text = "TServerMethods1.GetData";
    FGetDataCommand->Prepare();
  }
  FGetDataCommand->Parameters->Parameter[0]->Value->SetInt32(PatientID);
  FGetDataCommand->Parameters->Parameter[1]->Value->SetInt32(count);
  FGetDataCommand->Parameters->Parameter[2]->Value->SetStream(stream, FInstanceOwner);
  FGetDataCommand->ExecuteUpdate();
  count = FGetDataCommand->Parameters->Parameter[1]->Value->GetInt32();
  stream = FGetDataCommand->Parameters->Parameter[2]->Value->GetStream(FInstanceOwner);
  System::UnicodeString result = FGetDataCommand->Parameters->Parameter[3]->Value->GetWideString();
  return result;
}

这会在 ExecuteUpdate() 调用中引发访问冲突。

有没有办法可以将指针传递给服务器方法并以某种方式标记它应该将流传递回调用客户端?

4

1 回答 1

0

雷米的回答是正确的。

服务器方法是

System::UnicodeString TServerMethods1::GetData(int PatientID, int& count, 
    TStream*& stream) {
count = 10;
String newSimpleString = "New Simple String";
TByteDynArray theBytes;
theBytes.Length = newSimpleString.Length();
for (int i = 0; i < newSimpleString.Length(); i++) {
    theBytes[i] = newSimpleString[i + 1];
}

TDBXBytesStream* newStream =
    new TDBXBytesStream(theBytes, newSimpleString.Length());
stream = newStream;
return "StringResult";

}

客户端方法是

void __fastcall TForm1::Button2Click(TObject *Sender) {
int count = 1;
TStringStream* stringStream = new TStringStream(String("Passed In"));
TStream* str = stringStream;
String result = ClientModule1->ServerMethods1Client->GetData(1, count, str);
int len = str->Size;
ShowMessage("Result is: '" + result + "' and " + String(count) +
    ", and stream is " + String(len) + " bytes long");

}

如果设置为 true(生成的默认值),作为FInstanceOwner客户端方法传入的流在下次调用该方法时将被释放。

在服务器上,新创建的 TDBXBytesStream 在下次调用服务器方法时被释放。

TDBXBytesStream 不是一个功能齐全的流 - 例如,我无法让 CopyFrom 从 TStringStream 复制(例如),这就是我使用 TByteDynArray 的原因。

此外,我无法通过写入来修改传入服务器方法的流,这就是为什么我需要为传入的引用分配一个新的 TDBXBytesStream。

谢谢,雷米,帮助我解决这个问题。

于 2013-09-14T18:39:57.613 回答