c++builder调用delphi编写的datasnap程序的问题

kese 2010-05-05 11:09:33
delphi编写datasnap服务器
new datasnap server向导
unit ServerContainerUnit1;

interface

uses
SysUtils, Classes,
DSTCPServerTransport,
DSServer, DSCommonServer;

type
TServerContainer1 = class(TDataModule)
DSServer1: TDSServer;
DSTCPServerTransport1: TDSTCPServerTransport;
DSServerClass1: TDSServerClass;
procedure DSServerClass1GetClass(DSServerClass: TDSServerClass;
var PersistentClass: TPersistentClass);
private
{ Private declarations }
public
end;

var
ServerContainer1: TServerContainer1;

implementation

uses Windows, ServerMethodsUnit1;

{$R *.dfm}

procedure TServerContainer1.DSServerClass1GetClass(
DSServerClass: TDSServerClass; var PersistentClass: TPersistentClass);
begin
PersistentClass := ServerMethodsUnit1.TServerMethods1;
end;

end.



unit ServerMethodsUnit1;

interface

uses
SysUtils, Classes, DSServer, DBXJSON;

type
TServerMethods1 = class(TDSServerModule)
private
{ Private declarations }
public
{ Public declarations }
pecho: TDBXCallback;

function EchoString(Value: string): string;
procedure reg_echo(pecho: TDBXCallback);
end;

var
ServerMethods1: TServerMethods1;

implementation

{$R *.dfm}

function TServerMethods1.EchoString(Value: string): string;
var
param: TJSONObject;
returnresult: TJSONString;
begin
param := TJSONObject.Create(TJSONPair.Create('echostring',Value));
returnresult := pecho.Execute(param) as TJSONString;
Result := returnresult.Value;
end;

procedure TServerMethods1.reg_echo(pecho: TDBXCallback);
begin
self.pecho := pecho;
end;

end.

c++builder编写客户端代码

//---------------------------------------------------------------------------

#ifndef Unit4H
#define Unit4H

#include <DBXJSON.hpp>
//---------------------------------------------------------------------------
class TEchoCallback : TDBXCallback
{
public:
TJSONValue* __fastcall Execute(const TJSONValue* Arg);
};

#endif
//---------------------------------------------------------------------------


#pragma hdrstop

#include "Unit4.h"

//---------------------------------------------------------------------------

#pragma package(smart_init)

TJSONValue* __fastcall TEchoCallback::Execute(const TJSONValue* Arg)
{
TJSONString* returnstr;
TJSONObject* ArgObj = (TJSONObject*)Arg;
returnstr = new TJSONString(L"hello "+ArgObj->Get(0)->Value());
return returnstr;
}

自动生成的代码
#ifndef Unit3H
#define Unit3H

#include "DBXCommon.hpp"
#include "Classes.hpp"
#include "SysUtils.hpp"
#include "DB.hpp"
#include "SqlExpr.hpp"
#include "DBXDBReaders.hpp"

class TServerMethods1Client : public TObject
{
private:
TDBXConnection *FDBXConnection;
bool FInstanceOwner;
TDBXCommand *FEchoStringCommand;
TDBXCommand *Freg_echoCommand;
public:
__fastcall TServerMethods1Client::TServerMethods1Client(TDBXConnection *ADBXConnection);
__fastcall TServerMethods1Client::TServerMethods1Client(TDBXConnection *ADBXConnection, bool AInstanceOwner);
__fastcall TServerMethods1Client::~TServerMethods1Client();
System::UnicodeString __fastcall EchoString(System::UnicodeString Value);
void __fastcall reg_echo(TDBXCallback* pecho);
};

#endif

//
// Created by the DataSnap proxy generator.
//

#include "Unit3.h"

System::UnicodeString __fastcall TServerMethods1Client::EchoString(System::UnicodeString Value)
{
if (FEchoStringCommand == NULL)
{
FEchoStringCommand = FDBXConnection->CreateCommand();
FEchoStringCommand->CommandType = TDBXCommandTypes_DSServerMethod;
FEchoStringCommand->Text = "TServerMethods1.EchoString";
FEchoStringCommand->Prepare();
}
FEchoStringCommand->Parameters->Parameter[0]->Value->SetWideString(Value);
FEchoStringCommand->ExecuteUpdate();
System::UnicodeString result = FEchoStringCommand->Parameters->Parameter[1]->Value->GetWideString();
return result;
}

void __fastcall TServerMethods1Client::reg_echo(TDBXCallback* pecho)
{
if (Freg_echoCommand == NULL)
{
Freg_echoCommand = FDBXConnection->CreateCommand();
Freg_echoCommand->CommandType = TDBXCommandTypes_DSServerMethod;
Freg_echoCommand->Text = "TServerMethods1.reg_echo";
Freg_echoCommand->Prepare();
}
Freg_echoCommand->Parameters->Parameter[0]->Value->SetCallbackValue(pecho);
Freg_echoCommand->ExecuteUpdate();
}


