Как добавить пункт в контекстное меню для файлов?

Вопросы программирования и использования среды Lazarus.

Модератор: Модераторы

Как добавить пункт в контекстное меню для файлов?

Сообщение BadBoyAlex » 28.06.2015 10:44:56

Здравствуйте, уважаемые форумчане!
Подскажите пожалуйста, как добавить в контекстное меню проводника пункт для файлов: "Открыть в моей программе..."?

Пробовал так:
Код: Выделить всё
...
var Reg: TRegistry;
...
Reg:= TRegistry.Create(KEY_WRITE);
with Reg do
begin
RootKey:= HKEY_CLASSES_ROOT;
if OpenKey('CLSID\{20D04FE0-3AEA-1069-A2D8-08002B30309D}\shell\myprogram\', true) then
  begin
  WriteString('MUIVerb', GetLocalStr('syscontextmenu', 0));
  WriteString('Icon', prExpandPath('$prpath$') + 'images\contextmenu.ico');
  WriteString('Position', 'Top');
  CloseKey;
  end;
if OpenKey('CLSID\{20D04FE0-3AEA-1069-A2D8-08002B30309D}\shell\myprogram\command\', true) then
  begin
  WriteString('', prExpandPath('$prpath$') + 'asfpreviewer.exe /d="%1" /m=-1');
  CloseKey;
  end;
Free;
end;

не работает. Может кто знает, что надо делать?
Последний раз редактировалось BadBoyAlex 28.06.2015 12:02:12, всего редактировалось 1 раз.
Аватара пользователя
BadBoyAlex
постоялец
 
Сообщения: 119
Зарегистрирован: 08.06.2010 12:42:23
Откуда: Россия, Белгород

Re: Как добавить пункт в крнтекстное меню для файлов?

Сообщение resident » 28.06.2015 11:21:46

BadBoyAlex писал(а):как добавить в контекстное меню проводника пункт для файлов: "Открыть в моей программе..."?

При установке программы в систему или уже при установленной?
resident
энтузиаст
 
Сообщения: 605
Зарегистрирован: 13.03.2013 16:58:51

Re: Как добавить пункт в контекстное меню для файлов?

Сообщение BadBoyAlex » 28.06.2015 12:02:46

resident писал(а):При установке программы в систему или уже при установленной?

Желательно, в любой момент из самой программы.
Аватара пользователя
BadBoyAlex
постоялец
 
Сообщения: 119
Зарегистрирован: 08.06.2010 12:42:23
Откуда: Россия, Белгород

Re: Как добавить пункт в контекстное меню для файлов?

Сообщение resident » 28.06.2015 12:45:02

BadBoyAlex писал(а):Желательно, в любой момент из самой программы.

Дык это ж мазохизм. :mrgreen:
1) Системы Windows разные (я так подозреваю). Например, что замутишь в семерке, на десятке уже может и не пойти. Зачем на будущее оставлять этот головняк?
2) На сколько я понял, приложение туда попадает само после правильной установки ассоциации расширения с приложением
3) Даже правильно проведя ассоциацию, необходимо делать rebuild icon cashe
4) Время лучше потратить на более нужные для пользователей возможности программы
5) и т.д.

Вот мой модуль, тут есть функции и свойства для тестирования, но не забывайте про пункт (3). Но опять же повторю, доделав решение, я удалил его из проекта, т.к. радости и уверенности в завтрашней работоспособности у меня не было.
Код: Выделить всё
unit UAssociation;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, Registry, Dialogs, Forms, ShlObj;

