Jump to content
aehimself

Delphi & WM_DDE_INITIATE

Recommended Posts

I am in a bit of a dazzle here. However it wouldn't be a surprise in general, but is it possible that the Delphi IDE doesn't (and never did) handle WM_DDE_INITIATE correctly?

 

In a different post, @Attila Kovacs managed to get DDE functioning properly on a modern IDE, but I realized that Delphi 7 for example doesn't reply to any conversation request with service "bds" and topic "system".

Service is usually the executable name, this is confirmed by the registry entry:

 

image.thumb.png.af9bd8cbdc4bd694fd5259e4d2eccabf.png

 

However it says nothing about a topic. I experimented with sending empty strings, nulls, "system" or "DELPHI32" directly to windows and HWND_BROADCAST without success.

 

According to Microsoft:

Quote

 

If the low-order word of lParam is NULL, any server application can respond. If the high-order word of lParam is NULL, any topic is valid. Upon receiving a WM_DDE_INITIATE request with the high-order word of the lParam parameter set to NULL, a server must send a WM_DDE_ACK message for each of the topics it supports.

 

Basically, broadcasting 0-0 will end up discovering all available DDE services and topics for use.

 

explorer.exe behaves correctly:

Quote

PID: 5148, title: "", class: "DDEMLMom"
ACK from 4523036: service: PROGMAN, topic: PROGMAN
ACK from 4850962: service: Shell, topic: AppProperties
ACK from 4130072: service: Folders, topic: AppProperties

However Delphi 7 and Delphi 10.4.2 does not reply with anything. Is it possible that the Delphi IDE never handled WM_DDE_INITIATE messages correctly? If yes, what documentation I have to dig up to get DDE details for earlier Delphi IDEs?

 

The code I used is:

 

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;

type
  TForm1 = class(TForm)
    Memo1: TMemo;
    procedure FormCreate(Sender: TObject);
  private
    procedure DdeWndProc(var AMsg: TMessage);
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

Type
  TDDEInfo = Record
    WindowHandle: HWND;
    ServiceAtom: Word;
    TopicAtom: Word;
  End;

  PDDEInfo = ^TDDEInfo;

{$R *.dfm}

Function FindDelphiWindow(inHWND: HWND; inParam: LParam): Boolean; StdCall;
Var
  ppid: Cardinal;
  title, classname: Array[0..255] Of Char;
Begin
  // https://docs.microsoft.com/en-us/previous-versions/windows/desktop/legacy/ms633498(v=vs.85)
  // Result := True   ->   Continue evaluation
  // Result := False  ->   Do not continue evaluation

  Result := True;

  GetWindowThreadProcessID(inHWND, ppid);

//  if ppid <> 7196 then
//    Exit;

  GetWindowText(inHWND, title, 255);
  GetClassName(inHWND, classname, 255);


  Form1.Memo1.Lines.Add('PID: ' + ppid.ToString + ', title: "' + title + '", class: "' + classname + '"');
  SendMessage(inHWND, WM_DDE_INITIATE, PDDEInfo(inParam)^.WindowHandle, Makelong(PDDEInfo(inParam)^.ServiceAtom, PDDEInfo(inParam)^.TopicAtom));
End;


procedure TForm1.DdeWndProc(var AMsg: TMessage);
Var
 service, topic: PChar;
begin
  if Amsg.Msg = WM_DDE_ACK then
  Begin
    GetMem(service, 256);
    GetMem(topic, 256);
    Try
      GlobalGetAtomName(AMsg.LParamLo, service, 255);
      GlobalGetAtomName(AMsg.LParamHi, topic, 255);

      Memo1.Lines.Add('ACK from ' + AMsg.wParam.ToString + ': service: ' + service + ', topic: ' + topic);
    Finally
      FreeMem(service);
      FreeMem(topic);
    End;
//    PostMessage(HWND(AMsg.wParam), WM_DDE_TERMINATE, AMsg., 0);
  End;
end;

procedure TForm1.FormCreate(Sender: TObject);
Var
  di: PDDEInfo;
Begin
  New(di);
  di^.WindowHandle := AllocateHWND(DdeWndProc);
  Try
    di^.ServiceAtom := 0; // GlobalAddAtom(PChar('DELPHI32'));
    di^.TopicAtom := 0; // GlobalAddAtom(PChar('DELPHI32'));

    Memo1.Lines.BeginUpdate;
    Try
      Memo1.Lines.Clear;

      EnumWindows(@FindDelphiWindow, LParam(di));
    Finally
      Memo1.Lines.EndUpdate;
    End;

//    GlobalDeleteAtom(di^.ServiceAtom);
//    GlobalDeleteAtom(di^.TopicAtom);
  Finally
    DeallocateHwnd(di^.WindowHandle);
  End;
end;

end.


 

Share this post


Link to post
 di^.ServiceAtom := 0; // GlobalAddAtom(PChar('DELPHI32'));
 di^.TopicAtom := 0; // GlobalAddAtom(PChar('DELPHI32'));

 

it won't answer on 0/0,  just on 'system'/'bds'

 

does D7 support DDE anyway?

 

 

 

Share this post


Link to post

Sometimes it's good to take a break from something. I went to play with my daughter and realized... D7 doesn't understand Unicode! Maybe it receives the message but it will see only it's first character...

Will have to test this theory later out though.

  • Haha 1

Share this post


Link to post
3 hours ago, Attila Kovacs said:

it won't answer on 0/0,  just on 'system'/'bds'

 

does D7 support DDE anyway?

I know, this is one of the questions in this topic. As far as I understand, a DDE server should reply with one WM_DDE_ACK message for each service / topic pair it supports, but Delphi doesn't seem to do that. Neither 7, neither 10.4.2.

 

As for being Unicode it was a good guess but it doesn't work. Running the same code from D7, or changing GlobalAddAtom to GlobalAddAtomA yields no results.

 

I guess there's only one question. As detection doesn't seem to work, in which documentation / source file I can look for supported DDE service / topic strings for Delphi?

 

Edit:

 

Ummm...

 

image.png.a6fe8953ecf06a8968e95412086f5ff0.png

Edited by aehimself
  • Like 1

Share this post


Link to post

My idea seems to be correct after all, I should add my daughter right next to the rubber duck on my desk. I don't know what happened when I tried to run the code under D7 but if I change every call to the WinApi "A" version in D10.4.2 it simply works...

 

image.thumb.png.e5f0cb9ba5d948f0023b39f78de840f0.png

 

And yes, I can confirm... Delphi 7 supports DDE, needs the service "DELPHI32" and the topic "system". It just has to be ANSI, not Unicode.

  • Like 1

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×