Skojarzenie pliku z programem w delphi

1

Próbowałem w ten sposób
http://4programmers.net/Delphi/Gotowce/W%C5%82asne_rozszerzenie
skojarzyć swoją aplikację z swoim rozszerzeniem, ale to nie zadziałało
Win 11. Oczywiście program musimy otworzyć jako administrator. Inaczej żadne klucze się nie dodadzą. Ma ktoś inny kod, który na bank zadziała?
Dodam, że aby otworzyć plik używam kodu i to się dzieje, ale jak skojarzyć ten plik?

procedure Tglowna_forma_.FormShow(Sender: TObject);
begin

 NazwaPlikuINI:= GetSpecialFolderPath(26) + '\Simple Setup Maker\ustawienia.ini';
 if(FileExists(NazwaPlikuINI)=false) then
 Ustawienia_.Show;

 if ParamStr(1) <> '' then
        begin
        if (ExtractFileExt(ParamStr(1)) = '.ssm') then
                begin
          plik_skryptu_.Otworz(ParamStr(1));
          plik_skryptu_.Show;
          end else begin
          plik_skryptu_.Show;
          plik_skryptu_.Memo1.Clear;

                end;
        end;
end;

ParamStr(1) pobiera oczywiście ścieżkę do pliku. Rozszerzenie to ssm.
W podanym przykładzie próbowałem oczywiście z \ jak to powinno być. Bo ktoś na dole napisał, ale nie działa.

1

Na moje oko ten gotowiec ma błędy. Zerknij tutaj https://learn.microsoft.com/en-us/answers/questions/1462631/how-to-associate-a-certain-file-type-for-my-applic
Do do uprawnień admina to najprawdopodobniej twoja apka ich wymaga lub plik który chcesz nią otworzyć.

0

Pobawie się rejestrem i za pomocą pliku reg to dodam. Muszę więcej informacji zebrać...

0

Co jest tak też nie działa
https://4programmers.net/Z_pogranicza/Skojarzenie_pliku_z_naszym_programem_bez_wzgl%C4%99du_na_rozszerzenie
W exploratorze wybieram "Otwórz za pomocą" i to się wszystko aktualizuje i wtedy można otworzyć plik.

1

Wiesz, to są materiały pisane między innymi pod XP, nie dziw się że nie działają na najnowszych systemach.

1

Przecież jeżeli pytający poprawnie zrobił to co na pisano w artykule do którego sam podał źródło to nadal powinno działać! Tylko po pierwsze zadając pytanie autor nie podaje kodu jak to napisał a we wspomnianym kodzie są błędy prawdopodobnie wynikające z tego że kiedyś był zupełnie inny "silnik" strony i oczywiście część odpowiedzialna za formatowanie kodu i w wyniku różnych późniejszych zmian możliwe, że "zjadło" min. brakujące \ . Ale po drugie co ważniejsze o ile dobrze zrozumiałem to program się odpala tylko nie otwiera skojarzonego pliku a więc prawdopodobnie w skojarzenie działa tylko możliwe że w programie coś skopane.. Na początek proponuję ręcznie sprawdzić co jest w rejestrze we wspomnianym kluczu:shell\open\command\ wartość domyślna powinna zawierać najlepiej w " ścieżkę i nazwę programu, który ma się uruchamiać a po tym spację (odstęp) i %1 też w " czyli np. C:\CosTam\MojSuperProgram.exe" "%1". Druga sprawa jeżeli tam jest OK to wyświetlić sobie co zawiera ParamStr(1) choćby ShowMessage(ParamStr(1)) o tym że aby kod był poprawny należałoby sprawdzać ParamCount (choć w tym wypadku na pewno nie przez to jest problem).

5
hzmzp napisał(a):

Wiesz, to są materiały pisane między innymi pod XP, nie dziw się że nie działają na najnowszych systemach.

Rejestrowanie rozszerzeń nie zmieniło się od czasów WinXP praktycznie w ogóle. 😉


Na potrzeby edytorów zawartości mojej gry, napisałem sobie funkcjonalność rejestrowania lokalizacji edytora (to samo co robią typowe instalatory) , a także rozszerzeń. Ważne! Rejestrowanie tych danych wymaga uprawnień administratora, bo dotyczy zapisu danych w kluczach HKEY_CLASSES_ROOT i HKEY_LOCAL_MACHINE, które są chronione przez system.

