Otwieranie wielu plików skojarzonych z rozszerzeniem

0

Jak skojarzyć program z rozszerzeniem można sobie przeczytać np. tutaj
http://delphi32.blogspot.com/2011/05/delphi-class-for-managing-file.html

Zastanawia mnie jednak badzie skomplikowana sytuacja gdy jeden program ma otworzyć wiele plików.
Tak jak to się dzieje np. w programie Winamp , Foobar, czy dowolnym innym odtwarzaczu muzyki MP3.
Jak zaznaczymy kilka plików i zrobimy "Open" to uruchomi się tylko jeden program który będzie posiadał informację o wszystkich otwieranych plikach.

Ewentualnie można dodawać do playlist pojedyncze pliki , nie powoduje to uruchamianie kolejnych instancji programu.

Jak to się dzieje ?
System uruchamia dla każdego pliku EXE tylko że ono się nie uruchamia a przekazuje informację o otwieranym pliku do pierwszej instancji i się program zamyka ?

0

System uruchamia dla każdego pliku EXE tylko że ono się nie uruchamia a przekazuje informację o otwieranym pliku do pierwszej instancji i się program zamyka ?

Tak to mniej-więcej działa.

0

Otwieranie pliku lub plików przez skojarzenie działa banalnie prosto: jeśli klikamy pojedynczy plik skojarzony z aplikacją, to system uruchamia aplikację podstawiając jej za ParamStr(1) ścieżkę do klikniętego pliku, a jeśli zaznaczyliśmy N plików, to ścieżki są po kolei podstawiane za ParamStr(1)...ParamStr(N). Wystarczy, że Twoja aplikacja właściwie rozpozna podawane jej parametry (czy to ścieżki do plików, a nie np. obsługiwane komendy lub przełączniki), a reszta to już kwestia wrzucenia ścieżek do jakiejś (play)listy.
Inaczej ma się otwieranie plików za pośrednictwem komunikatów DDE (np. pliki pakietu Office), ale to już inna bajka ;)

0

Jak sie uruchamia kilka plików na raz to uruchamia sie nowy proces dla każdego pliku z osobna, wiec nie jest prawdą to co napisał marogo o [n] naprametrach
Wiec problem otworzenia kilku dokumentów trzeba rozwiazac za pomocą komunikacji miedzy procesami.
Program przy starcie sprawdza czy program już jest uruchomiony jezeli tak to wysyła mu nazwe dokumentu i kończy swój żywot.
Przetestowane i działa pięknie

0

Ją jeszcze uścislę, że uruchamiany plik wcale nie musi iść jako paramstr(1). Tak jest domyślnie, ale w rejestrze można to dość dowolnie definiować dla danej aplikacji.

0

@marogo - proszę sprawdź sobie to proszę, zrób najprostszy test: skojarz z rozszerzeniem .koza123 jakiś swój program a potem zaznacz kilka plików .koza123 i zrób "OPEN" i się zaskoczysz
@TomRiddle - w tym przypadku to chyba trzeba zapytać sie tego kto to tak zaimplementował choć móg wybrac inną drogę ale to już filozofia :D

0

Można tego dokonać tworząc choćby plik tekstowy np. w katalogu programu (tworzy go pierwszy proces i wpisuje otwierany/otwierane pliki), jeśli włączy się następny proces sprawdza czy już istnieje jeśli tak to powinien być plik i dopisuje do niego kolejny plik do kolejki.

0

Ja tam zastosowałem pipe i mutex.

begin
  CreateMutex(nil, FALSE, 'moj_mutex'); //
  if GetLastError() <> 0 then
  begin
    TPBPipeClient.SendData('\\.\pipe\moj_pipek', Daj_Parametry_programu());
    Halt;
  end;

  Application.Initialize;
  Application.MainFormOnTaskbar := True;
  Application.CreateForm(TFormMain, FormMain);
  Application.Run;
end.

I gdzieś w aplikacji musi być tylko TPBPipeServer który obsłuży nadchodzące dane.
W TPBPipeServer jest tylko drobny błąd bo przychodzące dane są obsługiwane w kontekście wątku ,
jak będziemy rzeźbić po kontrolkach wizualnych to czasami są niemiłe niespodzianki. Po drobnej poprawce działa pieknie.

Klasa TPBPipeClient z tego wątku
http://stackoverflow.com/questions/512366/how-do-i-send-a-string-from-one-instance-of-my-delphi-program-to-another,
Pozwoliłem sobie zacytować cały unit , bo potem zginie linkowana strona i nie wiadomo gdzie tego szukać

unit PetriW.Pipes;

interface

uses
  Windows,
  Classes,
  Forms,
  SyncObjs,
  SysUtils
  ;

type
  TPBPipeServerReceivedDataEvent = procedure(AData: string) of object;

  TPBPipeServer = class
  private
    type
      TPBPipeServerThread = class(TThread)
      private
        FServer: TPBPipeServer;
      protected
      public
        procedure Execute; override;

        property  Server: TPBPipeServer read FServer;
      end;
  private
    FOnReceivedData: TPBPipeServerReceivedDataEvent;
    FPath: string;
    FPipeHandle: THandle;
    FShutdownEvent: TEvent;
    FThread: TPBPipeServerThread;
  protected
  public
    constructor Create(APath: string);
    destructor Destroy; override;

    property  Path: string read FPath;

    property  OnReceivedData: TPBPipeServerReceivedDataEvent read FOnReceivedData write FOnReceivedData;
  end;

  TPBPipeClient = class
  private
    FPath: string;
  protected
  public
    constructor Create(APath: string);
    destructor Destroy; override;

    property  Path: string read FPath;

    procedure SendData(AData: string); overload;
    class procedure SendData(APath, AData: string); overload;
  end;

