用wm_copydata发送消息,竟然有消息丢失的现象,不解???

zhongguofr 2004-01-25 04:58:23
我用wm_copydata发送消息,程序在p4-2g,256m内存的机器上运行正常,但在p2-350,64m内存的机器上,出现消息丢失的情况,而且丢失的没有规律,不解。我是每600ms发送一次消息,有时1分钟丢5次,有时一次不丢,为什么会出现这种情况?
...全文
335 20 打赏 收藏 转发到动态 举报
写回复
用AI写文章
20 条回复
切换为时间正序
请发表友善的回复…
发表回复
Xleep 2004-02-02
  • 打赏
  • 举报
回复
wm_CopyData不能用postmessage,你的问题是wm_timer消息丢失,在wm_timer的消息还未处理玩,又有新的wm_Timer这个消息会丢失
zhongguofr 2004-01-31
  • 打赏
  • 举报
回复
在交换数据量较大的情况下实现数据频繁而又快速的交换用发送WM_COPYDATA消息的方法也是不合适的,当数据传输过于频繁时将有可能导致数据的丢失。

呵呵,什么情况算交换数据量较大呢?数据频繁而又快速的交换只是感性的,没有一个标准,我一直在不同配置的机器测试自己的程序。

我给程序加了时间功能,显示每一次接收消息到处理完所用时间,据我的观察,在p2-366,128m内存配置的机器,耗时最长不超过120ms,而每次发送消息的间隔是600ms。

如果说WM_COPYDATA消息的方法是不合适的,那还有什么别的办法吗?
ly_liuyang 2004-01-31
  • 打赏
  • 举报
回复
Shared Memory技术

unit SharedMemory;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs;

type

TSharedMemory = class(TComponent)
private
{ Private declarations }
FShareName: String;
FSize: integer;
FHandle, FMutex: THandle;
FReadOnly: boolean;
FTimeout: integer;

protected
procedure SetName(const aValue: TComponentName );override;
{ Protected declarations }
public
constructor Create(AOwner: TComponent);override;
destructor Destroy;override;
function MemoryExist: boolean;
function MapMemory: pointer; { Public declarations }
function UnMapMemory(aMapPtr: pointer):boolean;
function CreateMemory: boolean;
function CloseMemory: boolean;
function OpenMemory: boolean;
function RequestOwnership: boolean;
function ReleaseOwnership: boolean;
property Handle: THandle read FHandle;
property Mutex: THandle read FMutex;

published
{ Published declarations }
property ReadOnly: boolean read FReadOnly write FReadOnly default false;
property ShareName: String read FShareName write FShareName;
property Size: integer read FSize write FSize;
property Timeout: integer read FTimeout write FTimeout default -1;

end;

const
MUTEX_NAME = '_SMMutex';

procedure Register;

implementation

procedure TSharedMemory.SetName(const aValue: TComponentName );
var
lChange: boolean;
begin
lChange := (csDesigning in ComponentState) and
((Name = FShareName) or (Length(FShareName) = 0));
inherited;
if lChange then
begin
FShareName := Name;
end;
end;
//---------------------------------------------------------------------------
function TSharedMemory.MapMemory:pointer;
var
lMapping: DWord;
begin
if FHandle = 0 then
begin
Result := nil;
exit;
end;

