Attila Kovacs 629 Posted December 9, 2022 (edited) hehe, suddenly, the results of "UnpackDDElParam" make sense 😉 so looks like it can be done without it and without FreeDDElParam and without the reimport edit: almost The lParam parameter of the posted DDE message that was received. The application must free the memory object specified by the lParam parameter by calling the FreeDDElParam function. - Edited December 9, 2022 by Attila Kovacs Share this post Link to post
Attila Kovacs 629 Posted December 9, 2022 @aehimself great work, nice catch. would you make a QC report? Share this post Link to post
aehimself 396 Posted December 9, 2022 https://github.com/aehimself/AEFramework/blob/master/AE.DelphiVersions.pas finally updated, if anyone will need this in the future. I'll attempt the reporting sometime next week. Never did that before 🙂 1 Share this post Link to post
Attila Kovacs 629 Posted December 9, 2022 great! you can remove that comment in the middle 🙂 Share this post Link to post
aehimself 396 Posted December 12, 2022 @Attila Kovacs If you are interested, I managed to get execution of DDE commands to work with the API so you can ditch all windows message logic: Procedure TAEDDEManager.ExecuteCommand(Const inCommand: String; Const inConv: HConv; Const inTimeoutInMs: Cardinal = 5000); Var datahandle: HDDEData; res: LongInt; Begin datahandle := DdeCreateDataHandle(_ddeid, @PChar(inCommand)[0], Length(inCommand) * SizeOf(Char), 0, 0, CF_TEXT, 0); If datahandle = 0 Then Raise EAEDDEManagerException.Create('Creating data handle failed, DDE error ' + DdeGetLastError(_ddeid).ToString); If DdeClientTransaction(Pointer(datahandle), DWORD(-1), inConv, 0, CF_TEXT, XTYP_EXECUTE, inTimeOutInMs, @res) = 0 Then Raise EAEDDEManagerException.Create('Executing command failed, DDE error ' + DdeGetLastError(_ddeid).ToString); // If Not DdeFreeDataHandle(hszCmd) Then // Raise EDelphiVersionException.Create('Could not free data handle, DDE error ' + DdeGetLastError(_ddeid).ToString); End; This way the only method which needs reimporting is DdeInitializeW. inConv can come from DdeQueryNextServer or DdeConnect. As HDATA_APPOWNED is NOT defined as flag, freeing up the data handle will be performed on the DDE server side - that's why that last part is commented out. Share this post Link to post
Attila Kovacs 629 Posted December 12, 2022 Nah, at the end user32.dll also using the windows messages so I'm pretty happy using as little dde@user32 as possible. But thx anyway, maybe others finding it useful. 1 Share this post Link to post
aehimself 396 Posted December 13, 2022 I implemented the DDE API's execution code and there is a significant difference immediately. If you first open a large project (.dproj) which takes about 5-10 seconds to load, then a form / frame which takes about the same in rapid success, when using WIndows messages the form is often not loaded however the DDE server says it was accepted and processed. When using the DDE API, both are opened successfully. Maybe something is missing from the WIndows message version...? If it doesn't disturb you or you are not opening multiple files right after each other, you can safely ignore this. Share this post Link to post
Attila Kovacs 629 Posted December 13, 2022 1 hour ago, aehimself said: which takes about 5-10 seconds to load I can't imagine what would take so long to load, opened datasets on the forms? Anyway, I can't reproduce, it opens everything just fine. The messages are the very same at the end of the day, you can log it yourself with spy++. Share this post Link to post
aehimself 396 Posted December 23, 2022 @Attila Kovacs Your discovery method is inefficient. DDE_INITIATE is meant to be sent to HWND_BROADCAST and whoever supports it will reply. You also can identify the window who replied, as a WM_DDE_ACK message sent as a reply to DDE_INITIATE contains the DDE server window handle as WParam. Basically... Procedure TAEDDEManager.DiscoveryHandler(Var inMessage: TMessage); Var whandle: HWND; pid: Cardinal; Begin If inMessage.Msg <> WM_DDE_ACK Then Exit; whandle := inMessage.WParam; GetWindowThreadProcessId(whandle, pid); // Do something with the PID and the window handle of the process End; Procedure TAEDDEManager.RefreshServers; Var discoverywnd: HWND; serviceatom, topicatom: Word; msg: TMsg; res: Cardinal; Begin discoverywnd := AllocateHWnd(DiscoveryHandler); Try serviceatom := GlobalAddAtom(PChar(_service)); Try topicatom := GlobalAddAtom(PChar(_topic)); Try SendMessageTimeout(HWND_BROADCAST, WM_DDE_INITIATE, discoverywnd, Makelong(serviceatom, topicatom), SMTO_BLOCK, 1, res); While PeekMessage(msg, discoverywnd, 0, 0, PM_REMOVE) Do Begin TranslateMessage(msg); DispatchMessage(msg); End; Finally GlobalDeleteAtom(topicatom); End; Finally GlobalDeleteAtom(serviceatom); End; Finally DeallocateHWnd(_discoverywnd); End; End; And yes, I'll change my logic to window messages too. After long weeks of troubleshooting discovery still locks up after the fourth run when I'm using the DDE API 🙂 Share this post Link to post
Attila Kovacs 629 Posted December 23, 2022 4 hours ago, aehimself said: Your discovery method is inefficient. I don't think so. The opposite. My version is more efficient as it only talks to BDE instances. I don't care DDE, neither other apps, it's just for BDE. Share this post Link to post