__fastcall TServerMethods1Client::TServerMethods1Client(TDBXConnection *ADBXConnection)
{
if (ADBXConnection == NULL)
throw EInvalidOperation("Connection cannot be nil. Make sure the connection has been opened.");
FDBXConnection = ADBXConnection;
FInstanceOwner = True;
}


__fastcall TServerMethods1Client::TServerMethods1Client(TDBXConnection *ADBXConnection, bool AInstanceOwner)
{
if (ADBXConnection == NULL)
throw EInvalidOperation("Connection cannot be nil. Make sure the connection has been opened.");
FDBXConnection = ADBXConnection;
FInstanceOwner = AInstanceOwner;
}


__fastcall TServerMethods1Client::~TServerMethods1Client()
{
FreeAndNil(FEchoStringCommand);
FreeAndNil(Freg_echoCommand);
}

主窗口
//---------------------------------------------------------------------------

#ifndef Unit2H
#define Unit2H
//---------------------------------------------------------------------------
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
#include <DB.hpp>
#include <DbxDatasnap.hpp>
#include <SqlExpr.hpp>
#include <WideStrings.hpp>

#include "Unit3.h"
#include "Unit4.h"
//---------------------------------------------------------------------------
class TForm2 : public TForm
{
__published: // IDE-managed Components
TSQLConnection *SQLConnection1;
TButton *Button1;
void __fastcall Button1Click(TObject *Sender);
private: // User declarations
public: // User declarations
__fastcall TForm2(TComponent* Owner);
TServerMethods1Client* Server1;
};
//---------------------------------------------------------------------------
extern PACKAGE TForm2 *Form2;
//---------------------------------------------------------------------------
#endif


#pragma hdrstop

#include "Unit2.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm2 *Form2;
//---------------------------------------------------------------------------
__fastcall TForm2::TForm2(TComponent* Owner)
: TForm(Owner)
{
Server1 = new TServerMethods1Client(this->SQLConnection1->DBXConnection);
Server1->reg_echo((TDBXCallback*)new TEchoCallback());
}
//---------------------------------------------------------------------------
void __fastcall TForm2::Button1Click(TObject *Sender)
{
ShowMessage(Server1->EchoString(L"Project2"));
}
//---------------------------------------------------------------------------

[size=24px]远程调用EchoString时报错
Remote error: A callback parameter cannot be found at the provided index.[
/size]
...全文
366 6 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
6 条回复
切换为时间正序
请发表友善的回复…
发表回复
yongzhi092740 2010-06-11
  • 打赏
  • 举报
回复
好呀,谢谢呀
kese 2010-05-12
  • 打赏
  • 举报
回复
问题已经解决了。
基本原理是这样的:
datasnap2010的回调是在注册回调函数中才能被执行的。就是说回调函数的执行有一个生命,只能注册函数返回前。超过了这个时间,或者说注册函数返回了,那么回调就执行不了了。
下面给出代码,希望大家不要再和我一样迷茫了。
服务器代码
unit LEDServerMethodsUnit;


interface

uses
Classes, DBXJSON, SyncObjs, SysUtils;

type
{$METHODINFO ON}
TLEDServerMethods = class (TPersistent)
private

public
procedure start_server(PWriteAContextCallback,
PReadLEDnameCallback,
PReadSBIDCallback,
PReadAContextCallback :TDBXCallback);
procedure stop_server();
end;
{$METHODINFO OFF}

TLEDServerData = class
private
Arg: TJSONValue;
Res: TJSONValue;
FCriticalSection: TCriticalSection;
FWriteAContextCallback :TDBXCallback;
FReadLEDnameCallback :TDBXCallback;
FReadSBIDCallback :TDBXCallback;
FReadAContextCallback :TDBXCallback;
FStoped: TEvent;
public
constructor Create(PWriteAContextCallback,
PReadLEDnameCallback,
PReadSBIDCallback,
PReadAContextCallback :TDBXCallback);
destructor Destroy;
procedure WaitForStop;
procedure Stop;
function TryReadLEDname():TJSONValue;
function TryReadSBID(LEDname: string):TJSONValue;
function TryReadAContext(LEDname: string;SBID: Integer):TJSONValue;
function TryWriteAContext(
LEDname: string;
BlockStringid: Integer;
Color: Integer;
ContextString: string;
ContextOther: string):Integer;
end;

var
ServerData: TLEDServerData;

implementation

