我在Delphi中看到过很多DataSnap示例,但在C ++ Builder中看得很少,并且没有想出如何指定应该将TStream返回给调用客户端。
我使用的是一个简单的配置,类似于我见过的教程。示例服务器方法是:
System::UnicodeString GetData(int PatientID, int& count, TStream* stream);
从我的客户端调用该方法我没有问题。因为count作为引用传递,所以DataSnap服务器知道将它发送回客户端。在客户端的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()调用中抛出访问冲突。
有没有办法可以将指针传递给服务器方法并以某种方式标记它应该将流传递回调用客户端?
答案 0 :(得分: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");
}
如果FInstanceOwner
为true(默认为生成),则作为客户端方法传入的流将在下次调用方法时释放。
在服务器上,下次调用服务器方法时,新创建的TDBXBytesStream将被释放。
TDBXBytesStream不是一个功能齐全的流 - 例如,我无法从TStringStream复制CopyFrom(例如),这就是我使用TByteDynArray的原因。
另外,我无法通过写入来修改传入服务器方法的流,这就是为什么我需要为传入的引用分配新的TDBXBytesStream。
谢谢雷米帮我解决这个问题。