有关多线程取数据的问题,高手们请帮忙,实在没办法了!!!!!!!!!!!!

WantKindHeart 2004-07-12 10:05:12
请问我用以下的方法去取数据为什么不行呀?
自定义消息:
const
THREAD_GETDATA = WM_USER+1;
THREAD_UPDATEDATA = WM_USER+2;
THREAD_TERMINATE = WM_USER+3;

以下是自己定义的多线程类:
TDataThread = class(TThread)
private
FStream: Pointer;
IAppData: IAppServer;
FDelta: OleVariant;
FData: OleVariant;
FcdsData: TClientDataSet;

Function GetData(Fcds: TClientDataSet):OleVariant;
Procedure UpdateData(Fcds: TClientDataSet);
protected
Procedure Execute;override;
public
Constructor Create(Fcds: TClientDataSet);
Property Delta: OleVariant read FDelta write FDelta;
Property Data: OleVariant read FData write FData;
end;


constructor TDataThread.Create(Fcds: TClientDataSet);
var
Res: HRESULT;
begin
FreeOnTerminate := True;
OleCheck(CoInitialize(Nil));
Self.FcdsData := Fcds;
try
Res:= CoMarshalInterThreadInterfaceInStream(IID_IAppserver, //用来注册线程。
FcdsData.AppServer,IStream(FStream)); //OleCheck( )AppInteface:=IappServer(IDispatch(DataModule1.skc1.AppServer));
case res of
E_OUTOFMEMORY:
Dialogs.ShowMessage('There was not enough memory to complete the call.');
E_INVALIDARG:
Dialogs.ShowMessage('One or more arguments are invalid. '); //相当于ShowMessage.
end;
except
On e: Exception do
Begin
CoUninitialize;
Dialogs.ShowMessage(E.Message);
exit;
end;
end;
try
Res:= CoGetInterfaceAndReleaseStream(IStream(FStream),IID_IAppServer,IAppData);
case res of
E_INVALIDARG:
Dialogs.ShowMessage('Indicates that input arguments are invalid.');
end;
except
On e: Exception do
Begin
CoUninitialize;
Dialogs.ShowMessage(E.Message);
exit;
end;
end;
Inherited Create(False);
end;

procedure TDataThread.Execute;
var
Event: THandle;
Msg: TMsg;
cdsTemp: TClientDataSet;
begin
Event:= Self.Handle;
CoInitialize(Nil);
try
While Not Terminated do
begin
case MsgWaitForMultipleObjects(0,Event,False,INFINITE,QS_ALLINPUT) of
WAIT_OBJECT_0:
begin
While PeekMessage(Msg,0,0,0,PM_REMOVE) do
begin
if Msg.hwnd = 0 Then
begin
Case Msg.message of
THREAD_GETDATA:
begin
cdsTemp:=TClientDataSet(Pointer(Msg.wParam));
Self.Data := Self.GetData(cdsTemp);
end;
THREAD_UPDATEDATA:
begin
cdsTemp:=TClientDataSet(Pointer(Msg.wParam));
Self.UpdateData(cdsTemp);
end;
THREAD_TERMINATE:
Terminate;
end;
end;
end;
end;
end;
end;
finally
CoUnInitialize();
end;
end;

function TDataThread.GetData(Fcds: TClientDataSet): OleVariant;
var
ResCount: Integer;
Params: OleVariant;
OwerData: OleVariant;
begin
Result:=IAppData.AS_GetRecords(Fcds.ProviderName,Fcds.PacketRecords,ResCount,1,Fcds.CommandText,Params,OwerData);
end;

procedure TDataThread.UpdateData(Fcds: TClientDataSet);
var
iErrCount: Integer;
OwnerData: OleVariant;
begin
IAppData.AS_ApplyUpdates(Fcds.ProviderName,Fcds.Delta,-1,iErrCount,OwnerData);
end;

调用:
var
DataThread: TDataThread;

我用发送消息的形式:PostThreadMessage(DataThread.ThreadID,THREAD_GETDATA,Integer(Pointer(ClientDataSet1)),0);
来取数据:提老是在SConnect的单元里为提示出一个错误,说什么‘Invalid argument’