if(FReadOnly)then
begin
lMapping := FILE_MAP_READ;
end
else
begin
lMapping := File_Map_All_Access;
end;
Result := MapViewOfFile(FHandle, lMapping, 0, 0, FSize);
if(Result = nil)then
begin
ReleaseMutex(FMutex);
end;
end;
//---------------------------------------------------------------------------
function TSharedMemory.UnMapMemory(aMapPtr: pointer): boolean;
begin
if FHandle <> 0 then
begin
UnmapViewOfFile(aMapPtr);
result := true;
end
else
begin
result := false;
end;
end;
//---------------------------------------------------------------------------
function TSharedMemory.CreateMemory: boolean;
var
lMutexName: string;
begin
Result := true;
if FHandle <> 0 then CreateMemory := false;
FHandle := CreateFileMapping(THANDLE($FFFFFFFF), nil, PAGE_READWRITE, 0,
FSize, pchar(FShareName));
if (FHandle = 0) or ((FHandle <> 0) and (GetLastError = ERROR_ALREADY_EXISTS)) then
begin
CloseMemory;
Result := false;
end;
lMutexName := FShareName + MUTEX_NAME;
FMutex := CreateMutex(nil, false, pchar(lMutexName));
if(FMutex = 0) then
begin
CloseMemory;
Result := false;
end;
end;
//---------------------------------------------------------------------------
function TSharedMemory.CloseMemory: boolean;
begin
if(FHandle <> 0) then
begin
CloseHandle(FHandle);
FHandle := 0;
end;
if(FMutex <> 0) then
begin
CloseHandle(FMutex);
FMutex := 0;
end;
Result := true;
end;
//---------------------------------------------------------------------------
function TSharedMemory.OpenMemory: boolean;
var
lMutexName: string;
begin
Result := false;
if(FHandle = 0) then
begin
FHandle := OpenFileMapping(FILE_MAP_ALL_ACCESS, true, pchar(FShareName));
if(FHandle <> 0) then
begin
lMutexName := FShareName + MUTEX_NAME;
FMutex := OpenMutex(MUTEX_ALL_ACCESS, true, pchar(lMutexName));
if(FMutex <> 0 ) then
begin
Result := true;
end
else
begin
CloseMemory;
end;
end;
end;
end;
//---------------------------------------------------------------------------
function TSharedMemory.RequestOwnership: boolean;
var
lTimeout: DWord;
begin
Result := false;
if(FHandle <> 0) then
begin
if(FTimeout < 0) then
begin
lTimeout := INFINITE;
end
else
begin
lTimeout := FTimeout;
end;
Result := WaitForSingleObject(FMutex, lTimeout) = WAIT_OBJECT_0;
end;
end;
//---------------------------------------------------------------------------
function TSharedMemory.ReleaseOwnership: boolean;
begin
Result := false;
if(FHandle <> 0) then
begin
Result := ReleaseMutex(FMutex);
end;
end;
//---------------------------------------------------------------------------
constructor TSharedMemory.Create(AOwner: TComponent);
begin
inherited;
FShareName := '';
FTimeout := -1;
FSize := 0;
FReadOnly := false;
FHandle := 0;
FMutex := 0;
end;
//---------------------------------------------------------------------------
destructor TSharedMemory.Destroy;
begin
CloseMemory;
inherited;
end;
//---------------------------------------------------------------------------
procedure Register;
begin
RegisterComponents('Custom', [TSharedMemory]);
end;
//---------------------------------------------------------------------------
function TSharedMemory.MemoryExist: boolean;
var PVHandle:THandle;
begin
Result := false;
PVHandle := CreateFileMapping(THANDLE($FFFFFFFF), nil, PAGE_READWRITE, 0,
FSize, pchar(FShareName));
if (PVHandle <> 0) and (GetLastError = ERROR_ALREADY_EXISTS)
then Result:=true
else CloseHandle(PVHandle);
end;

end.
zhongguofr 2004-01-31
  • 打赏
  • 举报
回复
共享内存的方式传递数据?

你说的是内存映射文件?比如我把一个文件映射了,当这个文件的内容发生变化,我的程序可以马上知道?如果这个文件是别的程序创建的,而且是以独占方式在进行读写,我的程序还能映射它吗?
flyforlove 2004-01-31
  • 打赏
  • 举报
回复
你可以试一试共享内存的方式才传递数据。
siwuge 2004-01-31
  • 打赏
  • 举报
回复
up
dickeybird888 2004-01-30
  • 打赏
  • 举报
回复
sendmessage 能够确保对方在处理消息的时候,指针指向的内存区域还是有效的。
这是因为 sendmessage 在对方处理完消息才会返回,而你用 sendmessage 传递
的指针肯定是有效的。
但是,postmessage 只是把消息置入消息队列就立即返回了,如果你的程序以为这
时候对方已经处理了消息,就可以释放掉分配的内存,而对方在处理的时候这块内
存已经无效了。
sendmessage 对消息队列进行操作的时候,不会让你的窗口处理函数重入(也就是
说,这时候你的程序不会处理其他消息)。既然如此,你就不能让程序立即结束。
如果极端一点,你用 killprocess 结束了程序,那么依赖它的程序会出错。
如果你这个方面没有问题的话,那flyforlove(为情飞) 的那种可能性应该是存在的
dickeybird888 2004-01-30
  • 打赏
  • 举报
回复
wm_copydata根本就不能用postmessage,是因为在跨进程的内存映射方面,SendMessage函数对WM_COPYDATA消息进行了专门的处理,而PostMessage没有。

所以,即使发送者不释放内存、不适用局部变量、不退出进程,用PostMessage也不行。
zhongguofr 2004-01-30
  • 打赏
  • 举报
回复
唉,各位,我试了半天,又查了资料,发现用wm_copydata发送消息只能用sendmessage,postmessage不行
flyforlove 2004-01-30
  • 打赏
  • 举报
回复
不好意思,因为以前没有遇到过这样的情况,所以不知道wm_copydata不能用postmessage发送,这样看来可能就是wm_timer的问题了,参考下面这段话。