Rejestrowanie lokalizacji potrzebne jest do tego, aby program zawsze wiedział gdzie na dysku się znajduje. Bazowanie na Application.ExeName to słabe rozwiązanie, bo jeśli się program uruchomi z dodatkowego toolbara na pasku zadań, to ścieżka aplikacji wskazywać będzie na pulpit, mimo że tam tej aplikacji nie ma. Zauważyłem to pierwszy raz na WinXP i tak samo jest na Win10. Rejestrowanie lokalizacji można olać, ale jeśli program trzyma dane (do odczytu) w plikach obok pliku wykonywalnego oraz korzysta ze ścieżek relatywnych, to mogą wystąpić błędy dostępu do tych plików (tak jak w przypadku ww. uruchomienia programu z toolbara).

Rejestrowanie rozszerzeń służy do dwóch celów. Po pierwsze, aby po uruchomieniu pliku o zadanym rozszerzeniu system otwierał go w moim edytorze. A po drugie, aby powłoka systemu wyświetlała określone przeze mnie ikonki dla konkretnych rozszerzeń. Nie tylko w eksploratorze plików, ale też w różnych menu kontekstowych, a nawet w cudzych programach, które ikonki ładują na podstawie ustawień systemowych (np. w 7-zip).

Pierwsza funkcja służy do zarejestrowania lokalizacji programu. Ja co prawda bazuję na Application.ExeName, dlatego że nie robiłem instalatorów do edytorów — rejestrowanie tych rzeczy mam w oknie ustawień programu. To zwykle robi instalator, więc jeśli się to robi z poziomu aplikacji to lepiej się upewnić, że Application.ExeName faktycznie zawiera prawidłową ścieżkę aplikacji.

function TEditorUtilsRegister.LocationRegister(): Integer;
var
  Registry:   TRegistry;
  EditorPath: String;
begin
  Result   := EDITOR_ERROR_REGISTER_SUCCESS;
  Registry := TRegistry.Create();
  try
    Registry.RootKey := HKEY_LOCAL_MACHINE;

    if Registry.OpenKey('SOFTWARE\flowCRANE\Wtnc\Editor\Cursor', True) then
    begin
      EditorPath := ExtractFilePath(Application.ExeName);
      EditorPath := IncludeTrailingPathDelimiter(EditorPath);

      Registry.WriteString('', EditorPath);
    end
    else
      Result := EDITOR_ERROR_REGISTER_FAILED;
  finally
    Registry.Free();
  end;
end;

Ta funkcja otwiera rejestr, ustawia gałąź na HKEY_LOCAL_MACHINE, a tworzy w nim klucz o ścieżce SOFTWARE\flowCRANE\Wtnc\Editor\Cursor i otwiera go, a na koniec wpisuje ścieżkę programu do domyślnej wartości tego klucza (stąd pusty ciąg znaków jako nazwa wartości). Ścieżka powinna być absolutna i zakończona separatorem oraz nie zawierać nazwy pliku wykonywalnego.

screenshot-20241205154118.png

Edytor przy starcie sprawdza istnienie tego klucza, pobiera ścieżkę z domyślnej wartości, dodaje do niej nazwę pliku wykonywalnego edytora i sprawdza czy plik wykonywalny istnieje pod taką ścieżką. Jeśli istnieje, to używa tej ścieżki do ustawienia working directory, tak aby edytor mógł używać ścieżek relatywnych w trakcie działania. A jeśli tych danych w rejestrze nie ma, to nie modyfikuje working directory. Jej kod wygląda tak:

function TEditorUtilsInstances.LoadLocation(): Boolean;
var
  Registry:   TRegistry;
  EditorPath: String;
begin
  Result    := False;
  Registry  := TRegistry.Create();
  try
    Registry.RootKey := HKEY_LOCAL_MACHINE;

    if Registry.OpenKeyReadOnly('SOFTWARE\flowCRANE\Wtnc\Editor\Cursor') then
    begin
      EditorPath := Registry.ReadString('');
      EditorPath := IncludeTrailingPathDelimiter(EditorPath);

      if FileExists(EditorPath + ExtractFileName(Application.ExeName)) then
        if SetCurrentDir(EditorPath) then
        begin
          FLocation := EditorPath;
          Result    := True;
        end;
    end;
  finally
    Registry.Free();
  end;
end;

Ścieżka pobierana z rejestru przez powyższą funkcję zapisywana jest w polu klasy i używana nie tylko do ustawienia working directory, ale też do zarejestrowania skojarzeń rozszerzeń plików. Tak jak niżej rejestruję rozszerzenie .cursor, zawierających kursory przeznaczone dla mojej gry. Kod funkcji rejestrującej wygląda tak:

function TEditorUtilsRegister.AssociationRegister(): Integer;
var
  Registry:          TRegistry;
  EditorExeName:     String;
  EditorPath:        String = '';
  EditorPathIcon:    String;
  EditorPathCommand: String;
