Delphi WM_COPYDATA字符串未出现在目标应用程序中

Delphi WM_COPYDATA字符串未出现在目标应用程序中,delphi,delphi-2010,wm-copydata,Delphi,Delphi 2010,Wm Copydata,我试图在Delphi2010中的两个应用程序之间传递信息 我使用的是我过去成功使用过的代码的简化版本(简化是因为我不需要发送者知道发送已经成功),我将接收到的发送归结为一对示例应用程序,其实质如下 发送 接受申请 procedure TMF.WMCopyData(var Msg: TWMCopyData); var s : AnsiString; begin s := PAnsiChar(Msg.CopyDataStruct.lpData) ; jobstatus.Panels

我试图在Delphi2010中的两个应用程序之间传递信息

我使用的是我过去成功使用过的代码的简化版本(简化是因为我不需要发送者知道发送已经成功),我将接收到的发送归结为一对示例应用程序,其实质如下

发送

接受申请

procedure TMF.WMCopyData(var Msg: TWMCopyData);
var
   s : AnsiString;
begin
   s := PAnsiChar(Msg.CopyDataStruct.lpData) ;
   jobstatus.Panels[1].Text := s;
end;
var
  GetPhoneMsg: DWORD = 0;

procedure TMF.WMCopyData(var Msg: TWMCopyData);
var
  s : AnsiString;
begin
  if (GetPhoneMsg <> 0) and (Msg.CopyDataStruct.dwData = GetPhoneMsg) then
  begin
    SetString(s, PAnsiChar(Msg.CopyDataStruct.lpData), Msg.CopyDataStruct.cbData);
    jobstatus.Panels[1].Text := s;
  end else
    inherited;
end;

initialization
  GetPhoneMsg := RegisterWindowMessage('TMF_GetPhone');
工作测试应用程序和我正在向其中添加代码的应用程序之间的主要区别在于,目标应用程序中有很多额外的活动。尤其是在启动时

有没有关于WMCopyData过程似乎根本不启动的建议

干杯


Dan

如果您使用的是Windows 7,它将不再工作。
如果您正在使用它,请查看此页面以了解如何添加异常:

我认为添加异常是一个好习惯

  copyDataStruct.dwData := Handle; 
过程中TMF.SendString-如果您没有自定义标识符,则将源HWND值放入目标将有助于在目标上进行调试(您可以在另一端检查此值,从而避免对广播的WMCOPY_数据的误解,例如。-是的,不应该有,但我看到了一些!)

TMF
客户机类定义中,对吗

嵌套的
SendData
调用后应缺少
exit
else

procedure TMF.SendData(copyDataStruct: TCopyDataStruct);
  (...)
      Sleep(3000);
      SendData(copyDataStruct);
   end else
     SendMessage(rh, WM_COPYDATA, NativeInt(Handle), NativeInt(@copyDataStruct));
end;
但这不会有多大改变


检查
rh:=FindWindow()
返回的句柄:是
TMF
客户端窗体的句柄还是应用程序的句柄?

如果需要启动应用程序,我认为调用时(rh)句柄为0有问题。但现在我看到SendData递归地调用自己。我在代码中为此添加了一条注释,因为这并不明显。但现在还有另一个问题。SendData的第二个实例将具有正确的句柄。但随后您将跳出,返回到第一个实例,其中句柄仍然为0,然后您将再次调用SendMessage,这次使用0句柄。这可能不是你麻烦的原因,但这是无意的、不必要的,而且是完全不好的。在我看来,这是一个试图太聪明而使事情复杂化的案例

您的代码有一些问题

第一,您没有为消息分配唯一的ID。VCL和各种第三方组件也使用
WM_COPYDATA
,因此您必须确保您实际处理的是您的消息,而不是其他人的消息