type
  //////////////////// TAssociation /////////////////////
  // Методы класса производят ассоциацию (или её удаление)
  // моей проги с файлами заданного расширения
  // Это нужно чтобы они открывались по двойному щелчку
  // Кроме ассоцияции нужно еще передавать имя файла командной
  // строкой ParamStr(1) см. UfMain -> TfMain.FormCreate
  TAssociation = class // ассоциация расширения файла проекта с программой в Windows
    private
      fExtension: string; // расширение файла без точки
      fExeName: string; // название ехе-шника (путь + название)
      fProgName: string; // название программы, будет использовано только в реестре
      fIconIndex: integer; // индекс иконки в ехе-шнике, для моих проектов индекс = 1 (0 - иконка приложения)
    protected
      procedure SetExtension(NewExt: string);
    public
      function GetExeNameByExtension(sExt: string = ''): string;

      property Extension: string read fExtension write SetExtension;
      property ExeName: string read fExeName write fExeName;
      property ProgName: string read fProgName write fProgName;
      property IconIndex: integer read fIconIndex write fIconIndex;

      procedure MakeAssociation;
      procedure DeleteAssociation;

      constructor Create;
    end;


implementation

procedure TAssociation.SetExtension(NewExt: string);
  begin
    if NewExt[1] = '.'
      then // убираю точку в начале, если есть
        fExtension := Copy(NewExt, 2, MaxInt)
      else fExtension := NewExt;
  end;

procedure TAssociation.MakeAssociation;
  var
    Reg: TRegistry;
    sKey, sVal: AnsiString;
  procedure WriteToReg;
    begin
      Reg.OpenKey(sKey, True);
      Reg.WriteString('', sVal);
      Reg.CloseKey;
    end;

  begin
    Reg := TRegistry.Create;
    try
      Reg.RootKey := HKEY_CLASSES_ROOT;

      sKey := UTF8ToAnsi('.' + fExtension);
      sVal := UTF8ToAnsi(fProgName);
      WriteToReg;

      sKey := UTF8ToAnsi(fProgName);
      sVal := UTF8ToAnsi('Open .' + fExtension + ' extension');
      WriteToReg;

      sKey := UTF8ToAnsi(fProgName + '\DefaultIcon');
      sVal := UTF8ToAnsi(fExeName + ',' + IntToStr(fIconIndex));
      WriteToReg;

      sKey := UTF8ToAnsi(fProgName + '\Shell\Open\Command');
      sVal := UTF8ToAnsi('"' + fExeName + '"' + ' "%1"');
      WriteToReg;
    finally
      Reg.Free;
    end;

    SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, nil, nil);
  end;

procedure TAssociation.DeleteAssociation;
  var
    sExtAnsi, sExtDescAnsi: AnsiString;
    Reg: TRegistry;
  begin
    Reg := TRegistry.Create;
    try
      Reg.RootKey := HKEY_CLASSES_ROOT;

      sExtAnsi := UTF8ToAnsi('.' + fExtension);

      if Reg.OpenKeyReadOnly(sExtAnsi)
        then
          begin
            sExtDescAnsi := Reg.ReadString('');
            //ShowMessage(AnsiToUTF8(sExtDescAnsi));
            Reg.CloseKey;

            Reg.DeleteKey(sExtAnsi);
            Reg.DeleteKey(sExtDescAnsi + '\DefaultIcon');
            Reg.DeleteKey(sExtDescAnsi + '\Shell\Open\Command');
            Reg.DeleteKey(sExtDescAnsi + '\Shell\Open');
            Reg.DeleteKey(sExtDescAnsi + '\Shell');
            Reg.DeleteKey(sExtDescAnsi);
          end;
    finally
      Reg.Free;
    end;

    SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, nil, nil);
  end;

constructor TAssociation.Create;
  var
    s: string; // название ехе-шника
  begin
    fExeName := AnsiToUTF8(Application.ExeName);
    s := ExtractFileName(fExeName);
    // fProgName - название ехе-шника без .ехе
    fProgName := StringReplace(s,
                               '.exe',
                               '',
                               [rfReplaceAll, rfIgnoreCase]);
    //ShowMessage(AnsiToUTF8(fProgName));
    fIconIndex := 0;
  end;