...全文
296 24 打赏 收藏 转发到动态 举报
写回复
用AI写文章
24 条回复
切换为时间正序
请发表友善的回复…
发表回复
WantKindHeart 2004-07-20
  • 打赏
  • 举报
回复
难道在开发数据库时大家都没有遇到过这种问题吗?
WantKindHeart 2004-07-19
  • 打赏
  • 举报
回复
谢谢dbexpress,我会参考你的代码的。
WantKindHeart 2004-07-19
  • 打赏
  • 举报
回复
看样子,这个问题也只能这样子了,不过我我还有一个问题,不知各位有没有遇到过,那就是在做三层数据库开发时,为什么数据库服务器的数据大了,就在客户端连接时会显示‘灾难性错误’呢不然就是TSocketConnect会出现'Read Socket Error'
starcbh 2004-07-18
  • 打赏
  • 举报
回复
一堆代码……

懒得看
dbExpress 2004-07-17
  • 打赏
  • 举报
回复
我改了一下您老的代码,如下:

const
THREAD_GETDATA = WM_USER+1;
THREAD_UPDATEDATA = WM_USER+2;
THREAD_TERMINATE = WM_USER+3;

以下是自己定义的多线程类:
TDataThread = class(TThread)
private

IAppData: IAppServer;

fHost: string;
fPort: Integer;
fServerGUID: string;

Function GetData(Fcds: TClientDataSet):OleVariant;
Procedure UpdateData(Fcds: TClientDataSet);
protected
Procedure Execute;override;
public
constructor TDataThread.Create(
//假设你用的是SocketConnection
const Host: string;
const Port: Integer;
const ServerGUID: string);

end;


constructor TDataThread.Create(
//假设你用的是SocketConnection
const Host: string;
const Port: Integer;
const ServerGUID: string);
var
Res: HRESULT;
begin
inherited Create(False);
FreeOnTerminate := True;
fHost := Host; fPort := Port; fServerGUID := ServerGUID;
end;

procedure TDataThread.Execute;
var
Event: THandle;
Msg: TMsg;
cdsTemp: TClientDataSet;
begin
//在工作线程内创建一个连接,那就不必marshal了
Event:= Self.Handle;
CoInitialize(nil);
try
SocketConn := TSocketConnection.Create(nil);
try
SocketConn.Host := fHost;
SocketConn.Port := fPort;
SocketConn.ServerGUID := fServerGUID;

SocketConn.Connected := True; //如果连接失败,自己找一个机制反馈给主线程吧

IAppData := SocketConn.GetServer();

if IAppData = nil then
raise Exception.Create('GetServer error'); //如果失败,自己找一个机制反馈给主线程吧

while not Terminated do
begin
case ... of
... //你原来的代码
end;

finally
SocketConn.Destroy();
end;
finally
CoUninitialize();
end;
end;

function TDataThread.GetData(Fcds: TClientDataSet): OleVariant;
var
ResCount: Integer;
Params: OleVariant;
OwerData: OleVariant;
begin
Result:=IAppData.AS_GetRecords(Fcds.ProviderName,Fcds.PacketRecords,ResCount,1,Fcds.CommandText,Params,OwerData);
end;

procedure TDataThread.UpdateData(Fcds: TClientDataSet);
var
iErrCount: Integer;
OwnerData: OleVariant;
begin
IAppData.AS_ApplyUpdates(Fcds.ProviderName,Fcds.Delta,-1,iErrCount,OwnerData);
end;

我也是菜鸟一个,所以你只能参考,如果不行也别骂我
另外,没功劳也有苦劳,给分的时候,请适当给点
WantKindHeart 2004-07-17
  • 打赏
  • 举报
回复
楼上的兄弟,你说我这个程序可以不用Marshal,你的那种方法我有点不懂,因为我也是开始接触这方面的知识,能不能帮我举点代码呢?我会不盛感激的。先谢了。
dbExpress 2004-07-15
  • 打赏
  • 举报
回复
建议用COM时避免多线程,
很容易发生错误,又难调试
象你的程序客户端就不能用socketConnection来连接
你却用了SocketConnection

