【问题标题】:Delphi 7 dde callback on windows 7 - 64 bitsWindows 7 - 64 位上的 Delphi 7 dde ​​回调
【发布时间】:2015-12-15 12:04:03
【问题描述】:

我们有一个 delphi 7 dde ​​客户端应用程序,它与另一家公司的 dde ​​服务器通信(ISIS Papyrus 打印系统) 两者都是 32 位,在 windows 7 32 位上运行良好。

现在我们公司正在切换到windows 7 64位,客户端和服务器之间的通信不再正常了。 我们使用带有 DdeInitialize 的回调函数

我们使用它是因为我们想知道服务器完成的过程何时真正完成并生成文档。

在 windows 7 64bits 上,我们得到了 PTMonMsgStruct(pData)^.wMsg 的粗糙数据

有谁知道怎么回事?

代码:

DdeInitialize(FDdeInstId, SVDdeCallBack, MF_POSTMSGS + MF_SENDMSGS, 0);

和 SVDdeCallBack

function SVDdeCallBack(
   CallType, Fmt : UINT; //transaction type ; format atom of the data sent from the server
   Conv: HConv;          //a handle the conversation
   hsz1, hsz2: HSZ;      // hsz1: topic name ; hsz2: item name
   Data: HDDEData;       //a handle to the data associated with the topic and item name pair
   Data1, Data2: ULONG)  //
   : HDDEData; stdcall;
var
  pData: Pointer;
  Len: Integer;
type
  PTMonMsgStruct = ^TMonMsgStruct;
begin
  Result := 0;
  // Check if the calltype is the monitoring DDE call
    if CallType = XTYP_MONITOR then
  begin
    // Get the DDE data
        pData := DdeAccessData( Data, @Len);
    // If data
        if pData <> nil then
    begin
        // If data is a posted message
        if Data2 = MF_POSTMSGS then
      begin
                try
            // Check if the message was an acknowledge message
          //myMonitorStruct := PTMonMsgStruct(pData^);
            if PTMonMsgStruct(pData)^.wMsg = WM_DDE_ACK then
          begin
            WriteLogFile('prcDDE.DDECallBack: TMonMsgStruct(pData^).wMsg = WM_DDE_ACK');
            WriteLogFile('prcDDE.DDECallBack: Acknowledge message');
            // Detect only the acknowledge messages with no busy flag
              if ((PTMonMsgStruct(pData)^.dmhd.uilo and DDE_FACK) = DDE_FACK) and
               ((PTMonMsgStruct(pData)^.dmhd.uilo and DDE_FBUSY) = 0) then
            begin
                // The DDE command has terminated
              WriteLogFile('prcDDE.DDECallback: ((TMonMsgStruct(pData^).dmhd.uilo and DDE_FACK) = DDE_FACK) and ((TMonMsgStruct(pData^).dmhd.uilo and DDE_FBUSY) = 0)');
              WriteLogFile('prcDDE.DDECallback: Acknowledge with BUSY Flag = 0');
                    ApplData.WaitStat := False;
              WriteLogFile('prcDDE.DDECallback: ApplData.WaitStat := False');
            end
            else
            begin
              WriteLogFile('prcDDE.DDECallback: Acknowledge with BUSY Flag <> 0')
            end;
          end;
          if PTMonMsgStruct(pData)^.wMsg = WM_DDE_TERMINATE then
          begin
            // Check if in close
            WriteLogFile('prcDDE.DDECallBack:TMonMsgStruct(pData^).wMsg = WM_DDE_TERMINATE');
            WriteLogFile('prcDDE.DDECallBack: DDE_terminate message');
            if not scrFrontOffice.FInClose then
               begin
                  // Check if there is a second file
                  if ((Length(ApplData.DataFile2) > 0) and (ApplData.DataFile <> ApplData.DataFile2)) then
                     begin
                        // Activate the timer
                        // 2 following commands removed by VDP -> added in PrcFrontOffice
                        if bInternWaitForView then
                           begin
                              scrFrontOffice.FTimerProcess := True;
                              scrFrontOffice.tmrClose.Enabled := True;
                           end;
                     end
                  else
                     begin
                        // The DDE connection is inactive
                        scrFrontOffice.FDDEConnectionActive := False;
                            // Close the program
                        scrFrontOffice.Close;
                     end;
               end;
          end;
                finally
            // Free the accessed data
                    DdeUnaccessData(Data);
                end;
        end
      else
      begin
        //WriteLogFile('Data is no posted message');
      end;
    end
    else
    begin
      //WriteLogFile('No data received with DdeAccessData');
    end;
  end;
end;