function TAssociation.GetExeNameByExtension(sExt: string): string;
  var
    sExtAnsi, sExtDescAnsi, sAnsi: AnsiString;
    i: integer;
  begin
    if sExt = ''
      then sExtAnsi := UTF8ToAnsi(fExtension)
      else sExtAnsi := UTF8ToAnsi(sExt);

    if sExtAnsi[1] <> '.'
      then  // добавляю точку в начало, если отсутствует
        sExtAnsi := '.' + sExtAnsi;

    with TRegistry.Create do
      begin
        try
          RootKey := HKEY_CLASSES_ROOT;

          if OpenKeyReadOnly(sExtAnsi)
            then
              begin
                sExtDescAnsi := ReadString('');
                //ShowMessage(AnsiToUTF8(sExtDescAnsi));
                CloseKey;
              end;

          if sExtDescAnsi <> ''
            then
              begin
                if OpenKeyReadOnly(sExtDescAnsi + '\Shell\Open\Command')
                  then
                    begin
                      sAnsi:= ReadString('');
                      //ShowMessage(AnsiToUTF8(sAnsi));
                    end
              end;
        finally
          Free;
        end;
      end;

    if sAnsi <> ''
      then
        begin
          if sAnsi[1] = '"'
            then // нужно убрать кавычки впереди и кавычки (и что за ними) в конце
              begin
                sAnsi := Copy(sAnsi, 2, MaxInt); // убираю кавычки в начале = копирую часть после них
                i := Pos('"', sAnsi); // позиция следующих кавычек
                sAnsi := Copy(sAnsi, 1, i - 1); // убираю кавычки в конце = копирую часть до них
                //ShowMessage(AnsiToUTF8(sAnsi));
              end
        end;

    Result := AnsiToUTF8(sAnsi);
  end;


end.

resident
энтузиаст
 
Сообщения: 605
Зарегистрирован: 13.03.2013 16:58:51

Re: Как добавить пункт в контекстное меню для файлов?

Сообщение BadBoyAlex » 28.06.2015 15:38:48

resident писал(а):Вот мой модуль, тут есть функции и свойства для тестирования, но не забывайте про пункт (3). Но опять же повторю, доделав решение, я удалил его из проекта, т.к. радости и уверенности в завтрашней работоспособности у меня не было.

Вы немного не поняли. Стандартная ассоциация у меня уже давно реализована. Проблема в добавлении именно пункта меню. Например, как WinRAR добавляет пункты в контекстное меню системы.
Аватара пользователя
BadBoyAlex
постоялец
 
Сообщения: 119
Зарегистрирован: 08.06.2010 12:42:23
Откуда: Россия, Белгород

Re: Как добавить пункт в контекстное меню для файлов?

Сообщение resident » 28.06.2015 16:43:21

BadBoyAlex писал(а):Проблема в добавлении именно пункта меню. Например, как WinRAR добавляет пункты в контекстное меню системы.

Ok, я подумал о подменю "Открыть с помощью...". В самый верхний узел меню я не лез.
resident
энтузиаст
 
Сообщения: 605
Зарегистрирован: 13.03.2013 16:58:51

Re: Как добавить пункт в контекстное меню для файлов?

Сообщение Sharfik » 28.06.2015 18:52:56

Поищи примеры использования WinAPI - InsertMenuItem.

Тут вроде по человечески что к чему описано
http://forum.sources.ru/index.php?act=P ... 1&t=149048
Я не тестил, но по коду очень похоже на копию того что в примерах делфи лежит.
http://www.delphisources.ru/pages/sourc ... nsion.html
Аватара пользователя
Sharfik
энтузиаст
 
Сообщения: 809
Зарегистрирован: 20.07.2013 01:04:30

Re: Как добавить пункт в контекстное меню для файлов?

Сообщение BadBoyAlex » 29.06.2015 17:03:25

Sharfik писал(а):Тут вроде по человечески что к чему описано
http://forum.sources.ru/index.php?act=P ... 1&t=149048
Я не тестил, но по коду очень похоже на копию того что в примерах делфи лежит.
http://www.delphisources.ru/pages/sourc ... nsion.html