begin
  if not GetRegisteredLocation(EditorPath) then
    exit(EDITOR_ERROR_REGISTER_FAILED);

  EditorExeName     := ExtractFileName(Application.ExeName);
  EditorPathIcon    := EditorPath + EditorExeName + ',0';
  EditorPathCommand := '"' + EditorPath + EditorExeName + '" "%1"';

  Result   := EDITOR_ERROR_REGISTER_SUCCESS;
  Registry := TRegistry.Create();
  try
    Registry.RootKey := HKEY_CLASSES_ROOT;

    if Registry.OpenKey('.cursor', True) then
    begin
      Registry.WriteString('', 'Wtnc.Editor.Cursor');
      Registry.CloseKey();
    end
    else
      exit(EDITOR_ERROR_REGISTER_FAILED);

    if Registry.OpenKey('Wtnc.Editor.Cursor', True) then
    begin
      Registry.WriteString('', 'Wtnc cursor file');
      Registry.CloseKey();
    end
    else
      exit(EDITOR_ERROR_REGISTER_FAILED);

    if Registry.OpenKey('Wtnc.Editor.Cursor\DefaultIcon', True) then
    begin
      Registry.WriteString('', EditorPathIcon);
      Registry.CloseKey();
    end
    else
      exit(EDITOR_ERROR_REGISTER_FAILED);

    if Registry.OpenKey('Wtnc.Editor.Cursor\shell\open\command', True) then
      Registry.WriteString('', EditorPathCommand)
    else
      exit(EDITOR_ERROR_REGISTER_FAILED);
  finally
    Registry.Free();
  end;
end;

Najpierw wywoływana jest funkcja GetRegisteredLocation, która pobiera zarejestrowaną ścieżkę programu z rejestru. Potem otwiera gałąź HKEY_CLASSES_ROOT, gdzie znajdują się dane skojarzeń i tam będzie zapisywać dane.

Pierwsze co należy zrobić to stworzyć klucz z nazwą rozszerzenia, poprzedzoną kropką — w powyższym przypadku klucz nosi nazwę .cursor (rozszerzenie można sobie wymyślić dowolne). Ten klucz po stworzeniu należy otworzyć i do jego wartości domyślnej zapisać nazwę klucza-deskryptora, zawierającego informacje na temat rozszerzenia — u mnie jest to Wtnc.Editor.Cursor (nazwa tego klucza może być dowolna). Po wszystkim zamykamy klucz rozszerzenia.

screenshot-20241205153205.png

Następnie należy zarejestrować klucz-deskryptor, o takiej nazwie jaka została użyta w wartości domyślnej klucza rozszerzenia — czyli u mnie tworzony jest klucz o nazwie Wtnc.Editor.Cursor. Po stworzeniu tego klucza, do jego wartości domyślnej wpisujemy ciąg znaków będący krótkim opisem czym jest plik z naszym rozszerzeniem (czyli z rozszerzeniem .cursor). U mnie jest to plik z danymi kursora dla mojej gry, więc jako opis podałem Wtnc cursor file.

screenshot-20241205153338.png

Kolejnym krokiem jest zarejestrowanie ikonki dla plików. Należy stworzyć podklucz o nazwie DefaultIcon i w jego wartości domyślnej podać ścieżkę pliku z ikonką. Tutaj jest spora dowolność, bo ścieżka może wskazywać bezpośrednio na plik .ico, ale może też wskazywać na plik wykonywalny lub DLL, a jeśli tak, to dodatkowo można określić liczbowy indeks ikonki w zasobach exe/dll. U mnie ścieżka ikonki to pełna ścieżka pliku wykonywalnego edytora, zakończona sufiksem ,0, co oznacza, że system ma użyć głównej ikony programu edytora jako ikonki plików z rozszerzeniem .cursor.

screenshot-20241205153411.png

Ostatnim krokiem (u mnie) jest dodanie skojarzenia rozszerzenia .cursor z moim edytorem, tak aby otwarcie pliku .cursor np. dwuklikiem w oknie eksploratora plików powodowało otwarcie mojego edytora i dostarczenie mu w parametrze uruchomieniowym ścieżki pliku kursora. Ścieżka otwartego pliku będzie dostępna w ParamStr(1).

Aby skojarzyć rozszerzenie z naszym programem, należy stworzyć podklucz shell\open\command i w jego wartości domyślnej podać ciąg znaków komendy. Komenda to pełna ścieżka programu zakończona nazwą pliku wykonywalnego oraz z sufiksem "%1" będącym rozkazem przekazania ścieżki pliku w parametrze uruchomieniowym. Warto jest ścieżkę programu objąć w cudzysłowy, bo może ona zawierać w sobie spacje. Pełna treść komendy powinna wyglądać w ten sposób:

"C:\Tutaj\Sciezka\Programu.exe" "%1"