【问题讨论】:

  • 我们能否假设您检查了DDEInitialize 的返回值并验证了它是DMLERR_NO_ERROR?否则,可能的 DDE 问题通常是 win7 安装不是最新的(过去一些坏 KB 已经破坏了 DDE)、防病毒应用程序阻止 DDE 消息、坏硬件驱动程序、UAC 问题...... DDE 非常脆弱 - 它已经快 30 年了老了,已经死了将近 20 年。不幸的是,这里没有足够的信息来提供帮助。
  • DDE 大约在 20 年前被 COM 取代。也许该软件具有更现代的 COM 自动化接口。我快速浏览了一下,here 据说它有一个 'MQ/SOAP/HTML/REST' 接口无论如何,我找不到任何有效的开发人员文档。
  • 2 周前在 Embarcadero 论坛上提出了完全相同的问题:DDECallback with Delphi 7 on win7 64 bits machine
  • 是的,我知道。现在公司要求我修复它:-(

标签: windows delphi 64-bit dde


【解决方案1】:

首先,为什么要手动实现 DDE 而不是使用 Delphi 的 TDdeClientConv 组件?

我在您的手动代码中看到了两个错误:

  1. 回调声明不正确。 Data1Data2 参数声明为 ULONG,但它们需要改为 ULONG_PTR。请参阅 MSDN 上的定义:

    DdeCallback callback function

    HDDEDATA CALLBACK DdeCallback(
      _In_ UINT      uType,
      _In_ UINT      uFmt,
      _In_ HCONV     hconv,
      _In_ HSZ       hsz1,
      _In_ HSZ       hsz2,
      _In_ HDDEDATA  hdata,
      _In_ ULONG_PTR dwData1,
      _In_ ULONG_PTR dwData2
    );
    

    ULONG 的大小始终为 32 位,即使在 64 位上也是如此 系统。 ULONG_PTR 是 32 位还是 64 位,具体取决于您是 编译为 32 位或 64 位。因此,在这种情况下,您的回调将 如果您将应用重新编译为 64 位,请截断这些参数值。

  2. 回调正在寻找XTYP_MONITOR 事务,但APPCLASS_MONITOR 未包含在对DdeInitialize() 的调用中。

话虽如此,如果你从TMonMsgStruct 得到垃圾,很可能它没有正确声明。在 Delphi 7(一直到 XE)中,我看到 Delphi 的 DDeml 单元中的 TMonMsgStruct 被声明为 packed 记录,这意味着它使用字节对齐。但在 Delphi XE2 中,packed 指令最终被删除,因此TMonMsgStruct 使用更自然的对齐方式(应该如此)。因此,您可能必须在自己的代码中重新声明 TMonMsgStruct 以使用与 64 位系统兼容的正确对齐方式(4 或 8 字节)。

更新:在 32 位系统上,您正在接收 32 位数据,而在 64 位系统上,您正在接收 64 位数据,即使您的应用程序是为 32 位编译的。 TMonMsgStruct 的大小在 32 位中为 72 字节,在 64 位中为 112 字节。 TMonMsgStruct 包含几个使用数据类型的字段,这些数据类型在 32 位中为 4 字节,在 64 位中为 8 字节(即HWNDTHandleWPARAMLPARAMUINT_PTR)。这些字段与对齐填充一起解释了大小的差异。因此,您需要:

  1. 编译 64 位版本的应用程序以在 64 位系统上运行。但是,您无法使用 Delphi 7 做到这一点,您需要 Delphi XE2 或更高版本。

  2. 让您的 32 位应用程序定义一个 64 位兼容版本的 TMonMsgStruct,然后使用从 DdeAccessData() 返回的 Len 值来决定是使用 32 位还是 64 位记录来访问数据。

【讨论】:

  • 对不起,但不知道如何格式化评论:-(谢谢你的回答。代码是用delphi 7编译的,所以32位exe,但它在64位windows 7上运行。我试过你的建议声明我自己的 TMonMsgStruct 声明为记录而不是打包记录。如果我调试回调函数 dwdata1 和 dwdata2 与我在 ddespy 中看到的值相同。
  • 这是由不在团队中的其他人开发的旧代码 :-( 在切换到 Windows 64 位之前它工作正常。我尝试使用 delphi 组件,但我无法理解工作。
  • 我在 32 位窗口上调试时看到的其他东西调用 pData := DdeAccessData(Data, @Len); len 是 72,但是当我在 64 位窗口上执行此操作时,len 是 112。我尝试提供尽可能多的信息。不知道如何解决这个问题:-(
  • 72 是 32 位的正确大小,112 是 64 位的正确大小。 TMonMsgStruct 包含几个使用数据类型的字段,这些数据类型在 32 位中为 4 个字节,在 64 位中为 8 个字节。这些字段与对齐填充一起解释了大小的差异。我已经用这些信息更新了我的答案。
猜你喜欢
  • 1970-01-01
  • 2011-11-25
  • 2023-03-30
  • 1970-01-01
  • 2011-04-16
  • 2012-04-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多