Remus Rigo
Remus Rigo

Reputation: 1464

open text files in one application

I want to write an text editor and to assign the txt files to it. My problem is that I want to have only one instance running and when a new file is opened to send the filename to the first app that is already running... (I want to do this using mutex). Here is a small test

DPR looks like this

uses
  Windows, Messages, SysUtils,
  Forms,
  wndMain in 'wndMain.pas' {frmMain};

{$R *.res}

var
  PrevWindow : HWND;
  S : string;
  CData : TCopyDataStruct;
begin 
  PrevWindow := 0;
  if OpenMutex(MUTEX_ALL_ACCESS, False, 'MyMutex') <> 0 then
  begin
  repeat
     PrevWindow:=FindWindow('TfrmMain', nil);
  until PrevWindow<>Application.Handle;

     if IsWindow(PrevWindow) then
     begin
        SendMessage(PrevWindow, WM_SYSCOMMAND, SC_RESTORE, 0);
        BringWindowToTop(PrevWindow);
        SetForegroundWindow(PrevWindow);

        if FileExists(ParamStr(1)) then
        begin
           S:=ParamStr(1);
           CData.dwData:=0;
           CData.lpData:=PChar(S);
           CData.cbData:=1+Length(S);

           SendMessage(PrevWindow, WM_COPYDATA, 0, DWORD(@CData) );
           end;
        end;
     end
   else
      CreateMutex(nil, False, 'MyMutex');

  Application.Initialize;
  Application.CreateForm(TfrmMain, frmMain);
  Application.Run;
end.

PAS:

type TfrmMain = class(TForm)
   memo: TMemo;
   private
      procedure WMCopyData ( var msg : TWMCopyData ) ; message WM_COPYDATA;
  public
     procedure OpenFile(f : String);
end;

var
  frmMain: TfrmMain;

implementation

{$R *.dfm}

procedure TfrmMain.WMCopyData ( var msg : TWMCopyData ) ;
var
   f : String;
begin
   f:=PChar(msg.CopyDataStruct.lpData);
   //ShowMessage(f);
   OpenFile(f);
end;

procedure TfrmMain.OpenFile(f : String);
begin
   memo.Clear;
   memo.Lines.LoadFromFile(f);
   Caption:=f;
end;

this code should be ok, but if i want to open a text file (from the second app), the first app receives a message like this:

alt text http://img218.imageshack.us/img218/2175/errorjd.jpg

thanks

Upvotes: 1

Views: 1010

Answers (2)

Rob Kennedy
Rob Kennedy

Reputation: 163247

I suspect you're using Delphi 2009 or Delphi 2010. Those version use Unicode strings, so the Length function tells the number of characters in a string, but not the number bytes. The wm_CopyData message needs to know the number of bytes to send. Multiply the character count by two, or SizeOf(WideChar).

CData.lpData := PWideChar(S);
CData.cbData := (1+Length(S)) * SizeOf(WideChar);

Upvotes: 0

Mason Wheeler
Mason Wheeler

Reputation: 84540

This looks like a Unicode problem. You're probably in D2009 or D2010. You need to give the size in bytes, not in chaaracters. Try multiplying your length call by sizeof(char) and it should work.

Upvotes: 1

Related Questions