第二,您可能没有足够长的时间等待第二个应用程序启动。不要使用
Sleep()
,而是使用
ShellExecuteEx()
SEE\u MASK\u WAITFORINPUTIDLE
标志(或使用
CreateProcess()
WAITFORINPUTIDLE()

第三,当启动第二个应用程序时,您的递归逻辑正试图再次发送消息。如果失败了,你会启动第三个应用程序,以此类推。你应该完全去掉递归,你不需要它

试试这个:

var
  GetPhoneMsg: DWORD = 0;

procedure TMF.SendString;
var
  copyDataStruct: TCopyDataStruct;
  s: AnsiString;
begin
  if GetPhoneMsg = 0 then Exit;
  s := ebFirm.Text;
  copyDataStruct.dwData := GetPhoneMsg;
  copyDataStruct.cbData := Length(s);
  copyDataStruct.lpData := PAnsiChar(s);
  SendData(copyDataStruct);
end;

procedure TMF.SendData(copyDataStruct: TCopyDataStruct);
var
  rh: HWND;
  si: TShellExecuteInfo;
  res: Integer;
begin
  rh := FindWindow(PChar('TMF'), PChar('Get Phone'));
  if rh = 0 then
  begin
    // Launch the target application and give time to start
    ZeroMemory(@si, SizeOf(si));
    si.cbSize := SizeOf(si);
    si.fMask := SEE_MASK_WAITFORINPUTIDLE;
    si.hwnd := Handle;
    si.lpVerb := 'open';
    si.lpFile := GetPhone;
    si.nShow := SW_SHOWNORMAL;
    if not ShellExecuteEx(@si) then Exit;
    rh := FindWindow(PChar('TMF'), PChar('Get Phone'));
    if rh = 0 then Exit;
  end;
  SendMessage(rh, WM_COPYDATA, WParam(Handle), LParam(@copyDataStruct));
end;

initialization
  GetPhoneMsg := RegisterWindowMessage('TMF_GetPhone');
接受申请

procedure TMF.WMCopyData(var Msg: TWMCopyData);
var
   s : AnsiString;
begin
   s := PAnsiChar(Msg.CopyDataStruct.lpData) ;
   jobstatus.Panels[1].Text := s;
end;
var
  GetPhoneMsg: DWORD = 0;

procedure TMF.WMCopyData(var Msg: TWMCopyData);
var
  s : AnsiString;
begin
  if (GetPhoneMsg <> 0) and (Msg.CopyDataStruct.dwData = GetPhoneMsg) then
  begin
    SetString(s, PAnsiChar(Msg.CopyDataStruct.lpData), Msg.CopyDataStruct.cbData);
    jobstatus.Panels[1].Text := s;
  end else
    inherited;
end;

initialization
  GetPhoneMsg := RegisterWindowMessage('TMF_GetPhone');
var
GetPhoneMsg:DWORD=0;
程序TMF.WMCopyData(var Msg:TWMCopyData);
变量
s:翻译;
开始
如果(GetPhoneMsg 0)和(Msg.CopyDataStruct.dwData=GetPhoneMsg),则
开始
设置字符串(s,PAnsiChar(Msg.CopyDataStruct.lpData),Msg.CopyDataStruct.cbData);
jobstatus.Panels[1]。文本:=s;
结束其他
继承;
结束;
初始化
GetPhoneMsg:=RegisterWindowMessage('TMF_GetPhone');

使用Windows XP,但感谢您为未来做准备。-1对不起,这是非常误导的
WM_COPYDATA
在Vista和更高版本上运行良好,只要收件人进程的完整性级别等于或低于发件人的完整性级别。我必须同意David的观点。我个人在Windows7上使用了WM_COPYDATA
…好的。。。对不起,我误会了。。。我可能在不同级别上遇到了这个问题……在Vista+上,如果UIPI阻止从较低完整性进程接收消息,并且您不希望它被阻止,那么接收方可以使用
ChangeWindowMessageFilter/Ex()
允许消息通过。调试器告诉您什么?投票关闭,因为问题的解决方案与问题或任何答案中所写的内容无关。@RobKennedy-为什么要关闭有效的问题和如此好的答案?我看不出您需要
copyDataStruct.dwData:=处理
谢谢。原来目标应用程序的更新代码中有一个bug,它在开发副本上复制了一个旧的(即当前的实时应用程序)。这仅在从发送方应用程序调用目标应用程序时发生。正常运行或从Delphi内部运行时没有问题。@Arnaud您是否介意澄清您关于
dwData
的第一个建议的意思。如果我是错的,那么我想知道,如果我是对的,那么您可以删除它,避免误导他人。@David我更改了注释以指定此行的目的。当您广播消息时,wParam不是自定义值吗?AFAIK中有这样一个参数。这就是我精确的原因——来自实验。某种内部签名不是强制性的,但更安全。谢谢你指出这一点。实际上,在发送消息之前,我在原始代码中有一个else,但是上面的示例中遗漏了它。感谢提供ShellExecuteEx信息。看起来比递归更好。正如上面向Chris提到的,在“if rh=0”上应该有一个else来阻止SendMessage被调用两次。完美的代码。除了Zarko和其他几家俄罗斯网站外,互联网上没有其他发送消息的代码起作用。我得到了不完整的字符串。因此,开发人员也忙着解释对这个备受追捧的代码段的评论,而不是发布任何完整的工作代码。也许是吧