Jump to content

Attila Kovacs

Members
  • Content Count

    2067
  • Joined

  • Last visited

  • Days Won

    27

Everything posted by Attila Kovacs

  1. Attila Kovacs

    How to open a file in the already running IDE?

    There is an array with the window handles which answered to DDE_INITIATE, there is GetWindowExeName to get the executable, you have everything just like before, the only difference to your needs is, that I'm trying to open a file in every running IDE's in my demos.
  2. Attila Kovacs

    How to open a file in the already running IDE?

    by the way, if you are looking into my logs, DdeConnectList does the same. The only thing I don't know, how "DdeConnectList" is enumerating the windows. It was sending it to 128 ones.
  3. Attila Kovacs

    How to open a file in the already running IDE?

    Yes, but only the ones answering with ACK who's listening to DDE. It works very fine. Refresh the post, I've updated several times.
  4. Attila Kovacs

    How to open a file in the already running IDE?

    ok, here a native approach, finding the dde window with winapi and sending dde messages, no dde@user32 involved let's see, if it's more stable unit uBdsLauncher2; interface procedure OpenFile(const AFileName: string; ALog: boolean = False); implementation uses Winapi.Windows, Winapi.Messages, Winapi.PsAPI, System.SysUtils, System.Classes; const cDdeService = 'bds'; cDdeTopic = 'system'; var FDDEHWND: THandle = 0; FLog: boolean; FWHandles: TArray<HWND>; aService, aTopic: WORD; type TDdeHelper = class public class procedure DdeWndProc(var AMsg: TMessage); end; function EnumWindowsProc(wHandle: HWND; lParam: THandle): BOOL; stdcall; export; var ClassName: array [0 .. 255] of char; begin Result := True; GetClassName(wHandle, ClassName, 255); if SameText(ClassName, 'TPUtilWindow') then SendMessage(wHandle, WM_DDE_INITIATE, FDDEHWND, Makelong(aService, aTopic)); end; // make a string global, dont forget to unlock/free it function GlobalLockString(AValue: string; AFlags: UINT): THandle; var DataPtr: Pointer; begin Result := GlobalAlloc(GMEM_ZEROINIT or AFlags, (Length(AValue) * SizeOf(char)) + 1); try DataPtr := GlobalLock(Result); Move(PChar(AValue)^, DataPtr^, Length(AValue) * SizeOf(char)); except GlobalFree(Result); raise; end; end; function GetWindowExeName(wHandle: HWND): string; var PID: DWORD; hProcess: THandle; nTemp: Cardinal; Modules: array [0 .. 255] of THandle; Buffer: array [0 .. 4095] of char; begin Result := ''; if GetWindowThreadProcessId(wHandle, PID) <> 0 then begin hProcess := OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ, False, PID); if hProcess <> 0 then if EnumProcessModules(hProcess, @Modules[0], Length(Modules), nTemp) then if GetModuleFileNameEx(hProcess, 0, Buffer, SizeOf(Buffer)) > 0 then Result := Buffer; end; end; procedure OpenFile(const AFileName: string; ALog: boolean = False); var i: integer; ddeCommand: string; ddeCommandH: THandle; begin FLog := ALog; FDDEHWND := AllocateHWnd(TDdeHelper.DdeWndProc); try SetLength(FWHandles, 0); aService := GlobalAddAtom(PChar(cDdeService)); aTopic := GlobalAddAtom(PChar(cDdeTopic)); try EnumWindows(@EnumWindowsProc, 0); finally GlobalDeleteAtom(aService); GlobalDeleteAtom(aTopic); end; // send the DDE command to every running BDE instances ddeCommand := Format('[open("%s")]', [AFileName]); ddeCommandH := GlobalLockString(ddeCommand, GMEM_DDESHARE); try for i := 0 to High(FWHandles) do begin if FLog then WriteLn(Format('Sending command "%s" to %s', [ddeCommand, IntToHex(FWHandles[i], 8)])); PostMessage(FWHandles[i], WM_DDE_EXECUTE, FDDEHWND, ddeCommandH); PostMessage(FWHandles[i], WM_DDE_TERMINATE, FDDEHWND, 0); end; finally GlobalUnlock(ddeCommandH); GlobalFree(ddeCommandH); end; finally DeAllocateHWND(FDDEHWND); end; end; class procedure TDdeHelper.DdeWndProc(var AMsg: TMessage); var l: integer; begin // ack debug if AMsg.Msg = WM_DDE_ACK then begin l := Length(FWHandles); SetLength(FWHandles, l + 1); FWHandles[l] := AMsg.WParam; if FLog then WriteLn(Format('ACK from: %x %x', [AMsg.WParam, AMsg.lParam])); end else if FDDEHWND <> 0 then DefWindowProc(FDDEHWND, AMsg.Msg, AMsg.WParam, AMsg.lParam); end; end.
  5. Attila Kovacs

    How to open a file in the already running IDE?

    Here are two DDE log files, This is what BDS is getting by calling "DdeConnectList()"..... (why??? 128 conversations are opened. wtaf?) 1(-3) working, 4th, last terminate is missing and the returned list by DdeConnectList is empty. 1.sxl 4.sxl Ok, these are all the window handles on my system, not just bds however I was filtering for the one hwnd.... never mind. But, 00C70C4C is a TPUtilWindow (AllocateHwd), which belongs to bds.exe <000280> 00C70C4C S WM_DDE_INITIATE hwnd:003109E0 aApp:C24F ("bds") aTopic:C009 ("System") <000281> 003109E0 S WM_DDE_ACK hwnd:00C70C4C aApp:C24F ("bds") aTopic:C009 ("System") <000282> 003109E0 R WM_DDE_ACK <000283> 00C70C4C R WM_DDE_INITIATE <000400> 00C70C4C P WM_DDE_TERMINATE hwnd:003109E0 <---- this is missing from the 4th run Code Meaning P The message was posted to the queue with the PostMessage function. No information is available concerning the ultimate disposition of the message. S The message was sent with the SendMessage function. This means that the sender doesn’t regain control until the receiver processes and returns the message. The receiver can, therefore, pass a return value back to the sender. s The message was sent, but security prevents access to the return value. R Each ‘S’ line has a corresponding ‘R’ (return) line that lists the message return value. Sometimes message calls are nested, which means that one message handler sends another message.
  6. Attila Kovacs

    How to open a file in the already running IDE?

    but opening files from the shell still works which is also DDE from bdsLauncher
  7. Attila Kovacs

    How to open a file in the already running IDE?

    something is still not ok, after 4 calls the IDE won't respond anymore
  8. Attila Kovacs

    How to open a file in the already running IDE?

    there is a small change since then in at the beginning of the DDE part lHszApp := DdeCreateStringHandleW(FDdeInstId, PChar(DdeService), CP_WINUNICODE); DdeKeepStringHandle(FDdeInstId, lHszApp); lHszTopic := DdeCreateStringHandleW(FDdeInstId, PChar(DdeTopic), CP_WINUNICODE); DdeKeepStringHandle(FDdeInstId, lHszTopic); try ConvList := DdeConnectList(FDdeInstId, lHszApp, lHszTopic, 0, nil); finally DdeFreeStringHandle(FDdeInstId, lHszApp); DdeFreeStringHandle(FDdeInstId, lHszTopic); end; also, I dropped vcl.ddeman and initialize DDE myself ..... function DdeMgrCallBack(CallType, Fmt: UINT; Conv: HConv; hsz1, hsz2: HSZ; Data: HDDEData; Data1, Data2: ULONG_PTR): HDDEData; stdcall; begin Result := 0; end; initialization // DdeInitialize FDdeInstId := 0; InitRes := DdeInitializeW(FDdeInstId, DdeMgrCallBack, APPCLASS_STANDARD, 0); if InitRes <> 0 then raise Exception.CreateFmt('DDE Error: %d', [DdeGetLastError(InitRes)]); finalization DdeUninitialize(FDdeInstId); and headless dde windows messages (from console), optional: FDDEHWND := AllocateHWnd(TDDeHelper.DDEWndProc); try // fist initiate the communication, this results an ACK from the host aService := GlobalAddAtom(PChar(sService)); aTopic := GlobalAddAtom(PChar(sTopic)); try SendMessage(ci.hwndPartner, WM_DDE_INITIATE, FDDEHWND, Makelong(aService, aTopic)); finally GlobalDeleteAtom(aService); GlobalDeleteAtom(aTopic); end; // send dde script ddeCommandH := GlobalLockString(ddeCommand, GMEM_DDESHARE); try PostMessage(ci.hwndPartner, WM_DDE_EXECUTE, FDDEHWND, ddeCommandH); finally GlobalUnlock(ddeCommandH); GlobalFree(ddeCommandH); end; finally DeAllocateHWND(FDDEHWND); end; whereas class procedure TDDeHelper.DDEWndProc(var AMsg: TMessage); begin // ack debug if AMsg.Msg = WM_DDE_ACK then begin if FLog then WriteLn(Format('ACK from: %x %x', [AMsg.WParam, AMsg.LParam])); end else if FDDEHWND <> 0 then DefWindowProc(FDDEHWND, AMsg.Msg, AMsg.WParam, AMsg.LParam); end; as a whole: uBdsLauncher2.pas
  9. Attila Kovacs

    How to open a file in the already running IDE?

    caption is a good alternative yes, as long as it won't change in the future
  10. Attila Kovacs

    How to open a file in the already running IDE?

    as you can only have one instance of one major version installed, it should not be a problem
  11. Attila Kovacs

    How to open a file in the already running IDE?

    with http://melander.dk/articles/versioninfo/ the versions are Berlin 24.0.25048.9432 D2007 11.0.2902.10471 we have everything we need
  12. Attila Kovacs

    How to open a file in the already running IDE?

    here is the executable name Buffer: array [0 .. 4095] of Char; Modules: array [0 .. 255] of THandle; PID: DWORD; exePathLen: integer; hProcess: THandle; nResult: boolean; nTemp: Cardinal; aService, aTopic: WORD; .... if GetWindowThreadProcessId(ci.hwndPartner, PID) <> 0 then begin hProcess := OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ, False, PID); if hProcess <> 0 then begin nResult := EnumProcessModules(hProcess, @Modules[0], Length(Modules), nTemp); if nResult then begin nTemp := GetModuleFileNameEx(hProcess, 0, Buffer, SizeOf(Buffer)); Memo1.Lines.Add(Buffer); end; end; end; ...
  13. Attila Kovacs

    How to open a file in the already running IDE?

    make exhaustive testing, it stopped working on my system again. no clue why
  14. Attila Kovacs

    How to open a file in the already running IDE?

    Yeah, but now, I want my bdsLaucher2, where one can define, from which folder which IDE should spawn or open the file!
  15. Attila Kovacs

    How to open a file in the already running IDE?

    ooooooooo **** me running. This helped to fix my problem opening files by doublekingkong on them in the explorer. At some point, I set bds.exe itself to run as administrator, not just a shortcut, the exe! No clue why, but from that point I could only open files from the IDE, of course. I noticed that the program above works only from the IDE, which made me think.
  16. Attila Kovacs

    How to open a file in the already running IDE?

    Here. This queries all the running bde's and opens a file in every one. This is a good start, you have to find out which is which version somehow, I have no more time for that. DDE-test.7z
  17. Attila Kovacs

    How to open a file in the already running IDE?

    this opens me the file in the running IDE DdeClientConv1.ServiceApplication := '"C:\Program Files (x86)\Embarcadero\Studio\18.0\bin\bds.exe"'; Memo1.Lines.Add('Setting DDE link...'); If Not DdeClientConv1.SetLink('bds', 'system') then begin Memo1.Lines.Add('Setting link failed!'); Exit; end; // Memo1.Lines.Add('Opening DDE link...'); // If Not DdeClientConv1.OpenLink then // begin // Memo1.Lines.Add('Opening link failed!'); // Exit; // end; try Memo1.Lines.Add('Invoking DDE command...'); if Not DdeClientConv1.ExecuteMacro(PAnsiChar('[open("C:\Temp\tmp\a.pas")]'), False) then begin Memo1.Lines.Add('Invoking command failed!'); Exit; end; finally Memo1.Lines.Add('Closing DDE link...'); DdeClientConv1.CloseLink; end;
  18. Attila Kovacs

    How to open a file in the already running IDE?

    @aehimself How is the bdslauncher answering your query anyway? It's not a resident application, do you have some ghost processes of it? It's bdsLauncher which should detect if bds is running and if yes, send a dde to bds, otherwise start it. AFAIK. Am I Wrong?
  19. Attila Kovacs

    How to open a file in the already running IDE?

    are you sure it's PAnsiChar?
  20. Attila Kovacs

    How to open a file in the already running IDE?

    perhaps he has a Cherry keyboard...
  21. Attila Kovacs

    How to open a file in the already running IDE?

    with full path of bds.exe?
  22. Attila Kovacs

    How to open a file in the already running IDE?

    what about bdslauncher.exe bds.exe /np d:\myfile.pas ? with full paths ofc
  23. Attila Kovacs

    How to open a file in the already running IDE?

    you have to start the bdslauncher not the bds, theoretically, on my install it stopped working completely couple of months ago.
  24. Attila Kovacs

    How do I delete a row in a database with FireDAC?

    not buying every hdd's on the earth? 😉
  25. Attila Kovacs

    form data store component ?

    It's for text only. I'd put binary in resources. Or you can extend the component to apply to your needs.. but in this case you have to replace tstringlists with streams and implement a Writer and a Reader for the dfm.
×