implementation

const
  PIPE_MESSAGE_SIZE = $20000;

{ TPipeServer }

constructor TPBPipeServer.Create(APath: string);
begin
  FPath := APath;

  FShutdownEvent := TEvent.Create(nil, True, False, '');

  FPipeHandle := CreateNamedPipe(
    PWideChar(FPath),
    PIPE_ACCESS_DUPLEX or FILE_FLAG_OVERLAPPED,
    PIPE_TYPE_MESSAGE or PIPE_READMODE_MESSAGE or PIPE_WAIT,
    PIPE_UNLIMITED_INSTANCES,
    SizeOf(Integer),
    PIPE_MESSAGE_SIZE,
    NMPWAIT_USE_DEFAULT_WAIT,
    nil
  );

  if FPipeHandle = INVALID_HANDLE_VALUE then
    RaiseLastOSError;

  FThread := TPBPipeServerThread.Create(true);
  FThread.FreeOnTerminate := false;
  FThread.FServer := self;
  FThread.Resume;
end;

destructor TPBPipeServer.Destroy;
begin
  FShutdownEvent.SetEvent;
  FreeAndNil(FThread);
  CloseHandle(FPipeHandle);
  FreeAndNil(FShutdownEvent);

  inherited;
end;

{ TPipeServer.TPipeServerThread }

procedure TPBPipeServer.TPBPipeServerThread.Execute;
var
  ConnectEvent, ReadEvent: TEvent;
  events: THandleObjectArray;
  opconnect, opread: TOverlapped;
  Signal: THandleObject;
  buffer: TBytes;
  bytesRead, error: Cardinal;
begin
  inherited;

  //SetThreadName('TPBPipeServer.TPBPipeServerThread');

  ConnectEvent := TEvent.Create(nil, False, False, '');
  try
    setlength(events, 2);
    events[1] := Server.FShutdownEvent;

    FillMemory(@opconnect, SizeOf(TOverlapped), 0);
    opconnect.hEvent := ConnectEvent.Handle;

    while not Terminated do
    begin
      ConnectNamedPipe(Server.FPipeHandle, @opconnect);

      events[0] := ConnectEvent;
      THandleObject.WaitForMultiple(events, INFINITE, False, Signal);
      if Signal = ConnectEvent then
      try
        // successful connect!
        ReadEvent := TEvent.Create(nil, True, False, '');
        try
          FillMemory(@opread, SizeOf(TOverlapped), 0);
          opread.hEvent := ReadEvent.Handle;
          setlength(buffer, PIPE_MESSAGE_SIZE);

          if not ReadFile(Server.FPipeHandle, buffer[0], PIPE_MESSAGE_SIZE, bytesRead, @opread) then
          begin
            error := GetLastError;
            if error = ERROR_IO_PENDING then
            begin
              if not GetOverlappedResult(Server.FPipeHandle, opread, bytesRead, True) then
                error := GetLastError
              else
                error := ERROR_SUCCESS;
            end;
            if error = ERROR_BROKEN_PIPE then
              // ignore, but discard data
              bytesRead := 0
            else if error = ERROR_SUCCESS then
              // ignore
            else
              RaiseLastOSError(error);
          end;

          if (bytesRead > 0) and Assigned(Server.OnReceivedData) then
            Server.OnReceivedData(TEncoding.Unicode.GetString(buffer, 0, bytesRead));

          // Set result to 1
          PInteger(@buffer[0])^ := 1;
          if not WriteFile(Server.FPipeHandle, buffer[0], SizeOf(Integer), bytesRead, @opread) then
          begin
            error := GetLastError;
            if error = ERROR_IO_PENDING then
            begin
              if not GetOverlappedResult(Server.FPipeHandle, opread, bytesRead, True) then
                error := GetLastError
              else
                error := ERROR_SUCCESS;
            end;
            if error = ERROR_BROKEN_PIPE then
              // ignore
            else if error = ERROR_SUCCESS then
              // ignore
            else
              RaiseLastOSError(error);
          end;
        finally
          FreeAndNil(ReadEvent);
        end;
      finally
        DisconnectNamedPipe(Server.FPipeHandle);
      end
      else if Signal = Server.FShutdownEvent then
      begin
        // server is shutting down!
        Terminate;
      end;
    end;
  finally
    FreeAndNil(ConnectEvent);
  end;
end;

{ TPBPipeClient }

constructor TPBPipeClient.Create(APath: string);
begin
  FPath := APath;
end;

destructor TPBPipeClient.Destroy;
begin

  inherited;
end;

class procedure TPBPipeClient.SendData(APath, AData: string);
var
  bytesRead: Cardinal;
  success: Integer;
begin
  if not CallNamedPipe(PWideChar(APath), PWideChar(AData), length(AData) * SizeOf(Char), @success, SizeOf(Integer), bytesRead, NMPWAIT_USE_DEFAULT_WAIT) then
    RaiseLastOSError;
end;

procedure TPBPipeClient.SendData(AData: string);
var
  bytesRead: Cardinal;
  success: boolean;
begin
  if not CallNamedPipe(PWideChar(FPath), PWideChar(AData), length(AData) * SizeOf(Char), @success, SizeOf(Integer), bytesRead, NMPWAIT_USE_DEFAULT_WAIT) then
    RaiseLastOSError;
end;

end.
 

1 użytkowników online, w tym zalogowanych: 0, gości: 1