screenshot-20241205153500.png

Na koniec zamykamy rejestr i gotowe. Można do rejestru dodać znacznie więcej informacji, aby rozbudować sobie powłokę, np. dodać własne pozycje do systemowego menu kontekstowego dla plików z naszym rozszerzeniem (w eksploratorze plików czy na pulpicie), ale to zależy od wymagań. Ja potrzebowałem tego co wyżej i nic więcej.

Pliki moich kursorów w oknie eksploratora wyglądają tak:

screenshot-20241205153828.png

0

O dzięki. Spróbuję to wdrożyć...

0

@flowCRANE
A czy sprawdzałeś kod, w sytuacji gdy inny program zarejestruje twoje rozszerzenie wcześniej? Lub gdy je nadpisze? Czy rejestracja rozszerzenia w przypadku już wcześniejszej rejestracji przez inny program lub system działa prawidłowo?

Z tego co się orientuję, Microsoft robi wszystko, żeby utrudnić rejestrację rozszerzeń (w sensie ty możesz jedynie dodać program do listy zarejestrowanych programów (HKLM\SOFTWARE\RegisteredApplication), a użytkownik musi to zatwierdzić). Mogę się mylić.
Próbowałem kiedyś rejestrować protokoły i rozszerzenia dla przeglądarki i nic ciekawego to nie jest.

1
Pepe napisał(a):

@flowCRANE
A czy sprawdzałeś kod, w sytuacji gdy inny program zarejestruje twoje rozszerzenie wcześniej? Lub gdy je nadpisze? Czy rejestracja rozszerzenia w przypadku już wcześniejszej rejestracji przez inny program lub system działa prawidłowo?

Wytyczne co do rejestrowania rozszerzeń znajdują się w artykule How to Register a File Type for a New Application.

Jeśli rejestrujemy rozszerzenie, to bez względu na to czy ono jest już zarejestrowane (przeze inny program) czy nie, należy nadpisać istniejące dane mapowania. Natomiast w przypadku wyrejestrowywania rozszerzenia, usuwa się jedynie klucz z mapowaniem rozszerzenia (u mnie to klucz Wtnc.Editor.Cursor), natomiast klucz z nazwą rozszerzenia (u mnie to .cursor) nawet się nie dotyka. Wszystko dlatego, że od momentu rejestracji naszego skojarzenia, inny program mógł skojarzyć to rozszerzenie ze sobą i aby mu nie zepsuć danych, nie modyfikuje się tego klucza.

Co prawda można by sprawdzić czy nazwa klucza z mapowaniem rozszerzenia, znajdująca się w kluczu rozszerzenia, nadal wskazuje na nasz klucz z mapowaniem (czyli, u mnie, czy wartość domyślna klucza .cursor nadal zawiera Wtnc.Editor.Cursor) i jeśli tak, to usunąć również i ten klucz, ale to już kwestia własnych preferencji.

W każdym razie oficjalne zalecenia Microsoftu są takie, aby niczego nie usuwać:

Leave the file type mappings unchanged at uninstall time. Doing so works because file type mappings are stored per user in HKEY_CLASSES_ROOT.ext, and the system identifies the case where the ProgID value is missing and ignores it. Leaving file type mappings unchanged avoids the need to have conditional code that only removes the file type mapping if the value still points to your ProgID. It is important to avoid doing so in cases where it might have been changed by another application and you thus cannot easily remove the value.

Tak więc jak kto woli, choć lepiej robić to z głową, aby nie utrudnić innym programom działania. Ja akurat dodałem sobie opcję usuwania danych z rejestru, po pierwsze dlatego, że używam unikalnych rozszerzeń i tylko na własne potrzeby, a po drugie, że mój program nie jest instalowany i jeśli pozostawię w rejestrze dane skojarzeń, to one nadal będą wskazywać na istniejący na dysku program edytora.

Pepe napisał(a):

Z tego co się orientuję, Microsoft robi wszystko, żeby utrudnić rejestrację rozszerzeń (w sensie ty możesz jedynie dodać program do listy zarejestrowanych programów (HKLM\SOFTWARE\RegisteredApplication), a użytkownik musi to zatwierdzić). Mogę się mylić.

Nie zauważyłem żadnych utrudnień związanych z tym tematem. Jedyne co inne niż w starych systemach to wymagane podwyższone uprawnienia procesu modyfikującego rejestr, ale to ze względu na bezpieczeństwo systemu, więc jest to jak najbardziej zrozumiałe.

1

Nie długo zaprezentuję swój program robiący instalatory innych programów. Już wszystko jest zrobione tylko muszę jeszcze zlecić tłumaczenie na niektóre języki. Podobny do inno setup.

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.