constructor TLEDServerData.Create(PWriteAContextCallback,
PReadLEDnameCallback,
PReadSBIDCallback,
PReadAContextCallback :TDBXCallback);
begin
FWriteAContextCallback := PWriteAContextCallback;
FReadLEDnameCallback := PReadLEDnameCallback;
FReadSBIDCallback := PReadSBIDCallback;
FReadAContextCallback := PReadAContextCallback;
FCriticalSection := TCriticalSection.Create;
FStoped := TEvent.Create(nil,False,False,'',False);
end;

destructor TLEDServerData.Destroy;
begin
FreeAndNil(FStoped);
FreeAndNil(FCriticalSection);
end;

procedure TLEDServerData.WaitForStop;
begin
FStoped.WaitFor(INFINITE);
end;

procedure TLEDServerData.Stop;
begin
FStoped.SetEvent;
end;

function TLEDServerData.TryReadLEDname:TJSONValue;
begin
FCriticalSection.Acquire;
Arg := TJSONNull.Create;
Result := FReadLEDnameCallback.Execute(Arg);
FCriticalSection.Release;
end;

function TLEDServerData.TryReadSBID(LEDname: string):TJSONValue;
begin
FCriticalSection.Acquire;
Arg := TJSONString.Create(LEDname);
Result := FReadSBIDCallback.Execute(Arg);
FCriticalSection.Release;
end;

function TLEDServerData.TryReadAContext(LEDname: string; SBID: Integer):TJSONValue;
begin
FCriticalSection.Acquire;
Arg := TJSONObject.Create;
TJSONObject(Arg).AddPair(TJSONPair.Create('LEDname',
TJSONString.Create(LEDname)));
TJSONObject(Arg).AddPair(TJSONPair.Create('SBID',
TJSONNumber.Create(SBID)));
Result := FReadAContextCallback.Execute(Arg);
FCriticalSection.Release;
end;

function TLEDServerData.TryWriteAContext(
LEDname: string;
BlockStringid: Integer;
Color: Integer;
ContextString: string;
ContextOther: string):Integer;
begin
FCriticalSection.Acquire;
Arg := TJSONObject.Create;
TJSONObject(Arg).AddPair(TJSONPair.Create('LEDname',
TJSONString.Create(LEDname)));
TJSONObject(Arg).AddPair(TJSONPair.Create('BlockStringid',
TJSONNumber.Create(BlockStringid)));
TJSONObject(Arg).AddPair(TJSONPair.Create('Color',
TJSONNumber.Create(Color)));
TJSONObject(Arg).AddPair(TJSONPair.Create('ContextString',
TJSONString.Create(ContextString)));
TJSONObject(Arg).AddPair(TJSONPair.Create('ContextOther',
TJSONString.Create(ContextOther)));
Res := FWriteAContextCallback.Execute(Arg);
Result := TJSONNumber(Res).AsInt;
TJSONNumber(Res).Free;
FCriticalSection.Release;
end;

procedure TLEDServerMethods.start_server(PWriteAContextCallback,
PReadLEDnameCallback,
PReadSBIDCallback,
PReadAContextCallback :TDBXCallback);
begin
ServerData := TLEDServerData.Create(PWriteAContextCallback,
PReadLEDnameCallback,
PReadSBIDCallback,
PReadAContextCallback);
ServerData.WaitForStop;
FreeAndNil(ServerData);
end;

procedure TLEDServerMethods.stop_server;
begin
ServerData.Stop;
end;

end.

客户端代码,就给出原理吧
首先要在一个线程中连接服务器,并连接服务器
//注册回调函数
void __fastcall TLEDServerThread::Execute(void)
{
TSQLConnection* conn = FormLEDServer->SQLConnection1->CloneConnection();
conn->Open();
TLEDServerMethodsClient* ServerMethodsProxy = new TLEDServerMethodsClient(
conn->DBXConnection);
ServerMethodsProxy->start_server(new TLEDWriteAContextCallback(CurrentThread),
new TLEDReadLEDnameCallback(CurrentThread),
new TLEDReadSBIDCallback(CurrentThread),
new TLEDReadAContextCallback(CurrentThread));
conn->Close();
}
其他的调用就可以在主线程中完成了。
williamsong997 2010-05-11
  • 打赏
  • 举报
回复
妖哥,你试出来了吗?
我对这个问题也很想知道答案,
更希望知道为什么?
ccrun.com 2010-05-06
  • 打赏
  • 举报
回复
楼主,我收到你的邮件了,但是没有附件?
kese 2010-05-06
  • 打赏
  • 举报
回复
多谢大版主。
ccrun.com 2010-05-06
  • 打赏
  • 举报
回复
这个问题没有回复?大概是google不到任何有用的信息。

如果楼主的问题还没有解决,请发一个demo工程到我的信箱:cbfans#163.com
我抽时间帮你分析。

1,317

社区成员

发帖
与我相关
我的任务
社区描述
C++ Builder 网络及通讯开发
社区管理员
  • 网络及通讯开发社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