线程间列集的问题,应该在线程的Execute代码里面coGetInterfaceAndReleaseStream,
而不是在Create方法里面,因为调用Create方法的是主线程

象你的问题,完全没有必要Marshal,直接传递一个ServerName和ServerGUID给工作线程
然后由工作线程来创建IAppServer实例再服务主线程就可以了

如果多线程概念不是很清晰就不要用COM,或者用COM就避免多线程,
很多时候测试不充分,到用户手上的时候就容易出错
WantKindHeart 2004-07-15
  • 打赏
  • 举报
回复
怎么没什么人发话呀?
WantKindHeart 2004-07-14
  • 打赏
  • 举报
回复
请问你有做过相关的程序吗?如果有的话能不能贴点出来给我们大家学习学习呀?我看这方面的知识也少,那里能找到相关的知识呢?谢谢了。
halfdream 2004-07-13
  • 打赏
  • 举报
回复
呵呵。。CoGetInterfaceAndReleaseStream
你看这函数的名字,取得接口后就释放STREAM,能让你用第二次吗??


你就不能if not Assigned(IAppData) then
CoGetInterfaceAndReleaseStream.....
WantKindHeart 2004-07-12
  • 打赏
  • 举报
回复
我有跟踪过,出错的地方是在SConnect单元里。出错的。我按你的意思看一下在Execute里去Marshal一下,看能不能成。谢谢了。
halfdream 2004-07-12
  • 打赏
  • 举报
回复
至于哪儿报参数错误,,你先跟踪执行一下,找着地方再说。。
halfdream 2004-07-12
  • 打赏
  • 举报
回复
楼主没有明白我的意思。
我明白你是想把接口Marshal到工作线程,
可是在TThread.Create...是在调用它的线程。。我猜你这儿是主线程。呵呵。
并不是在你要用接口的那线程。。。
在TThread.Execute才是那线程执行的地方!!!要在这里面MARSHAL才对啊。

WantKindHeart 2004-07-12
  • 打赏
  • 举报
回复
谢谢兄弟,有时间帮我看看吧。还有就是
Res:= CoGetInterfaceAndReleaseStream(IStream(FStream),IID_IAppServer,IAppData);
不是为了线程转接用吗?他不是为了把我们传过去的FCDS的AppServer转接到我们线程类里的IAppData变量里吗?而且如果我把那个私有函数GetData(fcds:TClientDataSet)放到公共接口区,有人为调用就不会有出错,而且能取到数据。
halfdream 2004-07-12
  • 打赏
  • 举报
回复
来不及细看,刚看一眼,发现个问题。

你的这句是写在TThread.Create里面。。。
Res:= CoGetInterfaceAndReleaseStream(IStream(FStream),IID_IAppServer,IAppData);

可是,TThread.Create。。只是创建这个线程对象,并不是这个线程的执行。。
你至少应该写在TThread.Execute里面。。。
WantKindHeart 2004-07-12
  • 打赏
  • 举报
回复
来呀,我TOP
WantKindHeart 2004-07-12
  • 打赏
  • 举报
回复
自已先Top一下,兄弟们来吧,我真的没了办法了。
WantKindHeart 2004-07-12
  • 打赏
  • 举报
回复
TO: halfdream,我按你的方法试过了,把下面的代码放到Execute里后可以执行一次,但第二次再去执行时就会出现前面的错误。
Res:= CoGetInterfaceAndReleaseStream(IStream(FStream),IID_IAppServer,IAppData);
WantKindHeart 2004-07-12
  • 打赏
  • 举报
回复
兄弟,你能不能把我的代码拿到机子调试一下呀。我看跟进去时,每次出错都是在:
function TDataBlockInterpreter.LockObject(ID: Integer): IDispatch;
begin
-》 Result := FDispList[ID];
end;
halfdream 2004-07-12
  • 打赏
  • 举报
回复
GetData里面加上这句试试吧.

Params:=Unassigned;

加载更多回复(4)

1,593

社区成员

发帖
与我相关
我的任务
社区描述
Delphi 网络通信/分布式开发
社区管理员
  • 网络通信/分布式开发社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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