Проблема в том, что все они ссылаются на tlHelp32, которая в лазаре почему-то не реализована (или я что-то пропустил?).
Аватара пользователя
BadBoyAlex
постоялец
 
Сообщения: 119
Зарегистрирован: 08.06.2010 12:42:23
Откуда: Россия, Белгород

Re: Как добавить пункт в контекстное меню для файлов?

Сообщение Sharfik » 30.06.2015 02:08:17

Тебе надо, решение описанное есть, так в чем проблема? Разобраться что "круглый винтик" делает и зачем самостоятельно никак?
Аватара пользователя
Sharfik
энтузиаст
 
Сообщения: 809
Зарегистрирован: 20.07.2013 01:04:30

Re: Как добавить пункт в контекстное меню для файлов?

Сообщение sign » 30.06.2015 07:02:34

Код: Выделить всё
uses
  Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs, ExtCtrls
  , types
  , StdCtrls
  , ComCtrls
  , LMessages
  , ComponentEditors
  , PropEdits
  ;

type

  { TTreePanels }
  TLabelTree = class(TCustomLabel)
  end;

  TSplitterTree = class(TCustomSplitter)
  end;

  TEditTree = class(TCustomEdit)
  end;

  TTree = class(TTreeView)
  end;

  TComponentEditorTreePanel = class(TComponentEditor)
  public
    function GetVerbCount: Integer; override;
    function GetVerb(Index: Integer): string; override;
    procedure ExecuteVerb(Index: Integer); override;
  end;

  TPropertyEditorTreePanel = class(TPropertyEditor)

procedure Register;

implementation

uses typinfo ;

procedure Register;
begin
  {$I treepanels_icon.lrs}
  RegisterComponents('Standard',[TTreePanels]);
  RegisterPropertyEditor(TypeInfo(TEditTree),     TTreePanels, 'Filter',      TClassProperty);
  RegisterPropertyEditor(TypeInfo(TPageControl),  TTreePanels, 'Pages', TClassProperty);
  RegisterPropertyEditor(TypeInfo(TSplitterTree), TTreePanels, 'Splitter',    TClassProperty);
  RegisterPropertyEditor(TypeInfo(TLabelTree),    TTreePanels, 'Title',       TClassProperty);
  RegisterPropertyEditor(TypeInfo(TTreeView),     TTreePanels, 'Tree',        TClassProperty);
  RegisterComponentEditor(TTreePanels, TComponentEditorTreePanel);

procedure RegisterComponentClasses(AComponent: TComponent);
var i: Integer;
begin
  RegisterClass(TPersistentClass(AComponent.ClassType));
  if AComponent is TWinControl then
    for i := 0 to TWinControl(AComponent).ControlCount - 1 do
      RegisterComponentClasses(TWinControl(AComponent).Controls[i]);
end;

{  TComponentEditorTreePanel }

function TComponentEditorTreePanel.GetVerbCount: Integer;
begin
  if TTreePanels(Component).Pages.PageCount = 0 then Result := 1
    else Result := 5;
end;

function TComponentEditorTreePanel.GetVerb(Index: Integer): string;
begin
  case Index of
    0: Result := 'Добавить страницу';
    1: Result := 'Удалить страницу';
    2: Result := 'Переместить страницу влево';
    3: Result := 'Переместить страницу вправо';
    4: Result := 'Показать страницу';
  end;
end;

procedure TComponentEditorTreePanel.ExecuteVerb(Index: Integer);
begin
  case Index Of
    0: TTreePanels(Component).AddPage;
    1: TTreePanels(Component).DeletePage;
    2: ShowMessage('Действие 3');
    3: ShowMessage('Действие 4');
    4: ShowMessage('Действие 5');
  end;

sign
энтузиаст
 
Сообщения: 1131
Зарегистрирован: 30.08.2009 09:20:53


Вернуться в Lazarus

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 227

Рейтинг@Mail.ru
cron