在Windows 7 - 64位上的Delphi 7 dde回调

时间:2015-12-15 12:04:04

标签: windows delphi 64-bit dde

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

现在我们公司正在切换到Windows 7 64位,客户端和服务器之间的通信不再有效。 我们使用DdeInitialize

的回调函数

我们使用这个是因为我们想知道服务器完成的流程何时真正完成并且生成了文档。

在Windows 7 64位上,我们得到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;

1 个答案:

答案 0 :(得分:0)

首先,为什么要手动实现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()

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

    更新:在32位系统上,您正在接收32位数据,而在64位系统上,即使您的应用程序编译为32位,您也会收到64位数据。 TMonMsgStruct的大小在32位是72字节,在64位是112字节。 TMonMsgStruct包含几个使用数据类型的字段,这些字段在32位中为4个字节,在64位中为8个字节(即HWNDTHandleWPARAMLPARAM,以及UINT_PTR)。这些字段以及对齐填充代表了大小的差异。所以,你需要:

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

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