Jump to content
aehimself

How to open a file in the already running IDE?

Recommended Posts

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 by Attila Kovacs

Share this post


Link to post

@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

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.

  • Like 1

Share this post


Link to post

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
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

@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
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

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

×