TC Change dirs from Delphi

Discuss and announce Total Commander plugins, addons and other useful tools here, both their usage and their development.

Moderators: Hacker, petermad, Stefan2, white

Post Reply
olesio
Junior Member
Junior Member
Posts: 54
Joined: 2009-01-22, 15:29 UTC
Location: Poland

TC Change dirs from Delphi

Post by *olesio »

Hello. I have problem again. This time with changing directory in TC from
Delphi code. I readed http://ghisler.ch/wiki/index.php/TCUtils.cpp and try
to do this with code below. Memo shows Text ok. But TC do not recognize
my command. I readed http://www.ghisler.ch/board/viewtopic.php?t=24865
also but tips given there do not help. MVV wrote there how to add chars to
a parameter, but I can not use #0 in Delphi because it breaks string and if
even I use it the command do not work. How to do this correctly in Delphi?
Please tell me how to fix my code. Is only way to change dirs id using a CD
command added in own em_ commands? I gues no because method with a
similar code in C was given in topic from link above so it work somehow ;/

Code: Select all

  private
    procedure WMCopyData(var Msg : TWMCopyData); message WM_COPYDATA;
  public
  end;

var
  Form1 : TForm1;

implementation

{$R *.dfm}

procedure TForm1.WMCopyData(var Msg : TWMCopyData);
var
  S : string;
begin
  S := PChar(Msg.CopyDataStruct.lpData);
  Memo1.Lines.Add(S);
  Msg.Result := 2006;
end;

procedure SendChangeDirectory(FirstPath, SecondPath, Flags : string);
var
  Tc_H : HWND;
  WholePath : string;
  DataStruct : CopyDataStruct;
begin
  TC_H := FindWindow('TTOTAL_CMD', nil);
  if (TC_H <> 0) then
  begin
    if (FirstPath = '') then
    begin
      Exit;
    end
    else
    begin
      WholePath := FirstPath + #10;
      if (SecondPath <> '') then
      begin
        WholePath := WholePath + SecondPath;
      end;
      if (Flags <> '') then
      begin
        WholePath := WholePath + Flags;
      end;
      DataStruct.dwData := Ord('C') + 256 * Ord('D');
      DataStruct.cbData := Length(WholePath) + 1;
      DataStruct.lpData := PChar(WholePath);
      SendMessage(TC_H, WM_COPYDATA, 0, Integer(@DataStruct));
      SendMessage(Form1.Handle, WM_COPYDATA, 0, Integer(@DataStruct));
      SetForegroundWindow(TC_H);
    end;
  end;
end;


procedure TForm1.Button1Click(Sender : TObject);
begin
  SendChangeDirectory('C:\', '' , '');
end;
Best regards: olesio
User avatar
MVV
Power Member
Power Member
Posts: 8711
Joined: 2008-08-03, 12:51 UTC
Location: Russian Federation

Post by *MVV »

AFAIK normal Delphi strings have special length field and their length is determined by this field and not 'til zero char. So you need to declare String variable, set its length to enough value and work with string as with char buffer - e.g. if you need to append zero char, you need to increase string length using SetLength and set last string char to #0: s[length(s)]:=#0. When you will append next string to this string, Delphi should keep zero char. I will repeat, data block that TC expects with WM_COPYDATA is not a valid string because it contains zero characters.
olesio
Junior Member
Junior Member
Posts: 54
Joined: 2009-01-22, 15:29 UTC
Location: Poland

Post by *olesio »

AFAIK strings in Delphi "are null termnatd strings" so they end with #0.
I'm trying with added in code like below:

Code: Select all

      WholePath := FirstPath + #10;
      SetLength(WholePath, Length(WholePath) + 1);
      WholePath[Length(WholePath)] := #0;
But still do not work. It is strange because code below for em_ commands
work witouh problems. Probable my WholePath variable contains something
other than TC expect. Maybe you have other idea? Maybe TC author know?
Best regards: olesio
User avatar
MVV
Power Member
Power Member
Posts: 8711
Joined: 2008-08-03, 12:51 UTC
Location: Russian Federation

Post by *MVV »

Strings in Delphi are null-terminated but zero char doesn't signal end of string for internal functions (null char is only for quick string to pchar converting - since pchar is null-terminated string).
Anyway, you may remember indexes of chars that must be zero and assign spaces to theese chars and set them to zeroes after last string modification, then you'll need to put pchar(s) and length(s) into WM_COPYDATA structure. Also you may set string length once (to some enough value) and use wsprintf function to fill buffer as TC needs:

Code: Select all

setLength(S, length(Path1)+length(Path2)+length(Flags)+4);
lpData:=pchar(S);
cbData:=wsprintfA(pchar(S), "%s\r%s%c%s", pchar(Path1), pchar(Path2), 0, pchar(Flags));
Sob
Power Member
Power Member
Posts: 945
Joined: 2005-01-19, 17:33 UTC

Post by *Sob »

One sigle character and how much it can do. :)

"\r" is not #10, but #13.
olesio
Junior Member
Junior Member
Posts: 54
Joined: 2009-01-22, 15:29 UTC
Location: Poland

Post by *olesio »

Sob and MVV thanks a lot for help. Lame me. I seen \r in C source, but in
other thread MVV suggest to use #10 char, so I did int realized it can be
wrong. Now everything works fine. Here is ok code if someone need it :)

Code: Select all

procedure SendTCChangeDirectory(FirstPath, SecondPath, Flags : string);
var
  Tc_H : HWND;
  WholePath : string;
  DataStruct : CopyDataStruct;
begin
  TC_H := FindWindow('TTOTAL_CMD', nil);
  if (TC_H <> 0) then
  begin
    if (FirstPath = '') then
    begin
      Exit;
    end
    else
    begin
      WholePath := FirstPath + #13;
      if (SecondPath <> '') then
      begin
        WholePath := WholePath + SecondPath + #0;
      end;
      if (Flags <> '') then
      begin
        WholePath := WholePath + Flags;
      end;
      DataStruct.dwData := Ord('C') + 256 * Ord('D');
      DataStruct.cbData := Length(WholePath) + 1;
      DataStruct.lpData := PChar(WholePath);
      SendMessage(TC_H, WM_COPYDATA, 0, Integer(@DataStruct));
    end;
  end;
end;
Best regards: olesio
User avatar
MVV
Power Member
Power Member
Posts: 8711
Joined: 2008-08-03, 12:51 UTC
Location: Russian Federation

Post by *MVV »

Yes, seems it's my fault, I mistyped char index in that topic and missed that it's wrong in this one. :)

Sob, thanks for observation!
Post Reply