但是在使用WM_COPYDATA消息时,只能用SendMessage()函数发送而不能使用PostMessage(),这两个函数虽然功能非常相似都是负责向指定的窗口发送消息,但是SendMessage()函数发出消息后不是马上返回,而是在接收方的消息响应函数处理完之后才能返回,并能够得到返回结果。在此期间发送方程序将被阻塞,SendMessage()后面的语句不能被继续执行。而PostMessage()函数在发出消息后马上返回,其后语句能够被立即执行,但是无法获取消息的执行结果。可见,在交换数据量较大的情况下实现数据频繁而又快速的交换用发送WM_COPYDATA消息的方法也是不合适的,当数据传输过于频繁时将有可能导致数据的丢失。
SeaWave 2004-01-30
  • 打赏
  • 举报
回复
WM_COPYDATA只能用SendMessage()来发送,因为它是跨进程传递数据。
------
问题应该出在定时器,如果是用时钟定时,那么会出现丢失的现象,因为定时消息是最低级的消息,上一个定时器消息未被处理时,这一次的定时消息就会丢掉。
改用线程就好了。
flyforlove 2004-01-29
  • 打赏
  • 举报
回复
应该不是你说的那个样子,WM_TIMER消息会覆盖,也就是如果一个WM_TIMER消息来不及处理
后面的会把它覆盖掉,所以不会出现你所说的有规律,或者越丢越多的情况,因为你程序
处理消息的速度,以及消息队列的消息数目,也在不停的变化着。

楼上地说得对,你试试就好了,postmessage虽然不能保证消息被处理,但是能保证每个消息
都被发出去了吧。
IDWB 2004-01-28
  • 打赏
  • 举报
回复
测试一下不就行了,实践是检验真理的唯一标准
zhongguofr 2004-01-28
  • 打赏
  • 举报
回复
但是postmessage发送消息到消息队列,此时用户移动鼠标,敲击键盘,运行其他程序都会产生消息,消息队列里的消息岂不是很多?谁来保证消息不丢失呢?
你说的有道理,wm_copydata消息没有来得及发送使数据丢失,如果说是由于机器配置低,处理不过来,消息应大量丢失,或有间隔,有规律的丢失(比如:越丢越多),但我观察了没有这个现象,丢失完全是不规律的,这是为什么?

我明天换成postmessage试试
flyforlove 2004-01-27
  • 打赏
  • 举报
回复
就是因为你用了sendmessage,才有可能出现wm_timer消息重叠,以致丢失,
这样就等于你有wm_copydata消息没有来得及发送。
所以你用sendmessage发送wm_copydata消息反而使数据丢失。
你换成postmessage试一下。

我想你没有认真看我上面的解释。
zhongguofr 2004-01-27
  • 打赏
  • 举报
回复
我用的是sendmessage,因为我觉得用postmessage发送消息后马上返回,此时消息在消息队列排队,可能会有未知的问题造成消息丢失。而sendmessage我觉得有点象点对点的发送消息。

一家之言,没有证实,还请高手排砖。
flyforlove 2004-01-25
  • 打赏
  • 举报
回复
//你用postmessage还是sendmessage?
//postmessage发送消息后马上返回,无需对方程序回应。但有可能造成丢失消息。
//sendmessage发送消息后知道对方程序相应,该sendmessage调用才返回。

我倒是觉得它这种情况倒是用sendmessage会丢失消息,
因为向消息队列发送时钟消息(用timer其实就是发送时钟消息)后,
如果前面的一个时钟消息还没有来得及处理的话,
后面的时钟消息就会把前面的覆盖掉,
我想他的情况正是因为在处理时钟消息的时候用sendmessage发送wm_copydata消息,
而这个消息因为没有及时处理,所以就没及时返回,
这样的话,后面的时钟消息就会发生覆盖。
而wm_copydata这一类消息应该不会发生覆盖。
所以我想倒是用postmessage来发送wm_copydata消息到不会丢失数据。

一家之言,没有证实,还请高手排砖。
fengyvn 2004-01-25
  • 打赏
  • 举报
回复
是不是因为配置太差所以系统资源不够用才发生数据丢失的?
lgqTiger 2004-01-25
  • 打赏
  • 举报
回复
关注中!
严黎斌 2004-01-25
  • 打赏
  • 举报
回复
你用postmessage还是sendmessage?
postmessage发送消息后马上返回,无需对方程序回应。但有可能造成丢失消息。
sendmessage发送消息后知道对方程序相应,该sendmessage调用才返回。

理论上这么说的,我没有详细测试过,呵呵

1,183

社区成员

发帖
与我相关
我的任务
社区描述
Delphi Windows SDK/API
社区管理员
  • Windows SDK/API社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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