我们有一个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;
答案 0 :(得分:0)
首先,为什么要手动实现DDE而不是使用Delphi的TDdeClientConv
组件?
我在手动代码中看到的两个错误:
回调声明不正确。 Data1
和Data2
参数声明为ULONG
,但它们必须为ULONG_PTR
。请参阅MSDN上的定义:
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位重新编译应用程序,则截断这些参数值。
回调正在查找XTYP_MONITOR
次交易,但APPCLASS_MONITOR
的调用中未包含DdeInitialize()
。
话虽如此,如果你从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个字节(即HWND
,THandle
,WPARAM
,LPARAM
,以及UINT_PTR
)。这些字段以及对齐填充代表了大小的差异。所以,你需要:
编译64位版本的应用程序以在64位系统上运行。但是,你不能用Delphi 7做到这一点,你需要Delphi XE2或更高版本。
让您的32位应用定义64位兼容版本的TMonMsgStruct
,然后使用Len
返回的DdeAccessData()
值来决定是使用32位还是64位记录访问数据。